2014-02-05 19:06:35 +01:00
|
|
|
package cpw.mods.ironchest;
|
|
|
|
|
|
|
|
|
|
import io.netty.buffer.ByteBuf;
|
|
|
|
|
import io.netty.channel.ChannelHandlerContext;
|
|
|
|
|
import io.netty.channel.SimpleChannelInboundHandler;
|
2014-05-11 22:00:59 +02:00
|
|
|
|
2014-02-05 19:06:35 +01:00
|
|
|
import java.util.EnumMap;
|
2014-05-11 22:00:59 +02:00
|
|
|
|
2014-02-05 19:06:35 +01:00
|
|
|
import net.minecraft.network.Packet;
|
|
|
|
|
import net.minecraft.tileentity.TileEntity;
|
|
|
|
|
import net.minecraft.world.World;
|
|
|
|
|
import cpw.mods.fml.common.FMLCommonHandler;
|
|
|
|
|
import cpw.mods.fml.common.network.FMLEmbeddedChannel;
|
|
|
|
|
import cpw.mods.fml.common.network.FMLIndexedMessageToMessageCodec;
|
|
|
|
|
import cpw.mods.fml.common.network.NetworkRegistry;
|
2014-02-05 22:28:07 +01:00
|
|
|
import cpw.mods.fml.common.network.internal.FMLProxyPacket;
|
2014-02-05 19:06:35 +01:00
|
|
|
import cpw.mods.fml.relauncher.Side;
|
|
|
|
|
import cpw.mods.fml.relauncher.SideOnly;
|
|
|
|
|
|
2014-02-05 22:28:07 +01:00
|
|
|
/**
|
|
|
|
|
* Handles the packet wrangling for IronChest
|
2014-05-11 22:00:59 +02:00
|
|
|
*
|
2014-02-05 22:28:07 +01:00
|
|
|
* @author cpw
|
2014-05-11 22:00:59 +02:00
|
|
|
*
|
2014-02-05 22:28:07 +01:00
|
|
|
*/
|
2014-02-05 19:06:35 +01:00
|
|
|
public enum PacketHandler {
|
2014-05-11 22:00:59 +02:00
|
|
|
INSTANCE;
|
2014-02-05 22:28:07 +01:00
|
|
|
|
2014-05-11 22:00:59 +02:00
|
|
|
/**
|
|
|
|
|
* Our channel "pair" from {@link NetworkRegistry}
|
|
|
|
|
*/
|
|
|
|
|
private EnumMap<Side, FMLEmbeddedChannel> channels;
|
2014-02-05 19:06:35 +01:00
|
|
|
|
2014-05-11 22:00:59 +02:00
|
|
|
/**
|
|
|
|
|
* Make our packet handler, and add an {@link IronChestCodec} always
|
|
|
|
|
*/
|
|
|
|
|
private PacketHandler() {
|
|
|
|
|
// request a channel pair for IronChest from the network registry
|
|
|
|
|
// Add the IronChestCodec as a member of both channel pipelines
|
|
|
|
|
this.channels = NetworkRegistry.INSTANCE.newChannel("IronChest", new IronChestCodec());
|
|
|
|
|
if (FMLCommonHandler.instance().getSide() == Side.CLIENT) {
|
|
|
|
|
addClientHandler();
|
|
|
|
|
}
|
|
|
|
|
}
|
2014-02-05 19:06:35 +01:00
|
|
|
|
2014-05-11 22:00:59 +02:00
|
|
|
/**
|
|
|
|
|
* This is only called on the client side - it adds an
|
|
|
|
|
* {@link IronChestMessageHandler} to the client side pipeline, since the
|
|
|
|
|
* only place we expect to <em>handle</em> messages is on the client.
|
|
|
|
|
*/
|
|
|
|
|
@SideOnly(Side.CLIENT)
|
|
|
|
|
private void addClientHandler() {
|
|
|
|
|
FMLEmbeddedChannel clientChannel = this.channels.get(Side.CLIENT);
|
|
|
|
|
// These two lines find the existing codec (Ironchestcodec) and insert
|
|
|
|
|
// our message handler after it in the pipeline
|
|
|
|
|
String codec = clientChannel.findChannelHandlerNameForType(IronChestCodec.class);
|
|
|
|
|
clientChannel.pipeline().addAfter(codec, "ClientHandler", new IronChestMessageHandler());
|
|
|
|
|
}
|
2014-02-05 19:06:35 +01:00
|
|
|
|
2014-05-11 22:00:59 +02:00
|
|
|
/**
|
|
|
|
|
* This class simply handles the {@link IronChestMessage} when it's received
|
|
|
|
|
* at the client side It can contain client only code, because it's only run
|
|
|
|
|
* on the client.
|
|
|
|
|
*
|
|
|
|
|
* @author cpw
|
|
|
|
|
*
|
|
|
|
|
*/
|
|
|
|
|
private static class IronChestMessageHandler extends SimpleChannelInboundHandler<IronChestMessage> {
|
|
|
|
|
@Override
|
|
|
|
|
protected void channelRead0(ChannelHandlerContext ctx, IronChestMessage msg) throws Exception {
|
|
|
|
|
World world = IronChest.proxy.getClientWorld();
|
|
|
|
|
TileEntity te = world.getTileEntity(msg.x, msg.y, msg.z);
|
|
|
|
|
if (te instanceof TileEntityIronChest) {
|
|
|
|
|
TileEntityIronChest icte = (TileEntityIronChest) te;
|
|
|
|
|
icte.setFacing(msg.facing);
|
|
|
|
|
icte.handlePacketData(msg.type, msg.items);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2014-02-05 22:28:07 +01:00
|
|
|
|
2014-05-11 22:00:59 +02:00
|
|
|
/**
|
|
|
|
|
* This is our "message". In fact, {@link FMLIndexedMessageToMessageCodec}
|
|
|
|
|
* can handle many messages on the same channel at once, using a
|
|
|
|
|
* discriminator byte. But for IronChest, we only need the one message, so
|
|
|
|
|
* we have just this.
|
|
|
|
|
*
|
|
|
|
|
* @author cpw
|
|
|
|
|
*
|
|
|
|
|
*/
|
|
|
|
|
public static class IronChestMessage {
|
|
|
|
|
int x, y, z, type, facing, items[];
|
|
|
|
|
}
|
2014-02-05 22:28:07 +01:00
|
|
|
|
2014-05-11 22:00:59 +02:00
|
|
|
/**
|
|
|
|
|
* This is the codec that automatically transforms the
|
|
|
|
|
* {@link FMLProxyPacket} which wraps the client and server custom payload
|
|
|
|
|
* packets into a message we care about.
|
|
|
|
|
*
|
|
|
|
|
* @author cpw
|
|
|
|
|
*
|
|
|
|
|
*/
|
|
|
|
|
private class IronChestCodec extends FMLIndexedMessageToMessageCodec<IronChestMessage> {
|
|
|
|
|
/**
|
|
|
|
|
* We register our discriminator bytes here. We only have the one type,
|
|
|
|
|
* so we only register one.
|
|
|
|
|
*/
|
|
|
|
|
public IronChestCodec() {
|
|
|
|
|
addDiscriminator(0, IronChestMessage.class);
|
|
|
|
|
}
|
2014-02-05 19:06:35 +01:00
|
|
|
|
2014-05-11 22:00:59 +02:00
|
|
|
@Override
|
|
|
|
|
public void encodeInto(ChannelHandlerContext ctx, IronChestMessage msg, ByteBuf target) throws Exception {
|
|
|
|
|
target.writeInt(msg.x);
|
|
|
|
|
target.writeInt(msg.y);
|
|
|
|
|
target.writeInt(msg.z);
|
|
|
|
|
int typeAndFacing = ((msg.type & 0x0F) | ((msg.facing & 0x0F) << 4)) & 0xFF;
|
|
|
|
|
target.writeByte(typeAndFacing);
|
|
|
|
|
target.writeBoolean(msg.items != null);
|
|
|
|
|
if (msg.items != null) {
|
|
|
|
|
int[] items = msg.items;
|
|
|
|
|
for (int j = 0; j < items.length; j++) {
|
|
|
|
|
int i = items[j];
|
|
|
|
|
target.writeInt(i);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2014-02-05 19:06:35 +01:00
|
|
|
|
2014-05-11 22:00:59 +02:00
|
|
|
@Override
|
|
|
|
|
public void decodeInto(ChannelHandlerContext ctx, ByteBuf dat, IronChestMessage msg) {
|
|
|
|
|
msg.x = dat.readInt();
|
|
|
|
|
msg.y = dat.readInt();
|
|
|
|
|
msg.z = dat.readInt();
|
|
|
|
|
int typDat = dat.readByte();
|
|
|
|
|
msg.type = (byte) (typDat & 0xf);
|
|
|
|
|
msg.facing = (byte) ((typDat >> 4) & 0xf);
|
|
|
|
|
boolean hasStacks = dat.readBoolean();
|
|
|
|
|
msg.items = new int[0];
|
|
|
|
|
if (hasStacks) {
|
|
|
|
|
msg.items = new int[24];
|
|
|
|
|
for (int i = 0; i < msg.items.length; i++) {
|
|
|
|
|
msg.items[i] = dat.readInt();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2014-02-05 19:06:35 +01:00
|
|
|
|
2014-05-11 22:00:59 +02:00
|
|
|
/**
|
|
|
|
|
* This is a utility method called to transform a packet from a custom
|
|
|
|
|
* packet into a "system packet". We're called from
|
|
|
|
|
* {@link TileEntity#getDescriptionPacket()} in this case, but there are
|
|
|
|
|
* others. All network packet methods in minecraft have been adapted to
|
|
|
|
|
* handle {@link FMLProxyPacket} but general purpose objects can't be
|
|
|
|
|
* handled sadly.
|
|
|
|
|
*
|
|
|
|
|
* This method uses the {@link IronChestCodec} to transform a custom packet
|
|
|
|
|
* {@link IronChestMessage} into an {@link FMLProxyPacket} by using the
|
|
|
|
|
* utility method {@link FMLEmbeddedChannel#generatePacketFrom(Object)} on
|
|
|
|
|
* the channel to do exactly that.
|
|
|
|
|
*
|
|
|
|
|
* @param tileEntityIronChest
|
|
|
|
|
* @return
|
|
|
|
|
*/
|
|
|
|
|
public static Packet getPacket(TileEntityIronChest tileEntityIronChest) {
|
|
|
|
|
IronChestMessage msg = new IronChestMessage();
|
|
|
|
|
msg.x = tileEntityIronChest.xCoord;
|
|
|
|
|
msg.y = tileEntityIronChest.yCoord;
|
|
|
|
|
msg.z = tileEntityIronChest.zCoord;
|
|
|
|
|
msg.type = tileEntityIronChest.getType().ordinal();
|
|
|
|
|
msg.facing = tileEntityIronChest.getFacing();
|
|
|
|
|
msg.items = tileEntityIronChest.buildIntDataList();
|
|
|
|
|
return INSTANCE.channels.get(Side.SERVER).generatePacketFrom(msg);
|
|
|
|
|
}
|
|
|
|
|
}
|