Jump to content
View in the app

A better way to browse. Learn more.

Forge Forums

A full-screen app on your home screen with push notifications, badges and more.

To install this app on iOS and iPadOS
  1. Tap the Share icon in Safari
  2. Scroll the menu and tap Add to Home Screen.
  3. Tap Add in the top-right corner.
To install this app on Android
  1. Tap the 3-dot menu (⋮) in the top-right corner of the browser.
  2. Tap Add to Home screen or Install app.
  3. Confirm by tapping Install.

Featured Replies

Posted

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.
}
}

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.

  • 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;
}
}

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);

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()

  • 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);

  • 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.

  • 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.

  • 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;
}
}

  • 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.

  • 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.

  • 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.

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.

Guest
Unfortunately, your content contains terms that we do not allow. Please edit your content to remove the highlighted words below.
Reply to this topic...

Important Information

By using this site, you agree to our Terms of Use.

Configure browser push notifications

Chrome (Android)
  1. Tap the lock icon next to the address bar.
  2. Tap Permissions → Notifications.
  3. Adjust your preference.
Chrome (Desktop)
  1. Click the padlock icon in the address bar.
  2. Select Site settings.
  3. Find Notifications and adjust your preference.