Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
196 changes: 196 additions & 0 deletions Spigot-API-Patches/0076-Better-ProjectileHitEvent-API.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,196 @@
From 2326dfc8d8961b6d6da4772593c5fa78e3456e5d Mon Sep 17 00:00:00 2001
From: Vanolex <vanolex@vanolex.net>
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.
+ * <p>
+ * 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

193 changes: 193 additions & 0 deletions Spigot-Server-Patches/0256-Better-ProjectileHitEvent-API.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,193 @@
From 9cef6a2f9bcb79a176f428c9d37a8ed1c3c4cf1d Mon Sep 17 00:00:00 2001
From: Vanolex <vanolex@vanolex.net>
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