diff --git a/build-data/paper.at b/build-data/paper.at index 1f7a551541..c57689418b 100644 --- a/build-data/paper.at +++ b/build-data/paper.at @@ -321,3 +321,6 @@ public net.minecraft.world.entity.item.FallingBlockEntity (Lnet/minecraft/ # Fix cancelling ProjectileHitEvent for piercing arrows protected net.minecraft.world.entity.projectile.Projectile hitCancelled + +# Expose firework item directly + manually setting flight ticks +public net.minecraft.world.entity.projectile.FireworkRocketEntity life diff --git a/patches/api/0373-More-Projectile-API.patch b/patches/api/0373-More-Projectile-API.patch new file mode 100644 index 0000000000..934b09b0a0 --- /dev/null +++ b/patches/api/0373-More-Projectile-API.patch @@ -0,0 +1,110 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Owen1212055 <23108066+Owen1212055@users.noreply.github.com> +Date: Wed, 26 May 2021 19:34:43 -0400 +Subject: [PATCH] More Projectile API + + +diff --git a/src/main/java/org/bukkit/entity/Firework.java b/src/main/java/org/bukkit/entity/Firework.java +index d616d5941b3c7b85e350e845901da798601b9a3c..b7a6e3b1ac327c4e03f9d73952c1ce4d54967cf4 100644 +--- a/src/main/java/org/bukkit/entity/Firework.java ++++ b/src/main/java/org/bukkit/entity/Firework.java +@@ -15,6 +15,8 @@ public interface Firework extends Projectile { + + /** + * Apply the provided meta to the fireworks ++ *

++ * Adjusts detonation ticks automatically. + * + * @param meta The FireworkMeta to apply + */ +@@ -54,4 +56,52 @@ public interface Firework extends Projectile { + @org.jetbrains.annotations.Nullable + public LivingEntity getBoostedEntity(); + // Paper end ++ ++ // Paper start - Firework API ++ /** ++ * Gets the item used in the firework. ++ * ++ * @return firework item ++ */ ++ @NotNull ++ public org.bukkit.inventory.ItemStack getItem(); ++ ++ /** ++ * Sets the item used in the firework. ++ *

++ * Firework explosion effects are used from this item. ++ * ++ * @param itemStack item to set ++ */ ++ void setItem(@org.jetbrains.annotations.Nullable org.bukkit.inventory.ItemStack itemStack); ++ ++ /** ++ * Gets the number of ticks the firework has flown. ++ * ++ * @return ticks flown ++ */ ++ int getTicksFlown(); ++ ++ /** ++ * Sets the number of ticks the firework has flown. ++ * Setting this greater than detonation ticks will cause the firework to explode. ++ * ++ * @param ticks ticks flown ++ */ ++ void setTicksFlown(int ticks); ++ ++ /** ++ * Gets the number of ticks the firework will detonate on. ++ * ++ * @return the tick to detonate on ++ */ ++ int getTicksToDetonate(); ++ ++ /** ++ * Set the amount of ticks the firework will detonate on. ++ * ++ * @param ticks ticks to detonate on ++ */ ++ void setTicksToDetonate(int ticks); ++ // Paper stop + } +diff --git a/src/main/java/org/bukkit/entity/ThrownPotion.java b/src/main/java/org/bukkit/entity/ThrownPotion.java +index 10a3c297bd87ad3ab4555054858f47a479e76e1a..1afda5d6d948b7e8589e69d3cd2c045763b5e784 100644 +--- a/src/main/java/org/bukkit/entity/ThrownPotion.java ++++ b/src/main/java/org/bukkit/entity/ThrownPotion.java +@@ -32,12 +32,29 @@ public interface ThrownPotion extends Projectile { + + /** + * Set the ItemStack for this thrown potion. +- *

+- * The ItemStack must be of type {@link org.bukkit.Material#SPLASH_POTION} +- * or {@link org.bukkit.Material#LINGERING_POTION}, otherwise an exception +- * is thrown. + * + * @param item New ItemStack + */ + public void setItem(@NotNull ItemStack item); ++ ++ // Paper start - Projectile API ++ /** ++ * Gets a copy of the PotionMeta for this thrown potion. ++ * This includes what effects will be applied by this potion. ++ * ++ * @return potion meta ++ */ ++ @NotNull ++ org.bukkit.inventory.meta.PotionMeta getPotionMeta(); ++ ++ /** ++ * Sets the PotionMeta of this thrown potion. ++ * This will modify the effects applied by this potion. ++ *

++ * Note that the type of {@link #getItem()} is irrelevant ++ * ++ * @param meta potion meta ++ */ ++ void setPotionMeta(@NotNull org.bukkit.inventory.meta.PotionMeta meta); ++ // Paper end + } diff --git a/patches/server/0881-More-Projectile-API.patch b/patches/server/0881-More-Projectile-API.patch new file mode 100644 index 0000000000..3a0c2d24c1 --- /dev/null +++ b/patches/server/0881-More-Projectile-API.patch @@ -0,0 +1,169 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Owen1212055 <23108066+Owen1212055@users.noreply.github.com> +Date: Tue, 22 Jun 2021 23:41:11 -0400 +Subject: [PATCH] More Projectile API + + +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftFirework.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftFirework.java +index be86114eac3975b82ca74d4d6ed3f0402a642e8a..a28178f2c2d4dda6481a58c73bada95aa95e6764 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftFirework.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftFirework.java +@@ -14,24 +14,26 @@ import org.bukkit.inventory.meta.FireworkMeta; + public class CraftFirework extends CraftProjectile implements Firework { + + private final Random random = new Random(); +- private final CraftItemStack item; ++ //private CraftItemStack item; // Paper - Remove usage, not accurate representation of current item. + + public CraftFirework(CraftServer server, FireworkRocketEntity entity) { + super(server, entity); + +- ItemStack item = this.getHandle().getEntityData().get(FireworkRocketEntity.DATA_ID_FIREWORKS_ITEM); +- +- if (item.isEmpty()) { +- item = new ItemStack(Items.FIREWORK_ROCKET); +- this.getHandle().getEntityData().set(FireworkRocketEntity.DATA_ID_FIREWORKS_ITEM, item); +- } +- +- this.item = CraftItemStack.asCraftMirror(item); +- +- // Ensure the item is a firework... +- if (this.item.getType() != Material.FIREWORK_ROCKET) { +- this.item.setType(Material.FIREWORK_ROCKET); +- } ++// Paper Start - Expose firework item directly ++// ItemStack item = this.getHandle().getEntityData().get(FireworkRocketEntity.DATA_ID_FIREWORKS_ITEM); ++// ++// if (item.isEmpty()) { ++// item = new ItemStack(Items.FIREWORK_ROCKET); ++// this.getHandle().getEntityData().set(FireworkRocketEntity.DATA_ID_FIREWORKS_ITEM, item); ++// } ++// ++// this.item = CraftItemStack.asCraftMirror(item); ++// ++// // Ensure the item is a firework... ++// if (this.item.getType() != Material.FIREWORK_ROCKET) { ++// this.item.setType(Material.FIREWORK_ROCKET); ++// } ++ // Paper End - Expose firework item directly + } + + @Override +@@ -51,13 +53,13 @@ public class CraftFirework extends CraftProjectile implements Firework { + + @Override + public FireworkMeta getFireworkMeta() { +- return (FireworkMeta) this.item.getItemMeta(); ++ return (FireworkMeta) CraftItemStack.getItemMeta(this.getHandle().getEntityData().get(FireworkRocketEntity.DATA_ID_FIREWORKS_ITEM), Material.FIREWORK_ROCKET); // Paper - Expose firework item directly + } + + @Override + public void setFireworkMeta(FireworkMeta meta) { +- this.item.setItemMeta(meta); + ++ applyFireworkEffect(meta); // Paper - Expose firework item directly + // Copied from EntityFireworks constructor, update firework lifetime/power + this.getHandle().lifetime = 10 * (1 + meta.getPower()) + this.random.nextInt(6) + this.random.nextInt(7); + +@@ -91,4 +93,43 @@ public class CraftFirework extends CraftProjectile implements Firework { + return boostedEntity != null ? (org.bukkit.entity.LivingEntity) boostedEntity.getBukkitEntity() : null; + } + // Paper end ++ // Paper start - Expose firework item directly + manually setting flight ++ @Override ++ public org.bukkit.inventory.ItemStack getItem() { ++ return CraftItemStack.asBukkitCopy(this.getHandle().getItem()); ++ } ++ ++ @Override ++ public void setItem(org.bukkit.inventory.ItemStack itemStack) { ++ FireworkMeta meta = getFireworkMeta(); ++ var nmsItem = itemStack == null ? ItemStack.EMPTY : CraftItemStack.asNMSCopy(itemStack); ++ this.getHandle().getEntityData().set(FireworkRocketEntity.DATA_ID_FIREWORKS_ITEM, nmsItem); ++ ++ applyFireworkEffect(meta); ++ } ++ ++ @Override ++ public int getTicksFlown() { ++ return this.getHandle().life; ++ } ++ ++ @Override ++ public void setTicksFlown(int ticks) { ++ this.getHandle().life = ticks; ++ } ++ ++ @Override ++ public int getTicksToDetonate() { ++ return this.getHandle().lifetime; ++ } ++ ++ @Override ++ public void setTicksToDetonate(int ticks) { ++ this.getHandle().lifetime = ticks; ++ } ++ ++ void applyFireworkEffect(FireworkMeta meta) { ++ CraftItemStack.applyMetaToItem(this.getHandle().getEntityData().get(FireworkRocketEntity.DATA_ID_FIREWORKS_ITEM), meta); ++ } ++ // Paper end - Expose firework item directly + manually setting flight + } +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftThrownPotion.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftThrownPotion.java +index b08739dd1ffd041f0885af6c1f57dca9027763b6..aa3afdf320852e83bb530fff5616a61e33dbc30c 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftThrownPotion.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftThrownPotion.java +@@ -39,11 +39,25 @@ public class CraftThrownPotion extends CraftProjectile implements ThrownPotion { + Validate.notNull(item, "ItemStack cannot be null."); + + // The ItemStack must be a potion. +- Validate.isTrue(item.getType() == Material.LINGERING_POTION || item.getType() == Material.SPLASH_POTION, "ItemStack must be a lingering or splash potion. This item stack was " + item.getType() + "."); ++ //Validate.isTrue(item.getType() == Material.LINGERING_POTION || item.getType() == Material.SPLASH_POTION, "ItemStack must be a lingering or splash potion. This item stack was " + item.getType() + "."); // Paper - Projectile API ++ var meta = getPotionMeta(); // Paper - Projectile API + + this.getHandle().setItem(CraftItemStack.asNMSCopy(item)); ++ setPotionMeta(meta); // Paper - Projectile API + } + ++ // Paper start - Projectile API ++ @Override ++ public org.bukkit.inventory.meta.PotionMeta getPotionMeta() { ++ return (org.bukkit.inventory.meta.PotionMeta) CraftItemStack.getItemMeta(this.getHandle().getItemRaw(), Material.SPLASH_POTION); ++ } ++ ++ @Override ++ public void setPotionMeta(org.bukkit.inventory.meta.PotionMeta meta) { ++ CraftItemStack.applyMetaToItem(this.getHandle().getItemRaw(), meta); ++ this.getHandle().setItem(this.getHandle().getItemRaw()); // Reset item ++ } ++ // Paper end + @Override + public net.minecraft.world.entity.projectile.ThrownPotion getHandle() { + return (net.minecraft.world.entity.projectile.ThrownPotion) entity; +diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java +index 14da2997b5fff4434b1fe8d5a1b3109dde143740..226d9ac01c601fc8954a88bea93a521cdce79eda 100644 +--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java ++++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemStack.java +@@ -274,12 +274,20 @@ public final class CraftItemStack extends ItemStack { + public ItemMeta getItemMeta() { + return CraftItemStack.getItemMeta(this.handle); + } ++ // Paper start ++ public static void applyMetaToItem(net.minecraft.world.item.ItemStack itemStack, ItemMeta meta) { ++ ((org.bukkit.craftbukkit.inventory.CraftMetaItem) meta).applyToItem(itemStack.getOrCreateTag()); ++ } + + public static ItemMeta getItemMeta(net.minecraft.world.item.ItemStack item) { ++ return getItemMeta(item, CraftItemStack.getType(item)); ++ } ++ public static ItemMeta getItemMeta(net.minecraft.world.item.ItemStack item, Material material) { ++ // Paper end + if (!CraftItemStack.hasItemMeta(item)) { +- return CraftItemFactory.instance().getItemMeta(CraftItemStack.getType(item)); ++ return CraftItemFactory.instance().getItemMeta(material); // Paper + } +- switch (CraftItemStack.getType(item)) { ++ switch (material) { // Paper + case WRITTEN_BOOK: + return new CraftMetaBookSigned(item.getTag()); + case WRITABLE_BOOK: