1
0
Fork 0
mirror of https://github.com/PaperMC/Paper.git synced 2025-04-04 05:21:01 +02:00

Add RayTraceConfigurationBuilder ()

This commit is contained in:
Tamion 2025-01-25 20:58:16 +01:00 committed by GitHub
parent 336ea9dfeb
commit 939bb7828f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 249 additions and 0 deletions
paper-api/src/main/java
paper-server/src/main/java
io/papermc/paper/raytracing
org/bukkit/craftbukkit

View file

@ -0,0 +1,112 @@
package io.papermc.paper.raytracing;
import java.util.function.Predicate;
import org.bukkit.FluidCollisionMode;
import org.bukkit.Location;
import org.bukkit.block.Block;
import org.bukkit.entity.Entity;
import org.bukkit.util.Vector;
import org.checkerframework.checker.index.qual.NonNegative;
import org.jetbrains.annotations.Contract;
import org.jspecify.annotations.NullMarked;
/**
* A builder for configuring a raytrace with a starting location
* and direction.
*/
@NullMarked
public interface PositionedRayTraceConfigurationBuilder {
/**
* Sets the starting location.
*
* @param start the new starting location
* @return a reference to this object
*/
@Contract(value = "_ -> this", mutates = "this")
PositionedRayTraceConfigurationBuilder start(Location start);
/**
* Sets the direction.
*
* @param direction the new direction
* @return a reference to this object
*/
@Contract(value = "_ -> this", mutates = "this")
PositionedRayTraceConfigurationBuilder direction(Vector direction);
/**
* Sets the maximum distance.
*
* @param maxDistance the new maxDistance
* @return a reference to this object
*/
@Contract(value = "_ -> this", mutates = "this")
PositionedRayTraceConfigurationBuilder maxDistance(@NonNegative double maxDistance);
/**
* Sets the FluidCollisionMode when looking for block collisions.
* <p>
* If collisions with passable blocks are ignored, fluid collisions are
* ignored as well regardless of the fluid collision mode.
*
* @param fluidCollisionMode the new FluidCollisionMode
* @return a reference to this object
*/
@Contract(value = "_ -> this", mutates = "this")
PositionedRayTraceConfigurationBuilder fluidCollisionMode(FluidCollisionMode fluidCollisionMode);
/**
* Sets whether the raytrace should ignore passable blocks when looking for
* block collisions.
* <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.
*
* @param ignorePassableBlocks if the raytrace should ignore passable blocks
* @return a reference to this object
*/
@Contract(value = "_ -> this", mutates = "this")
PositionedRayTraceConfigurationBuilder ignorePassableBlocks(boolean ignorePassableBlocks);
/**
* Sets the size of the raytrace when looking for entity collisions.
*
* @param raySize the new raytrace size
* @return a reference to this object
*/
@Contract(value = "_ -> this", mutates = "this")
PositionedRayTraceConfigurationBuilder raySize(@NonNegative double raySize);
/**
* Sets the current entity filter when looking for entity collisions.
*
* @param entityFilter predicate for entities the ray can potentially collide with
* @return a reference to this object
*/
@Contract(value = "_ -> this", mutates = "this")
PositionedRayTraceConfigurationBuilder entityFilter(Predicate<? super Entity> entityFilter);
/**
* Sets the current block filter when looking for block collisions.
*
* @param blockFilter predicate for blocks the ray can potentially collide with
* @return a reference to this object
*/
@Contract(value = "_ -> this", mutates = "this")
PositionedRayTraceConfigurationBuilder blockFilter(Predicate<? super Block> blockFilter);
/**
* Sets the targets for the rayTrace.
*
* @param first the first target
* @param others the other targets
* @return a reference to this object
*/
@Contract(value = "_, _ -> this", mutates = "this")
PositionedRayTraceConfigurationBuilder targets(RayTraceTarget first, RayTraceTarget... others);
}

View file

@ -0,0 +1,9 @@
package io.papermc.paper.raytracing;
/**
* List of Targets a builder can target.
*/
public enum RayTraceTarget {
ENTITY,
BLOCK
}

View file

