From 04f61108963f781d0f06637af64f9af50b8acf44 Mon Sep 17 00:00:00 2001 From: BillyGalbreath Date: Fri, 17 Aug 2018 16:55:40 -0500 Subject: [PATCH] 1.13: Player launch projectile event (#1249) Replaces PR #1193 for 1.13 I'm pretty sure I got all player launched projectiles (except arrows). Let me know if I missed any. This fixes a use-case specific issue that was discovered [here](https://www.spigotmc.org/threads/projectilehitevent-doesnt-work-in-survival-mode.327097/page-2#post-3059433). I have a use-case example a few posts down, [here](https://www.spigotmc.org/threads/projectilehitevent-doesnt-work-in-survival-mode.327097/page-2#post-3060204). --- .../0125-PlayerLaunchProjectileEvent.patch | 93 ++++++ .../0299-PlayerLaunchProjectileEvent.patch | 273 ++++++++++++++++++ 2 files changed, 366 insertions(+) create mode 100644 Spigot-API-Patches/0125-PlayerLaunchProjectileEvent.patch create mode 100644 Spigot-Server-Patches/0299-PlayerLaunchProjectileEvent.patch diff --git a/Spigot-API-Patches/0125-PlayerLaunchProjectileEvent.patch b/Spigot-API-Patches/0125-PlayerLaunchProjectileEvent.patch new file mode 100644 index 0000000000..f2d656641e --- /dev/null +++ b/Spigot-API-Patches/0125-PlayerLaunchProjectileEvent.patch @@ -0,0 +1,93 @@ +From 771312c9e0119acefafffcaa9ea40dd0106e7ca9 Mon Sep 17 00:00:00 2001 +From: BillyGalbreath +Date: Sat, 21 Jul 2018 03:10:50 -0500 +Subject: [PATCH] PlayerLaunchProjectileEvent + + +diff --git a/src/main/java/com/destroystokyo/paper/event/player/PlayerLaunchProjectileEvent.java b/src/main/java/com/destroystokyo/paper/event/player/PlayerLaunchProjectileEvent.java +new file mode 100644 +index 00000000..d2b244a4 +--- /dev/null ++++ b/src/main/java/com/destroystokyo/paper/event/player/PlayerLaunchProjectileEvent.java +@@ -0,0 +1,78 @@ ++package com.destroystokyo.paper.event.player; ++ ++import org.bukkit.entity.Player; ++import org.bukkit.entity.Projectile; ++import org.bukkit.event.Cancellable; ++import org.bukkit.event.HandlerList; ++import org.bukkit.event.player.PlayerEvent; ++import org.bukkit.inventory.ItemStack; ++ ++/** ++ * Called when a player shoots a projectile ++ */ ++public class PlayerLaunchProjectileEvent extends PlayerEvent implements Cancellable { ++ private static final HandlerList handlers = new HandlerList(); ++ private final Projectile projectile; ++ private final ItemStack itemStack; ++ private boolean consumeItem = true; ++ private boolean cancelled; ++ ++ public PlayerLaunchProjectileEvent(Player shooter, ItemStack itemStack, Projectile projectile) { ++ super(shooter); ++ this.itemStack = itemStack; ++ this.projectile = projectile; ++ } ++ ++ /** ++ * Gets the projectile which will be launched by this event ++ * ++ * @return the launched projectile ++ */ ++ public Projectile getProjectile() { ++ return projectile; ++ } ++ ++ /** ++ * Get the ItemStack used to fire the projectile ++ * ++ * @return The ItemStack used ++ */ ++ public ItemStack getItemStack() { ++ return itemStack; ++ } ++ ++ /** ++ * Get whether to consume the ItemStack or not ++ * ++ * @return True to consume ++ */ ++ public boolean shouldConsume() { ++ return consumeItem; ++ } ++ ++ /** ++ * Set whether to consume the ItemStack or not ++ * ++ * @param consumeItem True to consume ++ */ ++ public void setShouldConsume(boolean consumeItem) { ++ this.consumeItem = consumeItem; ++ } ++ ++ public boolean isCancelled() { ++ return cancelled; ++ } ++ ++ public void setCancelled(boolean cancel) { ++ cancelled = cancel; ++ } ++ ++ @Override ++ public HandlerList getHandlers() { ++ return handlers; ++ } ++ ++ public static HandlerList getHandlerList() { ++ return handlers; ++ } ++} +-- +2.11.0 + diff --git a/Spigot-Server-Patches/0299-PlayerLaunchProjectileEvent.patch b/Spigot-Server-Patches/0299-PlayerLaunchProjectileEvent.patch new file mode 100644 index 0000000000..77bbb0ddcf --- /dev/null +++ b/Spigot-Server-Patches/0299-PlayerLaunchProjectileEvent.patch @@ -0,0 +1,273 @@ +From 056a868d854ffc68bc947d2da87f127811835aca Mon Sep 17 00:00:00 2001 +From: BillyGalbreath +Date: Sat, 21 Jul 2018 03:11:03 -0500 +Subject: [PATCH] PlayerLaunchProjectileEvent + + +diff --git a/src/main/java/net/minecraft/server/ItemEgg.java b/src/main/java/net/minecraft/server/ItemEgg.java +index 771e809fb..ab4fdb7f0 100644 +--- a/src/main/java/net/minecraft/server/ItemEgg.java ++++ b/src/main/java/net/minecraft/server/ItemEgg.java +@@ -9,16 +9,34 @@ public class ItemEgg extends Item { + public InteractionResultWrapper a(World world, EntityHuman entityhuman, EnumHand enumhand) { + ItemStack itemstack = entityhuman.b(enumhand); + +- if (!entityhuman.abilities.canInstantlyBuild) { +- itemstack.subtract(1); +- } +- +- world.a((EntityHuman) null, entityhuman.locX, entityhuman.locY, entityhuman.locZ, SoundEffects.ENTITY_EGG_THROW, SoundCategory.PLAYERS, 0.5F, 0.4F / (ItemEgg.k.nextFloat() * 0.4F + 0.8F)); ++ // Paper start - moved down ++ //if (!entityhuman.abilities.canInstantlyBuild) { ++ // itemstack.subtract(1); ++ //} ++ // ++ //world.a((EntityHuman) null, entityhuman.locX, entityhuman.locY, entityhuman.locZ, SoundEffects.ENTITY_EGG_THROW, SoundCategory.PLAYERS, 0.5F, 0.4F / (ItemEgg.k.nextFloat() * 0.4F + 0.8F)); ++ // Paper end + if (!world.isClientSide) { + EntityEgg entityegg = new EntityEgg(world, entityhuman); + + entityegg.a(entityhuman, entityhuman.pitch, entityhuman.yaw, 0.0F, 1.5F, 1.0F); +- world.addEntity(entityegg); ++ // Paper start ++ com.destroystokyo.paper.event.player.PlayerLaunchProjectileEvent event = new com.destroystokyo.paper.event.player.PlayerLaunchProjectileEvent((org.bukkit.entity.Player) entityhuman.getBukkitEntity(), org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(itemstack), (org.bukkit.entity.Projectile) entityegg.getBukkitEntity()); ++ if (event.callEvent() && world.addEntity(entityegg)) { ++ if (event.shouldConsume() && !entityhuman.abilities.canInstantlyBuild) { ++ itemstack.subtract(1); ++ } else if (entityhuman instanceof EntityPlayer) { ++ ((EntityPlayer) entityhuman).getBukkitEntity().updateInventory(); ++ } ++ ++ world.a((EntityHuman) null, entityhuman.locX, entityhuman.locY, entityhuman.locZ, SoundEffects.ENTITY_EGG_THROW, SoundCategory.PLAYERS, 0.5F, 0.4F / (ItemEgg.k.nextFloat() * 0.4F + 0.8F)); ++ } else { ++ if (entityhuman instanceof EntityPlayer) { ++ ((EntityPlayer) entityhuman).getBukkitEntity().updateInventory(); ++ } ++ return new InteractionResultWrapper(EnumInteractionResult.FAIL, itemstack); ++ } ++ // Paper end + } + + entityhuman.b(StatisticList.ITEM_USED.b(this)); +diff --git a/src/main/java/net/minecraft/server/ItemEnderPearl.java b/src/main/java/net/minecraft/server/ItemEnderPearl.java +index 5559a5abe..cf1ba7ec9 100644 +--- a/src/main/java/net/minecraft/server/ItemEnderPearl.java ++++ b/src/main/java/net/minecraft/server/ItemEnderPearl.java +@@ -14,7 +14,19 @@ public class ItemEnderPearl extends Item { + EntityEnderPearl entityenderpearl = new EntityEnderPearl(world, entityhuman); + + entityenderpearl.a(entityhuman, entityhuman.pitch, entityhuman.yaw, 0.0F, 1.5F, 1.0F); +- if (!world.addEntity(entityenderpearl)) { ++ // Paper start ++ com.destroystokyo.paper.event.player.PlayerLaunchProjectileEvent event = new com.destroystokyo.paper.event.player.PlayerLaunchProjectileEvent((org.bukkit.entity.Player) entityhuman.getBukkitEntity(), org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(itemstack), (org.bukkit.entity.Projectile) entityenderpearl.getBukkitEntity()); ++ if (event.callEvent() && world.addEntity(entityenderpearl)) { ++ if (event.shouldConsume() && !entityhuman.abilities.canInstantlyBuild) { ++ itemstack.subtract(1); ++ } else if (entityhuman instanceof EntityPlayer) { ++ ((EntityPlayer) entityhuman).getBukkitEntity().updateInventory(); ++ } ++ ++ world.a((EntityHuman) null, entityhuman.locX, entityhuman.locY, entityhuman.locZ, SoundEffects.ENTITY_ENDER_PEARL_THROW, SoundCategory.NEUTRAL, 0.5F, 0.4F / (ItemEnderPearl.k.nextFloat() * 0.4F + 0.8F)); ++ entityhuman.getCooldownTracker().a(this, 20); ++ } else { ++ // Paper end + if (entityhuman instanceof EntityPlayer) { + ((EntityPlayer) entityhuman).getBukkitEntity().updateInventory(); + } +@@ -22,13 +34,15 @@ public class ItemEnderPearl extends Item { + } + } + +- if (!entityhuman.abilities.canInstantlyBuild) { +- itemstack.subtract(1); +- } +- +- world.a((EntityHuman) null, entityhuman.locX, entityhuman.locY, entityhuman.locZ, SoundEffects.ENTITY_ENDER_PEARL_THROW, SoundCategory.NEUTRAL, 0.5F, 0.4F / (ItemEnderPearl.k.nextFloat() * 0.4F + 0.8F)); +- entityhuman.getCooldownTracker().a(this, 20); +- // CraftBukkit end ++ // Paper start - moved up ++ //if (!entityhuman.abilities.canInstantlyBuild) { ++ // itemstack.subtract(1); ++ //} ++ // ++ //world.a((EntityHuman) null, entityhuman.locX, entityhuman.locY, entityhuman.locZ, SoundEffects.ENTITY_ENDER_PEARL_THROW, SoundCategory.NEUTRAL, 0.5F, 0.4F / (ItemEnderPearl.k.nextFloat() * 0.4F + 0.8F)); ++ //entityhuman.getCooldownTracker().a(this, 20); ++ // // CraftBukkit end ++ // Paper end + + entityhuman.b(StatisticList.ITEM_USED.b(this)); + return new InteractionResultWrapper(EnumInteractionResult.SUCCESS, itemstack); +diff --git a/src/main/java/net/minecraft/server/ItemExpBottle.java b/src/main/java/net/minecraft/server/ItemExpBottle.java +index c16456c4d..49c58fee7 100644 +--- a/src/main/java/net/minecraft/server/ItemExpBottle.java ++++ b/src/main/java/net/minecraft/server/ItemExpBottle.java +@@ -9,16 +9,34 @@ public class ItemExpBottle extends Item { + public InteractionResultWrapper a(World world, EntityHuman entityhuman, EnumHand enumhand) { + ItemStack itemstack = entityhuman.b(enumhand); + +- if (!entityhuman.abilities.canInstantlyBuild) { +- itemstack.subtract(1); +- } +- +- world.a((EntityHuman) null, entityhuman.locX, entityhuman.locY, entityhuman.locZ, SoundEffects.ENTITY_EXPERIENCE_BOTTLE_THROW, SoundCategory.NEUTRAL, 0.5F, 0.4F / (ItemExpBottle.k.nextFloat() * 0.4F + 0.8F)); ++ // Paper start - moved down ++ //if (!entityhuman.abilities.canInstantlyBuild) { ++ // itemstack.subtract(1); ++ //} ++ // ++ //world.a((EntityHuman) null, entityhuman.locX, entityhuman.locY, entityhuman.locZ, SoundEffects.ENTITY_EXPERIENCE_BOTTLE_THROW, SoundCategory.NEUTRAL, 0.5F, 0.4F / (ItemExpBottle.k.nextFloat() * 0.4F + 0.8F)); ++ // Paper end + if (!world.isClientSide) { + EntityThrownExpBottle entitythrownexpbottle = new EntityThrownExpBottle(world, entityhuman); + + entitythrownexpbottle.a(entityhuman, entityhuman.pitch, entityhuman.yaw, -20.0F, 0.7F, 1.0F); +- world.addEntity(entitythrownexpbottle); ++ // Paper start ++ com.destroystokyo.paper.event.player.PlayerLaunchProjectileEvent event = new com.destroystokyo.paper.event.player.PlayerLaunchProjectileEvent((org.bukkit.entity.Player) entityhuman.getBukkitEntity(), org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(itemstack), (org.bukkit.entity.Projectile) entitythrownexpbottle.getBukkitEntity()); ++ if (event.callEvent() && world.addEntity(entitythrownexpbottle)) { ++ if (event.shouldConsume() && !entityhuman.abilities.canInstantlyBuild) { ++ itemstack.subtract(1); ++ } else if (entityhuman instanceof EntityPlayer) { ++ ((EntityPlayer) entityhuman).getBukkitEntity().updateInventory(); ++ } ++ ++ world.a((EntityHuman) null, entityhuman.locX, entityhuman.locY, entityhuman.locZ, SoundEffects.ENTITY_EXPERIENCE_BOTTLE_THROW, SoundCategory.NEUTRAL, 0.5F, 0.4F / (ItemExpBottle.k.nextFloat() * 0.4F + 0.8F)); ++ } else { ++ if (entityhuman instanceof EntityPlayer) { ++ ((EntityPlayer) entityhuman).getBukkitEntity().updateInventory(); ++ } ++ return new InteractionResultWrapper(EnumInteractionResult.FAIL, itemstack); ++ } ++ // Paper end + } + + entityhuman.b(StatisticList.ITEM_USED.b(this)); +diff --git a/src/main/java/net/minecraft/server/ItemLingeringPotion.java b/src/main/java/net/minecraft/server/ItemLingeringPotion.java +index 8d3969b5f..44af46cbf 100644 +--- a/src/main/java/net/minecraft/server/ItemLingeringPotion.java ++++ b/src/main/java/net/minecraft/server/ItemLingeringPotion.java +@@ -8,14 +8,38 @@ public class ItemLingeringPotion extends ItemPotion { + + public InteractionResultWrapper a(World world, EntityHuman entityhuman, EnumHand enumhand) { + ItemStack itemstack = entityhuman.b(enumhand); +- ItemStack itemstack1 = entityhuman.abilities.canInstantlyBuild ? itemstack.cloneItemStack() : itemstack.cloneAndSubtract(1); +- +- world.a((EntityHuman) null, entityhuman.locX, entityhuman.locY, entityhuman.locZ, SoundEffects.ENTITY_LINGERING_POTION_THROW, SoundCategory.NEUTRAL, 0.5F, 0.4F / (ItemLingeringPotion.k.nextFloat() * 0.4F + 0.8F)); ++ // Paper start - moved down ++ //ItemStack itemstack1 = entityhuman.abilities.canInstantlyBuild ? itemstack.cloneItemStack() : itemstack.cloneAndSubtract(1); ++ // ++ //world.a((EntityHuman) null, entityhuman.locX, entityhuman.locY, entityhuman.locZ, SoundEffects.ENTITY_LINGERING_POTION_THROW, SoundCategory.NEUTRAL, 0.5F, 0.4F / (ItemLingeringPotion.k.nextFloat() * 0.4F + 0.8F)); ++ // Paper end + if (!world.isClientSide) { ++ // Paper start - ensure stack count matches vanilla behavior without modifying original stack yet ++ ItemStack itemstack1 = itemstack.cloneItemStack(); ++ if (!entityhuman.abilities.canInstantlyBuild) { ++ itemstack1.setCount(1); ++ } ++ // Paper end + EntityPotion entitypotion = new EntityPotion(world, entityhuman, itemstack1); + + entitypotion.a(entityhuman, entityhuman.pitch, entityhuman.yaw, -20.0F, 0.5F, 1.0F); +- world.addEntity(entitypotion); ++ // Paper start ++ com.destroystokyo.paper.event.player.PlayerLaunchProjectileEvent event = new com.destroystokyo.paper.event.player.PlayerLaunchProjectileEvent((org.bukkit.entity.Player) entityhuman.getBukkitEntity(), org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(itemstack), (org.bukkit.entity.Projectile) entitypotion.getBukkitEntity()); ++ if (event.callEvent() && world.addEntity(entitypotion)) { ++ if (event.shouldConsume() && !entityhuman.abilities.canInstantlyBuild) { ++ itemstack.subtract(1); ++ } else if (entityhuman instanceof EntityPlayer) { ++ ((EntityPlayer) entityhuman).getBukkitEntity().updateInventory(); ++ } ++ ++ world.a((EntityHuman) null, entityhuman.locX, entityhuman.locY, entityhuman.locZ, SoundEffects.ENTITY_LINGERING_POTION_THROW, SoundCategory.NEUTRAL, 0.5F, 0.4F / (ItemLingeringPotion.k.nextFloat() * 0.4F + 0.8F)); ++ } else { ++ if (entityhuman instanceof EntityPlayer) { ++ ((EntityPlayer) entityhuman).getBukkitEntity().updateInventory(); ++ } ++ return new InteractionResultWrapper(EnumInteractionResult.FAIL, itemstack); ++ } ++ // Paper end + } + + entityhuman.b(StatisticList.ITEM_USED.b(this)); +diff --git a/src/main/java/net/minecraft/server/ItemSnowball.java b/src/main/java/net/minecraft/server/ItemSnowball.java +index 597413f25..9d316bde3 100644 +--- a/src/main/java/net/minecraft/server/ItemSnowball.java ++++ b/src/main/java/net/minecraft/server/ItemSnowball.java +@@ -21,15 +21,23 @@ public class ItemSnowball extends Item { + EntitySnowball entitysnowball = new EntitySnowball(world, entityhuman); + + entitysnowball.a(entityhuman, entityhuman.pitch, entityhuman.yaw, 0.0F, 1.5F, 1.0F); +- if (world.addEntity(entitysnowball)) { +- if (!entityhuman.abilities.canInstantlyBuild) { ++ // Paper start ++ com.destroystokyo.paper.event.player.PlayerLaunchProjectileEvent event = new com.destroystokyo.paper.event.player.PlayerLaunchProjectileEvent((org.bukkit.entity.Player) entityhuman.getBukkitEntity(), org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(itemstack), (org.bukkit.entity.Projectile) entitysnowball.getBukkitEntity()); ++ if (event.callEvent() && world.addEntity(entitysnowball)) { ++ if (event.shouldConsume() && !entityhuman.abilities.canInstantlyBuild) { + itemstack.subtract(1); ++ } else if (entityhuman instanceof EntityPlayer) { ++ ((EntityPlayer) entityhuman).getBukkitEntity().updateInventory(); + } + + world.a((EntityHuman) null, entityhuman.locX, entityhuman.locY, entityhuman.locZ, SoundEffects.ENTITY_SNOWBALL_THROW, SoundCategory.NEUTRAL, 0.5F, 0.4F / (ItemSnowball.k.nextFloat() * 0.4F + 0.8F)); +- } else if (entityhuman instanceof EntityPlayer) { +- ((EntityPlayer) entityhuman).getBukkitEntity().updateInventory(); ++ } else { ++ if (entityhuman instanceof EntityPlayer) { ++ ((EntityPlayer) entityhuman).getBukkitEntity().updateInventory(); ++ } ++ return new InteractionResultWrapper(EnumInteractionResult.FAIL, itemstack); + } ++ // Paper end + } + // CraftBukkit end + +diff --git a/src/main/java/net/minecraft/server/ItemSplashPotion.java b/src/main/java/net/minecraft/server/ItemSplashPotion.java +index 7427f97d5..bc90d8936 100644 +--- a/src/main/java/net/minecraft/server/ItemSplashPotion.java ++++ b/src/main/java/net/minecraft/server/ItemSplashPotion.java +@@ -8,14 +8,38 @@ public class ItemSplashPotion extends ItemPotion { + + public InteractionResultWrapper a(World world, EntityHuman entityhuman, EnumHand enumhand) { + ItemStack itemstack = entityhuman.b(enumhand); +- ItemStack itemstack1 = entityhuman.abilities.canInstantlyBuild ? itemstack.cloneItemStack() : itemstack.cloneAndSubtract(1); +- +- world.a((EntityHuman) null, entityhuman.locX, entityhuman.locY, entityhuman.locZ, SoundEffects.ENTITY_SPLASH_POTION_THROW, SoundCategory.PLAYERS, 0.5F, 0.4F / (ItemSplashPotion.k.nextFloat() * 0.4F + 0.8F)); ++ // Paper start - moved down ++ //ItemStack itemstack1 = entityhuman.abilities.canInstantlyBuild ? itemstack.cloneItemStack() : itemstack.cloneAndSubtract(1); ++ // ++ //world.a((EntityHuman) null, entityhuman.locX, entityhuman.locY, entityhuman.locZ, SoundEffects.ENTITY_SPLASH_POTION_THROW, SoundCategory.PLAYERS, 0.5F, 0.4F / (ItemSplashPotion.k.nextFloat() * 0.4F + 0.8F)); ++ // Paper end + if (!world.isClientSide) { ++ // Paper start - ensure stack count matches vanilla behavior without modifying original stack yet ++ ItemStack itemstack1 = itemstack.cloneItemStack(); ++ if (!entityhuman.abilities.canInstantlyBuild) { ++ itemstack1.setCount(1); ++ } ++ // Paper end + EntityPotion entitypotion = new EntityPotion(world, entityhuman, itemstack1); + + entitypotion.a(entityhuman, entityhuman.pitch, entityhuman.yaw, -20.0F, 0.5F, 1.0F); +- world.addEntity(entitypotion); ++ // Paper start ++ com.destroystokyo.paper.event.player.PlayerLaunchProjectileEvent event = new com.destroystokyo.paper.event.player.PlayerLaunchProjectileEvent((org.bukkit.entity.Player) entityhuman.getBukkitEntity(), org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(itemstack), (org.bukkit.entity.Projectile) entitypotion.getBukkitEntity()); ++ if (event.callEvent() && world.addEntity(entitypotion)) { ++ if (event.shouldConsume() && !entityhuman.abilities.canInstantlyBuild) { ++ itemstack.subtract(1); ++ } else if (entityhuman instanceof EntityPlayer) { ++ ((EntityPlayer) entityhuman).getBukkitEntity().updateInventory(); ++ } ++ ++ world.a((EntityHuman) null, entityhuman.locX, entityhuman.locY, entityhuman.locZ, SoundEffects.ENTITY_SPLASH_POTION_THROW, SoundCategory.NEUTRAL, 0.5F, 0.4F / (ItemLingeringPotion.k.nextFloat() * 0.4F + 0.8F)); ++ } else { ++ if (entityhuman instanceof EntityPlayer) { ++ ((EntityPlayer) entityhuman).getBukkitEntity().updateInventory(); ++ } ++ return new InteractionResultWrapper(EnumInteractionResult.FAIL, itemstack); ++ } ++ // Paper end + } + + entityhuman.b(StatisticList.ITEM_USED.b(this)); +-- +2.11.0 +