Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -4,32 +4,77 @@
import io.github.itzispyder.clickcrystals.scripting.components.ConditionEvaluationContext;
import io.github.itzispyder.clickcrystals.scripting.components.ConditionEvaluationResult;
import io.github.itzispyder.clickcrystals.scripting.components.Conditional;
import io.github.itzispyder.clickcrystals.util.minecraft.EntityUtils;
import io.github.itzispyder.clickcrystals.util.minecraft.PlayerUtils;
import net.minecraft.block.BlockState;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.hit.BlockHitResult;
import net.minecraft.util.hit.HitResult;
import net.minecraft.util.math.Vec3d;
import net.minecraft.world.RaycastContext;

import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Predicate;

public class ConditionalBlockInFov implements Conditional {

private static final double DEFAULT_RANGE = 6.0;
private static final float[] YAW_OFFSETS = {0, -1, 1};
private static final float[] PITCH_OFFSETS = {0, -1, 1};

@Override
public ConditionEvaluationResult evaluate(ConditionEvaluationContext ctx) {
Predicate<BlockState> filter = ctx.match(0, "any_block") ? state -> true : ScriptParser.parseBlockPredicate(ctx.get(0).toString());
AtomicBoolean bl = new AtomicBoolean(false);
float fovDeg = ctx.get(1).toFloat();

EntityUtils.runOnNearestBlock(ctx.entity, 32,
(pos, state) -> filter.test(state) && validBlock(pos, fovDeg),
(pos, state) -> bl.set(true));
return ctx.end(true, bl.get());
if (!PlayerUtils.valid())
return ctx.end(true, false);

Predicate<BlockState> filter = resolveFilter(ctx);
float fovDeg = resolveFov(ctx);

boolean found = scanCone(ctx, filter, fovDeg);
return ctx.end(true, found);
}

private Predicate<BlockState> resolveFilter(ConditionEvaluationContext ctx) {
return ctx.match(0, "any_block") ? state -> true : ScriptParser.parseBlockPredicate(ctx.get(0).toString());
}

private float resolveFov(ConditionEvaluationContext ctx) {
float fov = ctx.get(1).toFloat();
if (fov <= 0 || fov > 360)
return 90;
return fov;
}

private boolean scanCone(ConditionEvaluationContext ctx, Predicate<BlockState> filter, float fovDeg) {
Vec3d eyes = PlayerUtils.getEyes();
float yaw = PlayerUtils.player().getYaw();
float pitch = PlayerUtils.player().getPitch();
float step = fovDeg / 4;

for (float yawMult : YAW_OFFSETS) {
for (float pitchMult : PITCH_OFFSETS) {
Vec3d dir = getDirection(yaw + yawMult * step, pitch + pitchMult * step);
Vec3d end = eyes.add(dir.multiply(DEFAULT_RANGE));

BlockHitResult hit = ctx.entity.getEntityWorld().raycast(
new RaycastContext(eyes, end, RaycastContext.ShapeType.OUTLINE, RaycastContext.FluidHandling.NONE, ctx.entity)
);

if (hit.getType() == HitResult.Type.BLOCK) {
BlockState state = ctx.entity.getEntityWorld().getBlockState(hit.getBlockPos());
if (filter.test(state))
return true;
}
}
}
return false;
}

private boolean validBlock(BlockPos pos, float fovDeg) {
if (fovDeg != 360 && PlayerUtils.valid())
if (!ConditionalEntityInFov.isPointInFov(PlayerUtils.getEyes(), PlayerUtils.getDir(), fovDeg, pos.toCenterPos()))
return false;
return pos.toCenterPos().distanceTo(PlayerUtils.getPos()) <= fovDeg;
private Vec3d getDirection(float yaw, float pitch) {
float yawRad = (float) Math.toRadians(yaw);
float pitchRad = (float) Math.toRadians(pitch);
float cosPitch = (float) Math.cos(pitchRad);
return new Vec3d(
-Math.sin(yawRad) * cosPitch,
-Math.sin(pitchRad),
Math.cos(yawRad) * cosPitch
);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -142,16 +142,33 @@ public static boolean isCollidingVertically() {
}

public static void boxIterator(World world, Box box, BiConsumer<BlockPos, BlockState> function) {
for (double x = box.minX; x <= box.maxX; x++) {
for (double y = box.minY; y <= box.maxY; y++) {
for (double z = box.minZ; z <= box.maxZ; z++) {
BlockPos pos = new BlockPos((int) Math.floor(x), (int) Math.floor(y), (int) Math.floor(z));
BlockState state = world.getBlockState(pos);

if (state == null || state.isAir()) {
continue;
Vec3d center = box.getCenter();
int centerX = (int) Math.floor(center.x);
int centerY = (int) Math.floor(center.y);
int centerZ = (int) Math.floor(center.z);
double range = Math.max(Math.max(box.getXLength(), box.getYLength()), box.getZLength()) / 2;
int maxRadius = (int) Math.ceil(range);

for (int radius = 0; radius <= maxRadius; radius++) {
for (int x = -radius; x <= radius; x++) {
for (int y = -radius; y <= radius; y++) {
for (int z = -radius; z <= radius; z++) {
if (Math.abs(x) != radius && Math.abs(y) != radius && Math.abs(z) != radius) {
continue;
}

BlockPos pos = new BlockPos(centerX + x, centerY + y, centerZ + z);
if (!box.contains(pos.getX(), pos.getY(), pos.getZ())) {
continue;
}

BlockState state = world.getBlockState(pos);
if (state == null || state.isAir()) {
continue;
}

function.accept(pos, state);
}
function.accept(pos, state);
}
}
}
Expand Down