Jump to content

[SOLVED] [1.12] NoSuchMethodError for getSlotFor


IceMetalPunk

Recommended Posts

After testing my Totem Essentials mod and having no issues, I released it, but now I'm getting a report from someone that they're getting crashes. This is the log they submitted: https://gist.github.com/knoxhack/4ae7603dfa1d9e33e35f363000e6faa4

 

As you can see, it's caused by a NoSuchMethodError for net.minecraft.entity.player.InventoryPlayer.func_184429_b, which is the SRG name for InventoryPlayer#getSlotFor(), which simply takes an ItemStack and finds the slot that matches it in the player's inventory.

What would cause that method to not exist, especially when I never got this crash in my own Minecraft environment? I'm guessing it's some sort of mod conflict with one of the mods Knoxhack has installed, but what kind of mod conflict can remove the existence of a core method like that?

Edited by IceMetalPunk

Whatever Minecraft needs, it is most likely not yet another tool tier.

Link to comment
Share on other sites

7 minutes ago, IceMetalPunk said:

After testing my Totem Essentials mod and having no issues, I released it, but now I'm getting a report from someone that they're getting crashes. This is the log they submitted: https://gist.github.com/knoxhack/4ae7603dfa1d9e33e35f363000e6faa4

 

As you can see, it's caused by a NoSuchMethodError for net.minecraft.entity.player.InventoryPlayer.func_184429_b, which is the SRG name for InventoryPlayer#getSlotFor(), which simply takes an ItemStack and finds the slot that matches it in the player's inventory.

What would cause that method to not exist, especially when I never got this crash in my own Minecraft environment? I'm guessing it's some sort of mod conflict with one of the mods Knoxhack has installed, but what kind of mod conflict can remove the existence of a core method like that?

Did you try to run the func on the server side only??

Edited by tebreca
Link to comment
Share on other sites

3 minutes ago, tebreca said:

Did you try to run the func on the server side only??

it says

	at net.minecraft.world.World.func_72939_s(World.java:1755)
	at net.minecraft.world.WorldServer.func_72939_s(WorldServer.java:612)

 maybe you need to do a !World.isRemote statement

Link to comment
Share on other sites

>> No code posted

> Help not available

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

On 10/24/2017 at 10:02 AM, tebreca said:

it says


	at net.minecraft.world.World.func_72939_s(World.java:1755)
	at net.minecraft.world.WorldServer.func_72939_s(WorldServer.java:612)

 maybe you need to do a !World.isRemote statement

I mean... if that was the issue, wouldn't I have also gotten the error when testing? Besides, World#isRemote returns true if it's on the client, meaning if I check for !isRemote, my code will only run on the server... and as you pointed out, this error is triggering on the server... Normally, I'd be willing to at least try it, but since I can't replicate the error, the only way to see if my patch works is by re-releasing a revision and waiting for the players to try again. I don't want to keep releasing revisions unless I at least know I'm going in the right direction with the bugfixes.

On 10/24/2017 at 11:19 AM, Draco18s said:

>> No code posted

> Help not available

I didn't think my code was pertinent since the error is that a vanilla method isn't found... the TEEvents class has a *lot* of code in it (and most is probably completely unrelated to this bug), so I don't want to post the entire class...

Here's the TEEvents#getStackInPlayerInv method that's calling the getSlotFor method:

	// Helper method to get a matching stack from a player's inventory,
	// regardless of which part of the inventory it's in.
	public static ItemStack getStackInPlayerInv(EntityPlayer player, ItemStack compareTo) {
		InventoryPlayer inv = player.inventory;
		ItemStack stack = ItemStack.EMPTY;
		int slotID = inv.getSlotFor(compareTo); // Doesn't include offhand!
		if (slotID < 0) {
			ItemStack inOffhand = player.getHeldItemOffhand();
			if (inOffhand.getItem() == compareTo.getItem()
					&& (!inOffhand.getHasSubtypes() || inOffhand.getMetadata() == compareTo.getMetadata())
					&& ItemStack.areItemStackTagsEqual(inOffhand, compareTo)) {
				stack = inOffhand;
			} else {
				for (ItemStack armorStack : player.getArmorInventoryList()) {
					if (armorStack.getItem() == compareTo.getItem()
							&& (!armorStack.getHasSubtypes() || armorStack.getMetadata() == compareTo.getMetadata())
							&& ItemStack.areItemStackTagsEqual(armorStack, compareTo)) {
						stack = armorStack;
						break;
					}
				}
			}
		} else {
			stack = inv.getStackInSlot(slotID);
		}
		return stack;
	}


And the TEEnsouledEvents#onAttackTarget method which is calling that:

	@SubscribeEvent
	public void onAttackTarget(LivingSetAttackTargetEvent ev) {
		EntityLivingBase target = ev.getTarget();
		if (target instanceof EntityPlayer) {
			ItemStack stack = TEEvents.getStackInPlayerInv((EntityPlayer) target,
					new ItemStack(TotemEssentials.proxy.items.get("ensouled_aggression_totem")));
			if (stack != ItemStack.EMPTY) {
				ItemEnsouledAggressionTotem.performEffect(stack, ev.getEntity().world, (EntityPlayer) target);
			}
		}
	}

 

