001/* 002 * PlotSquared, a land and world management plugin for Minecraft. 003 * Copyright (C) IntellectualSites <https://intellectualsites.com> 004 * Copyright (C) IntellectualSites team and contributors 005 * 006 * This program is free software: you can redistribute it and/or modify 007 * it under the terms of the GNU General Public License as published by 008 * the Free Software Foundation, either version 3 of the License, or 009 * (at your option) any later version. 010 * 011 * This program is distributed in the hope that it will be useful, 012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 014 * GNU General Public License for more details. 015 * 016 * You should have received a copy of the GNU General Public License 017 * along with this program. If not, see <https://www.gnu.org/licenses/>. 018 */ 019package com.plotsquared.core.location; 020 021import com.google.common.base.Objects; 022import com.google.common.base.Preconditions; 023import com.plotsquared.core.PlotSquared; 024import com.plotsquared.core.plot.Plot; 025import com.plotsquared.core.plot.PlotArea; 026import com.sk89q.worldedit.math.BlockVector2; 027import com.sk89q.worldedit.math.BlockVector3; 028import org.checkerframework.checker.nullness.qual.NonNull; 029import org.checkerframework.checker.nullness.qual.Nullable; 030import org.khelekore.prtree.MBR; 031import org.khelekore.prtree.SimpleMBR; 032 033/** 034 * An unmodifiable 6-tuple (world,x,y,z,yaw,pitch) 035 */ 036@SuppressWarnings("unused") 037public sealed class Location extends BlockLoc implements Comparable<Location> permits UncheckedWorldLocation { 038 039 private final float yaw; 040 private final float pitch; 041 private final BlockVector3 blockVector3; 042 private final World<?> world; 043 044 /** 045 * @since 6.9.0 046 */ 047 protected Location( 048 final @NonNull World<?> world, final @NonNull BlockVector3 blockVector3, 049 final float yaw, final float pitch 050 ) { 051 super(blockVector3.getX(), blockVector3.getY(), blockVector3.getZ(), yaw, pitch); 052 this.world = Preconditions.checkNotNull(world, "World may not be null"); 053 this.blockVector3 = Preconditions.checkNotNull(blockVector3, "Vector may not be null"); 054 this.yaw = yaw; 055 this.pitch = pitch; 056 } 057 058 private Location( 059 final @NonNull String worldName, final @NonNull BlockVector3 blockVector3, 060 final float yaw, final float pitch 061 ) { 062 super(blockVector3.getX(), blockVector3.getY(), blockVector3.getZ(), yaw, pitch); 063 Preconditions.checkNotNull(worldName, "World name may not be null"); 064 if (worldName.isEmpty()) { 065 this.world = World.nullWorld(); 066 } else { 067 this.world = PlotSquared.platform().getPlatformWorld(worldName); 068 } 069 this.blockVector3 = Preconditions.checkNotNull(blockVector3, "Vector may not be null"); 070 this.yaw = yaw; 071 this.pitch = pitch; 072 } 073 074 /** 075 * Construct a new location 076 * 077 * @param world World 078 * @param blockVector3 (x,y,z) vector 079 * @param yaw yaw 080 * @param pitch pitch 081 * @return New location 082 */ 083 public static @NonNull Location at( 084 final @NonNull String world, 085 final @NonNull BlockVector3 blockVector3, final float yaw, final float pitch 086 ) { 087 return new Location(world, blockVector3, yaw, pitch); 088 } 089 090 /** 091 * Construct a new location with yaw and pitch equal to 0 092 * 093 * @param world World 094 * @param blockVector3 (x,y,z) vector 095 * @return New location 096 */ 097 public static @NonNull Location at( 098 final @NonNull String world, 099 final @NonNull BlockVector3 blockVector3 100 ) { 101 return at(world, blockVector3, 0f, 0f); 102 } 103 104 /** 105 * Construct a new location 106 * 107 * @param world World 108 * @param x X coordinate 109 * @param y Y coordinate 110 * @param z Z coordinate 111 * @param yaw Yaw 112 * @param pitch Pitch 113 * @return New location 114 */ 115 public static @NonNull Location at( 116 final @NonNull String world, final int x, final int y, 117 final int z, final float yaw, final float pitch 118 ) { 119 return at(world, BlockVector3.at(x, y, z), yaw, pitch); 120 } 121 122 /** 123 * Construct a new location with yaw and pitch equal to 0 124 * 125 * @param world World 126 * @param x X coordinate 127 * @param y Y coordinate 128 * @param z Z coordinate 129 * @return New location 130 */ 131 public static @NonNull Location at( 132 final @NonNull String world, final int x, final int y, 133 final int z 134 ) { 135 return at(world, BlockVector3.at(x, y, z)); 136 } 137 138 /** 139 * Construct a new location 140 * 141 * @param world World 142 * @param blockVector3 (x,y,z) vector 143 * @param yaw yaw 144 * @param pitch pitch 145 * @return New location 146 */ 147 public static @NonNull Location at( 148 final @NonNull World<?> world, 149 final @NonNull BlockVector3 blockVector3, final float yaw, final float pitch 150 ) { 151 return new Location(world, blockVector3, yaw, pitch); 152 } 153 154 /** 155 * Construct a new location with yaw and pitch equal to 0 156 * 157 * @param world World 158 * @param blockVector3 (x,y,z) vector 159 * @return New location 160 */ 161 public static @NonNull Location at( 162 final @NonNull World<?> world, 163 final @NonNull BlockVector3 blockVector3 164 ) { 165 return at(world, blockVector3, 0f, 0f); 166 } 167 168 /** 169 * Construct a new location 170 * 171 * @param world World 172 * @param x X coordinate 173 * @param y Y coordinate 174 * @param z Z coordinate 175 * @param yaw Yaw 176 * @param pitch Pitch 177 * @return New location 178 */ 179 public static @NonNull Location at( 180 final @NonNull World<?> world, final int x, final int y, 181 final int z, final float yaw, final float pitch 182 ) { 183 return at(world, BlockVector3.at(x, y, z), yaw, pitch); 184 } 185 186 /** 187 * Construct a new location with yaw and pitch equal to 0 188 * 189 * @param world World 190 * @param x X coordinate 191 * @param y Y coordinate 192 * @param z Z coordinate 193 * @return New location 194 */ 195 public static @NonNull Location at( 196 final @NonNull World<?> world, final int x, final int y, 197 final int z 198 ) { 199 return at(world, BlockVector3.at(x, y, z)); 200 } 201 202 /** 203 * Get the world object 204 * 205 * @return World object 206 */ 207 public @NonNull World<?> getWorld() { 208 return this.world; 209 } 210 211 /** 212 * Get the name of the world this location is in 213 * 214 * @return World name 215 */ 216 public @NonNull String getWorldName() { 217 return this.world.getName(); 218 } 219 220 /** 221 * Get the X coordinate 222 * 223 * @return X coordinate 224 */ 225 public int getX() { 226 return this.blockVector3.getBlockX(); 227 } 228 229 /** 230 * Get the Y coordinate 231 * 232 * @return Y coordinate 233 */ 234 public int getY() { 235 return this.blockVector3.getY(); 236 } 237 238 /** 239 * Get the Z coordinate 240 * 241 * @return Z coordinate 242 */ 243 public int getZ() { 244 return this.blockVector3.getZ(); 245 } 246 247 /** 248 * Get the {@link PlotArea}, if any, that contains this location 249 * 250 * @return Plot area containing the location, or {@code null} 251 */ 252 public @Nullable PlotArea getPlotArea() { 253 return PlotSquared.get().getPlotAreaManager().getPlotArea(this); 254 } 255 256 /** 257 * Get the owned {@link Plot}, if any, that contains this location 258 * 259 * @return Plot containing the location, or {@code null} 260 */ 261 public @Nullable Plot getOwnedPlot() { 262 final PlotArea area = this.getPlotArea(); 263 if (area != null) { 264 return area.getOwnedPlot(this); 265 } else { 266 return null; 267 } 268 } 269 270 /** 271 * Get the (absolute) owned {@link Plot}, if any, that contains this location 272 * 273 * @return (Absolute) plot containing the location, or {@code null} 274 */ 275 public @Nullable Plot getOwnedPlotAbs() { 276 final PlotArea area = this.getPlotArea(); 277 if (area != null) { 278 return area.getOwnedPlotAbs(this); 279 } else { 280 return null; 281 } 282 } 283 284 /** 285 * Check whether the location belongs to a plot area 286 * 287 * @return {@code true} if the location belongs to a plot area, else {@code false} 288 */ 289 public boolean isPlotArea() { 290 return this.getPlotArea() != null; 291 } 292 293 /** 294 * Check whether the location belongs to a plot road 295 * 296 * @return {@code true} if the location belongs to a plot road, else {@code false} 297 */ 298 public boolean isPlotRoad() { 299 final PlotArea area = this.getPlotArea(); 300 return area != null && area.getPlotAbs(this) == null; 301 } 302 303 /** 304 * Checks if anyone owns a plot at the current location. 305 * 306 * @return {@code true} if the location is a road, not a plot area, or if the plot is unclaimed. 307 */ 308 public boolean isUnownedPlotArea() { 309 final PlotArea area = this.getPlotArea(); 310 return area != null && area.getOwnedPlotAbs(this) == null; 311 } 312 313 /** 314 * Get the absolute {@link Plot}, if any, that contains this location 315 * 316 * @return (Absolute) plot containing the location, or {@code null} 317 */ 318 public @Nullable Plot getPlotAbs() { 319 final PlotArea area = this.getPlotArea(); 320 if (area != null) { 321 return area.getPlotAbs(this); 322 } else { 323 return null; 324 } 325 } 326 327 /** 328 * Get the {@link Plot}, if any, that contains this location 329 * 330 * @return plot containing the location, or {@code null} 331 */ 332 public @Nullable Plot getPlot() { 333 final PlotArea area = this.getPlotArea(); 334 if (area != null) { 335 return area.getPlot(this); 336 } else { 337 return null; 338 } 339 } 340 341 /** 342 * Get the coordinates of the chunk that contains this location 343 * 344 * @return Chunk coordinates 345 */ 346 public @NonNull BlockVector2 getChunkLocation() { 347 return BlockVector2.at(this.getX() >> 4, this.getZ() >> 4); 348 } 349 350 /** 351 * Return a new location offset by the given coordinates 352 * 353 * @param x X offset 354 * @param y Y offset 355 * @param z Z offset 356 * @return New location 357 */ 358 public @NonNull Location add(final int x, final int y, final int z) { 359 return new Location(this.world, this.blockVector3.add(x, y, z), this.yaw, this.pitch); 360 } 361 362 /** 363 * Return a new location using the given X coordinate 364 * 365 * @param x New X coordinate 366 * @return New location 367 */ 368 public @NonNull Location withX(final int x) { 369 return new Location(this.world, this.blockVector3.withX(x), this.yaw, this.pitch); 370 } 371 372 /** 373 * Return a new location using the given Y coordinate 374 * 375 * @param y New Y coordinate 376 * @return New location 377 */ 378 public @NonNull Location withY(final int y) { 379 return new Location(this.world, this.blockVector3.withY(y), this.yaw, this.pitch); 380 } 381 382 /** 383 * Return a new location using the given Z coordinate 384 * 385 * @param z New Z coordinate 386 * @return New location 387 */ 388 public @NonNull Location withZ(final int z) { 389 return new Location(this.world, this.blockVector3.withZ(z), this.yaw, this.pitch); 390 } 391 392 /** 393 * Return a new location using the given yaw 394 * 395 * @param yaw New yaw 396 * @return New location 397 */ 398 public @NonNull Location withYaw(final float yaw) { 399 return new Location(this.world, this.blockVector3, yaw, this.pitch); 400 } 401 402 /** 403 * Return a new location using the given pitch 404 * 405 * @param pitch New pitch 406 * @return New location 407 */ 408 public @NonNull Location withPitch(final float pitch) { 409 return new Location(this.world, this.blockVector3, this.yaw, pitch); 410 } 411 412 /** 413 * Return a new location using the given world 414 * 415 * @param world New world 416 * @return New location 417 */ 418 public @NonNull Location withWorld(final @NonNull String world) { 419 return new Location(world, this.blockVector3, this.yaw, this.pitch); 420 } 421 422 public double getEuclideanDistanceSquared(final @NonNull Location l2) { 423 double x = getX() - l2.getX(); 424 double y = getY() - l2.getY(); 425 double z = getZ() - l2.getZ(); 426 return x * x + y * y + z * z; 427 } 428 429 public double getEuclideanDistance(final @NonNull Location l2) { 430 return Math.sqrt(getEuclideanDistanceSquared(l2)); 431 } 432 433 /** 434 * Return a new location offset by (-) the given coordinates 435 * 436 * @param x X offset 437 * @param y Y offset 438 * @param z Z offset 439 * @return New location 440 */ 441 public @NonNull Location subtract(int x, int y, int z) { 442 return this.add(-x, -y, -z); 443 } 444 445 /** 446 * Get a minimum bounding rectangle that contains this location only 447 * 448 * @return Minimum bounding rectangle 449 */ 450 public @NonNull MBR toMBR() { 451 return new SimpleMBR(this.getX(), this.getX(), this.getY(), this.getY(), this.getZ(), 452 this.getZ() 453 ); 454 } 455 456 @Override 457 public int compareTo(final @NonNull Location o) { 458 if (this.getX() == o.getX() && this.getY() == o.getY() || this.getZ() == o.getZ()) { 459 return 0; 460 } 461 if (this.getX() < o.getX() && this.getY() < o.getY() && this.getZ() < o.getZ()) { 462 return -1; 463 } 464 return 1; 465 } 466 467 @Override 468 public boolean equals(final Object o) { 469 if (this == o) { 470 return true; 471 } 472 if (o == null || getClass() != o.getClass()) { 473 return false; 474 } 475 if (!super.equals(o)) { 476 return false; 477 } 478 final Location location = (Location) o; 479 return Float.compare(location.getYaw(), getYaw()) == 0 480 && Float.compare(location.getPitch(), getPitch()) == 0 && Objects 481 .equal(getBlockVector3(), location.getBlockVector3()) && Objects 482 .equal(getWorld(), location.getWorld()); 483 } 484 485 @Override 486 public int hashCode() { 487 return Objects 488 .hashCode(super.hashCode(), getYaw(), getPitch(), getBlockVector3(), getWorld()); 489 } 490 491 @Override 492 public String toString() { 493 return "\"plotsquaredlocation\":{\"x\":" + this.getX() + ",\"y\":" + this.getY() + ",\"z\":" 494 + this.getZ() + ",\"yaw\":" + this.yaw + ",\"pitch\":" + this.pitch + ",\"world\":\"" 495 + this.world + "\"}"; 496 } 497 498 public float getYaw() { 499 return this.yaw; 500 } 501 502 public float getPitch() { 503 return this.pitch; 504 } 505 506 public BlockVector3 getBlockVector3() { 507 return this.blockVector3; 508 } 509 510}