24package com.dreamfirestudios.dreamcore.DreamLocation;
26import org.bukkit.Location;
27import org.bukkit.World;
28import org.bukkit.block.Block;
29import org.bukkit.util.Vector;
31import java.util.ArrayList;
33import java.util.Locale;
34import java.util.Objects;
78 public static Location
closestLocation(List<Location> locations, Location originLocation) {
79 if (locations ==
null || locations.isEmpty())
80 throw new IllegalArgumentException(
"Locations list cannot be null or empty.");
81 if (originLocation ==
null || originLocation.getWorld() ==
null)
82 throw new IllegalArgumentException(
"Origin location/world cannot be null.");
84 final World world = originLocation.getWorld();
85 double best = Double.POSITIVE_INFINITY;
86 Location bestLoc =
null;
88 for (Location candidate : locations) {
89 if (candidate ==
null || candidate.getWorld() ==
null)
continue;
90 if (!world.equals(candidate.getWorld()))
continue;
92 double d2 = originLocation.distanceSquared(candidate);
96 if (best == 0.0)
break;
123 public static Location
midpoint(Location a, Location b) {
124 if (a ==
null || b ==
null)
throw new IllegalArgumentException(
"Both locations must not be null.");
125 if (!Objects.equals(a.getWorld(), b.getWorld()))
return null;
128 (a.getX() + b.getX()) * 0.5,
129 (a.getY() + b.getY()) * 0.5,
130 (a.getZ() + b.getZ()) * 0.5
158 public static boolean isBlockBetween(Location location1, Location location2, Block block) {
159 if (location1 ==
null || location2 ==
null || block ==
null)
160 throw new IllegalArgumentException(
"Locations and block must not be null.");
161 if (location1.getWorld() ==
null || location2.getWorld() ==
null || block.getWorld() ==
null)
163 if (!location1.getWorld().equals(location2.getWorld()))
return false;
164 if (!block.getWorld().equals(location1.getWorld()))
return false;
166 int minX = Math.min(location1.getBlockX(), location2.getBlockX());
167 int maxX = Math.max(location1.getBlockX(), location2.getBlockX());
168 int minY = Math.min(location1.getBlockY(), location2.getBlockY());
169 int maxY = Math.max(location1.getBlockY(), location2.getBlockY());
170 int minZ = Math.min(location1.getBlockZ(), location2.getBlockZ());
171 int maxZ = Math.max(location1.getBlockZ(), location2.getBlockZ());
173 int bx = block.getX(), by = block.getY(), bz = block.getZ();
174 return bx >= minX && bx <= maxX
175 && by >= minY && by <= maxY
176 && bz >= minZ && bz <= maxZ;
202 public static Location[]
pointsBetween(Location start, Location end,
double spacing) {
203 if (start ==
null || end ==
null)
throw new IllegalArgumentException(
"Start/end must not be null.");
204 if (start.getWorld() ==
null || end.getWorld() ==
null)
205 throw new IllegalArgumentException(
"Start/end worlds must not be null.");
206 if (!start.getWorld().equals(end.getWorld()))
207 throw new IllegalArgumentException(
"Start/end must be in the same world.");
208 if (spacing <= 0)
throw new IllegalArgumentException(
"Spacing must be greater than zero.");
210 double distance = start.distance(end);
211 if (distance == 0.0) {
212 return new Location[]{start.clone()};
215 int segments = Math.max(1, (
int) Math.floor(distance / spacing));
216 int points = segments + 1;
218 Vector step = end.toVector().subtract(start.toVector()).multiply(1.0 / segments);
220 Location[] out =
new Location[points];
221 for (
int i = 0; i < points; i++) {
222 Vector v = start.toVector().add(step.clone().multiply(i));
223 out[i] =
new Location(start.getWorld(), v.getX(), v.getY(), v.getZ());
248 if (a ==
null || b ==
null)
throw new IllegalArgumentException(
"Locations must not be null.");
249 if (a.getWorld() ==
null || b.getWorld() ==
null)
250 throw new IllegalArgumentException(
"Worlds must not be null.");
251 if (!a.getWorld().equals(b.getWorld()))
252 throw new IllegalArgumentException(
"Locations must be in the same world.");
254 List<Location> locations =
new ArrayList<>();
256 int minX = Math.min(a.getBlockX(), b.getBlockX());
257 int minY = Math.min(a.getBlockY(), b.getBlockY());
258 int minZ = Math.min(a.getBlockZ(), b.getBlockZ());
260 int maxX = Math.max(a.getBlockX(), b.getBlockX());
261 int maxY = Math.max(a.getBlockY(), b.getBlockY());
262 int maxZ = Math.max(a.getBlockZ(), b.getBlockZ());
264 World w = a.getWorld();
266 for (
int x = minX; x <= maxX; x++) {
267 for (
int y = minY; y <= maxY; y++) {
268 for (
int z = minZ; z <= maxZ; z++) {
269 locations.add(
new Location(w, x, y, z));
295 if (locations ==
null || locations.length < 2)
296 throw new IllegalArgumentException(
"At least two locations must be provided.");
298 for (
int i = 0; i < locations.length - 1; i++) {
299 Location a = Objects.requireNonNull(locations[i],
"Location[" + i +
"] is null");
300 Location b = Objects.requireNonNull(locations[i + 1],
"Location[" + (i + 1) +
"] is null");
301 if (!Objects.equals(a.getWorld(), b.getWorld()))
302 throw new IllegalArgumentException(
"All consecutive locations must be in the same world.");
303 total += a.distance(b);
325 return translate(start, direction, distance);
328 public static Location
translate(Location start, Vector direction,
double distance) {
329 if (start ==
null || direction ==
null)
330 throw new IllegalArgumentException(
"Start location and direction must not be null.");
331 Vector newPos = start.toVector().add(direction.clone().normalize().multiply(distance));
332 return newPos.toLocation(start.getWorld());
361 public static double axisAngle(Location a, Location b, String axis) {
362 if (a ==
null || b ==
null)
throw new IllegalArgumentException(
"Locations must not be null.");
363 double dx = b.getX() - a.getX();
364 double dy = b.getY() - a.getY();
365 double dz = b.getZ() - a.getZ();
367 String ax = Objects.requireNonNull(axis,
"axis").trim().toUpperCase(Locale.ROOT);
369 case "X":
return Math.atan2(dy, dz);
370 case "Y":
return Math.atan2(dx, dz);
371 case "Z":
return Math.atan2(dy, dx);
372 default:
throw new IllegalArgumentException(
"Invalid axis: " + axis +
" (expected X, Y, or Z)");
Location and vector helper utilities with safe null checks, world consistency checks,...
static Location GetLocationInDirection(Location start, Vector direction, double distance)
Computes a location offset from start by direction.normalized * distance.
static boolean IsBlockBetweenLocations(Location location1, Location location2, Block block)
Checks if a block lies within the axis-aligned box defined by two locations.
static Location ReturnClosestLocation(List< Location > locations, Location originLocation)
Returns the closest location to the provided origin from a list.
static Location FindMidPointBetween2Locations(Location a, Location b)
Finds the midpoint between two locations (same world required).
static Location[] ReturnAllLocationsBetweenTwoLocations(Location start, Location end, double spacing)
Returns evenly spaced points (including endpoints) between two locations.
static Location translate(Location start, Vector direction, double distance)
static boolean isBlockBetween(Location location1, Location location2, Block block)
static double totalDistance(Location... locations)
static List< Location > GetAllLocationsInCubeArea(Location a, Location b)
Returns all block locations inside the axis-aligned box defined by two points.
static double TotalDistance(Location... locations)
Calculates the total path length through provided locations in order.
static double CalculateAngleBetweenLocations(Location a, Location b, String axis)
Calculates angle (radians) of vector a->b around a given axis.
static Location midpoint(Location a, Location b)
static Location closestLocation(List< Location > locations, Location originLocation)
static Location[] pointsBetween(Location start, Location end, double spacing)
static double axisAngle(Location a, Location b, String axis)
static List< Location > cubeLocations(Location a, Location b)