diff --git a/pom.xml b/pom.xml index 51dcd497..65ab69e7 100644 --- a/pom.xml +++ b/pom.xml @@ -89,14 +89,14 @@ com.fastasyncworldedit FAWE-Core - 1.17-93 + 1.12 provided com.fastasyncworldedit FAWE-Bukkit - 1.17-93 + 1.12 provided @@ -122,6 +122,14 @@ compile + + + com.github.fierioziy.particlenativeapi + ParticleNativeAPI-plugin + 3.2.0 + provided + + com.github.IPVP-MC diff --git a/src/main/java/com/alpsbte/plotsystem/PlotSystem.java b/src/main/java/com/alpsbte/plotsystem/PlotSystem.java index 56480d96..1e163d90 100644 --- a/src/main/java/com/alpsbte/plotsystem/PlotSystem.java +++ b/src/main/java/com/alpsbte/plotsystem/PlotSystem.java @@ -188,6 +188,7 @@ public void onEnable() { PlotManager.checkPlotsForLastActivity(); PlotManager.syncPlotSchematicFiles(); + PlotManager.startTimer(); try { new PacketListener(); @@ -309,10 +310,25 @@ public static boolean isHolographicDisplaysEnabled() { return plugin.getServer().getPluginManager().isPluginEnabled("HolographicDisplays"); } + /** + * @return True if ParticleNativeAPI is present + */ + public static boolean isParticleNativeAPIEnabled() { + return plugin.getServer().getPluginManager().isPluginEnabled("ParticleNativeAPI"); + } + public static boolean isMultiverseInventoriesEnabled() { return plugin.getServer().getPluginManager().isPluginEnabled("Multiverse-Inventories"); } + /** + * @param worldName Name of the world + * @return Config path for the world + */ + public static String getMultiverseInventoriesConfigPath(String worldName) { + return PlotSystem.DependencyManager.isMultiverseInventoriesEnabled() ? Bukkit.getPluginManager().getPlugin("Multiverse-Inventories").getDataFolder() + "/worlds/" + worldName : ""; + } + /** * @return Multiverse-Core instance */ @@ -334,6 +350,14 @@ public static WorldGuardPlugin getWorldGuard() { return WorldGuardPlugin.inst(); } + /** + * @param worldName Name of the world + * @return Config path for the world + */ + public static String getWorldGuardConfigPath(String worldName) { + return Bukkit.getPluginManager().getPlugin("WorldGuard").getDataFolder() + "/worlds/" + worldName; + } + /** * @return Protocol Lib Instance */ diff --git a/src/main/java/com/alpsbte/plotsystem/commands/CMD_Plots.java b/src/main/java/com/alpsbte/plotsystem/commands/CMD_Plots.java index 4cccfcf1..9d997899 100644 --- a/src/main/java/com/alpsbte/plotsystem/commands/CMD_Plots.java +++ b/src/main/java/com/alpsbte/plotsystem/commands/CMD_Plots.java @@ -53,7 +53,7 @@ public boolean onCommand(CommandSender sender, Command cmd, String s, String[] a player.sendMessage(Utils.getErrorMessageFormat(LangUtil.get(sender, LangPaths.Message.Error.PLAYER_NOT_FOUND))); } } else { - new PlayerPlotsMenu(player, new Builder(player.getUniqueId())); + new PlayerPlotsMenu(player, Builder.byUUID(player.getUniqueId())); } } catch (SQLException ex) { sender.sendMessage(Utils.getErrorMessageFormat(LangUtil.get(sender, LangPaths.Message.Error.ERROR_OCCURRED))); diff --git a/src/main/java/com/alpsbte/plotsystem/commands/CMD_Tpll.java b/src/main/java/com/alpsbte/plotsystem/commands/CMD_Tpll.java index 5bc89ed1..b66b6829 100644 --- a/src/main/java/com/alpsbte/plotsystem/commands/CMD_Tpll.java +++ b/src/main/java/com/alpsbte/plotsystem/commands/CMD_Tpll.java @@ -24,11 +24,13 @@ package com.alpsbte.plotsystem.commands; +import com.alpsbte.plotsystem.core.system.Builder; import com.alpsbte.plotsystem.core.system.plot.Plot; import com.alpsbte.plotsystem.core.system.plot.PlotManager; import com.alpsbte.plotsystem.utils.Utils; import com.alpsbte.plotsystem.utils.conversion.CoordinateConversion; import com.alpsbte.plotsystem.utils.conversion.projection.OutOfProjectionBoundsException; +import com.alpsbte.plotsystem.utils.enums.Status; import com.alpsbte.plotsystem.utils.io.language.LangPaths; import com.alpsbte.plotsystem.utils.io.language.LangUtil; import org.bukkit.Bukkit; @@ -88,7 +90,7 @@ public boolean onCommand(CommandSender sender, Command cmd, String s, String[] a double[] terraCoords = CoordinateConversion.convertFromGeo(lon, lat); // Get plot, that the player is in - Plot plot = PlotManager.getPlotByWorld(playerWorld); + Plot plot = PlotManager.getCurrentPlot(Builder.byUUID(player.getUniqueId()), Status.unfinished, Status.unreviewed); // Convert terra coordinates to plot relative coordinates CompletableFuture plotCoords = PlotManager.convertTerraToPlotXZ(plot, terraCoords); diff --git a/src/main/java/com/alpsbte/plotsystem/commands/plot/CMD_Plot_Abandon.java b/src/main/java/com/alpsbte/plotsystem/commands/plot/CMD_Plot_Abandon.java index 3d4f41c7..46abea9c 100644 --- a/src/main/java/com/alpsbte/plotsystem/commands/plot/CMD_Plot_Abandon.java +++ b/src/main/java/com/alpsbte/plotsystem/commands/plot/CMD_Plot_Abandon.java @@ -26,6 +26,7 @@ import com.alpsbte.plotsystem.commands.BaseCommand; import com.alpsbte.plotsystem.commands.SubCommand; +import com.alpsbte.plotsystem.core.system.Builder; import com.alpsbte.plotsystem.core.system.plot.Plot; import com.alpsbte.plotsystem.core.system.plot.PlotManager; import com.alpsbte.plotsystem.core.system.plot.PlotHandler; @@ -58,7 +59,7 @@ public void onCommand(CommandSender sender, String[] args) { return; } } else if (getPlayer(sender) != null && PlotManager.isPlotWorld(getPlayer(sender).getWorld())) { - plot = PlotManager.getPlotByWorld(getPlayer(sender).getWorld()); + plot = PlotManager.getCurrentPlot(Builder.byUUID(getPlayer(sender).getUniqueId()), Status.unfinished); } else { sendInfo(sender); return; diff --git a/src/main/java/com/alpsbte/plotsystem/commands/plot/CMD_Plot_Feedback.java b/src/main/java/com/alpsbte/plotsystem/commands/plot/CMD_Plot_Feedback.java index 81452313..57adb258 100644 --- a/src/main/java/com/alpsbte/plotsystem/commands/plot/CMD_Plot_Feedback.java +++ b/src/main/java/com/alpsbte/plotsystem/commands/plot/CMD_Plot_Feedback.java @@ -27,9 +27,11 @@ import com.alpsbte.plotsystem.commands.BaseCommand; import com.alpsbte.plotsystem.commands.SubCommand; import com.alpsbte.plotsystem.core.menus.FeedbackMenu; +import com.alpsbte.plotsystem.core.system.Builder; import com.alpsbte.plotsystem.core.system.plot.Plot; import com.alpsbte.plotsystem.core.system.plot.PlotManager; import com.alpsbte.plotsystem.utils.Utils; +import com.alpsbte.plotsystem.utils.enums.Status; import com.alpsbte.plotsystem.utils.io.language.LangPaths; import com.alpsbte.plotsystem.utils.io.language.LangUtil; import org.bukkit.Bukkit; @@ -59,7 +61,7 @@ public void onCommand(CommandSender sender, String[] args) { return; } } else if (PlotManager.isPlotWorld(getPlayer(sender).getWorld())) { - plot = PlotManager.getPlotByWorld(getPlayer(sender).getWorld()); + plot = PlotManager.getCurrentPlot(Builder.byUUID(getPlayer(sender).getUniqueId()), Status.completed); } else { sendInfo(sender); return; diff --git a/src/main/java/com/alpsbte/plotsystem/commands/plot/CMD_Plot_Links.java b/src/main/java/com/alpsbte/plotsystem/commands/plot/CMD_Plot_Links.java index 57b62c75..abe6ba32 100644 --- a/src/main/java/com/alpsbte/plotsystem/commands/plot/CMD_Plot_Links.java +++ b/src/main/java/com/alpsbte/plotsystem/commands/plot/CMD_Plot_Links.java @@ -26,10 +26,12 @@ import com.alpsbte.plotsystem.commands.BaseCommand; import com.alpsbte.plotsystem.commands.SubCommand; +import com.alpsbte.plotsystem.core.system.Builder; import com.alpsbte.plotsystem.core.system.plot.Plot; import com.alpsbte.plotsystem.core.system.plot.PlotHandler; import com.alpsbte.plotsystem.core.system.plot.PlotManager; import com.alpsbte.plotsystem.utils.Utils; +import com.alpsbte.plotsystem.utils.enums.Status; import com.alpsbte.plotsystem.utils.io.language.LangPaths; import com.alpsbte.plotsystem.utils.io.language.LangUtil; import org.bukkit.Bukkit; @@ -57,7 +59,7 @@ public void onCommand(CommandSender sender, String[] args) { sender.sendMessage(Utils.getErrorMessageFormat(LangUtil.get(sender, LangPaths.Message.Error.PLOT_DOES_NOT_EXIST))); } } else if (PlotManager.isPlotWorld(getPlayer(sender).getWorld())) { - PlotHandler.sendLinkMessages(PlotManager.getPlotByWorld(getPlayer(sender).getWorld()), getPlayer(sender)); + PlotHandler.sendLinkMessages(PlotManager.getCurrentPlot(Builder.byUUID(getPlayer(sender).getUniqueId()), Status.unfinished, Status.unreviewed), getPlayer(sender)); } else { sendInfo(sender); } diff --git a/src/main/java/com/alpsbte/plotsystem/commands/plot/CMD_Plot_Members.java b/src/main/java/com/alpsbte/plotsystem/commands/plot/CMD_Plot_Members.java index af9cc140..c7377623 100644 --- a/src/main/java/com/alpsbte/plotsystem/commands/plot/CMD_Plot_Members.java +++ b/src/main/java/com/alpsbte/plotsystem/commands/plot/CMD_Plot_Members.java @@ -2,11 +2,12 @@ import com.alpsbte.plotsystem.commands.BaseCommand; import com.alpsbte.plotsystem.commands.SubCommand; -import com.alpsbte.plotsystem.core.menus.FeedbackMenu; import com.alpsbte.plotsystem.core.menus.PlotMemberMenu; +import com.alpsbte.plotsystem.core.system.Builder; import com.alpsbte.plotsystem.core.system.plot.Plot; import com.alpsbte.plotsystem.core.system.plot.PlotManager; import com.alpsbte.plotsystem.utils.Utils; +import com.alpsbte.plotsystem.utils.enums.Status; import org.bukkit.Bukkit; import org.bukkit.ChatColor; import org.bukkit.command.CommandSender; @@ -37,7 +38,7 @@ public void onCommand(CommandSender sender, String[] args) { } } else if (PlotManager.isPlotWorld(getPlayer(sender).getWorld())) { //plot members - plot = PlotManager.getPlotByWorld(getPlayer(sender).getWorld()); + plot = PlotManager.getCurrentPlot(Builder.byUUID(getPlayer(sender).getUniqueId()), Status.unfinished, Status.unreviewed); } else { sendInfo(sender); return; diff --git a/src/main/java/com/alpsbte/plotsystem/commands/plot/CMD_Plot_Submit.java b/src/main/java/com/alpsbte/plotsystem/commands/plot/CMD_Plot_Submit.java index 088d78d4..fd0c2c36 100644 --- a/src/main/java/com/alpsbte/plotsystem/commands/plot/CMD_Plot_Submit.java +++ b/src/main/java/com/alpsbte/plotsystem/commands/plot/CMD_Plot_Submit.java @@ -26,6 +26,7 @@ import com.alpsbte.plotsystem.commands.BaseCommand; import com.alpsbte.plotsystem.commands.SubCommand; +import com.alpsbte.plotsystem.core.system.Builder; import com.alpsbte.plotsystem.core.system.plot.Plot; import com.alpsbte.plotsystem.core.system.plot.PlotHandler; import com.alpsbte.plotsystem.core.system.plot.PlotManager; @@ -58,7 +59,7 @@ public void onCommand(CommandSender sender, String[] args) { return; } } else if (getPlayer(sender) != null && PlotManager.isPlotWorld(getPlayer(sender).getWorld())) { - plot = PlotManager.getPlotByWorld(getPlayer(sender).getWorld()); + plot = PlotManager.getCurrentPlot(Builder.byUUID(getPlayer(sender).getUniqueId())); } else { sendInfo(sender); return; diff --git a/src/main/java/com/alpsbte/plotsystem/commands/plot/CMD_Plot_Teleport.java b/src/main/java/com/alpsbte/plotsystem/commands/plot/CMD_Plot_Teleport.java index 89fe30dd..b4f93611 100644 --- a/src/main/java/com/alpsbte/plotsystem/commands/plot/CMD_Plot_Teleport.java +++ b/src/main/java/com/alpsbte/plotsystem/commands/plot/CMD_Plot_Teleport.java @@ -59,7 +59,7 @@ public void onCommand(CommandSender sender, String[] args) { plot.getWorld().teleportPlayer(getPlayer(sender)); } else { if (sender.hasPermission("plotsystem.admin") && PlotManager.plotExists(plotID)) { - new DefaultPlotGenerator(new Plot(plotID), new Builder(getPlayer(sender).getUniqueId())); + new DefaultPlotGenerator(new Plot(plotID), Builder.byUUID(getPlayer(sender).getUniqueId())); } else { sender.sendMessage(Utils.getErrorMessageFormat(LangUtil.get(sender, LangPaths.Message.Error.PLOT_DOES_NOT_EXIST))); } diff --git a/src/main/java/com/alpsbte/plotsystem/commands/plot/CMD_Plot_UndoSubmit.java b/src/main/java/com/alpsbte/plotsystem/commands/plot/CMD_Plot_UndoSubmit.java index ec366c1a..fbc4025c 100644 --- a/src/main/java/com/alpsbte/plotsystem/commands/plot/CMD_Plot_UndoSubmit.java +++ b/src/main/java/com/alpsbte/plotsystem/commands/plot/CMD_Plot_UndoSubmit.java @@ -26,6 +26,7 @@ import com.alpsbte.plotsystem.commands.BaseCommand; import com.alpsbte.plotsystem.commands.SubCommand; +import com.alpsbte.plotsystem.core.system.Builder; import com.alpsbte.plotsystem.core.system.plot.Plot; import com.alpsbte.plotsystem.core.system.plot.PlotHandler; import com.alpsbte.plotsystem.core.system.plot.PlotManager; @@ -58,7 +59,7 @@ public void onCommand(CommandSender sender, String[] args) { return; } } else if (getPlayer(sender) != null && PlotManager.isPlotWorld(getPlayer(sender).getWorld())) { - plot = PlotManager.getPlotByWorld(getPlayer(sender).getWorld()); + plot = PlotManager.getCurrentPlot(Builder.byUUID(getPlayer(sender).getUniqueId()), Status.unreviewed); } else { sendInfo(sender); return; diff --git a/src/main/java/com/alpsbte/plotsystem/commands/review/CMD_EditPlot.java b/src/main/java/com/alpsbte/plotsystem/commands/review/CMD_EditPlot.java index da77e87d..28f3926a 100644 --- a/src/main/java/com/alpsbte/plotsystem/commands/review/CMD_EditPlot.java +++ b/src/main/java/com/alpsbte/plotsystem/commands/review/CMD_EditPlot.java @@ -26,7 +26,9 @@ import com.alpsbte.plotsystem.PlotSystem; import com.alpsbte.plotsystem.commands.BaseCommand; +import com.alpsbte.plotsystem.utils.enums.Status; import com.alpsbte.plotsystem.utils.io.config.ConfigPaths; +import com.alpsbte.plotsystem.core.system.Builder; import com.alpsbte.plotsystem.core.system.plot.Plot; import com.alpsbte.plotsystem.core.system.plot.PlotManager; import com.alpsbte.plotsystem.utils.Utils; @@ -56,7 +58,7 @@ public boolean onCommand(CommandSender sender, Command cmd, String s, String[] a return true; } } else if (getPlayer(sender) != null && PlotManager.isPlotWorld(getPlayer(sender).getWorld())) { - plot = PlotManager.getPlotByWorld(getPlayer(sender).getWorld()); + plot = PlotManager.getCurrentPlot(Builder.byUUID(getPlayer(sender).getUniqueId()), Status.unfinished, Status.unreviewed); } else { sendInfo(sender); return true; diff --git a/src/main/java/com/alpsbte/plotsystem/commands/review/CMD_Review.java b/src/main/java/com/alpsbte/plotsystem/commands/review/CMD_Review.java index 403a9690..84d35f82 100644 --- a/src/main/java/com/alpsbte/plotsystem/commands/review/CMD_Review.java +++ b/src/main/java/com/alpsbte/plotsystem/commands/review/CMD_Review.java @@ -27,6 +27,8 @@ import com.alpsbte.plotsystem.commands.BaseCommand; import com.alpsbte.plotsystem.core.menus.ReviewMenu; import com.alpsbte.plotsystem.core.menus.ReviewPlotMenu; +import com.alpsbte.plotsystem.core.system.Builder; +import com.alpsbte.plotsystem.core.system.plot.Plot; import com.alpsbte.plotsystem.core.system.plot.PlotManager; import com.alpsbte.plotsystem.utils.Utils; import com.alpsbte.plotsystem.utils.enums.Status; @@ -48,11 +50,10 @@ public boolean onCommand(CommandSender sender, Command cmd, String s, String[] a if (getPlayer(sender) != null) { try { Player player = (Player) sender; - if (PlotManager.isPlotWorld(player.getWorld()) && PlotManager.getPlotByWorld(player.getWorld()).getStatus() == Status.unreviewed) { - new ReviewPlotMenu(player, PlotManager.getPlotByWorld(player.getWorld())); - } else { - new ReviewMenu(player); - } + Plot plot = PlotManager.getCurrentPlot(Builder.byUUID(player.getUniqueId()), Status.unreviewed); + if (plot != null && plot.getStatus() == Status.unreviewed) { + new ReviewPlotMenu(player, plot); + } else new ReviewMenu(player); } catch (SQLException ex) { sender.sendMessage(Utils.getErrorMessageFormat(LangUtil.get(sender, LangPaths.Message.Error.ERROR_OCCURRED))); Bukkit.getLogger().log(Level.SEVERE, "A SQL error occurred!", ex); diff --git a/src/main/java/com/alpsbte/plotsystem/core/EventListener.java b/src/main/java/com/alpsbte/plotsystem/core/EventListener.java index b2ad7ca4..5be28584 100644 --- a/src/main/java/com/alpsbte/plotsystem/core/EventListener.java +++ b/src/main/java/com/alpsbte/plotsystem/core/EventListener.java @@ -25,6 +25,7 @@ package com.alpsbte.plotsystem.core; import com.alpsbte.plotsystem.PlotSystem; +import com.alpsbte.plotsystem.core.system.plot.world.PlotWorld; import com.alpsbte.plotsystem.utils.io.config.ConfigPaths; import com.alpsbte.plotsystem.core.system.plot.PlotManager; import com.alpsbte.plotsystem.core.menus.CompanionMenu; @@ -101,7 +102,7 @@ public void onPlayerJoinEvent(PlayerJoinEvent event) { // Check if player has changed his name try { - Builder builder = new Builder(event.getPlayer().getUniqueId()); + Builder builder = Builder.byUUID(event.getPlayer().getUniqueId()); if (!builder.getName().equals(event.getPlayer().getName())) { DatabaseConnection.createStatement("UPDATE plotsystem_builders SET name = ? WHERE uuid = ?") .setValue(event.getPlayer().getName()).setValue(event.getPlayer().getUniqueId().toString()).executeUpdate(); @@ -112,7 +113,7 @@ public void onPlayerJoinEvent(PlayerJoinEvent event) { // Informing player about new feedback try { - List plots = PlotManager.getPlots(new Builder(event.getPlayer().getUniqueId()), Status.completed, Status.unfinished); + List plots = PlotManager.getPlots(Builder.byUUID(event.getPlayer().getUniqueId()), Status.completed, Status.unfinished); List reviewedPlots = new ArrayList<>(); for(Plot plot : plots) { @@ -132,7 +133,7 @@ public void onPlayerJoinEvent(PlayerJoinEvent event) { // Informing player about unfinished plots try { - List plots = PlotManager.getPlots(new Builder(event.getPlayer().getUniqueId()), Status.unfinished); + List plots = PlotManager.getPlots(Builder.byUUID(event.getPlayer().getUniqueId()), Status.unfinished); if(plots.size() >= 1) { PlotHandler.sendUnfinishedPlotReminderMessage(plots, event.getPlayer()); event.getPlayer().sendMessage(""); @@ -196,36 +197,28 @@ public void onPlayerInteractEvent(PlayerInteractEvent event) { @EventHandler public void onPlayerInteractAtEntity(PlayerInteractAtEntityEvent event) throws SQLException { if (event.getRightClicked().getType().equals(EntityType.PLAYER)) { - event.getPlayer().performCommand("plots " + new Builder(event.getRightClicked().getUniqueId()).getName()); + event.getPlayer().performCommand("plots " + Builder.byUUID(event.getRightClicked().getUniqueId()).getName()); } } @EventHandler public void onPlayerQuitEvent(PlayerQuitEvent event) { final World w = event.getPlayer().getWorld(); + Bukkit.getScheduler().scheduleSyncDelayedTask(PlotSystem.getPlugin(), () -> { if(PlotManager.isPlotWorld(w)) { - try { - PlotManager.getPlotByWorld(w).getWorld().unloadWorld(false); - } catch (SQLException ex) { - Bukkit.getLogger().log(Level.SEVERE, ex.getMessage(), ex); - } - DefaultPlotGenerator.playerPlotGenerationHistory.remove(event.getPlayer().getUniqueId()); + try { PlotWorld.getPlotWorldByName(w.getName()).unloadWorld(false); + } catch (SQLException ex) { Bukkit.getLogger().log(Level.SEVERE, "A SQL error occurred!", ex); } } + DefaultPlotGenerator.playerPlotGenerationHistory.remove(event.getPlayer().getUniqueId()); + PlotManager.clearCache(event.getPlayer().getUniqueId()); }, 60L); } - @EventHandler - public void onPlayerTeleportEvent(PlayerTeleportEvent event) throws SQLException { - if(PlotManager.isPlotWorld(event.getPlayer().getWorld()) && !event.getFrom().getWorld().equals(event.getTo().getWorld())) { - PlotManager.getPlotByWorld(event.getFrom().getWorld()).getWorld().unloadWorld(false); - } - } - @EventHandler public void onPlayerChangedWorldEvent(PlayerChangedWorldEvent event) throws SQLException { if (PlotManager.isPlotWorld(event.getFrom())) { - PlotManager.getPlotByWorld(event.getFrom()).getWorld().unloadWorld(false); + PlotWorld.getPlotWorldByName(event.getFrom().getName()).unloadWorld(false); } if (PlotManager.isPlotWorld(event.getPlayer().getWorld())) { diff --git a/src/main/java/com/alpsbte/plotsystem/core/database/DatabaseConnection.java b/src/main/java/com/alpsbte/plotsystem/core/database/DatabaseConnection.java index af022e22..c6360a2f 100644 --- a/src/main/java/com/alpsbte/plotsystem/core/database/DatabaseConnection.java +++ b/src/main/java/com/alpsbte/plotsystem/core/database/DatabaseConnection.java @@ -263,14 +263,16 @@ public static List getTables() { "(" + " `uuid` varchar(36) NOT NULL ," + " `name` varchar(16) NOT NULL ," + - " `score` int DEFAULt 0 ," + + " `score` int DEFAULT 0 ," + " `completed_plots` int DEFAULT 0 ," + + " `third_slot` int NULL ," + " `first_slot` int NULL ," + " `second_slot` int NULL ," + " `third_slot` int NULL ," + "PRIMARY KEY (`uuid`)" + ");", "ALTER TABLE plotsystem_builders ADD COLUMN IF NOT EXISTS lang varchar(5) NULL;", + "ALTER TABLE plotsystem_builders ADD COLUMN IF NOT EXISTS setting_plot_type int DEFAULT 1;", // Reviews "CREATE TABLE IF NOT EXISTS `plotsystem_reviews`" + @@ -322,8 +324,9 @@ public static List getTables() { "KEY `fkIdx_82` (`difficulty_id`)," + "CONSTRAINT `FK_81` FOREIGN KEY `fkIdx_82` (`difficulty_id`) REFERENCES `plotsystem_difficulties` (`id`)" + ");", - "ALTER TABLE plotsystem_plots ADD COLUMN IF NOT EXISTS outline longtext NOT NULL;" - + "ALTER TABLE plotsystem_plots ADD COLUMN IF NOT EXISTS outline longtext NULL DEFAULT NULL;", + "ALTER TABLE plotsystem_plots ADD COLUMN IF NOT EXISTS type int NOT NULL DEFAULT 1;", + "ALTER TABLE plotsystem_plots ADD COLUMN IF NOT EXISTS version DOUBLE NULL DEFAULT NULL;" ); } } diff --git a/src/main/java/com/alpsbte/plotsystem/core/menus/AbstractMenu.java b/src/main/java/com/alpsbte/plotsystem/core/menus/AbstractMenu.java index b9fba787..b5ee5f3d 100644 --- a/src/main/java/com/alpsbte/plotsystem/core/menus/AbstractMenu.java +++ b/src/main/java/com/alpsbte/plotsystem/core/menus/AbstractMenu.java @@ -33,6 +33,11 @@ public abstract class AbstractMenu { + public static int MAX_CHARS_PER_LINE = 30; + public static char LINE_BAKER = '\n'; + + + private final Menu menu; private final Player menuPlayer; @@ -53,9 +58,9 @@ public AbstractMenu(int rows, String title, Player menuPlayer, boolean reload) { protected abstract void setMenuItemsAsync(); /** - * Sets click events for the items placed in the menu after it is opened + * Sets click events for the items placed in the menu async after it is opened */ - protected abstract void setItemClickEvents(); + protected abstract void setItemClickEventsAsync(); /** * Places pre-defined items in the menu before it is opened @@ -75,13 +80,13 @@ protected void setPreviewItems() { /** * Reloads all menu items and click events in the menu asynchronously - * {@link #setPreviewItems()}.{@link #setMenuItemsAsync()}.{@link #setItemClickEvents()} + * {@link #setPreviewItems()}.{@link #setMenuItemsAsync()}.{@link #setItemClickEventsAsync()} */ protected void reloadMenuAsync() { setPreviewItems(); Bukkit.getScheduler().runTaskAsynchronously(PlotSystem.getPlugin(), () -> { setMenuItemsAsync(); - Bukkit.getScheduler().runTask(PlotSystem.getPlugin(), this::setItemClickEvents); + setItemClickEventsAsync(); }); } diff --git a/src/main/java/com/alpsbte/plotsystem/core/menus/BuilderUtilitiesMenu.java b/src/main/java/com/alpsbte/plotsystem/core/menus/BuilderUtilitiesMenu.java index b7a69e3a..5734e25e 100644 --- a/src/main/java/com/alpsbte/plotsystem/core/menus/BuilderUtilitiesMenu.java +++ b/src/main/java/com/alpsbte/plotsystem/core/menus/BuilderUtilitiesMenu.java @@ -78,7 +78,7 @@ protected void setMenuItemsAsync() { } @Override - protected void setItemClickEvents() { + protected void setItemClickEventsAsync() { // Set click event for custom-heads menu item getMenu().getSlot(10).setClickHandler((clickPlayer, clickInformation) -> clickPlayer.performCommand("hdb")); diff --git a/src/main/java/com/alpsbte/plotsystem/core/menus/CompanionMenu.java b/src/main/java/com/alpsbte/plotsystem/core/menus/CompanionMenu.java index 34e5e4d6..72238018 100644 --- a/src/main/java/com/alpsbte/plotsystem/core/menus/CompanionMenu.java +++ b/src/main/java/com/alpsbte/plotsystem/core/menus/CompanionMenu.java @@ -93,7 +93,7 @@ protected void setPreviewItems() { slots = new Plot[3]; for (int i = 0; i < 3; i++) { try { - Builder builder = new Builder(getMenuPlayer().getUniqueId()); + Builder builder = Builder.byUUID(getMenuPlayer().getUniqueId()); slots[i] = builder.getPlot(Slot.values()[i]); if (slots[i] != null) { @@ -141,7 +141,7 @@ protected void setMenuItemsAsync() { } @Override - protected void setItemClickEvents() { + protected void setItemClickEventsAsync() { // Set click event for navigator item getMenu().getSlot(4).setClickHandler((clickPlayer, clickInformation) -> { clickPlayer.closeInventory(); @@ -171,7 +171,7 @@ protected void setItemClickEvents() { if (!getMenu().getSlot(9 + itemSlot).getItem(clickPlayer).equals(MenuItems.errorItem(getMenuPlayer()))) { try { clickPlayer.closeInventory(); - Builder builder = new Builder(clickPlayer.getUniqueId()); + Builder builder = Builder.byUUID(clickPlayer.getUniqueId()); int cityID = cityProjects.get(itemSlot).getID(); PlotDifficulty plotDifficultyForCity = selectedPlotDifficulty != null ? selectedPlotDifficulty : PlotManager.getPlotDifficultyForBuilder(cityID, builder).get(); @@ -257,7 +257,7 @@ private void setCityProjectItems() throws SQLException { ItemStack cpItem = cp.getCountry().getHead(); try { PlotDifficulty cpPlotDifficulty = selectedPlotDifficulty != null ? - selectedPlotDifficulty : PlotManager.getPlotDifficultyForBuilder(cp.getID(), new Builder(getMenuPlayer().getUniqueId())).get(); + selectedPlotDifficulty : PlotManager.getPlotDifficultyForBuilder(cp.getID(), Builder.byUUID(getMenuPlayer().getUniqueId())).get(); int plotsOpen = PlotManager.getPlots(cp.getID(), Status.unclaimed).size(); int plotsInProgress = PlotManager.getPlots(cp.getID(), Status.unfinished, Status.unreviewed).size(); @@ -326,7 +326,7 @@ private ItemStack getSelectedDifficultyItem() { public static ItemStack getMenuItem(Player player) { return new ItemBuilder(Material.NETHER_STAR, 1) .setName("§b§l" + LangUtil.get(player, LangPaths.MenuTitle.COMPANION) + " §7(" + LangUtil.get(player, LangPaths.Note.Action.RIGHT_CLICK) + ")") - .setEnchantment(true) + .setEnchanted(true) .build(); } } \ No newline at end of file diff --git a/src/main/java/com/alpsbte/plotsystem/core/menus/FeedbackMenu.java b/src/main/java/com/alpsbte/plotsystem/core/menus/FeedbackMenu.java index 15b258f8..59bc3a87 100644 --- a/src/main/java/com/alpsbte/plotsystem/core/menus/FeedbackMenu.java +++ b/src/main/java/com/alpsbte/plotsystem/core/menus/FeedbackMenu.java @@ -122,7 +122,7 @@ protected void setMenuItemsAsync() { } @Override - protected void setItemClickEvents() {} + protected void setItemClickEventsAsync() {} @Override protected Mask getMask() { diff --git a/src/main/java/com/alpsbte/plotsystem/core/menus/PlayerPlotsMenu.java b/src/main/java/com/alpsbte/plotsystem/core/menus/PlayerPlotsMenu.java index ab6e42e4..030d999e 100644 --- a/src/main/java/com/alpsbte/plotsystem/core/menus/PlayerPlotsMenu.java +++ b/src/main/java/com/alpsbte/plotsystem/core/menus/PlayerPlotsMenu.java @@ -116,7 +116,7 @@ protected void setMenuItemsAsync() { } @Override - protected void setItemClickEvents() { + protected void setItemClickEventsAsync() { // Add click event for player plot items for(int i = 0; i < plotDisplayCount; i++) { int itemSlot = i; diff --git a/src/main/java/com/alpsbte/plotsystem/core/menus/PlotActionsMenu.java b/src/main/java/com/alpsbte/plotsystem/core/menus/PlotActionsMenu.java index 8e7c036f..714d05f8 100644 --- a/src/main/java/com/alpsbte/plotsystem/core/menus/PlotActionsMenu.java +++ b/src/main/java/com/alpsbte/plotsystem/core/menus/PlotActionsMenu.java @@ -138,7 +138,7 @@ protected void setMenuItemsAsync() { } @Override - protected void setItemClickEvents() { + protected void setItemClickEventsAsync() { // Set click event for submit or undo submit plot item getMenu().getSlot(10).setClickHandler((clickPlayer, clickInformation) -> { clickPlayer.closeInventory(); @@ -180,7 +180,7 @@ protected void setItemClickEvents() { new PlotMemberMenu(plot,clickPlayer); } else if (plot.getPlotMembers().stream().anyMatch(m -> m.getUUID().equals(getMenuPlayer().getUniqueId()))) { // Leave Plot - plot.removePlotMember(new Builder(clickPlayer.getUniqueId())); + plot.removePlotMember(Builder.byUUID(clickPlayer.getUniqueId())); clickPlayer.sendMessage(Utils.getInfoMessageFormat(LangUtil.get(getMenuPlayer(), LangPaths.Message.Info.LEFT_PLOT, Integer.toString(plot.getID())))); clickPlayer.closeInventory(); } diff --git a/src/main/java/com/alpsbte/plotsystem/core/menus/PlotMemberMenu.java b/src/main/java/com/alpsbte/plotsystem/core/menus/PlotMemberMenu.java index e0a31d97..668220aa 100644 --- a/src/main/java/com/alpsbte/plotsystem/core/menus/PlotMemberMenu.java +++ b/src/main/java/com/alpsbte/plotsystem/core/menus/PlotMemberMenu.java @@ -107,7 +107,7 @@ protected void setMenuItemsAsync() { } @Override - protected void setItemClickEvents() { + protected void setItemClickEventsAsync() { // Set click event for member slots for (int i = 12; i < 15; i++) { int itemSlot = i; diff --git a/src/main/java/com/alpsbte/plotsystem/core/menus/ReviewMenu.java b/src/main/java/com/alpsbte/plotsystem/core/menus/ReviewMenu.java index d546f4f8..6c7d91d4 100644 --- a/src/main/java/com/alpsbte/plotsystem/core/menus/ReviewMenu.java +++ b/src/main/java/com/alpsbte/plotsystem/core/menus/ReviewMenu.java @@ -136,7 +136,7 @@ protected void setMenuItemsAsync() { } @Override - protected void setItemClickEvents() { + protected void setItemClickEventsAsync() { // Set click event for previous page item getMenu().getSlot(46).setClickHandler((clickPlayer, clickInformation) -> { if (hasPreviousPage()) { @@ -176,7 +176,7 @@ protected Mask getMask() { public static ItemStack getMenuItem(Player player) { return new ItemBuilder(Material.BOOK, 1) .setName("§b§l" + LangUtil.get(player, LangPaths.MenuTitle.REVIEW_PLOTS) + " §7(" + LangUtil.get(player, LangPaths.Note.Action.RIGHT_CLICK) + ")") - .setEnchantment(true) + .setEnchanted(true) .build(); } } diff --git a/src/main/java/com/alpsbte/plotsystem/core/menus/ReviewPlotMenu.java b/src/main/java/com/alpsbte/plotsystem/core/menus/ReviewPlotMenu.java index d51110c7..436e4dbd 100644 --- a/src/main/java/com/alpsbte/plotsystem/core/menus/ReviewPlotMenu.java +++ b/src/main/java/com/alpsbte/plotsystem/core/menus/ReviewPlotMenu.java @@ -213,7 +213,7 @@ protected void setMenuItemsAsync() { } @Override - protected void setItemClickEvents() { + protected void setItemClickEventsAsync() { // Set click event for close item getMenu().getSlot(50).setClickHandler((clickPlayer, clickInformation) -> clickPlayer.closeInventory()); @@ -356,7 +356,13 @@ protected void setItemClickEvents() { } // Delete plot world after reviewing - if (!finalIsRejected) plot.getWorld().deleteWorld(); + try { + if (!finalIsRejected && plot.getPlotType().hasOnePlotPerWorld()) + plot.getWorld().deleteWorld(); + } catch (SQLException ex) { + Bukkit.getLogger().log(Level.SEVERE, "A SQL error occurred!", ex); + } + clickPlayer.sendMessage(reviewerConfirmationMessage); clickPlayer.playSound(clickPlayer.getLocation(), Utils.FinishPlotSound, 1f, 1f); diff --git a/src/main/java/com/alpsbte/plotsystem/core/menus/SelectLanguageMenu.java b/src/main/java/com/alpsbte/plotsystem/core/menus/SelectLanguageMenu.java index c305ade6..8e55cac3 100644 --- a/src/main/java/com/alpsbte/plotsystem/core/menus/SelectLanguageMenu.java +++ b/src/main/java/com/alpsbte/plotsystem/core/menus/SelectLanguageMenu.java @@ -29,7 +29,7 @@ public SelectLanguageMenu(Player player) { protected void setPreviewItems() { super.setPreviewItems(); - builder = new Builder(getMenuPlayer().getUniqueId()); + builder = Builder.byUUID(getMenuPlayer().getUniqueId()); isAutoDetectEnabled = builder.getLanguageTag() == null; } @@ -60,13 +60,13 @@ protected void setMenuItemsAsync() { } @Override - protected void setItemClickEvents() { + protected void setItemClickEventsAsync() { // Set click event for language items for (int i = 0; i < LangUtil.languages.length; i++) { LangUtil.LanguageFile langFile = LangUtil.languages[i]; getMenu().getSlot(i).setClickHandler((clickPlayer, clickInformation) -> { try { - Builder builder = new Builder(getMenuPlayer().getUniqueId()); + Builder builder = Builder.byUUID(getMenuPlayer().getUniqueId()); builder.setLanguageTag(langFile.getTag()); Utils.updatePlayerInventorySlots(clickPlayer); diff --git a/src/main/java/com/alpsbte/plotsystem/core/menus/SelectPlotTypeMenu.java b/src/main/java/com/alpsbte/plotsystem/core/menus/SelectPlotTypeMenu.java new file mode 100644 index 00000000..a581163e --- /dev/null +++ b/src/main/java/com/alpsbte/plotsystem/core/menus/SelectPlotTypeMenu.java @@ -0,0 +1,107 @@ +package com.alpsbte.plotsystem.core.menus; + +import com.alpsbte.plotsystem.core.system.Builder; +import com.alpsbte.plotsystem.core.system.plot.PlotType; +import com.alpsbte.plotsystem.utils.Utils; +import com.alpsbte.plotsystem.utils.io.language.LangPaths; +import com.alpsbte.plotsystem.utils.io.language.LangUtil; +import com.alpsbte.plotsystem.utils.items.MenuItems; +import com.alpsbte.plotsystem.utils.items.builder.ItemBuilder; +import com.alpsbte.plotsystem.utils.items.builder.LoreBuilder; +import org.bukkit.Material; +import org.bukkit.entity.Player; +import org.ipvp.canvas.mask.BinaryMask; +import org.ipvp.canvas.mask.Mask; + +public class SelectPlotTypeMenu extends AbstractMenu { + private Builder builder; + + public SelectPlotTypeMenu(Player player) { + super(3, LangUtil.get(player, LangPaths.MenuTitle.SELECT_PLOT_TYPE), player); + } + + @Override + protected void setPreviewItems() { + super.setPreviewItems(); + + builder = Builder.byUUID(getMenuPlayer().getUniqueId()); + } + + @Override + protected void setMenuItemsAsync() { + // Set plot type items + getMenu().getSlot(11).setItem( + new ItemBuilder(Utils.CustomHead.FOCUS_MODE.getAsItemStack()) + .setName("§6§l" + LangUtil.get(getMenuPlayer(), LangPaths.MenuTitle.SELECT_FOCUS_MODE)) + .setLore(new LoreBuilder() + .addLines(Utils.createMultilineFromString(LangUtil.get(getMenuPlayer(), LangPaths.MenuDescription.SELECT_FOCUS_MODE), AbstractMenu.MAX_CHARS_PER_LINE, AbstractMenu.LINE_BAKER)) + .build()) + .setEnchanted(builder.getPlotTypeSetting().getId() == PlotType.FOCUS_MODE.getId()) + .build()); + + getMenu().getSlot(13).setItem( + new ItemBuilder(Material.SAPLING, 1, (byte) 5) + .setName("§6§l" + LangUtil.get(getMenuPlayer(), LangPaths.MenuTitle.SELECT_INSPIRATION_MODE)) + .setLore(new LoreBuilder() + .addLines(Utils.createMultilineFromString(LangUtil.get(getMenuPlayer(), LangPaths.MenuDescription.SELECT_INSPIRATION_MODE), AbstractMenu.MAX_CHARS_PER_LINE, AbstractMenu.LINE_BAKER)) + .build()) + .setEnchanted(builder.getPlotTypeSetting().getId() == PlotType.LOCAL_INSPIRATION_MODE.getId()) + .build()); + + getMenu().getSlot(15).setItem( + new ItemBuilder(Utils.CustomHead.CITY_INSPIRATION_MODE.getAsItemStack()) + .setName("§6§l" + LangUtil.get(getMenuPlayer(), LangPaths.MenuTitle.SELECT_CITY_INSPIRATION_MODE)) + .setLore(new LoreBuilder() + .addLines(Utils.createMultilineFromString(LangUtil.get(getMenuPlayer(), LangPaths.MenuDescription.SELECT_CITY_INSPIRATION_MODE), AbstractMenu.MAX_CHARS_PER_LINE, AbstractMenu.LINE_BAKER)) + .build()) + .setEnchanted(builder.getPlotTypeSetting().getId() == PlotType.CITY_INSPIRATION_MODE.getId()) + .build()); + + // Set selected glass pane + int selectedPlotTypeSlot = 13; + if(builder.getPlotTypeSetting() == PlotType.FOCUS_MODE) + selectedPlotTypeSlot = 11; + if(builder.getPlotTypeSetting() == PlotType.CITY_INSPIRATION_MODE) + selectedPlotTypeSlot = 15; + getMenu().getSlot(selectedPlotTypeSlot - 9).setItem(new ItemBuilder(Material.STAINED_GLASS_PANE, 1, (byte) 5).setName(" ").build()); + + + // Set back item + getMenu().getSlot(22).setItem(MenuItems.backMenuItem(getMenuPlayer())); + } + + @Override + protected void setItemClickEventsAsync() { + // Set click event for plot type items + getMenu().getSlot(11).setClickHandler(((clickPlayer, clickInformation) -> { + builder.setPlotTypeSetting(PlotType.FOCUS_MODE); + getMenuPlayer().playSound(getMenuPlayer().getLocation(), Utils.Done, 1f, 1f); + reloadMenuAsync(); + })); + + getMenu().getSlot(13).setClickHandler(((clickPlayer, clickInformation) -> { + builder.setPlotTypeSetting(PlotType.LOCAL_INSPIRATION_MODE); + getMenuPlayer().playSound(getMenuPlayer().getLocation(), Utils.Done, 1f, 1f); + reloadMenuAsync(); + })); + + getMenu().getSlot(15).setClickHandler(((clickPlayer, clickInformation) -> { + builder.setPlotTypeSetting(PlotType.CITY_INSPIRATION_MODE); + getMenuPlayer().playSound(getMenuPlayer().getLocation(), Utils.Done, 1f, 1f); + reloadMenuAsync(); + })); + + // Set click event for back item + getMenu().getSlot(22).setClickHandler((clickPlayer, clickInformation) -> new SettingsMenu(clickPlayer)); + } + + @Override + protected Mask getMask() { + return BinaryMask.builder(getMenu()) + .item(new ItemBuilder(Material.STAINED_GLASS_PANE, 1, (byte) 7).setName(" ").build()) + .pattern("111111111") + .pattern("000000000") + .pattern("111101111") + .build(); + } +} diff --git a/src/main/java/com/alpsbte/plotsystem/core/menus/SettingsMenu.java b/src/main/java/com/alpsbte/plotsystem/core/menus/SettingsMenu.java index 83b0d97d..8b3f4149 100644 --- a/src/main/java/com/alpsbte/plotsystem/core/menus/SettingsMenu.java +++ b/src/main/java/com/alpsbte/plotsystem/core/menus/SettingsMenu.java @@ -19,7 +19,7 @@ public SettingsMenu(Player player) { @Override protected void setMenuItemsAsync() { // Set language item - getMenu().getSlot(10).setItem( + getMenu().getSlot(11).setItem( new ItemBuilder(Utils.CustomHead.GLOBE.getAsItemStack()) .setName("§6§l" + LangUtil.get(getMenuPlayer(), LangPaths.MenuTitle.SELECT_LANGUAGE)) .setLore(new LoreBuilder() @@ -27,18 +27,33 @@ protected void setMenuItemsAsync() { .build()) .build()); + // Set Plot type item + getMenu().getSlot(15).setItem( + new ItemBuilder(Utils.CustomHead.PLOT_TYPE.getAsItemStack()) + .setName("§6§l" + LangUtil.get(getMenuPlayer(), LangPaths.MenuTitle.SELECT_PLOT_TYPE)) + .setLore(new LoreBuilder() + .addLine(LangUtil.get(getMenuPlayer(), LangPaths.MenuDescription.SELECT_PLOT_TYPE)) + .build()) + .build()); + // Set back item getMenu().getSlot(22).setItem(MenuItems.backMenuItem(getMenuPlayer())); } @Override - protected void setItemClickEvents() { + protected void setItemClickEventsAsync() { // Set click event for language item - getMenu().getSlot(10).setClickHandler(((clickPlayer, clickInformation) -> { + getMenu().getSlot(11).setClickHandler(((clickPlayer, clickInformation) -> { getMenuPlayer().closeInventory(); new SelectLanguageMenu(clickPlayer); })); + // Set click event for plot type item + getMenu().getSlot(15).setClickHandler(((clickPlayer, clickInformation) -> { + getMenuPlayer().closeInventory(); + new SelectPlotTypeMenu(clickPlayer); + })); + // Set click event for back item getMenu().getSlot(22).setClickHandler((clickPlayer, clickInformation) -> clickPlayer.performCommand("companion")); } diff --git a/src/main/java/com/alpsbte/plotsystem/core/menus/SpecialBlocksMenu.java b/src/main/java/com/alpsbte/plotsystem/core/menus/SpecialBlocksMenu.java index 736817e9..db87ee7a 100644 --- a/src/main/java/com/alpsbte/plotsystem/core/menus/SpecialBlocksMenu.java +++ b/src/main/java/com/alpsbte/plotsystem/core/menus/SpecialBlocksMenu.java @@ -56,7 +56,7 @@ protected void setMenuItemsAsync() { } @Override - protected void setItemClickEvents() { + protected void setItemClickEventsAsync() { // Set click event for special block items for(int i = 0; i <= 14; i++) { int specialBlockID = i; diff --git a/src/main/java/com/alpsbte/plotsystem/core/system/Builder.java b/src/main/java/com/alpsbte/plotsystem/core/system/Builder.java index acbb667b..b17244a4 100644 --- a/src/main/java/com/alpsbte/plotsystem/core/system/Builder.java +++ b/src/main/java/com/alpsbte/plotsystem/core/system/Builder.java @@ -30,6 +30,7 @@ import com.alpsbte.plotsystem.core.database.DatabaseConnection; import com.alpsbte.plotsystem.core.holograms.PlotsLeaderboard; import com.alpsbte.plotsystem.core.holograms.ScoreLeaderboard; +import com.alpsbte.plotsystem.core.system.plot.PlotType; import com.alpsbte.plotsystem.utils.enums.Slot; import org.bukkit.Bukkit; import org.bukkit.entity.Player; @@ -37,27 +38,42 @@ import java.sql.ResultSet; import java.sql.SQLException; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; import java.util.UUID; import java.util.logging.Level; public class Builder { - private final UUID UUID; + public static HashMap builders = new HashMap<>(); - public Builder(UUID UUID) { - this.UUID = UUID; + private final UUID uuid; + public PlotType plotType; + + private Builder(UUID UUID) { + this.uuid = UUID; } + public static Builder byUUID(UUID uuid){ + if(builders.containsKey(uuid)) + return builders.get(uuid); + + Builder builder = new Builder(uuid); + builders.put(uuid, builder); + + return builders.get(uuid); + } + + public Player getPlayer() { - return Bukkit.getPlayer(UUID); + return Bukkit.getPlayer(uuid); } public java.util.UUID getUUID() { - return UUID; + return uuid; } - public boolean isOnline() { return Bukkit.getPlayer(UUID) != null; } + public boolean isOnline() { return Bukkit.getPlayer(uuid) != null; } public String getName() throws SQLException { try (ResultSet rs = DatabaseConnection.createStatement("SELECT name FROM plotsystem_builders WHERE uuid = ?") @@ -174,7 +190,7 @@ public static Builder getBuilderByName(String name) throws SQLException { if (rs.next()) { String s = rs.getString(1); DatabaseConnection.closeResultSet(rs); - return new Builder(java.util.UUID.fromString(s)); + return Builder.byUUID(UUID.fromString(s)); } DatabaseConnection.closeResultSet(rs); @@ -245,4 +261,44 @@ public void setLanguageTag(String langTag) throws SQLException { .executeUpdate(); } } + + public PlotType getPlotTypeSetting() { + if(plotType != null) + return plotType; + + try (ResultSet rs = DatabaseConnection.createStatement("SELECT setting_plot_type FROM plotsystem_builders WHERE uuid = ?") + .setValue(getUUID().toString()).executeQuery()) { + + if (rs.next()) { + int id = rs.getInt(1); + this.plotType = PlotType.byId(id); + DatabaseConnection.closeResultSet(rs); + + return plotType; + } + DatabaseConnection.closeResultSet(rs); + } catch (SQLException ex) { + Bukkit.getLogger().log(Level.SEVERE,"An error occurred while getting language setting from database", ex); + } + return null; + } + + public void setPlotTypeSetting(PlotType plotType){ + try { + if (plotType == null) { + DatabaseConnection.createStatement("UPDATE plotsystem_builders SET setting_plot_type = DEFAULT(setting_plot_type) WHERE uuid = ?") + .setValue(getUUID().toString()).executeUpdate(); + } else { + DatabaseConnection.createStatement("UPDATE plotsystem_builders SET setting_plot_type = ? WHERE uuid = ?") + .setValue(plotType.getId()).setValue(getUUID().toString()) + .executeUpdate(); + } + }catch (SQLException ex){ + Bukkit.getLogger().log(Level.SEVERE,"An error occurred while getting language setting from database", ex); + } + + this.plotType = plotType; + } + + } diff --git a/src/main/java/com/alpsbte/plotsystem/core/system/Review.java b/src/main/java/com/alpsbte/plotsystem/core/system/Review.java index 37975ee6..0cbaec40 100644 --- a/src/main/java/com/alpsbte/plotsystem/core/system/Review.java +++ b/src/main/java/com/alpsbte/plotsystem/core/system/Review.java @@ -93,7 +93,7 @@ public Builder getReviewer() throws SQLException { if (rs.next()) { String s = rs.getString(1); DatabaseConnection.closeResultSet(rs); - return new Builder(UUID.fromString(s)); + return Builder.byUUID(UUID.fromString(s)); } DatabaseConnection.closeResultSet(rs); diff --git a/src/main/java/com/alpsbte/plotsystem/core/system/plot/IPlot.java b/src/main/java/com/alpsbte/plotsystem/core/system/plot/IPlot.java index d3d2a377..53018acd 100644 --- a/src/main/java/com/alpsbte/plotsystem/core/system/plot/IPlot.java +++ b/src/main/java/com/alpsbte/plotsystem/core/system/plot/IPlot.java @@ -31,13 +31,13 @@ import com.alpsbte.plotsystem.utils.enums.PlotDifficulty; import com.alpsbte.plotsystem.utils.enums.Slot; import com.alpsbte.plotsystem.utils.enums.Status; -import com.sk89q.worldedit.BlockVector; import com.sk89q.worldedit.BlockVector2D; import com.sk89q.worldedit.Vector; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.io.File; +import java.io.IOException; import java.sql.SQLException; import java.util.Date; import java.util.List; @@ -69,8 +69,9 @@ public interface IPlot { /** * @return polygon outline of the plot * @throws SQLException SQL database exception + * @throws IOException IO exception */ - List getOutline() throws SQLException; + List getOutline() throws SQLException, IOException; /** * Sets the given builder to the plot owner @@ -99,14 +100,14 @@ public interface IPlot { Review getReview() throws SQLException; /** - * @return plot world, can be null if it has not yet been generated + * @return plot world, can be one or city plot world */ - PlotWorld getWorld(); + T getWorld() throws SQLException; /** * @return plot permission manager to add or remove build rights */ - PlotPermissions getPermissions(); + PlotPermissions getPermissions() throws SQLException; /** * @return total points given for the plot @@ -177,6 +178,11 @@ public interface IPlot { */ File getOutlinesSchematic(); + /** + * @return schematic file with environment only + */ + File getEnvironmentSchematic(); + /** * @return schematic file of the completed plot */ @@ -186,9 +192,9 @@ public interface IPlot { * Returns geographic coordinates in numeric format * @return WG84 EPSG:4979 coordinates as double array {lon,lat} in degrees * @see com.alpsbte.plotsystem.utils.conversion.CoordinateConversion#convertToGeo(double, double) - * @throws SQLException SQL database exception + * @throws IOException fails to load schematic file */ - String getGeoCoordinates() throws SQLException; + String getGeoCoordinates() throws IOException; /** * Returns in-game Minecraft coordinates on a Terra121 world @@ -196,14 +202,43 @@ public interface IPlot { * @see com.alpsbte.plotsystem.utils.conversion.CoordinateConversion#convertFromGeo(double, double) * @throws SQLException SQL database exception */ + @Deprecated Vector getMinecraftCoordinates() throws SQLException; + /** + * Returns in-game Minecraft coordinates on a Terra121 world + * @return the in-game coordinates (x, z) + * @see com.alpsbte.plotsystem.utils.conversion.CoordinateConversion#convertFromGeo(double, double) + * @throws IOException fails to load schematic file + */ + Vector getCoordinates() throws IOException; + + /** + * Returns the plot type the player has selected when creating the plot + * @return the plot type + * @throws SQLException SQL database exception + */ + PlotType getPlotType() throws SQLException; + + /** + * Sets the plot type the player has selected + * @param type plot type + * @throws SQLException SQL database exception + */ + void setPlotType(PlotType type) throws SQLException; + /** * @param pasted if true, plot has been pasted on the Terra121 server * @throws SQLException SQL database exception */ void setPasted(boolean pasted) throws SQLException; + /** + * @return plot version in which it was created + * @throws SQLException SQL database exception + */ + double getVersion() throws SQLException; + /** * @return if {@link #getReview()} is null, it will return false * @throws SQLException SQL database exception diff --git a/src/main/java/com/alpsbte/plotsystem/core/system/plot/Plot.java b/src/main/java/com/alpsbte/plotsystem/core/system/plot/Plot.java index 70ac3f6c..3cbec94c 100644 --- a/src/main/java/com/alpsbte/plotsystem/core/system/plot/Plot.java +++ b/src/main/java/com/alpsbte/plotsystem/core/system/plot/Plot.java @@ -27,8 +27,11 @@ import com.alpsbte.plotsystem.core.system.CityProject; import com.alpsbte.plotsystem.core.system.Review; import com.alpsbte.plotsystem.core.system.plot.world.PlotWorld; +import com.alpsbte.plotsystem.core.system.plot.world.CityPlotWorld; +import com.alpsbte.plotsystem.core.system.plot.world.OnePlotWorld; +import com.alpsbte.plotsystem.utils.Utils; import com.alpsbte.plotsystem.utils.conversion.CoordinateConversion; -import com.sk89q.worldedit.BlockVector; +import com.boydti.fawe.FaweAPI; import com.sk89q.worldedit.BlockVector2D; import com.sk89q.worldedit.Vector; import com.alpsbte.plotsystem.core.database.DatabaseConnection; @@ -38,10 +41,13 @@ import com.alpsbte.plotsystem.utils.enums.Slot; import com.alpsbte.plotsystem.utils.enums.Status; import com.alpsbte.plotsystem.utils.ftp.FTPManager; +import com.sk89q.worldedit.extent.clipboard.Clipboard; +import com.sk89q.worldedit.regions.CuboidRegion; import org.bukkit.Bukkit; import org.jetbrains.annotations.NotNull; import java.io.File; +import java.io.IOException; import java.net.URISyntaxException; import java.nio.file.Paths; import java.sql.ResultSet; @@ -54,9 +60,18 @@ import java.util.stream.Collectors; public class Plot implements IPlot { + public static final double PLOT_VERSION = 3; private final int ID; - private PlotWorld plotWorld; + private List outline; + private List blockOutline; + private CityProject city; + private Builder plotOwner; + private PlotType plotType; + private double plotVersion = -1; + + private OnePlotWorld onePlotWorld; + private CityPlotWorld cityPlotWorld; private PlotPermissions plotPermissions; public Plot(int ID) throws SQLException { @@ -70,13 +85,20 @@ public int getID() { @Override public CityProject getCity() throws SQLException { + if(this.city != null) + return this.city; + try (ResultSet rs = DatabaseConnection.createStatement("SELECT city_project_id FROM plotsystem_plots WHERE id = ?") .setValue(this.ID).executeQuery()) { if (rs.next()){ int i = rs.getInt(1); DatabaseConnection.closeResultSet(rs); - return new CityProject(i); + CityProject cityProject = new CityProject(i); + + this.city = cityProject; + + return cityProject; } DatabaseConnection.closeResultSet(rs); @@ -101,31 +123,66 @@ public PlotDifficulty getDifficulty() throws SQLException { } @Override - public List getOutline() throws SQLException { + /* return the outline of the plot which contains all corner points of the polygon */ + public List getOutline() throws SQLException, IOException { + if(this.outline != null) + return this.outline; + try (ResultSet rs = DatabaseConnection.createStatement("SELECT outline FROM plotsystem_plots WHERE id = ?") .setValue(this.ID).executeQuery()) { + List locations = new ArrayList<>(); if (rs.next()){ - List locations = new ArrayList<>(); - String[] list = rs.getString(1).split("\\|"); - - for(String s : list) { - String[] locs = s.split(","); - locations.add(new BlockVector2D(Double.parseDouble(locs[0]), Double.parseDouble(locs[1]))); + String listString = rs.getString(1); + if (rs.wasNull() || listString.isEmpty() || getVersion() <= 2) { + CuboidRegion plotRegion = PlotManager.getPlotAsRegion(this); + if (plotRegion != null) locations.addAll(plotRegion.polygonize(4)); + } else { + String[] list = listString.split("\\|"); + + for (String s : list) { + String[] locs = s.split(","); + locations.add(new BlockVector2D(Double.parseDouble(locs[0]), Double.parseDouble(locs[1]))); + } } - - DatabaseConnection.closeResultSet(rs); - return locations; } + this.outline = locations; DatabaseConnection.closeResultSet(rs); + return locations; } + } - return null; + /** return the outline of the polygon with one point per Block*/ + public List getBlockOutline() throws SQLException, IOException { + if(this.blockOutline != null) + return this.blockOutline; + + List points = new ArrayList<>(); + List outline = getOutline(); + + for(int i = 0; i < outline.size() - 1; i++){ + BlockVector2D b1 = outline.get(i); + BlockVector2D b2 = outline.get(i + 1); + int distance = (int) b1.distance(b2); + + points.addAll(Utils.getLineBetweenPoints(b1, b2, distance)); + } + + BlockVector2D first = outline.get(0); + BlockVector2D last = outline.get(outline.size() - 1); + points.addAll(Utils.getLineBetweenPoints(last, first, (int) first.distance(last))); + + blockOutline = points; + + return points; } @Override public Builder getPlotOwner() throws SQLException { + if(plotOwner != null) + return plotOwner; + if(getStatus() != Status.unclaimed) { try (ResultSet rs = DatabaseConnection.createStatement("SELECT owner_uuid FROM plotsystem_plots WHERE id = ?") .setValue(this.ID).executeQuery()) { @@ -133,7 +190,10 @@ public Builder getPlotOwner() throws SQLException { if (rs.next()){ String s = rs.getString(1); DatabaseConnection.closeResultSet(rs); - return new Builder(UUID.fromString(s)); + + plotOwner = Builder.byUUID(UUID.fromString(s)); + + return plotOwner; } DatabaseConnection.closeResultSet(rs); @@ -151,6 +211,8 @@ public void setPlotOwner(String UUID) throws SQLException { DatabaseConnection.createStatement("UPDATE plotsystem_plots SET owner_uuid = ? WHERE id = ?") .setValue(UUID).setValue(this.ID).executeUpdate(); } + + plotOwner = null; } @Override @@ -166,7 +228,7 @@ public List getPlotMembers() throws SQLException { String[] uuidMembers = members.split(","); for (String uuid : uuidMembers) { - builders.add(new Builder(UUID.fromString(uuid))); + builders.add(Builder.byUUID(UUID.fromString(uuid))); } } } @@ -208,10 +270,19 @@ public Review getReview() throws SQLException { return null; } + @SuppressWarnings("unchecked") @Override - public PlotWorld getWorld() { - if (plotWorld == null) plotWorld = new PlotWorld(this); - return plotWorld; + public T getWorld() { + try { + if (getVersion() <= 2 || getPlotType().hasOnePlotPerWorld()) { + if (onePlotWorld == null) onePlotWorld = new OnePlotWorld(this); + return (T) onePlotWorld; + } else { + if (cityPlotWorld == null) cityPlotWorld = new CityPlotWorld(this); + return (T) cityPlotWorld; + } + } catch (SQLException ex) { Bukkit.getLogger().log(Level.SEVERE, "A SQL error occurred!", ex); } + return null; } @Override @@ -333,7 +404,7 @@ public Builder getPlotCreator() throws SQLException { if (rs.next()) { String s = rs.getString(1); DatabaseConnection.closeResultSet(rs); - return new Builder(UUID.fromString(s)); + return Builder.byUUID(UUID.fromString(s)); } DatabaseConnection.closeResultSet(rs); @@ -365,10 +436,19 @@ public Slot getSlot() throws SQLException { @Override public File getOutlinesSchematic() { + return getSchematic(getID() + ""); + } + + @Override + public File getEnvironmentSchematic() { + return getSchematic(getID() + "-env"); + } + + private File getSchematic(String filename){ try { return CompletableFuture.supplyAsync(() -> { try { - File file = Paths.get(PlotManager.getDefaultSchematicPath(), String.valueOf(getCity().getCountry().getServer().getID()), String.valueOf(getCity().getID()), getID() + ".schematic").toFile(); + File file = Paths.get(PlotManager.getDefaultSchematicPath(), String.valueOf(getCity().getCountry().getServer().getID()), String.valueOf(getCity().getID()), filename + ".schematic").toFile(); if(!file.exists()) { if (getCity().getCountry().getServer().getFTPConfiguration() != null) { @@ -397,9 +477,9 @@ public File getFinishedSchematic() { } @Override - public String getGeoCoordinates() throws SQLException { + public String getGeoCoordinates() throws IOException { // Convert MC coordinates to geo coordinates - Vector mcCoordinates = getMinecraftCoordinates(); + Vector mcCoordinates = getCoordinates(); try { return CoordinateConversion.formatGeoCoordinatesNumeric(CoordinateConversion.convertToGeo(mcCoordinates.getX(), mcCoordinates.getZ())); } catch (OutOfProjectionBoundsException ex) { @@ -408,6 +488,7 @@ public String getGeoCoordinates() throws SQLException { return null; } + @Deprecated @Override public Vector getMinecraftCoordinates() throws SQLException { try (ResultSet rs = DatabaseConnection.createStatement("SELECT mc_coordinates FROM plotsystem_plots WHERE id = ?") @@ -425,15 +506,64 @@ public Vector getMinecraftCoordinates() throws SQLException { } } - public String getOSMMapsLink() throws SQLException { + @Override + public Vector getCoordinates() throws IOException { + Clipboard clipboard = FaweAPI.load(getOutlinesSchematic()).getClipboard(); + if (clipboard != null) return clipboard.getOrigin(); + return null; + } + + @Override + public PlotType getPlotType() throws SQLException { + if (plotType != null) return plotType; + + try (ResultSet rs = DatabaseConnection.createStatement("SELECT type FROM plotsystem_plots WHERE id = ?") + .setValue(this.ID).executeQuery()) { + + if (rs.next()) { + int typeId = rs.getInt(1); + DatabaseConnection.closeResultSet(rs); + + plotType = PlotType.byId(typeId); + return plotType; + } + + DatabaseConnection.closeResultSet(rs); + return null; + } + } + + @Override + public void setPlotType(PlotType type) throws SQLException { + DatabaseConnection.createStatement("UPDATE plotsystem_plots SET type = ? WHERE id = ?") + .setValue(type.ordinal()).setValue(this.ID).executeUpdate(); + plotType = type; + } + + public Vector getCenter() { + try { + if (getVersion() >= 3) { + Clipboard clipboard = FaweAPI.load(getOutlinesSchematic()).getClipboard(); + if (clipboard != null) { + Vector clipboardCenter = clipboard.getRegion().getCenter(); + return new Vector(clipboardCenter.getX(), this.getWorld().getPlotHeightCentered(), clipboardCenter.getZ()); + } + } else return new Vector(PlotWorld.PLOT_SIZE / 2d, this.getWorld().getPlotHeightCentered(), PlotWorld.PLOT_SIZE / 2d); + } catch (IOException ex) { + Bukkit.getLogger().log(Level.SEVERE, "Failed to load schematic file to clipboard!", ex); + } + return null; + } + + public String getOSMMapsLink() throws IOException { return "https://www.openstreetmap.org/#map=19/" + getGeoCoordinates().replace(",", "/"); } - public String getGoogleMapsLink() throws SQLException { + public String getGoogleMapsLink() throws IOException { return "https://www.google.com/maps/place/"+ getGeoCoordinates(); } - public String getGoogleEarthLink() throws SQLException { + public String getGoogleEarthLink() throws IOException { return "https://earth.google.com/web/@" + getGeoCoordinates() + ",0a,1000d,20y,-0h,0t,0r"; } @@ -443,6 +573,30 @@ public void setPasted(boolean pasted) throws SQLException { .setValue(pasted).setValue(this.ID).executeUpdate(); } + @Override + public double getVersion() { + if (plotVersion != -1) return plotVersion; + + try (ResultSet rs = DatabaseConnection.createStatement("SELECT version FROM plotsystem_plots WHERE id = ?") + .setValue(this.ID).executeQuery()) { + + if (rs.next()) { + double version = rs.getDouble(1); + if (!rs.wasNull()) { + plotVersion = version; + } else { + plotVersion = 2; // Plot version was implemented since v3, so we assume that the plot is v2. + } + + DatabaseConnection.closeResultSet(rs); + return plotVersion; + } + + DatabaseConnection.closeResultSet(rs); + } catch (SQLException ex) { Bukkit.getLogger().log(Level.SEVERE, "A SQL error occurred!", ex); } + return PLOT_VERSION; + } + public void addPlotMember(Builder member) throws SQLException { List members = getPlotMembers(); if (members.size() < 3 && members.stream().noneMatch(m -> m.getUUID().equals(member.getUUID()))) { diff --git a/src/main/java/com/alpsbte/plotsystem/core/system/plot/PlotHandler.java b/src/main/java/com/alpsbte/plotsystem/core/system/plot/PlotHandler.java index e198a5fd..c5b5749d 100644 --- a/src/main/java/com/alpsbte/plotsystem/core/system/plot/PlotHandler.java +++ b/src/main/java/com/alpsbte/plotsystem/core/system/plot/PlotHandler.java @@ -28,6 +28,9 @@ import com.alpsbte.plotsystem.core.system.Builder; import com.alpsbte.plotsystem.core.database.DatabaseConnection; import com.alpsbte.plotsystem.core.system.Server; +import com.alpsbte.plotsystem.core.system.plot.generator.AbstractPlotGenerator; +import com.alpsbte.plotsystem.core.system.plot.world.CityPlotWorld; +import com.alpsbte.plotsystem.core.system.plot.world.OnePlotWorld; import com.alpsbte.plotsystem.utils.ShortLink; import com.alpsbte.plotsystem.utils.Utils; import com.alpsbte.plotsystem.utils.enums.Status; @@ -35,6 +38,9 @@ import com.alpsbte.plotsystem.utils.io.config.ConfigPaths; import com.alpsbte.plotsystem.utils.io.language.LangPaths; import com.alpsbte.plotsystem.utils.io.language.LangUtil; +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldguard.bukkit.RegionContainer; +import com.sk89q.worldguard.protection.managers.RegionManager; import net.md_5.bungee.api.chat.*; import org.bukkit.*; import org.bukkit.entity.Player; @@ -46,6 +52,7 @@ import java.nio.file.Paths; import java.sql.SQLException; import java.text.DecimalFormat; +import java.util.ArrayList; import java.util.List; import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletionException; @@ -57,7 +64,7 @@ public static void submitPlot(Plot plot) throws SQLException { plot.setStatus(Status.unreviewed); if(plot.getWorld().isWorldLoaded()) { - for(Player player : plot.getWorld().getBukkitWorld().getPlayers()) { + for(Player player : plot.getWorld() instanceof OnePlotWorld ? plot.getWorld().getBukkitWorld().getPlayers() : ((CityPlotWorld) plot.getWorld()).getPlayersOnPlot()) { player.teleport(Utils.getSpawnLocation()); } } @@ -74,52 +81,82 @@ public static void undoSubmit(Plot plot) throws SQLException { plot.setStatus(Status.unfinished); plot.getPermissions().addBuilderPerms(plot.getPlotOwner().getUUID()).save(); + if (plot.getPlotMembers().size() != 0) { + for (Builder builder : plot.getPlotMembers()) { + plot.getPermissions().addBuilderPerms(builder.getUUID()); + } + } } public static boolean abandonPlot(Plot plot) { try { - if (plot.getWorld().isWorldGenerated() && plot.getWorld().loadWorld()) { - for (Player player : plot.getWorld().getBukkitWorld().getPlayers()) { - player.teleport(Utils.getSpawnLocation()); + if (plot.getWorld() instanceof OnePlotWorld) { + if (plot.getWorld().isWorldGenerated()) { + if (plot.getWorld().isWorldLoaded()) { + for(Player player : plot.getWorld().getBukkitWorld().getPlayers()) { + player.teleport(Utils.getSpawnLocation()); + } + } + if (!plot.getWorld().deleteWorld()) Bukkit.getLogger().log(Level.WARNING, "Could not delete plot world " + plot.getWorld().getWorldName() + "!"); } + } else { + RegionContainer regionContainer = PlotSystem.DependencyManager.getWorldGuard().getRegionContainer(); - if (plot.getWorld().deleteWorld()) { - for (Builder builder : plot.getPlotMembers()) { - plot.removePlotMember(builder); + if (plot.getWorld().loadWorld()) { + CityPlotWorld world = plot.getWorld(); + List playersToTeleport = new ArrayList<>(world.getPlayersOnPlot()); + + RegionManager regionManager = regionContainer.get(world.getBukkitWorld()); + if (regionManager != null) { + for (Builder builder : plot.getPlotMembers()) { + plot.removePlotMember(builder); + } + + if (regionManager.hasRegion(world.getRegionName())) regionManager.removeRegion(world.getRegionName()); + if (regionManager.hasRegion(world.getRegionName() + "-1")) regionManager.removeRegion(world.getRegionName() + "-1"); + + AbstractPlotGenerator.pasteSchematic(null, plot.getOutlinesSchematic(), world, true); + } else Bukkit.getLogger().log(Level.WARNING, "Region Manager is null!"); + + playersToTeleport.forEach(p -> p.teleport(Utils.getSpawnLocation())); + if (plot.getWorld().isWorldLoaded()) plot.getWorld().unloadWorld(false); + } + } + } catch (SQLException | IOException | WorldEditException ex) { + Bukkit.getLogger().log(Level.SEVERE, "Failed to abandon plot with the ID " + plot.getID() + "!", ex); + return false; + } + + try { + CompletableFuture.runAsync(() -> { + try { + if (plot.isReviewed()) { + DatabaseConnection.createStatement("UPDATE plotsystem_plots SET review_id = DEFAULT(review_id) WHERE id = ?") + .setValue(plot.getID()).executeUpdate(); + + DatabaseConnection.createStatement("DELETE FROM plotsystem_reviews WHERE id = ?") + .setValue(plot.getReview().getReviewID()).executeUpdate(); } - try { - CompletableFuture.runAsync(() -> { - try { - if (plot.isReviewed()) { - DatabaseConnection.createStatement("UPDATE plotsystem_plots SET review_id = DEFAULT(review_id) WHERE id = ?") - .setValue(plot.getID()).executeUpdate(); - - DatabaseConnection.createStatement("DELETE FROM plotsystem_reviews WHERE id = ?") - .setValue(plot.getReview().getReviewID()).executeUpdate(); - } - - plot.getPlotOwner().removePlot(plot.getSlot()); - plot.setPlotOwner(null); - plot.setLastActivity(true); - plot.setTotalScore(-1); - plot.setStatus(Status.unclaimed); - } catch (SQLException ex) { - Bukkit.getLogger().log(Level.SEVERE, "A SQL error occurred!", ex); - throw new CompletionException(ex); - } - }).join(); - } catch (CompletionException ex) { - return false; + if (plot.getPlotOwner() != null) { + PlotManager.clearCache(plot.getPlotOwner().getUUID()); + plot.getPlotOwner().removePlot(plot.getSlot()); } - return true; + plot.setPlotOwner(null); + plot.setLastActivity(true); + plot.setTotalScore(-1); + plot.setStatus(Status.unclaimed); + plot.setPlotType(PlotType.LOCAL_INSPIRATION_MODE); + } catch (SQLException ex) { + Bukkit.getLogger().log(Level.SEVERE, "A SQL error occurred!", ex); + throw new CompletionException(ex); } - } - } catch (SQLException ex) { - Bukkit.getLogger().log(Level.SEVERE, "A SQL error occurred!", ex); + }).join(); + } catch (CompletionException ex) { + Bukkit.getLogger().log(Level.SEVERE, "Failed to abandon plot with the ID " + plot.getID() + "!", ex); + return false; } - Bukkit.getLogger().log(Level.WARNING, "Failed to abandon plot with the ID " + plot.getID() + "!"); - return false; + return true; } public static boolean deletePlot(Plot plot) throws SQLException { @@ -184,8 +221,6 @@ public static void sendLinkMessages(Plot plot, Player player){ tc[0].setClickEvent(new ClickEvent(ClickEvent.Action.OPEN_URL, plot.getGoogleMapsLink())); tc[1].setClickEvent(new ClickEvent(ClickEvent.Action.OPEN_URL, plot.getGoogleEarthLink())); tc[2].setClickEvent(new ClickEvent(ClickEvent.Action.OPEN_URL, plot.getOSMMapsLink())); - } catch (SQLException ex) { - Bukkit.getLogger().log(Level.SEVERE, "A SQl error occurred!", ex); } catch (IOException ex) { Bukkit.getLogger().log(Level.SEVERE, "An error occurred while creating shortlink!", ex); } @@ -203,7 +238,7 @@ public static void sendLinkMessages(Plot plot, Player player){ DecimalFormat df = new DecimalFormat("##.#####"); df.setRoundingMode(RoundingMode.FLOOR); coords = "§a" + df.format(lat) + "§7, §a" + df.format(lon); - } catch (SQLException ex) { + } catch (IOException ex) { Bukkit.getLogger().log(Level.SEVERE, ex.getMessage(), ex); } diff --git a/src/main/java/com/alpsbte/plotsystem/core/system/plot/PlotManager.java b/src/main/java/com/alpsbte/plotsystem/core/system/plot/PlotManager.java index 824a7ba8..141b1743 100644 --- a/src/main/java/com/alpsbte/plotsystem/core/system/plot/PlotManager.java +++ b/src/main/java/com/alpsbte/plotsystem/core/system/plot/PlotManager.java @@ -24,8 +24,16 @@ package com.alpsbte.plotsystem.core.system.plot; +import com.alpsbte.plotsystem.core.system.plot.world.CityPlotWorld; +import com.alpsbte.plotsystem.core.system.plot.world.PlotWorld; import com.alpsbte.plotsystem.utils.io.config.ConfigPaths; import com.alpsbte.plotsystem.core.system.CityProject; +import com.alpsbte.plotsystem.core.system.plot.world.OnePlotWorld; +import com.boydti.fawe.FaweAPI; +import com.github.fierioziy.particlenativeapi.api.ParticleNativeAPI; +import com.github.fierioziy.particlenativeapi.api.Particles_1_8; +import com.github.fierioziy.particlenativeapi.plugin.ParticleNativePlugin; +import com.sk89q.worldedit.BlockVector2D; import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.Vector; import com.sk89q.worldedit.WorldEditException; @@ -43,9 +51,13 @@ import com.alpsbte.plotsystem.utils.enums.PlotDifficulty; import com.alpsbte.plotsystem.utils.enums.Status; import com.alpsbte.plotsystem.utils.ftp.FTPManager; +import com.sk89q.worldedit.regions.Polygonal2DRegion; import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.Particle; import org.bukkit.World; import org.bukkit.configuration.file.FileConfiguration; +import org.bukkit.entity.Player; import java.io.File; import java.io.FileInputStream; @@ -55,16 +67,80 @@ import java.nio.file.Paths; import java.sql.ResultSet; import java.sql.SQLException; -import java.util.ArrayList; -import java.util.Date; -import java.util.List; -import java.util.Objects; +import java.util.*; import java.util.concurrent.CompletableFuture; import java.util.logging.Level; public class PlotManager { + // TODO: Start -> Move to another class + public static int CACHE_UPDATE_TICKS = 20*60; - public final static int PLOT_SIZE = 150; + public static int time; + + public static HashMap> cachedInProgressPlots = new HashMap<>(); + + private static boolean ParticleAPIEnabled = false; + private static Particles_1_8 particles; + + + + public static void startTimer(){ + if(PlotSystem.DependencyManager.isParticleNativeAPIEnabled()) + loadParticleNativeAPI(); + + Bukkit.getScheduler().scheduleSyncDelayedTask(PlotSystem.getPlugin(), () -> { + if(PlotSystem.DependencyManager.isParticleNativeAPIEnabled()) + loadParticleNativeAPI(); + }, 20*10L); + + + Bukkit.getScheduler().runTaskTimerAsynchronously(PlotSystem.getPlugin(), PlotManager::tick, 0L, 0L); + } + + public static void tick(){ + time++; + + if(time%CACHE_UPDATE_TICKS == 0) + clearCache(); + + + if(time%10 == 0) + showOutlines(); + } + + public static void clearCache(){ + cachedInProgressPlots.clear(); + } + + public static void clearCache(UUID builderUUID) { + cachedInProgressPlots.remove(builderUUID); + } + + public static void loadParticleNativeAPI(){ + ParticleAPIEnabled = PlotSystem.DependencyManager.isParticleNativeAPIEnabled(); + + // get API + ParticleNativeAPI api = ParticleNativePlugin.getAPI(); + + // choose particles lists you want to use + particles = api.getParticles_1_8(); + } + + + + public static List getCachedInProgressPlots(Builder builder){ + if(!cachedInProgressPlots.containsKey(builder.getUUID())) { + try { + cachedInProgressPlots.put(builder.getUUID(), getPlots(builder, Status.unfinished)); + } catch (SQLException ex) { + Bukkit.getLogger().log(Level.SEVERE, "A SQL error occurred!", ex); + return new ArrayList<>(); + } + } + + return cachedInProgressPlots.get(builder.getUUID()); + } + // TODO: End -> Move to another class public static List getPlots() throws SQLException { return listPlots(DatabaseConnection.createStatement("SELECT id FROM plotsystem_plots").executeQuery()); @@ -82,9 +158,23 @@ public static List getPlots(Builder builder) throws SQLException { } public static List getPlots(Builder builder, Status... statuses) throws SQLException { - List plots = listPlots(DatabaseConnection.createStatement(getStatusQuery( "' AND owner_uuid = '" + builder.getUUID(), statuses)).executeQuery()); - //plots.addAll(listPlots(DatabaseConnection.createStatement(getStatusQuery("id", "' AND INSTR(member_uuids, '" + builder.getUUID() + "') > 0", statuses)).executeQuery())); - // TODO: Add support for member plots + List plots = listPlots(DatabaseConnection.createStatement(getStatusQuery("' AND owner_uuid = '" + builder.getUUID(), statuses)).executeQuery()); + plots.addAll(getPlotsAsMember(builder, statuses)); + return plots; + } + + public static List getPlots(Builder builder, int cityID, Status... statuses) throws SQLException { + List plots = listPlots(DatabaseConnection.createStatement(getStatusQuery( "' AND owner_uuid = '" + builder.getUUID() + "' AND city_project_id = '" + cityID, statuses)).executeQuery()); + plots.addAll(getPlotsAsMember(builder, statuses)); + return plots; + } + + // Temporary fix to receive plots of builder as member + private static List getPlotsAsMember(Builder builder, Status... status) throws SQLException { + List plots = new ArrayList<>(); + for (Status stat : status) { + plots.addAll(listPlots(DatabaseConnection.createStatement("SELECT id FROM plotsystem_plots WHERE status = '" + stat.name() + "' AND INSTR(member_uuids, '" + builder.getUUID() + "') > 0 ORDER BY CAST(status AS CHAR)").executeQuery())); + } return plots; } @@ -150,97 +240,108 @@ private static List listPlots(ResultSet rs) throws SQLException { return plots; } - public static boolean savePlotAsSchematic(Plot plot) throws IOException, SQLException, WorldEditException { - // TODO: MOVE CONVERSION TO SEPERATE METHODS - - Vector terraOrigin, schematicOrigin, plotOrigin; - Vector schematicMinPoint, schematicMaxPoint; - Vector plotCenter; - - // Load plot outlines schematic as clipboard - Clipboard outlinesClipboard = ClipboardFormat.SCHEMATIC.getReader(new FileInputStream(plot.getOutlinesSchematic())).read(null); - - // Get player origin coordinates on terra - terraOrigin = plot.getMinecraftCoordinates(); - - - // Get plot center - plotCenter = PlotManager.getPlotCenter(); - - - // Calculate min and max points of schematic - int outlinesClipboardCenterX = (int) Math.floor(outlinesClipboard.getRegion().getWidth() / 2d); - int outlinesClipboardCenterZ = (int) Math.floor(outlinesClipboard.getRegion().getLength() / 2d); - - schematicMinPoint = Vector.toBlockPoint( - plotCenter.getX() - outlinesClipboardCenterX, - PlotManager.getPlotCenter().getY(), - plotCenter.getZ() - outlinesClipboardCenterZ - ); - - schematicMaxPoint = Vector.toBlockPoint( - plotCenter.getX() + outlinesClipboardCenterX, - 256, - plotCenter.getZ() + outlinesClipboardCenterZ - ); - + public static CuboidRegion getPlotAsRegion(Plot plot) throws IOException { + Clipboard clipboard = FaweAPI.load(plot.getOutlinesSchematic()).getClipboard(); + if (clipboard != null) { + if (plot.getVersion() >= 3) { + return new CuboidRegion( + clipboard.getMinimumPoint().setY(plot.getWorld().getPlotHeight()), + clipboard.getMaximumPoint().setY(PlotWorld.MAX_WORLD_HEIGHT)); + } else { + Vector plotCenter = plot.getCenter(); + + // Calculate min and max points of schematic + int regionCenterModX = clipboard.getRegion().getWidth() % 2 == 0 ? 1 : 0; + int regionCenterModZ = clipboard.getRegion().getLength() % 2 == 0 ? 1 : 0; + int outlinesClipboardCenterX = (int) Math.floor(clipboard.getRegion().getWidth() / 2d); + int outlinesClipboardCenterZ = (int) Math.floor(clipboard.getRegion().getLength() / 2d); + + Vector schematicMinPoint = new Vector( + plotCenter.getX() - (outlinesClipboardCenterX - regionCenterModX), + PlotWorld.MIN_WORLD_HEIGHT, + plotCenter.getZ() - (outlinesClipboardCenterZ - regionCenterModZ) + ); + + Vector schematicMaxPoint = new Vector( + plotCenter.getX() + outlinesClipboardCenterX, + PlotWorld.MAX_WORLD_HEIGHT, + plotCenter.getZ() + outlinesClipboardCenterZ + ); + + return new CuboidRegion(schematicMinPoint, schematicMaxPoint); + } + } + return null; + } - // Convert terra schematic coordinates into relative plot schematic coordinates - schematicOrigin = Vector.toBlockPoint( - Math.floor(terraOrigin.getX()) - Math.floor(outlinesClipboard.getMinimumPoint().getX()), - Math.floor(terraOrigin.getY()) - Math.floor(outlinesClipboard.getMinimumPoint().getY()), - Math.floor(terraOrigin.getZ()) - Math.floor(outlinesClipboard.getMinimumPoint().getZ()) - ); + // TODO: MOVE CONVERSION TO SEPARATE METHODS + public static boolean savePlotAsSchematic(Plot plot) throws IOException, SQLException, WorldEditException { + Clipboard clipboard = FaweAPI.load(plot.getOutlinesSchematic()).getClipboard(); + if (clipboard != null) { + CuboidRegion cuboidRegion = getPlotAsRegion(plot); + if (cuboidRegion != null) { + Vector plotCenter = plot.getCenter(); - // Add additional plot sizes to relative plot schematic coordinates - plotOrigin = Vector.toBlockPoint( - schematicOrigin.getX() + schematicMinPoint.getX(), - schematicOrigin.getY() + schematicMinPoint.getY(), - schematicOrigin.getZ() + schematicMinPoint.getZ() - ); + // Get plot outline + List plotOutlines = plot.getOutline(); + // Load finished plot region as cuboid region + if (plot.getWorld().loadWorld()) { + com.sk89q.worldedit.world.World world = new BukkitWorld(plot.getWorld().getBukkitWorld()); + Polygonal2DRegion region = new Polygonal2DRegion(world, plotOutlines, cuboidRegion.getMinimumPoint().getBlockY(), cuboidRegion.getMaximumPoint().getBlockY()); - // Load finished plot region as cuboid region - plot.getWorld().loadWorld(); - CuboidRegion region = new CuboidRegion(new BukkitWorld(plot.getWorld().getBukkitWorld()), schematicMinPoint, schematicMaxPoint); + // Copy and write finished plot clipboard to schematic file + File finishedSchematicFile = plot.getFinishedSchematic(); + if (!finishedSchematicFile.exists()) { + boolean createdDirs = finishedSchematicFile.getParentFile().mkdirs(); + boolean createdFile = finishedSchematicFile.createNewFile(); + if ((!finishedSchematicFile.getParentFile().exists() && !createdDirs) || (!finishedSchematicFile.exists() && !createdFile)) { + return false; + } + } - // Copy finished plot region to clipboard - Clipboard cb = new BlockArrayClipboard(region); - cb.setOrigin(plotOrigin); - EditSession editSession = PlotSystem.DependencyManager.getWorldEdit().getEditSessionFactory().getEditSession(region.getWorld(), -1); - ForwardExtentCopy forwardExtentCopy = new ForwardExtentCopy(editSession, region, cb, region.getMinimumPoint()); - Operations.complete(forwardExtentCopy); + Clipboard cb = new BlockArrayClipboard(region); + if (plot.getVersion() >= 3) { + cb.setOrigin(new Vector(Math.floor(plotCenter.getX()), cuboidRegion.getMinimumY(), Math.floor(plotCenter.getZ()))); + } else { + Vector terraCenter = plot.getMinecraftCoordinates(); + plotCenter = new Vector( + Math.floor(terraCenter.getX()) - Math.floor(clipboard.getMinimumPoint().getX()) + cuboidRegion.getMinimumPoint().getX(), + Math.floor(terraCenter.getY()) - Math.floor(clipboard.getMinimumPoint().getY()) + cuboidRegion.getMinimumPoint().getY(), + Math.floor(terraCenter.getZ()) - Math.floor(clipboard.getMinimumPoint().getZ()) + cuboidRegion.getMinimumPoint().getZ() + ); + cb.setOrigin(plotCenter); + } - // Write finished plot clipboard to schematic file - File finishedSchematicFile = plot.getFinishedSchematic(); + EditSession editSession = PlotSystem.DependencyManager.getWorldEdit().getEditSessionFactory().getEditSession(region.getWorld(), -1); + ForwardExtentCopy forwardExtentCopy = new ForwardExtentCopy(editSession, region, cb, region.getMinimumPoint()); + Operations.complete(forwardExtentCopy); - if (!finishedSchematicFile.exists()) { - boolean createdDirs = finishedSchematicFile.getParentFile().mkdirs(); - boolean createdFile = finishedSchematicFile.createNewFile(); - if ((!finishedSchematicFile.getParentFile().exists() && !createdDirs) || (!finishedSchematicFile.exists() && !createdFile)) { - return false; - } - } + try(ClipboardWriter writer = ClipboardFormat.SCHEMATIC.getWriter(new FileOutputStream(finishedSchematicFile, false))) { + writer.write(cb, Objects.requireNonNull(region.getWorld()).getWorldData()); + } - try(ClipboardWriter writer = ClipboardFormat.SCHEMATIC.getWriter(new FileOutputStream(finishedSchematicFile, false))) { - writer.write(cb, Objects.requireNonNull(region.getWorld()).getWorldData()); - } + // Upload to FTP server + if (plot.getCity().getCountry().getServer().getFTPConfiguration() != null) { + CompletableFuture.supplyAsync(() -> { + try { + return FTPManager.uploadSchematic(FTPManager.getFTPUrl(plot.getCity().getCountry().getServer(), plot.getCity().getID()), finishedSchematicFile); + } catch (SQLException | URISyntaxException ex) { + Bukkit.getLogger().log(Level.SEVERE, "A SQL error occurred!", ex); + } + return null; + }); + } - // Upload to FTP server - if (plot.getCity().getCountry().getServer().getFTPConfiguration() != null) { - CompletableFuture.supplyAsync(() -> { - try { - return FTPManager.uploadSchematic(FTPManager.getFTPUrl(plot.getCity().getCountry().getServer(), plot.getCity().getID()), finishedSchematicFile); - } catch (SQLException | URISyntaxException ex) { - Bukkit.getLogger().log(Level.SEVERE, "A SQL error occurred!", ex); + // If plot was created in a void world, copy the result to the city world + // TODO: Copy finished schematic to city world + return true; } - return null; - }); + } } - - return true; + return false; } public static CompletableFuture convertTerraToPlotXZ(Plot plot, double[] terraCoords) throws IOException { @@ -253,15 +354,15 @@ public static CompletableFuture convertTerraToPlotXZ(Plot plot, double int outlinesClipboardCenterZ = (int) Math.floor(outlinesClipboard.getRegion().getLength() / 2d); Vector schematicMinPoint = Vector.toBlockPoint( - PlotManager.getPlotCenter().getX() - outlinesClipboardCenterX + ((outlinesClipboard.getRegion().getWidth() % 2 == 0 ? 1 : 0)), + plot.getCenter().getX() - outlinesClipboardCenterX + ((outlinesClipboard.getRegion().getWidth() % 2 == 0 ? 1 : 0)), 0, - PlotManager.getPlotCenter().getZ() - outlinesClipboardCenterZ + ((outlinesClipboard.getRegion().getLength() % 2 == 0 ? 1 : 0)) + plot.getCenter().getZ() - outlinesClipboardCenterZ + ((outlinesClipboard.getRegion().getLength() % 2 == 0 ? 1 : 0)) ); Vector schematicMaxPoint = Vector.toBlockPoint( - PlotManager.getPlotCenter().getX() + outlinesClipboardCenterX, + plot.getCenter().getX() + outlinesClipboardCenterX, 256, - PlotManager.getPlotCenter().getZ() + outlinesClipboardCenterZ + plot.getCenter().getZ() + outlinesClipboardCenterZ ); // Convert terra schematic coordinates into relative plot schematic coordinates @@ -326,8 +427,53 @@ public static void syncPlotSchematicFiles() { } } - public static Plot getPlotByWorld(World plotWorld) throws SQLException { - return new Plot(Integer.parseInt(plotWorld.getName().substring(2))); + /** Returns the plot that the player is currently standing on or next to. + * If he is standing in a single plot world it returns the plot of this world. + * If he is standing in a multi plot world it returns the closest plot of all unfinished plots of this city + * + * @param builder + * @return the current plot of the player + * @throws SQLException + */ + public static Plot getCurrentPlot(Builder builder, Status... statuses) throws SQLException { + if (builder.isOnline()) { + String worldName = builder.getPlayer().getWorld().getName(); + + if(PlotWorld.isOnePlotWorld(worldName)) + return new Plot(Integer.parseInt(worldName.substring(2))); + else if (CityPlotWorld.isCityPlotWorld(worldName)) { + int cityID = Integer.parseInt(worldName.substring(2)); + List plots = getPlots(cityID, statuses); + + if(plots.size() == 0) + return getPlots(builder).get(0); + if(plots.size() == 1) + return plots.get(0); + + // Find the plot in the city world that is closest to the player + Location playerLoc = builder.getPlayer().getLocation().clone(); + Vector playerVector = new Vector(playerLoc.getX(), playerLoc.getY(), playerLoc.getZ()); + + double distance = 100000000; + Plot chosenPlot = plots.get(0); + for(Plot plot : plots) + if(plot.getCenter().distance(playerVector) < distance){ + distance = plot.getCenter().distance(playerVector); + chosenPlot = plot; + } + + return chosenPlot; + } + } + return null; + } + + public static boolean isPlayerOnPlot(Plot plot, Player player) { + if (plot.getWorld().isWorldLoaded() && plot.getWorld().getBukkitWorld().getPlayers().contains(player)) { + Location playerLoc = player.getLocation(); + return plot.getWorld().getProtectedRegion().contains(Vector.toBlockPoint(playerLoc.getX(), playerLoc.getY(), playerLoc.getZ())); + } + return false; } public static boolean plotExists(int ID) { @@ -380,26 +526,52 @@ public static CompletableFuture getPlotDifficultyForBuilder(int } public static boolean isPlotWorld(World world) { - return PlotSystem.DependencyManager.getMultiverseCore().getMVWorldManager().isMVWorld(world) && world.getName().startsWith("P-"); + return PlotSystem.DependencyManager.getMultiverseCore().getMVWorldManager().isMVWorld(world) && (OnePlotWorld.isOnePlotWorld(world.getName()) || CityPlotWorld.isCityPlotWorld(world.getName())); } - public static Vector getPlotCenter() { - return Vector.toBlockPoint( - PLOT_SIZE / 2d, - 5, - PLOT_SIZE / 2d - ); - } - public static String getWorldGuardConfigPath(String worldName) { - return Bukkit.getPluginManager().getPlugin("WorldGuard").getDataFolder() + "/worlds/" + worldName; + public static String getDefaultSchematicPath() { + return Paths.get(PlotSystem.getPlugin().getDataFolder().getAbsolutePath(), "schematics") + File.separator; } - public static String getMultiverseInventoriesConfigPath(String worldName) { - return PlotSystem.DependencyManager.isMultiverseInventoriesEnabled() ? Bukkit.getPluginManager().getPlugin("Multiverse-Inventories").getDataFolder() + "/worlds/" + worldName : ""; - } + public static void showOutlines(){ + try { + for (Player player : Bukkit.getOnlinePlayers()) { + Builder builder = Builder.byUUID(player.getUniqueId()); - public static String getDefaultSchematicPath() { - return Paths.get(PlotSystem.getPlugin().getDataFolder().getAbsolutePath(), "schematics") + File.separator; + List plots = getCachedInProgressPlots(builder); + BlockVector2D playerPos2D = new BlockVector2D(player.getLocation().getX(), player.getLocation().getZ()); + + if(plots.size() == 0) + continue; + + for(Plot plot : plots){ + if(!plot.getWorld().getWorldName().equals(player.getWorld().getName())) + continue; + + if(!plot.getPlotOwner().getPlotTypeSetting().hasEnvironment()) + continue; + + List points = plot.getBlockOutline(); + + for(BlockVector2D point : points) + if(point.distanceSq(playerPos2D) < 50*50) + if(!ParticleAPIEnabled) + player.spawnParticle(Particle.FLAME, point.getX(), player.getLocation().getY() + 1, point.getZ(), 1, 0.0 ,0.0,0.0, 0); + else{ + Location loc = new Location(player.getWorld(), point.getX(), player.getLocation().getY() + 1, point.getZ()); + // create a particle packet + Object packet = particles.FLAME().packet(true, loc); + + // send this packet to player + particles.sendPacket(player, packet); + } + } + } + + } catch (SQLException | IOException ex) { + Bukkit.getLogger().log(Level.INFO, "A SQL error occurred!", ex); + } } + } \ No newline at end of file diff --git a/src/main/java/com/alpsbte/plotsystem/core/system/plot/PlotPermissions.java b/src/main/java/com/alpsbte/plotsystem/core/system/plot/PlotPermissions.java index 4134e355..49dce17b 100644 --- a/src/main/java/com/alpsbte/plotsystem/core/system/plot/PlotPermissions.java +++ b/src/main/java/com/alpsbte/plotsystem/core/system/plot/PlotPermissions.java @@ -1,7 +1,7 @@ /* * The MIT License (MIT) * - * Copyright © 2021, Alps BTE + * Copyright © 2021-2022, Alps BTE * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -30,42 +30,49 @@ public class PlotPermissions { - private final PlotWorld plotWorld; + private final PlotWorld world; - public PlotPermissions(PlotWorld plotWorld) { - this.plotWorld = plotWorld; + public PlotPermissions(PlotWorld world) { + this.world = world; } public PlotPermissions addBuilderPerms(UUID builder) { - plotWorld.getProtectedRegion().getOwners().addPlayer(builder); + if (world.getProtectedRegion() != null) world.getProtectedRegion().getOwners().addPlayer(builder); + world.getProtectedBuildRegion().getOwners().addPlayer(builder); + PlotManager.clearCache(builder); return this; } public PlotPermissions removeBuilderPerms(UUID builder) { - plotWorld.getProtectedRegion().getOwners().removePlayer(builder); + if (world.getProtectedRegion() != null) world.getProtectedRegion().getOwners().removePlayer(builder); + world.getProtectedBuildRegion().getOwners().removePlayer(builder); + PlotManager.clearCache(builder); return this; } public PlotPermissions addReviewerPerms() { - plotWorld.getProtectedRegion().getOwners().addGroup("staff"); + if (world.getProtectedRegion() != null) world.getProtectedRegion().getOwners().addGroup("staff"); + world.getProtectedBuildRegion().getOwners().addGroup("staff"); return this; } public PlotPermissions removeReviewerPerms() { - plotWorld.getProtectedRegion().getOwners().removeGroup("staff"); + if (world.getProtectedRegion() != null) world.getProtectedRegion().getOwners().removeGroup("staff"); + world.getProtectedBuildRegion().getOwners().removeGroup("staff"); return this; } public PlotPermissions clearAllPerms() { - plotWorld.getProtectedRegion().getOwners().removeAll(); + if (world.getProtectedRegion() != null) world.getProtectedRegion().getOwners().removeAll(); + world.getProtectedBuildRegion().getOwners().removeAll(); return this; } public boolean hasReviewerPerms() { - return plotWorld.getProtectedRegion().getOwners().getGroups().contains("staff"); + return world.getProtectedBuildRegion().getOwners().getGroups().contains("staff"); } public void save() { - plotWorld.unloadWorld(false); + world.unloadWorld(false); } } diff --git a/src/main/java/com/alpsbte/plotsystem/core/system/plot/PlotType.java b/src/main/java/com/alpsbte/plotsystem/core/system/plot/PlotType.java new file mode 100644 index 00000000..8ce1a369 --- /dev/null +++ b/src/main/java/com/alpsbte/plotsystem/core/system/plot/PlotType.java @@ -0,0 +1,36 @@ +package com.alpsbte.plotsystem.core.system.plot; + +public enum PlotType { + + FOCUS_MODE(0), + LOCAL_INSPIRATION_MODE(1), + CITY_INSPIRATION_MODE(2); + + int id; + + PlotType(int id){ + this.id = id; + } + + public int getId() { + return id; + } + + // Returns true, if the plot type only contains environment around the plot. + public boolean hasEnvironment(){ + return id == 1 || id == 2; + } + + // Returns true, if the plot type only contains one plot per world. + public boolean hasOnePlotPerWorld(){ + return id == 0 || id == 1; + } + + public static PlotType byId(int id){ + for(PlotType plotType : values()) + if(plotType.getId() == id) + return plotType; + + return null; + } +} diff --git a/src/main/java/com/alpsbte/plotsystem/core/system/plot/generator/AbstractPlotGenerator.java b/src/main/java/com/alpsbte/plotsystem/core/system/plot/generator/AbstractPlotGenerator.java index e9fe262f..b4a3beea 100644 --- a/src/main/java/com/alpsbte/plotsystem/core/system/plot/generator/AbstractPlotGenerator.java +++ b/src/main/java/com/alpsbte/plotsystem/core/system/plot/generator/AbstractPlotGenerator.java @@ -26,6 +26,10 @@ import com.alpsbte.plotsystem.PlotSystem; import com.alpsbte.plotsystem.commands.BaseCommand; +import com.alpsbte.plotsystem.core.system.plot.PlotType; +import com.alpsbte.plotsystem.core.system.plot.world.OnePlotWorld; +import com.alpsbte.plotsystem.core.system.plot.world.PlotWorld; +import com.alpsbte.plotsystem.core.system.plot.world.CityPlotWorld; import com.alpsbte.plotsystem.utils.io.config.ConfigPaths; import com.alpsbte.plotsystem.core.system.Builder; import com.alpsbte.plotsystem.core.system.plot.Plot; @@ -35,18 +39,17 @@ import com.alpsbte.plotsystem.utils.enums.Status; import com.alpsbte.plotsystem.utils.io.language.LangPaths; import com.alpsbte.plotsystem.utils.io.language.LangUtil; -import com.onarandombox.MultiverseCore.api.MVWorldManager; -import com.onarandombox.MultiverseCore.api.MultiverseWorld; -import com.sk89q.worldedit.BlockVector; -import com.sk89q.worldedit.EditSession; +import com.boydti.fawe.FaweAPI; +import com.boydti.fawe.util.EditSessionBuilder; +import com.sk89q.worldedit.*; import com.sk89q.worldedit.Vector; -import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.blocks.BaseBlock; import com.sk89q.worldedit.bukkit.BukkitWorld; -import com.sk89q.worldedit.extent.clipboard.Clipboard; -import com.sk89q.worldedit.extent.clipboard.io.ClipboardFormat; -import com.sk89q.worldedit.function.operation.Operation; -import com.sk89q.worldedit.function.operation.Operations; -import com.sk89q.worldedit.session.ClipboardHolder; +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.function.mask.ExistingBlockMask; +import com.sk89q.worldedit.regions.CylinderRegion; +import com.sk89q.worldedit.regions.Polygonal2DRegion; +import com.sk89q.worldedit.world.World; import com.sk89q.worldguard.bukkit.RegionContainer; import com.sk89q.worldguard.domains.DefaultDomain; import com.sk89q.worldguard.protection.flags.DefaultFlag; @@ -54,236 +57,225 @@ import com.sk89q.worldguard.protection.flags.StateFlag; import com.sk89q.worldguard.protection.managers.RegionManager; import com.sk89q.worldguard.protection.managers.storage.StorageException; -import com.sk89q.worldguard.protection.regions.GlobalProtectedRegion; -import com.sk89q.worldguard.protection.regions.ProtectedCuboidRegion; +import com.sk89q.worldguard.protection.regions.ProtectedPolygonalRegion; import com.sk89q.worldguard.protection.regions.ProtectedRegion; import org.bukkit.*; import org.bukkit.configuration.file.FileConfiguration; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.io.File; -import java.io.FileInputStream; import java.io.IOException; import java.sql.SQLException; -import java.util.Arrays; -import java.util.HashSet; -import java.util.List; +import java.util.*; import java.util.logging.Level; public abstract class AbstractPlotGenerator { - - private static final MVWorldManager worldManager = PlotSystem.DependencyManager.getMultiverseCore().getMVWorldManager(); - private WorldCreator worldCreator; - private final Plot plot; private final Builder builder; + private final PlotWorld world; + private final double plotVersion; + private final PlotType plotType; + + /** + * Generates a new plot in the plot world + * @param plot - plot which should be generated + * @param builder - builder of the plot + */ + public AbstractPlotGenerator(@NotNull Plot plot, @NotNull Builder builder) throws SQLException { + this(plot, builder, builder.getPlotTypeSetting()); + } /** + * Generates a new plot in the given world * @param plot - plot which should be generated * @param builder - builder of the plot + * @param plotType - type of the plot */ - public AbstractPlotGenerator(@NotNull Plot plot, @NotNull Builder builder) { + public AbstractPlotGenerator(@NotNull Plot plot, @NotNull Builder builder, @NotNull PlotType plotType) throws SQLException { + this(plot, builder, plotType, plot.getVersion() <= 2 || plotType.hasOnePlotPerWorld() ? new OnePlotWorld(plot) : new CityPlotWorld(plot)); + } + + /** + * Generates a new plot in the given world + * @param plot - plot which should be generated + * @param builder - builder of the plot + * @param world - world of the plot + */ + private AbstractPlotGenerator(@NotNull Plot plot, @NotNull Builder builder, @NotNull PlotType plotType, @NotNull PlotWorld world) { this.plot = plot; this.builder = builder; + this.world = world; + this.plotVersion = plot.getVersion(); + this.plotType = plotType; if (init()) { Exception exception = null; try { - generateWorld(); - generateOutlines(plot.getOutlinesSchematic()); - createMultiverseWorld(); - configureWorld(worldManager.getMVWorld(plot.getWorld().getBukkitWorld())); - createProtection(); + if (plotType.hasOnePlotPerWorld() || !world.isWorldGenerated()) { + new PlotWorldGenerator(world.getWorldName()); + } else if (!world.isWorldLoaded() && !world.loadWorld()) throw new Exception("Could not load world"); + generateOutlines(plot.getOutlinesSchematic(), plotVersion >= 3 ? plot.getEnvironmentSchematic() : null); + createPlotProtection(); } catch (Exception ex) { exception = ex; } try { - this.onComplete(exception != null); + this.onComplete(exception != null, false); } catch (SQLException ex) { exception = ex; } if (exception != null) { - if (worldManager.isMVWorld(plot.getWorld().getWorldName())) PlotHandler.abandonPlot(plot); + PlotHandler.abandonPlot(plot); onException(exception); } } } + /** * Executed before plot generation * @return true if initialization was successful */ protected abstract boolean init(); - /** - * Generates plot world - */ - protected void generateWorld() { - if (getPlot().getWorld().isWorldGenerated()) plot.getWorld().deleteWorld(); - - worldCreator = new WorldCreator(plot.getWorld().getWorldName()); - worldCreator.environment(org.bukkit.World.Environment.NORMAL); - worldCreator.type(WorldType.FLAT); - worldCreator.generatorSettings("2;0;1;"); - worldCreator.createWorld(); - } - - /** - * Creates Multiverse world - */ - protected void createMultiverseWorld() { - // Check if world creator is configured and add new world to multiverse world manager - if (worldCreator != null) { - worldManager.addWorld(plot.getWorld().getWorldName(), worldCreator.environment(), null, worldCreator.type(), false, - "VoidGen:{\"caves\":false,\"decoration\":false,\"mobs\":false,\"structures\":false}"); - } else { - throw new RuntimeException("World Creator is not configured"); - } - } /** * Generates plot schematic and outlines - * @param plotSchematic - schematic file + * @param plotSchematic - plot schematic file + * @param environmentSchematic - environment schematic file */ - protected void generateOutlines(File plotSchematic) { - try { - if (plotSchematic != null) { - Vector buildingOutlinesCoordinates = PlotManager.getPlotCenter(); - - com.sk89q.worldedit.world.World weWorld = new BukkitWorld(plot.getWorld().getBukkitWorld()); - Clipboard clipboard = ClipboardFormat.SCHEMATIC.getReader(new FileInputStream(plotSchematic)).read(weWorld.getWorldData()); + protected void generateOutlines(@NotNull File plotSchematic, @Nullable File environmentSchematic) throws IOException, WorldEditException, SQLException { + final class OnlyAirMask extends ExistingBlockMask { + public OnlyAirMask(Extent extent) { + super(extent); + } - // Place the bottom part of the schematic 5 blocks above 0 - double heightDif = clipboard.getOrigin().getY() - clipboard.getMinimumPoint().getY(); - buildingOutlinesCoordinates = buildingOutlinesCoordinates.add(0, heightDif, 0); + @Override + public boolean test(Vector vector) { + return this.getExtent().getLazyBlock(vector).getType() == 0; + } + } - ClipboardHolder clipboardHolder = new ClipboardHolder(clipboard, weWorld.getWorldData()); - EditSession editSession = PlotSystem.DependencyManager.getWorldEdit().getEditSessionFactory().getEditSession(weWorld, -1); + com.sk89q.worldedit.world.World weWorld = new BukkitWorld(world.getBukkitWorld()); + EditSession editSession = new EditSessionBuilder(weWorld).fastmode(true).build(); - Operation operation = clipboardHolder.createPaste(editSession, weWorld.getWorldData()).to(buildingOutlinesCoordinates).ignoreAirBlocks(false).build(); - Operations.complete(operation); - editSession.flushQueue(); + if(plotVersion >= 3 && plotType.hasEnvironment() && environmentSchematic != null && environmentSchematic.exists()){ + editSession.setMask(new OnlyAirMask(weWorld)); + pasteSchematic(editSession, environmentSchematic, world, false); + } - Location spawnLocation = plot.getWorld().getSpawnPoint(); - if (spawnLocation != null) plot.getWorld().getBukkitWorld().setSpawnLocation(spawnLocation); - } - } catch (IOException | WorldEditException ex) { - Bukkit.getLogger().log(Level.SEVERE, "An error occurred while generating plot outlines!", ex); - throw new RuntimeException("Plot outlines generation completed exceptionally"); + pasteSchematic(editSession, plotSchematic, world, true); + + // If the player is playing in his own world, then additionally generate the plot in the city world + if (PlotWorld.isOnePlotWorld(world.getWorldName()) && plotVersion >= 3 && plot.getStatus() != Status.completed) { + // Generate city plot world if it doesn't exist + new AbstractPlotGenerator(plot, builder, PlotType.CITY_INSPIRATION_MODE) { + @Override + protected boolean init() { + return true; + } + + @Override + protected void createPlotProtection() {} + + @Override + protected void onComplete(boolean failed, boolean unloadWorld) throws SQLException { + super.onComplete(true, true); + } + + @Override + protected void onException(Throwable ex) { + Bukkit.getLogger().log(Level.WARNING, "Could not generate plot in city world " + world.getWorldName() + "!", ex); + } + }; } } - /** - * Configures plot world - * @param mvWorld - plot world - */ - protected void configureWorld(@NotNull MultiverseWorld mvWorld) { - // Set Bukkit world game rules - plot.getWorld().getBukkitWorld().setGameRuleValue("randomTickSpeed", "0"); - plot.getWorld().getBukkitWorld().setGameRuleValue("doDaylightCycle", "false"); - plot.getWorld().getBukkitWorld().setGameRuleValue("doFireTick", "false"); - plot.getWorld().getBukkitWorld().setGameRuleValue("doWeatherCycle", "false"); - plot.getWorld().getBukkitWorld().setGameRuleValue("keepInventory", "true"); - plot.getWorld().getBukkitWorld().setGameRuleValue("announceAdvancements", "false"); - - // Set world time to midday - plot.getWorld().getBukkitWorld().setTime(6000); - - // Configure multiverse world - mvWorld.setAllowFlight(true); - mvWorld.setGameMode(GameMode.CREATIVE); - mvWorld.setEnableWeather(false); - mvWorld.setDifficulty(Difficulty.PEACEFUL); - mvWorld.setAllowAnimalSpawn(false); - mvWorld.setAllowMonsterSpawn(false); - mvWorld.setAutoLoad(false); - mvWorld.setKeepSpawnInMemory(false); - worldManager.saveWorldsConfig(); - } /** * Creates plot protection */ - protected void createProtection() { - BlockVector min = BlockVector.toBlockPoint(0, 1, 0); - BlockVector max = BlockVector.toBlockPoint(PlotManager.PLOT_SIZE, 256, PlotManager.PLOT_SIZE); - - RegionContainer container = PlotSystem.DependencyManager.getWorldGuard().getRegionContainer(); - RegionManager regionManager = container.get(plot.getWorld().getBukkitWorld()); - - // Create protected region for world - GlobalProtectedRegion globalRegion = new GlobalProtectedRegion("__global__"); - globalRegion.setFlag(DefaultFlag.ENTRY, StateFlag.State.DENY); - globalRegion.setFlag(DefaultFlag.ENTRY.getRegionGroupFlag(), RegionGroup.ALL); - - // Create protected region for plot - ProtectedRegion protectedPlotRegion = new ProtectedCuboidRegion(plot.getWorld().getWorldName(), min, max); - protectedPlotRegion.setPriority(100); - - // Add and save regions - try { - if (regionManager != null) { - regionManager.addRegion(globalRegion); - regionManager.addRegion(protectedPlotRegion); - regionManager.saveChanges(); - } else { - throw new RuntimeException("Region Manager is null"); + protected void createPlotProtection() throws StorageException, SQLException, IOException { + RegionContainer regionContainer = PlotSystem.DependencyManager.getWorldGuard().getRegionContainer(); + RegionManager regionManager = regionContainer.get(world.getBukkitWorld()); + + if (regionManager != null) { + // Create build region for plot from the outline of the plot + ProtectedRegion protectedBuildRegion = new ProtectedPolygonalRegion(world.getRegionName(), plot.getOutline(), PlotWorld.MIN_WORLD_HEIGHT, PlotWorld.MAX_WORLD_HEIGHT); + protectedBuildRegion.setPriority(100); + + // Create protected plot region for plot + World weWorld = new BukkitWorld(world.getBukkitWorld()); + CylinderRegion cylinderRegion = new CylinderRegion(weWorld, plot.getCenter(), new Vector2D(PlotWorld.PLOT_SIZE, PlotWorld.PLOT_SIZE), PlotWorld.MIN_WORLD_HEIGHT, PlotWorld.MAX_WORLD_HEIGHT); + ProtectedRegion protectedRegion = new ProtectedPolygonalRegion(world.getRegionName() + "-1", cylinderRegion.polygonize(-1), PlotWorld.MIN_WORLD_HEIGHT, PlotWorld.MAX_WORLD_HEIGHT); + protectedRegion.setPriority(50); + + // Add plot owner + DefaultDomain owner = protectedBuildRegion.getOwners(); + owner.addPlayer(builder.getUUID()); + protectedBuildRegion.setOwners(owner); + protectedRegion.setOwners(owner); + + + // Set permissions + protectedBuildRegion.setFlag(DefaultFlag.BUILD, StateFlag.State.ALLOW); + protectedBuildRegion.setFlag(DefaultFlag.BUILD.getRegionGroupFlag(), RegionGroup.OWNERS); + protectedRegion.setFlag(DefaultFlag.BUILD, StateFlag.State.DENY); + protectedRegion.setFlag(DefaultFlag.BUILD.getRegionGroupFlag(), RegionGroup.ALL); + protectedRegion.setFlag(DefaultFlag.ENTRY, StateFlag.State.ALLOW); + protectedRegion.setFlag(DefaultFlag.ENTRY.getRegionGroupFlag(), RegionGroup.ALL); + + FileConfiguration config = PlotSystem.getPlugin().getConfigManager().getCommandsConfig(); + List allowedCommandsNonBuilder = config.getStringList(ConfigPaths.ALLOWED_COMMANDS_NON_BUILDERS); + allowedCommandsNonBuilder.removeIf(c -> c.equals("/cmd1")); + for (BaseCommand baseCommand : PlotSystem.getPlugin().getCommandManager().getBaseCommands()) { + allowedCommandsNonBuilder.addAll(Arrays.asList(baseCommand.getNames())); + for (String command : baseCommand.getNames()) { + allowedCommandsNonBuilder.add("/" + command); + } } - } catch (StorageException ex) { - Bukkit.getLogger().log(Level.SEVERE, "An error occurred while saving plot protection!", ex); - throw new RuntimeException("Plot protection creation completed exceptionally"); - } - - - // Add plot owner - DefaultDomain owner = protectedPlotRegion.getOwners(); - owner.addPlayer(builder.getUUID()); - protectedPlotRegion.setOwners(owner); - - - // Set permissions - protectedPlotRegion.setFlag(DefaultFlag.PASSTHROUGH, StateFlag.State.ALLOW); - protectedPlotRegion.setFlag(DefaultFlag.PASSTHROUGH.getRegionGroupFlag(), RegionGroup.OWNERS); - - protectedPlotRegion.setFlag(DefaultFlag.ENTRY, StateFlag.State.ALLOW); - protectedPlotRegion.setFlag(DefaultFlag.ENTRY.getRegionGroupFlag(), RegionGroup.ALL); - - FileConfiguration config = PlotSystem.getPlugin().getConfigManager().getCommandsConfig(); - - List allowedCommandsNonBuilder = config.getStringList(ConfigPaths.ALLOWED_COMMANDS_NON_BUILDERS); - allowedCommandsNonBuilder.removeIf(c -> c.equals("/cmd1")); - for (BaseCommand baseCommand : PlotSystem.getPlugin().getCommandManager().getBaseCommands()) { - allowedCommandsNonBuilder.addAll(Arrays.asList(baseCommand.getNames())); - for (String command : baseCommand.getNames()) { - allowedCommandsNonBuilder.add("/" + command); - } - } - - List blockedCommandsBuilders = config.getStringList(ConfigPaths.BLOCKED_COMMANDS_BUILDERS); - blockedCommandsBuilders.removeIf(c -> c.equals("/cmd1")); - - protectedPlotRegion.setFlag(DefaultFlag.BLOCKED_CMDS, new HashSet<>(blockedCommandsBuilders)); - protectedPlotRegion.setFlag(DefaultFlag.BLOCKED_CMDS.getRegionGroupFlag(), RegionGroup.OWNERS); - - protectedPlotRegion.setFlag(DefaultFlag.ALLOWED_CMDS, new HashSet<>(allowedCommandsNonBuilder)); - protectedPlotRegion.setFlag(DefaultFlag.ALLOWED_CMDS.getRegionGroupFlag(), RegionGroup.NON_OWNERS); + List blockedCommandsBuilders = config.getStringList(ConfigPaths.BLOCKED_COMMANDS_BUILDERS); + blockedCommandsBuilders.removeIf(c -> c.equals("/cmd1")); + + protectedRegion.setFlag(DefaultFlag.BLOCKED_CMDS, new HashSet<>(blockedCommandsBuilders)); + protectedRegion.setFlag(DefaultFlag.BLOCKED_CMDS.getRegionGroupFlag(), RegionGroup.OWNERS); + protectedRegion.setFlag(DefaultFlag.ALLOWED_CMDS, new HashSet<>(allowedCommandsNonBuilder)); + protectedRegion.setFlag(DefaultFlag.ALLOWED_CMDS.getRegionGroupFlag(), RegionGroup.NON_OWNERS); + + + // Add regions and save changes + if (regionManager.hasRegion(world.getRegionName())) regionManager.removeRegion(world.getRegionName()); + if (regionManager.hasRegion(world.getRegionName() + "-1")) regionManager.removeRegion(world.getRegionName() + "-1"); + regionManager.addRegion(protectedBuildRegion); + regionManager.addRegion(protectedRegion); + regionManager.saveChanges(); + } else Bukkit.getLogger().log(Level.WARNING, "Region Manager is null!"); } + /** * Gets invoked when generation is completed * @param failed - true if generation has failed + * @param unloadWorld - try to unload world after generation * @throws SQLException - caused by a database exception */ - protected void onComplete(boolean failed) throws SQLException { + protected void onComplete(boolean failed, boolean unloadWorld) throws SQLException { if (!failed) { builder.setPlot(plot.getID(), builder.getFreeSlot()); + plot.setPlotType(plotType); plot.setStatus(Status.unfinished); plot.setPlotOwner(builder.getPlayer().getUniqueId().toString()); + PlotManager.clearCache(builder.getUUID()); } + + // Unload plot world if it is not needed anymore + if (unloadWorld) world.unloadWorld(false); } + /** * Gets invoked when an exception has occurred * @param ex - caused exception @@ -294,6 +286,7 @@ protected void onException(Throwable ex) { builder.getPlayer().playSound(builder.getPlayer().getLocation(), Utils.ErrorSound,1,1); } + /** * @return - plot object */ @@ -301,10 +294,33 @@ public Plot getPlot() { return plot; } + /** * @return - builder object */ public Builder getBuilder() { return builder; } + + + + /** + * Pastes the schematic to the plot center in the given world + * @param schematicFile - plot/environment schematic file + * @param world - world to paste in + */ + public static void pasteSchematic(@Nullable EditSession editSession, File schematicFile, PlotWorld world, boolean clearArea) throws IOException, MaxChangedBlocksException, SQLException { + if (world.loadWorld()) { + com.sk89q.worldedit.world.World weWorld = new BukkitWorld(world.getBukkitWorld()); + if (editSession == null) editSession = new EditSessionBuilder(weWorld).fastmode(true).build(); + if (clearArea) { + Polygonal2DRegion polyRegion = new Polygonal2DRegion(weWorld, world.getPlot().getOutline(), 0, PlotWorld.MAX_WORLD_HEIGHT); + editSession.replaceBlocks(polyRegion, null, new BaseBlock(0)); + editSession.flushQueue(); + } + + FaweAPI.load(schematicFile).paste(editSession, world.getPlot().getCenter().setY(world.getPlotHeight()), false); + editSession.flushQueue(); + } + } } diff --git a/src/main/java/com/alpsbte/plotsystem/core/system/plot/generator/DefaultPlotGenerator.java b/src/main/java/com/alpsbte/plotsystem/core/system/plot/generator/DefaultPlotGenerator.java index 894b5ece..a7ab8f42 100644 --- a/src/main/java/com/alpsbte/plotsystem/core/system/plot/generator/DefaultPlotGenerator.java +++ b/src/main/java/com/alpsbte/plotsystem/core/system/plot/generator/DefaultPlotGenerator.java @@ -27,6 +27,7 @@ import com.alpsbte.plotsystem.core.system.Builder; import com.alpsbte.plotsystem.core.system.plot.Plot; import com.alpsbte.plotsystem.core.system.plot.PlotManager; +import com.alpsbte.plotsystem.core.system.plot.PlotType; import com.alpsbte.plotsystem.utils.Utils; import com.alpsbte.plotsystem.utils.enums.PlotDifficulty; import com.alpsbte.plotsystem.utils.enums.Status; @@ -50,10 +51,14 @@ public DefaultPlotGenerator(int cityID, PlotDifficulty plotDifficulty, Builder b this(PlotManager.getPlots(cityID, plotDifficulty, Status.unclaimed).get(new Random().nextInt(PlotManager.getPlots(cityID, plotDifficulty, Status.unclaimed).size())), builder); } - public DefaultPlotGenerator(@NotNull Plot plot, @NotNull Builder builder) { + public DefaultPlotGenerator(@NotNull Plot plot, @NotNull Builder builder) throws SQLException { super(plot, builder); } + public DefaultPlotGenerator(@NotNull Plot plot, @NotNull Builder builder, PlotType plotType) throws SQLException { + super(plot, builder, plotType); + } + @Override protected boolean init() { try { @@ -83,8 +88,8 @@ protected boolean init() { } @Override - protected void onComplete(boolean failed) throws SQLException { - super.onComplete(failed); + protected void onComplete(boolean failed, boolean unloadWorld) throws SQLException { + super.onComplete(failed, false); if (!failed) { getPlot().getWorld().teleportPlayer(getBuilder().getPlayer()); diff --git a/src/main/java/com/alpsbte/plotsystem/core/system/plot/generator/PlotWorldGenerator.java b/src/main/java/com/alpsbte/plotsystem/core/system/plot/generator/PlotWorldGenerator.java new file mode 100644 index 00000000..7972a179 --- /dev/null +++ b/src/main/java/com/alpsbte/plotsystem/core/system/plot/generator/PlotWorldGenerator.java @@ -0,0 +1,102 @@ +package com.alpsbte.plotsystem.core.system.plot.generator; + +import com.alpsbte.plotsystem.PlotSystem; +import com.onarandombox.MultiverseCore.api.MVWorldManager; +import com.onarandombox.MultiverseCore.api.MultiverseWorld; +import com.sk89q.worldguard.bukkit.RegionContainer; +import com.sk89q.worldguard.protection.flags.DefaultFlag; +import com.sk89q.worldguard.protection.flags.RegionGroup; +import com.sk89q.worldguard.protection.flags.StateFlag; +import com.sk89q.worldguard.protection.managers.RegionManager; +import com.sk89q.worldguard.protection.managers.storage.StorageException; +import com.sk89q.worldguard.protection.regions.GlobalProtectedRegion; +import org.bukkit.*; + +import java.util.logging.Level; + +public class PlotWorldGenerator { + private final MVWorldManager worldManager = PlotSystem.DependencyManager.getMultiverseCore().getMVWorldManager(); + private WorldCreator worldCreator; + + private final String worldName; + private static final World.Environment environment = World.Environment.NORMAL; + private static final WorldType worldType = WorldType.FLAT; + private static final String generatorSettings = "2;0;1;"; + + public PlotWorldGenerator(String worldName) throws Exception { + this.worldName = worldName; + + generateWorld(); + createMultiverseWorld(); + configureWorld(); + createGlobalProtection(); + } + + protected void generateWorld() { + worldCreator = new WorldCreator(worldName); + worldCreator.environment(environment); + worldCreator.type(worldType); + worldCreator.generatorSettings(generatorSettings); + worldCreator.createWorld(); + } + + protected void createMultiverseWorld() throws Exception { + // Check if world creator is configured and add new world to multiverse world manager + if (worldCreator != null) { + if(!worldManager.isMVWorld(worldName)) + worldManager.addWorld(worldName, environment, null, worldType, false, + "VoidGen:{\"caves\":false,\"decoration\":false,\"mobs\":false,\"structures\":false}", false); + } else { + throw new Exception("World Creator is not configured"); + } + } + + protected void configureWorld() { + World bukkitWorld = Bukkit.getWorld(worldName); + MultiverseWorld mvWorld = worldManager.getMVWorld(bukkitWorld); + + // Set world time to midday + bukkitWorld.setTime(6000); + + // Set Bukkit world game rules + bukkitWorld.setGameRuleValue("randomTickSpeed", "0"); + bukkitWorld.setGameRuleValue("doDaylightCycle", "false"); + bukkitWorld.setGameRuleValue("doFireTick", "false"); + bukkitWorld.setGameRuleValue("doWeatherCycle", "false"); + bukkitWorld.setGameRuleValue("keepInventory", "true"); + bukkitWorld.setGameRuleValue("doMobSpawning", "false"); + bukkitWorld.setGameRuleValue("announceAdvancements", "false"); + + // Configure multiverse world + mvWorld.setAllowFlight(true); + mvWorld.setGameMode(GameMode.CREATIVE); + mvWorld.setEnableWeather(false); + mvWorld.setDifficulty(Difficulty.PEACEFUL); + mvWorld.setAllowAnimalSpawn(false); + mvWorld.setAllowMonsterSpawn(false); + mvWorld.setAutoLoad(false); + mvWorld.setKeepSpawnInMemory(false); + worldManager.saveWorldsConfig(); + } + + protected void createGlobalProtection() throws StorageException { + RegionContainer regionContainer = PlotSystem.DependencyManager.getWorldGuard().getRegionContainer(); + RegionManager regionManager = regionContainer.get(Bukkit.getWorld(worldName)); + + if (regionManager != null) { + // Create protected region for world + String regionName = "__global__"; + GlobalProtectedRegion globalRegion = new GlobalProtectedRegion(regionName); + globalRegion.setFlag(DefaultFlag.ENTRY, StateFlag.State.DENY); + globalRegion.setFlag(DefaultFlag.ENTRY.getRegionGroupFlag(), RegionGroup.ALL); + globalRegion.setFlag(DefaultFlag.PASSTHROUGH, StateFlag.State.DENY); + globalRegion.setFlag(DefaultFlag.PASSTHROUGH.getRegionGroupFlag(), RegionGroup.ALL); + globalRegion.setFlag(DefaultFlag.TNT, StateFlag.State.DENY); + globalRegion.setFlag(DefaultFlag.TNT.getRegionGroupFlag(), RegionGroup.ALL); + + if (regionManager.hasRegion(regionName)) regionManager.removeRegion(regionName); + regionManager.addRegion(globalRegion); + regionManager.saveChanges(); + } else Bukkit.getLogger().log(Level.WARNING, "Region Manager is null!"); + } +} diff --git a/src/main/java/com/alpsbte/plotsystem/core/system/plot/generator/RawPlotGenerator.java b/src/main/java/com/alpsbte/plotsystem/core/system/plot/generator/RawPlotGenerator.java deleted file mode 100644 index 270281f6..00000000 --- a/src/main/java/com/alpsbte/plotsystem/core/system/plot/generator/RawPlotGenerator.java +++ /dev/null @@ -1,85 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright © 2021, Alps BTE - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package com.alpsbte.plotsystem.core.system.plot.generator; - -import com.alpsbte.plotsystem.PlotSystem; -import com.alpsbte.plotsystem.core.system.Builder; -import com.alpsbte.plotsystem.core.system.plot.Plot; -import com.alpsbte.plotsystem.utils.Utils; -import com.onarandombox.MultiverseCore.api.MultiverseWorld; -import com.sk89q.worldguard.bukkit.RegionContainer; -import com.sk89q.worldguard.protection.managers.RegionManager; -import org.bukkit.Bukkit; -import org.jetbrains.annotations.NotNull; - -import java.io.File; -import java.util.logging.Level; - -public class RawPlotGenerator extends AbstractPlotGenerator { - - public RawPlotGenerator(Plot plot, Builder builder) { - super(plot, builder); - } - - @Override - protected boolean init() { - return true; - } - - @Override - protected void generateWorld() {} - - @Override - protected void configureWorld(@NotNull MultiverseWorld mvWorld) {} - - @Override - protected void generateOutlines(@NotNull File plotSchematic) {} - - @Override - protected void createProtection() { - RegionContainer container = PlotSystem.DependencyManager.getWorldGuard().getRegionContainer(); - RegionManager regionManager = container.get(getPlot().getWorld().getBukkitWorld()); - - if (regionManager != null) { - for (String regionID : regionManager.getRegions().keySet()) { - regionManager.removeRegion(regionID); - } - } else { - throw new RuntimeException("Region Manager is null"); - } - - super.createProtection(); - } - - @Override - protected void onComplete(boolean failed) {} - - @Override - protected void onException(Throwable ex) { - Bukkit.getLogger().log(Level.SEVERE, "An error occurred while cleaning plot!"); - getBuilder().getPlayer().sendMessage(Utils.getErrorMessageFormat("An error occurred while cleaning plot! Please try again!")); - getBuilder().getPlayer().playSound(getBuilder().getPlayer().getLocation(), Utils.ErrorSound,1,1); - } -} diff --git a/src/main/java/com/alpsbte/plotsystem/core/system/plot/world/CityPlotWorld.java b/src/main/java/com/alpsbte/plotsystem/core/system/plot/world/CityPlotWorld.java new file mode 100644 index 00000000..519e1259 --- /dev/null +++ b/src/main/java/com/alpsbte/plotsystem/core/system/plot/world/CityPlotWorld.java @@ -0,0 +1,106 @@ +package com.alpsbte.plotsystem.core.system.plot.world; + +import com.alpsbte.plotsystem.core.system.plot.Plot; +import com.alpsbte.plotsystem.core.system.plot.PlotHandler; +import com.alpsbte.plotsystem.core.system.plot.PlotManager; +import com.alpsbte.plotsystem.utils.Utils; +import com.alpsbte.plotsystem.utils.io.language.LangPaths; +import com.alpsbte.plotsystem.utils.io.language.LangUtil; +import com.boydti.fawe.FaweAPI; +import com.google.common.annotations.Beta; +import com.sk89q.worldedit.extent.clipboard.Clipboard; +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; + +import java.io.IOException; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.List; +import java.util.logging.Level; + +public class CityPlotWorld extends PlotWorld { + public CityPlotWorld(@NotNull Plot plot) throws SQLException { + super("C-" + plot.getCity().getID(), plot); + } + + @Override + public boolean teleportPlayer(@NotNull Player player) { + if (super.teleportPlayer(player)) { + try { + player.playSound(player.getLocation(), Utils.TeleportSound, 1, 1); + player.setAllowFlight(true); + player.setFlying(true); + + if (getPlot() != null) { + player.sendMessage(Utils.getInfoMessageFormat(LangUtil.get(player, LangPaths.Message.Info.TELEPORTING_PLOT, String.valueOf(getPlot().getID())))); + + Utils.updatePlayerInventorySlots(player); + PlotHandler.sendLinkMessages(getPlot(), player); + + if(getPlot().getPlotOwner().getUUID().equals(player.getUniqueId())) { + getPlot().setLastActivity(false); + } + } + + return true; + } catch (SQLException ex) { + Bukkit.getLogger().log(Level.SEVERE, "A SQL error occurred!", ex); + } + } + return false; + } + + @Override + public String getRegionName() { + return super.getRegionName() + "-" + getPlot().getID(); + } + + + @Beta + @Override + public int getPlotHeight() throws IOException { + return getPlot().getVersion() >= 3 ? MIN_WORLD_HEIGHT + getWorldHeight() : getPlotHeightCentered(); + } + + @Beta + @Override + public int getPlotHeightCentered() throws IOException { + return MIN_WORLD_HEIGHT + getWorldHeight() + super.getPlotHeightCentered(); + } + + /** + * Calculate additional height for the plot + * @return additional height + * @throws IOException if the outline schematic fails to load + */ + @Beta + public int getWorldHeight() throws IOException { + Clipboard clipboard = FaweAPI.load(getPlot().getOutlinesSchematic()).getClipboard(); + int plotHeight = clipboard != null ? clipboard.getMinimumPoint().getBlockY() : MIN_WORLD_HEIGHT; + + // Plots created below min world height are not supported + if (plotHeight < MIN_WORLD_HEIGHT) throw new IOException("Plot height is not supported"); + + // Move Y height to a usable value below 256 blocks + while (plotHeight >= 150) { + plotHeight -= 150; + } + return plotHeight; + } + + /** + * Gets all players located on the plot in the city plot world + * @return a list of players located on the plot + */ + public List getPlayersOnPlot() { + List players = new ArrayList<>(); + if (getPlot() != null && getPlot().getWorld().isWorldLoaded() && !getPlot().getWorld().getBukkitWorld().getPlayers().isEmpty()) { + for (Player player : getPlot().getWorld().getBukkitWorld().getPlayers()) { + if (PlotManager.isPlayerOnPlot(getPlot(), player)) players.add(player); + } + return players; + } + return players; + } +} diff --git a/src/main/java/com/alpsbte/plotsystem/core/system/plot/world/IPlotWorld.java b/src/main/java/com/alpsbte/plotsystem/core/system/plot/world/IWorld.java similarity index 71% rename from src/main/java/com/alpsbte/plotsystem/core/system/plot/world/IPlotWorld.java rename to src/main/java/com/alpsbte/plotsystem/core/system/plot/world/IWorld.java index 6b1dcc9a..828f973c 100644 --- a/src/main/java/com/alpsbte/plotsystem/core/system/plot/world/IPlotWorld.java +++ b/src/main/java/com/alpsbte/plotsystem/core/system/plot/world/IWorld.java @@ -24,29 +24,30 @@ package com.alpsbte.plotsystem.core.system.plot.world; -import com.alpsbte.plotsystem.core.system.Builder; -import com.alpsbte.plotsystem.core.system.plot.generator.AbstractPlotGenerator; +import com.alpsbte.plotsystem.core.system.plot.generator.PlotWorldGenerator; +import com.sk89q.worldedit.Vector; import com.sk89q.worldguard.protection.regions.ProtectedRegion; import org.bukkit.Location; import org.bukkit.World; import org.bukkit.entity.Player; import org.jetbrains.annotations.NotNull; -public interface IPlotWorld { +import java.io.IOException; + +public interface IWorld { /** * Generates the plot world with the required configurations and schematic - * @param plotOwner plow owner of the plot * @param generator generator type as class * @return true if world was generated successfully */ - boolean generateWorld(@NotNull Builder plotOwner, @NotNull Class generator); + boolean generateWorld(@NotNull Class generator); /** * Regenerates the current plot with an optional new generator type * @param generator generator type as class * @return true if world was regenerated successfully */ - boolean regenWorld(@NotNull Class generator); + boolean regenWorld(@NotNull Class generator); /** * Deletes the world file and entry in the config file @@ -62,7 +63,7 @@ public interface IPlotWorld { /** * Unloads the plot world from memory. Plot cannot be used anymore. Plot has to be generated. - * @param movePlayers - if true, players will get teleported to the spawn location. Otherwise, plot will not get unloaded. + * @param movePlayers if true, players will get teleported to the spawn location. Otherwise, plot will not get unloaded. * @return true if world was loaded successfully */ boolean unloadWorld(boolean movePlayers); @@ -72,13 +73,28 @@ public interface IPlotWorld { * @param player bukkit player * @return true if player was teleported successfully */ - boolean teleportPlayer(Player player); + boolean teleportPlayer(@NotNull Player player); /** * Returns the spawn point of the plot * @return center coordinates of the plot + * @param plotVector plot vector + */ + Location getSpawnPoint(Vector plotVector); + + /** + * Calculates the origin Y value in the plot world used for schematic pasting + * @return the origin Y value + * @throws IOException if the outline schematic fails to load + */ + int getPlotHeight() throws IOException; + + /** + * Calculates the centered Y value in the plot world + * @return the centered Y value + * @throws IOException if the outline schematic fails to load */ - Location getSpawnPoint(); + int getPlotHeightCentered() throws IOException; /** * @return Bukkit plot world @@ -90,12 +106,23 @@ public interface IPlotWorld { */ String getWorldName(); + /** + * @return region world name of the plot + */ + String getRegionName(); + /** * Loads the protected plot world region from WorldGuard config * @return protected WorldGuard region */ ProtectedRegion getProtectedRegion(); + /** + * Loads the protected plot world build region from WorldGuard config + * @return protected WorldGuard build region + */ + ProtectedRegion getProtectedBuildRegion(); + /** * Checks if the plot world is loaded to memory * @return true if world is loaded diff --git a/src/main/java/com/alpsbte/plotsystem/core/system/plot/world/OnePlotWorld.java b/src/main/java/com/alpsbte/plotsystem/core/system/plot/world/OnePlotWorld.java new file mode 100644 index 00000000..4ddf7433 --- /dev/null +++ b/src/main/java/com/alpsbte/plotsystem/core/system/plot/world/OnePlotWorld.java @@ -0,0 +1,156 @@ +/* + * The MIT License (MIT) + * + * Copyright © 2021-2022, Alps BTE + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.alpsbte.plotsystem.core.system.plot.world; + +import com.alpsbte.plotsystem.core.system.Builder; +import com.alpsbte.plotsystem.core.system.plot.Plot; +import com.alpsbte.plotsystem.core.system.plot.PlotHandler; +import com.alpsbte.plotsystem.core.system.plot.generator.PlotWorldGenerator; +import com.alpsbte.plotsystem.core.system.plot.generator.DefaultPlotGenerator; +import com.alpsbte.plotsystem.utils.Utils; +import com.alpsbte.plotsystem.utils.enums.Status; +import com.alpsbte.plotsystem.utils.io.language.LangPaths; +import com.alpsbte.plotsystem.utils.io.language.LangUtil; +import com.sk89q.worldedit.WorldEditException; +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.io.File; +import java.io.IOException; +import java.sql.SQLException; +import java.util.logging.Level; + +public class OnePlotWorld extends PlotWorld { + private final Builder plotOwner; + + public OnePlotWorld(@NotNull Plot plot) throws SQLException { + super("P-" + plot.getID(), plot); + this.plotOwner = plot.getPlotOwner(); + } + + @Override + public boolean generateWorld(@NotNull Class generator) { + if (!isWorldGenerated()) { + try { + if (generator.isAssignableFrom(DefaultPlotGenerator.class)) { + new DefaultPlotGenerator(getPlot(), plotOwner); + } else return false; + return true; + } catch (SQLException ex) { + Bukkit.getLogger().log(Level.SEVERE, "A SQL error occurred!", ex); + } + } + return false; + } + + @Override + public boolean loadWorld() { + // Generate plot if it doesn't exist + if (getPlot() != null && !isWorldGenerated() && getPlot().getFinishedSchematic().exists()) { + try { + new DefaultPlotGenerator(getPlot(), plotOwner, getPlot().getPlotType()) { + @Override + protected void generateOutlines(@NotNull File plotSchematic, @Nullable File environmentSchematic) throws SQLException, IOException, WorldEditException { + super.generateOutlines(getPlot().getFinishedSchematic(), environmentSchematic); + } + + @Override + protected boolean init() { + return true; + } + + @Override + protected void onComplete(boolean failed, boolean unloadWorld) throws SQLException { + getPlot().getPermissions().clearAllPerms(); + super.onComplete(true, false); + } + }; + } catch (SQLException ex) { + Bukkit.getLogger().log(Level.SEVERE, "A SQL error occurred!", ex); + } + + if (!isWorldGenerated() || !isWorldLoaded()) { + Bukkit.getLogger().log(Level.WARNING, "Could not regenerate world " + getWorldName() + " for plot " + getPlot().getID() + "!"); + return false; + } + return true; + } else return super.loadWorld(); + } + + @Override + public boolean unloadWorld(boolean movePlayers) { + if (super.unloadWorld(movePlayers)) { + try { + if (getPlot() != null && getPlot().getStatus() == Status.completed) { + deleteWorld(); + return true; + } + return !isWorldLoaded(); + } catch (SQLException ex) { + Bukkit.getLogger().log(Level.SEVERE, "An SQL error occurred!", ex); + } + } + return false; + } + + @Override + public boolean teleportPlayer(@NotNull Player player) { + if (super.teleportPlayer(player)) { + try { + player.playSound(player.getLocation(), Utils.TeleportSound, 1, 1); + player.setAllowFlight(true); + player.setFlying(true); + + if (getPlot() != null) { + player.sendMessage(Utils.getInfoMessageFormat(LangUtil.get(player, LangPaths.Message.Info.TELEPORTING_PLOT, String.valueOf(getPlot().getID())))); + + Utils.updatePlayerInventorySlots(player); + PlotHandler.sendLinkMessages(getPlot(), player); + + if(getPlot().getPlotOwner().getUUID().equals(player.getUniqueId())) { + getPlot().setLastActivity(false); + } + } + + return true; + } catch (SQLException ex) { + Bukkit.getLogger().log(Level.SEVERE, "An SQL error occurred!", ex); + } + } + return false; + } + + @Override + public int getPlotHeight() throws IOException { + return getPlot().getVersion() >= 3 ? MIN_WORLD_HEIGHT : getPlotHeightCentered(); + } + + @Override + public int getPlotHeightCentered() throws IOException { + return MIN_WORLD_HEIGHT + super.getPlotHeightCentered(); + } +} diff --git a/src/main/java/com/alpsbte/plotsystem/core/system/plot/world/PlotWorld.java b/src/main/java/com/alpsbte/plotsystem/core/system/plot/world/PlotWorld.java index a0c54372..51d1e5ec 100644 --- a/src/main/java/com/alpsbte/plotsystem/core/system/plot/world/PlotWorld.java +++ b/src/main/java/com/alpsbte/plotsystem/core/system/plot/world/PlotWorld.java @@ -1,44 +1,13 @@ -/* - * The MIT License (MIT) - * - * Copyright © 2021-2022, Alps BTE - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - package com.alpsbte.plotsystem.core.system.plot.world; import com.alpsbte.plotsystem.PlotSystem; -import com.alpsbte.plotsystem.core.menus.CompanionMenu; -import com.alpsbte.plotsystem.core.menus.ReviewMenu; -import com.alpsbte.plotsystem.core.system.Builder; import com.alpsbte.plotsystem.core.system.plot.Plot; -import com.alpsbte.plotsystem.core.system.plot.PlotHandler; -import com.alpsbte.plotsystem.core.system.plot.PlotManager; -import com.alpsbte.plotsystem.core.system.plot.generator.AbstractPlotGenerator; -import com.alpsbte.plotsystem.core.system.plot.generator.DefaultPlotGenerator; -import com.alpsbte.plotsystem.core.system.plot.generator.RawPlotGenerator; +import com.alpsbte.plotsystem.core.system.plot.generator.PlotWorldGenerator; import com.alpsbte.plotsystem.utils.Utils; -import com.alpsbte.plotsystem.utils.enums.Status; -import com.alpsbte.plotsystem.utils.io.language.LangPaths; -import com.alpsbte.plotsystem.utils.io.language.LangUtil; +import com.boydti.fawe.FaweAPI; import com.onarandombox.MultiverseCore.MultiverseCore; +import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.extent.clipboard.Clipboard; import com.sk89q.worldguard.bukkit.RegionContainer; import com.sk89q.worldguard.protection.managers.RegionManager; import com.sk89q.worldguard.protection.regions.ProtectedRegion; @@ -48,6 +17,7 @@ import org.bukkit.World; import org.bukkit.entity.Player; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.io.File; import java.io.IOException; @@ -55,38 +25,28 @@ import java.util.Locale; import java.util.logging.Level; -public class PlotWorld implements IPlotWorld { +public class PlotWorld implements IWorld { + public static final int PLOT_SIZE = 150; + public static final int MAX_WORLD_HEIGHT = 256; + public static final int MIN_WORLD_HEIGHT = 5; + private final MultiverseCore mvCore = PlotSystem.DependencyManager.getMultiverseCore(); + private final String worldName; private final Plot plot; - private final MultiverseCore mvCore; - public PlotWorld(Plot plot) { + public PlotWorld(@NotNull String worldName, @Nullable Plot plot) { + this.worldName = worldName; this.plot = plot; - this.mvCore = PlotSystem.DependencyManager.getMultiverseCore(); } @Override - public boolean generateWorld(@NotNull Builder plotOwner, @NotNull Class generator) { - if (!isWorldGenerated()) { - if (generator.isAssignableFrom(DefaultPlotGenerator.class)) { - new DefaultPlotGenerator(plot, plotOwner); - } else if (generator.isAssignableFrom(RawPlotGenerator.class)) { - new RawPlotGenerator(plot, plotOwner); - } else return false; - return true; - } - return false; + public boolean generateWorld(@NotNull Class generator) { + throw new UnsupportedOperationException("No world generator set for world " + getWorldName()); } @Override - public boolean regenWorld(@NotNull Class generator) { - try { - if (deleteWorld() && generateWorld(plot.getPlotOwner(), generator)) - return true; - } catch (SQLException ex) { - Bukkit.getLogger().log(Level.SEVERE, ex.getMessage(), ex); - } - return false; + public boolean regenWorld(@NotNull Class generator) { + return deleteWorld() && generateWorld(generator); } @Override @@ -94,152 +54,164 @@ public boolean deleteWorld() { if (isWorldGenerated() && loadWorld()) { if (mvCore.getMVWorldManager().deleteWorld(getWorldName(), true, true) && mvCore.saveWorldConfig()) { try { - File multiverseInventoriesConfig = new File(PlotManager.getMultiverseInventoriesConfigPath(plot.getWorld().getWorldName())); - File worldGuardConfig = new File(PlotManager.getWorldGuardConfigPath(plot.getWorld().getWorldName())); + File multiverseInventoriesConfig = new File(PlotSystem.DependencyManager.getMultiverseInventoriesConfigPath(getWorldName())); + File worldGuardConfig = new File(PlotSystem.DependencyManager.getWorldGuardConfigPath(getWorldName())); if (multiverseInventoriesConfig.exists()) FileUtils.deleteDirectory(multiverseInventoriesConfig); if (worldGuardConfig.exists()) FileUtils.deleteDirectory(worldGuardConfig); } catch (IOException ex) { - Bukkit.getLogger().log(Level.WARNING, "Could not delete world configs of plot #" + plot.getID() + "!"); + Bukkit.getLogger().log(Level.WARNING, "Could not delete config files for world " + getWorldName() + "!"); return false; } return true; - } else Bukkit.getLogger().log(Level.WARNING, "Could not delete world of plot #" + plot.getID() + "!"); + } else Bukkit.getLogger().log(Level.WARNING, "Could not delete world " + getWorldName() + "!"); } return false; } @Override public boolean loadWorld() { - try { - // Generate plot if it doesn't exist - if (!isWorldGenerated() && plot.getFinishedSchematic().exists()) { - new DefaultPlotGenerator(plot, plot.getPlotOwner()) { - @Override - protected void generateOutlines(File plotSchematic) { - super.generateOutlines(plot.getFinishedSchematic()); - } - - @Override - protected boolean init() { - return true; - } - - @Override - protected void onComplete(boolean failed) throws SQLException { - plot.getPermissions().clearAllPerms(); - super.onComplete(true); // This code sucks - } - }; - if (!isWorldGenerated() || !isWorldLoaded()) { - Bukkit.getLogger().log(Level.WARNING, "Could not regenerate world of plot #" + plot.getID() + "!"); - return false; - } + if(isWorldGenerated()) { + if (isWorldLoaded()) { return true; - } else if (isWorldGenerated()) - return mvCore.getMVWorldManager().loadWorld(getWorldName()) || isWorldLoaded(); - } catch (SQLException ex) { - Bukkit.getLogger().log(Level.SEVERE, ex.getMessage(), ex); - } + } else return mvCore.getMVWorldManager().loadWorld(getWorldName()) || isWorldLoaded(); + } else Bukkit.getLogger().log(Level.WARNING, "Could not load world " + worldName + " because it is not generated!"); return false; } @Override public boolean unloadWorld(boolean movePlayers) { - if(isWorldLoaded()) { - if (movePlayers && !getBukkitWorld().getPlayers().isEmpty()) { - for (Player player : getBukkitWorld().getPlayers()) { - player.teleport(Utils.getSpawnLocation()); + if (isWorldGenerated()) { + if(isWorldLoaded()) { + if (movePlayers && !getBukkitWorld().getPlayers().isEmpty()) { + for (Player player : getBukkitWorld().getPlayers()) { + player.teleport(Utils.getSpawnLocation()); + } } - } - try { - if (plot.getStatus() == Status.completed && getBukkitWorld().getPlayers().isEmpty()) { - deleteWorld(); - return true; - } - } catch (SQLException ex) { - Bukkit.getLogger().log(Level.SEVERE, ex.getMessage(), ex); + Bukkit.unloadWorld(getBukkitWorld(), true); + return !isWorldLoaded(); } - - Bukkit.getScheduler().scheduleSyncDelayedTask(PlotSystem.getPlugin(), (() -> - Bukkit.unloadWorld(getBukkitWorld(), true)), 60L); - return !isWorldLoaded(); - } - return true; + return true; + } else Bukkit.getLogger().log(Level.WARNING, "Could not unload world " + worldName + " because it is not generated!"); + return false; } @Override - public boolean teleportPlayer(Player player) { - Location spawnLocation; - if (loadWorld() && (spawnLocation = getSpawnPoint()) != null) { - try { - player.sendMessage(Utils.getInfoMessageFormat(LangUtil.get(player, LangPaths.Message.Info.TELEPORTING_PLOT, String.valueOf(plot.getID())))); - - player.teleport(spawnLocation); - player.playSound(player.getLocation(), Utils.TeleportSound, 1, 1); - player.setAllowFlight(true); - player.setFlying(true); - - Utils.updatePlayerInventorySlots(player); - - PlotHandler.sendLinkMessages(plot, player); + public boolean teleportPlayer(@NotNull Player player) { + if (loadWorld()) { + Location spawnLocation = plot != null ? getSpawnPoint(plot.getCenter()) : getBukkitWorld().getSpawnLocation(); + // Set spawn point 1 block above the highest block at the spawn location + spawnLocation.setY(getBukkitWorld().getHighestBlockYAt((int) spawnLocation.getX(), (int) spawnLocation.getZ()) + 1); - if(plot.getPlotOwner().getUUID().equals(player.getUniqueId())) { - plot.setLastActivity(false); - } - } catch (SQLException ex) { - Bukkit.getLogger().log(Level.SEVERE, ex.getMessage(), ex); - } + player.teleport(spawnLocation); return true; - } else player.sendMessage(Utils.getErrorMessageFormat("Could not load plot world. Please try again!")); + } else Bukkit.getLogger().log(Level.WARNING, "Could not teleport player " + player.getName() + " to world " + worldName + "!"); return false; } @Override - public Location getSpawnPoint() { - if (getBukkitWorld() != null) { - Location spawnLocation = new Location(plot.getWorld().getBukkitWorld(), - PlotManager.getPlotCenter().getX() + 0.5, - 30, - PlotManager.getPlotCenter().getZ() + 0.5, - -90, - 90); - // Set spawn point 1 block above the highest center point - spawnLocation.setY(plot.getWorld().getBukkitWorld().getHighestBlockYAt((int) spawnLocation.getX(), (int) spawnLocation.getZ()) + 1); - return spawnLocation; + public Location getSpawnPoint(Vector plotVector) { + if (isWorldGenerated() && loadWorld()) { + return plotVector == null ? getBukkitWorld().getSpawnLocation() : + new Location(getBukkitWorld(), plotVector.getX(), plotVector.getY(), plotVector.getZ()); } return null; } + @Override + public int getPlotHeight() throws IOException { + throw new UnsupportedOperationException("No plot height set for " + getWorldName()); + } + + @Override + public int getPlotHeightCentered() throws IOException { + if (plot != null) { + Clipboard clipboard = FaweAPI.load(plot.getOutlinesSchematic()).getClipboard(); + if (clipboard != null) { + return clipboard.getRegion().getCenter().getBlockY() - clipboard.getMinimumPoint().getBlockY(); + } + } + return 0; + } + @Override public World getBukkitWorld() { - return Bukkit.getWorld(getWorldName()); + return Bukkit.getWorld(worldName); } @Override public String getWorldName() { - return "P-" + plot.getID(); + return worldName; + } + + @Override + public String getRegionName() { + return worldName.toLowerCase(Locale.ROOT); } @Override public ProtectedRegion getProtectedRegion() { + return getRegion(getRegionName() + "-1"); + } + + @Override + public ProtectedRegion getProtectedBuildRegion() { + return getRegion(getRegionName()); + } + + @Override + public boolean isWorldLoaded() { + return getBukkitWorld() != null; + } + + @Override + public boolean isWorldGenerated() { + return mvCore.getMVWorldManager().getMVWorld(worldName) != null || mvCore.getMVWorldManager().getUnloadedWorlds().contains(worldName); + } + + private ProtectedRegion getRegion(String regionName) { RegionContainer container = PlotSystem.DependencyManager.getWorldGuard().getRegionContainer(); if (loadWorld()) { RegionManager regionManager = container.get(getBukkitWorld()); if (regionManager != null) { - return regionManager.getRegion(getWorldName().toLowerCase(Locale.ROOT)); + return regionManager.getRegion(regionName); } else Bukkit.getLogger().log(Level.WARNING, "Region manager is null"); } return null; } - @Override - public boolean isWorldLoaded() { - return getBukkitWorld() != null; + public Plot getPlot() { + return plot; } - @Override - public boolean isWorldGenerated() { - return mvCore.getMVWorldManager().getMVWorld(getWorldName()) != null || mvCore.getMVWorldManager().getUnloadedWorlds().contains(getWorldName()); + + /** + * @param worldName - the name of the world + * @return - true if the world is a plot world + */ + public static boolean isOnePlotWorld(String worldName) { + return worldName.toLowerCase(Locale.ROOT).startsWith("p-"); + } + + /** + * @param worldName - the name of the world + * @return - true if the world is a city plot world + */ + public static boolean isCityPlotWorld(String worldName) { + return worldName.toLowerCase(Locale.ROOT).startsWith("c-"); + } + + /** + * Returns OnePlotWorld or PlotWorld (CityPlotWorld) class depending on the world name. + * It won't return the CityPlotWorld class because there is no use case without a plot. + * @param worldName - name of the world + * @return - plot world + * @param - OnePlotWorld or PlotWorld + */ + @SuppressWarnings("unchecked") + public static T getPlotWorldByName(String worldName) throws SQLException { + if (isOnePlotWorld(worldName)) { + return new Plot(Integer.parseInt(worldName.substring(2))).getWorld(); + } else return (T) new PlotWorld(worldName, null); } } diff --git a/src/main/java/com/alpsbte/plotsystem/utils/Invitation.java b/src/main/java/com/alpsbte/plotsystem/utils/Invitation.java index ad2a01d9..b3c1f470 100644 --- a/src/main/java/com/alpsbte/plotsystem/utils/Invitation.java +++ b/src/main/java/com/alpsbte/plotsystem/utils/Invitation.java @@ -67,9 +67,9 @@ public Invitation(Player invitee, Plot plot) throws SQLException { } public void AcceptInvite() throws SQLException { - Builder builder = new Builder(invitee.getUniqueId()); + Builder builder = Builder.byUUID(invitee.getUniqueId()); if (builder.getFreeSlot() != null) { - plot.addPlotMember(new Builder(invitee.getUniqueId())); + plot.addPlotMember(Builder.byUUID(invitee.getUniqueId())); // Messages Receiver invitee.sendMessage(Utils.getInfoMessageFormat("Invitation to " + plot.getPlotOwner().getName() + "'s plot has been accepted!")); diff --git a/src/main/java/com/alpsbte/plotsystem/utils/Utils.java b/src/main/java/com/alpsbte/plotsystem/utils/Utils.java index cc808721..5fe6286c 100644 --- a/src/main/java/com/alpsbte/plotsystem/utils/Utils.java +++ b/src/main/java/com/alpsbte/plotsystem/utils/Utils.java @@ -30,6 +30,7 @@ import com.onarandombox.MultiverseCore.api.MultiverseWorld; import com.alpsbte.plotsystem.utils.io.config.ConfigPaths; import com.alpsbte.plotsystem.utils.items.builder.ItemBuilder; +import com.sk89q.worldedit.BlockVector2D; import org.bukkit.*; import com.alpsbte.plotsystem.utils.enums.PlotDifficulty; import me.arcaniax.hdb.api.HeadDatabaseAPI; @@ -37,7 +38,10 @@ import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.SkullMeta; +import org.bukkit.util.Vector; +import java.util.ArrayList; +import java.util.HashSet; import java.util.UUID; import java.util.logging.Level; @@ -162,6 +166,114 @@ public static String getFormattedDifficulty(PlotDifficulty plotDifficulty) { } } + public static HashSet getLineBetweenPoints(Vector point1, Vector point2, int pointsInLine){ + double p1X = point1.getX(); + double p1Y = point1.getY(); + double p1Z = point1.getZ(); + double p2X = point2.getX(); + double p2Y = point2.getY(); + double p2Z = point2.getZ(); + + double lineAveX = (p2X-p1X)/pointsInLine; + double lineAveY = (p2Y-p1Y)/pointsInLine; + double lineAveZ = (p2Z-p1Z)/pointsInLine; + + HashSet line = new HashSet<>(); + for(int i = 0; i <= pointsInLine; i++){ + Vector vector = new Vector(p1X + lineAveX * i, p1Y + lineAveY * i, p1Z + lineAveZ * i); + line.add(vector); + } + return line; + } + + public static HashSet getLineBetweenPoints(BlockVector2D point1, BlockVector2D point2, int pointsInLine){ + double p1X = point1.getX(); + double p1Z = point1.getZ(); + double p2X = point2.getX(); + double p2Z = point2.getZ(); + + double lineAveX = (p2X-p1X)/pointsInLine; + double lineAveZ = (p2Z-p1Z)/pointsInLine; + + HashSet line = new HashSet<>(); + for(int i = 0; i <= pointsInLine; i++){ + BlockVector2D vector = new BlockVector2D(p1X + lineAveX * i, p1Z + lineAveZ * i); + line.add(vector); + } + return line; + } + + /** This function creates a list of lines from one long string. + * Given a max value of characters per line it will iterate through the string till the maximum chars value and then back until the start of the word (until a space symbol is reached). + * Then it will cut that string into an extra line. + * This way the function will never cut a word in half and still keep the max char value (e.g. line breaks in word) + * + * @param maxCharsPerLine: max characters per line + * @param lineBreaker: characters which creates a new line (e.g. \n) + * @return + */ + public static ArrayList createMultilineFromString(String text, int maxCharsPerLine, char lineBreaker){ + ArrayList list = new ArrayList(); + + // Split text at line breaker symbol, iterate through all subtexts and create all lists together to one large list. + String[] texts = text.split(String.valueOf(lineBreaker)); + + for(String subText : texts) + list.addAll(createMultilineFromString(subText, maxCharsPerLine)); + + return list; + } + + public static ArrayList createMultilineFromString(String text, int maxCharsPerLine){ + int i = 0; + ArrayList list = new ArrayList(); + String currentText = text; + boolean findSpace = false; + + + // Create infinite loop with termination condition. + while (true){ + + // If current text is smaller than maxCharsPerLine, then add the rest of the text and return the list. + if(currentText == null || currentText.length() < maxCharsPerLine) { + if(currentText != null) + list.add(currentText); + return list; + } + + // If it should iterate through the word, increase i until it hits maxCharsPerLine + if(!findSpace && i < maxCharsPerLine - 1){ + i++; + + // If it hit the maxCharsPerLine value, go back until it finds a space. + }else{ + findSpace = true; + + // If it goes back to the start without finding a space symbol, return everything. + if(i == 0){ + list.add(currentText); + return list; + } + + char currentSymbol = currentText.charAt(i); + + // If it reaches a space symbol, split the text from start till i and add it to the list + if(currentSymbol == ' '){ + String firstPart = currentText.substring(0 , i); + String lastPart = currentText.substring(i+1); + + list.add(firstPart); + currentText = lastPart; + findSpace = false; + } + + i--; + } + + } + } + + public static class CustomHead { private final ItemStack headItem; @@ -189,6 +301,9 @@ public ItemStack getAsItemStack() { public static CustomHead PREVIOUS_BUTTON; public static CustomHead GLOBE; + public static CustomHead PLOT_TYPE; + public static CustomHead FOCUS_MODE; + public static CustomHead CITY_INSPIRATION_MODE; public static void loadHeadsAsync(HeadDatabaseAPI api) { headDatabaseAPI = api; @@ -206,6 +321,9 @@ public static void loadHeadsAsync(HeadDatabaseAPI api) { PREVIOUS_BUTTON = new CustomHead("9226"); GLOBE = new CustomHead("49973"); + PLOT_TYPE = new CustomHead("4159"); + FOCUS_MODE = new CustomHead("38199"); + CITY_INSPIRATION_MODE = new CustomHead("38094"); }); } } diff --git a/src/main/java/com/alpsbte/plotsystem/utils/ftp/FTPManager.java b/src/main/java/com/alpsbte/plotsystem/utils/ftp/FTPManager.java index 5caa7c93..e7b37a1a 100644 --- a/src/main/java/com/alpsbte/plotsystem/utils/ftp/FTPManager.java +++ b/src/main/java/com/alpsbte/plotsystem/utils/ftp/FTPManager.java @@ -80,7 +80,7 @@ public static CompletableFuture downloadSchematic(String ftpURL, File sche // Get remote schematic and write it to local file FileObject remoteSchematic = remote.resolveFile(schematic.getName()); - localSchematic.copyFrom(remoteSchematic, Selectors.SELECT_SELF); + if (remoteSchematic.exists()) localSchematic.copyFrom(remoteSchematic, Selectors.SELECT_SELF); localSchematic.close(); remoteSchematic.close(); diff --git a/src/main/java/com/alpsbte/plotsystem/utils/io/language/LangPaths.java b/src/main/java/com/alpsbte/plotsystem/utils/io/language/LangPaths.java index ddd44609..dbf6d187 100644 --- a/src/main/java/com/alpsbte/plotsystem/utils/io/language/LangPaths.java +++ b/src/main/java/com/alpsbte/plotsystem/utils/io/language/LangPaths.java @@ -75,6 +75,10 @@ public static final class MenuTitle { public static final String REVIEW_PLOT = MENU_TITLES + "review-plot"; public static final String ENTER_PLAYER_NAME = MENU_TITLES + "enter-player-name"; public static final String SELECT_LANGUAGE = MENU_TITLES + "select-language"; + public static final String SELECT_PLOT_TYPE = MENU_TITLES + "select-plot-type"; + public static final String SELECT_FOCUS_MODE = MENU_TITLES + "select-focus-mode"; + public static final String SELECT_INSPIRATION_MODE = MENU_TITLES + "select-local-inspiration-mode"; + public static final String SELECT_CITY_INSPIRATION_MODE = MENU_TITLES + "select-city-inspiration-mode"; public static final String AUTO_DETECT_LANGUAGE = MENU_TITLES + "auto-detect-language"; } @@ -101,6 +105,10 @@ public static final class MenuDescription { public static final String SUBMIT_REVIEW = MENU_DESCRIPTIONS + "submit-review-desc"; public static final String LEAVE_PLOT = MENU_DESCRIPTIONS + "leave-plot-desc"; public static final String SELECT_LANGUAGE = MENU_DESCRIPTIONS + "select-language-desc"; + public static final String SELECT_PLOT_TYPE = MENU_DESCRIPTIONS + "select-plot-type-desc"; + public static final String SELECT_FOCUS_MODE = MENU_DESCRIPTIONS + "select-focus-mode-desc"; + public static final String SELECT_INSPIRATION_MODE = MENU_DESCRIPTIONS + "select-local-inspiration-mode-desc"; + public static final String SELECT_CITY_INSPIRATION_MODE = MENU_DESCRIPTIONS + "select-city-inspiration-mode-desc"; public static final String AUTO_DETECT_LANGUAGE = MENU_DESCRIPTIONS + "auto-detect-language-desc"; } diff --git a/src/main/java/com/alpsbte/plotsystem/utils/io/language/LangUtil.java b/src/main/java/com/alpsbte/plotsystem/utils/io/language/LangUtil.java index 49527525..15572086 100644 --- a/src/main/java/com/alpsbte/plotsystem/utils/io/language/LangUtil.java +++ b/src/main/java/com/alpsbte/plotsystem/utils/io/language/LangUtil.java @@ -18,13 +18,13 @@ public class LangUtil extends YamlFileFactory { public final static LanguageFile[] languages = new LanguageFile[] { - new LanguageFile("en_GB", 1.0), - new LanguageFile("de_DE", 1.0, "de_AT", "de_CH"), - new LanguageFile("fr_FR", 1.0, "fr_CA"), - new LanguageFile("ko_KR", 1.0), - new LanguageFile("ru_RU", 1.0, "ba_RU", "tt_RU"), - new LanguageFile("zh_CN", 1.0), - new LanguageFile("zh_TW", 1.0, "zh_HK"), + new LanguageFile("en_GB", 1.1), + new LanguageFile("de_DE", 1.1, "de_AT", "de_CH"), + new LanguageFile("fr_FR", 1.1, "fr_CA"), + new LanguageFile("ko_KR", 1.1), + new LanguageFile("ru_RU", 1.1, "ba_RU", "tt_RU"), + new LanguageFile("zh_CN", 1.1), + new LanguageFile("zh_TW", 1.1, "zh_HK"), }; public LangUtil() { @@ -59,7 +59,7 @@ private static LanguageFile getLanguageFileByLocale(String locale) { } private static String getLocaleTagByPlayer(Player player) { - Builder builder = new Builder(player.getUniqueId()); + Builder builder = Builder.byUUID(player.getUniqueId()); if (builder.getLanguageTag() != null) { return builder.getLanguageTag(); } else return player.getPlayer().getLocale(); diff --git a/src/main/java/com/alpsbte/plotsystem/utils/items/SpecialBlocks.java b/src/main/java/com/alpsbte/plotsystem/utils/items/SpecialBlocks.java index 86b4c2f7..90b0b1ef 100644 --- a/src/main/java/com/alpsbte/plotsystem/utils/items/SpecialBlocks.java +++ b/src/main/java/com/alpsbte/plotsystem/utils/items/SpecialBlocks.java @@ -38,7 +38,7 @@ public class SpecialBlocks { "§7ID: §b43:9") .emptyLine() .build()) - .setEnchantment(true) + .setEnchanted(true) .build(); public static ItemStack SeamlessRedSandstone = new ItemBuilder(Material.RED_SANDSTONE, 1, (byte) 2) @@ -49,7 +49,7 @@ public class SpecialBlocks { "§7ID: §b181:12") .emptyLine() .build()) - .setEnchantment(true) + .setEnchanted(true) .build(); public static ItemStack SeamlessStone = new ItemBuilder(Material.STONE, 1) @@ -60,7 +60,7 @@ public class SpecialBlocks { "§7ID: §b43:8") .emptyLine() .build()) - .setEnchantment(true) + .setEnchanted(true) .build(); public static ItemStack RedMushroom = new ItemBuilder(Material.HUGE_MUSHROOM_2, 1) @@ -71,7 +71,7 @@ public class SpecialBlocks { "§7ID: §b100") .emptyLine() .build()) - .setEnchantment(true) + .setEnchanted(true) .build(); public static ItemStack BrownMushroom = new ItemBuilder(Material.HUGE_MUSHROOM_1, 1) @@ -82,7 +82,7 @@ public class SpecialBlocks { "§7ID: §b99:14") .emptyLine() .build()) - .setEnchantment(true) + .setEnchanted(true) .build(); public static ItemStack SeamlessMushroomStem = new ItemBuilder(Material.HUGE_MUSHROOM_2, 1) @@ -93,7 +93,7 @@ public class SpecialBlocks { "§7ID: §b99:15") .emptyLine() .build()) - .setEnchantment(true) + .setEnchanted(true) .build(); public static ItemStack LightBrownMushroom = new ItemBuilder(Material.HUGE_MUSHROOM_1, 1) @@ -104,7 +104,7 @@ public class SpecialBlocks { "§7ID: §b99:11") .emptyLine() .build()) - .setEnchantment(true) + .setEnchanted(true) .build(); public static ItemStack Barrier = new ItemBuilder(Material.BARRIER, 1) @@ -115,7 +115,7 @@ public class SpecialBlocks { "§7ID: §b166") .emptyLine() .build()) - .setEnchantment(true) + .setEnchanted(true) .build(); public static ItemStack StructureVoid = new ItemBuilder(Material.STRUCTURE_VOID, 1) @@ -126,7 +126,7 @@ public class SpecialBlocks { "§7ID: §b217") .emptyLine() .build()) - .setEnchantment(true) + .setEnchanted(true) .build(); public static ItemStack BarkOakLog = new ItemBuilder(Material.LOG, 1, (byte) 0) @@ -137,7 +137,7 @@ public class SpecialBlocks { "§7ID: §b17:12") .emptyLine() .build()) - .setEnchantment(true) + .setEnchanted(true) .build(); public static ItemStack BarkBirchLog = new ItemBuilder(Material.LOG, 1, (byte) 2) @@ -148,7 +148,7 @@ public class SpecialBlocks { "§7ID: §b17:14") .emptyLine() .build()) - .setEnchantment(true) + .setEnchanted(true) .build(); public static ItemStack BarkSpruceLog = new ItemBuilder(Material.LOG, 1, (byte) 1) @@ -159,7 +159,7 @@ public class SpecialBlocks { "§7ID: §b17:13") .emptyLine() .build()) - .setEnchantment(true) + .setEnchanted(true) .build(); public static ItemStack BarkJungleLog = new ItemBuilder(Material.LOG, 1, (byte) 3) @@ -170,7 +170,7 @@ public class SpecialBlocks { "§7ID: §b17:15") .emptyLine() .build()) - .setEnchantment(true) + .setEnchanted(true) .build(); public static ItemStack BarkAcaciaLog = new ItemBuilder(Material.LOG_2, 1, (byte) 0) @@ -181,7 +181,7 @@ public class SpecialBlocks { "§7ID: §b162:12") .emptyLine() .build()) - .setEnchantment(true) + .setEnchanted(true) .build(); public static ItemStack BarkDarkOakLog = new ItemBuilder(Material.LOG_2, 1, (byte) 1) @@ -192,6 +192,6 @@ public class SpecialBlocks { "§7ID: §b162:13") .emptyLine() .build()) - .setEnchantment(true) + .setEnchanted(true) .build(); } diff --git a/src/main/java/com/alpsbte/plotsystem/utils/items/builder/ItemBuilder.java b/src/main/java/com/alpsbte/plotsystem/utils/items/builder/ItemBuilder.java index edef5927..a8975d60 100644 --- a/src/main/java/com/alpsbte/plotsystem/utils/items/builder/ItemBuilder.java +++ b/src/main/java/com/alpsbte/plotsystem/utils/items/builder/ItemBuilder.java @@ -67,11 +67,13 @@ public ItemBuilder setLore(List lore) { return this; } - public ItemBuilder setEnchantment(boolean setEnchanted) { + public ItemBuilder setEnchanted(boolean setEnchanted) { if(setEnchanted) { itemMeta.addEnchant(Enchantment.ARROW_DAMAGE,1,true); + itemMeta.addItemFlags(new ItemFlag[] { ItemFlag.HIDE_ENCHANTS }); } else { itemMeta.removeEnchant(Enchantment.ARROW_DAMAGE); + itemMeta.removeItemFlags(new ItemFlag[] { ItemFlag.HIDE_ENCHANTS }); } return this; } diff --git a/src/main/java/com/alpsbte/plotsystem/utils/items/builder/LoreBuilder.java b/src/main/java/com/alpsbte/plotsystem/utils/items/builder/LoreBuilder.java index 9fe03b07..81d41d55 100644 --- a/src/main/java/com/alpsbte/plotsystem/utils/items/builder/LoreBuilder.java +++ b/src/main/java/com/alpsbte/plotsystem/utils/items/builder/LoreBuilder.java @@ -50,6 +50,13 @@ public LoreBuilder addLines(String... lines) { return this; } + public LoreBuilder addLines(List lines) { + for (String line : lines) { + addLine(line); + } + return this; + } + public LoreBuilder emptyLine() { lore.add(""); return this; diff --git a/src/main/resources/lang/de_DE.yml b/src/main/resources/lang/de_DE.yml index 97fb276c..a0cd7ac2 100644 --- a/src/main/resources/lang/de_DE.yml +++ b/src/main/resources/lang/de_DE.yml @@ -8,7 +8,7 @@ # | [Formatting] Use // for a newline # | [Formatting] Words that are wrapped in the {number} tag are replaced afterwards # | -# | German translation by BlackStarHD#1333 +# | German translation by BlackStarHD#1333 and R3tuxn#7169 # ----------------------------------------------------- lang: @@ -88,6 +88,10 @@ menu-title: enter-player-name: "Spielername Eingeben" select-language: "Sprache Auswählen" auto-detect-language: "Sprache Automatisch Erkennen" + select-plot-type: "Plot Typ Auswählen" + select-focus-mode: "Focus-Mode Auswählen" + select-local-inspiration-mode: "Inspiration-Mode Auswählen" + select-city-inspiration-mode: "City-Inspiration-Mode Auswählen" # ----------------------------------------------------- @@ -116,6 +120,10 @@ menu-description: leave-plot-desc: "Klicke hier, um den Plot zu verlassen" select-language-desc: "Wähle deine Sprache" auto-detect-language-desc: "Klicke hier, um deine Sprache automatisch zu erkennen" + select-plot-type-desc: 'Wähle dein Plot-Typ aus' + select-focus-mode-desc: "Baue dein Plot auf einer schwebenden Insel in einer leeren Welt.\n\n- Keine Umgebung\n- Keine Nachbarsgrundstücke" + select-local-inspiration-mode-desc: "Baue dein Plot auf einer schwebenden Insel mit Umgebung, welche als Referenz dient.\n\n+ Umgebung\n- Keine Nachbarsgrundstücke" + select-city-inspiration-mode-desc: "Baue dein Plot auf einer schwebenden Insel mit Umgebung und den Plots anderer Spieler, welche sich in der Nähe des eigenen Plots befinden.\n\n+ Umgebung\n+ Nachbarsgrundstücke" # ----------------------------------------------------- @@ -227,4 +235,4 @@ message: # NOTE: Do not change -config-version: "1.0" \ No newline at end of file +config-version: "1.1" \ No newline at end of file diff --git a/src/main/resources/lang/en_GB.yml b/src/main/resources/lang/en_GB.yml index d73f3a4c..b66359e2 100644 --- a/src/main/resources/lang/en_GB.yml +++ b/src/main/resources/lang/en_GB.yml @@ -55,67 +55,75 @@ difficulty: # | Menu Titles # ----------------------------------------------------- menu-title: - close: "Close" - back: "Back" - next-page: "Next Page" - previous-page: "Previous Page" - error: "Error" - loading: "Loading..." - navigator: "Navigator" - plot-difficulty: "Plot Difficulty" - slot: "Slot" - builder-utilities: "Builder Utilities" - show-plots: "Show Plots" - settings: "Settings" - submit: "Submit" - teleport: "Teleport" - abandon: "Abandon" - undo-submit: "Undo Submit" - manage-members: "Manage Members" - feedback: "Feedback | Review #{0}" - custom-heads: "Custom Heads" - banner-maker: "Banner Maker" - special-blocks: "Special Blocks" - review-point: "Point" - review-points: "Points" - cancel: "Cancel" - add-member-to-plot: "Add Member to Plot" - companion: "Companion" - player-plots: "{0}s Plots" - leave-plot: "Leave Plot" - review-plots: "Review Plots" - review-plot: "Review Plot #{0}" - enter-player-name: "Enter player name" - select-language: "Select Language" - auto-detect-language: "Auto-Detect Language" + close: 'Close' + back: 'Back' + next-page: 'Next Page' + previous-page: 'Previous Page' + error: 'Error' + loading: 'Loading...' + navigator: 'Navigator' + plot-difficulty: 'Plot Difficulty' + slot: 'Slot' + builder-utilities: 'Builder Utilities' + show-plots: 'Show Plots' + settings: 'Settings' + submit: 'Submit' + teleport: 'Teleport' + abandon: 'Abandon' + undo-submit: 'Undo Submit' + manage-members: 'Manage Members' + feedback: 'Feedback | Review #{0}' + custom-heads: 'Custom Heads' + banner-maker: 'Banner Maker' + special-blocks: 'Special Blocks' + review-point: 'Point' + review-points: 'Points' + cancel: 'Cancel' + add-member-to-plot: 'Add Member to Plot' + companion: 'Companion' + player-plots: '{0}s Plots' + leave-plot: 'Leave Plot' + review-plots: 'Review Plots' + review-plot: 'Review Plot #{0}' + enter-player-name: 'Enter player name' + select-language: 'Select Language' + auto-detect-language: 'Auto-Detect Language' + select-plot-type: 'Select Plot Type' + select-focus-mode: "Select Focus Mode" + select-local-inspiration-mode: "Select Inspiration Mode" + select-city-inspiration-mode: "Select City Inspiration Mode" # ----------------------------------------------------- # | Menu Descriptions # ----------------------------------------------------- menu-description: - error-desc: "An error occurred..." - navigator-desc: "Open the navigator menu" - plot-difficulty-desc: "Click to Switch..." - slot-desc: "Click on a city project to create a new plot" - builder-utilities-desc: "Get access to custom heads, banners and special blocks" - show-plots-desc: "Show all your plots" - settings-desc: "Modify your user settings" - submit-plot-desc: "Click to complete this plot and submit it to be reviewed" - teleport-desc: "Click to teleport to the plot" - abandon-desc: "Click to reset your plot and give it to someone else" - undo-submit-desc: "Click to undo your submission" - manage-members-desc: "Click to open the Plot Members menu, where you can add//and remove other players on your plot" - feedback-desc: "Click to view your plot review feedback" - custom-heads-desc: "Click to open the head menu to get a variety of custom heads" - banner-maker-desc: "Click to open the banner maker menu to create your own custom banners" - special-blocks-desc: "Click to open the special blocks menu to get a variety of inaccessible blocks" - add-member-to-plot-desc: "Invite your friends to your plot and start building together" - review-points-desc: "Click to select" - submit-review-desc: "Submit selected points and mark plot as reviewed" - leave-plot-desc: "Click to leave this plot" - select-language-desc: "Choose your language" - auto-detect-language-desc: "Click to automatically detect your language" + error-desc: 'An error occurred...' + navigator-desc: 'Open the navigator menu' + plot-difficulty-desc: 'Click to Switch...' + slot-desc: 'Click on a city project to create a new plot' + builder-utilities-desc: 'Get access to custom heads, banners and special blocks' + show-plots-desc: 'Show all your plots' + settings-desc: 'Modify your user settings' + submit-plot-desc: 'Click to complete this plot and submit it to be reviewed' + teleport-desc: 'Click to teleport to the plot' + abandon-desc: 'Click to reset your plot and give it to someone else' + undo-submit-desc: 'Click to undo your submission' + manage-members-desc: 'Click to open the Plot Members menu, where you can add//and remove other players on your plot' + feedback-desc: 'Click to view your plot review feedback' + custom-heads-desc: 'Click to open the head menu to get a variety of custom heads' + banner-maker-desc: 'Click to open the banner maker menu to create your own custom banners' + special-blocks-desc: 'Click to open the special blocks menu to get a variety of inaccessible blocks' + add-member-to-plot-desc: 'Invite your friends to your plot and start building together' + review-points-desc: 'Click to select' + submit-review-desc: 'Submit selected points and mark plot as reviewed' + leave-plot-desc: 'Click to leave this plot' + select-language-desc: 'Choose your language' + auto-detect-language-desc: 'Click to automatically detect your language' + select-plot-type-desc: 'Choose your plot type' + select-focus-mode-desc: "Build your plot on a floating island in the void.\n\n- No Environment\n- No neighboring plots" + select-local-inspiration-mode-desc: "Build on a floating island with surrounding environment as a reference.\n\n+ Environment\n- No neighboring plots" + select-city-inspiration-mode-desc: "Build on a floating island with surrounding environment and other players plots that got scanned near the own plot.\n\n+ Environment\n+ Neighboring plots" # ----------------------------------------------------- @@ -227,4 +235,4 @@ message: # NOTE: Do not change -config-version: "1.0" +config-version: "1.1" diff --git a/src/main/resources/lang/fr_FR.yml b/src/main/resources/lang/fr_FR.yml index b251a783..b6e7588a 100644 --- a/src/main/resources/lang/fr_FR.yml +++ b/src/main/resources/lang/fr_FR.yml @@ -88,6 +88,10 @@ menu-title: enter-player-name: 'Entrer nom du joueur' select-language: 'Choix de la langue' auto-detect-language: 'Détection auto de la Langue' + select-plot-type: 'Select Plot Type' + select-focus-mode: "Select Focus Mode" + select-local-inspiration-mode: "Select Inspiration Mode" + select-city-inspiration-mode: "Select City Inspiration Mode" # ----------------------------------------------------- @@ -116,6 +120,10 @@ menu-description: leave-plot-desc: "Cliquez pour quitter ce tracé" select-language-desc: "Choisissez votre langue" auto-detect-language-desc: "Cliquez pour détecter automatiquement votre langue" + select-plot-type-desc: 'Choose your plot type' + select-focus-mode-desc: "Build your plot on a floating island in the void.\n\n- No Environment\n- No neighboring plots" + select-local-inspiration-mode-desc: "Build on a floating island with surrounding environment as a reference.\n\n+ Environment\n- No neighboring plots" + select-city-inspiration-mode-desc: "Build on a floating island with surrounding environment and other players plots that got scanned near the own plot.\n\n+ Environment\n+ Neighboring plots" # ----------------------------------------------------- @@ -227,4 +235,4 @@ message: # NOTE: Do not change -config-version: "1.0" \ No newline at end of file +config-version: "1.1" \ No newline at end of file diff --git a/src/main/resources/lang/ko_KR.yml b/src/main/resources/lang/ko_KR.yml index 6da3de05..335d94ad 100644 --- a/src/main/resources/lang/ko_KR.yml +++ b/src/main/resources/lang/ko_KR.yml @@ -88,6 +88,10 @@ menu-title: enter-player-name: "플레이어 이름 입력하기" select-language: "언어 설정" auto-detect-language: "언어 감지" + select-plot-type: 'Select Plot Type' + select-focus-mode: "Select Focus Mode" + select-local-inspiration-mode: "Select Inspiration Mode" + select-city-inspiration-mode: "Select City Inspiration Mode" # ----------------------------------------------------- @@ -116,6 +120,10 @@ menu-description: leave-plot-desc: "클릭하여 플롯에서 나가기" select-language-desc: "언어를 선택하세요" auto-detect-language-desc: "클릭하여 자동으로 언어 감지" + select-plot-type-desc: 'Choose your plot type' + select-focus-mode-desc: "Build your plot on a floating island in the void.\n\n- No Environment\n- No neighboring plots" + select-local-inspiration-mode-desc: "Build on a floating island with surrounding environment as a reference.\n\n+ Environment\n- No neighboring plots" + select-city-inspiration-mode-desc: "Build on a floating island with surrounding environment and other players plots that got scanned near the own plot.\n\n+ Environment\n+ Neighboring plots" # ----------------------------------------------------- @@ -227,4 +235,4 @@ message: # NOTE: Do not change -config-version: "1.0" \ No newline at end of file +config-version: "1.1" \ No newline at end of file diff --git a/src/main/resources/lang/ru_RU.yml b/src/main/resources/lang/ru_RU.yml index 081889ea..acb1d3a3 100644 --- a/src/main/resources/lang/ru_RU.yml +++ b/src/main/resources/lang/ru_RU.yml @@ -92,6 +92,10 @@ menu-title: enter-player-name: "Введите имя игрока" select-language: "Выберите Язык" auto-detect-language: "Автоматически определять Язык" + select-plot-type: 'Select Plot Type' + select-focus-mode: "Select Focus Mode" + select-local-inspiration-mode: "Select Inspiration Mode" + select-city-inspiration-mode: "Select City Inspiration Mode" # ----------------------------------------------------- @@ -120,6 +124,10 @@ menu-description: leave-plot-desc: "Нажмите, чтобы покинуть данный участок" select-language-desc: "Выберите свой язык" auto-detect-language-desc: "Нажмите, чтобы автоматически определить язык" + select-plot-type-desc: 'Choose your plot type' + select-focus-mode-desc: "Build your plot on a floating island in the void.\n\n- No Environment\n- No neighboring plots" + select-local-inspiration-mode-desc: "Build on a floating island with surrounding environment as a reference.\n\n+ Environment\n- No neighboring plots" + select-city-inspiration-mode-desc: "Build on a floating island with surrounding environment and other players plots that got scanned near the own plot.\n\n+ Environment\n+ Neighboring plots" # ----------------------------------------------------- @@ -231,4 +239,4 @@ message: # NOTE: Do not change -config-version: "1.0" \ No newline at end of file +config-version: "1.1" \ No newline at end of file diff --git a/src/main/resources/lang/zh_CN.yml b/src/main/resources/lang/zh_CN.yml index b904129c..4e653cd6 100644 --- a/src/main/resources/lang/zh_CN.yml +++ b/src/main/resources/lang/zh_CN.yml @@ -88,6 +88,10 @@ menu-title: enter-player-name: "输入玩家名称" select-language: "选择语言" auto-detect-language: "自动侦测语言" + select-plot-type: 'Select Plot Type' + select-focus-mode: "Select Focus Mode" + select-local-inspiration-mode: "Select Inspiration Mode" + select-city-inspiration-mode: "Select City Inspiration Mode" # ----------------------------------------------------- @@ -116,6 +120,10 @@ menu-description: leave-plot-desc: "点击以离开此建地" select-language-desc: "选择你的语言" auto-detect-language-desc: "点击以自动侦测你的语言" + select-plot-type-desc: 'Choose your plot type' + select-focus-mode-desc: "Build your plot on a floating island in the void.\n\n- No Environment\n- No neighboring plots" + select-local-inspiration-mode-desc: "Build on a floating island with surrounding environment as a reference.\n\n+ Environment\n- No neighboring plots" + select-city-inspiration-mode-desc: "Build on a floating island with surrounding environment and other players plots that got scanned near the own plot.\n\n+ Environment\n+ Neighboring plots" # ----------------------------------------------------- @@ -227,4 +235,4 @@ message: # NOTE: Do not change -config-version: "1.0" \ No newline at end of file +config-version: "1.1" \ No newline at end of file diff --git a/src/main/resources/lang/zh_TW.yml b/src/main/resources/lang/zh_TW.yml index 0a468eb7..2025f7c8 100644 --- a/src/main/resources/lang/zh_TW.yml +++ b/src/main/resources/lang/zh_TW.yml @@ -88,6 +88,10 @@ menu-title: enter-player-name: "輸入玩家名稱" select-language: "選擇語言" auto-detect-language: "自動偵測語言" + select-plot-type: 'Select Plot Type' + select-focus-mode: "Select Focus Mode" + select-local-inspiration-mode: "Select Inspiration Mode" + select-city-inspiration-mode: "Select City Inspiration Mode" # ----------------------------------------------------- @@ -116,6 +120,10 @@ menu-description: leave-plot-desc: "點擊以離開此建地" select-language-desc: "選擇你的語言" auto-detect-language-desc: "點擊以自動偵測你的語言" + select-plot-type-desc: 'Choose your plot type' + select-focus-mode-desc: "Build your plot on a floating island in the void.\n\n- No Environment\n- No neighboring plots" + select-local-inspiration-mode-desc: "Build on a floating island with surrounding environment as a reference.\n\n+ Environment\n- No neighboring plots" + select-city-inspiration-mode-desc: "Build on a floating island with surrounding environment and other players plots that got scanned near the own plot.\n\n+ Environment\n+ Neighboring plots" # ----------------------------------------------------- @@ -227,4 +235,4 @@ message: # NOTE: Do not change -config-version: "1.0" \ No newline at end of file +config-version: "1.1" \ No newline at end of file diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index d37a700d..15c68c45 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -3,7 +3,7 @@ version: 2.3 api-version: 1.12.2 name: Plot-System author: R3tuxn & Cinnazeyy -softdepend: [VoidGen, FastAsyncWorldEdit, Multiverse-Core, WorldEdit, HolographicDisplays, WorldGuard, HeadDatabase, ProtocolLib] +softdepend: [VoidGen, FastAsyncWorldEdit, Multiverse-Core, WorldEdit, HolographicDisplays, WorldGuard, HeadDatabase, ProtocolLib, ParticleNativeAPI] commands: spawn: