Jump to content

LivingJumpEvent issues: Firing twice, not finding capability/NBT


Alekseyev

Recommended Posts

Hey again,

 

I have a strange issue: I am subscribed to the LivingJumpEvent

 

@SubscribeEvent
public void jumpEffect(LivingEvent.LivingJumpEvent event)
{
	if (event.getEntity() instanceof EntityPlayer)
	{
		System.out.println("jumpEvent: Entity is EntityPlayer");

		EntityPlayer evPlayer = (EntityPlayer)event.getEntity();

		Boolean abc = getHandler(evPlayer).getElement() == BioElements.AIR;
		Boolean def = 1+1 == 2;

		if (true)
		{
			System.out.println("Element is AIR, adjusting Jump 1");
			evPlayer.motionY += 1.0D;
		}

		if (abc) // check for BioElements.AIR
		{
			System.out.println("Element is AIR, adjusting Jump 2");
			evPlayer.motionX += 1.0D;
		}

		if (def)
		{
			System.out.println("Element is AIR, adjusting Jump 3");
			evPlayer.motionZ += 1.0D;
		}
	}
}

 

The strange conditions like "def" and (true) are for testing. What I found out: When I jump in "single player", the event is first called for EntityPlayerSP. It does not find the capability or NBT data required for the boolean abc, so there is no movement on the X axis. Then, immediately after, it is called again for EntityPlayerMP. This time, all 3 conditions are met, however the movement change is not actually applied. However, If I jump and then receive damage mid-air (such as jumping against a cactus or getting hit by a mob), then the effects are all applied, including the previously missing X motion.

 

Any advice on how to solve it?

Edited by Alekseyev
fixed topic title
Link to comment
Share on other sites

11 minutes ago, Alekseyev said:

the event is first called for EntityPlayerSP. It does not find the capability or NBT data required for the boolean abc, so there is no movement on the X axis. Then, immediately after, it is called again for EntityPlayerMP.

You need to do a isRemote check, because the event is ran on both the client and server.

VANILLA MINECRAFT CLASSES ARE THE BEST RESOURCES WHEN MODDING

I will be posting 1.15.2 modding tutorials on this channel. If you want to be notified of it do the normal YouTube stuff like subscribing, ect.

Forge and vanilla BlockState generator.

Link to comment
Share on other sites

The event is supposed to fire twice, client and server side. Any capability data may not be present on the client (this is normal) unless you are properly syncing that yourself using custom packets. Player movement is a bit strange because (in order to ensure smooth player movement despite network lag) the client has a lot of control of it with the server just verifying and occasionally affecting it.

 

Since this affects player movement I suspect you do want to process the event on both sides. However, it sounds like your player data isn't synced and available on client. You need to debug that.

Check out my tutorials here: http://jabelarminecraft.blogspot.com/

Link to comment
Share on other sites

  • 1 month later...

Hey there,

for a variety of reasons I didn't work on it since making the last post. Now, however, I decided to continue.

 

How would I go about making sure the capability is synchronised between the server and the client?
I found this tutorial on packets: Link, but it only fires once a certain action is performed. When jumping, sending the packets back and forth only upon requiring the capability info might be too slow?

Edited by Alekseyev
Link to comment
Share on other sites

7 minutes ago, Alekseyev said:

How would I go about making sure the capability is synchronised between the server and the client?

As @jabelar said you need to use packets. Send the data needed(what you want present on the client) when it is needed(upon initial login and when it changes). Don't send the packet when the data is needed, send it when it is changed. This ensures that the client always has up to date data.

Link to comment
Share on other sites

Just now, V0idWa1k3r said:

As @jabelar said you need to use packets. Send the data needed(what you want present on the client) when it is needed(upon initial login and when it changes). Don't send the packet when the data is needed, send it when it is changed. This ensures that the client always has up to date data.

Right, but how do I store or retrieve the player's data that has been sent this way? In the event I could retrieve the object that performed the jump and then get its data, but how do I make sure the client has this data for this object?

Link to comment
Share on other sites

  • When the data changes on the server send the packet with the new data to the client
  • When the client recieves the data get the client's capability and set the data in that capability to the data you've recieved.
  • When the time comes to use the data the client conveniently already knows the latest up-to-date information. Just use the capability as you would normally do - it already has the latest data in it.
Link to comment
Share on other sites

On 9/15/2018 at 6:37 PM, V0idWa1k3r said:
  • When the client recieves the data get the client's capability and set the data in that capability to the data you've recieved. 

How exactly do I do this?

 

I followed this tutorial on capabilities: https://tutorials.darkhax.net/tutorials/custom_entity_data/ and I know the Forge documentation, but how to make it work on the client side specifically?

Link to comment
Share on other sites

