package openmods.sync; import com.google.common.base.Preconditions; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import net.minecraft.nbt.NBTTagCompound; import openmods.utils.ByteUtils; import openmods.utils.bitmap.IBitMap; import openmods.utils.bitmap.IRpcIntBitMap; public abstract class SyncableFlags extends SyncableObjectBase implements IRpcIntBitMap, IBitMap<Integer> { private static class ByteFlags extends SyncableFlags { @Override public void readFromStream(DataInputStream stream) throws IOException { value = stream.readByte(); } @Override public void writeToStream(DataOutputStream stream) throws IOException { stream.writeByte(value); } @Override public void writeToNBT(NBTTagCompound tag, String name) { tag.setByte(name, (byte)value); } @Override public void readFromNBT(NBTTagCompound tag, String name) { value = tag.getByte(name); } } private static class ShortFlags extends SyncableFlags { @Override public void readFromStream(DataInputStream stream) throws IOException { value = stream.readShort(); } @Override public void writeToStream(DataOutputStream stream) throws IOException { stream.writeShort(value); } @Override public void writeToNBT(NBTTagCompound tag, String name) { tag.setShort(name, (short)value); } @Override public void readFromNBT(NBTTagCompound tag, String name) { value = tag.getShort(name); } } private static class IntFlags extends SyncableFlags { @Override public void readFromStream(DataInputStream stream) throws IOException { value = stream.readInt(); } @Override public void writeToStream(DataOutputStream stream) throws IOException { stream.writeInt(value); } @Override public void writeToNBT(NBTTagCompound tag, String name) { tag.setInteger(name, value); } @Override public void readFromNBT(NBTTagCompound tag, String name) { value = tag.getInteger(name); } } public static SyncableFlags create(int bitCount) { Preconditions.checkArgument(bitCount > 0, "Bit count must be positive"); if (bitCount <= Byte.SIZE) return new ByteFlags(); if (bitCount <= Short.SIZE) return new ShortFlags(); if (bitCount <= Integer.SIZE) return new IntFlags(); throw new IllegalArgumentException("Too many bits. Split some fields or implement LongFlags or BigIntFlags"); } protected int value; private int previousValue; protected SyncableFlags() {} public void on(Enum<?> slot) { on(slot.ordinal()); } public void on(int slot) { set(slot, true); } @Override public void mark(Integer value) { on(value); } public void off(Enum<?> slot) { off(slot.ordinal()); } public void off(int slot) { set(slot, false); } @Override public void clear(Integer value) { off(value); } public void set(Enum<?> slot, boolean bool) { set(slot.ordinal(), bool); } public void toggle(int slot) { set(value ^ (1 << slot)); } @Override public void toggle(Integer value) { toggle(value.intValue()); } public void toggle(Enum<?> slot) { toggle(slot.ordinal()); } private void set(int value) { if (value != this.value) { markDirty(); this.value = (short)value; } } public void set(int slot, boolean bool) { short newVal = (short)ByteUtils.set(value, slot, bool); if (newVal != value) { markDirty(); value = newVal; } } @Override public void set(Integer slot, boolean bool) { set(slot.intValue(), bool); } public boolean get(Enum<?> slot) { return get(slot.ordinal()); } public boolean get(int slot) { return ByteUtils.get(value, slot); } @Override public boolean get(Integer value) { return get(value.intValue()); } public boolean hasSlotChanged(Enum<?> slot) { return hasSlotChanged(slot.ordinal()); } public boolean hasSlotChanged(int slot) { int mask = 1 << slot; return (value & mask) == (previousValue & mask); } @Override public void markClean() { previousValue = value; dirty = false; } @Override public void clearAll() { value = 0; markDirty(); } }