diff --git a/Spigot-API-Patches/0076-Better-ProjectileHitEvent-API.patch b/Spigot-API-Patches/0076-Better-ProjectileHitEvent-API.patch new file mode 100644 index 000000000000..7ae8418e330f --- /dev/null +++ b/Spigot-API-Patches/0076-Better-ProjectileHitEvent-API.patch @@ -0,0 +1,196 @@ +From 2326dfc8d8961b6d6da4772593c5fa78e3456e5d Mon Sep 17 00:00:00 2001 +From: Vanolex +Date: Wed, 21 Jan 2026 01:33:31 +0100 +Subject: [PATCH] Better-ProjectileHitEvent-API + + +diff --git a/src/main/java/dev/rocco/kig/paper/api/event/ProjectileCollideEvent.java b/src/main/java/dev/rocco/kig/paper/api/event/ProjectileCollideEvent.java +index 4152109c..0ab8d44a 100644 +--- a/src/main/java/dev/rocco/kig/paper/api/event/ProjectileCollideEvent.java ++++ b/src/main/java/dev/rocco/kig/paper/api/event/ProjectileCollideEvent.java +@@ -4,21 +4,21 @@ import org.bukkit.entity.Entity; + import org.bukkit.entity.Projectile; + import org.bukkit.event.Cancellable; + import org.bukkit.event.HandlerList; +-import org.bukkit.event.entity.EntityEvent; + + /** + * Fired when a {@link Projectile} is about to collide with an {@link Entity}. + * Cancelling the event will make the projectile go through the entity. ++ * ++ * @deprecated use {@link ProjectilePreHitEntityEvent} + */ +-public class ProjectileCollideEvent extends EntityEvent implements Cancellable { ++@Deprecated ++public class ProjectileCollideEvent extends ProjectilePreHitEntityEvent implements Cancellable { + private static final HandlerList handlers = new HandlerList(); + +- private final Entity collided; + private boolean cancel; + + public ProjectileCollideEvent(Projectile projectile, Entity collided) { +- super(projectile); +- this.collided = collided; ++ super(projectile, collided); + } + + @Override +@@ -36,7 +36,7 @@ public class ProjectileCollideEvent extends EntityEvent implements Cancellable { + } + + public Entity getCollided() { +- return collided; ++ return getHitEntity(); + } + + @Override +diff --git a/src/main/java/dev/rocco/kig/paper/api/event/ProjectilePreHitBlockEvent.java b/src/main/java/dev/rocco/kig/paper/api/event/ProjectilePreHitBlockEvent.java +new file mode 100644 +index 00000000..c3acdf9d +--- /dev/null ++++ b/src/main/java/dev/rocco/kig/paper/api/event/ProjectilePreHitBlockEvent.java +@@ -0,0 +1,42 @@ ++package dev.rocco.kig.paper.api.event; ++ ++import org.bukkit.block.Block; ++import org.bukkit.block.BlockFace; ++import org.bukkit.entity.Projectile; ++import org.bukkit.event.entity.ProjectileHitEvent; ++ ++/** ++ * Called when a projectile hits a block. Called every tick when phasing through blocks. ++ */ ++public class ProjectilePreHitBlockEvent extends ProjectilePreHitEvent { ++ private final Block hitBlock; ++ private final BlockFace hitFace; ++ ++ public ProjectilePreHitBlockEvent(Projectile projectile, Block hitBlock, BlockFace hitFace) { this(projectile,hitBlock,hitFace,false); } ++ public ProjectilePreHitBlockEvent(Projectile projectile, Block hitBlock, BlockFace hitFace, boolean cancelled) { ++ super(projectile, cancelled); ++ this.hitBlock = hitBlock; ++ this.hitFace = hitFace; ++ } ++ ++ /** ++ * Gets the block that is about to be hit. ++ *

++ * Note: modifying the block does not change the outcome of the event. ++ * ++ * @return the block that is about to be hit ++ */ ++ public Block getHitBlock() { ++ return hitBlock; ++ } ++ ++ /** ++ * Gets the face of the block that is about to be hit. ++ * ++ * @return the face of the block that is about to be hit ++ */ ++ public BlockFace getHitFace() { ++ return hitFace; ++ } ++} ++ +diff --git a/src/main/java/dev/rocco/kig/paper/api/event/ProjectilePreHitEntityEvent.java b/src/main/java/dev/rocco/kig/paper/api/event/ProjectilePreHitEntityEvent.java +new file mode 100644 +index 00000000..c04ad72a +--- /dev/null ++++ b/src/main/java/dev/rocco/kig/paper/api/event/ProjectilePreHitEntityEvent.java +@@ -0,0 +1,27 @@ ++package dev.rocco.kig.paper.api.event; ++ ++import org.bukkit.entity.Entity; ++import org.bukkit.entity.Projectile; ++ ++/** ++ * Called when a projectile is about to hit an entity. ++ */ ++public class ProjectilePreHitEntityEvent extends ProjectilePreHitEvent { ++ ++ private final Entity hitEntity; ++ ++ public ProjectilePreHitEntityEvent(Projectile projectile, Entity hitEntity) { this(projectile, hitEntity, false); } ++ public ProjectilePreHitEntityEvent(Projectile projectile, Entity hitEntity, boolean cancelled) { ++ super(projectile, cancelled); ++ this.hitEntity = hitEntity; ++ } ++ ++ /** ++ * Gets the entity that is about to be hit. ++ * ++ * @return the entity that is about to be hit ++ */ ++ public Entity getHitEntity() { ++ return hitEntity; ++ } ++} +diff --git a/src/main/java/dev/rocco/kig/paper/api/event/ProjectilePreHitEvent.java b/src/main/java/dev/rocco/kig/paper/api/event/ProjectilePreHitEvent.java +new file mode 100644 +index 00000000..4726a60e +--- /dev/null ++++ b/src/main/java/dev/rocco/kig/paper/api/event/ProjectilePreHitEvent.java +@@ -0,0 +1,60 @@ ++package dev.rocco.kig.paper.api.event; ++ ++import org.bukkit.entity.Projectile; ++import org.bukkit.event.Cancellable; ++import org.bukkit.event.HandlerList; ++import org.bukkit.event.entity.EntityEvent; ++ ++/** ++ * Called when a projectile is about to hit something (Entity or Block). ++ * Cancelling disables collisions. ++ */ ++public class ProjectilePreHitEvent extends EntityEvent implements Cancellable { ++ private static final HandlerList handlers = new HandlerList(); ++ private boolean cancelled; ++ ++ public ProjectilePreHitEvent(final Projectile projectile) { this(projectile, false); } ++ public ProjectilePreHitEvent(final Projectile projectile, final boolean cancelled) { ++ super(projectile); ++ this.cancelled = cancelled; ++ } ++ ++ @Override ++ /** ++ * Gets the projectile involved in this event. ++ * ++ * @return the projectile involved in this event ++ */ ++ public Projectile getEntity() { ++ return (Projectile) entity; ++ } ++ ++ @Override ++ public HandlerList getHandlers() { ++ return handlers; ++ } ++ ++ /** ++ * Gets the handler list for this event. ++ * ++ * @return the handler list ++ */ ++ public static HandlerList getHandlerList() { ++ return handlers; ++ } ++ ++ @Override ++ public boolean isCancelled() { ++ return cancelled; ++ } ++ ++ @Override ++ /** ++ * Sets whether to cancel the collision. ++ * ++ * @param cancel true if the collision should be cancelled ++ */ ++ public void setCancelled(boolean cancel) { ++ cancelled = cancel; ++ } ++} +-- +2.51.0.windows.1 + diff --git a/Spigot-Server-Patches/0256-Better-ProjectileHitEvent-API.patch b/Spigot-Server-Patches/0256-Better-ProjectileHitEvent-API.patch new file mode 100644 index 000000000000..a3b66bfd1905 --- /dev/null +++ b/Spigot-Server-Patches/0256-Better-ProjectileHitEvent-API.patch @@ -0,0 +1,193 @@ +From 9cef6a2f9bcb79a176f428c9d37a8ed1c3c4cf1d Mon Sep 17 00:00:00 2001 +From: Vanolex +Date: Sat, 24 Jan 2026 00:30:00 +0100 +Subject: [PATCH] Better-ProjectileHitEvent-API + + +diff --git a/src/main/java/net/minecraft/server/EntityArrow.java b/src/main/java/net/minecraft/server/EntityArrow.java +index 78bb8bfbe..928bbbf7e 100644 +--- a/src/main/java/net/minecraft/server/EntityArrow.java ++++ b/src/main/java/net/minecraft/server/EntityArrow.java +@@ -1,9 +1,10 @@ + package net.minecraft.server; + + import dev.rocco.kig.paper.api.event.PlayerCheckCriticalEvent; +-import dev.rocco.kig.paper.api.event.ProjectileCollideEvent; ++import dev.rocco.kig.paper.api.event.ProjectilePreHitEvent; + import dev.rocco.kig.paper.api.particle.ProjectileEffect; + import org.bukkit.Location; ++import org.bukkit.craftbukkit.event.CraftEventFactory; + import org.bukkit.entity.LivingEntity; + import org.bukkit.entity.Player; + import org.bukkit.event.entity.EntityCombustByEntityEvent; +@@ -261,8 +262,13 @@ public class EntityArrow extends Entity implements IProjectile { + // PaperSpigot end + + // KigPaper start +- if (movingobjectposition != null && movingobjectposition.entity != null) { +- ProjectileCollideEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callProjectileCollideEvent(this, movingobjectposition.entity); ++ if (movingobjectposition != null) { ++ ProjectilePreHitEvent event; ++ if (movingobjectposition.entity != null) { ++ event = CraftEventFactory.callProjectileCollideEvent(this, movingobjectposition.entity); ++ } else { ++ event = CraftEventFactory.callProjectilePreHitBlockEvent(this, movingobjectposition); ++ } + if (event.isCancelled()) movingobjectposition = null; + } + // KigPaper end +diff --git a/src/main/java/net/minecraft/server/EntityFireball.java b/src/main/java/net/minecraft/server/EntityFireball.java +index 7a6a0843d..4418c9784 100644 +--- a/src/main/java/net/minecraft/server/EntityFireball.java ++++ b/src/main/java/net/minecraft/server/EntityFireball.java +@@ -2,7 +2,7 @@ package net.minecraft.server; + + import java.util.List; + +-import dev.rocco.kig.paper.api.event.ProjectileCollideEvent; ++import dev.rocco.kig.paper.api.event.ProjectilePreHitEvent; + import org.bukkit.craftbukkit.event.CraftEventFactory; // CraftBukkit + + public abstract class EntityFireball extends Entity { +@@ -128,8 +128,13 @@ public abstract class EntityFireball extends Entity { + } + + // KigPaper start +- if (movingobjectposition != null && movingobjectposition.entity != null) { +- ProjectileCollideEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callProjectileCollideEvent(this, movingobjectposition.entity); ++ if (movingobjectposition != null) { ++ ProjectilePreHitEvent event; ++ if (movingobjectposition.entity != null) { ++ event = CraftEventFactory.callProjectileCollideEvent(this, movingobjectposition.entity); ++ } else { ++ event = CraftEventFactory.callProjectilePreHitBlockEvent(this, movingobjectposition); ++ } + if (event.isCancelled()) movingobjectposition = null; + } + // KigPaper end +diff --git a/src/main/java/net/minecraft/server/EntityFishingHook.java b/src/main/java/net/minecraft/server/EntityFishingHook.java +index e5d2f80f6..d9dee525f 100644 +--- a/src/main/java/net/minecraft/server/EntityFishingHook.java ++++ b/src/main/java/net/minecraft/server/EntityFishingHook.java +@@ -1,8 +1,9 @@ + package net.minecraft.server; + +-import dev.rocco.kig.paper.api.event.ProjectileCollideEvent; ++import dev.rocco.kig.paper.api.event.ProjectilePreHitEvent; + import dev.rocco.kig.paper.api.particle.ProjectileEffect; + import org.bukkit.Location; ++import org.bukkit.craftbukkit.event.CraftEventFactory; + import org.bukkit.entity.Fish; + import org.bukkit.entity.Player; + import org.bukkit.event.player.PlayerFishEvent; +@@ -216,8 +217,15 @@ public class EntityFishingHook extends Entity { + // PaperSpigot end + + // KigPaper start +- if (movingobjectposition != null && movingobjectposition.entity != null) { +- ProjectileCollideEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callProjectileCollideEvent(this, movingobjectposition.entity); ++ boolean isBlockEventCancelled = false; ++ if (movingobjectposition != null) { ++ ProjectilePreHitEvent event; ++ if (movingobjectposition.entity != null) { ++ event = CraftEventFactory.callProjectileCollideEvent(this, movingobjectposition.entity); ++ } else { ++ event = CraftEventFactory.callProjectilePreHitBlockEvent(this, movingobjectposition); ++ isBlockEventCancelled = event.isCancelled(); ++ } + if (event.isCancelled()) movingobjectposition = null; + } + // KigPaper end +@@ -240,7 +248,16 @@ public class EntityFishingHook extends Entity { + trailEffect.spawn(loc); + } + } ++ ++ ++ boolean oldNoclip = this.noclip; // KigPaper ++ this.noclip = this.noclip || isBlockEventCancelled; // KigPaper - allow projectiles to pass through blocks when event cancelled ++ + this.move(this.motX, this.motY, this.motZ); ++ ++ this.noclip = oldNoclip; // KigPaper ++ ++ + float f1 = MathHelper.sqrt(this.motX * this.motX + this.motZ * this.motZ); + + this.yaw = (float) (MathHelper.b(this.motX, this.motZ) * 180.0D / 3.1415927410125732D); +diff --git a/src/main/java/net/minecraft/server/EntityProjectile.java b/src/main/java/net/minecraft/server/EntityProjectile.java +index 793cd1191..7692de18b 100644 +--- a/src/main/java/net/minecraft/server/EntityProjectile.java ++++ b/src/main/java/net/minecraft/server/EntityProjectile.java +@@ -2,9 +2,10 @@ package net.minecraft.server; + + // KigPaper start + +-import dev.rocco.kig.paper.api.event.ProjectileCollideEvent; ++import dev.rocco.kig.paper.api.event.ProjectilePreHitEvent; + import dev.rocco.kig.paper.api.particle.ProjectileEffect; + import org.bukkit.Location; ++import org.bukkit.craftbukkit.event.CraftEventFactory; + import org.bukkit.entity.Player; + + import java.util.List; +@@ -179,8 +180,11 @@ public abstract class EntityProjectile extends Entity implements IProjectile { + // PaperSpigot end + + // KigPaper start +- if (movingobjectposition != null && movingobjectposition.entity != null) { +- ProjectileCollideEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callProjectileCollideEvent(this, movingobjectposition.entity); ++ if (movingobjectposition != null) { ++ ProjectilePreHitEvent event = ++ movingobjectposition.entity != null ? ++ CraftEventFactory.callProjectileCollideEvent(this, movingobjectposition.entity) : ++ CraftEventFactory.callProjectilePreHitBlockEvent(this, movingobjectposition); + if (event.isCancelled()) movingobjectposition = null; + } + // KigPaper end +diff --git a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java +index ff62ce025..5b495c4ea 100644 +--- a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java ++++ b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java +@@ -10,6 +10,8 @@ import com.google.common.base.Function; + import com.google.common.base.Functions; + + import dev.rocco.kig.paper.api.event.ProjectileCollideEvent; ++import dev.rocco.kig.paper.api.event.ProjectilePreHitBlockEvent; ++import dev.rocco.kig.paper.api.event.ProjectilePreHitEntityEvent; + import net.minecraft.server.*; + + import org.bukkit.Bukkit; +@@ -766,11 +768,29 @@ public class CraftEventFactory { + } + + // KigPaper start ++ ++ /** ++ * @deprecated use {@link ProjectilePreHitEntityEvent} ++ */ ++ @Deprecated + public static ProjectileCollideEvent callProjectileCollideEvent(Entity entity, Entity collided) { + ProjectileCollideEvent event = new ProjectileCollideEvent((Projectile) entity.getBukkitEntity(), collided.getBukkitEntity()); + entity.world.getServer().getPluginManager().callEvent(event); + return event; + } ++ ++ public static ProjectilePreHitEntityEvent callProjectilePreHitEntityEvent(Entity projectile, Entity hitEntity) { ++ ProjectilePreHitEntityEvent event = new ProjectilePreHitEntityEvent((Projectile) projectile, hitEntity.getBukkitEntity()); ++ projectile.world.getServer().getPluginManager().callEvent(event); ++ return event; ++ } ++ ++ public static ProjectilePreHitBlockEvent callProjectilePreHitBlockEvent(Entity projectile, MovingObjectPosition movingObjectPosition) { ++ org.bukkit.block.Block block = projectile.world.getWorld().getBlockAt(movingObjectPosition.a().getX(), movingObjectPosition.a().getY(), movingObjectPosition.a().getZ()); ++ ProjectilePreHitBlockEvent event = new ProjectilePreHitBlockEvent((Projectile) projectile.getBukkitEntity(), block, CraftBlock.notchToBlockFace(movingObjectPosition.direction)); ++ projectile.world.getServer().getPluginManager().callEvent(event); ++ return event; ++ } + // KigPaper end + + public static ExpBottleEvent callExpBottleEvent(Entity entity, int exp) { +-- +2.51.0.windows.1 +