All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.spongepowered.api.util.blockray.RayTrace Maven / Gradle / Ivy

There is a newer version: 9.0.0
Show newest version
/*
 * 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:

* *
    *
  1. {@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.
  2. *
  3. {@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 .
  4. *
  5. {@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.
  6. *
  7. {@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.
  8. *
* * @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(); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy