Unicopia/src/main/java/com/minelittlepony/unicopia/util/VecHelper.java

175 lines
6.3 KiB
Java
Raw Normal View History

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
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 {
/**
* 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
*
* @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)
);
}
2018-09-12 01:29:49 +02:00
/**
2018-09-12 01:29:49 +02:00
* Gets the entity the player is currently looking at, or null.
*/
@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()
.expand(look.x, look.y, look.z)
.expand(1, 1, 1), predicate);
}
2018-09-12 01:29:49 +02: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);
}
/**
* 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
if (tracedBlock != null) {
2020-01-16 12:35:46 +01:00
totalTraceDistance = tracedBlock.getPos().distanceTo(pos);
}
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)
.expand(1, 1, 1), predicate);
2018-09-12 01:29:49 +02:00
double traceDistance = totalTraceDistance;
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-12 01:29:49 +02:00
return tracedBlock;
}
}