Solved Detect when item enters/exits a player's inventory

Discussion in 'Spigot Plugin Development' started by repeater64, Jun 19, 2021.

  1. Hi all,

    I'm trying to create a system that can reliably detect when a certain item enters or exits a player's inventory.

    The first idea I had was to listen to all Set Slot and Window Items packets sent to the client, and use this to see if the target item had entered or exited the inventory. However, this method is quite unreliable and there are lots of ways it can be tricked. Equipping armor doesn't count as obtaining the item (probably because the client is informed about it with the Entity Equipment packet?) and any change to an item EG durability change triggers the code to think the item has been added.

    The only other options I can think of are:

    1. Try and listen to every possible event I could think of that could result in an item entering or exiting the inventory. InventoryClickEvent, InventoryDragEvent, PlayerDropItemEvent, ItemPickupEvent, all that kind of thing. However, this might still miss things such as players obtaining an item with a command.
    2. Regularly check PlayerInventory#getContents() on a scheduler, try and make some efficient code for checking if anything has changed, and then seeing if that change involves the adding or removal of my target item.

    Can anyone advise me, either on another, better method for doing this, or on which of the two methods I described would be better?

    Thanks in advance.
     
  2. Scheduler needs too many resources, so listen to all events: PlayerItemPickup, PlayerItemDrop, InventoryDragItems etc
     
  3. Alright, I might go with this, but I feel like this would miss some methods of obtaining/loosing items
     
  4. You can find all the events under the java doc
     
  5. Yes, I'm aware, but there are ways that an item could enter a players' inventory without an event being triggered.
    (EG a plugin puts it there, a command puts it there)
     
  6. This is something that could work:

    1. Create a custom InventoryModifiedEvent
    2. Create an async scheduler ( so it won't affect the server completely ) which checks (based on a data map) the amount of items a player has in his inventory
    3. In the async scheduler, if the player doesn't has the same amount of items as in the data map, call InventoryModifiedEvent and update the data map with the new values

    The InventoryModifiedEvent could have something like getModifiedSlot() ( better than creating a getModifiedItem ) and getPlayer().

    Using some logic you could aso add a "isItemMove" or "isNewItem" to the event, but that would require extra checks which I don't think you want to do
     
    • Optimistic Optimistic x 1
  7. That almost works but not quite. The amount of items in someone's inventory could be the same despite an item having entered their inventory - perhaps between runs of the scheduler, they dropped one item and picked up another. Could be a super common occurrence in the case of someone having a full inventory and swapping between stuff on the ground.

    I've ended up going with a scheduled task that I've just tried to make as efficient as possible. The task runs at different times for different players to avoid lagspikes, and it's a pretty minimal performance impact.
     
    • Agree Agree x 1