package com.minelittlepony.unicopia.util; import java.util.Optional; import java.util.function.Consumer; import java.util.function.Predicate; import net.minecraft.entity.Entity; import net.minecraft.util.hit.*; import net.minecraft.util.math.*; @SuppressWarnings("unchecked") public record Trace( Optional result ) { /** * Performs a ray trace from the given entity and returns * a result for the first Entity that passes the given predicate * or block that the ray intercepts. * * * @param e Entity to start from * @param distance Maximum distance * @param tickDelta Client partial ticks * @param predicate Predicate test to filter entities * * @return A Trace describing what was found. */ public static Trace create(Entity e, double distance, float tickDelta, Predicate predicate) { return new Trace( ((Optional)(Optional)TraceHelper.traceEntity(e, distance, tickDelta, predicate)) .or(() -> Optional.ofNullable(e.raycast(distance, tickDelta, false))) ); } static T toEntity(EntityHitResult hit) { return (T)hit.getEntity(); } public Optional getEntityResult() { return result() .filter(s -> s.getType() == HitResult.Type.ENTITY) .map(EntityHitResult.class::cast); } public Optional getBlockResult() { return result() .filter(s -> s.getType() == HitResult.Type.BLOCK) .map(BlockHitResult.class::cast); } public Optional getEntity() { return getEntityResult().map(Trace::toEntity); } public Optional getBlockPos() { return getBlockResult().map(BlockHitResult::getBlockPos); } public Optional getBlockOrEntityPos() { return getBlockPos().or(() -> getEntity().map(Entity::getBlockPos)); } public Optional getSide() { return getBlockResult().map(BlockHitResult::getSide); } public Trace ifEntity(Consumer consumer) { getEntity().ifPresent(consumer); return this; } public Trace ifBlock(Consumer consumer) { getBlockPos().ifPresent(consumer); return this; } }