@ -1,6 +1,7 @@
package org.bukkit;
import java.io.File;
import io.papermc.paper.raytracing.PositionedRayTraceConfigurationBuilder;
import org.bukkit.generator.ChunkGenerator;
import java.util.ArrayList;
@ -1938,6 +1939,20 @@ public interface World extends RegionAccessor, WorldInfo, PluginMessageRecipient
@Nullable RayTraceResult rayTrace(io.papermc.paper.math.@NotNull Position start, @NotNull Vector direction, double maxDistance, @NotNull FluidCollisionMode fluidCollisionMode, boolean ignorePassableBlocks, double raySize, @Nullable Predicate<? super Entity> filter, @Nullable Predicate<? super Block> canCollide);
// Paper end
/**
* Performs a ray trace that checks for collisions with the specified
* targets.
* <p>
* This may cause loading of chunks! Some implementations may impose
* artificial restrictions on the maximum distance.
*
* @param builderConsumer a consumer to configure the ray trace configuration.
* The received builder is not valid for use outside the consumer
* @return the closest ray trace hit result with either a block or an
* entity, or <code>null</code> if there is no hit
*/
@Nullable RayTraceResult rayTrace(@NotNull Consumer<PositionedRayTraceConfigurationBuilder> builderConsumer);
/**
* Gets the default spawn {@link Location} of this world
*

View file

@ -0,0 +1,90 @@
package io.papermc.paper.raytracing;
import com.google.common.base.Preconditions;
import java.util.EnumSet;
import java.util.OptionalDouble;
import java.util.function.Predicate;
import org.bukkit.FluidCollisionMode;
import org.bukkit.Location;
import org.bukkit.block.Block;
import org.bukkit.entity.Entity;
import org.bukkit.util.Vector;
import org.jspecify.annotations.NullMarked;
import org.jspecify.annotations.Nullable;
@NullMarked
public class PositionedRayTraceConfigurationBuilderImpl implements PositionedRayTraceConfigurationBuilder {
public @Nullable Location start;
public @Nullable Vector direction;
public OptionalDouble maxDistance = OptionalDouble.empty();
public FluidCollisionMode fluidCollisionMode = FluidCollisionMode.NEVER;
public boolean ignorePassableBlocks;
public double raySize = 0.0D;
public @Nullable Predicate<? super Entity> entityFilter;
public @Nullable Predicate<? super Block> blockFilter;
public EnumSet<RayTraceTarget> targets = EnumSet.noneOf(RayTraceTarget.class);
@Override
public PositionedRayTraceConfigurationBuilder start(final Location start) {
Preconditions.checkArgument(start != null, "start must not be null");
this.start = start.clone();
return this;
}
@Override
public PositionedRayTraceConfigurationBuilder direction(final Vector direction) {
Preconditions.checkArgument(direction != null, "direction must not be null");
this.direction = direction.clone();
return this;
}
@Override
public PositionedRayTraceConfigurationBuilder maxDistance(final double maxDistance) {
Preconditions.checkArgument(maxDistance >= 0, "maxDistance must be non-negative");
this.maxDistance = OptionalDouble.of(maxDistance);
return this;
}
@Override
public PositionedRayTraceConfigurationBuilder fluidCollisionMode(final FluidCollisionMode fluidCollisionMode) {
Preconditions.checkArgument(fluidCollisionMode != null, "fluidCollisionMode must not be null");
this.fluidCollisionMode = fluidCollisionMode;
return this;
}
@Override
public PositionedRayTraceConfigurationBuilder ignorePassableBlocks(final boolean ignorePassableBlocks) {
this.ignorePassableBlocks = ignorePassableBlocks;
return this;
}
@Override
public PositionedRayTraceConfigurationBuilder raySize(final double raySize) {
Preconditions.checkArgument(raySize >= 0, "raySize must be non-negative");
this.raySize = raySize;
return this;
}
@Override
public PositionedRayTraceConfigurationBuilder entityFilter(final Predicate<? super Entity> entityFilter) {
Preconditions.checkArgument(entityFilter != null, "entityFilter must not be null");
this.entityFilter = entityFilter;
return this;
}
@Override
public PositionedRayTraceConfigurationBuilder blockFilter(final Predicate<? super Block> blockFilter) {
Preconditions.checkArgument(blockFilter != null, "blockFilter must not be null");
this.blockFilter = blockFilter;
return this;
}
@Override
public PositionedRayTraceConfigurationBuilder targets(final RayTraceTarget first, final RayTraceTarget... others) {
Preconditions.checkArgument(first != null, "first must not be null");
Preconditions.checkArgument(others != null, "others must not be null");
this.targets = EnumSet.of(first, others);
return this;
}
}

View file

@ -6,9 +6,12 @@ import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.mojang.datafixers.util.Pair;
import io.papermc.paper.FeatureHooks;
import io.papermc.paper.raytracing.RayTraceTarget;
import io.papermc.paper.registry.RegistryAccess;
import io.papermc.paper.registry.RegistryKey;
import it.unimi.dsi.fastutil.longs.Long2ObjectMap;
import io.papermc.paper.raytracing.PositionedRayTraceConfigurationBuilder;
import io.papermc.paper.raytracing.PositionedRayTraceConfigurationBuilderImpl;
import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;
import java.io.File;
import java.util.ArrayList;
@ -1248,6 +1251,26 @@ public class CraftWorld extends CraftRegionAccessor implements World {
return blockHit;
}
@Override
public RayTraceResult rayTrace(Consumer<PositionedRayTraceConfigurationBuilder> builderConsumer) {
PositionedRayTraceConfigurationBuilderImpl builder = new PositionedRayTraceConfigurationBuilderImpl();
builderConsumer.accept(builder);
Preconditions.checkArgument(builder.start != null, "Start location cannot be null");
Preconditions.checkArgument(builder.direction != null, "Direction vector cannot be null");
Preconditions.checkArgument(builder.maxDistance.isPresent(), "Max distance must be set");
Preconditions.checkArgument(!builder.targets.isEmpty(), "At least one target");
final double maxDistance = builder.maxDistance.getAsDouble();
if (builder.targets.contains(RayTraceTarget.ENTITY)) {
if (builder.targets.contains(RayTraceTarget.BLOCK)) {
return this.rayTrace(builder.start, builder.direction, maxDistance, builder.fluidCollisionMode, builder.ignorePassableBlocks, builder.raySize, builder.entityFilter, builder.blockFilter);
}
return this.rayTraceEntities(builder.start, builder.direction, maxDistance, builder.raySize, builder.entityFilter);
}
return this.rayTraceBlocks(builder.start, builder.direction, maxDistance, builder.fluidCollisionMode, builder.ignorePassableBlocks, builder.blockFilter);
}
@Override
public List<Player> getPlayers() {
List<Player> list = new ArrayList<Player>(this.world.players().size());