diff --git a/pom.xml b/pom.xml index c75ffd4..b6eac05 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ com.modnmetl virtualrealty - 2.5.6 + 2.6.0 jar A plot creation and management plugin for Minecraft diff --git a/src/main/java/com/modnmetl/virtualrealty/VirtualRealty.java b/src/main/java/com/modnmetl/virtualrealty/VirtualRealty.java index 8b58d2b..35a4369 100644 --- a/src/main/java/com/modnmetl/virtualrealty/VirtualRealty.java +++ b/src/main/java/com/modnmetl/virtualrealty/VirtualRealty.java @@ -6,6 +6,7 @@ import com.modnmetl.virtualrealty.commands.plot.PlotCommand; import com.modnmetl.virtualrealty.commands.vrplot.VirtualRealtyCommand; import com.modnmetl.virtualrealty.configs.*; +import com.modnmetl.virtualrealty.listener.player.PlayerListener; import com.modnmetl.virtualrealty.model.plot.PlotSize; import com.modnmetl.virtualrealty.model.other.ServerVersion; import com.modnmetl.virtualrealty.exception.MaterialMatchException; @@ -46,6 +47,7 @@ import java.util.jar.JarEntry; import java.util.jar.JarFile; import java.util.logging.Level; +import java.util.stream.Collectors; public final class VirtualRealty extends JavaPlugin { @@ -149,6 +151,7 @@ public void onEnable() { loadDynMapHook(); registerCommands(); loadCommandsConfiguration(); + updateCommandsConfig(); registerListeners(); registerPlaceholders(); debug("Server version: " + this.getServer().getBukkitVersion() + " | " + this.getServer().getVersion()); @@ -190,6 +193,43 @@ public void registerPlaceholders() { debug("Registered new placeholders"); } + private void updateCommandsConfig() { + { + List messages = VirtualRealty.getCommands().plotCommandsHelp.get("plot"); + Set subCommands = VirtualRealty.getCommands().plotAliases.getAliasesMap().keySet(); + List missingSubCommands = subCommands.stream() + .filter(subCommand -> messages + .stream() + .noneMatch(helpMessage -> helpMessage.contains("%" + subCommand + "_command%")) + ).collect(Collectors.toList()); + for (String subCommand : missingSubCommands) { + PlotCommand.HELP_LIST.stream() + .filter(helpMessage -> helpMessage.contains("%" + subCommand + "_command%")) + .forEach(messages::add); + } + if (!missingSubCommands.isEmpty()) { + VirtualRealty.getCommands().save(); + } + } + { + List messages = VirtualRealty.getCommands().vrplotCommandsHelp.get("vrplot"); + Set subCommands = VirtualRealty.getCommands().vrplotAliases.keySet(); + List missingSubCommands = subCommands.stream() + .filter(subCommand -> messages + .stream() + .noneMatch(helpMessage -> helpMessage.contains("%" + subCommand + "_command%")) + ).collect(Collectors.toList()); + for (String subCommand : missingSubCommands) { + VirtualRealtyCommand.HELP_LIST.stream() + .filter(helpMessage -> helpMessage.contains("%" + subCommand + "_command%")) + .forEach(messages::add); + } + if (!missingSubCommands.isEmpty()) { + VirtualRealty.getCommands().save(); + } + } + } + public void checkUpdates() { String[] currentVersionNumbers = this.getDescription().getVersion().split("\\."); String[] updateCheck = UpdateChecker.getUpdate(); @@ -332,6 +372,7 @@ public void registerSubCommands(Class mainCommandClass, String... names) { private void registerListeners() { new BorderProtectionListener(this); + new PlayerListener(this); new PlotProtectionListener(this); new WorldProtectionListener(this); new PlotEntranceListener(this); diff --git a/src/main/java/com/modnmetl/virtualrealty/commands/CommandManager.java b/src/main/java/com/modnmetl/virtualrealty/commands/CommandManager.java index 1725bc6..8b30a1c 100644 --- a/src/main/java/com/modnmetl/virtualrealty/commands/CommandManager.java +++ b/src/main/java/com/modnmetl/virtualrealty/commands/CommandManager.java @@ -409,6 +409,19 @@ public List onTabComplete(@NotNull CommandSender sender, @NotNull Comman } break; } + case "LEAVE": { + if (args.length == 2) { + String trim = finalArgs[1].trim(); + PlotManager.getInstance().getMembershipPlots(player.getUniqueId()).forEach((integer, plot) -> { + if (trim.isEmpty()) { + tabCompleter.add(String.valueOf(plot.getID())); + } else if (String.valueOf(plot.getID()).toLowerCase().startsWith(trim.toLowerCase())) { + tabCompleter.add(String.valueOf(plot.getID())); + } + }); + } + return tabCompleter; + } case "KICK": { if (args.length == 2) { PlotManager.getInstance().getAccessPlots(player.getUniqueId()).forEach((integer, plot) -> { @@ -422,7 +435,13 @@ public List onTabComplete(@NotNull CommandSender sender, @NotNull Comman return tabCompleter; } if (args.length == 3) { - Plot plot = PlotManager.getInstance().getPlot(Integer.parseInt(args[1])); + String arg = args[1]; + try { + Integer.parseInt(arg.trim()); + } catch (NumberFormatException e) { + return tabCompleter; + } + Plot plot = PlotManager.getInstance().getPlot(Integer.parseInt(arg)); if (plot == null) return null; for (OfflinePlayer offlinePlayer : plot.getPlayerMembers()) { if (Objects.equals(offlinePlayer.getName(), player.getName())) continue; diff --git a/src/main/java/com/modnmetl/virtualrealty/commands/SubCommand.java b/src/main/java/com/modnmetl/virtualrealty/commands/SubCommand.java index 1b55ab9..cda598e 100644 --- a/src/main/java/com/modnmetl/virtualrealty/commands/SubCommand.java +++ b/src/main/java/com/modnmetl/virtualrealty/commands/SubCommand.java @@ -1,7 +1,6 @@ package com.modnmetl.virtualrealty.commands; import com.modnmetl.virtualrealty.VirtualRealty; -import com.modnmetl.virtualrealty.commands.vrplot.VirtualRealtyCommand; import com.modnmetl.virtualrealty.model.other.CommandType; import com.modnmetl.virtualrealty.exception.FailedCommandException; import com.modnmetl.virtualrealty.exception.InsufficientPermissionsException; @@ -11,12 +10,12 @@ import lombok.Setter; import lombok.SneakyThrows; import org.bukkit.command.Command; -import org.bukkit.command.CommandExecutor; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; import java.lang.reflect.Method; import java.util.LinkedList; +import java.util.List; import java.util.Map; import java.util.Optional; @@ -27,7 +26,7 @@ public abstract class SubCommand { private final String[] args; private final CommandSender commandSender; @Getter - public LinkedList HELP_LIST; + public LinkedList helpMessages; private final boolean bypass; @Getter @Setter @@ -37,15 +36,15 @@ public abstract class SubCommand { public SubCommand() { this.args = null; this.commandSender = null; - this.HELP_LIST = null; + this.helpMessages = null; this.bypass = false; this.alias = null; } @SneakyThrows - public SubCommand(CommandSender sender, Command command, String label, String[] args, boolean bypass, LinkedList HELP_LIST) throws FailedCommandException { + public SubCommand(CommandSender sender, Command command, String label, String[] args, boolean bypass, LinkedList helpMessages) throws FailedCommandException { this.args = args; - this.HELP_LIST = HELP_LIST; + this.helpMessages = helpMessages; this.commandSender = sender; this.bypass = bypass; this.alias = null; @@ -53,9 +52,9 @@ public SubCommand(CommandSender sender, Command command, String label, String[] } @SneakyThrows - public SubCommand(CommandSender sender, Command command, String label, String[] args, LinkedList HELP_LIST) throws FailedCommandException { + public SubCommand(CommandSender sender, Command command, String label, String[] args, LinkedList helpMessages) throws FailedCommandException { this.args = args; - this.HELP_LIST = HELP_LIST; + this.helpMessages = helpMessages; this.commandSender = sender; this.bypass = false; this.alias = null; @@ -140,7 +139,13 @@ public void printHelp(CommandType commandType) throws FailedCommandException { } String subCommandName = getSubCommandName(); String keyByValue = MapUtils.getKeyByValue(commandsAliases, subCommandName); - for (String s : commandsHelp.get(keyByValue)) { + List subCommandHelpMessages = commandsHelp.get(keyByValue); + if (subCommandHelpMessages == null) { + commandsHelp.put(subCommandName, getHelpMessages()); + subCommandHelpMessages = getHelpMessages(); + VirtualRealty.getCommands().save(); + } + for (String s : subCommandHelpMessages) { String message = s.replaceAll("%command%", subCommandName); ChatMessage.of(message).send(commandSender); } diff --git a/src/main/java/com/modnmetl/virtualrealty/commands/plot/PlotCommand.java b/src/main/java/com/modnmetl/virtualrealty/commands/plot/PlotCommand.java index d3b608d..b26c6d0 100644 --- a/src/main/java/com/modnmetl/virtualrealty/commands/plot/PlotCommand.java +++ b/src/main/java/com/modnmetl/virtualrealty/commands/plot/PlotCommand.java @@ -15,6 +15,7 @@ import java.lang.reflect.InvocationTargetException; import java.util.*; import java.util.logging.Level; +import java.util.stream.Collectors; public class PlotCommand implements CommandExecutor { @@ -28,6 +29,7 @@ public class PlotCommand implements CommandExecutor { HELP_LIST.add(" §a/plot %gm_command% §8- §7Changes gamemode"); HELP_LIST.add(" §a/plot %add_command% §8- §7Adds a member"); HELP_LIST.add(" §a/plot %kick_command% §8- §7Kicks a member"); + HELP_LIST.add(" §a/plot %leave_command% §8- §7Leaves a plot"); HELP_LIST.add(" §a/plot %list_command% §8- §7Shows your plots"); HELP_LIST.add(" §a/plot %tp_command% §8- §7Teleports to the plot"); } @@ -81,7 +83,7 @@ public boolean onCommand(CommandSender sender, Command command, String label, St private static void printHelp(CommandSender sender) { for (String message : VirtualRealty.getCommands().plotCommandsHelp.get("plot")) { - final String[] finalMessage = { message }; + final String[] finalMessage = {message}; CommandRegistry.PLOT_PLACEHOLDERS.forEach((s, s2) -> { finalMessage[0] = finalMessage[0].replaceAll(s, s2); }); diff --git a/src/main/java/com/modnmetl/virtualrealty/commands/plot/subcommand/LeaveSubCommand.java b/src/main/java/com/modnmetl/virtualrealty/commands/plot/subcommand/LeaveSubCommand.java new file mode 100644 index 0000000..a230d56 --- /dev/null +++ b/src/main/java/com/modnmetl/virtualrealty/commands/plot/subcommand/LeaveSubCommand.java @@ -0,0 +1,70 @@ +package com.modnmetl.virtualrealty.commands.plot.subcommand; + +import com.modnmetl.virtualrealty.VirtualRealty; +import com.modnmetl.virtualrealty.commands.SubCommand; +import com.modnmetl.virtualrealty.exception.FailedCommandException; +import com.modnmetl.virtualrealty.manager.PlotManager; +import com.modnmetl.virtualrealty.model.other.ChatMessage; +import com.modnmetl.virtualrealty.model.other.CommandType; +import com.modnmetl.virtualrealty.model.permission.ManagementPermission; +import com.modnmetl.virtualrealty.model.plot.Plot; +import com.modnmetl.virtualrealty.model.plot.PlotMember; +import org.bukkit.Bukkit; +import org.bukkit.OfflinePlayer; +import org.bukkit.command.Command; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; + +import java.time.LocalDateTime; +import java.util.LinkedList; + +public class LeaveSubCommand extends SubCommand { + + public static LinkedList HELP = new LinkedList<>(); + + static { + HELP.add(" "); + HELP.add(" §8§l«§8§m §8[§aVirtualRealty§8]§m §8§l»"); + HELP.add(" §a/plot %command% §8<§7plot§8>"); + } + + public LeaveSubCommand() {} + + public LeaveSubCommand(CommandSender sender, Command command, String label, String[] args) throws FailedCommandException { + super(sender, command, label, args, HELP); + } + + @Override + public void exec(CommandSender sender, Command command, String label, String[] args) throws FailedCommandException { + assertPlayer(); + Player player = ((Player) sender); + if (args.length < 2) { + printHelp(CommandType.PLOT); + return; + } + int plotID; + try { + plotID = Integer.parseInt(args[1]); + } catch (IllegalArgumentException e) { + ChatMessage.of(VirtualRealty.getMessages().useNaturalNumbersOnly).sendWithPrefix(sender); + return; + } + Plot plot = PlotManager.getInstance().getPlot(plotID); + if (plot == null) { + ChatMessage.of(VirtualRealty.getMessages().noPlotFound).sendWithPrefix(sender); + return; + } + if (!plot.hasMembershipAccess(player.getUniqueId())) { + ChatMessage.of(VirtualRealty.getMessages().notYourPlot).sendWithPrefix(sender); + return; + } + PlotMember plotMember = plot.getMember(player.getUniqueId()); + if (plot.getOwnedBy().equals(player.getUniqueId())) { + ChatMessage.of(VirtualRealty.getMessages().cantLeaveOwnPlot).sendWithPrefix(sender); + return; + } + plot.removeMember(plotMember); + ChatMessage.of(VirtualRealty.getMessages().plotLeave.replaceAll("%plot_id%", String.valueOf(plot.getID()))).sendWithPrefix(sender); + } + +} diff --git a/src/main/java/com/modnmetl/virtualrealty/commands/plot/subcommand/TpSubCommand.java b/src/main/java/com/modnmetl/virtualrealty/commands/plot/subcommand/TpSubCommand.java index 401123a..8a572d2 100644 --- a/src/main/java/com/modnmetl/virtualrealty/commands/plot/subcommand/TpSubCommand.java +++ b/src/main/java/com/modnmetl/virtualrealty/commands/plot/subcommand/TpSubCommand.java @@ -53,10 +53,6 @@ public void exec(CommandSender sender, Command command, String label, String[] a ChatMessage.of(VirtualRealty.getMessages().notYourPlot).sendWithPrefix(sender); return; } - if (plot.isOwnershipExpired()) { - ChatMessage.of(VirtualRealty.getMessages().ownershipExpired).sendWithPrefix(sender); - return; - } plot.teleportPlayer(player); ChatMessage.of(VirtualRealty.getMessages().teleportedToPlot).sendWithPrefix(sender); } diff --git a/src/main/java/com/modnmetl/virtualrealty/configs/CommandsConfiguration.java b/src/main/java/com/modnmetl/virtualrealty/configs/CommandsConfiguration.java index a999411..75ea78f 100644 --- a/src/main/java/com/modnmetl/virtualrealty/configs/CommandsConfiguration.java +++ b/src/main/java/com/modnmetl/virtualrealty/configs/CommandsConfiguration.java @@ -28,7 +28,6 @@ public class CommandsConfiguration extends OkaeriConfig { public Map> vrplotCommandsHelp = getCommandsHelp(CommandType.VRPLOT); - @Names(strategy = NameStrategy.HYPHEN_CASE) public static class PlotAliases extends OkaeriConfig { @@ -37,6 +36,7 @@ public static class PlotAliases extends OkaeriConfig { public String gm = "gm"; public String info = "info"; public String kick = "kick"; + public String leave = "leave"; public String list = "list"; public String tp = "tp"; diff --git a/src/main/java/com/modnmetl/virtualrealty/configs/MessagesConfiguration.java b/src/main/java/com/modnmetl/virtualrealty/configs/MessagesConfiguration.java index 32de2f7..7b4beb5 100644 --- a/src/main/java/com/modnmetl/virtualrealty/configs/MessagesConfiguration.java +++ b/src/main/java/com/modnmetl/virtualrealty/configs/MessagesConfiguration.java @@ -58,6 +58,10 @@ public class MessagesConfiguration extends OkaeriConfig { public String noPlotFound = "§cCouldn't get plot with specified ID!"; public String notYourPlot = "§cIt's not your plot!"; public String ownershipExpired = "§cYour ownership has expired!"; + public String ownershipExpiredJoinMessage = "§cYour %plot_size% plot %plot_id% has expired!"; + public String daysUntilExpirationThresholdMessage = "§6Your %plot_size% plot %plot_id% is due to expire in %days% days and %hours% hours," + + " use another plot claim item of the same size type while standing inside it to extend its lease," + + " or it could be claimed by another player after that time!"; public String teleportedToPlot = "§aYou have been teleported to the plot!"; public String gamemodeFeatureDisabled = "§cGamemode feature is disabled!"; public String gamemodeDisabled = "§cThis gamemode is disabled!"; @@ -84,6 +88,8 @@ public class MessagesConfiguration extends OkaeriConfig { public String standingOnPlot = "§cYou are standing on a plot!"; public String notStandingOnPlot = "§cYou aren't standing on any plot!"; public String playerKick = "§aPlayer §7%player% §ahas been kicked out of your plot!"; + public String plotLeave = "§aYou have left the plot with id %plot_id%!"; + public String cantLeaveOwnPlot = "§6You can't leave your own plot!"; public String playerAdd = "§aPlayer §7%player% §ahas been added to your plot!"; public String gamemodeSwitched = "§aYour gamemode has changed!"; public String gamemodeAlreadySelected = "§cThis gamemode is already selected!"; diff --git a/src/main/java/com/modnmetl/virtualrealty/configs/PluginConfiguration.java b/src/main/java/com/modnmetl/virtualrealty/configs/PluginConfiguration.java index e57facd..da00fa9 100644 --- a/src/main/java/com/modnmetl/virtualrealty/configs/PluginConfiguration.java +++ b/src/main/java/com/modnmetl/virtualrealty/configs/PluginConfiguration.java @@ -55,6 +55,9 @@ public static class License extends OkaeriConfig { @CustomKey("default-plot-gamemode") public String plotGamemode = "SURVIVAL"; + @Comment("The number of days before plot expiration when players should be notified") + public int daysUntilExpirationThreshold = 2; + @Comment("Disable natural spawning of all mobs in plots/areas") public boolean disablePlotMobsSpawn = false; diff --git a/src/main/java/com/modnmetl/virtualrealty/listener/player/PlayerListener.java b/src/main/java/com/modnmetl/virtualrealty/listener/player/PlayerListener.java new file mode 100644 index 0000000..84c1999 --- /dev/null +++ b/src/main/java/com/modnmetl/virtualrealty/listener/player/PlayerListener.java @@ -0,0 +1,51 @@ +package com.modnmetl.virtualrealty.listener.player; + +import com.modnmetl.virtualrealty.VirtualRealty; +import com.modnmetl.virtualrealty.listener.VirtualListener; +import com.modnmetl.virtualrealty.manager.PlotManager; +import com.modnmetl.virtualrealty.model.other.ChatMessage; +import com.modnmetl.virtualrealty.model.plot.Plot; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.player.PlayerJoinEvent; + +import java.time.Duration; +import java.time.LocalDateTime; +import java.time.temporal.ChronoUnit; +import java.util.List; + +public class PlayerListener extends VirtualListener { + + public PlayerListener(VirtualRealty plugin) { + super(plugin); + } + + @EventHandler (priority = EventPriority.MONITOR) + public void onPlayerJoin(PlayerJoinEvent event) { + Player player = event.getPlayer(); + PlotManager plotManager = PlotManager.getInstance(); + List playerPlots = plotManager.getPlayerPlots(player.getUniqueId()); + LocalDateTime now = LocalDateTime.now(); + for (Plot playerPlot : playerPlots) { + LocalDateTime expirationDate = playerPlot.getOwnedUntilDate(); + long daysUntilExpiration = ChronoUnit.DAYS.between(now, expirationDate); + Duration durationUntilExpiration = Duration.between(now, expirationDate); + if (durationUntilExpiration.isNegative()) { + String message = VirtualRealty.getMessages().ownershipExpiredJoinMessage + .replaceAll("%plot_size%", playerPlot.getPlotSize().name().toLowerCase()) + .replaceAll("%plot_id%", String.valueOf(playerPlot.getID())); + ChatMessage.of(message).sendWithPrefix(player); + } else if (daysUntilExpiration <= VirtualRealty.getPluginConfiguration().daysUntilExpirationThreshold) { + long hoursUntilExpiration = durationUntilExpiration.toHours() % 24; + String message = VirtualRealty.getMessages().daysUntilExpirationThresholdMessage + .replaceAll("%plot_size%", playerPlot.getPlotSize().name().toLowerCase()) + .replaceAll("%plot_id%", String.valueOf(playerPlot.getID())) + .replaceAll("%days%", String.valueOf(daysUntilExpiration)) + .replaceAll("%hours%", String.valueOf(hoursUntilExpiration)); + ChatMessage.of(message).sendWithPrefix(player); + } + } + } + +} \ No newline at end of file diff --git a/src/main/java/com/modnmetl/virtualrealty/manager/DynmapManager.java b/src/main/java/com/modnmetl/virtualrealty/manager/DynmapManager.java index 6e8d41d..329f959 100644 --- a/src/main/java/com/modnmetl/virtualrealty/manager/DynmapManager.java +++ b/src/main/java/com/modnmetl/virtualrealty/manager/DynmapManager.java @@ -105,7 +105,7 @@ public static void resetPlotMarker(Plot plot) { if (marker == null) { marker = VirtualRealty.getDynmapManager().markerset.createAreaMarker("virtualrealty.plots." + plot.getID(), plot.getOwnedBy() == null ? String.format(MARKER_STRING, plot.getID()) : String.format(MARKER_OWNED_STRING, plot.getID(), ownedBy, dateTimeFormatter.format(localDateTime)), true, - plot.getCreatedWorldString(), new double[]{plot.getXMin(), plot.getXMax()}, new double[]{plot.getZMin(), plot.getZMax()}, true); + plot.getCreatedWorldRaw(), new double[]{plot.getXMin(), plot.getXMax()}, new double[]{plot.getZMin(), plot.getZMax()}, true); areaMarkers.add(marker); } else { marker.setLabel( diff --git a/src/main/java/com/modnmetl/virtualrealty/manager/PlotManager.java b/src/main/java/com/modnmetl/virtualrealty/manager/PlotManager.java index e42faa5..c9a2d0a 100644 --- a/src/main/java/com/modnmetl/virtualrealty/manager/PlotManager.java +++ b/src/main/java/com/modnmetl/virtualrealty/manager/PlotManager.java @@ -10,6 +10,7 @@ import lombok.Data; import org.bukkit.Location; import org.bukkit.Material; +import org.bukkit.World; import java.sql.Connection; import java.sql.PreparedStatement; @@ -157,7 +158,7 @@ public Plot getPlot(int ID) { public List getPlots(String world) { List newPlots = new LinkedList<>(); for (Plot plot : plots) - if (plot.getCreatedWorldString().equals(world)) newPlots.add(plot); + if (plot.getCreatedWorldRaw().equals(world)) newPlots.add(plot); return newPlots; } @@ -170,10 +171,19 @@ public HashMap getPlots(UUID owner) { return plotHashMap; } + public HashMap getMembershipPlots(UUID player) { + HashMap membershipMap = new HashMap<>(); + for (Plot plot : plots) { + if (plot.getMember(player) != null) + membershipMap.put(plot.getID(), plot); + } + return membershipMap; + } + public HashMap getAccessPlots(UUID player) { HashMap plotHashMap = new HashMap<>(); for (Plot plot : plots) { - if (plot.getMember(player) != null || (plot.getOwnedBy() != null && plot.getPlotOwner().getUniqueId() == player)) + if (plot.getMember(player) != null || (plot.getOwnedBy() != null && plot.getPlotOwner().getUniqueId().equals(player))) plotHashMap.put(plot.getID(), plot); } return plotHashMap; @@ -208,18 +218,6 @@ public boolean isLocationInPlot(Location location, Plot plot) { return region.isIn(newVector, location.getWorld()); } -// public Plot getPlot(Location location) { -// BlockVector3 newVector = BlockVector3.at(location.getBlockX(), location.getBlockY(), location.getBlockZ()); -// for (Plot plot : plots) { -// Cuboid region = new Cuboid(plot.getBottomLeftCorner(), plot.getTopRightCorner(), location.getWorld()); -// if (region.isIn(newVector, plot.getCreatedWorld())) { -// return plot; -// } -// } -// return null; -// } -// - public Plot getPlot(Location location) { BlockVector3 newVector = BlockVector3.at(location.getBlockX(), location.getBlockY(), location.getBlockZ()); for (Plot plot : plots) { @@ -240,7 +238,11 @@ public Plot getPlot(Location location, boolean withBorder) { if (withBorder) { return getBorderedPlot(location); } else { - Cuboid region = new Cuboid(plot.getBottomLeftCorner(), plot.getTopRightCorner(), location.getWorld()); + World world = location.getWorld(); + assert world != null; + Cuboid region = plot.getCuboid(); + if (!region.getWorld().getName().equals(world.getName())) + continue; if (region.isIn(newVector, plot.getCreatedWorld())) return plot; } @@ -251,8 +253,12 @@ public Plot getPlot(Location location, boolean withBorder) { private Plot getBorderedPlot(Location location) { BlockVector3 newVector = BlockVector3.at(location.getBlockX(), location.getBlockY(), location.getBlockZ()); for (Plot plot : plots) { - Cuboid region = new Cuboid(plot.getBorderBottomLeftCorner(), plot.getBorderTopRightCorner(), location.getWorld()); - if (region.isIn(newVector, plot.getCreatedWorld())) + World world = location.getWorld(); + assert world != null; + Cuboid borderedRegion = plot.getBorderedCuboid(); + if (!borderedRegion.getWorld().getName().equals(world.getName())) + continue; + if (borderedRegion.isIn(newVector, plot.getCreatedWorld())) return plot; } return null; diff --git a/src/main/java/com/modnmetl/virtualrealty/model/plot/Plot.java b/src/main/java/com/modnmetl/virtualrealty/model/plot/Plot.java index f6d233d..e5d5864 100644 --- a/src/main/java/com/modnmetl/virtualrealty/model/plot/Plot.java +++ b/src/main/java/com/modnmetl/virtualrealty/model/plot/Plot.java @@ -54,6 +54,9 @@ public final class Plot { private Instant modified; private LocalDateTime createdAt; + private transient Cuboid cachedCuboid; + private transient Cuboid cachedBorderedCuboid; + public Plot(Location location, Material floorMaterial, Material borderMaterial, PlotSize plotSize, int length, int width, int height, boolean natural) { this.ID = PlotManager.getInstance().getPlots().isEmpty() ? 10000 : PlotManager.getInstance().getPlotMaxID() + 1; this.ownedBy = null; @@ -280,14 +283,32 @@ public BlockVector3 getCenter() { } public Cuboid getCuboid() { - return new Cuboid(bottomLeftCorner, topRightCorner, getCreatedWorld()); + if (cachedCuboid == null) { + cachedCuboid = new Cuboid( + bottomLeftCorner, + topRightCorner, + getCreatedWorld() + ); + } + return cachedCuboid; + } + + public Cuboid getBorderedCuboid() { + if (cachedBorderedCuboid == null) { + cachedBorderedCuboid = new Cuboid( + borderBottomLeftCorner, + borderTopRightCorner, + getCreatedWorld() + ); + } + return cachedBorderedCuboid; } public org.bukkit.World getCreatedWorld() { return Bukkit.getWorld(createdWorld); } - public String getCreatedWorldString() { + public String getCreatedWorldRaw() { return createdWorld; } diff --git a/src/main/java/com/modnmetl/virtualrealty/model/region/Cuboid.java b/src/main/java/com/modnmetl/virtualrealty/model/region/Cuboid.java index a923e03..3f6895c 100644 --- a/src/main/java/com/modnmetl/virtualrealty/model/region/Cuboid.java +++ b/src/main/java/com/modnmetl/virtualrealty/model/region/Cuboid.java @@ -17,6 +17,8 @@ public class Cuboid { private final int zMin; private final int zMax; private final World world; + private BlockVector3 centerVector; // Lazy initialization + private List walls; // Lazy initialization public Cuboid(Location point1, Location point2) { this.xMin = Math.min(point1.getBlockX(), point2.getBlockX()); @@ -38,6 +40,21 @@ public Cuboid(BlockVector3 point1, BlockVector3 point2, World world) { this.world = world; } + public List getWalls() { + if (walls == null) { + walls = new ArrayList<>(); + for (int z = zMin; z <= zMax; z++) { + walls.add(BlockVector2.at(xMin, z)); + walls.add(BlockVector2.at(xMax, z)); + } + for (int x = xMin; x < xMax; x++) { + walls.add(BlockVector2.at(x, zMin)); + walls.add(BlockVector2.at(x, zMax)); + } + } + return walls; + } + public List getBlocks() { List blocks = new ArrayList<>(); for (int x = this.xMin; x <= this.xMax; ++x) { @@ -73,8 +90,16 @@ public Location getCenter() { return new Location(this.world, (this.xMax - this.xMin) / 2 + this.xMin + 1, (this.yMax - this.yMin) / 2 + this.yMin, (this.zMax - this.zMin) / 2 + this.zMin + 1); } + // Suggestion 3 - Lazy calculation and cached results public BlockVector3 getCenterVector() { - return BlockVector3.at((this.xMax - this.xMin) / 2 + this.xMin + 1, (this.yMax - this.yMin) / 2 + this.yMin, (this.zMax - this.zMin) / 2 + this.zMin + 1); + if (centerVector == null) { + centerVector = BlockVector3.at( + (xMax - xMin) / 2 + xMin, + (yMax - yMin) / 2 + yMin, + (zMax - zMin) / 2 + zMin + ); + } + return centerVector; } public double getDistance() { @@ -105,9 +130,11 @@ public Location getPoint2() { return new Location(this.world, this.xMax, this.yMax, this.zMax); } - public boolean isIn(BlockVector3 vector3, World world) { - return world == this.world && vector3.getBlockX() >= this.xMin && vector3.getBlockX() <= this.xMax && vector3.getBlockY() >= this.yMin && vector3.getBlockY() <= this.yMax && vector3 - .getBlockZ() >= this.zMin && vector3.getBlockZ() <= this.zMax; + public boolean isIn(BlockVector3 vector3, String world) { + return world.equals(this.world.getName()) + && vector3.getBlockX() >= this.xMin && vector3.getBlockX() <= this.xMax + && vector3.getBlockY() >= this.yMin && vector3.getBlockY() <= this.yMax + && vector3.getBlockZ() >= this.zMin && vector3.getBlockZ() <= this.zMax; } public int getCuboidSize() { @@ -123,8 +150,10 @@ public int getZWidth() { } public boolean isIn(Location loc) { - return loc.getWorld() == this.world && loc.getBlockX() >= this.xMin && loc.getBlockX() <= this.xMax && loc.getBlockY() >= this.yMin && loc.getBlockY() <= this.yMax && loc - .getBlockZ() >= this.zMin && loc.getBlockZ() <= this.zMax; + return loc.getWorld() == this.world + && loc.getBlockX() >= this.xMin && loc.getBlockX() <= this.xMax + && loc.getBlockY() >= this.yMin && loc.getBlockY() <= this.yMax + && loc.getBlockZ() >= this.zMin && loc.getBlockZ() <= this.zMax; } public boolean isIn(BlockVector2 vector2, World world, int spacing) { @@ -136,15 +165,23 @@ public boolean isIn(BlockVector2 vector2, World world) { return this.isIn(vector2, world, 0); } - public boolean isColliding(Cuboid cuboid) { - if (cuboid.getWorld() != world) return false; - List flatRegion1 = new ArrayList<>(this.getFlatRegion()); - List flatRegion2 = new ArrayList<>(cuboid.getFlatRegion()); - for (BlockVector2 vector1 : flatRegion1) { - for (BlockVector2 vector2 : flatRegion2) - if (vector1.getBlockX() == vector2.getBlockX() && vector1.getBlockZ() == vector2.getBlockZ()) return true; - } - return false; + public boolean isColliding(Cuboid other) { + return this.world == other.world && + this.xMax >= other.xMin && this.xMin <= other.xMax && + this.yMax >= other.yMin && this.yMin <= other.yMax && + this.zMax >= other.zMin && this.zMin <= other.zMax; + } + + public boolean isColliding2D(Cuboid other) { + return this.world.equals(other.world) && + this.xMax >= other.xMin && this.xMin <= other.xMax && + this.zMax >= other.zMin && this.zMin <= other.zMax; + } + + public boolean isWithin2D(Cuboid other) { + return this.world.equals(other.world) && + this.xMin >= other.xMin && this.xMax <= other.xMax && + this.zMin >= other.zMin && this.zMax <= other.zMax; } public boolean containsBlock(Block block) { @@ -156,19 +193,6 @@ public boolean containsBlock(Block block) { return false; } - public List getWalls() { - List walls = new ArrayList<>(); - for (int z = zMin; z <= zMax; z++) { - walls.add(BlockVector2.at(xMin, z)); - walls.add(BlockVector2.at(xMax, z)); - } - for (int x = xMin; x < xMax; x++) { - walls.add(BlockVector2.at(x, zMin)); - walls.add(BlockVector2.at(x, zMax)); - } - return walls; - } - public World getWorld() { return world; } diff --git a/src/main/java/com/modnmetl/virtualrealty/util/RegionUtil.java b/src/main/java/com/modnmetl/virtualrealty/util/RegionUtil.java index 696a2e4..bbc280e 100644 --- a/src/main/java/com/modnmetl/virtualrealty/util/RegionUtil.java +++ b/src/main/java/com/modnmetl/virtualrealty/util/RegionUtil.java @@ -46,23 +46,49 @@ public static Cuboid getRegion(Location location, Direction direction, int lengt public static boolean isCollidingWithBedrock(Cuboid cuboid) { for (Block block : cuboid.getBlocks()) { - if (block.getType() == Material.BEDROCK) return true; + if (block.getType() == Material.BEDROCK) + return true; } return false; } public static boolean isCollidingWithAnotherPlot(Cuboid cuboid) { long time = System.currentTimeMillis(); + int spacing = VirtualRealty.getPluginConfiguration().plotSpacing; + + // Adjust the cuboid boundaries to include the spacing + Cuboid expandedCuboid = new Cuboid( + BlockVector3.at(cuboid.getMinimumPoint().getBlockX() - spacing, + cuboid.getMinimumPoint().getBlockY(), + cuboid.getMinimumPoint().getBlockZ() - spacing), + BlockVector3.at(cuboid.getMaximumPoint().getBlockX() + spacing, + cuboid.getMaximumPoint().getBlockY(), + cuboid.getMaximumPoint().getBlockZ() + spacing), + cuboid.getWorld() + ); + for (Plot plot : PlotManager.getInstance().getPlots(cuboid.getWorld().getName())) { - for (BlockVector2 blockVector2 : plot.getCuboid().getFlatRegion()) { - if (cuboid.isIn(blockVector2, cuboid.getWorld(), VirtualRealty.getPluginConfiguration().plotSpacing)) { - VirtualRealty.debug("Collision checked! (Found) " + (System.currentTimeMillis() - time) + " ms | Spacing: " + VirtualRealty.getPluginConfiguration().plotSpacing); - return true; - } + if (expandedCuboid.isColliding2D(plot.getCuboid()) || expandedCuboid.isWithin2D(plot.getCuboid())) { + VirtualRealty.debug("Collision checked! (Found) " + (System.currentTimeMillis() - time) + " ms | Spacing: " + spacing); + return true; } } - VirtualRealty.debug("Collision checked! " + (System.currentTimeMillis() - time) + " ms | Spacing: " + VirtualRealty.getPluginConfiguration().plotSpacing); + VirtualRealty.debug("Collision checked! " + (System.currentTimeMillis() - time) + " ms | Spacing: " + spacing); return false; } +// public static boolean isCollidingWithAnotherPlot(Cuboid cuboid) { +// long time = System.currentTimeMillis(); +// for (Plot plot : PlotManager.getInstance().getPlots(cuboid.getWorld().getName())) { +// for (BlockVector2 blockVector2 : plot.getCuboid().getFlatRegion()) { +// if (cuboid.isIn(blockVector2, cuboid.getWorld(), VirtualRealty.getPluginConfiguration().plotSpacing)) { +// VirtualRealty.debug("Collision checked! (Found) " + (System.currentTimeMillis() - time) + " ms | Spacing: " + VirtualRealty.getPluginConfiguration().plotSpacing); +// return true; +// } +// } +// } +// VirtualRealty.debug("Collision checked! " + (System.currentTimeMillis() - time) + " ms | Spacing: " + VirtualRealty.getPluginConfiguration().plotSpacing); +// return false; +// } + }