stop leads from dropping

Discussion in 'Spigot Plugin Development' started by xlis1, May 5, 2017.

  1. is there a way to prevent leads from dropping when broken?
     
  2. try using a BlockBreakEvent
     
  3. but its not a block, and its not being broken
     
  4. I've never used leads before so I don't really know what they are, but in your post you said 'is there a way to prevent leads from dropping when broken', but then proceeded to say 'it's not being broken', kind of contradictory. What breaks to give a lead? Or does the lead break as you use it or something over time? I'm not sure


    Sent from my iPhone using Tapatalk
     
    • Agree Agree x 1
  5. Leads are an entity if i am right so it has an own entity factory,,

    https://hub.spigotmc.org/javadocs/spigot/org/bukkit/entity/LeashHitch.html
     
  6. Unfortunately there is no easy way to do this. The entity Item for the lead is created and spawned into the world after the EntityUnleashEvent is called and finished.

    Some NMS from EntityInsentient.java showing where the event gets fired from:
    Code (Text):
    protected void cV() {
        if (this.bF != null) {
            this.da();
        }

        if (this.bD) {
            if (!this.isAlive()) {
                this.world.getServer().getPluginManager().callEvent(new EntityUnleashEvent(this.getBukkitEntity(), UnleashReason.PLAYER_UNLEASH)); // CraftBukkit
                this.unleash(true, true);
            }

            if (this.leashHolder == null || this.leashHolder.dead) {
                this.world.getServer().getPluginManager().callEvent(new EntityUnleashEvent(this.getBukkitEntity(), UnleashReason.HOLDER_GONE)); // CraftBukkit
                this.unleash(true, true);
            }
        }
    }
    I did trace it all the way to the spawning of the Item entity, and it indeed fires off an ItemSpawnEvent, which is a little helpful because you can trace it's location compared to the hitch's location from the EntityUnleashEvent. You'd just have to track this between the events because they fire separately, and some type of scheduler to remove the tracked items after a brief delay (just a few ticks). Quite cumbersome, to say the least. Also, this allows for a margin of error since the lead's spawn location can vary from the hitch's location slightly. How big that margin of error is is left to be tested.

    Now, this can be fixed a better way, but would require someone to send a PR to Spigot. To fix, someone could simply add a boolean to the EntityUnleashEvent that defaults to true. This boolean can then be set to the 2nd boolean in the unleash() method shown above to prevent the lead from ever spawning if it was changed to false in a plugin's event listener.

    More NMS code from EntitySentient.java showing the unleash() method:
    Code (Text):
    public void unleash(boolean flag, boolean flag1) {
        if (this.bD) {
            this.bD = false;
            this.leashHolder = null;
            if (!this.world.isClientSide && flag1) {
                this.forceDrops = true; // CraftBukkit
                this.a(Items.LEAD, 1);
                this.forceDrops = false; // CraftBukkit
            }

            if (!this.world.isClientSide && flag && this.world instanceof WorldServer) {
                ((WorldServer) this.world).getTracker().a((Entity) this, (Packet) (new PacketPlayOutAttachEntity(this, (Entity) null)));
            }
        }
    }
    I'd do it, but I no longer send PRs to Spigot ;)
     
    #6 BillyGalbreath, May 5, 2017
    Last edited: May 5, 2017
    • Like Like x 2