Jump to content

Hotbar item change weird behaviour


Zethariel

Recommended Posts

Hello,

 

I've been trying to make an item that, when equipped, runs a function and goes back to the last equipped item. To do that, I check for the hotbar hotkeys being pressed and act accordingly.

The problem begins when the hotbar key is pressed down. After a flicker or two the item that wasn't supposed to be equipped in the main hand is, despite the local EntityPlayerSP telling me that the currently equipped slot is different from the displayed one.

After that even, single presses have a 50% chance of fixing the issue. Is this because the item gets set server side and feeds the player what he should have, or is there a race condition I'm not seeing somewhere?

 

int lastItemSlot = -1;
	
	boolean[] lastHotbarKeyState;

	
	@SideOnly(Side.CLIENT)
	@SubscribeEvent
	public void handlePlayerSwitchingItemsToMagic(ClientTickEvent event){
		//only do this at the end of tick to set the proper item we are selecting
		EntityPlayerSP player = (EntityPlayerSP) Minecraft.getMinecraft().player;
		if ((event.side == Side.CLIENT) && (event.phase == Phase.START) && (player != null)){
			KeyBinding[] hotbar = Minecraft.getMinecraft().gameSettings.keyBindsHotbar;
			
			PonyLogger.info(player.inventory.currentItem+"");
			//lazy creation
			if (lastHotbarKeyState == null){
				lastHotbarKeyState = new boolean[hotbar.length];
			}
			
			if (lastItemSlot == -1){
				lastItemSlot = player.inventory.currentItem;
			}
			
			
			for (int i = 0; i < 9; ++i)
	        {
				//if this button is pressed...
	            if (hotbar[i].isKeyDown())
	            {
	            	//...check if it is the first press or is this a continuous press...
	            	//...if first press, cast spell and go back to last item....
	            	if (!lastHotbarKeyState[i])
	            		handlePlayerSwitchingItems(player, i, true);
	            	else{
	            		//...if not first press, don't cast spell and go to last item...
	            		handlePlayerSwitchingItems(player, i, false);
	            	}
	            	lastHotbarKeyState[i] = true;
	            } else{
	            	//...if it is not pressed, reset it's state
	            	lastHotbarKeyState[i] = false;
	            }
	            
	            
	                
	        }
			
		
		}
	}
	
	
	private void handlePlayerSwitchingItems(EntityPlayerSP player, int destinationSlot, boolean castSpell){
		ItemStack stack = player.inventory.getStackInSlot(destinationSlot);
		Item item = stack.getItem();
		//if this is a magic spell, we will need to activate the spell and put the player back in the slot he was
		if (item == PonyPowersItemManager.itemTestSpell){
			if (castSpell)
				((ItemTestSpell)item).onSelectedFromHotbar(stack);
			player.inventory.currentItem = lastItemSlot;
			PonyLogger.info("forcing change to "+lastItemSlot);
		} else 
			//if this wasn't the spell, allow for the change;
			lastItemSlot = destinationSlot;
	}
		

 

The reason for the event being the ClientTickEvent instead of the PlayerTick variant is that I was experimenting with this to see where the issue could be.

 

If something is unclear, please let me know, and thanks for your time.

I do pony stuff :3

Link to comment
Share on other sites

1 minute ago, diesieben07 said:

Why not just override onUpdate in the item class?

Fair point. But does the place at which I set my rules to changing the hotbar behaviour make a difference? Plus, the client ticket has the potential to trigger the revert of hotbar selection before the item update, yes?

I do pony stuff :3

Link to comment
Share on other sites

Just now, diesieben07 said:

The problem is that ClientTickEvent is, well, client-side. The server is just going to override your change.

Okay, so it's deffinetly the issue with the server getting the information then? If so, you're right, I'll change to the update in the item...

I do pony stuff :3

Link to comment
Share on other sites

48 minutes ago, Zethariel said:

Okay, so it's deffinetly the issue with the server getting the information then? If so, you're right, I'll change to the update in the item...

Server is authority. The client should not do anything but send input requests to the server.  The server then insures that the action is allowable and changes state (or not).

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

Just now, Draco18s said:

Server is authority. The client should not do anything but send input requests to the server.  The server then insures that the action is allowable and changes state (or not).

I was attempting to persuade the client to send to the server my version of events, but I guess that failed.

I do pony stuff :3

Link to comment
Share on other sites

That will never, and should never, work.

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

1 minute ago, Draco18s said:

That will never, and should never, work.

Isn't that the point of modding though, with how the events are exposed? By my version of events, I meant the changed state of the hotbar - the client knows best what it wanted to click, and I wanted to influence that before it got sent to the server.

I do pony stuff :3

Link to comment
Share on other sites

2 hours ago, Zethariel said:

Isn't that the point of modding though, with how the events are exposed? By my version of events, I meant the changed state of the hotbar - the client knows best what it wanted to click, and I wanted to influence that before it got sent to the server.

Remember:
Someone could decompile your mod, change the value, recompile it, and get a different effect than your intent.  Say, by removing the jump back to the prior slot.

 

The client always lies.

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

18 hours ago, Draco18s said:

