mirror of
https://github.com/PaperMC/Paper.git
synced 2025-02-10 01:21:46 +01:00
Add predicate for block when raytracing (#9691)
* Add predicate for block data when raytracing blocks * Match based on block, instead of block data * Use instanceof instead of casting * Use Position instead of Location, add overload for rayTraceEntities * Implement requested changes * Invert predicate * Cleanup
This commit is contained in:
parent
6e88b4fa1e
commit
e83e680321
@ -273,6 +273,13 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
|||||||
+ boolean isFine();
|
+ boolean isFine();
|
||||||
+
|
+
|
||||||
+ /**
|
+ /**
|
||||||
|
+ * Checks if each component of this position is finite.
|
||||||
|
+ */
|
||||||
|
+ default boolean isFinite() {
|
||||||
|
+ return Double.isFinite(this.x()) && Double.isFinite(this.y()) && Double.isFinite(this.z());
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ /**
|
||||||
+ * Returns a position offset by the specified amounts.
|
+ * Returns a position offset by the specified amounts.
|
||||||
+ *
|
+ *
|
||||||
+ * @param x x value to offset
|
+ * @param x x value to offset
|
||||||
@ -415,6 +422,11 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
|||||||
+ }
|
+ }
|
||||||
+
|
+
|
||||||
+ @Override
|
+ @Override
|
||||||
|
+ public boolean isFinite() {
|
||||||
|
+ return io.papermc.paper.math.FinePosition.super.isFinite() && Float.isFinite(this.getYaw()) && Float.isFinite(this.getPitch());
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ @Override
|
||||||
+ public @NotNull Location toLocation(@NotNull World world) {
|
+ public @NotNull Location toLocation(@NotNull World world) {
|
||||||
+ return new Location(world, this.x(), this.y(), this.z(), this.getYaw(), this.getPitch());
|
+ return new Location(world, this.x(), this.y(), this.z(), this.getYaw(), this.getPitch());
|
||||||
+ }
|
+ }
|
||||||
|
119
patches/api/Add-predicate-for-blocks-when-raytracing.patch
Normal file
119
patches/api/Add-predicate-for-blocks-when-raytracing.patch
Normal file
@ -0,0 +1,119 @@
|
|||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: TonytheMacaroni <tonythemacaroni123@gmail.com>
|
||||||
|
Date: Wed, 6 Sep 2023 19:24:53 -0400
|
||||||
|
Subject: [PATCH] Add predicate for blocks when raytracing
|
||||||
|
|
||||||
|
|
||||||
|
diff --git a/src/main/java/org/bukkit/World.java b/src/main/java/org/bukkit/World.java
|
||||||
|
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||||
|
--- a/src/main/java/org/bukkit/World.java
|
||||||
|
+++ b/src/main/java/org/bukkit/World.java
|
||||||
|
@@ -0,0 +0,0 @@ public interface World extends RegionAccessor, WorldInfo, PluginMessageRecipient
|
||||||
|
@Nullable
|
||||||
|
public RayTraceResult rayTraceEntities(@NotNull Location start, @NotNull Vector direction, double maxDistance, double raySize, @Nullable Predicate<Entity> filter);
|
||||||
|
|
||||||
|
+ // Paper start
|
||||||
|
+ /**
|
||||||
|
+ * Performs a ray trace that checks for entity collisions.
|
||||||
|
+ * <p>
|
||||||
|
+ * This may not consider entities in currently unloaded chunks. Some
|
||||||
|
+ * implementations may impose artificial restrictions on the maximum
|
||||||
|
+ * distance.
|
||||||
|
+ *
|
||||||
|
+ * @param start the start position
|
||||||
|
+ * @param direction the ray direction
|
||||||
|
+ * @param maxDistance the maximum distance
|
||||||
|
+ * @param raySize entity bounding boxes will be uniformly expanded (or
|
||||||
|
+ * shrinked) by this value before doing collision checks
|
||||||
|
+ * @param filter only entities that fulfill this predicate are considered,
|
||||||
|
+ * or <code>null</code> to consider all entities
|
||||||
|
+ * @return the closest ray trace hit result, or <code>null</code> if there
|
||||||
|
+ * is no hit
|
||||||
|
+ */
|
||||||
|
+ @Nullable
|
||||||
|
+ public RayTraceResult rayTraceEntities(@NotNull io.papermc.paper.math.Position start, @NotNull Vector direction, double maxDistance, double raySize, @Nullable Predicate<Entity> filter);
|
||||||
|
+ // Paper end
|
||||||
|
+
|
||||||
|
/**
|
||||||
|
* Performs a ray trace that checks for block collisions using the blocks'
|
||||||
|
* precise collision shapes.
|
||||||
|
@@ -0,0 +0,0 @@ public interface World extends RegionAccessor, WorldInfo, PluginMessageRecipient
|
||||||
|
@Nullable
|
||||||
|
public RayTraceResult rayTraceBlocks(@NotNull Location start, @NotNull Vector direction, double maxDistance, @NotNull FluidCollisionMode fluidCollisionMode, boolean ignorePassableBlocks);
|
||||||
|
|
||||||
|
+ // Paper start
|
||||||
|
+ /**
|
||||||
|
+ * Performs a ray trace that checks for block collisions using the blocks'
|
||||||
|
+ * precise collision shapes.
|
||||||
|
+ * <p>
|
||||||
|
+ * If collisions with passable blocks are ignored, fluid collisions are
|
||||||
|
+ * ignored as well regardless of the fluid collision mode.
|
||||||
|
+ * <p>
|
||||||
|
+ * Portal blocks are only considered passable if the ray starts within
|
||||||
|
+ * them. Apart from that collisions with portal blocks will be considered
|
||||||
|
+ * even if collisions with passable blocks are otherwise ignored.
|
||||||
|
+ * <p>
|
||||||
|
+ * This may cause loading of chunks! Some implementations may impose
|
||||||
|
+ * artificial restrictions on the maximum distance.
|
||||||
|
+ *
|
||||||
|
+ * @param start the start position
|
||||||
|
+ * @param direction the ray direction
|
||||||
|
+ * @param maxDistance the maximum distance
|
||||||
|
+ * @param fluidCollisionMode the fluid collision mode
|
||||||
|
+ * @param ignorePassableBlocks whether to ignore passable but collidable
|
||||||
|
+ * blocks (ex. tall grass, signs, fluids, ..)
|
||||||
|
+ * @param canCollide predicate for blocks the ray can potentially collide
|
||||||
|
+ * with, or <code>null</code> to consider all blocks
|
||||||
|
+ * @return the ray trace hit result, or <code>null</code> if there is no hit
|
||||||
|
+ */
|
||||||
|
+ @Nullable
|
||||||
|
+ public RayTraceResult rayTraceBlocks(@NotNull io.papermc.paper.math.Position start, @NotNull Vector direction, double maxDistance, @NotNull FluidCollisionMode fluidCollisionMode, boolean ignorePassableBlocks, @Nullable Predicate<Block> canCollide);
|
||||||
|
+ // Paper end
|
||||||
|
+
|
||||||
|
/**
|
||||||
|
* Performs a ray trace that checks for both block and entity collisions.
|
||||||
|
* <p>
|
||||||
|
@@ -0,0 +0,0 @@ public interface World extends RegionAccessor, WorldInfo, PluginMessageRecipient
|
||||||
|
@Nullable
|
||||||
|
public RayTraceResult rayTrace(@NotNull Location start, @NotNull Vector direction, double maxDistance, @NotNull FluidCollisionMode fluidCollisionMode, boolean ignorePassableBlocks, double raySize, @Nullable Predicate<Entity> filter);
|
||||||
|
|
||||||
|
+ // Paper start
|
||||||
|
+ /**
|
||||||
|
+ * Performs a ray trace that checks for both block and entity collisions.
|
||||||
|
+ * <p>
|
||||||
|
+ * Block collisions use the blocks' precise collision shapes. The
|
||||||
|
+ * <code>raySize</code> parameter is only taken into account for entity
|
||||||
|
+ * collision checks.
|
||||||
|
+ * <p>
|
||||||
|
+ * If collisions with passable blocks are ignored, fluid collisions are
|
||||||
|
+ * ignored as well regardless of the fluid collision mode.
|
||||||
|
+ * <p>
|
||||||
|
+ * Portal blocks are only considered passable if the ray starts within them.
|
||||||
|
+ * Apart from that collisions with portal blocks will be considered even if
|
||||||
|
+ * collisions with passable blocks are otherwise ignored.
|
||||||
|
+ * <p>
|
||||||
|
+ * This may cause loading of chunks! Some implementations may impose
|
||||||
|
+ * artificial restrictions on the maximum distance.
|
||||||
|
+ *
|
||||||
|
+ * @param start the start position
|
||||||
|
+ * @param direction the ray direction
|
||||||
|
+ * @param maxDistance the maximum distance
|
||||||
|
+ * @param fluidCollisionMode the fluid collision mode
|
||||||
|
+ * @param ignorePassableBlocks whether to ignore passable but collidable
|
||||||
|
+ * blocks (ex. tall grass, signs, fluids, ..)
|
||||||
|
+ * @param raySize entity bounding boxes will be uniformly expanded (or
|
||||||
|
+ * shrinked) by this value before doing collision checks
|
||||||
|
+ * @param filter only entities that fulfill this predicate are considered,
|
||||||
|
+ * or <code>null</code> to consider all entities
|
||||||
|
+ * @param canCollide predicate for blocks the ray can potentially collide
|
||||||
|
+ * with, or <code>null</code> to consider all blocks
|
||||||
|
+ * @return the closest ray trace hit result with either a block or an
|
||||||
|
+ * entity, or <code>null</code> if there is no hit
|
||||||
|
+ */
|
||||||
|
+ @Nullable
|
||||||
|
+ public RayTraceResult rayTrace(@NotNull io.papermc.paper.math.Position start, @NotNull Vector direction, double maxDistance, @NotNull FluidCollisionMode fluidCollisionMode, boolean ignorePassableBlocks, double raySize, @Nullable Predicate<Entity> filter, @Nullable Predicate<Block> canCollide);
|
||||||
|
+ // Paper end
|
||||||
|
+
|
||||||
|
/**
|
||||||
|
* Gets the default spawn {@link Location} of this world
|
||||||
|
*
|
116
patches/server/Add-predicate-for-blocks-when-raytracing.patch
Normal file
116
patches/server/Add-predicate-for-blocks-when-raytracing.patch
Normal file
@ -0,0 +1,116 @@
|
|||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: TonytheMacaroni <tonythemacaroni123@gmail.com>
|
||||||
|
Date: Wed, 6 Sep 2023 19:24:16 -0400
|
||||||
|
Subject: [PATCH] Add predicate for blocks when raytracing
|
||||||
|
|
||||||
|
|
||||||
|
diff --git a/src/main/java/net/minecraft/world/level/BlockGetter.java b/src/main/java/net/minecraft/world/level/BlockGetter.java
|
||||||
|
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||||
|
--- a/src/main/java/net/minecraft/world/level/BlockGetter.java
|
||||||
|
+++ b/src/main/java/net/minecraft/world/level/BlockGetter.java
|
||||||
|
@@ -0,0 +0,0 @@ public interface BlockGetter extends LevelHeightAccessor {
|
||||||
|
|
||||||
|
// CraftBukkit start - moved block handling into separate method for use by Block#rayTrace
|
||||||
|
default BlockHitResult clip(ClipContext raytrace1, BlockPos blockposition) {
|
||||||
|
+ // Paper start
|
||||||
|
+ return clip(raytrace1, blockposition, null);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ default BlockHitResult clip(ClipContext raytrace1, BlockPos blockposition, java.util.function.Predicate<org.bukkit.block.Block> canCollide) {
|
||||||
|
+ // Paper end
|
||||||
|
// Paper start - Prevent raytrace from loading chunks
|
||||||
|
BlockState iblockdata = this.getBlockStateIfLoaded(blockposition);
|
||||||
|
if (iblockdata == null) {
|
||||||
|
@@ -0,0 +0,0 @@ public interface BlockGetter extends LevelHeightAccessor {
|
||||||
|
return BlockHitResult.miss(raytrace1.getTo(), Direction.getNearest(vec3d.x, vec3d.y, vec3d.z), BlockPos.containing(raytrace1.getTo()));
|
||||||
|
}
|
||||||
|
// Paper end
|
||||||
|
- if (iblockdata.isAir()) return null; // Paper - optimise air cases
|
||||||
|
+ if (iblockdata.isAir() || (canCollide != null && this instanceof LevelAccessor levelAccessor && !canCollide.test(org.bukkit.craftbukkit.block.CraftBlock.at(levelAccessor, blockposition)))) return null; // Paper - optimise air cases and check canCollide predicate
|
||||||
|
FluidState fluid = iblockdata.getFluidState(); // Paper - don't need to go to world state again
|
||||||
|
Vec3 vec3d = raytrace1.getFrom();
|
||||||
|
Vec3 vec3d1 = raytrace1.getTo();
|
||||||
|
@@ -0,0 +0,0 @@ public interface BlockGetter extends LevelHeightAccessor {
|
||||||
|
// CraftBukkit end
|
||||||
|
|
||||||
|
default BlockHitResult clip(ClipContext context) {
|
||||||
|
+ // Paper start
|
||||||
|
+ return clip(context, (java.util.function.Predicate<org.bukkit.block.Block>) null);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ default BlockHitResult clip(ClipContext context, java.util.function.Predicate<org.bukkit.block.Block> canCollide) {
|
||||||
|
+ // Paper end
|
||||||
|
return (BlockHitResult) BlockGetter.traverseBlocks(context.getFrom(), context.getTo(), context, (raytrace1, blockposition) -> {
|
||||||
|
- return this.clip(raytrace1, blockposition); // CraftBukkit - moved into separate method
|
||||||
|
+ return this.clip(raytrace1, blockposition, canCollide); // CraftBukkit - moved into separate method // Paper - use method with canCollide predicate
|
||||||
|
}, (raytrace1) -> {
|
||||||
|
Vec3 vec3d = raytrace1.getFrom().subtract(raytrace1.getTo());
|
||||||
|
|
||||||
|
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
|
||||||
|
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||||
|
--- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
|
||||||
|
+++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
|
||||||
|
@@ -0,0 +0,0 @@ public class CraftWorld extends CraftRegionAccessor implements World {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public RayTraceResult rayTraceEntities(Location start, Vector direction, double maxDistance, double raySize, Predicate<Entity> filter) {
|
||||||
|
+ // Paper start
|
||||||
|
+ return rayTraceEntities((io.papermc.paper.math.Position) start, direction, maxDistance, raySize, filter);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ public RayTraceResult rayTraceEntities(io.papermc.paper.math.Position start, Vector direction, double maxDistance, double raySize, Predicate<Entity> filter) {
|
||||||
|
Preconditions.checkArgument(start != null, "Location start cannot be null");
|
||||||
|
- Preconditions.checkArgument(this.equals(start.getWorld()), "Location start cannot be in a different world");
|
||||||
|
- start.checkFinite();
|
||||||
|
+ Preconditions.checkArgument(!(start instanceof Location location) || this.equals(location.getWorld()), "Location start cannot be in a different world");
|
||||||
|
+ Preconditions.checkArgument(start.isFinite(), "Location start is not finite");
|
||||||
|
+ // Paper end
|
||||||
|
|
||||||
|
Preconditions.checkArgument(direction != null, "Vector direction cannot be null");
|
||||||
|
direction.checkFinite();
|
||||||
|
@@ -0,0 +0,0 @@ public class CraftWorld extends CraftRegionAccessor implements World {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public RayTraceResult rayTraceBlocks(Location start, Vector direction, double maxDistance, FluidCollisionMode fluidCollisionMode, boolean ignorePassableBlocks) {
|
||||||
|
+ // Paper start
|
||||||
|
+ return this.rayTraceBlocks(start, direction, maxDistance, fluidCollisionMode, ignorePassableBlocks, null);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ @Override
|
||||||
|
+ public RayTraceResult rayTraceBlocks(io.papermc.paper.math.Position start, Vector direction, double maxDistance, FluidCollisionMode fluidCollisionMode, boolean ignorePassableBlocks, Predicate<Block> canCollide) {
|
||||||
|
Preconditions.checkArgument(start != null, "Location start cannot be null");
|
||||||
|
- Preconditions.checkArgument(this.equals(start.getWorld()), "Location start cannot be in a different world");
|
||||||
|
- start.checkFinite();
|
||||||
|
+ Preconditions.checkArgument(!(start instanceof Location location) || this.equals(location.getWorld()), "Location start cannot be in a different world");
|
||||||
|
+ Preconditions.checkArgument(start.isFinite(), "Location start is not finite");
|
||||||
|
+ // Paper end
|
||||||
|
|
||||||
|
Preconditions.checkArgument(direction != null, "Vector direction cannot be null");
|
||||||
|
direction.checkFinite();
|
||||||
|
@@ -0,0 +0,0 @@ public class CraftWorld extends CraftRegionAccessor implements World {
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector dir = direction.clone().normalize().multiply(maxDistance);
|
||||||
|
- Vec3 startPos = CraftLocation.toVec3D(start);
|
||||||
|
+ Vec3 startPos = io.papermc.paper.util.MCUtil.toVec3(start); // Paper
|
||||||
|
Vec3 endPos = startPos.add(dir.getX(), dir.getY(), dir.getZ());
|
||||||
|
- HitResult nmsHitResult = this.getHandle().clip(new ClipContext(startPos, endPos, ignorePassableBlocks ? ClipContext.Block.COLLIDER : ClipContext.Block.OUTLINE, CraftFluidCollisionMode.toNMS(fluidCollisionMode), null));
|
||||||
|
+ HitResult nmsHitResult = this.getHandle().clip(new ClipContext(startPos, endPos, ignorePassableBlocks ? ClipContext.Block.COLLIDER : ClipContext.Block.OUTLINE, CraftFluidCollisionMode.toNMS(fluidCollisionMode), null), canCollide); // Paper - use method with canCollide predicate
|
||||||
|
|
||||||
|
return CraftRayTraceResult.fromNMS(this, nmsHitResult);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public RayTraceResult rayTrace(Location start, Vector direction, double maxDistance, FluidCollisionMode fluidCollisionMode, boolean ignorePassableBlocks, double raySize, Predicate<Entity> filter) {
|
||||||
|
- RayTraceResult blockHit = this.rayTraceBlocks(start, direction, maxDistance, fluidCollisionMode, ignorePassableBlocks);
|
||||||
|
+ // Paper start
|
||||||
|
+ return this.rayTrace(start, direction, maxDistance, fluidCollisionMode, ignorePassableBlocks, raySize, filter, null);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ @Override
|
||||||
|
+ public RayTraceResult rayTrace(io.papermc.paper.math.Position start, Vector direction, double maxDistance, FluidCollisionMode fluidCollisionMode, boolean ignorePassableBlocks, double raySize, Predicate<Entity> filter, Predicate<Block> canCollide) {
|
||||||
|
+ RayTraceResult blockHit = this.rayTraceBlocks(start, direction, maxDistance, fluidCollisionMode, ignorePassableBlocks, canCollide);
|
||||||
|
+ // Paper end
|
||||||
|
Vector startVec = null;
|
||||||
|
double blockHitDistance = maxDistance;
|
||||||
|
|
@ -3972,6 +3972,10 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
|||||||
+ return Position.block(vector.getX(), vector.getY(), vector.getZ());
|
+ return Position.block(vector.getX(), vector.getY(), vector.getZ());
|
||||||
+ }
|
+ }
|
||||||
+
|
+
|
||||||
|
+ public static Vec3 toVec3(Position position) {
|
||||||
|
+ return new Vec3(position.x(), position.y(), position.z());
|
||||||
|
+ }
|
||||||
|
+
|
||||||
+ public static boolean isEdgeOfChunk(BlockPos pos) {
|
+ public static boolean isEdgeOfChunk(BlockPos pos) {
|
||||||
+ final int modX = pos.getX() & 15;
|
+ final int modX = pos.getX() & 15;
|
||||||
+ final int modZ = pos.getZ() & 15;
|
+ final int modZ = pos.getZ() & 15;
|
||||||
|
Loading…
Reference in New Issue
Block a user