AttachCapabilitiesEvent fires on both the server and the client. This means that the client also has the capability, just not the latest data. 

On the client you always have access to the client player - Minecraft.getMinecraft().player.

That player will have your capability.

All that's left is to set the data in that capability. I assume you do know how to create and use a setter.

Link to comment
Share on other sites

  • 4 months later...
On 9/18/2018 at 5:07 PM, V0idWa1k3r said:

AttachCapabilitiesEvent fires on both the server and the client. This means that the client also has the capability, just not the latest data. 

On the client you always have access to the client player - Minecraft.getMinecraft().player.

That player will have your capability.

All that's left is to set the data in that capability. I assume you do know how to create and use a setter.

Hey, sorry for replying so late - haven't really had the time to continue on it before due to unforseen developments.

I currently have this method:

@SubscribeEvent
public void playerLogin(PlayerEvent.PlayerLoggedInEvent event)
{
	System.out.println("Event active: playerLogin");
	getHandler(event.player).setElement(BioElements.AIR);
}

If I add the line

getHandler(Minecraft.getMinecraft().player).setElement(BioElements.AIR);

to the it, the game crashes in the function

public static IElementHandler getHandler(Entity entity)
{
	if (entity.hasCapability(CAPABILITY_ELEMENT, EnumFacing.DOWN))
		return entity.getCapability(CAPABILITY_ELEMENT, EnumFacing.DOWN);

	return null;
}

reporting a NullPointerException.

If I add the same line in the LivingJumpEvent subscriber, it works completely fine and gives the desired result. I'm assuming this is because at the time the player joins the world, the entity Minecraft.getMinecraft().player doesn't exist yet?

How do I get this to work? Or also, how do I have a method be called at a later point but be triggered within PlayerLoggedInEvent?

Edit: If it helps anything, here's a github repository: https://github.com/JohnTheLate/NTutMod/tree/january2019/src/main/java/john/mod

Edited by Alekseyev
Link to comment
Share on other sites

Please post the full crash with GitHub gist, “crashing with an NPE” isn’t very helpful when we don’t know where it’s crashing at

About Me

Spoiler

My Discord - Cadiboo#8887

My WebsiteCadiboo.github.io

My ModsCadiboo.github.io/projects

My TutorialsCadiboo.github.io/tutorials

Versions below 1.14.4 are no longer supported on this forum. Use the latest version to receive support.

When asking support remember to include all relevant log files (logs are found in .minecraft/logs/), code if applicable and screenshots if possible.

Only download mods from trusted sites like CurseForge (minecraft.curseforge.com). A list of bad sites can be found here, with more information available at stopmodreposts.org

Edit your own signature at www.minecraftforge.net/forum/settings/signature/ (Make sure to check its compatibility with the Dark Theme)

Link to comment
Share on other sites

I think you should step through your code with the debugger, it does seem like the player might be null at that time. Also check if the event provides a way to get the player.

Also: why are you using getCapability(DOWN)? If you want to get the capability and don’t care about the facing it is acceptable to pass null in. Null usually indicates you want full access to all parts of the capability, not just what would be provided from a facing.

About Me

Spoiler

My Discord - Cadiboo#8887

My WebsiteCadiboo.github.io

My ModsCadiboo.github.io/projects

My TutorialsCadiboo.github.io/tutorials

Versions below 1.14.4 are no longer supported on this forum. Use the latest version to receive support.

When asking support remember to include all relevant log files (logs are found in .minecraft/logs/), code if applicable and screenshots if possible.

Only download mods from trusted sites like CurseForge (minecraft.curseforge.com). A list of bad sites can be found here, with more information available at stopmodreposts.org

Edit your own signature at www.minecraftforge.net/forum/settings/signature/ (Make sure to check its compatibility with the Dark Theme)

Link to comment
Share on other sites

Yes, the player (from Minecraft.getMinecraft().player) is null at that time. The event's player, while allowing for EntityPlayer in general, only seems to receive an EntityPlayerMP to provide.
So that brings me back to my earlier question, I assume: How do I have a method be called at a later point but be triggered within PlayerLoggedInEvent? If you (or anyone else) has a better suggestion, please let me know!

 

I had no idea what to use the facing for, so I simply followed the tutorial I linked earlier regarding this and didn't give it much thought. I'll change this, thanks for making me aware.

Link to comment
Share on other sites

I solved this problem the following way: PlayerLoggedInEvent creates a new runnable that does the following:

 

	@Override
	public void run()
	{
		try
		{
			while (Minecraft.getMinecraft().player == null)
			{
				System.out.println("player is null, sleeping for 2 seconds");
				Thread.sleep(2000);
			}
			getHandler(Minecraft.getMinecraft().player).setElement(element);
		}
		catch (InterruptedException ie)
		{
			ie.printStackTrace();
		}
		System.out.println("Runnable finished");
	}

 

