diff --git a/src/main/java/com/minelittlepony/unicopia/ability/CarryAbility.java b/src/main/java/com/minelittlepony/unicopia/ability/CarryAbility.java index 978cd5b2..a7e5cc4c 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/CarryAbility.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/CarryAbility.java @@ -3,9 +3,7 @@ package com.minelittlepony.unicopia.ability; import com.minelittlepony.unicopia.Race; import com.minelittlepony.unicopia.ability.data.Hit; import com.minelittlepony.unicopia.entity.player.Pony; -import com.minelittlepony.unicopia.util.VecHelper; - -import net.minecraft.entity.Entity; +import com.minelittlepony.unicopia.util.RayTraceHelper; import net.minecraft.entity.LivingEntity; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.network.packet.s2c.play.EntityPassengersSetS2CPacket; @@ -38,15 +36,9 @@ public class CarryAbility implements Ability { } protected LivingEntity findRider(PlayerEntity player, World w) { - Entity hit = VecHelper.getLookedAtEntity(player, 10); - - if (hit instanceof LivingEntity && !player.isConnectedThroughVehicle(hit)) { - if (!(hit instanceof IPickupImmuned)) { - return (LivingEntity)hit; - } - } - - return null; + return RayTraceHelper.findEntity(player, 10, 1, hit -> { + return hit instanceof LivingEntity && !player.isConnectedThroughVehicle(hit) && !(hit instanceof IPickupImmuned); + }).orElse(null); } @Override diff --git a/src/main/java/com/minelittlepony/unicopia/ability/ChangelingDisguiseAbility.java b/src/main/java/com/minelittlepony/unicopia/ability/ChangelingDisguiseAbility.java index 9ea50379..52aada57 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/ChangelingDisguiseAbility.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/ChangelingDisguiseAbility.java @@ -8,19 +8,14 @@ import com.minelittlepony.unicopia.ability.magic.spell.DisguiseSpell; import com.minelittlepony.unicopia.entity.behaviour.Disguise; import com.minelittlepony.unicopia.entity.player.Pony; import com.minelittlepony.unicopia.particle.UParticles; -import com.minelittlepony.unicopia.util.VecHelper; - -import net.minecraft.block.BlockState; +import com.minelittlepony.unicopia.util.RayTraceHelper; import net.minecraft.entity.Entity; import net.minecraft.entity.FallingBlockEntity; import net.minecraft.entity.LightningEntity; import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.predicate.entity.EntityPredicates; import net.minecraft.sound.SoundCategory; import net.minecraft.sound.SoundEvents; -import net.minecraft.util.hit.BlockHitResult; -import net.minecraft.util.hit.EntityHitResult; -import net.minecraft.util.hit.HitResult; -import net.minecraft.util.math.BlockPos; /** * Changeling ability to disguise themselves as other players. @@ -36,33 +31,21 @@ public class ChangelingDisguiseAbility extends ChangelingFeedAbility { @Override public void apply(Pony iplayer, Hit data) { PlayerEntity player = iplayer.getOwner(); - HitResult trace = VecHelper.getObjectMouseOver(player, 10, 1); - Entity looked = null; - - if (trace.getType() == HitResult.Type.BLOCK) { - BlockPos pos = ((BlockHitResult)trace).getBlockPos(); + RayTraceHelper.Trace trace = RayTraceHelper.doTrace(player, 10, 1, EntityPredicates.EXCEPT_SPECTATOR.and(e -> !(e instanceof LightningEntity))); + Entity looked = trace.getEntity().map(e -> { + return e instanceof PlayerEntity ? Pony.of((PlayerEntity)e) + .getSpellOrEmpty(DisguiseSpell.class) + .map(DisguiseSpell::getDisguise) + .map(Disguise::getAppearance) + .orElse(e) : e; + }).orElseGet(() -> trace.getBlockPos().map(pos -> { if (!iplayer.getWorld().isAir(pos)) { - BlockState state = iplayer.getWorld().getBlockState(pos); - - looked = new FallingBlockEntity(player.getEntityWorld(), 0, 0, 0, state); + return new FallingBlockEntity(player.getEntityWorld(), 0, 0, 0, iplayer.getWorld().getBlockState(pos)); } - } else if (trace.getType() == HitResult.Type.ENTITY) { - looked = ((EntityHitResult)trace).getEntity(); - - if (looked instanceof PlayerEntity) { - looked = Pony.of((PlayerEntity)looked) - .getSpellOrEmpty(DisguiseSpell.class) - .map(DisguiseSpell::getDisguise) - .map(Disguise::getAppearance) - .orElse(looked); - } - - if (looked instanceof LightningEntity) { - looked = null; - } - } + return null; + }).orElse(null)); player.getEntityWorld().playSound(null, player.getBlockPos(), SoundEvents.ENTITY_PARROT_IMITATE_RAVAGER, SoundCategory.PLAYERS, 1.4F, 0.4F); @@ -72,8 +55,8 @@ public class ChangelingDisguiseAbility extends ChangelingFeedAbility { iplayer.setSpell(disc); return disc; }).setDisguise(looked); - player.calculateDimensions(); + player.calculateDimensions(); iplayer.setDirty(); } diff --git a/src/main/java/com/minelittlepony/unicopia/ability/ChangelingFeedAbility.java b/src/main/java/com/minelittlepony/unicopia/ability/ChangelingFeedAbility.java index fdda34e7..8cf1ad23 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/ChangelingFeedAbility.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/ChangelingFeedAbility.java @@ -11,6 +11,7 @@ import com.minelittlepony.unicopia.entity.player.Pony; import com.minelittlepony.unicopia.particle.ParticleUtils; import com.minelittlepony.unicopia.particle.UParticles; import com.minelittlepony.unicopia.util.MagicalDamageSource; +import com.minelittlepony.unicopia.util.RayTraceHelper; import com.minelittlepony.unicopia.util.VecHelper; import net.minecraft.entity.Entity; @@ -78,12 +79,11 @@ public class ChangelingFeedAbility implements Ability { } protected List getTargets(Pony player) { - List list = VecHelper.getWithinRange(player.getOwner(), 3, this::canDrain); + List list = VecHelper.getWithinReach(player.getOwner(), 3, this::canDrain); - Entity looked = VecHelper.getLookedAtEntity(player.getOwner(), 17); - if (looked != null && !list.contains(looked) && canDrain(looked)) { - list.add(looked); - } + RayTraceHelper.findEntity(player.getOwner(), 17, 1, + looked -> looked instanceof LivingEntity && !list.contains(looked) && canDrain(looked)) + .ifPresent(list::add); return list.stream().map(i -> (LivingEntity)i).collect(Collectors.toList()); } diff --git a/src/main/java/com/minelittlepony/unicopia/ability/EarthPonyGrowAbility.java b/src/main/java/com/minelittlepony/unicopia/ability/EarthPonyGrowAbility.java index 11c769cc..ae446ee0 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/EarthPonyGrowAbility.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/EarthPonyGrowAbility.java @@ -5,14 +5,11 @@ import com.minelittlepony.unicopia.ability.data.Hit; import com.minelittlepony.unicopia.ability.data.Pos; import com.minelittlepony.unicopia.entity.player.Pony; import com.minelittlepony.unicopia.particle.MagicParticleEffect; -import com.minelittlepony.unicopia.util.VecHelper; - +import com.minelittlepony.unicopia.util.RayTraceHelper; import net.minecraft.block.BlockState; import net.minecraft.item.BoneMealItem; import net.minecraft.item.ItemStack; import net.minecraft.item.Items; -import net.minecraft.util.hit.BlockHitResult; -import net.minecraft.util.hit.HitResult; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Direction; import net.minecraft.world.World; @@ -39,13 +36,7 @@ public class EarthPonyGrowAbility implements Ability { @Override public Pos tryActivate(Pony player) { - HitResult ray = VecHelper.getObjectMouseOver(player.getOwner(), 3, 1); - - if (ray instanceof BlockHitResult && ray.getType() == HitResult.Type.BLOCK) { - return new Pos(((BlockHitResult)ray).getBlockPos()); - } - - return null; + return RayTraceHelper.doTrace(player.getOwner(), 3, 1).getBlockPos().map(Pos::new).orElse(null); } @Override diff --git a/src/main/java/com/minelittlepony/unicopia/ability/EarthPonyStompAbility.java b/src/main/java/com/minelittlepony/unicopia/ability/EarthPonyStompAbility.java index f9121ba1..b61b1705 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/EarthPonyStompAbility.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/EarthPonyStompAbility.java @@ -2,6 +2,7 @@ package com.minelittlepony.unicopia.ability; import java.util.ArrayList; import java.util.List; +import java.util.Optional; import javax.annotation.Nullable; @@ -14,7 +15,7 @@ import com.minelittlepony.unicopia.ability.data.Multi; import com.minelittlepony.unicopia.entity.player.Pony; import com.minelittlepony.unicopia.util.MagicalDamageSource; import com.minelittlepony.unicopia.util.PosHelper; -import com.minelittlepony.unicopia.util.VecHelper; +import com.minelittlepony.unicopia.util.RayTraceHelper; import com.minelittlepony.unicopia.util.WorldEvent; import com.minelittlepony.unicopia.util.shape.Shape; import com.minelittlepony.unicopia.util.shape.Sphere; @@ -31,8 +32,6 @@ import net.minecraft.entity.player.PlayerEntity; import net.minecraft.particle.BlockStateParticleEffect; import net.minecraft.particle.ParticleTypes; import net.minecraft.tag.BlockTags; -import net.minecraft.util.hit.BlockHitResult; -import net.minecraft.util.hit.HitResult; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Box; import net.minecraft.util.math.Direction; @@ -70,10 +69,10 @@ public class EarthPonyStompAbility implements Ability { @Nullable @Override public Multi tryActivate(Pony player) { - HitResult mop = VecHelper.getObjectMouseOver(player.getOwner(), 6, 1); + Optional p = RayTraceHelper.doTrace(player.getOwner(), 6, 1).getBlockPos(); - if (mop instanceof BlockHitResult && mop.getType() == HitResult.Type.BLOCK) { - BlockPos pos = ((BlockHitResult)mop).getBlockPos(); + if (p.isPresent()) { + BlockPos pos = p.get(); BlockState state = player.getWorld().getBlockState(pos); if (state.getBlock().isIn(BlockTags.LOGS)) { diff --git a/src/main/java/com/minelittlepony/unicopia/ability/UnicornTeleportAbility.java b/src/main/java/com/minelittlepony/unicopia/ability/UnicornTeleportAbility.java index af72a25b..82bbef4c 100644 --- a/src/main/java/com/minelittlepony/unicopia/ability/UnicornTeleportAbility.java +++ b/src/main/java/com/minelittlepony/unicopia/ability/UnicornTeleportAbility.java @@ -5,8 +5,7 @@ import com.minelittlepony.unicopia.ability.data.Hit; import com.minelittlepony.unicopia.ability.data.Pos; import com.minelittlepony.unicopia.entity.player.Pony; import com.minelittlepony.unicopia.particle.MagicParticleEffect; -import com.minelittlepony.unicopia.util.VecHelper; - +import com.minelittlepony.unicopia.util.RayTraceHelper; import net.minecraft.block.Block; import net.minecraft.block.BlockState; import net.minecraft.block.FenceBlock; @@ -15,6 +14,7 @@ import net.minecraft.block.WallBlock; import net.minecraft.entity.Entity; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.network.packet.s2c.play.EntityPassengersSetS2CPacket; +import net.minecraft.predicate.entity.EntityPredicates; import net.minecraft.server.network.ServerPlayerEntity; import net.minecraft.sound.SoundCategory; import net.minecraft.sound.SoundEvents; @@ -45,7 +45,7 @@ public class UnicornTeleportAbility implements Ability { @Override public Pos tryActivate(Pony player) { - HitResult ray = VecHelper.getObjectMouseOver(player.getOwner(), 100, 1); + HitResult ray = RayTraceHelper.doTrace(player.getOwner(), 100, 1, EntityPredicates.EXCEPT_SPECTATOR).getResult(); World w = player.getWorld(); diff --git a/src/main/java/com/minelittlepony/unicopia/item/ZapAppleItem.java b/src/main/java/com/minelittlepony/unicopia/item/ZapAppleItem.java index 4fa96dd1..b800590e 100644 --- a/src/main/java/com/minelittlepony/unicopia/item/ZapAppleItem.java +++ b/src/main/java/com/minelittlepony/unicopia/item/ZapAppleItem.java @@ -1,11 +1,12 @@ package com.minelittlepony.unicopia.item; +import java.util.Optional; + import com.minelittlepony.unicopia.UTags; import com.minelittlepony.unicopia.item.toxin.Toxicity; import com.minelittlepony.unicopia.util.MagicalDamageSource; -import com.minelittlepony.unicopia.util.VecHelper; - +import com.minelittlepony.unicopia.util.RayTraceHelper; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityType; import net.minecraft.entity.LightningEntity; @@ -18,6 +19,7 @@ import net.minecraft.item.Item; import net.minecraft.item.ItemGroup; import net.minecraft.item.ItemStack; import net.minecraft.item.Items; +import net.minecraft.predicate.entity.EntityPredicates; import net.minecraft.server.world.ServerWorld; import net.minecraft.util.ActionResult; import net.minecraft.util.collection.DefaultedList; @@ -25,8 +27,6 @@ import net.minecraft.util.Hand; import net.minecraft.util.Identifier; import net.minecraft.util.Rarity; import net.minecraft.util.TypedActionResult; -import net.minecraft.util.hit.EntityHitResult; -import net.minecraft.util.hit.HitResult; import net.minecraft.util.registry.Registry; import net.minecraft.world.World; @@ -38,16 +38,12 @@ public class ZapAppleItem extends AppleItem { @Override public TypedActionResult use(World world, PlayerEntity player, Hand hand) { - HitResult mop = VecHelper.getObjectMouseOver(player, 5, 0); + ItemStack stack = player.getStackInHand(hand); - if (mop != null && mop.getType() == HitResult.Type.ENTITY) { - ItemStack stack = player.getStackInHand(hand); + Optional entity = RayTraceHelper.doTrace(player, 5, 1, EntityPredicates.EXCEPT_SPECTATOR.and(e -> canFeedTo(stack, e))).getEntity(); - EntityHitResult ehr = ((EntityHitResult)mop); - - if (canFeedTo(stack, ehr.getEntity())) { - return onFedTo(stack, player, ehr.getEntity()); - } + if (entity.isPresent()) { + return onFedTo(stack, player, entity.get()); } return super.use(world, player, hand); diff --git a/src/main/java/com/minelittlepony/unicopia/util/RayTraceHelper.java b/src/main/java/com/minelittlepony/unicopia/util/RayTraceHelper.java new file mode 100644 index 00000000..a4c4c699 --- /dev/null +++ b/src/main/java/com/minelittlepony/unicopia/util/RayTraceHelper.java @@ -0,0 +1,158 @@ +package com.minelittlepony.unicopia.util; + +import java.util.List; +import java.util.Optional; +import java.util.function.Consumer; +import java.util.function.Predicate; + +import javax.annotation.Nullable; + +import net.minecraft.entity.Entity; +import net.minecraft.predicate.entity.EntityPredicates; +import net.minecraft.util.hit.BlockHitResult; +import net.minecraft.util.hit.EntityHitResult; +import net.minecraft.util.hit.HitResult; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Box; +import net.minecraft.util.math.Vec3d; +import net.minecraft.world.RayTraceContext; + +public class RayTraceHelper { + public static Optional findEntity(Entity e, double distance) { + return doTrace(e, distance, 1).getEntity(); + } + + public static Optional findEntity(Entity e, double distance, float partialTick, Predicate predicate) { + return doTrace(e, distance, partialTick, EntityPredicates.EXCEPT_SPECTATOR.and(predicate)).getEntity(); + } + + public static Trace doTrace(Entity e, double distance, float partialTick) { + return doTrace(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. + *

+ * + * + * @param e Entity to start from + * @param distance Maximum distance + * @param partialTick Client partial ticks + * @param predicate Predicate test to filter entities + * + * @return A OptionalHit describing what was found. + */ + public static Trace doTrace(Entity e, double distance, float partialTick, Predicate predicate) { + HitResult tracedBlock = traceBlocks(e, distance, partialTick, false); + + double totalTraceDistance = distance; + + Vec3d pos = e.getCameraPosVec(partialTick); + + if (tracedBlock != null) { + totalTraceDistance = tracedBlock.getPos().distanceTo(pos); + } + + Vec3d look = e.getRotationVec(partialTick); + Vec3d ray = pos.add(look.multiply(distance)); + + Vec3d hit = null; + Entity pointedEntity = null; + List entitiesWithinRange = e.world.getOtherEntities(e, e.getBoundingBox() + .expand(look.x * distance, look.y * distance, look.z * distance) + .expand(1, 1, 1), predicate); + + double traceDistance = totalTraceDistance; + + for (Entity entity : entitiesWithinRange) { + if (entity.collides()) { + Box entityAABB = entity.getBoundingBox().expand(entity.getTargetingMargin()); + + Optional intercept = entityAABB.rayTrace(pos, ray); + + if (entityAABB.contains(pos)) { + if (traceDistance <= 0) { + pointedEntity = entity; + hit = intercept.orElse(null); + traceDistance = 0; + } + } else if (intercept.isPresent()) { + Vec3d inter = intercept.get(); + double distanceToHit = pos.distanceTo(inter); + + if (distanceToHit < traceDistance || traceDistance == 0) { + if (entity.getRootVehicle() == e.getRootVehicle()) { + if (traceDistance == 0) { + pointedEntity = entity; + hit = inter; + } + } else { + pointedEntity = entity; + hit = inter; + traceDistance = distanceToHit; + } + } + } + } + } + + if (pointedEntity != null && (traceDistance < totalTraceDistance || tracedBlock == null)) { + return new Trace(new EntityHitResult(pointedEntity, hit)); + } + + return new Trace(tracedBlock); + } + + /** + * Server-available version of Entity.rayTrace + */ + public static HitResult traceBlocks(Entity e, double maxDistance, float tickDelta, boolean includeFluids) { + Vec3d start = e.getCameraPosVec(tickDelta); + Vec3d end = e.getRotationVec(tickDelta).multiply(maxDistance).add(start); + + return e.world.rayTrace(new RayTraceContext(start, end, + RayTraceContext.ShapeType.OUTLINE, + includeFluids ? RayTraceContext.FluidHandling.ANY : RayTraceContext.FluidHandling.NONE, + e) + ); + } + + public static class Trace { + @Nullable + private final HitResult result; + + Trace(@Nullable HitResult result) { + this.result = result; + } + + @Nullable + public HitResult getResult() { + return result; + } + + @SuppressWarnings("unchecked") + public Optional getEntity() { + if (result != null && result.getType() == HitResult.Type.ENTITY) { + return Optional.of((T)((EntityHitResult)result).getEntity()); + } + return Optional.empty(); + } + + public Optional getBlockPos() { + if (result != null && result.getType() == HitResult.Type.BLOCK) { + return Optional.of(((BlockHitResult)result).getBlockPos()); + } + return Optional.empty(); + } + + public Trace ifEntity(Consumer consumer) { + getEntity().ifPresent(consumer); + return this; + } + + public Trace ifBlock(Consumer consumer) { + getBlockPos().ifPresent(consumer); + return this; + } + } +} diff --git a/src/main/java/com/minelittlepony/unicopia/util/VecHelper.java b/src/main/java/com/minelittlepony/unicopia/util/VecHelper.java index 85ac9c6f..546ba8d6 100644 --- a/src/main/java/com/minelittlepony/unicopia/util/VecHelper.java +++ b/src/main/java/com/minelittlepony/unicopia/util/VecHelper.java @@ -1,63 +1,19 @@ package com.minelittlepony.unicopia.util; import java.util.List; -import java.util.Optional; import java.util.function.Predicate; import java.util.stream.Stream; import javax.annotation.Nullable; import net.minecraft.entity.Entity; -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; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Box; import net.minecraft.util.math.Vec3d; -import net.minecraft.world.RayTraceContext; import net.minecraft.world.World; public interface VecHelper { - /** - * Performs a ray cast from the given entity and returns a result for the first block that ray intercepts. - * - * 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 - */ - 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) - ); - } - - /** - * Gets the entity the player is currently looking at, or null. - */ - @Nullable - static Entity getLookedAtEntity(LivingEntity e, int reach) { - HitResult objectMouseOver = getObjectMouseOver(e, reach, 1); - - if (objectMouseOver instanceof EntityHitResult && objectMouseOver.getType() == BlockHitResult.Type.ENTITY) { - return ((EntityHitResult)objectMouseOver).getEntity(); - } - - return null; - } - static Stream findAllEntitiesInRange(@Nullable Entity origin, World w, BlockPos pos, double radius) { return w.getOtherEntities(origin, new Box(pos).expand(radius), e -> { double dist = Math.sqrt(e.squaredDistanceTo(pos.getX(), pos.getY(), pos.getZ())); @@ -70,7 +26,7 @@ public interface VecHelper { /** * Gets all entities within a given range from the player. */ - static List getWithinRange(PlayerEntity player, double reach, @Nullable Predicate predicate) { + static List getWithinReach(PlayerEntity player, double reach, @Nullable Predicate predicate) { Vec3d look = player.getCameraPosVec(1).multiply(reach); return player.world.getOtherEntities(player, player @@ -78,90 +34,4 @@ public interface VecHelper { .expand(look.x, look.y, look.z) .expand(1, 1, 1), predicate); } - - /** - * 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 - */ - 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. - *

- * - * - * @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 - */ - static HitResult getObjectMouseOver(Entity e, double distance, float partialTick, Predicate predicate) { - HitResult tracedBlock = rayTrace(e, distance, partialTick); - - double totalTraceDistance = distance; - - Vec3d pos = e.getCameraPosVec(partialTick); - - if (tracedBlock != null) { - totalTraceDistance = tracedBlock.getPos().distanceTo(pos); - } - - Vec3d look = e.getRotationVec(partialTick); - Vec3d ray = pos.add(look.multiply(distance)); - - Vec3d hit = null; - Entity pointedEntity = null; - List entitiesWithinRange = e.world.getOtherEntities(e, e.getBoundingBox() - .expand(look.x * distance, look.y * distance, look.z * distance) - .expand(1, 1, 1), predicate); - - double traceDistance = totalTraceDistance; - - for (Entity entity : entitiesWithinRange) { - if (entity.collides()) { - Box entityAABB = entity.getBoundingBox().expand(entity.getTargetingMargin()); - - Optional intercept = entityAABB.rayTrace(pos, ray); - - if (entityAABB.contains(pos)) { - if (traceDistance <= 0) { - pointedEntity = entity; - hit = intercept.orElse(null); - traceDistance = 0; - } - } else if (intercept.isPresent()) { - Vec3d inter = intercept.get(); - double distanceToHit = pos.distanceTo(inter); - - if (distanceToHit < traceDistance || traceDistance == 0) { - if (entity.getRootVehicle() == e.getRootVehicle()) { - if (traceDistance == 0) { - pointedEntity = entity; - hit = inter; - } - } else { - pointedEntity = entity; - hit = inter; - traceDistance = distanceToHit; - } - } - } - } - } - - if (pointedEntity != null && (traceDistance < totalTraceDistance || tracedBlock == null)) { - return new EntityHitResult(pointedEntity, hit); - } - - return tracedBlock; - } }