package speedytools.common.network; import net.minecraft.util.BlockPos; import net.minecraftforge.fml.common.network.simpleimpl.IMessage; import net.minecraftforge.fml.common.network.simpleimpl.IMessageHandler; import net.minecraftforge.fml.common.network.simpleimpl.MessageContext; import net.minecraftforge.fml.relauncher.Side; import io.netty.buffer.ByteBuf; import net.minecraft.block.Block; import net.minecraft.init.Blocks; import speedytools.SpeedyToolsMod; import speedytools.common.blocks.BlockWithMetadata; import speedytools.common.utilities.ErrorLog; import speedytools.common.utilities.QuadOrientation; /** * This class is used to communicate actions from the client to the server for clone use * Client to Server: * (1) when user has made a selection using a clone tool * (2) user has performed an action with the tool (place) at the current selection position * (3) user has performed an undo with the tool */ public class Packet250CloneToolUse extends Packet250Base { public static Packet250CloneToolUse prepareForLaterAction() { Packet250CloneToolUse retval = new Packet250CloneToolUse(Command.PREPARE_FOR_LATER_ACTION); assert (retval.checkInvariants()); return retval; } public static Packet250CloneToolUse performToolAction(int i_sequenceNumber, int i_toolID, int x, int y, int z, QuadOrientation i_quadOrientation, BlockPos i_selectionOrigin) { Packet250CloneToolUse retval = new Packet250CloneToolUse(Command.PERFORM_TOOL_ACTION); retval.toolID = i_toolID; retval.xpos = x; retval.ypos = y; retval.zpos = z; retval.quadOrientation = i_quadOrientation; retval.sequenceNumber = i_sequenceNumber; retval.selectionInitialOrigin = i_selectionOrigin; assert (retval.checkInvariants()); retval.packetIsValid= true; return retval; } public static Packet250CloneToolUse performToolFillAction(int i_sequenceNumber, int i_toolID, BlockWithMetadata i_fillBlock, int x, int y, int z, QuadOrientation i_quadOrientation, BlockPos i_selectionOrigin) { Packet250CloneToolUse retval = new Packet250CloneToolUse(Command.PERFORM_TOOL_ACTION); retval.toolID = i_toolID; retval.blockWithMetadata = i_fillBlock; retval.xpos = x; retval.ypos = y; retval.zpos = z; retval.quadOrientation = i_quadOrientation; retval.sequenceNumber = i_sequenceNumber; retval.selectionInitialOrigin = i_selectionOrigin; assert (retval.checkInvariants()); retval.packetIsValid= true; return retval; } public static Packet250CloneToolUse cancelCurrentAction(int i_undoSequenceNumber, int i_actionSequenceNumber) { Packet250CloneToolUse retval = new Packet250CloneToolUse(Command.PERFORM_TOOL_UNDO); retval.sequenceNumber = i_undoSequenceNumber; retval.actionToBeUndoneSequenceNumber = i_actionSequenceNumber; assert (retval.checkInvariants()); return retval; } public static Packet250CloneToolUse performToolUndo(int i_undoSequenceNumber) { Packet250CloneToolUse retval = new Packet250CloneToolUse(Command.PERFORM_TOOL_UNDO); retval.sequenceNumber = i_undoSequenceNumber; retval.actionToBeUndoneSequenceNumber = NULL_SEQUENCE_NUMBER; assert (retval.checkInvariants()); return retval; } @Override protected void readFromBuffer(ByteBuf buf) { packetIsValid = false; try { byte commandValue = buf.readByte(); command = Command.byteToCommand(commandValue); if (command == null) return; toolID = buf.readInt(); sequenceNumber = buf.readInt(); actionToBeUndoneSequenceNumber = buf.readInt(); int blockID = buf.readInt(); blockWithMetadata = new BlockWithMetadata(); blockWithMetadata.block = Block.getBlockById(blockID); blockWithMetadata.metaData = buf.readInt(); xpos = buf.readInt(); ypos = buf.readInt(); zpos = buf.readInt(); quadOrientation = new QuadOrientation(buf); int originX = buf.readInt(); int originY = buf.readInt(); int originZ = buf.readInt(); selectionInitialOrigin = new BlockPos(originX, originY, originZ); } catch (IndexOutOfBoundsException ioe) { ErrorLog.defaultLog().info("Exception while reading Packet250CloneToolUse: " + ioe); return; } if (!checkInvariants()) return; packetIsValid = true; } @Override protected void writeToBuffer(ByteBuf buf) { if (!isPacketIsValid()) return; // buf.writeByte(Packet250Types.PACKET250_CLONE_TOOL_USE_ID.getPacketTypeID()); buf.writeByte(command.getCommandID()); buf.writeInt(toolID); buf.writeInt(sequenceNumber); buf.writeInt(actionToBeUndoneSequenceNumber); if (blockWithMetadata == null) { buf.writeInt(Block.getIdFromBlock(Blocks.air)); buf.writeInt(0); } else { buf.writeInt(Block.getIdFromBlock(blockWithMetadata.block)); buf.writeInt(blockWithMetadata.metaData); } buf.writeInt(xpos); buf.writeInt(ypos); buf.writeInt(zpos); if (quadOrientation == null) { quadOrientation = new QuadOrientation(0, 0, 1, 1); // just a dummy } quadOrientation.writeToStream(buf); if (selectionInitialOrigin == null) { selectionInitialOrigin = new BlockPos(0,0,0); } buf.writeInt(selectionInitialOrigin.getX()); buf.writeInt(selectionInitialOrigin.getY()); buf.writeInt(selectionInitialOrigin.getZ()); } public static enum Command { PREPARE_FOR_LATER_ACTION(0), PERFORM_TOOL_ACTION(1), PERFORM_TOOL_UNDO(2); public byte getCommandID() {return commandID;} private static Command byteToCommand(byte value) { for (Command command : Command.values()) { if (value == command.getCommandID()) return command; } return null; } private Command(int i_commandID) { commandID = (byte)i_commandID; } public final byte commandID; } /** * Is this packet valid to be received and acted on by the given side? * @param whichSide * @return true if yes */ public boolean validForSide(Side whichSide) { assert(checkInvariants()); return (whichSide == Side.SERVER); } public Command getCommand() { assert (checkInvariants()); return command; } public BlockWithMetadata getBlockWithMetadata() { return blockWithMetadata; } public int getToolID() { assert (checkInvariants()); assert(command == Command.PERFORM_TOOL_ACTION || command == Command.PERFORM_TOOL_UNDO); return toolID; } public int getXpos() { assert (checkInvariants()); assert(command == Command.PERFORM_TOOL_ACTION); return xpos; } public int getYpos() { assert (checkInvariants()); assert(command == Command.PERFORM_TOOL_ACTION); return ypos; } public int getZpos() { assert (checkInvariants()); assert(command == Command.PERFORM_TOOL_ACTION); return zpos; } public QuadOrientation getQuadOrientation() { assert (checkInvariants()); assert(command == Command.PERFORM_TOOL_ACTION); return quadOrientation; } public BlockPos getSelectionInitialOrigin() { assert (checkInvariants()); assert(command == Command.PERFORM_TOOL_ACTION); return selectionInitialOrigin; } public int getSequenceNumber() { return sequenceNumber; } // null means no specific action nominated for undo public Integer getActionToBeUndoneSequenceNumber() { return (actionToBeUndoneSequenceNumber == NULL_SEQUENCE_NUMBER) ? null : actionToBeUndoneSequenceNumber; } /** * Register the handler for this packet * @param packetHandlerRegistry * @param packetHandlerMethod * @param side */ public static void registerHandler(PacketHandlerRegistry packetHandlerRegistry, PacketHandlerMethod packetHandlerMethod, Side side) { if (side != Side.SERVER) { assert false : "Tried to register Packet250CloneToolUse on side " + side; } serverSideHandler = packetHandlerMethod; packetHandlerRegistry.getSimpleNetworkWrapper().registerMessage(ServerMessageHandler.class, Packet250CloneToolUse.class, Packet250Types.PACKET250_CLONE_TOOL_USE_ID.getPacketTypeID(), side); } public interface PacketHandlerMethod { public boolean handlePacket(Packet250CloneToolUse packet250CloneToolUse, MessageContext ctx); } public static class ServerMessageHandler implements IMessageHandler<Packet250CloneToolUse, IMessage> { /** * Called when a message is received of the appropriate type. You can optionally return a reply message, or null if no reply * is needed. * * @param message The message * @return an optional return message */ public IMessage onMessage(final Packet250CloneToolUse message, final MessageContext ctx) { if (serverSideHandler == null) { ErrorLog.defaultLog().severe("Packet250CloneToolUse received but not registered."); } else if (ctx.side != Side.SERVER) { ErrorLog.defaultLog().severe("Packet250CloneToolUse received on wrong side"); } else { Runnable messageProcessor = new Runnable() { @Override public void run() { serverSideHandler.handlePacket(message, ctx); } }; boolean success = SpeedyToolsMod.proxy.enqueueMessageOnCorrectThread(ctx, messageProcessor); if (!success) { ErrorLog.defaultLog().severe("Packet250CloneToolUse failed to handle Packet"); } } return null; } } private Packet250CloneToolUse(Command command) { this.command = command; this.packetIsValid = true; } public Packet250CloneToolUse() // used by Netty; invalid until populated by the packet handler { } /** * checks this class to see if it is internally consistent * @return true if ok, false if bad. */ private boolean checkInvariants() { if (command == null) return false; switch (command) { case PREPARE_FOR_LATER_ACTION: { return true; } case PERFORM_TOOL_ACTION: { return true; } case PERFORM_TOOL_UNDO: { return true; } default: { return false; } } } private static final int NULL_SEQUENCE_NUMBER = Integer.MIN_VALUE; private Command command; private int toolID; private BlockWithMetadata blockWithMetadata; private int sequenceNumber; private int actionToBeUndoneSequenceNumber; private int xpos; private int ypos; private int zpos; private QuadOrientation quadOrientation; private BlockPos selectionInitialOrigin; private static PacketHandlerMethod serverSideHandler; }