It appears to work, but I'm not super sure how clean the while + sleep loop is. Any suggestions on improving the code?

Link to comment
Share on other sites

You can’t access the player from another thread

About Me

Spoiler

My Discord - Cadiboo#8887

My WebsiteCadiboo.github.io

My ModsCadiboo.github.io/projects

My TutorialsCadiboo.github.io/tutorials

Versions below 1.14.4 are no longer supported on this forum. Use the latest version to receive support.

When asking support remember to include all relevant log files (logs are found in .minecraft/logs/), code if applicable and screenshots if possible.

Only download mods from trusted sites like CurseForge (minecraft.curseforge.com). A list of bad sites can be found here, with more information available at stopmodreposts.org

Edit your own signature at www.minecraftforge.net/forum/settings/signature/ (Make sure to check its compatibility with the Dark Theme)

Link to comment
Share on other sites

Just now, diesieben07 said:

It will work for 1000 times. And then it will fail with an obscure exception that you have no idea why it occurs (except we told you now).

And then it will work again, for 1000 times. Or 2000. Or 10.

Oh, that is interesting! I would have expected it to fail every time, Cadiboo's post sounded very absolute.

Do you have a different suggestion? I'd guess that handling it in playerTickEvent would add an unnecessary performance impact, adding a check to every single tick even though the condition would only be met once.

Link to comment
Share on other sites

39 minutes ago, Alekseyev said:

Oh, that is interesting! I would have expected it to fail every time, Cadiboo's post sounded very absolute.

Do you have a different suggestion? I'd guess that handling it in playerTickEvent would add an unnecessary performance impact, adding a check to every single tick even though the condition would only be met once.

Its called a race condition, and its effects are entirely non-deterministic due to outside factors like the hypervisor thread scheduling. 

Edited by Draco18s

Apparently I'm a complete and utter jerk and come to this forum just like to make fun of people, be confrontational, and make your personal life miserable.  If you think this is the case, JUST REPORT ME.  Otherwise you're just going to get reported when you reply to my posts and point it out, because odds are, I was trying to be nice.

 

Exception: If you do not understand Java, I WILL NOT HELP YOU and your thread will get locked.

 

DO NOT PM ME WITH PROBLEMS. No help will be given.

Link to comment
Share on other sites

14 hours ago, Alekseyev said:

I'd guess that handling it in playerTickEvent would add an unnecessary performance impact, adding a check to every single tick even though the condition would only be met once.

Checking if 2 integers are equal (one of them being a constant) and incrementing an integer will have a negligible performance impact. It is probably more performance intensive to just call your subscribed method.

About Me

Spoiler

My Discord - Cadiboo#8887

My WebsiteCadiboo.github.io

My ModsCadiboo.github.io/projects

My TutorialsCadiboo.github.io/tutorials

Versions below 1.14.4 are no longer supported on this forum. Use the latest version to receive support.

When asking support remember to include all relevant log files (logs are found in .minecraft/logs/), code if applicable and screenshots if possible.

Only download mods from trusted sites like CurseForge (minecraft.curseforge.com). A list of bad sites can be found here, with more information available at stopmodreposts.org

Edit your own signature at www.minecraftforge.net/forum/settings/signature/ (Make sure to check its compatibility with the Dark Theme)

Link to comment
Share on other sites

On 1/30/2019 at 7:38 PM, Draco18s said:

Its called a race condition, and its effects are entirely non-deterministic due to outside factors like the hypervisor thread scheduling. 

Oh, I thought race conditions only come into play if two threads try to modify the same value - in this case, the 2nd thread would change something that is never going to be changed by the first thread. But I may very much be wrong... I had this thing in university once, but it's been a while.

 

14 hours ago, Cadiboo said:

Checking if 2 integers are equal (one of them being a constant) and incrementing an integer will have a negligible performance impact. It is probably more performance intensive to just call your subscribed method.

Alright. In retrospective I should have thought about that myself, with all the other stuff in the vanilla classes that gets called all the time...

 

On 1/30/2019 at 7:09 PM, diesieben07 said:

For capability data to be available on the client a packet containing the data must be sent from the server to the client in the following events:

  • PlayerLoggedInEvent
  • PlayerRespawnEvent
  • PlayerChangedDimensionEvent
  • Whenever the data changes

This is for when the data needs to be available on each player's client only (i.e. data for player A is available on player A's client). If the data needs to be available on all clients that can see a player, more tracking is needed.

I'll get into that soon. Also congrats on 40k posts! :D

Link to comment
Share on other sites

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.



×
×
  • Create New...

Important Information

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