And as the stacktrace shows, everything leading up to that is Forge/vanilla code, so those should be the only relevant bits of my code.

Whatever Minecraft needs, it is most likely not yet another tool tier.

Link to comment
Share on other sites

InventoryPlayer#getSlotFor is a client-only method (i.e. it's annotated with @SideOnly(Side.CLIENT)), so it doesn't exist on the dedicated server and can't be used from common code (like an event handler running on the logical server).

Please don't PM me to ask for help. Asking your question in a public thread preserves it for people who are having the same problem in the future.

Link to comment
Share on other sites

3 minutes ago, Choonster said:

InventoryPlayer#getSlotFor is a client-only method (i.e. it's annotated with @SideOnly(Side.CLIENT)), so it doesn't exist on the dedicated server and can't be used from common code (like an event handler running on the logical server).

Wait... I may have misunderstood. When you say "dedicated server", that includes the integrated single-player server, too, right? If that's the case, wouldn't I have gotten this crash during my testing (which, by the way, properly called ItemEnsouledAggressionTotem.performEffect())? Or do you mean the method exists on both the client and the integrated server, but not on a standalone server?

If the latter is the case, how would I go about getting a match on an item stack anywhere in the player's inventory? Do I need to iterate over the entire inventory myself?

Whatever Minecraft needs, it is most likely not yet another tool tier.

Link to comment
Share on other sites

The reason you missed it when you were testing is because you probably tested in single player mode. You MUST test your mods by running a separate server and client. Within Eclipse you can simply run both the client and server configurations at same time and connect to the local host 127.0.0.1.

 

This happens because when running in single player there is only one Java VM running both sides to it actually sees the classes that are loaded on the other sides. But if you run a dedicated server run configuration you will have two separate Java VMs each loading only their own classes.

 

The isRemote is for an entirely different thing. This problem is related to classes and how they are loaded, not just how they are executed.

  • Like 1

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

Link to comment
Share on other sites

1 minute ago, jabelar said:

The reason you missed it when you were testing is because you probably tested in single player mode. You MUST test your mods by running a separate server and client. Within Eclipse you can simply run both the client and server configurations at same time and connect to the local host 127.0.0.1.

 

This happens because when running in single player there is only one Java VM running both sides to it actually sees the classes that are loaded on the other sides. But if you run a dedicated server run configuration you will have two separate Java VMs each loading only their own classes.

 

The isRemote is for an entirely different thing. This problem is related to classes and how they are loaded, not just how they are executed.

Ahhh.... suddenly things make sense. I was under the impression that the integrated server was essentially identical, for the most part, to the dedicated server. Clearly, I was mistaken.

So now I'm just left with that final question: is there an easier way to get an item stack from the player's inventory that matches a given stack loosely, without iterating over everything myself? (From the server-side, of course.)

Whatever Minecraft needs, it is most likely not yet another tool tier.

Link to comment
Share on other sites

16 minutes ago, IceMetalPunk said:

Wait... I may have misunderstood. When you say "dedicated server", that includes the integrated single-player server, too, right? If that's the case, wouldn't I have gotten this crash during my testing (which, by the way, properly called ItemEnsouledAggressionTotem.performEffect())? Or do you mean the method exists on both the client and the integrated server, but not on a standalone server?

@SideOnly restricts classes, methods and fields to a specific physical side. The integrated server runs on the physical client, so it has access to things annotated with @SideOnly(Side.CLIENT) (though it should never actually use these). The dedicated server runs on the physical server, which doesn't have access to things annotated with @SideOnly(Side.CLIENT).

 

Quote

If the latter is the case, how would I go about getting a match on an item stack anywhere in the player's inventory? Do I need to iterate over the entire inventory myself?

Use InventoryPlayer#hasItemStack to check if an ItemStack is anywhere in a player's inventory, matching the Item and metadata but not the NBT or capabilities.

Edited by Choonster
  • Like 1

Please don't PM me to ask for help. Asking your question in a public thread preserves it for people who are having the same problem in the future.

Link to comment
Share on other sites

2 minutes ago, Choonster said:

@SideOnly restricts classes, methods and fields to a specific physical side. The integrated server runs on the physical client, so it has access to things annotated with @SideOnly(Side.CLIENT) (though it should never actually use these). The dedicated server runs on the physical server, which doesn't have access to things annotated with @SideOnly(Side.CLIENT).

 

Use InventoryPlayer#hasItemStack to check if an ItemStack is anywhere in a player's inventory, matching the Item and metadata but not the NBT or capabilities.

Thank you for the clarification!

So the problem with hasItemStack is that it matches metadata/damage, and I need to check if the item is in the inventory regardless of its damage value. That's why I ended up writing that little static helper method. The getSlotFor method uses stackEqualExact, which checks the hasSubtypes field before deciding whether to compare damage values or not.

So it looks like I'm going to have to basically rewrite getSlotFor()'s loop in my own code? I mean, it's not terrible, it just feels like this is a functionality that would already exist somewhere in MC's or Forge's code base...

Whatever Minecraft needs, it is most likely not yet another tool tier.

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.

Announcements



×
×
  • Create New...

Important Information

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