Remember:
Someone could decompile your mod, change the value, recompile it, and get a different effect than your intent.  Say, by removing the jump back to the prior slot.

 

The client always lies.

The server takes the client's position at face value - that's why we have a lot of fly cheat mods. And I think the same happens, to my great dismay, with hotbars - the server only receives which item slot if selected instead of the keyboard input and act according to that. Or am I wrong? It SHOULD work so that I could check server-side what buttons were pressed so that I can work with them server-side.

 

Scenario I'm getting at: Player has currently my special item selected as the one he is wielding in main hand. He presses the hotbar key for the special item. What I want to happen is for the press to register and do something - in this case, I can't rely on checking the itemslot, only raw information about the button press can help me. This is even more relevant if some of the actions in my mod swap around the player's currently equipped item - I need to distinguish my mod changing the slot from a player's input.

 

Is what I'm trying even feasible, or should I look into a different method?

Edited by Zethariel

I do pony stuff :3

Link to comment
Share on other sites

There are some places where vanilla takes the client's report at face value (e.g. position) but they're things that Mojang did wrong.  In other places they did it right (such as item crafting recipes: the client needs to know and compute the result so it can be displayed, but if you attempt to pick it up and the server doesn't agree that the item can be crafted, you don't get anything).

 

All I'm saying is: assume the client is a lying fuck and do the calculation on the server (or at least, not only on the client).

  • Like 1

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

Just now, Draco18s said:

There are some places where vanilla takes the client's report at face value (e.g. position) but they're things that Mojang did wrong.  In other places they did it right (such as item crafting recipes: the client needs to know and compute the result so it can be displayed, but if you attempt to pick it up and the server doesn't agree that the item can be crafted, you don't get anything).

 

All I'm saying is: assume the client is a lying fuck and do the calculation on the server (or at least, not only on the client).

Yes, I'll agree with both things, and I'm trying to have that in mind - with my current conundrum, I just don't see it feasible to be able to control it server-side, save for sending packets with button clicks to the server, which would probably clog it if someone was stupid enough to faceroll the keyboard.

I do pony stuff :3

Link to comment
Share on other sites

Just for the record, I solved my problem, but it's not something I'm that much proud of.

 

I did this clientside-only, taking into consideration that the server has no clue what's happening on the hotbar and is only fed raw information about the currently held item. What I did was capture the hotbar press, check the item in the slot, if it's my special item, UNPRESS the hotbar key (via isPressed, which god knows why is the only function that actually is capable of doing so) and do whatever the item is supposed to. This prevents the flickering I had, the items don't swap out and it's perfect. The downside, as Draco18s mentioned, is that tampering with the code will break this specific functionality... Which is the user's problem, since the item doesn't do anything much.

 

Code for interested people:

 

public class ClientEvents {
	
	int lastItemSlot = -1;
	
	boolean[] lastHotbarKeyState;

	
	
	private void handlePlayerSwitchingItems(EntityPlayerSP player, int destinationSlot, boolean castSpell, KeyBinding hotbar){
		ItemStack stack = player.inventory.getStackInSlot(destinationSlot);
		Item item = stack.getItem();
		//if this is a magic spell, we will need to activate the spell and put the player back in the slot he was
		if (item == PonyPowersItemManager.itemTestSpell){
			if (castSpell)
				((ItemTestSpell)item).onSelectedFromHotbar(stack);
			player.inventory.currentItem = lastItemSlot;
			PonyLogger.info("forcing change to "+lastItemSlot);
			//have to use this f**** function to actually unpress something...
			hotbar.isPressed();
		} else 
			//if this wasn't the spell, allow for the change;
			lastItemSlot = destinationSlot;
	}
		
	
	
	
	@SideOnly(Side.CLIENT)
	@SubscribeEvent
	public void onTestKeyPress(KeyInputEvent event){
		
		EntityPlayerSP player = (EntityPlayerSP) Minecraft.getMinecraft().player;
		if (player != null){
			KeyBinding[] hotbar = Minecraft.getMinecraft().gameSettings.keyBindsHotbar;
	
			//lazy creation
			if (lastHotbarKeyState == null){
				lastHotbarKeyState = new boolean[hotbar.length];
			}
			
			if (lastItemSlot == -1){
				lastItemSlot = player.inventory.currentItem;
			}
			
			
			for (int i = 0; i < 9; ++i)
	        {
				//if this button is pressed...
	            if (hotbar[i].isKeyDown())
	            {
	            	//...check if it is the first press or is this a continuous press...
	            	//...if first press, cast spell and go back to last item....
	            	if (!lastHotbarKeyState[i])
	            		handlePlayerSwitchingItems(player, i, true, hotbar[i]);
	            	else{
	            		//...if not first press, don't cast spell and go to last item...
	            		handlePlayerSwitchingItems(player, i, false, hotbar[i]);
	            	}
	            	lastHotbarKeyState[i] = true;
	            } else{
	            	//...if it is not pressed, reset it's state
	            	lastHotbarKeyState[i] = false;
	            }
	            
	            
	                
	        }
			
		
		}

		
	
	}
	


}

 

I do pony stuff :3

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.