Solved Interaction animation seperation

Discussion in 'Spigot Plugin Development' started by AtomicZombies, Jan 9, 2020.

  1. I'm not too familiar with the changes in 1.15, but certain things now have animations, which causes the PlayerInteractionEvent. Most importantly, dropping an item.

    Now this causes a few issues, so I need to know how to filter these out.

    I don't want to keep a list of dropped ItemEvents.
     
  2. playerinteractionevent isnt a thing. do you mean playerinteractevent? based on your description, that seems weird, because pie only calls on left and right clicks and stepping on pressure plates.

    /e do you mean playeranimationevent? that wouldnt call from dropping an item i think tho... and theres only one playeranimationtype so far, which is arm_swing.
     
  3. They likely mean PlayerAnimationEvent.
    The actions you are trying to filter out aren't specified and your end goal here is unclear so there is not much we can do to assist you. Why are you first listening to PlayerAnimationEvent, why not just listen to the events that are actually called pertaining to the actions you actually want to listen for? Without knowing exactly what you're going for here, I can only really advise the following:
    • Listen for the PlayerAnimationEvent
    • Create a short delay listening for say a PlayerInteractEvent (Action.YOUR_ACTION_HERE)
    • If everything so far returns true, then I would create a new instance for a class that would listen specifically for that player for when their interact event changes or successive call for PlayerAnimationEvent stops after a short period. When it does, unregister your listener and listen for when the player starts fulfilling the intended actions you're checking for
    The example of going about your problem above is very broad and not a very efficient approach. You can look into utilizing ProtocolLib and listening for incoming packets to understand exactly the type of animation that is about to be fired for.

    A simpler and more accurate approach is possible if we're given more details about your problem though.
     
  4. Ah, I see how it's confusing... Let me try to explain it better.

    No, I mean the PlayerInteractEvent. Whenever a Player drops an Item in 1.15, they swing their fist. This triggers a PlayerInteractionEvent, and possible the PlayerAnimationEvent. I can tell because features of another plugin I use (crackshot) are triggered as if you were interacting.

    So I want to filter out Players dropping an item specifically, but players apparently are having the same thing occur with other things too, like hoes. I can get more information from people if need be.

    I'd like to avoid this, if possible.
     
  5. I was unaware that PlayerInteractEvent gets triggered when dropping an item, definately very odd. Can't you just do e.getAction() and specify the action type you're looking for to filter out item drop actions?
     
  6. Issue with this is that the action is equal to LEFT_CLICK_AIR.
    Edit: PlayerAnimationEvent is triggered every time (Drop an item, or punching normally)
     
    #6 AtomicZombies, Jan 10, 2020
    Last edited: Jan 10, 2020
  7. Well perhaps can you provide a bit of context for what you're trying to achieve here? Right now, the best solutions I can offer is what I explained above. Either listen for PlayerAnimationEvent, create a short delay to check if PlayerDropItemEvent is called and then cancel the entire operation, or if the delayed task goes through, execute whatever action you wanted originally. The approach I gave isn't necessarily great, but it's not that terrible if done properly and a less than instantaneous response won't ruin whatever you're going for here.

    Your second option is to of course utilize ProtocolLib, listen for an incoming packet related to what you want and execute.

    You may be interested in look at net.minecraft.server.v1_15_R1.PlayerInteractManager. I tried taking a look myself to see if I could find anything obvious that may be useful for determine the player's most recent interaction. The best thing I found was an enum class, net.minecraft.server.v1_15_R1.EnumPlayerDigType:
    Code (Java):
        public static enum EnumPlayerDigType {
            START_DESTROY_BLOCK,
            ABORT_DESTROY_BLOCK,
            STOP_DESTROY_BLOCK,
            DROP_ALL_ITEMS,
            DROP_ITEM,
            RELEASE_USE_ITEM,
            SWAP_HELD_ITEMS;

            private EnumPlayerDigType() {
            }
        }
    Unfortunately, DROP_ALL_ITEMS and DROP_ITEM is for some reason recognized by the packet, PacketPlayInBlockDig as well as the functions in PlayerInteractManager dealing with handling block breaking operations.EnumPlayerDigType never really appears to be stored globally in any one of the classes, so the use of reflection seems relatively pointless. You may be able to intercept a packet though and try to read the stored enum in one of the packets, but that again requires ProtocolLib, or you coming up with your own packet interceptor, which I would imagine would be potentially difficult to develop and maintain. There are still many fields and classes that handle player interaction, so I would potentially spend a bit more time, see what fields change corresponding to the action at play and see if you spot any patterns unique to a particular interaction.
     
    #7 Qruet, Jan 10, 2020
    Last edited: Jan 10, 2020
    • Like Like x 1
  8. Thanks for the informative post.
    So I use a plugin CrackShot that "zooms in" (Applies different speeds to players) when they punch while holding the weapon. To reload the weapon, you drop it.

    This creates an issue in 1.15 because whenever players attempt to reload the weapon, the weapon scopes in and out (Just visual, but annoying nonetheless). So I see now that even if I can filter these out, CrackShot doesn't check if the PlayerInteractEvent has been cancelled, but I'd like to find a good solution nonetheless (Maybe I can find a cheaty way past that later).

    DROP_ITEM looks promising, but packets can be tedious, and as you said, hard to maintain. :unsure:

    So right now the best option I see is tracking the System.currentTimeMillis() for each player when they drop an item. Then when I need to check if an Interaction was just caused by an Animation, I can get the current time and subtract the player's dropped item time and see if the difference is large enough.

    It would be nice for Spigot to add a method to check if the cause of the interaction was from an animation... Where is the best place to suggest that?
     
  9. It would be a little bit easier then that actually. Here's an example of what I mean:
    Code (Java):
    //detect left click (avoid false positives w/ drop)
    private BukkitRunnable task; //TODO Find a better implementation of this field so it doesn't get overriden by other interact instances during the check
    onInteract(PlayerInteractEvent e) {
            if(e.getAction != Action.LEFT_CLICK)
                  return;
            Player player = e.getPlayer();

            Listener listener = new Listener() {
                @EventHandler
                public void onDrop(PlayerDropItemEvent e) {
                    if(!(e.getPlayer().getUniqueId().equals(player.getUniqueId())))
                        return;
                    task.cancel();
                    //Handle item drop
                }
            };
            task = new BukkitRunnable() {
                @Override
                public void run() {
                    HandlerList.unregisterAll(listener);
                    //Handle legit left click
                }
            }.runTaskLater(plugin,1L);
            Bukkit.getPluginManager().registerEvents(listener, plugin);
     
    }
    I would actually create a custom Event clone of PlayerInteractEvent and add additional actions like ItemDrop and call it after the original PlayerInteractEvent is called and you determine whether it's an item drop or an actual left click. Then you can call your custom PlayerInteractEvent where the rest of your plugin can accurately recognize a legit left click interact event call without needing to do any additional nasty checks. Would help make things a bit more maintainable.

    https://www.spigotmc.org/forums/community-feedback-and-suggestions.34/
     
    #9 Qruet, Jan 13, 2020
    Last edited: Jan 13, 2020
    • Informative Informative x 1
  10. My first thoughts exactly.

    Going to, "think out loud" for my own clarity and anybody looking here for information:

    So you create a listener for item dropping, create the runnable, register the listener, wait 1 tick, and run the runnable.
    If the listener doesn't cancel the runnable, the runnable will unregister the listener.
    This way the runnable will only be executed if the a player doesn't drop an item.

    That is well done...
     
    • Like Like x 1