fix a bug that would kick players with an IllegalArgumentException when using workstation optimization
improve logging for some modules improve formatting of enums
This commit is contained in:
parent
4582cabc31
commit
f43f9898f1
4
pom.xml
4
pom.xml
@ -6,7 +6,7 @@
|
||||
|
||||
<groupId>me.xginko</groupId>
|
||||
<artifactId>VillagerOptimizer</artifactId>
|
||||
<version>1.5.1</version>
|
||||
<version>1.5.2</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>VillagerOptimizer</name>
|
||||
@ -23,7 +23,7 @@
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.11.0</version>
|
||||
<version>3.12.1</version>
|
||||
<configuration>
|
||||
<source>${java.version}</source>
|
||||
<target>${java.version}</target>
|
||||
|
@ -6,6 +6,7 @@ import me.xginko.villageroptimizer.VillagerCache;
|
||||
import me.xginko.villageroptimizer.VillagerOptimizer;
|
||||
import me.xginko.villageroptimizer.config.Config;
|
||||
import me.xginko.villageroptimizer.utils.GenericUtil;
|
||||
import me.xginko.villageroptimizer.utils.LocationUtil;
|
||||
import org.bukkit.Chunk;
|
||||
import org.bukkit.Server;
|
||||
import org.bukkit.World;
|
||||
@ -22,6 +23,7 @@ import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public class VillagerChunkLimit implements VillagerOptimizerModule, Listener {
|
||||
|
||||
@ -49,9 +51,19 @@ public class VillagerChunkLimit implements VillagerOptimizerModule, Listener {
|
||||
this.log_enabled = config.getBoolean(configPath() + ".log-removals", true);
|
||||
this.non_optimized_max_per_chunk = config.getInt(configPath() + ".unoptimized.max-per-chunk", 20,
|
||||
"The maximum amount of unoptimized villagers per chunk.");
|
||||
this.non_optimized_removal_priority = config.getList(configPath() + ".unoptimized.removal-priority", Arrays.asList(
|
||||
"NONE", "NITWIT", "SHEPHERD", "FISHERMAN", "BUTCHER", "CARTOGRAPHER", "LEATHERWORKER",
|
||||
"FLETCHER", "MASON", "FARMER", "ARMORER", "TOOLSMITH", "WEAPONSMITH", "CLERIC", "LIBRARIAN"),
|
||||
final List<String> defaults = Stream.of(
|
||||
"NONE", "NITWIT", "SHEPHERD", "FISHERMAN", "BUTCHER", "CARTOGRAPHER", "LEATHERWORKER",
|
||||
"FLETCHER", "MASON", "FARMER", "ARMORER", "TOOLSMITH", "WEAPONSMITH", "CLERIC", "LIBRARIAN")
|
||||
.filter(profession -> {
|
||||
try {
|
||||
// Make sure no scary warnings appear when creating config defaults
|
||||
Villager.Profession.valueOf(profession);
|
||||
return true;
|
||||
} catch (IllegalArgumentException e) {
|
||||
return false;
|
||||
}
|
||||
}).collect(Collectors.toList());
|
||||
this.non_optimized_removal_priority = config.getList(configPath() + ".unoptimized.removal-priority", defaults,
|
||||
"Professions that are in the top of the list are going to be scheduled for removal first.\n" +
|
||||
"Use enums from https://jd.papermc.io/paper/1.20/org/bukkit/entity/Villager.Profession.html")
|
||||
.stream()
|
||||
@ -69,9 +81,7 @@ public class VillagerChunkLimit implements VillagerOptimizerModule, Listener {
|
||||
.collect(Collectors.toList());
|
||||
this.optimized_max_per_chunk = config.getInt(configPath() + ".optimized.max-per-chunk", 60,
|
||||
"The maximum amount of optimized villagers per chunk.");
|
||||
this.optimized_removal_priority = config.getList(configPath() + ".optimized.removal-priority", Arrays.asList(
|
||||
"NONE", "NITWIT", "SHEPHERD", "FISHERMAN", "BUTCHER", "CARTOGRAPHER", "LEATHERWORKER",
|
||||
"FLETCHER", "MASON", "FARMER", "ARMORER", "TOOLSMITH", "WEAPONSMITH", "CLERIC", "LIBRARIAN"))
|
||||
this.optimized_removal_priority = config.getList(configPath() + ".optimized.removal-priority", defaults)
|
||||
.stream()
|
||||
.map(configuredProfession -> {
|
||||
try {
|
||||
@ -164,8 +174,8 @@ public class VillagerChunkLimit implements VillagerOptimizerModule, Listener {
|
||||
scheduler.runAtEntity(villager, kill -> {
|
||||
villager.remove();
|
||||
if (log_enabled) {
|
||||
info("Removed unoptimized villager with profession '" + villager.getProfession() + "' at " +
|
||||
GenericUtil.formatLocation(villager.getLocation()));
|
||||
info("Removed unoptimized villager with profession '" + GenericUtil.formatEnum(villager.getProfession()) + "' at " +
|
||||
LocationUtil.toString(villager.getLocation()));
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -186,8 +196,8 @@ public class VillagerChunkLimit implements VillagerOptimizerModule, Listener {
|
||||
villager.remove();
|
||||
|
||||
if (log_enabled) {
|
||||
info("Removed optimized villager with profession '" + villager.getProfession() + "' at " +
|
||||
GenericUtil.formatLocation(villager.getLocation()));
|
||||
info("Removed optimized villager with profession '" + GenericUtil.formatEnum(villager.getProfession()) + "' at " +
|
||||
LocationUtil.toString(villager.getLocation()));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -5,7 +5,7 @@ import me.xginko.villageroptimizer.VillagerCache;
|
||||
import me.xginko.villageroptimizer.VillagerOptimizer;
|
||||
import me.xginko.villageroptimizer.config.Config;
|
||||
import me.xginko.villageroptimizer.modules.VillagerOptimizerModule;
|
||||
import me.xginko.villageroptimizer.utils.GenericUtil;
|
||||
import me.xginko.villageroptimizer.utils.LocationUtil;
|
||||
import org.bukkit.GameMode;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.entity.EntityType;
|
||||
@ -90,7 +90,7 @@ public class EnableLeashingVillagers implements VillagerOptimizerModule, Listene
|
||||
handItem.subtract(1); // Manually consume for survival players
|
||||
|
||||
if (log_enabled) {
|
||||
info(player.getName() + " leashed a villager at " + GenericUtil.formatLocation(villager.getLocation()));
|
||||
info(player.getName() + " leashed a villager at " + LocationUtil.toString(villager.getLocation()));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -2,6 +2,7 @@ package me.xginko.villageroptimizer.modules.gameplay;
|
||||
|
||||
import me.xginko.villageroptimizer.VillagerCache;
|
||||
import me.xginko.villageroptimizer.VillagerOptimizer;
|
||||
import me.xginko.villageroptimizer.utils.LocationUtil;
|
||||
import me.xginko.villageroptimizer.wrapper.WrappedVillager;
|
||||
import me.xginko.villageroptimizer.config.Config;
|
||||
import me.xginko.villageroptimizer.enums.Permissions;
|
||||
@ -85,7 +86,7 @@ public class RestockOptimizedTrades implements VillagerOptimizerModule, Listener
|
||||
}
|
||||
|
||||
if (log_enabled) {
|
||||
info("Restocked optimized villager at " + GenericUtil.formatLocation(wVillager.villager().getLocation()));
|
||||
info("Restocked optimized villager at " + LocationUtil.toString(wVillager.villager().getLocation()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2,7 +2,6 @@ package me.xginko.villageroptimizer.modules.optimization;
|
||||
|
||||
import me.xginko.villageroptimizer.VillagerCache;
|
||||
import me.xginko.villageroptimizer.VillagerOptimizer;
|
||||
import me.xginko.villageroptimizer.wrapper.WrappedVillager;
|
||||
import me.xginko.villageroptimizer.config.Config;
|
||||
import me.xginko.villageroptimizer.enums.OptimizationType;
|
||||
import me.xginko.villageroptimizer.enums.Permissions;
|
||||
@ -11,7 +10,8 @@ import me.xginko.villageroptimizer.events.VillagerUnoptimizeEvent;
|
||||
import me.xginko.villageroptimizer.modules.VillagerOptimizerModule;
|
||||
import me.xginko.villageroptimizer.utils.GenericUtil;
|
||||
import me.xginko.villageroptimizer.utils.KyoriUtil;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import me.xginko.villageroptimizer.utils.LocationUtil;
|
||||
import me.xginko.villageroptimizer.wrapper.WrappedVillager;
|
||||
import net.kyori.adventure.text.TextReplacementConfig;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
@ -26,7 +26,10 @@ import org.bukkit.event.block.BlockBreakEvent;
|
||||
import org.bukkit.event.block.BlockPlaceEvent;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.*;
|
||||
import java.util.Arrays;
|
||||
import java.util.EnumSet;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@ -110,7 +113,8 @@ public class OptimizeByBlock implements VillagerOptimizerModule, Listener {
|
||||
for (Villager villager : blockLoc.getNearbyEntitiesByType(Villager.class, search_radius)) {
|
||||
final Villager.Profession profession = villager.getProfession();
|
||||
if (profession.equals(Villager.Profession.NONE) || profession.equals(Villager.Profession.NITWIT)) continue;
|
||||
final double distance = villager.getLocation().distanceSquared(blockLoc);
|
||||
|
||||
final double distance = LocationUtil.relDistanceSquared3D(villager.getLocation(), blockLoc);
|
||||
if (distance >= closestDistance) continue;
|
||||
|
||||
final WrappedVillager wVillager = villagerCache.getOrAdd(villager);
|
||||
@ -137,19 +141,19 @@ public class OptimizeByBlock implements VillagerOptimizerModule, Listener {
|
||||
if (notify_player) {
|
||||
final TextReplacementConfig vilProfession = TextReplacementConfig.builder()
|
||||
.matchLiteral("%vil_profession%")
|
||||
.replacement(closestOptimizableVillager.villager().getProfession().toString().toLowerCase())
|
||||
.replacement(GenericUtil.formatEnum(closestOptimizableVillager.villager().getProfession()))
|
||||
.build();
|
||||
final TextReplacementConfig placedMaterial = TextReplacementConfig.builder()
|
||||
.matchLiteral("%blocktype%")
|
||||
.replacement(placed.getType().toString().toLowerCase())
|
||||
.replacement(GenericUtil.formatEnum(placed.getType()))
|
||||
.build();
|
||||
VillagerOptimizer.getLang(player.locale()).block_optimize_success
|
||||
.forEach(line -> KyoriUtil.sendMessage(player, line.replaceText(vilProfession).replaceText(placedMaterial)));
|
||||
}
|
||||
|
||||
if (log_enabled) {
|
||||
VillagerOptimizer.getPrefixedLogger().info(Component.text(player.getName() + " optimized villager by block at " +
|
||||
GenericUtil.formatLocation(closestOptimizableVillager.villager().getLocation())).color(GenericUtil.COLOR));
|
||||
info(player.getName() + " optimized villager at " +
|
||||
LocationUtil.toString(closestOptimizableVillager.villager().getLocation()));
|
||||
}
|
||||
} else {
|
||||
closestOptimizableVillager.sayNo();
|
||||
@ -177,7 +181,7 @@ public class OptimizeByBlock implements VillagerOptimizerModule, Listener {
|
||||
double closestDistance = Double.MAX_VALUE;
|
||||
|
||||
for (Villager villager : blockLoc.getNearbyEntitiesByType(Villager.class, search_radius)) {
|
||||
final double distance = villager.getLocation().distanceSquared(blockLoc);
|
||||
final double distance = LocationUtil.relDistanceSquared3D(villager.getLocation(), blockLoc);
|
||||
if (distance >= closestDistance) continue;
|
||||
|
||||
final WrappedVillager wVillager = villagerCache.getOrAdd(villager);
|
||||
@ -202,19 +206,19 @@ public class OptimizeByBlock implements VillagerOptimizerModule, Listener {
|
||||
if (notify_player) {
|
||||
final TextReplacementConfig vilProfession = TextReplacementConfig.builder()
|
||||
.matchLiteral("%vil_profession%")
|
||||
.replacement(closestOptimizedVillager.villager().getProfession().toString().toLowerCase())
|
||||
.replacement(GenericUtil.formatEnum(closestOptimizedVillager.villager().getProfession()))
|
||||
.build();
|
||||
final TextReplacementConfig brokenMaterial = TextReplacementConfig.builder()
|
||||
.matchLiteral("%blocktype%")
|
||||
.replacement(broken.getType().toString().toLowerCase())
|
||||
.replacement(GenericUtil.formatEnum(broken.getType()))
|
||||
.build();
|
||||
VillagerOptimizer.getLang(player.locale()).block_unoptimize_success
|
||||
.forEach(line -> KyoriUtil.sendMessage(player, line.replaceText(vilProfession).replaceText(brokenMaterial)));
|
||||
}
|
||||
|
||||
if (log_enabled) {
|
||||
VillagerOptimizer.getPrefixedLogger().info(Component.text(player.getName() + " unoptimized villager by block at " +
|
||||
GenericUtil.formatLocation(closestOptimizedVillager.villager().getLocation())).color(GenericUtil.COLOR));
|
||||
info(player.getName() + " unoptimized villager using " + GenericUtil.formatEnum(broken.getType()) +
|
||||
LocationUtil.toString(closestOptimizedVillager.villager().getLocation()));
|
||||
}
|
||||
}
|
||||
}
|
@ -2,6 +2,7 @@ package me.xginko.villageroptimizer.modules.optimization;
|
||||
|
||||
import me.xginko.villageroptimizer.VillagerCache;
|
||||
import me.xginko.villageroptimizer.VillagerOptimizer;
|
||||
import me.xginko.villageroptimizer.utils.LocationUtil;
|
||||
import me.xginko.villageroptimizer.wrapper.WrappedVillager;
|
||||
import me.xginko.villageroptimizer.config.Config;
|
||||
import me.xginko.villageroptimizer.enums.OptimizationType;
|
||||
@ -123,7 +124,7 @@ public class OptimizeByNametag implements VillagerOptimizerModule, Listener {
|
||||
|
||||
if (log_enabled) {
|
||||
info(player.getName() + " optimized villager using nametag '" + nameTagPlainText + "' at " +
|
||||
GenericUtil.formatLocation(wVillager.villager().getLocation()));
|
||||
LocationUtil.toString(wVillager.villager().getLocation()));
|
||||
}
|
||||
} else {
|
||||
event.setCancelled(true);
|
||||
@ -156,7 +157,7 @@ public class OptimizeByNametag implements VillagerOptimizerModule, Listener {
|
||||
|
||||
if (log_enabled) {
|
||||
info(player.getName() + " unoptimized villager using nametag '" + nameTagPlainText + "' at " +
|
||||
GenericUtil.formatLocation(wVillager.villager().getLocation()));
|
||||
LocationUtil.toString(wVillager.villager().getLocation()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3,6 +3,7 @@ package me.xginko.villageroptimizer.modules.optimization;
|
||||
import com.tcoded.folialib.impl.ServerImplementation;
|
||||
import me.xginko.villageroptimizer.VillagerCache;
|
||||
import me.xginko.villageroptimizer.VillagerOptimizer;
|
||||
import me.xginko.villageroptimizer.utils.LocationUtil;
|
||||
import me.xginko.villageroptimizer.wrapper.WrappedVillager;
|
||||
import me.xginko.villageroptimizer.config.Config;
|
||||
import me.xginko.villageroptimizer.enums.OptimizationType;
|
||||
@ -108,7 +109,7 @@ public class OptimizeByWorkstation implements VillagerOptimizerModule, Listener
|
||||
if (villager.getProfession() != workstationProfession) continue;
|
||||
WrappedVillager wrapped = villagerCache.getOrAdd(villager);
|
||||
if (wrapped.getJobSite() == null) continue;
|
||||
if (wrapped.getJobSite().distanceSquared(workstationLoc) > 1) continue;
|
||||
if (LocationUtil.relDistanceSquared3D(wrapped.getJobSite(), workstationLoc) > 1) continue;
|
||||
|
||||
if (!wrapped.canOptimize(cooldown_millis) && !player.hasPermission(Permissions.Bypass.WORKSTATION_COOLDOWN.get())) {
|
||||
wrapped.sayNo();
|
||||
@ -139,19 +140,19 @@ public class OptimizeByWorkstation implements VillagerOptimizerModule, Listener
|
||||
if (notify_player) {
|
||||
final TextReplacementConfig vilProfession = TextReplacementConfig.builder()
|
||||
.matchLiteral("%vil_profession%")
|
||||
.replacement(wrapped.villager().getProfession().toString().toLowerCase())
|
||||
.replacement(GenericUtil.formatEnum(wrapped.villager().getProfession()))
|
||||
.build();
|
||||
final TextReplacementConfig placedWorkstation = TextReplacementConfig.builder()
|
||||
.matchLiteral("%blocktype%")
|
||||
.replacement(placed.getType().toString().toLowerCase())
|
||||
.replacement(GenericUtil.formatEnum(placed.getType()))
|
||||
.build();
|
||||
VillagerOptimizer.getLang(player.locale()).workstation_optimize_success
|
||||
.forEach(line -> KyoriUtil.sendMessage(player, line.replaceText(vilProfession).replaceText(placedWorkstation)));
|
||||
}
|
||||
|
||||
if (log_enabled) {
|
||||
info(player.getName() + " optimized villager using workstation " + placed.getType() + " at " +
|
||||
GenericUtil.formatLocation(wrapped.villager().getLocation()));
|
||||
info(player.getName() + " optimized villager using workstation " + GenericUtil.formatEnum(placed.getType()) + " at " +
|
||||
LocationUtil.toString(wrapped.villager().getLocation()));
|
||||
}
|
||||
|
||||
taskComplete.set(true);
|
||||
@ -176,7 +177,7 @@ public class OptimizeByWorkstation implements VillagerOptimizerModule, Listener
|
||||
|
||||
for (Villager villager : workstationLoc.getNearbyEntitiesByType(Villager.class, search_radius)) {
|
||||
if (!villager.getProfession().equals(workstationProfession)) continue;
|
||||
final double distance = villager.getLocation().distanceSquared(workstationLoc);
|
||||
final double distance = LocationUtil.relDistanceSquared3D(villager.getLocation(), workstationLoc);
|
||||
if (distance >= closestDistance) continue;
|
||||
|
||||
WrappedVillager wrapped = villagerCache.getOrAdd(villager);
|
||||
@ -203,19 +204,19 @@ public class OptimizeByWorkstation implements VillagerOptimizerModule, Listener
|
||||
if (notify_player) {
|
||||
final TextReplacementConfig vilProfession = TextReplacementConfig.builder()
|
||||
.matchLiteral("%vil_profession%")
|
||||
.replacement(closestOptimized.villager().getProfession().toString().toLowerCase())
|
||||
.replacement(GenericUtil.formatEnum(closestOptimized.villager().getProfession()))
|
||||
.build();
|
||||
final TextReplacementConfig brokenWorkstation = TextReplacementConfig.builder()
|
||||
.matchLiteral("%blocktype%")
|
||||
.replacement(broken.getType().toString().toLowerCase())
|
||||
.replacement(GenericUtil.formatEnum(broken.getType()))
|
||||
.build();
|
||||
VillagerOptimizer.getLang(player.locale()).workstation_unoptimize_success
|
||||
.forEach(line -> KyoriUtil.sendMessage(player, line.replaceText(vilProfession).replaceText(brokenWorkstation)));
|
||||
}
|
||||
|
||||
if (log_enabled) {
|
||||
info(player.getName() + " unoptimized villager using workstation " + broken.getType() + " at " +
|
||||
GenericUtil.formatLocation(closestOptimized.villager().getLocation()));
|
||||
info(player.getName() + " unoptimized villager using workstation " + GenericUtil.formatEnum(broken.getType()) + " at " +
|
||||
LocationUtil.toString(closestOptimized.villager().getLocation()));
|
||||
}
|
||||
}
|
||||
}
|
@ -3,15 +3,14 @@ package me.xginko.villageroptimizer.utils;
|
||||
import net.kyori.adventure.text.format.Style;
|
||||
import net.kyori.adventure.text.format.TextColor;
|
||||
import net.kyori.adventure.text.format.TextDecoration;
|
||||
import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer;
|
||||
import org.bukkit.Chunk;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.entity.Villager;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.Locale;
|
||||
|
||||
public class GenericUtil {
|
||||
|
||||
@ -34,8 +33,16 @@ public class GenericUtil {
|
||||
}
|
||||
}
|
||||
|
||||
public static @NotNull String formatLocation(@NotNull Location location) {
|
||||
return "[" + location.getWorld().getName() + "] x=" + location.getBlockX() + ", y=" + location.getBlockY() + ", z=" + location.getBlockZ();
|
||||
public static @NotNull String formatEnum(@NotNull Enum<?> input) {
|
||||
// Turn something like "REDSTONE_TORCH" into "redstone torch"
|
||||
String[] lowercaseWords = input.name().toLowerCase(Locale.ROOT).split("-");
|
||||
for (int i = 0; i < lowercaseWords.length; i++) {
|
||||
String word = lowercaseWords[i];
|
||||
// Capitalize first letter for each word
|
||||
lowercaseWords[i] = word.substring(0, 1).toUpperCase() + word.substring(1);
|
||||
}
|
||||
// return as nice string
|
||||
return String.join(" ", lowercaseWords);
|
||||
}
|
||||
|
||||
private static boolean specificChunkLoadedMethodAvailable = true;
|
||||
|
@ -0,0 +1,61 @@
|
||||
package me.xginko.villageroptimizer.utils;
|
||||
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.util.NumberConversions;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class LocationUtil {
|
||||
|
||||
public static @NotNull String toString(@NotNull Location location) {
|
||||
return "[" + location.getWorld().getName() + "] x=" + location.getBlockX() + ", y=" + location.getBlockY() + ", z=" + location.getBlockZ();
|
||||
}
|
||||
|
||||
public static double relDistanceSquared2D(@NotNull Location from, @NotNull Location to) {
|
||||
World.Environment toEnv = to.getWorld().getEnvironment();
|
||||
World.Environment fromEnv = from.getWorld().getEnvironment();
|
||||
double toX = to.getX();
|
||||
double toZ = to.getZ();
|
||||
double fromX = from.getX();
|
||||
double fromZ = from.getZ();
|
||||
|
||||
// Make sure distance is relative since one block in the nether equates to 8 in the overworld/end
|
||||
if (toEnv != fromEnv) {
|
||||
if (fromEnv == World.Environment.NETHER) {
|
||||
fromX *= 8;
|
||||
fromZ *= 8;
|
||||
}
|
||||
if (toEnv == World.Environment.NETHER) {
|
||||
toX *= 8;
|
||||
toZ *= 8;
|
||||
}
|
||||
}
|
||||
|
||||
return NumberConversions.square(toX - fromX) + NumberConversions.square(toZ - fromZ);
|
||||
}
|
||||
|
||||
public static double relDistanceSquared3D(@NotNull Location from, @NotNull Location to) {
|
||||
double toY = to.getY();
|
||||
double fromY = from.getY();
|
||||
|
||||
// Clamp Y levels the same way minecraft would for portal creation logic
|
||||
if (fromY < to.getWorld().getMinHeight())
|
||||
fromY = to.getWorld().getMinHeight();
|
||||
if (fromY > to.getWorld().getMaxHeight())
|
||||
fromY = to.getWorld().getMaxHeight();
|
||||
if (toY < from.getWorld().getMinHeight())
|
||||
toY = from.getWorld().getMinHeight();
|
||||
if (toY > from.getWorld().getMaxHeight())
|
||||
toY = from.getWorld().getMaxHeight();
|
||||
|
||||
return relDistanceSquared2D(from, to) + NumberConversions.square(toY - fromY);
|
||||
}
|
||||
|
||||
public static double relDistance2D(@NotNull Location from, @NotNull Location to) {
|
||||
return Math.sqrt(relDistanceSquared2D(from, to));
|
||||
}
|
||||
|
||||
public static double relDistance3D(@NotNull Location from, @NotNull Location to) {
|
||||
return Math.sqrt(relDistanceSquared3D(from, to));
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user