I cam across the same problem with my tile entitys when coding my mod, the way to get it to sync is to create your own packets.
To do this I first created a abstract class called IPacket which all my packet classes will extend;
[spoiler=IPacket Class]
import net.minecraft.entity.player.EntityPlayer;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
public abstract class IPacket {
public abstract void encodeInto(ChannelHandlerContext ctx, ByteBuf buffer);
public abstract void decodeInto(ChannelHandlerContext ctx, ByteBuf buffer);
public abstract void handleClientSide(EntityPlayer player);
public abstract void handleServerSide(EntityPlayer player);
}
then from this I created a PacketPipeline class that will handle the packets for me
[spoiler=PacketPipeline Class]
import java.util.*;
import com.sirfatal.adventureplus.Network.Packets.*;
import com.sirfatal.adventureplus.utils.ModInfo;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToMessageCodec;
import net.minecraft.client.Minecraft;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.network.INetHandler;
import net.minecraft.network.NetHandlerPlayServer;
import cpw.mods.fml.common.FMLCommonHandler;
import cpw.mods.fml.common.network.FMLEmbeddedChannel;
import cpw.mods.fml.common.network.FMLOutboundHandler;
import cpw.mods.fml.common.network.NetworkRegistry;
import cpw.mods.fml.common.network.internal.FMLProxyPacket;
import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;
@ChannelHandler.Sharable
public class PacketPipeline extends MessageToMessageCodec<FMLProxyPacket, IPacket> {
private EnumMap<Side, FMLEmbeddedChannel> channels;
private LinkedList<Class<? extends IPacket>> packets = new LinkedList<Class<? extends IPacket>>();
private boolean isPostInitialised = false;
/**
* Register your packet with the pipeline. Discriminators are automatically
* set.
*
* @param clazz
* the class to register
*
* @return whether registration was successful. Failure may occur if 256
* packets have been registered or if the registry already contains
* this packet
*/
public boolean registerPacket(Class<? extends IPacket> clazz) {
if (this.packets.size() > 256) {
// You should log here!!
return false;
}
if (this.packets.contains(clazz)) {
// You should log here!!
return false;
}
if (this.isPostInitialised) {
// You should log here!!
return false;
}
this.packets.add(clazz);
return true;
}
// In line encoding of the packet, including discriminator setting
@Override
protected void encode(ChannelHandlerContext ctx, IPacket msg, List<Object> out)
throws Exception {
ByteBuf buffer = Unpooled.buffer();
Class<? extends IPacket> clazz = msg.getClass();
if (!this.packets.contains(msg.getClass())) {
throw new NullPointerException("No Packet Registered for: "
+ msg.getClass().getCanonicalName());
}
byte discriminator = (byte) this.packets.indexOf(clazz);
buffer.writeByte(discriminator);
msg.encodeInto(ctx, buffer);
FMLProxyPacket proxyPacket = new FMLProxyPacket(buffer.copy(), ctx.channel()
.attr(NetworkRegistry.FML_CHANNEL).get());
out.add(proxyPacket);
}
// In line decoding and handling of the packet
@Override
protected void decode(ChannelHandlerContext ctx, FMLProxyPacket msg, List<Object> out)
throws Exception {
ByteBuf payload = msg.payload();
byte discriminator = payload.readByte();
Class<? extends IPacket> clazz = this.packets.get(discriminator);
if (clazz == null) {
throw new NullPointerException("No packet registered for discriminator: "
+ discriminator);
}
IPacket pkt = clazz.newInstance();
pkt.decodeInto(ctx, payload.slice());
EntityPlayer player;
switch (FMLCommonHandler.instance().getEffectiveSide()) {
case CLIENT:
player = this.getClientPlayer();
pkt.handleClientSide(player);
break;
case SERVER:
INetHandler netHandler = ctx.channel().attr(NetworkRegistry.NET_HANDLER).get();
player = ((NetHandlerPlayServer) netHandler).playerEntity;
pkt.handleServerSide(player);
break;
default:
}
out.add(pkt);
}
// Method to call from FMLInitializationEvent
public void initialise() {
this.channels = NetworkRegistry.INSTANCE.newChannel(ModInfo.CHANNEL, this);
registerPackets();
}
public void registerPackets() {
//registerPacket(PACKETFILENAME.class);
}
// Method to call from FMLPostInitializationEvent
// Ensures that packet discriminators are common between server and client
// by using logical sorting
public void postInitialise() {
if (this.isPostInitialised) {
return;
}
this.isPostInitialised = true;
Collections.sort(this.packets, new Comparator<Class<? extends IPacket>>() {
@Override
public int compare(Class<? extends IPacket> clazz1, Class<? extends IPacket> clazz2) {
int com = String.CASE_INSENSITIVE_ORDER.compare(clazz1.getCanonicalName(),
clazz2.getCanonicalName());
if (com == 0) {
com = clazz1.getCanonicalName().compareTo(clazz2.getCanonicalName());
}
return com;
}
});
}
@SideOnly(Side.CLIENT)
private EntityPlayer getClientPlayer() {
return Minecraft.getMinecraft().thePlayer;
}
/**
* Send this message to everyone.
* <p/>
* Adapted from CPW's code in
* cpw.mods.fml.common.network.simpleimpl.SimpleNetworkWrapper
*
* @param message
* The message to send
*/
public void sendToAll(IPacket message) {
this.channels.get(Side.SERVER).attr(FMLOutboundHandler.FML_MESSAGETARGET)
.set(FMLOutboundHandler.OutboundTarget.ALL);
this.channels.get(Side.SERVER).writeAndFlush(message);
}
/**
* Send this message to the specified player.
* <p/>
* Adapted from CPW's code in
* cpw.mods.fml.common.network.simpleimpl.SimpleNetworkWrapper
*
* @param message
* The message to send
* @param player
* The player to send it to
*/
public void sendTo(IPacket message, EntityPlayerMP player) {
this.channels.get(Side.SERVER).attr(FMLOutboundHandler.FML_MESSAGETARGET)
.set(FMLOutboundHandler.OutboundTarget.PLAYER);
this.channels.get(Side.SERVER).attr(FMLOutboundHandler.FML_MESSAGETARGETARGS).set(player);
this.channels.get(Side.SERVER).writeAndFlush(message);
}
/**
* Send this message to everyone within a certain range of a point.
* <p/>
* Adapted from CPW's code in
* cpw.mods.fml.common.network.simpleimpl.SimpleNetworkWrapper
*
* @param message
* The message to send
* @param point
* The
* {@link cpw.mods.fml.common.network.NetworkRegistry.TargetPoint}
* around which to send
*/
public void sendToAllAround(IPacket message, NetworkRegistry.TargetPoint point) {
this.channels.get(Side.SERVER).attr(FMLOutboundHandler.FML_MESSAGETARGET)
.set(FMLOutboundHandler.OutboundTarget.ALLAROUNDPOINT);
this.channels.get(Side.SERVER).attr(FMLOutboundHandler.FML_MESSAGETARGETARGS).set(point);
this.channels.get(Side.SERVER).writeAndFlush(message);
}
/**
* Send this message to everyone within the supplied dimension.
* <p/>
* Adapted from CPW's code in
* cpw.mods.fml.common.network.simpleimpl.SimpleNetworkWrapper
*
* @param message
* The message to send
* @param dimensionId
* The dimension id to target
*/
public void sendToDimension(IPacket message, int dimensionId) {
this.channels.get(Side.SERVER).attr(FMLOutboundHandler.FML_MESSAGETARGET)
.set(FMLOutboundHandler.OutboundTarget.DIMENSION);
this.channels.get(Side.SERVER).attr(FMLOutboundHandler.FML_MESSAGETARGETARGS)
.set(dimensionId);
this.channels.get(Side.SERVER).writeAndFlush(message);
}
/**
* Send this message to the server.
* <p/>
* Adapted from CPW's code in
* cpw.mods.fml.common.network.simpleimpl.SimpleNetworkWrapper
*
* @param message
* The message to send
*/
public void sendToServer(IPacket message) {
this.channels.get(Side.CLIENT).attr(FMLOutboundHandler.FML_MESSAGETARGET)
.set(FMLOutboundHandler.OutboundTarget.TOSERVER);
this.channels.get(Side.CLIENT).writeAndFlush(message);
}
}
In the register packet function you will want to put all the packets you want to register for example
registerPacket(PacketUpdateTE.class);
Next you want to setup your packet class for that tileentity, it will take in 3 parameters and also any other parameters you want to set, for example valueToSet can be whatever you want just make sure you register all your packet classes inside the packetpipeline.
[spoiler=Packet TileEntity Class]
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.world.World;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
public class PacketTileTE extends IPacket {
int xPos, yPos, zPos, dimension;
int valueToSet;
public PacketTileTE() {
}
public PacketTileTE(int dimension, int xPos, int yPos, int zPos, int valueToSet) {
this.dimension = dimension;
this.xPos = xPos;
this.yPos = yPos;
this.zPos = zPos;
this.valueToSet = valueToSet;
}
@Override
public void encodeInto(ChannelHandlerContext ctx, ByteBuf buffer) {
buffer.writeInt(xPos);
buffer.writeInt(yPos);
buffer.writeInt(zPos);
buffer.writeInt(valueToSet);
}
@Override
public void decodeInto(ChannelHandlerContext ctx, ByteBuf buffer) {
xPos = buffer.readInt();
yPos = buffer.readInt();
zPos = buffer.readInt();
x = buffer.readInt();
}
@Override
public void handleClientSide(EntityPlayer player) {
}
@Override
public void handleServerSide(EntityPlayer player) {
World world = player.worldObj;
TileEntity te = world.getTileEntity(xPos, yPos, zPos);
if (te instanceof TILE) {
NBTTagCompound data = new NBTTagCompound();
((YOURTileEntity) te).setVALUE(valueToSet);
((eventTileEntity) te).writeToNBT(data);
packetPipeline.sendToAll(new PacketUpdateTE(xPos, yPos, zPos, data));
}
}
}
The last class you will want to make is the PacketUpdateTE. This will just update you tile entity on the client side and can be used by multiple packet tile entity classes.
[spoiler=PacketUpdateTE]
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.network.PacketBuffer;
import net.minecraft.tileentity.TileEntity;
import com.sirfatal.adventureplus.Network.IPacket;
public class PacketUpdateTE extends IPacket {
private int xPos, yPos, zPos;
private NBTTagCompound data;
public PacketUpdateTE() {
}
public PacketUpdateTE(int xPos, int yPos, int zPos, NBTTagCompound data) {
this.xPos = xPos;
this.yPos = yPos;
this.zPos = zPos;
this.data = data;
}
@Override
public void encodeInto(ChannelHandlerContext ctx, ByteBuf buffer) {
PacketBuffer pckBuff = new PacketBuffer(buffer);
pckBuff.writeInt(xPos);
pckBuff.writeShort(yPos);
pckBuff.writeInt(zPos);
try {
pckBuff.writeNBTTagCompoundToBuffer(data);
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void decodeInto(ChannelHandlerContext ctx, ByteBuf buffer) {
PacketBuffer pckBuff = new PacketBuffer(buffer);
xPos = pckBuff.readInt();
yPos = pckBuff.readShort();
zPos = pckBuff.readInt();
try {
data = pckBuff.readNBTTagCompoundFromBuffer();
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void handleClientSide(EntityPlayer player) {
TileEntity te = player.worldObj.getTileEntity(xPos, yPos, zPos);
if (te != null) {
te.readFromNBT(data);
}
}
@Override
public void handleServerSide(EntityPlayer player) {
}
}
The final things you want to do is in your main mod class initialise the packet pipeline
public static final PacketPipeline packetPipeline = new PacketPipeline();
@EventHandler
public void initialise(FMLInitializationEvent evt) {
packetPipeline.initialise();
}
@EventHandler
public void postInitialise(FMLPostInitializationEvent evt) {
packetPipeline.postInitialise();
}
And also in your entity class where you want the sync to happen put
packetPipeline.sendToServer(new PacketENTITYTE(
this.worldObj.provider.dimensionId, this.xCoord, this.yCoord, this.zCoord, VALUE));
If you want some more help just ask and also all this information can be found in the Netty Packet Tutorial on the forums HERE
-SirFatal