2020-04-15 14:22:03 +02:00
|
|
|
package com.minelittlepony.unicopia.util;
|
2018-09-12 01:29:49 +02:00
|
|
|
|
|
|
|
import java.util.List;
|
2020-01-16 12:35:46 +01:00
|
|
|
import java.util.Optional;
|
|
|
|
import java.util.function.Predicate;
|
2019-01-20 00:07:59 +01:00
|
|
|
import java.util.stream.Stream;
|
2018-09-12 01:29:49 +02:00
|
|
|
|
2018-09-16 00:45:44 +02:00
|
|
|
import javax.annotation.Nullable;
|
|
|
|
|
2018-09-12 01:29:49 +02:00
|
|
|
import net.minecraft.entity.Entity;
|
2020-01-16 12:35:46 +01:00
|
|
|
import net.minecraft.entity.LivingEntity;
|
|
|
|
import net.minecraft.entity.player.PlayerEntity;
|
|
|
|
import net.minecraft.predicate.entity.EntityPredicates;
|
|
|
|
import net.minecraft.util.hit.BlockHitResult;
|
|
|
|
import net.minecraft.util.hit.EntityHitResult;
|
|
|
|
import net.minecraft.util.hit.HitResult;
|
2019-01-20 00:07:59 +01:00
|
|
|
import net.minecraft.util.math.BlockPos;
|
2020-01-16 12:35:46 +01:00
|
|
|
import net.minecraft.util.math.Box;
|
2018-09-12 01:29:49 +02:00
|
|
|
import net.minecraft.util.math.Vec3d;
|
2020-01-16 12:35:46 +01:00
|
|
|
import net.minecraft.world.RayTraceContext;
|
2019-01-20 00:07:59 +01:00
|
|
|
import net.minecraft.world.World;
|
2018-09-12 01:29:49 +02:00
|
|
|
|
|
|
|
public class VecHelper {
|
|
|
|
|
2019-02-08 22:39:02 +01:00
|
|
|
/**
|
|
|
|
* Performs a ray cast from the given entity and returns a result for the first block that ray intercepts.
|
|
|
|
*
|
2020-01-16 12:35:46 +01:00
|
|
|
* Server-available version of Entity.rayTrace
|
|
|
|
*
|
2019-02-08 22:39:02 +01:00
|
|
|
* @param e Entity to start from
|
|
|
|
* @param distance Maximum distance
|
|
|
|
* @param partialTick Client partial ticks
|
|
|
|
*
|
|
|
|
* @return RayTraceResult result or null
|
|
|
|
*/
|
2020-01-16 12:35:46 +01:00
|
|
|
public static HitResult rayTrace(Entity e, double distance, float partialTick) {
|
|
|
|
Vec3d cam = e.getCameraPosVec(partialTick);
|
|
|
|
Vec3d look = e.getRotationVec(partialTick).multiply(distance);
|
|
|
|
|
|
|
|
return e.world.rayTrace(
|
|
|
|
new RayTraceContext(cam, cam.add(look),
|
|
|
|
RayTraceContext.ShapeType.OUTLINE,
|
|
|
|
RayTraceContext.FluidHandling.NONE,
|
|
|
|
e)
|
|
|
|
);
|
2019-02-08 22:39:02 +01:00
|
|
|
}
|
2018-09-12 01:29:49 +02:00
|
|
|
|
2019-02-08 22:39:02 +01:00
|
|
|
/**
|
2018-09-12 01:29:49 +02:00
|
|
|
* Gets the entity the player is currently looking at, or null.
|
|
|
|
*/
|
2019-02-08 22:39:02 +01:00
|
|
|
@Nullable
|
2020-01-16 12:35:46 +01:00
|
|
|
public static Entity getLookedAtEntity(LivingEntity e, int reach) {
|
|
|
|
HitResult objectMouseOver = getObjectMouseOver(e, reach, 1);
|
2018-09-12 01:29:49 +02:00
|
|
|
|
2020-01-16 12:35:46 +01:00
|
|
|
if (objectMouseOver instanceof EntityHitResult && objectMouseOver.getType() == BlockHitResult.Type.ENTITY) {
|
|
|
|
return ((EntityHitResult)objectMouseOver).getEntity();
|
2018-09-12 01:29:49 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
2019-01-20 00:07:59 +01:00
|
|
|
public static Stream<Entity> findAllEntitiesInRange(@Nullable Entity origin, World w, BlockPos pos, double radius) {
|
|
|
|
|
|
|
|
BlockPos begin = pos.add(-radius, -radius, -radius);
|
|
|
|
BlockPos end = pos.add(radius, radius, radius);
|
|
|
|
|
2020-01-16 12:35:46 +01:00
|
|
|
Box bb = new Box(begin, end);
|
2019-01-20 00:07:59 +01:00
|
|
|
|
2020-01-16 12:35:46 +01:00
|
|
|
return w.getEntities(origin, bb, null).stream().filter(e -> {
|
|
|
|
double dist = e.squaredDistanceTo(pos.getX(), pos.getY(), pos.getZ());
|
|
|
|
double dist2 = e.squaredDistanceTo(pos.getX(), pos.getY() - e.getStandingEyeHeight(), pos.getZ());
|
2019-01-20 00:07:59 +01:00
|
|
|
|
|
|
|
return dist <= radius || dist2 <= radius;
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2018-09-12 01:29:49 +02:00
|
|
|
/**
|
|
|
|
* Gets all entities within a given range from the player.
|
|
|
|
*/
|
2020-01-16 12:35:46 +01:00
|
|
|
public static List<Entity> getWithinRange(PlayerEntity player, double reach, @Nullable Predicate<? super Entity> predicate) {
|
|
|
|
Vec3d look = player.getCameraPosVec(1).multiply(reach);
|
2018-09-12 01:29:49 +02:00
|
|
|
|
2020-01-16 12:35:46 +01:00
|
|
|
return player.world.getEntities(player, player
|
|
|
|
.getBoundingBox()
|
2018-09-16 00:45:44 +02:00
|
|
|
.expand(look.x, look.y, look.z)
|
|
|
|
.expand(1, 1, 1), predicate);
|
|
|
|
}
|
2018-09-12 01:29:49 +02:00
|
|
|
|
2019-02-08 22:39:02 +01:00
|
|
|
/**
|
|
|
|
* Performs a ray trace from the given entity and returns a result for the first Entity or block that the ray intercepts.
|
|
|
|
*
|
|
|
|
* @param e Entity to start from
|
|
|
|
* @param distance Maximum distance
|
|
|
|
* @param partialTick Client partial ticks
|
|
|
|
*
|
|
|
|
* @return RayTraceResult result or null
|
|
|
|
*/
|
2020-01-16 12:35:46 +01:00
|
|
|
public static HitResult getObjectMouseOver(Entity e, double distance, float partialTick) {
|
|
|
|
return getObjectMouseOver(e, distance, partialTick, EntityPredicates.EXCEPT_SPECTATOR);
|
2019-02-08 22:39:02 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Performs a ray trace from the given entity and returns a result for the first Entity that passing the given predicate or block that the ray intercepts.
|
|
|
|
* <p>
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* @param e Entity to start from
|
|
|
|
* @param distance Maximum distance
|
|
|
|
* @param partialTick Client partial ticks
|
|
|
|
* @param predicate Predicate test to filter entities
|
|
|
|
*
|
|
|
|
* @return RayTraceResult result or null
|
|
|
|
*/
|
2020-01-16 12:35:46 +01:00
|
|
|
public static HitResult getObjectMouseOver(Entity e, double distance, float partialTick, Predicate<Entity> predicate) {
|
|
|
|
HitResult tracedBlock = rayTrace(e, distance, partialTick);
|
2018-09-12 01:29:49 +02:00
|
|
|
|
|
|
|
double totalTraceDistance = distance;
|
|
|
|
|
2020-01-16 12:35:46 +01:00
|
|
|
Vec3d pos = e.getCameraPosVec(partialTick);
|
2018-09-12 01:29:49 +02:00
|
|
|
|
2018-09-16 00:45:44 +02:00
|
|
|
if (tracedBlock != null) {
|
2020-01-16 12:35:46 +01:00
|
|
|
totalTraceDistance = tracedBlock.getPos().distanceTo(pos);
|
2018-09-16 00:45:44 +02:00
|
|
|
}
|
2018-09-12 01:29:49 +02:00
|
|
|
|
2020-01-16 12:35:46 +01:00
|
|
|
Vec3d look = e.getRotationVec(partialTick);
|
|
|
|
Vec3d ray = pos.add(look.multiply(distance));
|
2018-09-12 01:29:49 +02:00
|
|
|
|
|
|
|
Vec3d hit = null;
|
|
|
|
Entity pointedEntity = null;
|
2020-01-16 12:35:46 +01:00
|
|
|
List<Entity> entitiesWithinRange = e.world.getEntities(e, e.getBoundingBox()
|
|
|
|
.expand(look.x * distance, look.y * distance, look.z * distance)
|
2018-09-16 00:45:44 +02:00
|
|
|
.expand(1, 1, 1), predicate);
|
2018-09-12 01:29:49 +02:00
|
|
|
|
|
|
|
double traceDistance = totalTraceDistance;
|
2018-09-16 00:45:44 +02:00
|
|
|
|
2018-09-12 01:29:49 +02:00
|
|
|
for (Entity entity : entitiesWithinRange) {
|
2020-01-16 12:35:46 +01:00
|
|
|
if (entity.collides()) {
|
|
|
|
Box entityAABB = entity.getBoundingBox().expand(entity.getTargetingMargin());
|
|
|
|
|
|
|
|
Optional<Vec3d> intercept = entityAABB.rayTrace(pos, ray);
|
2018-09-12 01:29:49 +02:00
|
|
|
|
|
|
|
if (entityAABB.contains(pos)) {
|
2020-01-16 12:35:46 +01:00
|
|
|
if (traceDistance <= 0) {
|
2018-09-12 01:29:49 +02:00
|
|
|
pointedEntity = entity;
|
2020-01-16 12:35:46 +01:00
|
|
|
hit = intercept.orElse(null);
|
2018-09-12 01:29:49 +02:00
|
|
|
traceDistance = 0;
|
|
|
|
}
|
2020-01-16 12:35:46 +01:00
|
|
|
} else if (intercept.isPresent()) {
|
|
|
|
Vec3d inter = intercept.get();
|
|
|
|
double distanceToHit = pos.distanceTo(inter);
|
|
|
|
|
2018-09-12 01:29:49 +02:00
|
|
|
if (distanceToHit < traceDistance || traceDistance == 0) {
|
2020-01-16 12:35:46 +01:00
|
|
|
if (entity.getRootVehicle() == e.getRootVehicle()) {
|
2018-09-12 01:29:49 +02:00
|
|
|
if (traceDistance == 0) {
|
|
|
|
pointedEntity = entity;
|
2020-01-16 12:35:46 +01:00
|
|
|
hit = inter;
|
2018-09-12 01:29:49 +02:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
pointedEntity = entity;
|
2020-01-16 12:35:46 +01:00
|
|
|
hit = inter;
|
2018-09-12 01:29:49 +02:00
|
|
|
traceDistance = distanceToHit;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (pointedEntity != null && (traceDistance < totalTraceDistance || tracedBlock == null)) {
|
2020-01-16 12:35:46 +01:00
|
|
|
return new EntityHitResult(pointedEntity, hit);
|
2018-09-12 01:29:49 +02:00
|
|
|
}
|
2018-09-16 00:45:44 +02:00
|
|
|
|
2018-09-12 01:29:49 +02:00
|
|
|
return tracedBlock;
|
|
|
|
}
|
|
|
|
}
|