org.spongepowered.api.util.blockray.RayTrace Maven / Gradle / Ivy
Show all versions of spongeapi Show documentation
/*
* This file is part of SpongeAPI, licensed under the MIT License (MIT).
*
* Copyright (c) SpongePowered
* Copyright (c) contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package org.spongepowered.api.util.blockray;
import org.spongepowered.api.Sponge;
import org.spongepowered.api.data.Keys;
import org.spongepowered.api.entity.Entity;
import org.spongepowered.api.entity.living.Living;
import org.spongepowered.api.util.AABB;
import org.spongepowered.api.world.Locatable;
import org.spongepowered.api.world.LocatableBlock;
import org.spongepowered.api.world.server.ServerLocation;
import org.spongepowered.api.world.server.ServerWorld;
import org.spongepowered.math.vector.Vector3d;
import java.util.Optional;
import java.util.function.Predicate;
/**
* Builds a set of parameters to define a ray trace that traces from a source
* position to a target position (or in a specified direction), subject to the
* supplied constraints.
*
* A ray trace will check supplied predicates in the following order in the
* case where multiple predicates should be checked:
*
*
* - {@link #continueWhileLocation(Predicate)} -- called when the boundary
* between two blocks is crossed, checking if the {@link ServerLocation} the
* ray is crossing in to is valid, regardless of what the ray has otherwise
* hit.
* - {@link #select(Predicate)} -- called when the {@link AABB} of
* {@code T} is crossed by the ray trace, for {@link LocatableBlock}s this
* is called directly after {@link #continueWhileLocation(Predicate)}. This
* is the only predicate that can return a result, any .
* - {@link #continueWhileBlock(Predicate)} -- called if no selection was
* returned (if appropriate), checks the {@link LocatableBlock} the ray is
* entering. All predicates should return {@code true} if the ray should
* continue to trace through the block.
* - {@link #continueWhileEntity(Predicate)} -- called if no selection was
* returned (if appropriate), checks the {@link Entity} the ray has struck.
* All predicates should return {@code true} if the ray should continue to
* trace through the entity.
*
*
* @param The type of {@link Locatable} that this ray trace will attempt to
* select
*/
public interface RayTrace {
/**
* Creates a {@link RayTrace} that will attempt to select a
* {@link LocatableBlock}.
*
* @return The ray trace builder.
*/
static RayTrace block() {
return Sponge.game().factoryProvider().provide(Factory.class).blockRayTrace();
}
/**
* Creates a {@link RayTrace} that will attempt to select an {@link Entity}.
*
* @return The ray trace builder.
*/
static RayTrace entity() {
return Sponge.game().factoryProvider().provide(Factory.class).entityRayTrace();
}
/**
* Returns a {@link Predicate} for use in
* {@link #continueWhileLocation(Predicate)} that only allows a trace to
* continue if the {@link LocatableBlock} at the given position is air.
*
* @return The predicate
*/
static Predicate onlyAir() {
return Sponge.game().factoryProvider().provide(Factory.class).onlyAir();
}
/**
* Returns a {@link Predicate} for use in {@link #select(Predicate)} that
* selects non-air blocks.
*
* @return The predicate
*/
static Predicate nonAir() {
return Sponge.game().factoryProvider().provide(Factory.class).notAir();
}
/**
* Sets the {@link ServerWorld} to perform the ray trace in.
*
* @param serverWorld The {@link ServerWorld}
* @return This, for chaining
*/
RayTrace world(ServerWorld serverWorld);
/**
* Sets the {@link Vector3d position} to trace from, based on the supplied
* {@link Entity}'s {@link Entity#position() position}.
*
* This will use {@link Entity#position()} to determine the entity
* position. This may be unexpected if you wish to ray trace along the line
* of sight of the entity. In this scenario, use
* {@link #sourceEyePosition(Living)} instead.
*
* @param entity The {@link Entity}
* @return This, for chaining
*/
default RayTrace sourcePosition(final Entity entity) {
return this.sourcePosition(entity.position());
}
/**
* Sets the {@link Vector3d position} to trace from, based on the supplied
* {@link Entity}'s {@link Keys#EYE_POSITION eye position}.
*
* If {@link Keys#EYE_POSITION} does not exist, this will throw an
* {@link IllegalArgumentException} instead.
*
* @param entity The {@link Living}
* @return This, for chaining
*/
RayTrace sourceEyePosition(Living entity);
/**
* Sets the {@link Vector3d} position to trace from.
*
* @param sourcePosition The {@link Vector3d}
* @return This, for chaining
*/
RayTrace sourcePosition(Vector3d sourcePosition);
/**
* Sets the direction to trace in.
*
* If {@link #continueUntil(Vector3d)} is set, this will be unset.
*
* @param direction The {@link Vector3d}
* @return This, for chaining
*/
RayTrace direction(Vector3d direction);
/**
* Sets the direction to trace in, based on the direction the
* {@link Living#headDirection() direction} the supplied {@link Living}
* is currently looking.
*
* If {@link #continueUntil(Vector3d)} is set, this will be unset.
*
* @param entity The {@link Living}
* @return This, for chaining
*/
default RayTrace direction(final Living entity) {
return this.direction(entity.headDirection());
}
/**
* Sets how far this trace will look to find a match, passing all other
* constraints, before returning no results.
*
* This defaults to a distance of 30. This will be ignored if a specific
* position is set via {@link #continueUntil(Vector3d)}.
*
* @param distance The distance
* @return This, for chaining
*/
RayTrace limit(int distance);
/**
* Sets the {@link Vector3d} position where a ray trace should end.
*
* If {@link #direction(Living)} or {@link #direction(Vector3d)} is set,
* this will be unset and any limit set via {@link #limit(int)} will be
* ignored.
*
* @param endPosition The position
* @return This, for chaining
*/
RayTrace continueUntil(Vector3d endPosition);
/**
* Provides a {@link Predicate} that allows a consumer to determine whether
* a given {@link ServerLocation} should allow the trace to succeed. The
* predicate should return {@code true} if the trace should proceed.
*
* This predicate will be checked when the boundary between two
* {@link LocatableBlock}s is crossed.
*
* @param predicate The predicate to check
* @return This, for chaining
*/
RayTrace continueWhileLocation(Predicate predicate);
/**
* Provides a {@link Predicate} that allows a consumer to determine whether
* a given {@link LocatableBlock} (which has not been selected by
* the predicate provided in {@link #select(Predicate)} should allow the
* trace to proceed.
*
* For example, if a trace is for {@link LocatableBlock}s, you may only
* want to continue the trace if it travels through air (generally used for
* line of sight purposes). In this case, the predicate may look like this:
*
*
* {@code
* block -> {
* final BlockType type = block.blockState().type();
* return type == BlockTypes.AIR.get() ||
* type == BlockTypes.CAVE_AIR.get() ||
* type == BlockTypes.VOID_AIR.get();
* }
* }
*
* If this is not supplied, this defaults to always returning
* {@code true}.
*
* @param predicate The predicate to check
* @return This, for chaining
*/
RayTrace continueWhileBlock(Predicate predicate);
/**
* Provides a {@link Predicate} that allows a consumer to determine whether
* a given {@link Entity} (which has not been selected by
* the predicate provided in {@link #select(Predicate)} should allow the
* trace to proceed.
*
* If this is not supplied, this will default to true, and if this is not
* an {@link Entity} based ray trace, no entity ray trace calculations will
* be performed.
*
* @param predicate The predicate
* @return This, for chaining
*/
RayTrace continueWhileEntity(Predicate predicate);
/**
* Determines the condition in which a {@link Locatable} hit will be
* considered successful.
*
* For example, if this ray trace is {@link LocatableBlock} specific and
* you want to obtain the first non-air block, the predicate might look
* something like this:
*
* {@code
* block -> {
* final BlockType type = block.blockState().type();
* return !(type == BlockTypes.AIR.get() &&
* type == BlockTypes.CAVE_AIR.get() &&
* type == BlockTypes.VOID_AIR.get());
* }
* }
*
* Given the other supplied conditions, if this supplied predicate
* returns {@code true}, the first hit will be returned as a
* {@link Locatable}.
*
* If multiple predicates are provided, they will be combined using
* {@link Predicate#or(Predicate)}.
*
* A selection will happen before any predicate supplied to
* {@link #continueWhileBlock(Predicate)}, but after any
* {@link #continueWhileLocation(Predicate)} is processed.
*
* @param filter The filter to use to determine whether to return a
* {@link RayTraceResult}
* @return This, for chaining.
*/
RayTrace select(Predicate filter);
/**
* Executes this ray trace and returns a {@link RayTraceResult} containing
* the {@link Locatable} if successful.
*
* @return The {@link RayTraceResult}, if any.
*/
Optional> execute();
/**
* Resets this object to its original state.
*
* @return This, for chaining.
*/
RayTrace reset();
/**
* Creates relevant objects for ray tracing.
*/
interface Factory {
/**
* @see RayTrace#entity()
*/
RayTrace entityRayTrace();
/**
* @see RayTrace#block()
*/
RayTrace blockRayTrace();
/**
* @see RayTrace#onlyAir()
*/
Predicate onlyAir();
/**
* @see RayTrace#nonAir()
*/
Predicate notAir();
}
}