Jump to content

How to detect right mouse-down?


JoeStrout

Recommended Posts

I've got a custom Item subclass that I want to do something when the user right-clicks — and I want it to behave the same way regardless of whether there is a block in reach or not.  (I do my own ray-casting to determine whether and where to do the effect.)

 

So I overrode and logged all the likely methods, and found that if a block is highlighted, I get onItemUseFirst, optionally followed by onItemUse (depending on the status code I return from onItemUseFirst); and if I'm pointed at something further away (or nothing at all), then I get onItemRightClick called repeatedly.  In the onItemRightClick case, there is nothing that's called when the user releases the right mouse button, as far as I can tell.

 

So there's the trouble: I don't want to trigger my effect over and over while the mouse button is held, but only on the initial mouse-down.  Easy enough if it goes through onItemUseFirst, but in the other case, how do I tell which onItemRightClick calls indicate a "first" call for that click?

 

Or am I going about it all wrong?

Link to comment
Share on other sites

You can probably make use of the active item use mechanic used by bows, food, shields, etc.

 

Try overriding Item#onItemRightClick to do the following:

  • Call EntityLivingBase#isHandActive to check if the player is actively using an item.
  • If they aren't, call EntityLivingBase#setActiveHand to make the player start using your item and then perform the effect.
  • If they are, do nothing.

 

You'll also need to override Item#getMaxItemUseDuration to return the maximum duration in ticks that the player can actively use your item (bows and shields use 72000, which is 1 hour), and optionally Item#getItemUseAction to return something other than EnumAction.NONE.

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 hours ago, JoeStrout said:

So there's the trouble: I don't want to trigger my effect over and over while the mouse button is held, but only on the initial mouse-down.  Easy enough if it goes through onItemUseFirst, but in the other case, how do I tell which onItemRightClick calls indicate a "first" call for that click?

You need to make a custom player capability, and then set it to false onItemRightClick(); to check for the very first time a player right clicks with this weapon.

I have a custom player capability class and this is how I would do it:

@Override
public ActionResult<ItemStack> onItemRightClick(ItemStack stack, World worldIn, EntityPlayer playerIn, EnumHand hand)
{
  DinocraftPlayer player = DinocraftPlayer.getEntityPlayer(playerIn);
  DinocraftPlayerActions actions = player.getActions();
  
  if (actions.isFirstTimeWeapon2 /* or whatever name */)
  {
    actions.setIsFirstTimeWeapon2(false);
    /* do things */
    // will never fire again until player respawns
  }
}
    

 

Edited by Differentiation
Link to comment
Share on other sites

Sorry, I think I was unclear.  Your code only fires once until the player respawns — so says the comment, and so too would I expect from the code, as nothing ever sets isFirstTimeWeapon2 back to true.

 

I'm trying to do something every time the right button goes down.  So: click, action fires; continue holding the button, nothing happens.  Release the button and click again, action fires again.

 

The problem is that I don't know how to detect when the button is released.  I've considered registering for an update event and doing something with that, but it feels so hackish... surely there's a better way.

 

Link to comment
Share on other sites

18 minutes ago, JoeStrout said:

Sorry, I think I was unclear.  Your code only fires once until the player respawns — so says the comment, and so too would I expect from the code, as nothing ever sets isFirstTimeWeapon2 back to true.

 

I'm trying to do something every time the right button goes down.  So: click, action fires; continue holding the button, nothing happens.  Release the button and click again, action fires again.

 

The problem is that I don't know how to detect when the button is released.  I've considered registering for an update event and doing something with that, but it feels so hackish... surely there's a better way.

 

Have you tried my suggestion?

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

6 minutes ago, Choonster said:

 

Have you tried my suggestion?

EDIT: no, I missed yours somehow and saw @Differentiation's, and then thought you were referring back to that one.

 

I will catch up and try yours right now.

 

Edited by JoeStrout
totally flubbed it the first time
Link to comment
Share on other sites

OK, thanks @Choonster, that gets me closer.  Right-clicks when I'm not pointed at any nearby block now work correctly.

 

It turns out I still have a problem when a block is highlighted, though: I get no onItemRightClick call in this case, and onItemUseFirst gets invoked over and over, about 5 times per second while the button is held down.  I have tried returning both EnumActionResult.PASS and EnumActionResult.SUCCESS from both onItemUseFirst and onItemUse; it makes no difference as far as I can tell.

 

[EDIT: my getMaxItemUseDuration returns 72000.]

 

I'd be happy to have exactly the same behavior as a bow: regardless of whether a nearby block is highlighted or not, the bow draws back while you hold the right mouse button down, and does its action when you release it.  But so far it's still not clear to me how to do that.

Edited by JoeStrout
Link to comment
Share on other sites

OK, I decided to try skipping all those item-use and right-click Item methods, and instead just subscribe to mouse events.  This seems to work well:

 

	@SubscribeEvent
	public static void onMouseEvent(MouseEvent event) {
		if (event.getButton() != 1) return;
		EntityPlayerSP player = Minecraft.getMinecraft().player;
		boolean isWand = (player.getHeldItemMainhand().getItem() == ModMain.itemWand);
		if (!isWand) return;
		if (event.isButtonstate()) {
			// RMB down
			Minecraft.getMinecraft().player.setActiveHand(EnumHand.MAIN_HAND);
		} else {
			// RMB up
			Minecraft.getMinecraft().player.resetActiveHand();
			DoBoom();
		}
	}

 

Very simple and appears reliable.  It bothers me a little to have my code executing every time the mouse wiggles, but I make it bail out as quickly as I can, and probably the same amount of work was going on in Item anyway.

 

If anybody can see a reason why this is not a good approach, please let me know!

Link to comment
Share on other sites

I knew this was purely client-sided — of course, since the server doesn't know anything about mice.  My goal with this exercise was only to properly process the mouse input.  I wouldn't expect that to be possible on the server.

 

So yes, that means I may soon be asking a questions about how to pass things over to the server.  My understanding is that this usually involves a network packet, though I still cling to a bit of hope that in some cases, such as spawning a projectile, the framework might take care of that for me.

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.