package mcjty.rftools.blocks.logic;
import mcjty.lib.entity.GenericTileEntity;
import mcjty.lib.network.Argument;
import mcjty.lib.varia.BlockTools;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.nbt.NBTTagCompound;
import java.util.Map;
public class SequencerTileEntity extends GenericTileEntity {
public static final String CMD_MODE = "mode";
public static final String CMD_SETBIT = "setBit";
public static final String CMD_SETBITS = "setBits";
public static final String CMD_SETDELAY = "setDelay";
private SequencerMode mode = SequencerMode.MODE_ONCE1;
private long cycleBits = 0;
private int currentStep = -1;
// For pulse detection.
private boolean prevIn = false;
private int delay = 1;
private int timer = 0;
private boolean redstoneOut = false;
public SequencerTileEntity() {
}
public int getDelay() {
return delay;
}
public void setDelay(int delay) {
this.delay = delay;
timer = delay;
markDirty();
worldObj.markBlockForUpdate(xCoord, yCoord, zCoord);
}
public SequencerMode getMode() {
return mode;
}
public void setMode(SequencerMode mode) {
this.mode = mode;
switch (mode) {
case MODE_ONCE1:
case MODE_ONCE2:
case MODE_LOOP3:
case MODE_LOOP4:
currentStep = -1;
break;
case MODE_LOOP1:
case MODE_LOOP2:
case MODE_STEP:
currentStep = 0;
break;
}
markDirty();
worldObj.markBlockForUpdate(xCoord, yCoord, zCoord);
}
public boolean getCycleBit(int bit) {
return ((cycleBits >> bit) & 1) == 1;
}
public void setCycleBit(int bit, boolean flag) {
if (flag) {
cycleBits |= 1L << bit;
} else {
cycleBits &= ~(1L << bit);
}
markDirty();
worldObj.markBlockForUpdate(xCoord, yCoord, zCoord);
}
public void setCycleBits(int start, int stop, boolean flag) {
for (int bit = start ; bit <= stop ; bit++) {
if (flag) {
cycleBits |= 1L << bit;
} else {
cycleBits &= ~(1L << bit);
}
}
markDirty();
worldObj.markBlockForUpdate(xCoord, yCoord, zCoord);
}
@Override
protected void checkStateServer() {
super.checkStateServer();
int meta = worldObj.getBlockMetadata(xCoord, yCoord, zCoord);
boolean newvalue = BlockTools.getRedstoneSignalIn(meta);
boolean pulse = newvalue && !prevIn;
prevIn = newvalue;
if (pulse) {
handlePulse();
}
markDirty();
timer--;
if (timer <= 0) {
timer = delay;
} else {
return;
}
boolean newout = currentStep != -1 && getCycleBit(currentStep);
if (newout != redstoneOut) {
redstoneOut = newout;
notifyBlockUpdate();
}
handleCycle(newvalue);
}
/**
* Handle a cycle step.
* @param redstone true if there is a redstone signal
*/
private void handleCycle(boolean redstone) {
switch (mode) {
case MODE_ONCE1:
case MODE_ONCE2:
if (currentStep != -1) {
nextStepAndStop();
}
break;
case MODE_LOOP1:
nextStep();
break;
case MODE_LOOP2:
nextStep();
break;
case MODE_LOOP3:
if (redstone) {
nextStep();
}
break;
case MODE_LOOP4:
if (redstone) {
nextStep();
} else {
currentStep = -1;
}
break;
case MODE_STEP:
break;
}
}
/**
* Handle the arrival of a new redstone pulse.
*/
private void handlePulse() {
switch (mode) {
case MODE_ONCE1:
// If we're not doing a cycle then we start one now. Otherwise we do nothing.
if (currentStep == -1) {
currentStep = 0;
}
break;
case MODE_ONCE2:
// If we're not doing a cycle then we start one now. Otherwise we restart the cycle..
currentStep = 0;
break;
case MODE_LOOP1:
// Ignore signals
break;
case MODE_LOOP2:
// Set cycle to the start.
currentStep = 0;
break;
case MODE_LOOP3:
case MODE_LOOP4:
// Ignore pulses. We just work on redstone signal.
break;
case MODE_STEP:
// Go to next step.
nextStep();
break;
}
}
private void nextStep() {
currentStep++;
if (currentStep >= 64) {
currentStep = 0;
}
}
private void nextStepAndStop() {
currentStep++;
if (currentStep >= 64) {
currentStep = -1;
}
}
@Override
protected int updateMetaData(int meta) {
meta = super.updateMetaData(meta);
return BlockTools.setRedstoneSignalOut(meta, redstoneOut);
}
@Override
public void readFromNBT(NBTTagCompound tagCompound) {
super.readFromNBT(tagCompound);
redstoneOut = tagCompound.getBoolean("rs");
currentStep = tagCompound.getInteger("step");
prevIn = tagCompound.getBoolean("prevIn");
timer = tagCompound.getInteger("timer");
}
@Override
public void readRestorableFromNBT(NBTTagCompound tagCompound) {
super.readRestorableFromNBT(tagCompound);
cycleBits = tagCompound.getLong("bits");
int m = tagCompound.getInteger("mode");
mode = SequencerMode.values()[m];
delay = tagCompound.getInteger("delay");
if (delay == 0) {
delay = 1;
}
}
@Override
public void writeToNBT(NBTTagCompound tagCompound) {
super.writeToNBT(tagCompound);
tagCompound.setBoolean("rs", redstoneOut);
tagCompound.setInteger("step", currentStep);
tagCompound.setBoolean("prevIn", prevIn);
tagCompound.setInteger("timer", timer);
}
@Override
public void writeRestorableToNBT(NBTTagCompound tagCompound) {
super.writeRestorableToNBT(tagCompound);
tagCompound.setLong("bits", cycleBits);
tagCompound.setInteger("mode", mode.ordinal());
tagCompound.setInteger("delay", delay);
}
@Override
public boolean execute(EntityPlayerMP playerMP, String command, Map<String, Argument> args) {
boolean rc = super.execute(playerMP, command, args);
if (rc) {
return true;
}
if (CMD_MODE.equals(command)) {
String m = args.get("mode").getString();
setMode(SequencerMode.getMode(m));
return true;
} else if (CMD_SETBIT.equals(command)) {
setCycleBit(args.get("bit").getInteger(), args.get("choice").getBoolean());
return true;
} else if (CMD_SETBITS.equals(command)) {
setCycleBits(args.get("start").getInteger(), args.get("stop").getInteger(), args.get("choice").getBoolean());
return true;
} else if (CMD_SETDELAY.equals(command)) {
setDelay(args.get("delay").getInteger());
return true;
}
return false;
}
}