Jump to content

(Solved) Packet not sending properly when in SinglePlayer.


Recommended Posts

Posted (edited)

I have a network packet that syncs all the player data from a custom capability from server to client when the player logs in. On a server this works properly every time. In SinglePlayer the data syncs inconsistently (Sometimes it syncs, sometimes it doesn't).

	@SubscribeEvent
	public void onPlayerLogin(PlayerLoggedInEvent event)
	{
		EntityPlayer player = event.player;
		IPlayerData playerData = PlayerDataProvider.getPlayerCapability(player);

		MagicMastery.network.sendTo(new MessageSyncAllPlayerData(playerData), (EntityPlayerMP) player);
	}

 

The weird thing is, when I put a breakpoint on this line:

MagicMastery.network.sendTo(new MessageSyncAllPlayerData(playerData), (EntityPlayerMP) player);

The game halts because of the breakpoint of course, so I click resume, and it syncs properly every time. 

It seems the CombinedClient needs a second, or even half a second, to properly send/load/or whatever for this packet to work properly. I think this because it works on the server every time, and it takes the server some time to send the data to the player about the world already, so this gives my message a chance to work as well. Also when I put the breakpoint, the game pauses when it gets to the breakpoint until I click resume, giving the message time to work properly.

I need this to sync properly on login because I have a levitation spell that allows the player to float around, and if they are floating when they log off they need to still be floating when they log back in so they don't fall.

I could get around this by syncing the isLevitating data on player tick, but the other data won't be synced properly still. I could then sync all the other player data every 5 seconds or so but this seems unnecessary. I should really only sync the data when the player logs in and then whenever anything is changed. 

Is there an event that takes place about a second or more after PlayerLoggedInEvent that doesn't happen too often where I can send the packet to sync all the data.

Ugh, it's so weird this works perfectly on a server but not in SinglePlayer. It's usually the other way around lol.

 

UPDATE: I seem to have fixed the issue by doing this:

	@SubscribeEvent
	public void onPlayerLogin(PlayerLoggedInEvent event) throws InterruptedException
	{
		if (MagicMastery.proxy instanceof CombinedClientProxy)
		{
			Thread.sleep(200);
		}
		
		EntityPlayer player = event.player;
		IPlayerData playerData = PlayerDataProvider.getPlayerCapability(player);

		MagicMastery.network.sendTo(new MessageSyncAllPlayerData(playerData), (EntityPlayerMP) player);
	}

 

 

SOLVED:

		@Override
		public IMessage onMessage(MessageSyncAllPlayerData message, MessageContext ctx)
		{
			//final EntityPlayer player = MagicMastery.proxy.getEntityPlayer(ctx);
			//final IPlayerData serverData = message.getData();
			
			MagicMastery.proxy.getThreadListener(ctx).addScheduledTask(() ->
			{
            			// The finals need to go in here
            			final EntityPlayer player = MagicMastery.proxy.getEntityPlayer(ctx);
				final IPlayerData serverData = message.getData();
              
				if (player != null && serverData != null)
				{

 

Edited by Kriptikz
Solved
Posted
19 minutes ago, Jay Avery said:

Post your packet and handler classes. Do you use Minecraft#addScheduledTask to process the message?

yes, I do use Minecraft#addScheduledTask

public class MessageSyncAllPlayerData implements IMessage
{
	private IPlayerData data = new PlayerData();
	
	public MessageSyncAllPlayerData()
	{
	}
	
	public MessageSyncAllPlayerData(IPlayerData playerData)
	{
		this.data = playerData;
	}

	@Override
	public void fromBytes(ByteBuf buf)
	{
		if (this.data != null)
		{
			this.data.setIsLevitating(buf.readBoolean());
			this.data.setMana(buf.readFloat());
			this.data.setMaxMana(buf.readFloat());
			this.data.setPlayerLevel(buf.readInt());
			this.data.setPlayerXp(buf.readInt());
			this.data.setPlayerCurrentLevelMaxXp(buf.readInt());
			this.data.setShouldPlayerGainXp(buf.readBoolean());
			this.data.setManaRegenPerSecond(buf.readFloat());
			this.data.setSelectedSpell(buf.readInt());
			
			for (int i = 0; i < IPlayerData.NUMBER_OF_SPELLS; i++)
			{
				readSpellArray(buf, i);			
			}
			
		}
	}

	@Override
	public void toBytes(ByteBuf buf)
	{
		if (this.data != null)
		{
			buf.writeBoolean(this.data.getIsLevitating());
			buf.writeFloat(this.data.getMana());
			buf.writeFloat(this.data.getMaxMana());
			buf.writeInt(this.data.getPlayerLevel());
			buf.writeInt(this.data.getPlayerXp());
			buf.writeInt(this.data.getPlayerCurrentLevelMaxXp());
			buf.writeBoolean(this.data.getShouldPlayerGainXp());
			buf.writeFloat(this.data.getManaRegenPerSecond());
			buf.writeInt(this.data.getSelectedSpell());

			for (int i = 0; i < IPlayerData.NUMBER_OF_SPELLS; i++)
			{
				writeSpellArray(buf, this.data.getSpellFromId(i));				
			}
			
		}
	}
	
	public void setData(IPlayerData data)
	{
		this.data = data;
	}
	
	public IPlayerData getData()
	{
		return this.data;
	}
	
	public void writeSpellArray(ByteBuf buf, int[] array)
	{
		for (int i = 0; i < 4; i++)
		{
			buf.writeInt(array[i]);
		}
	}
	
	public void readSpellArray(ByteBuf buf,int spellId)
	{
		int [] array = new int[4];
		
		for (int i = 0; i < 4; i++)
		{
			array[i] = buf.readInt();
		}
		
		this.data.setSpellFromId(spellId, array);

	}
	
	public static class MessageHandler implements IMessageHandler<MessageSyncAllPlayerData, IMessage>
	{

		@Override
		public IMessage onMessage(MessageSyncAllPlayerData message, MessageContext ctx)
		{
			final EntityPlayer player = MagicMastery.proxy.getEntityPlayer(ctx);
			final IPlayerData serverData = message.getData();
			
			MagicMastery.proxy.getThreadListener(ctx).addScheduledTask(() ->
			{
				if (player != null && serverData != null)
				{
					IPlayerData clientData = PlayerDataProvider.getPlayerCapability(player);
					
					if (clientData != null && serverData != null)
					{
						clientData.setIsLevitating(serverData.getIsLevitating());
						clientData.setMana(serverData.getMana());
						clientData.setMaxMana(serverData.getMaxMana());
						clientData.setPlayerLevel(serverData.getPlayerLevel());
						clientData.setPlayerXp(serverData.getPlayerXp());
						clientData.setPlayerCurrentLevelMaxXp(serverData.getPlayerCurrentLevelMaxXp());
						clientData.setShouldPlayerGainXp(serverData.getShouldPlayerGainXp());
						clientData.setManaRegenPerSecond(serverData.getManaRegenPerSecond());
						clientData.setSelectedSpell(serverData.getSelectedSpell());
						
						for (int i = 0; i < IPlayerData.NUMBER_OF_SPELLS; i++)
						{
							clientData.setSpellFromId(i, serverData.getSpellFromId(i));
						}
					}
				}
			});
			
			return null;
		}
		
	}

}

 

Posted
7 hours ago, diesieben07 said:

data cannot possibly contain a value inside fromBytes. fromBytes is called after your message class has been constructed using the no-argument constructor, you must fill the fields in this method.

They all have default values set in my PlayerData class, shouldn't this line create the object with all the default values:

private IPlayerData data = new PlayerData();

Here is some of my PlayerData:

public class PlayerData implements IPlayerData
{
	private int ticksStunned;
	private boolean isStunned = false;
	private int stunDuration = 20;
	private boolean isLevitating = false;
	
	// levitation amp of 5 is hovering, <5 goes down, >5 goes up.
	private int levitationAmp = 5;
	
	private float mana = 0;
	private float maxMana = 150;
	private int playerLevel = 1;
	private int playerXp = 0;
	private int playerCurrentLevelMaxXp = 100;
	private boolean shouldPlayerGainXp = true;
	private float manaRegenPerSecond = 0.5F;
	private int selectedSpell = 0;

 

Also, I got rid of the null check and the inconsistent sync was still a problem without:

		if (MagicMastery.proxy instanceof CombinedClientProxy)
		{
			Thread.sleep(200);
		}

 

Is using Thread.sleep here ok? It should only do that in SinglePlayer as well.

Posted
22 minutes ago, diesieben07 said:

No, Thread.sleep is a terrible idea to solve a thread inconsistency. Where did you put that code?

	@SubscribeEvent
	public void onPlayerLogin(PlayerLoggedInEvent event) throws InterruptedException
	{
		if (MagicMastery.proxy instanceof CombinedClientProxy)
		{
			Thread.sleep(200);
		}
		
		EntityPlayer player = event.player;
		IPlayerData playerData = PlayerDataProvider.getPlayerCapability(player);

		MagicMastery.network.sendTo(new MessageSyncAllPlayerData(playerData), (EntityPlayerMP) player);
	}

 

Posted (edited)
26 minutes ago, diesieben07 said:

Yeah, that's a terrible idea, don't do that.

Feelsbadman :(  What can go wrong with it?

This is only a problem with SinglePlayer, when connecting to a dedicated server it works fine. There just needs to be at least a 200 millisecond delay when in SinglePlayer in order for the message to work and the data to sync.

Is there a proper way to make the game wait at least 200 ms, only when in SinglePlayer?

Edited by Kriptikz
Posted
6 minutes ago, diesieben07 said:

The proper way is to figure out why that 200ms delay fixes it and then fix that bug.

Ok, I'm going to create a testmod where I create a very simple capability and a message to sync the data to client and see if this is still an issue.

Posted

Solved, I had to move the finals into addScheduledTask

This:


		@Override
		public IMessage onMessage(MessageSyncAllPlayerData message, MessageContext ctx)
		{
			final EntityPlayer player = MagicMastery.proxy.getEntityPlayer(ctx);
			final IPlayerData serverData = message.getData();
			
			MagicMastery.proxy.getThreadListener(ctx).addScheduledTask(() ->
			{
				if (player != null && serverData != null)
				{
					IPlayerData clientData = PlayerDataProvider.getPlayerCapability(player);
					
					if (clientData != null && serverData != null)
					{
						clientData.setIsLevitating(serverData.getIsLevitating());
						clientData.setMana(serverData.getMana());
						clientData.setMaxMana(serverData.getMaxMana());
						clientData.setPlayerLevel(serverData.getPlayerLevel());
						clientData.setPlayerXp(serverData.getPlayerXp());
						clientData.setPlayerCurrentLevelMaxXp(serverData.getPlayerCurrentLevelMaxXp());
						clientData.setShouldPlayerGainXp(serverData.getShouldPlayerGainXp());
						clientData.setManaRegenPerSecond(serverData.getManaRegenPerSecond());
						clientData.setSelectedSpell(serverData.getSelectedSpell());
						
						for (int i = 0; i < IPlayerData.NUMBER_OF_SPELLS; i++)
						{
							clientData.setSpellFromId(i, serverData.getSpellFromId(i));
						}
					}
				}
			});
			
			re

 

needed to be like this:

@Override
		public IMessage onMessage(MessageSyncAllPlayerData message, MessageContext ctx)
		{
			
			MagicMastery.proxy.getThreadListener(ctx).addScheduledTask(() ->
			{
				final EntityPlayer player = MagicMastery.proxy.getEntityPlayer(ctx);
				final IPlayerData serverData = message.getData();
				
				if (player != null && serverData != null)
				{
					IPlayerData clientData = PlayerDataProvider.getPlayerCapability(player);
					
					if (clientData != null && serverData != null)
					{

 

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

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Announcements



×
×
  • Create New...

Important Information

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