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

Co-authored-by: Nassim Jahnke <nassim@njahnke.dev>
Co-authored-by: SoSeDiK <mrsosedik@gmail.com>

diff --git a/src/main/java/org/bukkit/entity/AbstractArrow.java b/src/main/java/org/bukkit/entity/AbstractArrow.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/org/bukkit/entity/AbstractArrow.java
+++ b/src/main/java/org/bukkit/entity/AbstractArrow.java
@@ -0,0 +0,0 @@ public interface AbstractArrow extends Projectile {
      * Gets the ItemStack which will be picked up from this arrow.
      *
      * @return The picked up ItemStack
+     * @deprecated use {@link #getItemStack()}
      */
     @NotNull
     @ApiStatus.Experimental
+    @Deprecated(forRemoval = true, since = "1.20.4") // Paper
     public ItemStack getItem();
 
     /**
      * Sets the ItemStack which will be picked up from this arrow.
      *
      * @param item ItemStack set to be picked up
+     * @deprecated use {@link #getItemStack()}
      */
     @ApiStatus.Experimental
+    @Deprecated(forRemoval = true, since = "1.20.4") // Paper
     public void setItem(@NotNull ItemStack item);
 
     /**
@@ -0,0 +0,0 @@ public interface AbstractArrow extends Projectile {
         CREATIVE_ONLY;
     }
     // Paper end
+
+    // Paper start - more projectile API
+    /**
+     * Gets the {@link ItemStack} for this arrow. This stack is used
+     * for both visuals on the arrow and the stack that could be picked up.
+     *
+     * @return The ItemStack, as if a player picked up the arrow
+     */
+    @NotNull ItemStack getItemStack();
+
+    /**
+     * Sets the {@link ItemStack} for this arrow. This stack is used for both
+     * visuals on the arrow and the stack that could be picked up.
+     *
+     * @param stack the arrow stack
+     */
+    void setItemStack(@NotNull ItemStack stack);
+
+    /**
+     * Sets the amount of ticks this arrow has been alive in the world
+     * This is used to determine when the arrow should be automatically despawned.
+     *
+     * @param ticks lifetime ticks
+     */
+    void setLifetimeTicks(int ticks);
+
+    /**
+     * Gets how many ticks this arrow has been in the world for.
+     *
+     * @return ticks this arrow has been in the world
+     */
+    int getLifetimeTicks();
+
+    /**
+     * Gets the sound that is played when this arrow hits an entity.
+     *
+     * @return sound that plays
+     */
+    @NotNull
+    org.bukkit.Sound getHitSound();
+
+    /**
+     * Sets the sound that is played when this arrow hits an entity.
+     *
+     * @param sound sound that is played
+     */
+    void setHitSound(@NotNull org.bukkit.Sound sound);
+    // Paper end - more projectile API
 }
diff --git a/src/main/java/org/bukkit/entity/Firework.java b/src/main/java/org/bukkit/entity/Firework.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/org/bukkit/entity/Firework.java
+++ b/src/main/java/org/bukkit/entity/Firework.java
@@ -0,0 +0,0 @@ public interface Firework extends Projectile {
 
     /**
      * Apply the provided meta to the fireworks
+     * <p>
+     * Adjusts detonation ticks automatically.
      *
      * @param meta The FireworkMeta to apply
      */
@@ -0,0 +0,0 @@ public interface Firework extends Projectile {
      * {@link #getMaxLife()}, the firework will detonate.
      *
      * @param ticks the ticks to set. Must be greater than or equal to 0
+     * @deprecated use {@link #setTicksFlown(int)}
      * @return true if the life was set, false if this firework has already detonated
      */
+    @Deprecated(forRemoval = true) // Paper
     boolean setLife(int ticks);
 
     /**
      * Get the ticks that this firework has been alive. When this value reaches
      * {@link #getMaxLife()}, the firework will detonate.
      *
+     * @deprecated use {@link #getTicksFlown()}
      * @return the life ticks
      */
+    @Deprecated(forRemoval = true) // Paper
     int getLife();
 
     /**
      * Set the time in ticks this firework will exist until it is detonated.
      *
      * @param ticks the ticks to set. Must be greater than 0
+     * @deprecated use {@link #setTicksToDetonate(int)}
      * @return true if the time was set, false if this firework has already detonated
      */
+    @Deprecated(forRemoval = true) // Paper
     boolean setMaxLife(int ticks);
 
     /**
      * Get the time in ticks this firework will exist until it is detonated.
      *
+     * @deprecated use {@link #getTicksToDetonate()}
      * @return the maximum life in ticks
      */
+    @Deprecated(forRemoval = true) // Paper
     int getMaxLife();
 
     /**
@@ -0,0 +0,0 @@ public interface Firework extends Projectile {
         return getAttachedTo();
     }
     // 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.
+     * <p>
+     * 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 end
 }
diff --git a/src/main/java/org/bukkit/entity/FishHook.java b/src/main/java/org/bukkit/entity/FishHook.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/org/bukkit/entity/FishHook.java
+++ b/src/main/java/org/bukkit/entity/FishHook.java
@@ -0,0 +0,0 @@ public interface FishHook extends Projectile {
          */
         BOBBING;
     }
+
+    // Paper start - More FishHook API
+    /**
+     * Get the number of ticks the hook needs to wait for a fish to bite.
+     *
+     * @return Number of ticks
+     */
+    int getWaitTime();
+
+    /**
+     * Sets the number of ticks the hook needs to wait for a fish to bite.
+     *
+     * @param ticks Number of ticks
+     */
+    void setWaitTime(int ticks);
+
+    /**
+     * Get the number of ticks the fish has to swim until biting the hook.
+     * The {@link #getWaitTime()} has to be zero or below for the fish to start the time until bite timer.
+     *
+     * @return number of ticks.
+     *         A value of one indicates that the fish bites the very next time the fish hook is ticked
+     *         while a value of zero represents a fish that has already bitten the hook.
+     * @see #getWaitTime()
+     */
+    @org.jetbrains.annotations.Range(from = 0, to = Integer.MAX_VALUE)
+    int getTimeUntilBite();
+
+    /**
+     * Sets the number of ticks the fish has to swim until biting the hook.
+     *
+     * @param ticks number of ticks.
+     *              One is the minimum that can be passed to this method and instructs the fish to bite the very next tick.
+     * @throws IllegalArgumentException if the passed tick value is less than one.
+     */
+    void setTimeUntilBite(@org.jetbrains.annotations.Range(from = 1, to = Integer.MAX_VALUE) int ticks) throws IllegalArgumentException;
+
+    /**
+     * Completely resets this fishing hook's fishing state, re-randomizing the time needed until a fish is lured and
+     * bites the hook.
+     * <p>
+     * This method takes all properties of the fishing hook into account when resetting said values, such as a lure
+     * enchantment.
+     */
+    void resetFishingState();
+    // Paper end
 }
diff --git a/src/main/java/org/bukkit/entity/Projectile.java b/src/main/java/org/bukkit/entity/Projectile.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/org/bukkit/entity/Projectile.java
+++ b/src/main/java/org/bukkit/entity/Projectile.java
@@ -0,0 +0,0 @@ public interface Projectile extends Entity {
      * Retrieve the shooter of this projectile.
      *
      * @return the {@link ProjectileSource} that shot this projectile
+     * @see #getOwnerUniqueId()
      */
     @Nullable
     public ProjectileSource getShooter();
@@ -0,0 +0,0 @@ public interface Projectile extends Entity {
      */
     @Deprecated(forRemoval = true)
     public void setBounce(boolean doesBounce);
+    // Paper start
+
+    /**
+     * Gets whether the projectile has left the
+     * hitbox of their shooter and can now hit entities.
+     *
+     * @return has left shooter's hitbox
+     */
+    boolean hasLeftShooter();
+
+    /**
+     * Sets whether the projectile has left the
+     * hitbox of their shooter and can now hit entities.
+     *
+     * This is recalculated each tick if the projectile has a shooter.
+     *
+     * @param leftShooter has left shooter's hitbox
+     */
+    void setHasLeftShooter(boolean leftShooter);
+
+    /**
+     * Gets whether the projectile has been
+     * shot into the world and has sent a projectile
+     * shot game event.
+     *
+     * @return has been shot into the world
+     */
+    boolean hasBeenShot();
+
+    /**
+     * Sets whether the projectile has been
+     * shot into the world and has sent a projectile
+     * shot game event in the next tick.
+     *
+     * Setting this to false will cause a game event
+     * to fire and the value to be set back to true.
+     *
+     * @param beenShot has been in shot into the world
+     */
+    void setHasBeenShot(boolean beenShot);
+
+    /**
+     * Gets whether this projectile can hit an entity.
+     * <p>
+     * This method returns true under the following conditions:
+     * <p>
+     * - The shooter can see the entity ({@link Player#canSee(Entity)}) <p>
+     * - The entity is alive and not a spectator <p>
+     * - The projectile has left the hitbox of the shooter ({@link #hasLeftShooter()})<p>
+     * - If this is an arrow with piercing, it has not pierced the entity already
+     *
+     * @param entity the entity to check if this projectile can hit
+     * @return true if this projectile can damage the entity, false otherwise
+     */
+    boolean canHitEntity(@org.jetbrains.annotations.NotNull Entity entity);
+
+    /**
+     * Makes this projectile hit a specific entity.
+     * This uses the current position of the projectile for the hit point.
+     * Using this method will result in {@link org.bukkit.event.entity.ProjectileHitEvent} being called.
+     * @param entity the entity to hit
+     * @see #hitEntity(Entity, org.bukkit.util.Vector)
+     * @see #canHitEntity(Entity) 
+     */
+    void hitEntity(@org.jetbrains.annotations.NotNull Entity entity);
+
+    /**
+     * Makes this projectile hit a specific entity from a specific point.
+     * Using this method will result in {@link org.bukkit.event.entity.ProjectileHitEvent} being called.
+     * @param entity the entity to hit
+     * @param vector the direction to hit from
+     * @see #hitEntity(Entity)
+     * @see #canHitEntity(Entity) 
+     */
+    void hitEntity(@org.jetbrains.annotations.NotNull Entity entity, @org.jetbrains.annotations.NotNull org.bukkit.util.Vector vector);
+
+    /**
+     * Gets the owner's UUID
+     *
+     * @return the owner's UUID, or null if not owned
+     * @see #getShooter()
+     */
+    @Nullable
+    java.util.UUID getOwnerUniqueId();
+    // Paper end
 }
diff --git a/src/main/java/org/bukkit/entity/ShulkerBullet.java b/src/main/java/org/bukkit/entity/ShulkerBullet.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/org/bukkit/entity/ShulkerBullet.java
+++ b/src/main/java/org/bukkit/entity/ShulkerBullet.java
@@ -0,0 +0,0 @@ public interface ShulkerBullet extends Projectile {
      * @param target the entity to target
      */
     void setTarget(@Nullable Entity target);
+    // Paper start
+    /**
+     * Gets the relative offset that this shulker bullet should move towards,
+     * note that this will change each tick as the skulker bullet approaches the target.
+     *
+     * @return target delta offset
+     */
+    @org.jetbrains.annotations.NotNull
+    org.bukkit.util.Vector getTargetDelta();
+
+
+    /**
+     * Sets the relative offset that this shulker bullet should move towards,
+     * note that this will change each tick as the skulker bullet approaches the target.
+     * This is usually relative towards their target.
+     *
+     * @param vector target
+     */
+    void setTargetDelta(@org.jetbrains.annotations.NotNull org.bukkit.util.Vector vector);
+
+    /**
+     * Gets the current movement direction.
+     * This is used to determine the next movement direction to ensure
+     * that the bullet does not move in the same direction.
+     *
+     * @return null or their current direction
+     */
+    @Nullable
+    org.bukkit.block.BlockFace getCurrentMovementDirection();
+
+    /**
+     * Set the current movement direction.
+     * This is used to determine the next movement direction to ensure
+     * that the bullet does not move in the same direction.
+     *
+     * Set to null to simply pick a random direction.
+     *
+     * @param movementDirection null or a direction
+     */
+    void setCurrentMovementDirection(@Nullable org.bukkit.block.BlockFace movementDirection);
+
+    /**
+     * Gets how many ticks this shulker bullet
+     * will attempt to move in its current direction.
+     *
+     * @return number of steps
+     */
+    int getFlightSteps();
+
+    /**
+     * Sets how many ticks this shulker bullet
+     * will attempt to move in its current direction.
+     *
+     * @param steps number of steps
+     */
+    void setFlightSteps(int steps);
+    // Paper end
 }
diff --git a/src/main/java/org/bukkit/entity/ThrownPotion.java b/src/main/java/org/bukkit/entity/ThrownPotion.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/org/bukkit/entity/ThrownPotion.java
+++ b/src/main/java/org/bukkit/entity/ThrownPotion.java
@@ -0,0 +0,0 @@ public interface ThrownPotion extends ThrowableProjectile {
 
     /**
      * Set the ItemStack for this thrown potion.
-     * <p>
-     * 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.
+     * <p>
+     * Note that the type of {@link #getItem()} is irrelevant
+     *
+     * @param meta potion meta
+     */
+    void setPotionMeta(@NotNull org.bukkit.inventory.meta.PotionMeta meta);
+
+    /**
+     * Splashes the potion at its current location.
+     */
+    void splash();
+    // Paper end
 }
diff --git a/src/main/java/org/bukkit/entity/Trident.java b/src/main/java/org/bukkit/entity/Trident.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/org/bukkit/entity/Trident.java
+++ b/src/main/java/org/bukkit/entity/Trident.java
@@ -0,0 +0,0 @@ public interface Trident extends AbstractArrow, ThrowableProjectile {
      * @throws IllegalArgumentException if the loyalty level is lower than 0 or greater than 127
      */
     void setLoyaltyLevel(int loyaltyLevel);
+
+    /**
+     * Gets if this trident has dealt damage to an
+     * entity yet or has hit the floor.
+     *
+     * If neither of these events have occurred yet, this will
+     * return false.
+     *
+     * @return has dealt damage
+     */
+    boolean hasDealtDamage();
+
+    /**
+     * Sets if this trident has dealt damage to an entity
+     * yet or has hit the floor.
+     *
+     * @param hasDealtDamage has dealt damage or hit the floor
+     */
+    void setHasDealtDamage(boolean hasDealtDamage);
 }
 // Paper end