Posted May 10, 20169 yr I am having trouble syncing Capabilities. So in PlayerEvent.Clone I set a field in a capability. This field change in a capability causes it to send data to the client (if logically on the server) using my packets. However, I must be doing something wrong, because it isn't changing. Here is my message handler (it is intended solely for the logical client): public class ResearchMessageHandler implements IMessageHandler<ResearchMessage, IMessage> { @Override public IMessage onMessage(ResearchMessage message, MessageContext ctx) { EntityPlayer player = Minecraft.getMinecraft().thePlayer; if (player.hasCapability(CommonProxy.RESEARCH_CAP, null)) //This is true { IPlayerResearchCapability cap = player.getCapability(CommonProxy.RESEARCH_CAP, null); cap.setResearchStateNoCheck(null, message.research, message.state); //This works successfully. } return null; //Here it still works. But after here the changes mysteriously vanish. } }
May 10, 20169 yr http://greyminecraftcoder.blogspot.com.au/2015/01/thread-safety-with-network-messages.html Additionally, idk if Clone event allows syncing player cloned with himself (his client). Player clonning happens e.g when you respawn, and in that moment server has two players (old and new), and client has only old. Sending data about new player while client didn't spwn him yet kills updates. Thread safety MIGHT solve this (but I am not sure). What I am onto - Clone event should never be used to sync data. Use EntityJoinedWorldEvent - it is called always when you join world and is best for syncing initial data. 1.7.10 is no longer supported by forge, you are on your own.
May 10, 20169 yr Author When the packet arrives the player has not yet respawned - resulting in a null pointer exception.
May 10, 20169 yr Author As it turns out it was succeeding because of a bad if-statement. Same scenario. public class ResearchMessageHandler implements IMessageHandler<ResearchMessage, IMessage> { @Override public IMessage onMessage(final ResearchMessage message, MessageContext ctx) { Minecraft.getMinecraft().addScheduledTask(new Runnable() { @Override public void run() { EntityPlayer player = Minecraft.getMinecraft().thePlayer; if (player.hasCapability(CommonProxy.RESEARCH_CAP, null)) { IPlayerResearchCapability cap = player.getCapability(CommonProxy.RESEARCH_CAP, null); cap.setResearchState(null, message.research, message.state); } } }); return null; } }
May 10, 20169 yr Where are you sending the packet from? Show that code, too. Btw, you should not be using Minecraft.getMinecraft() directly - use your proxies: // CommonProxy /** * Returns a side-appropriate EntityPlayer for use during message handling */ public EntityPlayer getPlayerEntity(MessageContext ctx) { return ctx.getServerHandler().playerEntity; } /** * Returns the current thread based on side during message handling, * used for ensuring that the message is being handled by the main thread */ public IThreadListener getThreadFromContext(MessageContext ctx) { return ctx.getServerHandler().playerEntity.getServerForPlayer(); } // ClientProxy: @Override public EntityPlayer getPlayerEntity(MessageContext ctx) { return (ctx.side.isClient() ? mc.thePlayer : super.getPlayerEntity(ctx)); } @Override public IThreadListener getThreadFromContext(MessageContext ctx) { return (ctx.side.isClient() ? mc : super.getThreadFromContext(ctx)); } // message code: YourMod.proxy.getThreadFromContext(ctx).addScheduledTask(... EntityPlayer player = YourMod.proxy.getPlayerEntity(ctx); http://i.imgur.com/NdrFdld.png[/img]
May 10, 20169 yr To be honest it is okay to use it directly in netty context, because if you have a packet that you send from server to client side you always know that you are safe to use Minecraft.getMinecraft()
May 11, 20169 yr Author The sending of the message is complicated. The code which initiates the sending of the message is some test code in an EntityJoinWorldEvent, which ensures that the logical side is SERVER. The part which actually sends the code is: NETWORK_WRAPPER.sendTo(new ResearchMessage(research, state), (EntityPlayerMP)player);
May 11, 20169 yr Author I think I may need to do this in reverse, use EntityJoinWorldEvent on the client to request that the data be sent. I should be able to do that, if I make it serializable.
May 11, 20169 yr Author - Preemptive Bug Fixing Stuff - Thanks! I was going to ask about this once I had fixed the bugs, but its good to know in advance.
May 11, 20169 yr Author I am having another issue: I am having the client send a request to the server, and the server is supposed to respond with a response message. However, it then proceeds to crash. For some reason, the request message is being re-processed (I think) on the incorrect side (I think). I have no idea what is happening. package com.phantasma.phantasma.network; import io.netty.buffer.ByteBuf; import net.minecraftforge.fml.common.FMLCommonHandler; import net.minecraftforge.fml.common.network.simpleimpl.IMessage; public class RequestMessage implements IMessage { public RequestType type; public RequestMessage() { } public RequestMessage(RequestType type) { this.type = type; } @Override public void fromBytes(ByteBuf buf) { int ordinal = buf.readInt(); //java.lang.IndexOutOfBoundsException: readerIndex(0) + length(4) exceeds writerIndex(2): SlicedByteBuf(ridx: 0, widx: 2, cap: 2/2, unwrapped: UnpooledHeapByteBuf(ridx: 0, widx: 3, cap: 256)) this.type = RequestType.values()[ordinal]; } @Override public void toBytes(ByteBuf buf) { int ordinal = this.type.ordinal(); buf.writeInt(ordinal); } public static enum RequestType { RESEARCH } } package com.phantasma.phantasma.network; import com.phantasma.phantasma.Phantasma; import com.phantasma.phantasma.network.RequestMessage.RequestType; import net.minecraft.entity.player.EntityPlayer; 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; public class RequestMessageHandler implements IMessageHandler<RequestMessage, IMessage> { @Override public IMessage onMessage(RequestMessage message, MessageContext ctx) { if (ctx.side == Side.SERVER) { EntityPlayer player = Phantasma.proxy.getEntityPlayer(ctx); switch(message.type) { case RESEARCH: { return new ResearchMessage(player.getCapability(Phantasma.RESEARCH_CAP, null).serialize()); } } } return null; } }
May 11, 20169 yr Author This is why I need to stop using literals as unique ids... As it turns out I had registered both my messages under the same id. I am now using a counter and incrementing.
May 11, 20169 yr Author You have not implemented the thread-safety in your server handler. And using a request message here is pointless, just push the message out from the server without request when the player logs in (PlayerLoggedInEvent). Whenever I respawn I would lose all the capability data, unless there is an event I am missing.
May 11, 20169 yr PlayerEvent.Clone, but you shouldn't send packets from there; instead, use EntityJoinWorldEvent (or possibly RespawnEvent, though I've never tried that one) if you need to sync data after player death and respawn. http://i.imgur.com/NdrFdld.png[/img]
May 11, 20169 yr Author PlayerEvent.Clone, but you shouldn't send packets from there; instead, use EntityJoinWorldEvent (or possibly RespawnEvent, though I've never tried that one) if you need to sync data after player death and respawn. PlayerEvent.Clone was not working on the client thread, and EntityJoinWorldEvent was not working for sending from the server thread, for some reason.
May 11, 20169 yr PlayerEvent.Clone Is called ONLY on server and can be used to copy server data from dead player to new player. Then when new player joins (after respawn) you can send packet from EntityJoinWorldEvent to update client-side NEW player. It WILL work if you use thread safety, which was alredy pointed out. 1.7.10 is no longer supported by forge, you are on your own.
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.