public class ParticleLine { private static final double RENDER_DISTANCE = 32; private static final double RENDER_DISTANCE_SQUARED = RENDER_DISTANCE * RENDER_DISTANCE; private final Vector min; private final Vector max; private final double distanceBetween; public ParticleLine(Vector min, Vector max, double distanceBetween) { this.min = min; this.max = max; this.distanceBetween = distanceBetween; } public static ParticleLine interpolate(Vector start, Vector end, int pointCount) { double distance = start.distance(end); double distanceBetween = distance / pointCount; return interpolate(start, end, distanceBetween); } public static ParticleLine interpolate(Vector start, Vector end, double distanceBetween) { return new ParticleLine(start, end, distanceBetween); } public List getPoints(Player viewer) { // Same logic as before, but now we don't attempt to iterate over the points that we don't need to render List points = new ArrayList<>(); // This line might be 500 blocks long, but we only want to render the points that are within the player's view distance Vector start = min.clone(); Vector end = max.clone(); Location playerLoc = viewer.getEyeLocation(); Vector playerVec = playerLoc.toVector(); Vector newMin = start; Vector newMax = end; if (isTooFar(playerVec)) { return points; } double totalDistance = start.distance(end); if (totalDistance > RENDER_DISTANCE) { // Get the min and max percentage so that the line between newMin and newMax is RENDER_DISTANCE long double minPercentage = RENDER_DISTANCE / totalDistance; double maxPercentage = 1 - minPercentage; minPercentage = Math.max(0, minPercentage); maxPercentage = Math.min(1, maxPercentage); newMin = lerpSnap(start, end, minPercentage); newMax = lerpSnap(start, end, maxPercentage); } int pointCount = (int) (newMin.distance(newMax) / distanceBetween); Vector direction = newMax.clone().subtract(newMin).normalize().multiply(distanceBetween); for (int index = 0; index < pointCount; index++) { Vector point = newMin.clone().add(direction.clone().multiply(index)); points.add(point); } return points; } private Vector lerpSnap(Vector start, Vector end, double t) { Vector direction = end.clone().subtract(start).normalize().multiply(t); double distance = start.distance(end); int pointCount = (int) (distance / distanceBetween); return start.clone().add(direction.clone().multiply(pointCount)); } private boolean isTooFar(Vector playerVec) { // If it's too far in every direction return isTooFar(playerVec, min) && isTooFar(playerVec, max); } private boolean isTooFar(Vector playerVec, Vector point) { double dX = Math.abs(playerVec.getX() - point.getX()); double dY = Math.abs(playerVec.getY() - point.getY()); double dZ = Math.abs(playerVec.getZ() - point.getZ()); return dX > RENDER_DISTANCE && dY > RENDER_DISTANCE && dZ > RENDER_DISTANCE; } }