So I've been working on a 1.7.10 mod recently and I've had to adapt to some new methods. I've read some tutorials on this subject and googled just about everything I can think of to try and figure this out, but to no avail. What appears to be happening in my program is that while I have the ability to send packets from the Client to the Server, I do not have the ability to send packets from the Server to the Client. This is very confusing. As far as I can tell I have set everything up in the correct fashion for Server to Client packets to be possible. Let's take a look at some code. I'll be truncating irrelevant bits to save space.
The main mod class. The important thing here is that I create and store the SimpleNetworkWrapper here in the preInit() method.
@Mod(modid = ProjectAlchemy.ID, version = ProjectAlchemy.VERSION)
public class ProjectAlchemy
{
public static final String ID = "Project_Alchemy";
public static final String VERSION = "Alpha_0.0.0.1";
public static SimpleNetworkWrapper channel;
@Instance("Project_Alchemy")
public static ProjectAlchemy INSTANCE = new ProjectAlchemy();
//public static Logger log = Logger.getLogger("Project_Alchemy", ProjectAlchemy.class);
@SidedProxy(clientSide = "pa.main.CommonProxyClient", serverSide = "pa.main.CommonProxy")
public static CommonProxy proxy = new CommonProxy();
@EventHandler
public void preInit(FMLPreInitializationEvent event)
{
channel = NetworkRegistry.INSTANCE.newSimpleChannel(ID);
proxy.preInit(event.getModConfigurationDirectory(), this);
}
}
This code registers the messages. It's in a different file at the moment, but I've been moving it around. It's worked exactly the same in any location.
protected void registerPackets()
{
ProjectAlchemy.channel.registerMessage(PacketClipButton.Handler.class, PacketClipButton.class,
PacketIDs.CLIP_BUTTON, Side.SERVER);
ProjectAlchemy.channel.registerMessage(PacketClipNEI.Handler.class, PacketClipNEI.class,
PacketIDs.CLIP_NEI, Side.SERVER);
ProjectAlchemy.channel.registerMessage(PacketClipOpen.Handler.class, PacketClipOpen.class,
PacketIDs.CLIP_OPEN, Side.SERVER);
ProjectAlchemy.channel.registerMessage(PacketRename.Handler.class, PacketRename.class,
PacketIDs.RENAME, Side.SERVER);
ProjectAlchemy.channel.registerMessage(PacketMachineAccess.Handler.class, PacketMachineAccess.class,
PacketIDs.MACHINE_ACCESS, Side.SERVER);
ProjectAlchemy.channel.registerMessage(PacketPowerupSync.Handler.class, PacketPowerupSync.class,
PacketIDs.LEAF_SYNC, Side.CLIENT);
ProjectAlchemy.channel.registerMessage(PacketLeafFlutter.Handler.class, PacketLeafFlutter.class,
PacketIDs.LEAF_FLUTTER, Side.SERVER);
}
CommonProxy houses the actual method that I call to send packets.
public class CommonProxy
{
public void sendPacket(DartPacket packet)
{
System.out.println("Packet: " + packet.toString());
if (packet != null && packet.getToClient())
{
if (packet.isDimPacket())
{
ProjectAlchemy.channel.sendToDimension(packet, packet.getDimID());
//System.out.println("Send packet to dim: " + packet.getDimID() + ", " + packet.toString() + ", ");
} else if (packet.getLocation() != null)
{
ProjectAlchemy.channel.sendToAllAround(packet, packet.getLocation());
}else if (packet.getReceiver() != null)
{
EntityPlayer receiver = EntityUtils.getPlayerByName(packet.getReceiver());
ProjectAlchemy.channel.sendTo(packet, (EntityPlayerMP)receiver);
}
}
}
public boolean isSimulating(World world)
{
return true;
}
}
CommonProxyClient has the client-side version of the previous method.:
public class CommonProxyClient extends CommonProxy
{
@Override
public boolean isSimulating(World world)
{
return (world != null) ? !world.isRemote : false;
}
@Override
public void sendPacket(DartPacket packet)
{
//super.sendPacket(packet);
if (packet != null && !packet.getToClient())
ProjectAlchemy.channel.sendToServer(packet);
}
}
My custom Packet base, DartPacket:
public abstract class DartPacket implements IMessage
{
protected String receiver;
protected int dimensionID;
protected TargetPoint point;
public DartPacket() {}
public abstract boolean getToClient();
public abstract boolean isDimPacket();
public int getDimID()
{
return dimensionID;
}
public String getReceiver()
{
return receiver;
}
public TargetPoint getLocation()
{
return point;
}
@Override
public void fromBytes(ByteBuf buf)
{
try
{
if (isDimPacket())
dimensionID = buf.readByte();
int nameSize = (int)buf.readByte();
if (nameSize > 0)
{
this.receiver = "";
for (int i = 0; i < nameSize; i ++)
receiver += buf.readChar();
}
if (buf.readBoolean())
this.point = new TargetPoint(buf.readInt(), buf.readDouble(),
buf.readDouble(), buf.readDouble(), buf.readDouble());
} catch (Exception e) { DebugUtils.printError(e); }
}
@Override
public void toBytes(ByteBuf buf)
{
if (receiver == null)
receiver = "";
try
{
if (isDimPacket())
buf.writeByte(dimensionID);
buf.writeByte(receiver != null ? receiver.length() : 0);
for (int i = 0; i < receiver.length(); i ++)
buf.writeChar(receiver.charAt(i));
buf.writeBoolean(point != null);
if (point != null)
{
buf.writeInt(point.dimension);
buf.writeDouble(point.x);
buf.writeDouble(point.y);
buf.writeDouble(point.z);
buf.writeDouble(point.range);
}
} catch (Exception e) { DebugUtils.printError(e); }
}
}
The Packet in question:
public class PacketPowerupSync extends DartPacket
{
private boolean hasLeaf;
public PacketPowerupSync() {}
public PacketPowerupSync(EntityPlayer player)
{
hasLeaf = EntityUtils.hasLeaf(player);
receiver = player.getCommandSenderName();
this.dimensionID = player.worldObj.provider.dimensionId;
}
@Override
public boolean getToClient() { return true; }
@Override
public boolean isDimPacket() { return true; }
@Override
public void toBytes(ByteBuf buf)
{
super.toBytes(buf);
buf.writeBoolean(hasLeaf);
}
@Override
public void fromBytes(ByteBuf buf)
{
super.fromBytes(buf);
hasLeaf = buf.readBoolean();
}
public static class Handler implements IMessageHandler<PacketPowerupSync, IMessage>
{
//@SideOnly(Side.CLIENT)
@Override
public IMessage onMessage(PacketPowerupSync message, MessageContext ctx)
{
EntityPlayer player = EntityUtils.getPlayerByName(message.receiver);
System.out.println("Packet received.");
if (player != null)
{
System.out.println("Player not null: " + player.getCommandSenderName() + " Side: " + ProjectAlchemy.proxy.isSimulating(player.worldObj));
System.out.println("Leaf: " + message.hasLeaf);
if (message.hasLeaf)
EntityUtils.giveLeaf(player);
else
EntityUtils.takeLeaf(player);
}
return null;
}
}
}
I call the common proxy's sendPacket(DartPacket) method to send a packet from wherever I need to. The custom packet base I use forces me to specify manually in each packet I create what type it is. I do this so that I can simply call one method and pass the packet for ease of use and extensibility.
I've been trying to debug this for the past two days, so I've tried a great deal of other permutations for this setup. I've tried manually calling channel.sendToAll(), channel.sendToAllAround(), channel.setToDimension() both through and not through the proxy as well as on the server and on the client just in case. There seems to be no iteration of this where the packet actually reaches the client.
Here's what I do know: the server is properly calling and creating the packet to send to the client. However it simply just does not reach. Also, if I allow the client proxy to call its super's method (which I did for testing purposes) it will somehow send the packet from the server to the server. At that point the logic seems to work properly and set the data on the server that the server just attempted to send to the client. Neat! But not entirely useful...
I hope to Giygas I'm missing something simple, but I just can't mess with this anymore - I'm getting nowhere. Thank you for any help you can provide.