diff --git a/README.md b/README.md index c3461e8f..f43a7235 100644 --- a/README.md +++ b/README.md @@ -30,8 +30,8 @@ -## About The Project -The Plot System is an essential part of any BuildTheEarth server system, meant to run alongside the classic Terra servers to make participating a lot easier and appeal to both the casual and power users. The plot system gives every player the opportunity to participate in the project with ease using Minecraft versions 1.12-1.17 (Vanilla). +# About The Project +The Plot System is an essential part of any BuildTheEarth server system, meant to run alongside the classic Terra servers to make participating a lot easier and appeal to both the casual and power users. The plot system gives every player the opportunity to participate in the project with ease using Minecraft version 1.12 or higher, if ViaVersion is supported. After clicking on the Companion item in the hotbar, a selection window appears where you can choose a city from the list. If you now click on one of these cities, you will get to a random plot of this city and you can immediately start building. Links to Google Maps, Google Earth Web & OpenStreetMap appear when you enter the plot and allow you to quickly find your way around. @@ -40,20 +40,40 @@ The system is designed to make it easier for unexperienced people, casual player The plugin was programmed by the Alps BTE Team and is meant for everyone to use and help contribute. For any questions regarding setup or contribution feel free to contact us. All used Libraries and APIs are listed below. - - - - -## Features -✔️ Support for **multiple cities** and **countries/states**
+# Features +## Plot Types +![FocusMode_PlotSystemBanner](https://user-images.githubusercontent.com/64250550/184678178-f8b5c3e5-ec35-4b6b-9b1b-ac3170148d34.png) + +The focus mode is the old well-known mode that was also used by default before the release of v3.0. Build your plot on a floating island in an empty void world. Simple and straightforward, like in the good old days. +

➖ No Environment +
➖ No Neighboring Plots +


+ +![InspirationMode_PlotSystemBanner](https://user-images.githubusercontent.com/64250550/184681201-2f7e2103-df8d-42a3-93b0-ce42770e4fa8.png) + +The inspiration mode feels like building in a normal world. By adding the surrounding area of your plot, you will see neighboring buildings, streets and vegetation. In comparison to the focus mode, you will have a better orientation which helps you when building. This mode is selected as default, when using the Plot System for the first time. +

➕ Environment +
➖ No Neighboring Plots +


+ +![CityInspirationMode_PlotSystemBanner](https://user-images.githubusercontent.com/64250550/184683030-27f1760b-09ad-43f7-b5ed-bdd46c972246.png) + +The city inspiration mode will give you the full building experience by combining the inspiration mode with other players. Build with your friends and others in one world next to each other and see continuous progress. +

⚠️ This mode is not fully stable and still in BETA +

➕ Environment +
➕ Neighboring Plots +
+ +## Other Features +✔️ Support for **multiple cities** as well as for **continents** and **countries/states**
✔️ **User-friendly menus** and **commands**
-✔️ **Multi-Language** Support
+✔️ **Multi-Language** Support (currently up to 7 languages)
✔️ Plot **Group System** (Build together with up to 5 people on one plot)
✔️ **SFTP/FTP** Support
-✔️ Detailed **review system** with feedback
-✔️ Three plot **difficulty levels**
+✔️ Detailed **review system** with individual feedback
+✔️ Three plot **difficulty levels** (easy, medium and hard)
✔️ Building **Quality of Life tools**
-✔️ **/tpll support** on plots
+✔️ Full **/tpll support** on plots
✔️ **Leaderboards** when using the Holograms extension
✔️ Automatic **abandoning of inactive plots**
✔️ Automatic **placement of completed plots** on the terra server
@@ -61,7 +81,7 @@ All used Libraries and APIs are listed below. -## Installation +# Installation 💻 To use this system, you currently need at least two servers.
One is running Terra++ with the **[Plot-System-Terra Plugin](https://github.com/AlpsBTE/Plot-System-Terra)** and the other one is a Spigot Vanilla server for the Plot-System itself.
@@ -69,16 +89,15 @@ One is running Terra++ with the **[Plot-System-Terra Plugin](https://github.com/ -## Roadmap +# Roadmap 📋 Plot Tutorial
📋 In-Game Guidebook
📋 Discord Integration
-📋 More and Improved Leaderboards
📋 Statistics
-## Contributing +# Contributing 🔨 Any contributions you make are greatly appreciated. * Reporting a bug @@ -88,23 +107,13 @@ One is running Terra++ with the **[Plot-System-Terra Plugin](https://github.com/ -## License +# License Distributed under the MIT License. See `LICENSE` for more information. - -## Contacts - -- R3tuxn - [R3tuxn#7169](https://discord.com/invite/vgkspay) -- Cinnazeyy - [Cinnazeyy#2440](https://discord.com/invite/vgkspay) -- Coppertine - [Coppertine#1718](https://discord.com/invite/vgkspay) - -Project Link: [https://github.com/AlpsBTE/PlotSystem](https://github.com/AlpsBTE/Plot-System) - - -## Libraries & APIs +# Libraries & APIs * [Spigot & Bukkit API](https://hub.spigotmc.org/stash/projects/SPIGOT) * [WorldEdit API](https://github.com/EngineHub/WorldEdit) * [WorldGuard API](https://github.com/EngineHub/WorldGuard) @@ -117,3 +126,4 @@ Project Link: [https://github.com/AlpsBTE/PlotSystem](https://github.com/AlpsBTE * [Maria-DB Library](https://mariadb.com/kb/en/about-mariadb-connector-j/) * [Hikari-CP](https://github.com/brettwooldridge/HikariCP) * [Apache Common VFS API](https://commons.apache.org/proper/commons-vfs/commons-vfs2/apidocs/index.html) +* [ProtocolLIB](https://github.com/dmulloy2/ProtocolLib) diff --git a/pom.xml b/pom.xml index 51dcd497..f2ecd340 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ com.alpsbte PlotSystem - 2.3 + 3.0 @@ -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..a966753f 100644 --- a/src/main/java/com/alpsbte/plotsystem/PlotSystem.java +++ b/src/main/java/com/alpsbte/plotsystem/PlotSystem.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 @@ -25,11 +25,11 @@ package com.alpsbte.plotsystem; import com.alpsbte.plotsystem.commands.*; +import com.alpsbte.plotsystem.core.holograms.HologramManager; +import com.alpsbte.plotsystem.core.holograms.HolographicDisplay; +import com.alpsbte.plotsystem.core.system.Review; import com.alpsbte.plotsystem.utils.PacketListener; import com.alpsbte.plotsystem.utils.io.config.ConfigUtil; -import com.alpsbte.plotsystem.core.holograms.HolographicDisplay; -import com.alpsbte.plotsystem.core.holograms.PlotsLeaderboard; -import com.alpsbte.plotsystem.core.holograms.ScoreLeaderboard; import com.alpsbte.plotsystem.core.system.plot.PlotManager; import com.alpsbte.plotsystem.utils.io.language.LangUtil; import com.comphenix.protocol.ProtocolLibrary; @@ -37,7 +37,6 @@ import com.onarandombox.MultiverseCore.MultiverseCore; import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldguard.bukkit.WorldGuardPlugin; -import com.alpsbte.plotsystem.utils.io.config.ConfigPaths; import com.alpsbte.plotsystem.core.database.DatabaseConnection; import com.alpsbte.plotsystem.core.EventListener; import com.alpsbte.plotsystem.utils.io.config.ConfigNotImplementedException; @@ -52,15 +51,13 @@ import java.io.InputStream; import java.net.URL; import java.util.ArrayList; -import java.util.Arrays; import java.util.List; import java.util.Scanner; import java.util.function.Consumer; import java.util.logging.Level; public class PlotSystem extends JavaPlugin { - - private static final String VERSION = "2.3"; + private static final String VERSION = "3.0"; private static PlotSystem plugin; private ConfigUtil configManager; @@ -69,11 +66,6 @@ public class PlotSystem extends JavaPlugin { private boolean pluginEnabled = false; - private static final List holograms = Arrays.asList( - new ScoreLeaderboard(), - new PlotsLeaderboard() - ); - @Override public void onEnable() { System.setProperty("org.apache.commons.logging.Log", "org.apache.commons.logging.impl.NoOpLog"); // Disable Logging @@ -165,7 +157,7 @@ public void onEnable() { Bukkit.getConsoleSender().sendMessage(ChatColor.GOLD + "Extensions:"); if (DependencyManager.isHolographicDisplaysEnabled()) { - reloadHolograms(); + HologramManager.reloadHolograms(); Bukkit.getConsoleSender().sendMessage(ChatColor.YELLOW + "- HolographicDisplays (Leaderboards)"); } else { Bukkit.getConsoleSender().sendMessage(ChatColor.YELLOW + "No extensions enabled."); @@ -176,7 +168,7 @@ public void onEnable() { Bukkit.getConsoleSender().sendMessage(ChatColor.GOLD + "Update-Checker:"); UpdateChecker.getVersion(version -> { - if (version.equalsIgnoreCase(VERSION)) { + if (Double.parseDouble(VERSION) >= version) { Bukkit.getConsoleSender().sendMessage(ChatColor.YELLOW + "You are using the latest stable version."); } else { UpdateChecker.isUpdateAvailable = true; @@ -188,6 +180,8 @@ public void onEnable() { PlotManager.checkPlotsForLastActivity(); PlotManager.syncPlotSchematicFiles(); + Review.checkReviewerFeedbackList(); + PlotManager.startTimer(); try { new PacketListener(); @@ -214,6 +208,8 @@ public void onDisable() { Bukkit.getConsoleSender().sendMessage(ChatColor.DARK_GRAY + "> " + ChatColor.GRAY + "Made by " + ChatColor.RED + "Alps BTE (AT/CH/LI)"); Bukkit.getConsoleSender().sendMessage(ChatColor.DARK_GRAY + "> " + ChatColor.GRAY + "GitHub: " + ChatColor.WHITE + "https://github.com/AlpsBTE/Plot-System"); Bukkit.getConsoleSender().sendMessage(ChatColor.GOLD + "------------------------------------------------------"); + + HologramManager.getHolograms().forEach(HolographicDisplay::onShutdown); } } @@ -240,18 +236,6 @@ public void saveConfig() { this.configManager.saveFiles(); } - public static void reloadHolograms() { - if (DependencyManager.isHolographicDisplaysEnabled()) { - for (HolographicDisplay hologram : holograms) { - if(plugin.getConfigManager().getConfig().getBoolean(hologram.getDefaultPath() + ConfigPaths.HOLOGRAMS_ENABLED)) { - hologram.show(); - } else { - hologram.hide(); - } - } - } - } - public static PlotSystem getPlugin() { return plugin; } @@ -260,8 +244,6 @@ public CommandManager getCommandManager() { return commandManager; } - public static List getHolograms() { return holograms; } - public static class DependencyManager { @@ -309,10 +291,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 +331,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 */ @@ -348,10 +353,10 @@ public static class UpdateChecker { * Get latest plugin version from SpigotMC * @param version Returns latest stable version */ - public static void getVersion(final Consumer version) { + public static void getVersion(final Consumer version) { try (InputStream inputStream = new URL("https://api.spigotmc.org/legacy/update.php?resource=" + RESOURCE_ID).openStream(); Scanner scanner = new Scanner(inputStream)) { if (scanner.hasNext()) { - version.accept(scanner.next()); + version.accept(Double.parseDouble(scanner.next())); } } catch (IOException ex) { Bukkit.getLogger().log(Level.WARNING, "Cannot look for new updates: " + ex.getMessage()); @@ -365,4 +370,4 @@ public static boolean updateAvailable() { return isUpdateAvailable; } } -} +} \ No newline at end of file diff --git a/src/main/java/com/alpsbte/plotsystem/commands/CMD_Companion.java b/src/main/java/com/alpsbte/plotsystem/commands/CMD_Companion.java index dc2c77e9..6646b444 100644 --- a/src/main/java/com/alpsbte/plotsystem/commands/CMD_Companion.java +++ b/src/main/java/com/alpsbte/plotsystem/commands/CMD_Companion.java @@ -24,7 +24,7 @@ package com.alpsbte.plotsystem.commands; -import com.alpsbte.plotsystem.core.menus.CompanionMenu; +import com.alpsbte.plotsystem.core.menus.companion.CompanionMenu; import com.alpsbte.plotsystem.utils.Utils; import com.alpsbte.plotsystem.utils.io.language.LangPaths; import com.alpsbte.plotsystem.utils.io.language.LangUtil; @@ -37,7 +37,7 @@ public class CMD_Companion extends BaseCommand { public boolean onCommand(CommandSender sender, Command cmd, String s, String[] args) { if (sender.hasPermission(getPermission())) { if (getPlayer(sender) != null) { - new CompanionMenu((Player) sender); + CompanionMenu.open((Player) sender); } } else { sender.sendMessage(Utils.getErrorMessageFormat(LangUtil.get(sender, LangPaths.Message.Error.PLAYER_HAS_NO_PERMISSIONS))); 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..9394b633 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,14 @@ 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.core.system.plot.world.PlotWorld; 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,13 +91,13 @@ 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, Status.completed); // Convert terra coordinates to plot relative coordinates - CompletableFuture plotCoords = PlotManager.convertTerraToPlotXZ(plot, terraCoords); + CompletableFuture plotCoords = plot != null ? PlotManager.convertTerraToPlotXZ(plot, terraCoords) : null; if(plotCoords == null) { - player.sendMessage(Utils.getErrorMessageFormat(LangUtil.get(sender, LangPaths.Message.Error.CAN_ONLY_TELEPORT_TO_PLOT))); + player.sendMessage(Utils.getErrorMessageFormat(LangUtil.get(sender, LangPaths.Message.Error.CANNOT_TELEPORT_OUTSIDE_PLOT))); return true; } @@ -108,11 +111,11 @@ public boolean onCommand(CommandSender sender, Command cmd, String s, String[] a highestY = i; } } - if (highestY < 10) { - highestY = 10; + if (highestY < PlotWorld.MIN_WORLD_HEIGHT) { + highestY = PlotWorld.MIN_WORLD_HEIGHT; } - player.teleport(new Location(playerWorld, plotCoords.get()[0], highestY + 1, plotCoords.get()[1])); + player.teleport(new Location(playerWorld, plotCoords.get()[0], highestY + 1, plotCoords.get()[1], player.getLocation().getYaw(), player.getLocation().getPitch())); DecimalFormat df = new DecimalFormat("##.#####"); df.setRoundingMode(RoundingMode.FLOOR); @@ -129,7 +132,7 @@ public boolean onCommand(CommandSender sender, Command cmd, String s, String[] a sendInfo(sender); } } else { - player.sendMessage(Utils.getErrorMessageFormat(LangUtil.get(sender, LangPaths.Message.Error.CAN_ONLY_TELEPORT_TO_PLOT))); + player.sendMessage(Utils.getErrorMessageFormat(LangUtil.get(sender, LangPaths.Message.Error.CANNOT_TELEPORT_OUTSIDE_PLOT))); } } else { Bukkit.getConsoleSender().sendMessage(ChatColor.RED + "This command can only be used as a player!"); diff --git a/src/main/java/com/alpsbte/plotsystem/commands/CommandManager.java b/src/main/java/com/alpsbte/plotsystem/commands/CommandManager.java index 8f240072..64185be3 100644 --- a/src/main/java/com/alpsbte/plotsystem/commands/CommandManager.java +++ b/src/main/java/com/alpsbte/plotsystem/commands/CommandManager.java @@ -33,7 +33,7 @@ import com.alpsbte.plotsystem.commands.plot.CMD_Plot; import com.alpsbte.plotsystem.commands.review.CMD_EditPlot; import com.alpsbte.plotsystem.commands.review.CMD_Review; -import com.alpsbte.plotsystem.commands.review.CMD_SendFeedback; +import com.alpsbte.plotsystem.commands.review.CMD_EditFeedback; import com.alpsbte.plotsystem.commands.review.CMD_UndoReview; import java.util.ArrayList; @@ -54,7 +54,7 @@ public class CommandManager { // Review Commands add(new CMD_Review()); add(new CMD_UndoReview()); - add(new CMD_SendFeedback()); + add(new CMD_EditFeedback()); add(new CMD_EditPlot()); // Admin Commands diff --git a/src/main/java/com/alpsbte/plotsystem/commands/admin/CMD_PReload.java b/src/main/java/com/alpsbte/plotsystem/commands/admin/CMD_PReload.java index 7ff1f748..27252448 100644 --- a/src/main/java/com/alpsbte/plotsystem/commands/admin/CMD_PReload.java +++ b/src/main/java/com/alpsbte/plotsystem/commands/admin/CMD_PReload.java @@ -27,6 +27,7 @@ import com.alpsbte.plotsystem.PlotSystem; import com.alpsbte.plotsystem.commands.BaseCommand; import com.alpsbte.plotsystem.core.database.DatabaseConnection; +import com.alpsbte.plotsystem.core.holograms.HologramManager; import com.alpsbte.plotsystem.utils.Utils; import org.bukkit.Bukkit; import org.bukkit.command.Command; @@ -44,7 +45,7 @@ public boolean onCommand(CommandSender sender, Command cmd, String s, String[] a PlotSystem.getPlugin().getConfigManager().saveFiles(); sender.sendMessage(Utils.getInfoMessageFormat("Successfully reloaded config!")); - PlotSystem.reloadHolograms(); + HologramManager.reloadHolograms(); sender.sendMessage(Utils.getInfoMessageFormat("Successfully reloaded holograms!")); DatabaseConnection.InitializeDatabase(); @@ -77,4 +78,4 @@ public String[] getParameter() { public String getPermission() { return "plotsystem.admin.preload"; } -} +} \ No newline at end of file diff --git a/src/main/java/com/alpsbte/plotsystem/commands/admin/CMD_SetHologram.java b/src/main/java/com/alpsbte/plotsystem/commands/admin/CMD_SetHologram.java index ca46c6b2..cbdd7985 100644 --- a/src/main/java/com/alpsbte/plotsystem/commands/admin/CMD_SetHologram.java +++ b/src/main/java/com/alpsbte/plotsystem/commands/admin/CMD_SetHologram.java @@ -26,6 +26,7 @@ import com.alpsbte.plotsystem.PlotSystem; import com.alpsbte.plotsystem.commands.BaseCommand; +import com.alpsbte.plotsystem.core.holograms.HologramManager; import com.alpsbte.plotsystem.core.holograms.HolographicDisplay; import com.alpsbte.plotsystem.utils.Utils; import org.bukkit.Bukkit; @@ -44,7 +45,7 @@ public boolean onCommand(CommandSender sender, Command cmd, String s, String[] a Player player = (Player)sender; if (args.length == 1) { // Find hologram by name - HolographicDisplay hologram = PlotSystem.getHolograms().stream() + HolographicDisplay hologram = HologramManager.getHolograms().stream() .filter(holo -> holo.getHologramName().equalsIgnoreCase(args[0])) .findFirst() .orElse(null); @@ -55,14 +56,14 @@ public boolean onCommand(CommandSender sender, Command cmd, String s, String[] a player.sendMessage(Utils.getInfoMessageFormat("Successfully updated hologram location!")); player.playSound(player.getLocation(), Utils.Done,1,1); - PlotSystem.reloadHolograms(); + HologramManager.reloadHolograms(); } else { player.sendMessage(Utils.getErrorMessageFormat("Hologram could not be found!")); } } else { sendInfo(sender); player.sendMessage("§8------- §6§lHolograms §8-------"); - for(HolographicDisplay holo : PlotSystem.getHolograms()) { + for(HolographicDisplay holo : HologramManager.getHolograms()) { player.sendMessage(" §6> §f" + holo.getHologramName()); } player.sendMessage("§8--------------------------"); @@ -99,4 +100,4 @@ public String[] getParameter() { public String getPermission() { return "plotsystem.admin.sethologram"; } -} +} \ No newline at end of file diff --git a/src/main/java/com/alpsbte/plotsystem/commands/admin/setup/CMD_Setup.java b/src/main/java/com/alpsbte/plotsystem/commands/admin/setup/CMD_Setup.java index 96712afd..6f767f1e 100644 --- a/src/main/java/com/alpsbte/plotsystem/commands/admin/setup/CMD_Setup.java +++ b/src/main/java/com/alpsbte/plotsystem/commands/admin/setup/CMD_Setup.java @@ -31,6 +31,7 @@ public class CMD_Setup extends BaseCommand { public CMD_Setup() { + registerSubCommand(new CMD_Setup_BuildTeam(this)); registerSubCommand(new CMD_Setup_FTP(this)); registerSubCommand(new CMD_Setup_Server(this)); registerSubCommand(new CMD_Setup_Country(this)); @@ -66,4 +67,16 @@ public String[] getParameter() { public String getPermission() { return null; } + + public static String appendArgs(String[] args, int startIndex) { + StringBuilder name = new StringBuilder(); + for (int i = startIndex; i < args.length; i++) { + name.append(args[i]); + // Add space between words + if (i != args.length - 1) { + name.append(" "); + } + } + return name.toString(); + } } diff --git a/src/main/java/com/alpsbte/plotsystem/commands/admin/setup/CMD_Setup_BuildTeam.java b/src/main/java/com/alpsbte/plotsystem/commands/admin/setup/CMD_Setup_BuildTeam.java new file mode 100644 index 00000000..c27b8cf8 --- /dev/null +++ b/src/main/java/com/alpsbte/plotsystem/commands/admin/setup/CMD_Setup_BuildTeam.java @@ -0,0 +1,478 @@ +/* + * The MIT License (MIT) + * + * Copyright © 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.commands.admin.setup; + +import com.alpsbte.plotsystem.commands.BaseCommand; +import com.alpsbte.plotsystem.commands.SubCommand; +import com.alpsbte.plotsystem.core.system.BuildTeam; +import com.alpsbte.plotsystem.core.system.Builder; +import com.alpsbte.plotsystem.core.system.Country; +import com.alpsbte.plotsystem.utils.Utils; +import org.bukkit.Bukkit; +import org.bukkit.command.CommandSender; + +import java.sql.SQLException; +import java.util.List; +import java.util.StringJoiner; +import java.util.logging.Level; + +public class CMD_Setup_BuildTeam extends SubCommand { + public CMD_Setup_BuildTeam(BaseCommand baseCommand) { + super(baseCommand); + register(); + } + + private void register() { + registerSubCommand(new CMD_Setup_BuildTeam_List(getBaseCommand(), this)); + registerSubCommand(new CMD_Setup_BuildTeam_Add(getBaseCommand(), this)); + registerSubCommand(new CMD_Setup_BuildTeam_Remove(getBaseCommand(), this)); + registerSubCommand(new CMD_Setup_BuildTeam_SetName(getBaseCommand(), this)); + registerSubCommand(new CMD_Setup_BuildTeam_AddCountry(getBaseCommand(), this)); + registerSubCommand(new CMD_Setup_BuildTeam_RemoveCountry(getBaseCommand(), this)); + registerSubCommand(new CMD_Setup_BuildTeam_AddReviewer(getBaseCommand(), this)); + registerSubCommand(new CMD_Setup_BuildTeam_RemoveReviewer(getBaseCommand(), this)); + } + + @Override + public void onCommand(CommandSender sender, String[] args) { + sendInfo(sender); + } + + @Override + public String[] getNames() { + return new String[] { "buildteam" }; + } + + @Override + public String getDescription() { + return "Configure build teams"; + } + + @Override + public String[] getParameter() { + return new String[0]; + } + + @Override + public String getPermission() { + return "plotsystem.admin.pss.buildteam"; + } + + + + public static class CMD_Setup_BuildTeam_List extends SubCommand { + public CMD_Setup_BuildTeam_List(BaseCommand baseCommand, SubCommand subCommand) { + super(baseCommand, subCommand); + } + + @Override + public void onCommand(CommandSender sender, String[] args) { + List buildTeams = BuildTeam.getBuildTeams(); + if (buildTeams.size() != 0) { + sender.sendMessage(Utils.getInfoMessageFormat("There are currently " + buildTeams.size() + " build teams registered in the database:")); + sender.sendMessage("§8--------------------------"); + for (BuildTeam b : buildTeams) { + try { + StringJoiner countriesAsString = new StringJoiner(", "); + StringJoiner reviewersAsString = new StringJoiner(", "); + b.getCountries().forEach(c -> countriesAsString.add(String.valueOf(c.getID()))); + b.getReviewers().forEach(r -> { try { reviewersAsString.add(r.getName()); } catch (SQLException ex) { Bukkit.getLogger().log(Level.SEVERE, "A SQL error occurred!", ex); }}); + sender.sendMessage(" §6> §b" + b.getID() + " (" + b.getName() + ") §f- Country IDs: " + (countriesAsString.length() == 0 ? "No Countries" : countriesAsString) + " - Reviewers: " + (reviewersAsString.length() == 0 ? "No Reviewers" : reviewersAsString)); + } catch (SQLException ex) { + sender.sendMessage(Utils.getErrorMessageFormat("An error occurred while executing command!")); + Bukkit.getLogger().log(Level.SEVERE, "A SQL error occurred!", ex); + } + } + sender.sendMessage("§8--------------------------"); + } else { + sender.sendMessage(Utils.getInfoMessageFormat("There are currently no build teams registered in the database!")); + } + } + + @Override + public String[] getNames() { + return new String[] { "list" }; + } + + @Override + public String getDescription() { + return null; + } + + @Override + public String[] getParameter() { + return new String[0]; + } + + @Override + public String getPermission() { + return "plotsystem.admin.pss.buildteam.list"; + } + } + + public static class CMD_Setup_BuildTeam_Add extends SubCommand { + public CMD_Setup_BuildTeam_Add(BaseCommand baseCommand, SubCommand subCommand) { + super(baseCommand, subCommand); + } + + @Override + public void onCommand(CommandSender sender, String[] args) { + if (args.length > 1) { + if (args[1].length() <= 45) { + try { + String name = CMD_Setup.appendArgs(args, 1); + BuildTeam.addBuildTeam(name); + sender.sendMessage(Utils.getInfoMessageFormat("Successfully added build team with name '" + name + "'!")); + } catch (SQLException ex) { + sender.sendMessage(Utils.getErrorMessageFormat("An error occurred while executing command!")); + Bukkit.getLogger().log(Level.SEVERE, "A SQL error occurred!", ex); + return; + } + } else { + sender.sendMessage(Utils.getErrorMessageFormat("Build team name cannot be longer than 45 characters!")); + } + return; + } + sendInfo(sender); + } + + @Override + public String[] getNames() { + return new String[] { "add" }; + } + + @Override + public String getDescription() { + return null; + } + + @Override + public String[] getParameter() { + return new String[] { "Name" }; + } + + @Override + public String getPermission() { + return "plotsystem.admin.pss.buildteam.add"; + } + } + + public static class CMD_Setup_BuildTeam_Remove extends SubCommand { + public CMD_Setup_BuildTeam_Remove(BaseCommand baseCommand, SubCommand subCommand) { + super(baseCommand, subCommand); + } + + @Override + public void onCommand(CommandSender sender, String[] args) { + if (args.length > 1 && Utils.TryParseInt(args[1]) != null) { + // Check if build team exists + try { + if (BuildTeam.getBuildTeams().stream().anyMatch(b -> b.getID() == Integer.parseInt(args[1]))) { + BuildTeam.removeBuildTeam(Integer.parseInt(args[1])); + sender.sendMessage(Utils.getInfoMessageFormat("Successfully removed build team with ID " + args[1] + "!")); + } else { + sender.sendMessage(Utils.getErrorMessageFormat("Could not find any build team with ID " + args[1] + "!")); + sendInfo(sender); + } + } catch (SQLException ex) { + sender.sendMessage(Utils.getErrorMessageFormat("An error occurred while executing command!")); + Bukkit.getLogger().log(Level.SEVERE, "A SQL error occurred!", ex); + } + return; + } + sendInfo(sender); + } + + @Override + public String[] getNames() { + return new String[] { "remove" }; + } + + @Override + public String getDescription() { + return null; + } + + @Override + public String[] getParameter() { + return new String[] { "BuildTeam-ID" }; + } + + @Override + public String getPermission() { + return "plotsystem.admin.pss.buildteam.remove"; + } + } + + public static class CMD_Setup_BuildTeam_SetName extends SubCommand { + public CMD_Setup_BuildTeam_SetName(BaseCommand baseCommand, SubCommand subCommand) { + super(baseCommand, subCommand); + } + + @Override + public void onCommand(CommandSender sender, String[] args) { + if (args.length > 2 && Utils.TryParseInt(args[1]) != null) { + // Check if build team exits + try { + if (BuildTeam.getBuildTeams().stream().anyMatch(b -> b.getID() == Integer.parseInt(args[1]))) { + String name = CMD_Setup.appendArgs(args, 2); + if (name.length() <= 45) { + BuildTeam.setBuildTeamName(Integer.parseInt(args[1]), name); + sender.sendMessage(Utils.getInfoMessageFormat("Successfully changed name of build team with ID " + args[1] + " to '" + name + "'!")); + } else { + sender.sendMessage(Utils.getErrorMessageFormat("Build team name cannot be longer than 45 characters!")); + } + return; + } + } catch (SQLException ex) { + sender.sendMessage(Utils.getErrorMessageFormat("An error occurred while executing command!")); + Bukkit.getLogger().log(Level.SEVERE, "A SQL error occurred!", ex); + return; + } + } + sendInfo(sender); + } + + @Override + public String[] getNames() { + return new String[] { "setname" }; + } + + @Override + public String getDescription() { + return null; + } + + @Override + public String[] getParameter() { + return new String[] { "BuildTeam-ID", "Name" }; + } + + @Override + public String getPermission() { + return "plotsystem.admin.pss.buildteam.setname"; + } + } + + public static class CMD_Setup_BuildTeam_AddCountry extends SubCommand { + public CMD_Setup_BuildTeam_AddCountry(BaseCommand baseCommand, SubCommand subCommand) { + super(baseCommand, subCommand); + } + + @Override + public void onCommand(CommandSender sender, String[] args) { + if (args.length > 2 && Utils.TryParseInt(args[1]) != null && Utils.TryParseInt(args[2]) != null) { + // Check if build team and country exists + try { + if (BuildTeam.getBuildTeams().stream().anyMatch(b -> b.getID() == Integer.parseInt(args[1]))) { + if (Country.getCountries().stream().anyMatch(c -> c.getID() == Integer.parseInt(args[2]))) { + Country country = new Country(Integer.parseInt(args[2])); + BuildTeam.addCountry(Integer.parseInt(args[1]), country.getID()); + sender.sendMessage(Utils.getInfoMessageFormat("Successfully added country '" + country.getName() + "' to build team with ID " + args[1] + "!")); + } else { + sender.sendMessage(Utils.getErrorMessageFormat("Country could not be found or is already added to the build team!")); + } + return; + } + } catch (SQLException ex) { + sender.sendMessage(Utils.getErrorMessageFormat("An error occurred while executing command!")); + Bukkit.getLogger().log(Level.SEVERE, "A SQL error occurred!", ex); + return; + } + } + sendInfo(sender); + } + + @Override + public String[] getNames() { + return new String[] { "addcountry" }; + } + + @Override + public String getDescription() { + return null; + } + + @Override + public String[] getParameter() { + return new String[] { "BuildTeam-ID", "Country-ID" }; + } + + @Override + public String getPermission() { + return "plotsystem.admin.pss.buildteam.addcountry"; + } + } + + public static class CMD_Setup_BuildTeam_RemoveCountry extends SubCommand { + public CMD_Setup_BuildTeam_RemoveCountry(BaseCommand baseCommand, SubCommand subCommand) { + super(baseCommand, subCommand); + } + + @Override + public void onCommand(CommandSender sender, String[] args) { + if (args.length > 2 && Utils.TryParseInt(args[1]) != null && Utils.TryParseInt(args[2]) != null) { + // Check if build team and country exists + try { + if (BuildTeam.getBuildTeams().stream().anyMatch(b -> b.getID() == Integer.parseInt(args[1]))) { + if (Country.getCountries().stream().anyMatch(c -> c.getID() == Integer.parseInt(args[2]))) { + Country country = new Country(Integer.parseInt(args[2])); + BuildTeam.removeCountry(Integer.parseInt(args[1]), country.getID()); + sender.sendMessage(Utils.getInfoMessageFormat("Successfully removed country '" + country.getName() + "' from build team with ID " + args[1] + "!")); + } else { + sender.sendMessage(Utils.getErrorMessageFormat("Country could not be found or is not added to the build team!")); + } + return; + } + } catch (SQLException ex) { + sender.sendMessage(Utils.getErrorMessageFormat("An error occurred while executing command!")); + Bukkit.getLogger().log(Level.SEVERE, "A SQL error occurred!", ex); + return; + } + } + sendInfo(sender); + } + + @Override + public String[] getNames() { + return new String[] { "removecountry" }; + } + + @Override + public String getDescription() { + return null; + } + + @Override + public String[] getParameter() { + return new String[] { "BuildTeam-ID", "Country-ID" }; + } + + @Override + public String getPermission() { + return "plotsystem.admin.pss.buildteam.removecountry"; + } + } + + public static class CMD_Setup_BuildTeam_AddReviewer extends SubCommand { + public CMD_Setup_BuildTeam_AddReviewer(BaseCommand baseCommand, SubCommand subCommand) { + super(baseCommand, subCommand); + } + + @Override + public void onCommand(CommandSender sender, String[] args) { + if (args.length > 2 && Utils.TryParseInt(args[1]) != null) { + // Check if build team exits + try { + if (BuildTeam.getBuildTeams().stream().anyMatch(b -> b.getID() == Integer.parseInt(args[1]))) { + Builder builder = Builder.getBuilderByName(args[2]); + if (builder != null && BuildTeam.getBuildTeamsByReviewer(builder.getUUID()).stream().noneMatch(b -> b.getID() == Integer.parseInt(args[1]))) { + BuildTeam.addReviewer(Integer.parseInt(args[1]), builder.getUUID().toString()); + sender.sendMessage(Utils.getInfoMessageFormat("Successfully added '" + builder.getName() + "' as reviewer to build team with ID " + args[1] + "!")); + } else { + sender.sendMessage(Utils.getErrorMessageFormat("Player could not be found or is already reviewer for this build team!")); + } + return; + } + } catch (SQLException ex) { + sender.sendMessage(Utils.getErrorMessageFormat("An error occurred while executing command!")); + Bukkit.getLogger().log(Level.SEVERE, "A SQL error occurred!", ex); + return; + } + } + sendInfo(sender); + } + + @Override + public String[] getNames() { + return new String[] { "addreviewer" }; + } + + @Override + public String getDescription() { + return null; + } + + @Override + public String[] getParameter() { + return new String[] { "BuildTeam-ID", "Name" }; + } + + @Override + public String getPermission() { + return "plotsystem.admin.pss.buildteam.addreviewer"; + } + } + + public static class CMD_Setup_BuildTeam_RemoveReviewer extends SubCommand { + public CMD_Setup_BuildTeam_RemoveReviewer(BaseCommand baseCommand, SubCommand subCommand) { + super(baseCommand, subCommand); + } + + @Override + public void onCommand(CommandSender sender, String[] args) { + if (args.length > 2 && Utils.TryParseInt(args[1]) != null) { + // Check if build team exits + try { + if (BuildTeam.getBuildTeams().stream().anyMatch(b -> b.getID() == Integer.parseInt(args[1]))) { + Builder builder = Builder.getBuilderByName(args[2]); + if (builder != null && BuildTeam.getBuildTeamsByReviewer(builder.getUUID()).stream().anyMatch(b -> b.getID() == Integer.parseInt(args[1]))) { + BuildTeam.removeReviewer(Integer.parseInt(args[1]), builder.getUUID().toString()); + sender.sendMessage(Utils.getInfoMessageFormat("Successfully removed '" + builder.getName() + "' as reviewer from build team with ID " + args[1] + "!")); + } else { + sender.sendMessage(Utils.getErrorMessageFormat("Player could not be found or is not a reviewer for this build team!")); + } + return; + } + } catch (SQLException ex) { + sender.sendMessage(Utils.getErrorMessageFormat("An error occurred while executing command!")); + Bukkit.getLogger().log(Level.SEVERE, "A SQL error occurred!", ex); + return; + } + } + sendInfo(sender); + } + + @Override + public String[] getNames() { + return new String[] { "removereviewer" }; + } + + @Override + public String getDescription() { + return null; + } + + @Override + public String[] getParameter() { + return new String[] { "BuildTeam-ID", "Name" }; + } + + @Override + public String getPermission() { + return "plotsystem.admin.pss.buildteam.removereviewer"; + } + } +} diff --git a/src/main/java/com/alpsbte/plotsystem/commands/admin/setup/CMD_Setup_City.java b/src/main/java/com/alpsbte/plotsystem/commands/admin/setup/CMD_Setup_City.java index d0c224ed..4f4d37de 100644 --- a/src/main/java/com/alpsbte/plotsystem/commands/admin/setup/CMD_Setup_City.java +++ b/src/main/java/com/alpsbte/plotsystem/commands/admin/setup/CMD_Setup_City.java @@ -135,7 +135,7 @@ public void onCommand(CommandSender sender, String[] args) { if (args.length > 2 && Utils.TryParseInt(args[1]) != null) { Country country = Country.getCountries().stream().filter(c -> c.getID() == Integer.parseInt(args[1])).findFirst().orElse(null); if (country != null) { - String name = appendArgs(args,2); + String name = CMD_Setup.appendArgs(args,2); if (name.length() <= 45) { try { CityProject.addCityProject(country, name); @@ -237,7 +237,7 @@ public void onCommand(CommandSender sender, String[] args) { // Check if City Project exits try { if (CityProject.getCityProjects(false).stream().anyMatch(c -> c.getID() == Integer.parseInt(args[1]))) { - String name = appendArgs(args,2); + String name = CMD_Setup.appendArgs(args,2); if (name.length() <= 45) { CityProject.setCityProjectName(Integer.parseInt(args[1]), name); sender.sendMessage(Utils.getInfoMessageFormat("Successfully changed name of City Project with ID " + args[1] + " to '" + name + "'!")); @@ -287,7 +287,7 @@ public void onCommand(CommandSender sender, String[] args) { // Check if City Project exits try { if (CityProject.getCityProjects(false).stream().anyMatch(c -> c.getID() == Integer.parseInt(args[1]))) { - String description = appendArgs(args,2); + String description = CMD_Setup.appendArgs(args,2); if (description.length() <= 255) { CityProject.setCityProjectDescription(Integer.parseInt(args[1]), description); sender.sendMessage(Utils.getInfoMessageFormat("Successfully set description of City Project with ID " + args[1] + " to '" + description + "'!")); @@ -372,16 +372,4 @@ public String getPermission() { return "plotsystem.admin.pss.city.setvisible"; } } - - private static String appendArgs(String[] args, int startIndex) { - StringBuilder name = new StringBuilder(); - for (int i = startIndex; i < args.length; i++) { - name.append(args[i]); - // Add space between words - if (i != args.length - 1) { - name.append(" "); - } - } - return name.toString(); - } } diff --git a/src/main/java/com/alpsbte/plotsystem/commands/admin/setup/CMD_Setup_Country.java b/src/main/java/com/alpsbte/plotsystem/commands/admin/setup/CMD_Setup_Country.java index 876be0c5..ca94574e 100644 --- a/src/main/java/com/alpsbte/plotsystem/commands/admin/setup/CMD_Setup_Country.java +++ b/src/main/java/com/alpsbte/plotsystem/commands/admin/setup/CMD_Setup_Country.java @@ -28,10 +28,12 @@ import com.alpsbte.plotsystem.commands.SubCommand; import com.alpsbte.plotsystem.core.system.Country; import com.alpsbte.plotsystem.utils.Utils; +import com.alpsbte.plotsystem.utils.enums.Continent; import org.bukkit.Bukkit; import org.bukkit.command.CommandSender; import java.sql.SQLException; +import java.util.Arrays; import java.util.List; import java.util.logging.Level; @@ -128,10 +130,17 @@ public CMD_Setup_Country_Add(BaseCommand baseCommand, SubCommand subCommand) { @Override public void onCommand(CommandSender sender, String[] args) { - if (args.length > 2 && Utils.TryParseInt(args[1]) != null) { + if (args.length > 3 && Utils.TryParseInt(args[1]) != null) { if (args[2].length() <= 45) { + Continent continent; try { - Country.addCountry(Integer.parseInt(args[1]), args[2]); + continent = Continent.valueOf(args[3].toUpperCase()); + }catch(IllegalArgumentException e) { + sender.sendMessage(Utils.getErrorMessageFormat("Unknown continent! " + Arrays.toString(Continent.values()))); + return; + } + try { + Country.addCountry(Integer.parseInt(args[1]), args[2], continent); sender.sendMessage(Utils.getInfoMessageFormat("Successfully added country!")); } catch (SQLException ex) { sender.sendMessage(Utils.getErrorMessageFormat("An error occurred while executing command!")); @@ -157,7 +166,7 @@ public String getDescription() { @Override public String[] getParameter() { - return new String[] { "Server-ID", "Name" }; + return new String[] { "Server-ID", "Name", "Continent" }; } @Override 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_SendFeedback.java b/src/main/java/com/alpsbte/plotsystem/commands/review/CMD_EditFeedback.java similarity index 93% rename from src/main/java/com/alpsbte/plotsystem/commands/review/CMD_SendFeedback.java rename to src/main/java/com/alpsbte/plotsystem/commands/review/CMD_EditFeedback.java index 68071814..0569572b 100644 --- a/src/main/java/com/alpsbte/plotsystem/commands/review/CMD_SendFeedback.java +++ b/src/main/java/com/alpsbte/plotsystem/commands/review/CMD_EditFeedback.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 @@ -38,7 +38,7 @@ import java.sql.SQLException; import java.util.logging.Level; -public class CMD_SendFeedback extends BaseCommand { +public class CMD_EditFeedback extends BaseCommand { @Override public boolean onCommand(CommandSender sender, Command cmd, String s, String[] args) { @@ -81,21 +81,21 @@ public boolean onCommand(CommandSender sender, Command cmd, String s, String[] a @Override public String[] getNames() { - return new String[] { "sendFeedback" }; + return new String[] { "editfeedback" }; } @Override public String getDescription() { - return "Updates feedback of a plot."; + return "Updates the feedback of a plot."; } @Override public String[] getParameter() { - return new String[] { "ID", "Name" }; + return new String[] { "ID", "Feedback" }; } @Override public String getPermission() { - return "plotsystem.review.sendfeedback"; + return "plotsystem.review.editfeedback"; } } 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..addb8343 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 @@ -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 @@ -26,13 +26,16 @@ 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; import com.alpsbte.plotsystem.utils.io.language.LangPaths; import com.alpsbte.plotsystem.utils.io.language.LangUtil; import org.bukkit.Bukkit; +import org.bukkit.ChatColor; import org.bukkit.command.Command; import org.bukkit.command.CommandSender; @@ -43,41 +46,53 @@ public class CMD_EditPlot extends BaseCommand { @Override public boolean onCommand(CommandSender sender, Command cmd, String s, String[] args) { - if (PlotSystem.getPlugin().getConfigManager().getCommandsConfig().getBoolean(ConfigPaths.EDITPLOT_ENABLED)) { - if(sender.hasPermission(getPermission())) { - try { - Plot plot; - if (args.length > 0 && Utils.TryParseInt(args[0]) != null) { - int plotID = Integer.parseInt(args[0]); - if (PlotManager.plotExists(plotID)) { - plot = new Plot(plotID); + if (getPlayer(sender) != null) { + if (PlotSystem.getPlugin().getConfigManager().getCommandsConfig().getBoolean(ConfigPaths.EDITPLOT_ENABLED)) { + if (sender.hasPermission(getPermission())) { + try { + Plot plot; + if (args.length > 0 && Utils.TryParseInt(args[0]) != null) { + int plotID = Integer.parseInt(args[0]); + if (PlotManager.plotExists(plotID)) { + plot = new Plot(plotID); + } else { + sender.sendMessage(Utils.getErrorMessageFormat(LangUtil.get(sender, LangPaths.Message.Error.PLOT_DOES_NOT_EXIST))); + return true; + } + } else if (getPlayer(sender) != null && PlotManager.isPlotWorld(getPlayer(sender).getWorld())) { + plot = PlotManager.getCurrentPlot(Builder.byUUID(getPlayer(sender).getUniqueId()), Status.unfinished, Status.unreviewed); } else { - sender.sendMessage(Utils.getErrorMessageFormat(LangUtil.get(sender, LangPaths.Message.Error.PLOT_DOES_NOT_EXIST))); + sendInfo(sender); return true; } - } else if (getPlayer(sender) != null && PlotManager.isPlotWorld(getPlayer(sender).getWorld())) { - plot = PlotManager.getPlotByWorld(getPlayer(sender).getWorld()); - } else { - sendInfo(sender); - return true; - } - if(plot.getPermissions().hasReviewerPerms()) { - plot.getPermissions().removeReviewerPerms().save(); - sender.sendMessage(Utils.getInfoMessageFormat(LangUtil.get(sender, LangPaths.Message.Info.DISABLED_PLOT_PERMISSIONS,plot.getID() + ""))); - } else { - plot.getPermissions().addReviewerPerms().save(); - sender.sendMessage(Utils.getInfoMessageFormat(LangUtil.get(sender, LangPaths.Message.Info.ENABLED_PLOT_PERMISSIONS, plot.getID() + ""))); + if (plot != null && plot.getStatus() != Status.completed) { + Builder builder = Builder.byUUID(getPlayer(sender).getUniqueId()); + int countryID = plot.getCity().getCountry().getID(); + if (builder.isReviewer() && builder.getAsReviewer().getCountries().stream().anyMatch(c -> c.getID() == countryID) && plot.getPlotOwner().getUUID() != builder.getUUID() && plot.getPlotMembers().stream().noneMatch(b -> b.getUUID() == builder.getUUID())) { + if (plot.getPermissions().hasBuildingPerms(builder.getUUID())) { + plot.getPermissions().removeBuilderPerms(builder.getUUID()).save(); + sender.sendMessage(Utils.getInfoMessageFormat(LangUtil.get(sender, LangPaths.Message.Info.DISABLED_PLOT_PERMISSIONS, plot.getID() + ""))); + } else { + plot.getPermissions().addBuilderPerms(builder.getUUID()).save(); + sender.sendMessage(Utils.getInfoMessageFormat(LangUtil.get(sender, LangPaths.Message.Info.ENABLED_PLOT_PERMISSIONS, plot.getID() + ""))); + } + return true; + } + } + sender.sendMessage(Utils.getErrorMessageFormat(LangUtil.get(sender, LangPaths.Message.Error.PLAYER_IS_NOT_ALLOWED))); + } 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); } - } 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); + } else { + sender.sendMessage(Utils.getErrorMessageFormat(LangUtil.get(sender, LangPaths.Message.Error.PLAYER_HAS_NO_PERMISSIONS))); } } else { - sender.sendMessage(Utils.getErrorMessageFormat(LangUtil.get(sender, LangPaths.Message.Error.PLAYER_HAS_NO_PERMISSIONS))); + sender.sendMessage(Utils.getErrorMessageFormat(LangUtil.get(sender, LangPaths.Message.Error.COMMAND_DISABLED))); } } else { - sender.sendMessage(Utils.getErrorMessageFormat(LangUtil.get(sender, LangPaths.Message.Error.COMMAND_DISABLED))); + Bukkit.getConsoleSender().sendMessage(ChatColor.RED + "This command can only be used as a player!"); } 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..7ea25c67 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 @@ -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 @@ -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; @@ -44,24 +46,29 @@ public class CMD_Review extends BaseCommand { @Override public boolean onCommand(CommandSender sender, Command cmd, String s, String[] args) { - if (sender.hasPermission(getPermission())) { - if (getPlayer(sender) != null) { - try { + if (getPlayer(sender) != null) { + try { + if (sender.hasPermission(getPermission())) { + Builder.Reviewer builder = Builder.byUUID(getPlayer(sender).getUniqueId()).getAsReviewer(); 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) { + int countryID = plot.getCity().getCountry().getID(); + if (plot.getStatus() == Status.unreviewed && builder.getCountries().stream().anyMatch(c -> c.getID() == countryID)) { + new ReviewPlotMenu(player, plot); + return true; + } } - } 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); + new ReviewMenu(player); + } else { + sender.sendMessage(Utils.getErrorMessageFormat(LangUtil.get(sender, LangPaths.Message.Error.PLAYER_HAS_NO_PERMISSIONS))); } - } else { - Bukkit.getConsoleSender().sendMessage(ChatColor.RED + "This command can only be used as a 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); } } else { - sender.sendMessage(Utils.getErrorMessageFormat(LangUtil.get(sender, LangPaths.Message.Error.PLAYER_HAS_NO_PERMISSIONS))); + Bukkit.getConsoleSender().sendMessage(ChatColor.RED + "This command can only be used as a player!"); } return true; } diff --git a/src/main/java/com/alpsbte/plotsystem/core/EventListener.java b/src/main/java/com/alpsbte/plotsystem/core/EventListener.java index b2ad7ca4..d9d14e8d 100644 --- a/src/main/java/com/alpsbte/plotsystem/core/EventListener.java +++ b/src/main/java/com/alpsbte/plotsystem/core/EventListener.java @@ -25,15 +25,19 @@ package com.alpsbte.plotsystem.core; import com.alpsbte.plotsystem.PlotSystem; +import com.alpsbte.plotsystem.core.system.Review; +import com.alpsbte.plotsystem.core.system.plot.world.PlotWorld; +import com.alpsbte.plotsystem.core.menus.companion.CompanionMenu; import com.alpsbte.plotsystem.utils.io.config.ConfigPaths; import com.alpsbte.plotsystem.core.system.plot.PlotManager; -import com.alpsbte.plotsystem.core.menus.CompanionMenu; import com.alpsbte.plotsystem.core.menus.ReviewMenu; import com.alpsbte.plotsystem.core.database.DatabaseConnection; import com.alpsbte.plotsystem.core.system.plot.Plot; import com.alpsbte.plotsystem.core.system.plot.PlotHandler; import com.alpsbte.plotsystem.core.system.Builder; import com.alpsbte.plotsystem.core.system.plot.generator.DefaultPlotGenerator; +import com.alpsbte.plotsystem.utils.io.language.LangPaths; +import com.alpsbte.plotsystem.utils.io.language.LangUtil; import com.alpsbte.plotsystem.utils.items.SpecialBlocks; import com.alpsbte.plotsystem.utils.Utils; import com.alpsbte.plotsystem.utils.enums.Status; @@ -49,6 +53,7 @@ import org.bukkit.entity.EntityType; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; import org.bukkit.event.block.Action; import org.bukkit.event.block.BlockPlaceEvent; @@ -62,6 +67,7 @@ import java.sql.SQLException; import java.util.ArrayList; import java.util.List; +import java.util.UUID; import java.util.logging.Level; public class EventListener extends SpecialBlocks implements Listener { @@ -100,8 +106,8 @@ public void onPlayerJoinEvent(PlayerJoinEvent event) { } // Check if player has changed his name + Builder builder = Builder.byUUID(event.getPlayer().getUniqueId()); try { - Builder builder = new Builder(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 +118,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, Status.completed, Status.unfinished); List reviewedPlots = new ArrayList<>(); for(Plot plot : plots) { @@ -132,7 +138,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, Status.unfinished); if(plots.size() >= 1) { PlotHandler.sendUnfinishedPlotReminderMessage(plots, event.getPlayer()); event.getPlayer().sendMessage(""); @@ -142,16 +148,16 @@ public void onPlayerJoinEvent(PlayerJoinEvent event) { } // Informing reviewer about new reviews - if(event.getPlayer().hasPermission("plotsystem.review")) { - try { - List unreviewedPlots = PlotManager.getPlots(Status.unreviewed); + try { + if(event.getPlayer().hasPermission("plotsystem.review") && builder.isReviewer()) { + List unreviewedPlots = PlotManager.getPlots(builder.getAsReviewer().getCountries(), Status.unreviewed); if(unreviewedPlots.size() != 0) { PlotHandler.sendUnreviewedPlotsReminderMessage(unreviewedPlots, event.getPlayer()); } - } catch (Exception ex) { - Bukkit.getLogger().log(Level.SEVERE,"An error occurred while trying to inform the player about unreviewed plots!", ex); } + } catch (Exception ex) { + Bukkit.getLogger().log(Level.SEVERE,"An error occurred while trying to inform the player about unreviewed plots!", ex); } }); } @@ -196,36 +202,29 @@ 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()); + Review.awaitReviewerFeedbackList.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())) { @@ -288,6 +287,27 @@ public void onPlayerBlockPlaceEvent(BlockPlaceEvent event) { } } + @EventHandler(priority = EventPriority.HIGHEST) + public void onPlayerChatEvent(AsyncPlayerChatEvent event) throws SQLException { + UUID playerUUID = event.getPlayer().getUniqueId(); + if (Review.awaitReviewerFeedbackList.containsKey(playerUUID)) { + event.setCancelled(true); + String feedback = event.getMessage(); + + if (!feedback.equalsIgnoreCase("cancel")) { + Review review = Review.awaitReviewerFeedbackList.get(playerUUID).getReview(); + review.setFeedback(feedback); + Review.awaitReviewerFeedbackList.remove(playerUUID); + event.getPlayer().sendMessage(Utils.getInfoMessageFormat(LangUtil.get(event.getPlayer(), LangPaths.Message.Info.UPDATED_PLOT_FEEDBACK, String.valueOf(review.getPlotID())))); + event.getPlayer().playSound(event.getPlayer().getLocation(), Utils.FinishPlotSound, 1f, 1f); + } else { + Review.awaitReviewerFeedbackList.remove(playerUUID); + event.getPlayer().sendMessage(Utils.getErrorMessageFormat(LangUtil.get(event.getPlayer(), LangPaths.Message.Error.FEEDBACK_INPUT_EXPIRED))); + event.getPlayer().playSound(event.getPlayer().getLocation(), Utils.ErrorSound, 1f, 1f); + } + } + } + @EventHandler public void onDatabaseLoad(DatabaseLoadEvent event) { Utils.CustomHead.loadHeadsAsync(new HeadDatabaseAPI()); 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..e75b38e3 100644 --- a/src/main/java/com/alpsbte/plotsystem/core/database/DatabaseConnection.java +++ b/src/main/java/com/alpsbte/plotsystem/core/database/DatabaseConnection.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 @@ -72,7 +72,7 @@ public static void InitializeDatabase() throws ClassNotFoundException, SQLExcept dataSource = new HikariDataSource(config); createTables(); -} + } @Deprecated public static Connection getConnection() { @@ -94,8 +94,8 @@ public static StatementBuilder createStatement(String sql) { public static void closeResultSet(ResultSet resultSet) throws SQLException { if(resultSet.isClosed() - && resultSet.getStatement().isClosed() - && resultSet.getStatement().getConnection().isClosed()) + && resultSet.getStatement().isClosed() + && resultSet.getStatement().getConnection().isClosed()) return; resultSet.close(); @@ -104,8 +104,10 @@ public static void closeResultSet(ResultSet resultSet) throws SQLException { connectionClosed++; - if(connectionOpened > connectionClosed + 5) + if(connectionOpened > connectionClosed + 5) { Bukkit.getLogger().log(Level.SEVERE, "There are multiple database connections opened. Please report this issue."); + Bukkit.getLogger().log(Level.SEVERE, "Connections Open: " + (connectionOpened - connectionClosed)); + } } private static void createDatabase() throws SQLException { @@ -132,7 +134,7 @@ private static void createTables() { } } } catch (SQLException ex) { - Bukkit.getLogger().log(Level.SEVERE, "An error occurred while creating database table!"); + Bukkit.getLogger().log(Level.SEVERE, "An error occurred while creating database table!", ex); } } @@ -244,6 +246,7 @@ public static List getTables() { "KEY `fkIdx_38` (`server_id`)," + "CONSTRAINT `FK_37` FOREIGN KEY `fkIdx_38` (`server_id`) REFERENCES `plotsystem_servers` (`id`)" + ");", + "ALTER TABLE plotsystem_countries ADD COLUMN IF NOT EXISTS `continent` enum('europe', 'asia', 'africa', 'oceania', 'south america', 'north america') NOT NULL;", // City Projects "CREATE TABLE IF NOT EXISTS `plotsystem_city_projects`" + @@ -263,14 +266,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 +327,73 @@ 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;", + + // API Keys + "CREATE TABLE IF NOT EXISTS `plotsystem_api_keys`" + + "(" + + " `id` int NOT NULL AUTO_INCREMENT ," + + " `api_key` varchar(32) NOT NULL ," + + " `created_at` timestamp NOT NULL ," + + "PRIMARY KEY (`id`)" + + ");", + // Build-Teams + "CREATE TABLE IF NOT EXISTS `plotsystem_buildteams` (" + + "`id` INT(11) NOT NULL AUTO_INCREMENT," + + "`name` VARCHAR(45) NOT NULL COLLATE 'utf8mb4_general_ci'," + + "`api_key_id` VARCHAR(32) NULL DEFAULT NULL COLLATE 'utf8mb4_general_ci'," + + "PRIMARY KEY (`id`) USING BTREE," + + "INDEX `FK_132` (`api_key_id`) USING BTREE," + + "CONSTRAINT `FK_130` FOREIGN KEY (`api_key_id`) REFERENCES `plotsystem_test`.`api_keys` (`api_key`) ON UPDATE RESTRICT ON DELETE RESTRICT" + + ")" + + "COLLATE='utf8mb4_general_ci'" + + "ENGINE=InnoDB" + + ";", + + // Build-Team has Countries + "CREATE TABLE IF NOT EXISTS `plotsystem_buildteam_has_countries` (" + + "`id` INT(11) NOT NULL AUTO_INCREMENT," + + "`country_id` INT(11) NOT NULL," + + "`buildteam_id` INT(11) NOT NULL," + + "PRIMARY KEY (`id`) USING BTREE," + + "INDEX `FK_115` (`buildteam_id`) USING BTREE," + + "INDEX `FK_118` (`country_id`) USING BTREE," + + "CONSTRAINT `FK_113` FOREIGN KEY (`buildteam_id`) REFERENCES `plotsystem_test`.`plotsystem_buildteams` (`id`) ON UPDATE RESTRICT ON DELETE RESTRICT," + + "CONSTRAINT `FK_116` FOREIGN KEY (`country_id`) REFERENCES `plotsystem_test`.`plotsystem_countries` (`id`) ON UPDATE RESTRICT ON DELETE RESTRICT" + + ")" + + "COLLATE='utf8mb4_general_ci'" + + "ENGINE=InnoDB" + + ";", + + // Builder Is Reviewer + "CREATE TABLE IF NOT EXISTS `plotsystem_builder_is_reviewer` (" + + "`id` INT(11) NOT NULL AUTO_INCREMENT," + + "`builder_uuid` VARCHAR(36) NOT NULL COLLATE 'utf8mb4_general_ci'," + + "`buildteam_id` INT(11) NOT NULL," + + "PRIMARY KEY (`id`) USING BTREE," + + "INDEX `FK_138` (`builder_uuid`) USING BTREE," + + "INDEX `FK_141` (`buildteam_id`) USING BTREE," + + "CONSTRAINT `FK_136` FOREIGN KEY (`builder_uuid`) REFERENCES `plotsystem_test`.`plotsystem_builders` (`uuid`) ON UPDATE RESTRICT ON DELETE RESTRICT," + + "CONSTRAINT `FK_139` FOREIGN KEY (`buildteam_id`) REFERENCES `plotsystem_test`.`plotsystem_buildteams` (`id`) ON UPDATE RESTRICT ON DELETE RESTRICT" + + ")" + + "COLLATE='utf8mb4_general_ci'" + + "ENGINE=InnoDB" + + ";", + + // Payouts + "CREATE TABLE IF NOT EXISTS `plotsystem_payouts` (" + + "`id` INT(11) NOT NULL AUTO_INCREMENT," + + "`timeframe` ENUM('DAILY','WEEKLY','MONTHLY','YEARLY') NOT NULL COLLATE 'utf8mb4_general_ci'," + + "`position` INT(11) NOT NULL COMMENT 'position on the leaderboard for this timeframe'," + + "`payout_amount` VARCHAR(100) NOT NULL COLLATE 'utf8mb4_general_ci'," + + "PRIMARY KEY (`id`) USING BTREE" + + ")" + + "COLLATE='utf8mb4_general_ci'" + + "ENGINE=InnoDB" + + ";" ); } } diff --git a/src/main/java/com/alpsbte/plotsystem/core/holograms/HologramManager.java b/src/main/java/com/alpsbte/plotsystem/core/holograms/HologramManager.java new file mode 100644 index 00000000..1e59df77 --- /dev/null +++ b/src/main/java/com/alpsbte/plotsystem/core/holograms/HologramManager.java @@ -0,0 +1,63 @@ +/* + * 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.holograms; + +import com.alpsbte.plotsystem.PlotSystem; +import com.alpsbte.plotsystem.utils.io.config.ConfigPaths; + +import java.util.Arrays; +import java.util.List; + +public class HologramManager { + private static final List holograms = Arrays.asList( + new ScoreLeaderboard(), + new PlotsLeaderboard() + ); + + public static void reloadHolograms() { + if (PlotSystem.DependencyManager.isHolographicDisplaysEnabled()) { + for (HolographicDisplay hologram : holograms) { + if (PlotSystem.getPlugin().getConfigManager().getConfig().getBoolean(hologram.getDefaultPath() + ConfigPaths.HOLOGRAMS_ENABLED)) { + hologram.show(); + } else { + hologram.hide(); + } + } + } + } + + @SuppressWarnings("unchecked") + public static T getHologram(String id) { + return holograms.stream() + .filter(h -> h.getHologramName().equals(id)) + // T will already be extending HolographicDisplay, so casting will work + .map(h -> (T) h) + .findFirst().orElse(null); + } + + public static List getHolograms() { + return holograms; + } +} \ No newline at end of file diff --git a/src/main/java/com/alpsbte/plotsystem/core/holograms/HolographicDisplay.java b/src/main/java/com/alpsbte/plotsystem/core/holograms/HolographicDisplay.java index f3402b56..33f684d3 100644 --- a/src/main/java/com/alpsbte/plotsystem/core/holograms/HolographicDisplay.java +++ b/src/main/java/com/alpsbte/plotsystem/core/holograms/HolographicDisplay.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 @@ -29,6 +29,9 @@ import com.gmail.filoghost.holographicdisplays.api.HologramsAPI; import com.alpsbte.plotsystem.utils.io.config.ConfigPaths; import com.alpsbte.plotsystem.utils.Utils; +import com.gmail.filoghost.holographicdisplays.api.line.HologramLine; +import com.gmail.filoghost.holographicdisplays.api.line.ItemLine; +import com.gmail.filoghost.holographicdisplays.api.line.TextLine; import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.configuration.file.FileConfiguration; @@ -38,7 +41,6 @@ import java.util.logging.Level; public abstract class HolographicDisplay { - private final String hologramName; private Hologram hologram; private boolean isPlaced = false; @@ -48,12 +50,12 @@ public HolographicDisplay(String hologramName) { } public void show() { - placeHologram(); + reloadHologram(); updateHologram(); } public void hide() { - if(isPlaced()){ + if (isPlaced()) { getHologram().delete(); isPlaced = false; } @@ -84,59 +86,129 @@ public void setLocation(Location newLocation) { PlotSystem.getPlugin().getConfigManager().saveFiles(); - if(isPlaced) { - hologram.delete(); - isPlaced = false; - } - - placeHologram(); + reloadHologram(); } public void placeHologram() { - if(!isPlaced() && getLocation() != null) { + if (!isPlaced() && getLocation() != null) { hologram = HologramsAPI.createHologram(PlotSystem.getPlugin(), getLocation()); isPlaced = true; } } + protected String getHeader() { + return "§7---------------"; + } + + protected String getFooter() { + return "§7---------------"; + } + protected void insertLines() { - getHologram().insertItemLine(0, getItem()); + replaceLine(0, getItem()); - getHologram().insertTextLine(1, getTitle()); - getHologram().insertTextLine(2, "§7---------------"); + replaceLine(1, getTitle()); + replaceLine(2, getHeader()); - List data = getDataLines(); - for(int i = 2; i < data.size() + 2; i++) { - getHologram().insertTextLine(i + 1,"§e#" + (i - 1) + " §a" +data.get(i - 2).split(",")[0] + " §7- §b" + data.get(i - 2).split(",")[1]); + List data = getDataLines(); + for (int i = 2; i < data.size() + 2; i++) { + replaceLine(i + 1, data.get(i - 2).getLine()); } - getHologram().insertTextLine(data.size() + 3, "§7---------------"); + replaceLine(data.size() + 3, getFooter()); } - protected abstract List getDataLines(); + protected void replaceLine(int line, ItemStack item) { + if (getHologram().size() < line + 1) { + getHologram().insertItemLine(line, item); + } else { + HologramLine hologramLine = getHologram().getLine(line); + if (hologramLine instanceof TextLine) { + // we're replacing the line with a different type, so we will have to destroy old line to replace with new type + getHologram().insertItemLine(line, item); + getHologram().removeLine(line + 1); + } else { + ((ItemLine) hologramLine).setItemStack(item); + } + } + } + + protected void replaceLine(int line, String text) { + if (getHologram().size() < line + 1) { + getHologram().insertTextLine(line, text); + } else { + HologramLine hologramLine = getHologram().getLine(line); + if (hologramLine instanceof ItemLine) { + // we're replacing the line with a different type, so we will have to destroy old line to replace with new type + getHologram().insertTextLine(line, text); + getHologram().removeLine(line + 1); + } else { + ((TextLine) hologramLine).setText(text); + } + } + } + + protected abstract List getDataLines(); protected abstract ItemStack getItem(); + public abstract void onShutdown(); + public void updateHologram() { - Bukkit.getScheduler().scheduleSyncRepeatingTask(PlotSystem.getPlugin(), () -> { - if(isPlaced()) { - hologram.clearLines(); - insertLines(); - } - },0, getInterval()); + if (isPlaced()) { + insertLines(); + } + } + + public void reloadHologram() { + if (isPlaced) { + hologram.delete(); + isPlaced = false; + } + placeHologram(); } - public String getHologramName() { return hologramName; } + public String getHologramName() { + return hologramName; + } protected abstract String getTitle(); - public Hologram getHologram() { return hologram; } + public Hologram getHologram() { + return hologram; + } - public boolean isPlaced() { return isPlaced; } + public boolean isPlaced() { + return isPlaced; + } - public int getInterval() { return 20*60; } + public long getInterval() { + return PlotSystem.getPlugin().getConfigManager().getConfig().getInt(ConfigPaths.DISPLAY_OPTIONS_INTERVAL) * 20L; + } public String getDefaultPath() { return ConfigPaths.HOLOGRAMS + getHologramName(); } -} + + + public interface DataLine { + String getLine(); + } + + public static class LeaderboardPositionLine implements DataLine { + protected int position; + protected int score; + protected String username; + + public LeaderboardPositionLine(int position, String username, int score) { + this.position = position; + this.username = username; + this.score = score; + } + + @Override + public String getLine() { + return "§e#" + position + " " + (username != null ? "§a" + username : "§8No one, yet") + " §7- §b" + score; + } + } +} \ No newline at end of file diff --git a/src/main/java/com/alpsbte/plotsystem/core/holograms/PlotsLeaderboard.java b/src/main/java/com/alpsbte/plotsystem/core/holograms/PlotsLeaderboard.java index 21dde453..89afd11d 100644 --- a/src/main/java/com/alpsbte/plotsystem/core/holograms/PlotsLeaderboard.java +++ b/src/main/java/com/alpsbte/plotsystem/core/holograms/PlotsLeaderboard.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 @@ -42,13 +42,21 @@ public PlotsLeaderboard() { @Override protected String getTitle() { - return "§b§lCOMPLETED PLOTS"; + return "§b§lCOMPLETED PLOTS §6§l[Lifetime]"; } @Override - protected List getDataLines() { + protected List getDataLines() { try { - return Builder.getBuildersByCompletedBuilds(10); + ArrayList lines = new ArrayList<>(); + + List> entries = Builder.getBuildersByCompletedBuilds(10); + for(int i = 0; i < 10; i++ ) { + Builder.DatabaseEntry entry = i < entries.size() && entries.get(i).getValue() != 0 ? entries.get(i) : null; + lines.add(new LeaderboardPositionLine(i + 1, entry != null ? entry.getKey() : null, entry != null ? entry.getValue() : 0)); + } + + return lines; } catch (SQLException ex) { PlotSystem.getPlugin().getLogger().log(Level.SEVERE, "Could not read data lines.", ex); } @@ -61,10 +69,5 @@ protected ItemStack getItem() { } @Override - public void updateHologram() { - if(isPlaced()) { - getHologram().clearLines(); - insertLines(); - } - } -} + public void onShutdown() {} +} \ No newline at end of file diff --git a/src/main/java/com/alpsbte/plotsystem/core/holograms/ScoreLeaderboard.java b/src/main/java/com/alpsbte/plotsystem/core/holograms/ScoreLeaderboard.java index 1e5e8fc0..bbc35538 100644 --- a/src/main/java/com/alpsbte/plotsystem/core/holograms/ScoreLeaderboard.java +++ b/src/main/java/com/alpsbte/plotsystem/core/holograms/ScoreLeaderboard.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 @@ -26,29 +26,120 @@ import com.alpsbte.plotsystem.PlotSystem; import com.alpsbte.plotsystem.core.system.Builder; +import com.alpsbte.plotsystem.core.system.Payout; +import com.alpsbte.plotsystem.utils.Utils; +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 net.md_5.bungee.api.ChatColor; +import net.md_5.bungee.api.ChatMessageType; +import net.md_5.bungee.api.chat.BaseComponent; +import net.md_5.bungee.api.chat.ComponentBuilder; +import net.md_5.bungee.api.chat.TextComponent; +import org.bukkit.Bukkit; import org.bukkit.Material; +import org.bukkit.configuration.file.FileConfiguration; +import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; +import org.bukkit.scheduler.BukkitRunnable; +import org.bukkit.scheduler.BukkitTask; import java.sql.SQLException; +import java.text.DecimalFormat; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import java.util.logging.Level; +import java.util.stream.Collectors; public class ScoreLeaderboard extends HolographicDisplay { + private final DecimalFormat df = new DecimalFormat("#.##"); + private LeaderboardTimeframe sortBy = LeaderboardTimeframe.DAILY; + private BukkitTask changeSortTask = null; + private BukkitTask actionbarTask = null; + int changeState = 0; public ScoreLeaderboard() { super("score-leaderboard"); + init(); + } + + private void init() { + if (getPages().size() < 1) { + PlotSystem.getPlugin().getLogger().log(Level.WARNING, "Unable to initialize Score-Leaderboard - No display pages enabled! Check config for display-options."); + return; + } + + sortBy = getPages().get(0); + + long interval = getInterval(); + long changeDelay = interval / 15; + changeSortTask = new BukkitRunnable() { + @Override + public void run() { + if (changeState >= changeDelay) { + LeaderboardTimeframe next = Utils.getNextListItem(getPages(), sortBy); + if (next == null) { + sortBy = getPages().get(0); + } else { + sortBy = next; + } + changeState = 0; + } else { + changeState++; + updateHologram(); + } + } + }.runTaskTimerAsynchronously(PlotSystem.getPlugin(), changeDelay, changeDelay); + + actionbarTask = new BukkitRunnable() { + @Override + public void run() { + for (Player player : showToPlayers()) { + player.spigot().sendMessage(ChatMessageType.ACTION_BAR, rankingString(player)); + } + } + }.runTaskTimerAsynchronously(PlotSystem.getPlugin(), 0L, 20L); } @Override protected String getTitle() { - return "§b§lTOP SCORE"; + return "§b§lTOP SCORE §6§l[" + (sortBy.toString().charAt(0) + sortBy.toString().toLowerCase().substring(1)) + "]"; + } + + @Override + public String getFooter() { + long changeDelay = getInterval() / 15; + int highlightCount = (int) (((float) changeState / changeDelay) * 15); + + StringBuilder highlighted = new StringBuilder(); + for (int i = 0; i < highlightCount; i++) { + highlighted.append("-"); + } + StringBuilder notH = new StringBuilder(); + for (int i = 0; i < 15 - highlightCount; i++) { + notH.append("-"); + } + + return "§e" + highlighted + "§7" + notH; } @Override - protected List getDataLines() { + protected List getDataLines() { try { - return Builder.getBuildersByScore(10); + ArrayList lines = new ArrayList<>(); + + for (int index = 0; index < 10; index++) { + lines.add(new LeaderboardPositionLineWithPayout(index + 1, null, 0)); + } + + int index = 0; + for (Builder.DatabaseEntry entry : Builder.getBuildersByScore(sortBy)) { + lines.set(index, new LeaderboardPositionLineWithPayout(index + 1, entry.getKey(), entry.getValue())); + index++; + } + + return lines; } catch (SQLException ex) { PlotSystem.getPlugin().getLogger().log(Level.SEVERE, "Could not read data lines.", ex); } @@ -61,10 +152,142 @@ protected ItemStack getItem() { } @Override - public void updateHologram() { - if(isPlaced()) { - getHologram().clearLines(); - insertLines(); + public void onShutdown() { + if (changeSortTask != null) { + changeSortTask.cancel(); + changeSortTask = null; + } + + if (actionbarTask != null) { + actionbarTask.cancel(); + actionbarTask = null; + } + } + + @Override + public void reloadHologram() { + super.reloadHologram(); + onShutdown(); + init(); + } + + private List getPages() { + FileConfiguration config = PlotSystem.getPlugin().getConfigManager().getConfig(); + return Arrays.stream(LeaderboardTimeframe.values()).filter(p -> config.getBoolean(p.configPath)).collect(Collectors.toList()); + } + + private BaseComponent[] rankingString(Player player) { + int position; + int rows; + int myScore; + try { + position = Builder.getBuilderScorePosition(player.getUniqueId(), sortBy); + rows = Builder.getBuildersInSort(sortBy); + myScore = Builder.getBuilderScore(player.getUniqueId(), sortBy); + } catch (SQLException e) { + e.printStackTrace(); + return TextComponent.fromLegacyText("§cSQL Exception"); + } + + ComponentBuilder builder = new ComponentBuilder(""); + builder.append( + new ComponentBuilder(" " + LangUtil.get(player, sortBy.langPath)) + .color(ChatColor.GOLD) + .bold(true) + .create() + ); + + builder.append( + new ComponentBuilder(" ➜ ") + .color(ChatColor.DARK_GRAY) + .bold(true) + .create() + ); + + if (position == -1) { + builder.append( + new ComponentBuilder(LangUtil.get(player, LangPaths.Leaderboards.NOT_ON_LEADERBOARD)) + .color(ChatColor.RED) + .bold(false) + .create() + ); + } else if (position < 50) { + builder.append( + new ComponentBuilder( + LangUtil.get(player, LangPaths.Leaderboards.ACTIONBAR_POSITION, String.valueOf(position)) + ).color(ChatColor.GREEN).bold(false).create() + ); + } else { + String topPercentage = df.format(position * 1.0 / rows); + builder.append( + new ComponentBuilder( + LangUtil.get(player, LangPaths.Leaderboards.ACTIONBAR_PERCENTAGE, topPercentage) + ).bold(false).create() + ); + } + + if (myScore != -1) { + builder.append(TextComponent.fromLegacyText("§8 (§b" + myScore + " points§8)")); + } + + return builder.bold(false).create(); + } + + private List showToPlayers() { + FileConfiguration config = PlotSystem.getPlugin().getConfigManager().getConfig(); + boolean actionBarEnabled = config.getBoolean(ConfigPaths.DISPLAY_OPTIONS_ACTION_BAR_ENABLED, true); + int actionBarRadius = config.getInt(ConfigPaths.DISPLAY_OPTIONS_ACTION_BAR_RADIUS, 30); + List players = new ArrayList<>(); + for (Player player : Bukkit.getOnlinePlayers()) { + if (player.getWorld().getName().equals(getLocation().getWorld().getName()) && (!actionBarEnabled || getLocation().distance(player.getLocation()) <= actionBarRadius)) { + players.add(player); + } + } + return players; + } + + public enum LeaderboardTimeframe { + DAILY(ConfigPaths.DISPLAY_OPTIONS_SHOW_DAILY), + WEEKLY(ConfigPaths.DISPLAY_OPTIONS_SHOW_WEEKLY), + MONTHLY(ConfigPaths.DISPLAY_OPTIONS_SHOW_MONTHLY), + YEARLY(ConfigPaths.DISPLAY_OPTIONS_SHOW_YEARLY), + LIFETIME(ConfigPaths.DISPLAY_OPTIONS_SHOW_LIFETIME); + + public final String configPath; + public final String langPath; + + LeaderboardTimeframe(String configPath) { + this.configPath = configPath; + this.langPath = LangPaths.Leaderboards.PAGES + name(); + } + } + + private class LeaderboardPositionLineWithPayout extends LeaderboardPositionLine { + + public LeaderboardPositionLineWithPayout(int position, String username, int score) { + super(position, username, score); + } + + @Override + public String getLine() { + try { + String line = super.getLine(); + Payout payout = sortBy != LeaderboardTimeframe.LIFETIME ? Payout.getPayout(sortBy, position) : null; + if (payout == null) { + return line; + } else { + String payoutAmount = payout.getPayoutAmount(); + try { + // if payout amount can be number, prefix with dollar sign + Integer.valueOf(payoutAmount); + payoutAmount = "$" + payoutAmount; + } catch (NumberFormatException ignored) {} + + return line + " §7- §e§l" + payoutAmount; + } + } catch (SQLException e) { + return super.getLine() + " §7- §cSQL ERR"; + } } } -} +} \ No newline at end of file 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/AbstractPaginatedMenu.java b/src/main/java/com/alpsbte/plotsystem/core/menus/AbstractPaginatedMenu.java index 9c565a62..3944b2ce 100644 --- a/src/main/java/com/alpsbte/plotsystem/core/menus/AbstractPaginatedMenu.java +++ b/src/main/java/com/alpsbte/plotsystem/core/menus/AbstractPaginatedMenu.java @@ -31,16 +31,15 @@ import java.util.List; public abstract class AbstractPaginatedMenu extends AbstractMenu { - + private List source; private final int maxItemsPerPage; - private final int totalItemsAmount; + private int totalItemsAmount; private int currentPage = 0; public AbstractPaginatedMenu(int rows, int pagedRows, String title, Player menuPlayer) { super(rows, title, menuPlayer, false); this.maxItemsPerPage = pagedRows * 9; - this.totalItemsAmount = getSource().size(); reloadMenuAsync(); } @@ -83,15 +82,17 @@ protected void previousPage() { */ protected void setPage(int index) { currentPage = index; - reloadMenuAsync(); + reloadMenuAsync(false); } /** * Collects all item sources for the current page * @return item sources for the current page */ - private List getItemSources() { - return getSource().subList(getMinIndex(), Math.min(getMaxIndex(), totalItemsAmount)); + private List getItemSources(boolean reloadSources) { + if (reloadSources) source = getSource(); + this.totalItemsAmount = source.size(); + return source.subList(getMinIndex(), Math.min(getMaxIndex(), source.size())); } /** @@ -123,17 +124,24 @@ private int getMaxIndex() { } /** - * {@inheritDoc} + * @param reloadSources if true, reload the source collection for the inventory items */ - @Override - protected void reloadMenuAsync() { + protected void reloadMenuAsync(boolean reloadSources) { getMenu().clear(); super.reloadMenuAsync(); Bukkit.getScheduler().runTaskAsynchronously(PlotSystem.getPlugin(), () -> { - List sources = getItemSources(); + List sources = getItemSources(reloadSources); setPaginatedMenuItemsAsync(sources); setPaginatedItemClickEventsAsync(sources); }); } + + /** + * {@inheritDoc} + */ + @Override + protected void reloadMenuAsync() { + reloadMenuAsync(true); + } } 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 deleted file mode 100644 index 34e5e4d6..00000000 --- a/src/main/java/com/alpsbte/plotsystem/core/menus/CompanionMenu.java +++ /dev/null @@ -1,332 +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.menus; - -import com.alpsbte.plotsystem.PlotSystem; -import com.alpsbte.plotsystem.core.system.Builder; -import com.alpsbte.plotsystem.core.system.CityProject; -import com.alpsbte.plotsystem.core.system.plot.Plot; -import com.alpsbte.plotsystem.core.system.plot.PlotManager; -import com.alpsbte.plotsystem.utils.io.config.ConfigPaths; -import com.alpsbte.plotsystem.core.system.plot.generator.DefaultPlotGenerator; -import com.alpsbte.plotsystem.utils.Utils; -import com.alpsbte.plotsystem.utils.enums.PlotDifficulty; -import com.alpsbte.plotsystem.utils.enums.Slot; -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.alpsbte.plotsystem.utils.items.MenuItems; -import com.alpsbte.plotsystem.utils.items.builder.ItemBuilder; -import com.alpsbte.plotsystem.utils.items.builder.LoreBuilder; -import org.bukkit.Bukkit; -import org.bukkit.Material; -import org.bukkit.entity.Player; -import org.bukkit.inventory.ItemStack; -import org.ipvp.canvas.mask.BinaryMask; -import org.ipvp.canvas.mask.Mask; - -import java.sql.SQLException; -import java.util.List; -import java.util.concurrent.ExecutionException; -import java.util.logging.Level; - -public class CompanionMenu extends AbstractMenu { - - private Plot[] slots; - private List cityProjects; - - private PlotDifficulty selectedPlotDifficulty = null; - - public CompanionMenu(Player player) { - super(6, LangUtil.get(player, LangPaths.MenuTitle.COMPANION), player); - } - - @Override - protected void setPreviewItems() { - // Set navigator item - getMenu().getSlot(4) - .setItem(new ItemBuilder(Material.valueOf(PlotSystem.getPlugin().getConfigManager().getConfig().getString(ConfigPaths.NAVIGATOR_ITEM)), 1) - .setName("§6§l"+ LangUtil.get(getMenuPlayer(), LangPaths.MenuTitle.NAVIGATOR)).setLore(new LoreBuilder() - .addLine(LangUtil.get(getMenuPlayer(), LangPaths.MenuDescription.NAVIGATOR)).build()) - .build()); - - // Set loading item for plots difficulty item - getMenu().getSlot(7).setItem(MenuItems.loadingItem(Material.SKULL_ITEM, (byte) 3, getMenuPlayer())); - - // Set builder utilities menu item - getMenu().getSlot(50).setItem(BuilderUtilitiesMenu.getMenuItem(getMenuPlayer())); - - // Set player plots menu item - getMenu().getSlot(51).setItem(PlayerPlotsMenu.getMenuItem(getMenuPlayer())); - - // Set player settings menu item - getMenu().getSlot(52) - .setItem(new ItemBuilder(Material.REDSTONE_COMPARATOR) - .setName("§b§l" + LangUtil.get(getMenuPlayer(), LangPaths.MenuTitle.SETTINGS)) - .setLore(new LoreBuilder() - .addLine(LangUtil.get(getMenuPlayer(), LangPaths.MenuDescription.SETTINGS)).build()) - .build()); - - // Set players slot items - slots = new Plot[3]; - for (int i = 0; i < 3; i++) { - try { - Builder builder = new Builder(getMenuPlayer().getUniqueId()); - slots[i] = builder.getPlot(Slot.values()[i]); - - if (slots[i] != null) { - getMenu().getSlot(46 + i).setItem(new ItemBuilder(Material.MAP, 1 + i) - .setName("§b§l" + LangUtil.get(getMenuPlayer(), LangPaths.MenuTitle.SLOT).toUpperCase() + " " + (i + 1)) - .setLore(new LoreBuilder() - .addLines("§7" + LangUtil.get(getMenuPlayer(), LangPaths.Plot.ID) + ": §f" + slots[i].getID(), - "§7" + LangUtil.get(getMenuPlayer(), LangPaths.Plot.CITY) + ": §f" + slots[i].getCity().getName(), - "§7" + LangUtil.get(getMenuPlayer(), LangPaths.Plot.DIFFICULTY) + ": §f" + slots[i].getDifficulty().name().charAt(0) + slots[i].getDifficulty().name().substring(1).toLowerCase(), - "", - "§6§l" + LangUtil.get(getMenuPlayer(), LangPaths.Plot.STATUS) + ": §7§l" + slots[i].getStatus().name().substring(0, 1).toUpperCase() + slots[i].getStatus().name().substring(1) - ).build()) - .build()); - } else { - getMenu().getSlot(46 + i).setItem(new ItemBuilder(Material.EMPTY_MAP, 1 + i) - .setName("§b§l" + LangUtil.get(getMenuPlayer(), LangPaths.MenuTitle.SLOT).toUpperCase() + " " + (i + 1)) - .setLore(new LoreBuilder() - .addLines("§7" + LangUtil.get(getMenuPlayer(), LangPaths.MenuDescription.SLOT), - "", - "§6§l" + LangUtil.get(getMenuPlayer(), LangPaths.Plot.STATUS) + ": §7§lUnassigned") // Cant translate because name is stored in the database - .build()) - .build()); - } - } catch (NullPointerException | SQLException ex) { - Bukkit.getLogger().log(Level.SEVERE, "An error occurred while placing player slot items!", ex); - getMenu().getSlot(46 + i).setItem(MenuItems.errorItem(getMenuPlayer())); - } - } - - super.setPreviewItems(); - } - - @Override - protected void setMenuItemsAsync() { - // Set plots difficulty item head - getMenu().getSlot(7).setItem(getSelectedDifficultyItem()); - - // Set city project items - try { - cityProjects = CityProject.getCityProjects(true); - setCityProjectItems(); - } catch (SQLException ex) { - Bukkit.getLogger().log(Level.SEVERE, "A SQL error occurred!", ex); - } - } - - @Override - protected void setItemClickEvents() { - // Set click event for navigator item - getMenu().getSlot(4).setClickHandler((clickPlayer, clickInformation) -> { - clickPlayer.closeInventory(); - clickPlayer.performCommand(PlotSystem.getPlugin().getConfigManager().getConfig().getString(ConfigPaths.NAVIGATOR_COMMAND)); - }); - - // Set click event for plots difficulty item - getMenu().getSlot(7).setClickHandler(((clickPlayer, clickInformation) -> { - selectedPlotDifficulty = (selectedPlotDifficulty == null ? - PlotDifficulty.values()[0] : selectedPlotDifficulty.ordinal() != PlotDifficulty.values().length - 1 ? - PlotDifficulty.values()[selectedPlotDifficulty.ordinal() + 1] : null); - - getMenu().getSlot(7).setItem(getSelectedDifficultyItem()); - clickPlayer.playSound(clickPlayer.getLocation(), Utils.Done, 1, 1); - - try { - setCityProjectItems(); - } catch (SQLException ex) { - Bukkit.getLogger().log(Level.SEVERE, "A SQL error occurred!", ex); - } - })); - - // Set click event for city project items - for(int i = 0; i < cityProjects.size(); i++) { - int itemSlot = i; - getMenu().getSlot(9 + i).setClickHandler((clickPlayer, clickInformation) -> { - if (!getMenu().getSlot(9 + itemSlot).getItem(clickPlayer).equals(MenuItems.errorItem(getMenuPlayer()))) { - try { - clickPlayer.closeInventory(); - Builder builder = new Builder(clickPlayer.getUniqueId()); - int cityID = cityProjects.get(itemSlot).getID(); - - PlotDifficulty plotDifficultyForCity = selectedPlotDifficulty != null ? selectedPlotDifficulty : PlotManager.getPlotDifficultyForBuilder(cityID, builder).get(); - if (PlotManager.getPlots(cityID, plotDifficultyForCity, Status.unclaimed).size() != 0) { - if (selectedPlotDifficulty != null && PlotSystem.getPlugin().getConfigManager().getConfig().getBoolean(ConfigPaths.ENABLE_SCORE_REQUIREMENT) && !PlotManager.hasPlotDifficultyScoreRequirement(builder, selectedPlotDifficulty)) { - clickPlayer.sendMessage(Utils.getErrorMessageFormat(LangUtil.get(clickPlayer, LangPaths.Message.Error.PLAYER_NEEDS_HIGHER_SCORE))); - clickPlayer.playSound(clickPlayer.getLocation(), Utils.ErrorSound, 1, 1); - return; - } - - new DefaultPlotGenerator(cityID, plotDifficultyForCity, builder); - } else { - clickPlayer.sendMessage(Utils.getErrorMessageFormat(LangUtil.get(clickPlayer, LangPaths.Message.Error.NO_PLOTS_LEFT))); - clickPlayer.playSound(clickPlayer.getLocation(), Utils.ErrorSound, 1, 1); - } - } catch (SQLException | ExecutionException | InterruptedException ex) { - Bukkit.getLogger().log(Level.SEVERE, "A SQL error occurred!", ex); - clickPlayer.sendMessage(Utils.getErrorMessageFormat(LangUtil.get(clickPlayer, LangPaths.Message.Error.ERROR_OCCURRED))); - clickPlayer.playSound(clickPlayer.getLocation(), Utils.ErrorSound, 1, 1); - } - } else { - clickPlayer.playSound(clickPlayer.getLocation(), Utils.ErrorSound, 1, 1); - } - }); - } - - // Set click event for player slot items - Bukkit.getScheduler().runTask(PlotSystem.getPlugin(), () -> { - for(int i = 0; i < 3; i++) { - if (slots[i] != null) { - int itemSlot = i; - getMenu().getSlot(46 + i).setClickHandler((clickPlayer, clickInformation) -> { - clickPlayer.closeInventory(); - try { - new PlotActionsMenu(clickPlayer, slots[itemSlot]); - } catch (SQLException ex) { - clickPlayer.sendMessage(Utils.getErrorMessageFormat(LangUtil.get(clickPlayer, LangPaths.Message.Error.ERROR_OCCURRED))); - clickPlayer.playSound(clickPlayer.getLocation(), Utils.ErrorSound, 1, 1); - Bukkit.getLogger().log(Level.SEVERE, "An error occurred while opening the plot actions menu!", ex); - } - }); - } - } - }); - - // Set click event for builder utilities menu item - getMenu().getSlot(50).setClickHandler(((clickPlayer, clickInformation) -> { - clickPlayer.closeInventory(); - new BuilderUtilitiesMenu(clickPlayer); - })); - - // Set click event for player plots menu item - getMenu().getSlot(51).setClickHandler(((clickPlayer, clickInformation) -> { - clickPlayer.closeInventory(); - clickPlayer.performCommand("plots " + clickPlayer.getName()); - })); - - // Set click event for player settings menu item - getMenu().getSlot(52).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("111101111") - .pattern("000000000") - .pattern("000000000") - .pattern("000000000") - .pattern("000000000") - .pattern("100010001") - .build(); - } - - /** - * Sets city project items asynchronously in the menu - * @throws SQLException When querying database - */ - private void setCityProjectItems() throws SQLException { - for(int i = 0; i < cityProjects.size(); i++) { - if(i <= 28) { - CityProject cp = cityProjects.get(i); - ItemStack cpItem = cp.getCountry().getHead(); - try { - PlotDifficulty cpPlotDifficulty = selectedPlotDifficulty != null ? - selectedPlotDifficulty : PlotManager.getPlotDifficultyForBuilder(cp.getID(), new Builder(getMenuPlayer().getUniqueId())).get(); - - int plotsOpen = PlotManager.getPlots(cp.getID(), Status.unclaimed).size(); - int plotsInProgress = PlotManager.getPlots(cp.getID(), Status.unfinished, Status.unreviewed).size(); - int plotsCompleted = PlotManager.getPlots(cp.getID(), Status.completed).size(); - int plotsUnclaimed = PlotManager.getPlots(cp.getID(), cpPlotDifficulty, Status.unclaimed).size(); - - getMenu().getSlot(9 + cityProjects.indexOf(cp)).setItem(new ItemBuilder(cpItem) - .setName("§b§l" + cp.getName()) - .setLore(new LoreBuilder() - .addLines(cp.getDescription(), - "", - "§6" + plotsOpen + " §7" + LangUtil.get(getMenuPlayer(), LangPaths.CityProject.PROJECT_OPEN), - "§8---------------------", - "§6" + plotsInProgress + " §7" + LangUtil.get(getMenuPlayer(), LangPaths.CityProject.PROJECT_IN_PROGRESS), - "§6" + plotsCompleted + " §7" + LangUtil.get(getMenuPlayer(), LangPaths.CityProject.PROJECT_COMPLETED), - "", - plotsUnclaimed != 0 ? Utils.getFormattedDifficulty(cpPlotDifficulty) : "§f§l" + LangUtil.get(getMenuPlayer(), LangPaths.CityProject.PROJECT_NO_PLOTS) - ).build()) - .build()); - - } catch (SQLException | ExecutionException | InterruptedException ex) { - Bukkit.getLogger().log(Level.SEVERE, "A SQL error occurred!", ex); - getMenu().getSlot(9 + cityProjects.indexOf(cp)).setItem(MenuItems.errorItem(getMenuPlayer())); - } - } - } - } - - /** - * Returns head for current selected plot difficulty - * @return plots difficulty head as ItemStack - */ - private ItemStack getSelectedDifficultyItem() { - ItemStack item = Utils.getItemHead(Utils.CustomHead.WHITE_CONCRETE); - - if (selectedPlotDifficulty != null) { - if (selectedPlotDifficulty == PlotDifficulty.EASY) { - item = Utils.getItemHead(Utils.CustomHead.GREEN_CONCRETE); - } else if (selectedPlotDifficulty == PlotDifficulty.MEDIUM) { - item = Utils.getItemHead(Utils.CustomHead.YELLOW_CONCRETE); - } else if (selectedPlotDifficulty == PlotDifficulty.HARD) { - item = Utils.getItemHead(Utils.CustomHead.RED_CONCRETE); - } - } - - try { - return new ItemBuilder(item) - .setName("§b§l" + LangUtil.get(getMenuPlayer(), LangPaths.MenuTitle.PLOT_DIFFICULTY).toUpperCase()) - .setLore(new LoreBuilder() - .addLines("", - selectedPlotDifficulty != null ? Utils.getFormattedDifficulty(selectedPlotDifficulty) : "§f§l" + LangUtil.get(getMenuPlayer(), LangPaths.Difficulty.AUTOMATIC), - selectedPlotDifficulty != null ? "§7" + LangUtil.get(getMenuPlayer(), LangPaths.Difficulty.SCORE_MULTIPLIER) + ": §fx" + PlotManager.getMultiplierByDifficulty(selectedPlotDifficulty) : "", - "", - "§7" + LangUtil.get(getMenuPlayer(), LangPaths.MenuDescription.PLOT_DIFFICULTY)) - .build()) - .build(); - } catch (SQLException ex) { - Bukkit.getLogger().log(Level.SEVERE, "A SQL error occurred!", ex); - return MenuItems.errorItem(getMenuPlayer()); - } - } - - /** - * @return Menu item - */ - 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) - .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..c2d05981 100644 --- a/src/main/java/com/alpsbte/plotsystem/core/menus/FeedbackMenu.java +++ b/src/main/java/com/alpsbte/plotsystem/core/menus/FeedbackMenu.java @@ -101,7 +101,8 @@ protected void setMenuItemsAsync() { getMenu().getSlot(13).setItem(new ItemBuilder(Material.BOOK_AND_QUILL) .setName("§b§l" + LangUtil.get(getMenuPlayer(), LangPaths.Review.FEEDBACK)) .setLore(new LoreBuilder() - .addLine(plot.getReview().getFeedback()).build()) + .addLines(Utils.createMultilineFromString(plot.getReview().getFeedback(), AbstractMenu.MAX_CHARS_PER_LINE, AbstractMenu.LINE_BAKER)) + .build()) .build()); } catch (SQLException ex) { Bukkit.getLogger().log(Level.SEVERE, "A SQL error occurred!", ex); @@ -122,7 +123,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..fe735f6c 100644 --- a/src/main/java/com/alpsbte/plotsystem/core/menus/PlayerPlotsMenu.java +++ b/src/main/java/com/alpsbte/plotsystem/core/menus/PlayerPlotsMenu.java @@ -55,7 +55,7 @@ public class PlayerPlotsMenu extends AbstractMenu { private int plotDisplayCount = 0; public PlayerPlotsMenu(Player menuPlayer, Builder builder) throws SQLException { - super(6, LangUtil.get(menuPlayer, LangPaths.MenuTitle.PLAYER_PLOTS, menuPlayer.getName() + "'"), menuPlayer); + super(6, LangUtil.get(menuPlayer.getPlayer(), LangPaths.MenuTitle.PLAYER_PLOTS, builder.getName() + "'"), menuPlayer); this.builder = builder; } @@ -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..e016920e 100644 --- a/src/main/java/com/alpsbte/plotsystem/core/menus/ReviewMenu.java +++ b/src/main/java/com/alpsbte/plotsystem/core/menus/ReviewMenu.java @@ -24,14 +24,19 @@ package com.alpsbte.plotsystem.core.menus; +import com.alpsbte.plotsystem.PlotSystem; +import com.alpsbte.plotsystem.core.system.Builder; +import com.alpsbte.plotsystem.core.system.Country; import com.alpsbte.plotsystem.core.system.plot.Plot; import com.alpsbte.plotsystem.core.system.plot.PlotManager; +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.alpsbte.plotsystem.utils.items.builder.ItemBuilder; import com.alpsbte.plotsystem.utils.items.MenuItems; import com.alpsbte.plotsystem.utils.Utils; import com.alpsbte.plotsystem.utils.enums.Status; +import com.alpsbte.plotsystem.utils.items.builder.LoreBuilder; import org.bukkit.Bukkit; import org.bukkit.Material; import org.bukkit.entity.Player; @@ -46,6 +51,8 @@ import java.util.stream.Collectors; public class ReviewMenu extends AbstractPaginatedMenu { + private final List countries = Builder.byUUID(getMenuPlayer().getUniqueId()).getAsReviewer().getCountries(); + private Country filteredCountry = null; public ReviewMenu(Player player) throws SQLException { super(6, 4, LangUtil.get(player, LangPaths.Review.MANAGE_AND_REVIEW_PLOTS), player); @@ -55,8 +62,8 @@ public ReviewMenu(Player player) throws SQLException { protected List getSource() { List plots = new ArrayList<>(); try { - plots.addAll(PlotManager.getPlots(Status.unreviewed)); - plots.addAll(PlotManager.getPlots(Status.unfinished)); + plots.addAll(PlotManager.getPlots(countries, Status.unreviewed)); + plots.addAll(PlotManager.getPlots(countries, Status.unfinished)); } catch (SQLException ex) { Bukkit.getLogger().log(Level.SEVERE, ex.getMessage(), ex); } @@ -74,7 +81,7 @@ protected void setPreviewItems() { @Override protected void setPaginatedMenuItemsAsync(List source) { // Set unreviewed and unfinished plot items - List plots = source.stream().map(p -> (Plot) p).collect(Collectors.toList()); + List plots = getFilteredPlots(source); for(int i = 0; i < plots.size(); i++) { try { Plot plot = plots.get(i); @@ -88,6 +95,7 @@ protected void setPaginatedMenuItemsAsync(List source) { }).collect(Collectors.joining(", ")) ); lines.add("§7" + LangUtil.get(getMenuPlayer(), LangPaths.Plot.CITY) + ": §f" + plot.getCity().getName()); + lines.add("§7" + LangUtil.get(getMenuPlayer(), LangPaths.Plot.COUNTRY) + ": §f" + plot.getCity().getCountry().getName()); lines.add("§7" + LangUtil.get(getMenuPlayer(), LangPaths.Plot.DIFFICULTY) + ": §f" + plot.getDifficulty().name().charAt(0) + plot.getDifficulty().name().substring(1).toLowerCase()); getMenu().getSlot(i + 9).setItem(new ItemBuilder(plot.getStatus() == Status.unfinished ? Material.EMPTY_MAP : Material.MAP, 1) @@ -104,15 +112,17 @@ protected void setPaginatedMenuItemsAsync(List source) { @Override protected void setPaginatedItemClickEventsAsync(List source) { // Set click event for unreviewed and unfinished plot items - List plots = source.stream().map(p -> (Plot) p).collect(Collectors.toList()); + List plots = getFilteredPlots(source); for (int i = 0; i < plots.size(); i++) { Plot plot = plots.get(i); getMenu().getSlot(i + 9).setClickHandler((player, info) -> { try { - getMenuPlayer().closeInventory(); if (plot.getStatus() == Status.unreviewed) { - if (!plot.getPlotOwner().getUUID().toString().equals(getMenuPlayer().getUniqueId().toString())) { - plot.getWorld().teleportPlayer(getMenuPlayer()); + if (!plot.getPlotOwner().getUUID().toString().equals(getMenuPlayer().getUniqueId().toString()) || PlotSystem.getPlugin().getConfigManager().getConfig().getBoolean(ConfigPaths.DEV_MODE)) { + Plot currentPlot = PlotManager.getCurrentPlot(Builder.byUUID(getMenuPlayer().getUniqueId()), Status.unreviewed); + if (currentPlot != null && currentPlot.getID() == plot.getID()) { + new ReviewPlotMenu(getMenuPlayer(), currentPlot); + } else plot.getWorld().teleportPlayer(getMenuPlayer()); } else { getMenuPlayer().sendMessage(Utils.getErrorMessageFormat(LangUtil.get(getMenuPlayer(), LangPaths.Message.Error.CANNOT_REVIEW_OWN_PLOT))); } @@ -121,6 +131,7 @@ protected void setPaginatedItemClickEventsAsync(List source) { } } catch (SQLException ex) { Bukkit.getLogger().log(Level.SEVERE, ex.getMessage(), ex); + getMenuPlayer().closeInventory(); } }); } @@ -128,6 +139,9 @@ protected void setPaginatedItemClickEventsAsync(List source) { @Override protected void setMenuItemsAsync() { + // Set filter item + getMenu().getSlot(7).setItem(getFilterItem(getMenuPlayer())); + // Set previous page item if (hasPreviousPage()) getMenu().getSlot(46).setItem(MenuItems.previousPageItem(getMenuPlayer())); @@ -136,7 +150,22 @@ protected void setMenuItemsAsync() { } @Override - protected void setItemClickEvents() { + protected void setItemClickEventsAsync() { + // Set click event for filter item + getMenu().getSlot(7).setClickHandler((clickPlayer, clickInformation) -> { + clickPlayer.playSound(clickPlayer.getLocation(), Utils.INVENTORY_CLICK, 1, 1); + if (countries.size() == 0) return; + + if (filteredCountry == null) { + filteredCountry = countries.get(0); + } else { + int index = countries.indexOf(filteredCountry); + filteredCountry = index + 1 >= countries.size() ? null : countries.get(index + 1); + } + + reloadMenuAsync(false); + }); + // Set click event for previous page item getMenu().getSlot(46).setClickHandler((clickPlayer, clickInformation) -> { if (hasPreviousPage()) { @@ -170,13 +199,40 @@ protected Mask getMask() { .build(); } + private List getFilteredPlots(List plots) { + List filteredPlots = plots.stream().map(p -> (Plot) p).collect(Collectors.toList()); + if (filteredCountry != null) filteredPlots = filteredPlots.stream().filter(p -> { + try { return p.getCity().getCountry().getID() == filteredCountry.getID(); + } catch (SQLException ex) { Bukkit.getLogger().log(Level.SEVERE, "A SQL error occurred!", ex); } + return false; + }).collect(Collectors.toList()); + return filteredPlots; + } + + private ItemStack getFilterItem(Player langPlayer) { + LoreBuilder loreBuilder = new LoreBuilder(); + loreBuilder.addLine((filteredCountry == null ? "§b§l> §f§l" : "§7") + LangUtil.get(langPlayer, LangPaths.MenuDescription.FILTER)); + loreBuilder.emptyLine(); + + countries.forEach(c -> { + if (filteredCountry != null && filteredCountry.getID() == c.getID()) { + loreBuilder.addLine("§b§l> §f§l" + filteredCountry.getName()); + } else loreBuilder.addLine("§7" + c.getName()); + }); + + return new ItemBuilder(MenuItems.filterItem(getMenuPlayer())) + .setLore(loreBuilder.build()) + .setEnchanted(filteredCountry != null) + .build(); + } + /** * @return Menu item */ 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..7daebca7 100644 --- a/src/main/java/com/alpsbte/plotsystem/core/menus/ReviewPlotMenu.java +++ b/src/main/java/com/alpsbte/plotsystem/core/menus/ReviewPlotMenu.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 @@ -26,6 +26,7 @@ import com.alpsbte.plotsystem.PlotSystem; import com.alpsbte.plotsystem.core.system.plot.PlotManager; +import com.alpsbte.plotsystem.utils.ChatFeedbackInput; import com.alpsbte.plotsystem.utils.io.language.LangPaths; import com.alpsbte.plotsystem.utils.io.language.LangUtil; import com.sk89q.worldedit.WorldEditException; @@ -38,6 +39,10 @@ import com.alpsbte.plotsystem.utils.items.MenuItems; import com.alpsbte.plotsystem.utils.Utils; import com.alpsbte.plotsystem.utils.enums.Status; +import net.md_5.bungee.api.chat.ClickEvent; +import net.md_5.bungee.api.chat.ComponentBuilder; +import net.md_5.bungee.api.chat.HoverEvent; +import net.md_5.bungee.api.chat.TextComponent; import org.bukkit.Bukkit; import org.bukkit.Material; import org.bukkit.enchantments.Enchantment; @@ -50,6 +55,7 @@ import java.io.IOException; import java.sql.SQLException; import java.util.Collections; +import java.util.Locale; import java.util.concurrent.CompletableFuture; import java.util.logging.Level; @@ -62,15 +68,6 @@ public class ReviewPlotMenu extends AbstractMenu { public ReviewPlotMenu(Player player, Plot plot) { super(6, LangUtil.get(player, LangPaths.MenuTitle.REVIEW_PLOT, Integer.toString(plot.getID())), player); this.plot = plot; - - // Check if plot is from player - try { - if (plot.getPlotOwner().getUUID().equals(player.getUniqueId())){ - player.sendMessage(Utils.getErrorMessageFormat(LangUtil.get(getMenuPlayer(), LangPaths.Message.Error.CANNOT_REVIEW_OWN_PLOT))); - } - } catch (SQLException ex) { - Bukkit.getLogger().log(Level.SEVERE, "A SQL error occurred!", ex); - } } @Override @@ -195,6 +192,10 @@ protected void setPreviewItems() { @Override protected void setMenuItemsAsync() { + // Set back item + getMenu().getSlot(1).setItem(MenuItems.backMenuItem(getMenuPlayer())); + + // Set plot information item try { getMenu().getSlot(4).setItem(new ItemBuilder(Material.MAP, 1) .setName("§b§l" + LangUtil.get(getMenuPlayer(), LangPaths.Review.REVIEW_PLOT)) @@ -203,17 +204,38 @@ protected void setMenuItemsAsync() { "", "§7" + LangUtil.get(getMenuPlayer(), LangPaths.Plot.OWNER) + ": §f" + plot.getPlotOwner().getName(), "§7" + LangUtil.get(getMenuPlayer(), LangPaths.Plot.CITY) + ": §f" + plot.getCity().getName(), + "§7" + LangUtil.get(getMenuPlayer(), LangPaths.Plot.COUNTRY) + ": §f" + plot.getCity().getCountry().getName(), "§7" + LangUtil.get(getMenuPlayer(), LangPaths.Plot.DIFFICULTY) + ": §f" + plot.getDifficulty().name().charAt(0) + plot.getDifficulty().name().substring(1).toLowerCase()) + .emptyLine() + .addLine("§7" + LangUtil.get(getMenuPlayer(), LangPaths.Review.PLAYER_LANGUAGE) + ": §f" + LangUtil.getLanguageFileByLocale(plot.getPlotOwner().getLanguageTag()).getLangName()) .build()) .build()); } catch (SQLException ex) { Bukkit.getLogger().log(Level.SEVERE, "A SQL error occurred!", ex); getMenu().getSlot(4).setItem(MenuItems.errorItem(getMenuPlayer())); } + + // Set review information item + String points = LangUtil.get(getMenuPlayer(), LangPaths.MenuTitle.REVIEW_POINTS); + getMenu().getSlot(7).setItem(new ItemBuilder(Utils.getItemHead(Utils.CustomHead.INFO_BUTTON)) + .setName("§b§l" + LangUtil.get(getMenuPlayer(), LangPaths.MenuTitle.INFORMATION)) + .setLore(new LoreBuilder() + .addLines(Utils.createMultilineFromString( "§7" + LangUtil.get(getMenuPlayer(), LangPaths.MenuDescription.INFORMATION), AbstractMenu.MAX_CHARS_PER_LINE, AbstractMenu.LINE_BAKER)) + .emptyLine() + .addLines("§f" + points + " <= 0: §c" + LangUtil.get(getMenuPlayer(), LangPaths.Review.ABANDONED), + "§f" + points + " <= 8: §e" + LangUtil.get(getMenuPlayer(), LangPaths.Review.REJECTED), + "§f" + points + " <= 20: §a" + LangUtil.get(getMenuPlayer(), LangPaths.Review.ACCEPTED)) + .build()) + .build()); } @Override - protected void setItemClickEvents() { + protected void setItemClickEventsAsync() { + // Set click event for back item + getMenu().getSlot(1).setClickHandler((clickPlayer, clickInformation) -> { + try { new ReviewMenu(getMenuPlayer()); } catch (SQLException ex) { Bukkit.getLogger().log(Level.SEVERE, "A SQL error occurred!", ex); } + }); + // Set click event for close item getMenu().getSlot(50).setClickHandler((clickPlayer, clickInformation) -> clickPlayer.closeInventory()); @@ -356,10 +378,28 @@ 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); + + try { + Review.awaitReviewerFeedbackList.remove(clickPlayer.getUniqueId()); + Review.awaitReviewerFeedbackList.put(clickPlayer.getUniqueId(), new ChatFeedbackInput(plot.getReview())); + clickPlayer.sendMessage(""); + clickPlayer.sendMessage("§a" + LangUtil.get(clickPlayer, LangPaths.Message.Info.ENTER_FEEDBACK)); + TextComponent txtComponent = new TextComponent(); + txtComponent.setText(LangUtil.get(clickPlayer, LangPaths.Message.Info.INPUT_EXPIRES_AFTER, "5") + " §7§l[§c§l" + LangUtil.get(clickPlayer, LangPaths.MenuTitle.CANCEL).toUpperCase(Locale.ROOT) + "§7§l]"); + txtComponent.setHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, new ComponentBuilder(LangUtil.get(clickPlayer, LangPaths.MenuTitle.CANCEL)).create())); + txtComponent.setClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, "cancel")); + clickPlayer.spigot().sendMessage(txtComponent); + } catch (SQLException ex) { Bukkit.getLogger().log(Level.SEVERE, "A SQL error occurred!", ex); } }); for (Builder member : plot.getPlotMembers()) { @@ -401,6 +441,7 @@ protected void setItemClickEvents() { } meta.addEnchant(Enchantment.ARROW_DAMAGE, 1, true); + clickPlayer.playSound(clickPlayer.getLocation(), Utils.INVENTORY_CLICK, 1, 1); ItemStack newItem = getMenu().getSlot(slot).getItem(clickPlayer); newItem.setItemMeta(meta); @@ -415,7 +456,7 @@ protected void setItemClickEvents() { protected Mask getMask() { return BinaryMask.builder(getMenu()) .item(new ItemBuilder(Material.STAINED_GLASS_PANE, 1, (byte) 7).setName(" ").build()) - .pattern("111101111") + .pattern("101101101") .pattern("100000001") .pattern("100000001") .pattern("100000001") 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..b6b0d053 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; } @@ -38,7 +38,7 @@ protected void setMenuItemsAsync() { // Set language items for (int i = 0; i < LangUtil.languages.length; i++) { LangUtil.LanguageFile langFile = LangUtil.languages[i]; - getMenu().getSlot(i).setItem( + getMenu().getSlot(i + 1).setItem( new ItemBuilder(langFile.getHead()) .setName("§6§l" + langFile.getLangName()) .build()); @@ -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) -> { + getMenu().getSlot(i + 1).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..81078591 --- /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) + " §7§l[§c§lBETA§7§l]") // temporary BETA tag + .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..6ee29906 100644 --- a/src/main/java/com/alpsbte/plotsystem/core/menus/SettingsMenu.java +++ b/src/main/java/com/alpsbte/plotsystem/core/menus/SettingsMenu.java @@ -11,15 +11,23 @@ import org.ipvp.canvas.mask.BinaryMask; import org.ipvp.canvas.mask.Mask; +import java.util.function.Consumer; + public class SettingsMenu extends AbstractMenu { + private Consumer onBack = (player) -> player.performCommand("companion"); + public SettingsMenu(Player player) { super(3, LangUtil.get(player, LangPaths.MenuTitle.SETTINGS), player); } + public SettingsMenu(Player player, Consumer onBack) { + this(player); + this.onBack = onBack; + } @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,20 +35,35 @@ 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")); + getMenu().getSlot(22).setClickHandler((clickPlayer, clickInformation) -> onBack.accept(clickPlayer)); } @Override 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/menus/companion/CityProjectMenu.java b/src/main/java/com/alpsbte/plotsystem/core/menus/companion/CityProjectMenu.java new file mode 100644 index 00000000..6ee9acbc --- /dev/null +++ b/src/main/java/com/alpsbte/plotsystem/core/menus/companion/CityProjectMenu.java @@ -0,0 +1,206 @@ +package com.alpsbte.plotsystem.core.menus.companion; + +import com.alpsbte.plotsystem.PlotSystem; +import com.alpsbte.plotsystem.core.menus.AbstractPaginatedMenu; +import com.alpsbte.plotsystem.core.system.Builder; +import com.alpsbte.plotsystem.core.system.CityProject; +import com.alpsbte.plotsystem.core.system.Country; +import com.alpsbte.plotsystem.core.system.plot.PlotManager; +import com.alpsbte.plotsystem.core.system.plot.generator.DefaultPlotGenerator; +import com.alpsbte.plotsystem.utils.Utils; +import com.alpsbte.plotsystem.utils.enums.PlotDifficulty; +import com.alpsbte.plotsystem.utils.enums.Status; +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.alpsbte.plotsystem.utils.items.MenuItems; +import com.alpsbte.plotsystem.utils.items.builder.ItemBuilder; +import com.alpsbte.plotsystem.utils.items.builder.LoreBuilder; +import org.bukkit.Bukkit; +import org.bukkit.Material; +import org.bukkit.entity.Player; +import org.ipvp.canvas.mask.BinaryMask; +import org.ipvp.canvas.mask.Mask; + +import java.sql.SQLException; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ExecutionException; +import java.util.logging.Level; +import java.util.stream.Collectors; + +public class CityProjectMenu extends AbstractPaginatedMenu { + Country country; + List projects; + private PlotDifficulty selectedPlotDifficulty; + + CityProjectMenu(Player player, Country country, PlotDifficulty selectedPlotDifficulty) { + super(6, 4, country.getName() + " -> " + LangUtil.get(player, LangPaths.MenuTitle.COMPANION_SELECT_CITY), player); + this.country = country; + this.selectedPlotDifficulty = selectedPlotDifficulty; + } + + @Override + protected void setPreviewItems() { + getMenu().getSlot(1).setItem(MenuItems.backMenuItem(getMenuPlayer())); + + for (Map.Entry entry : CompanionMenu.getFooterItems(45, getMenuPlayer(), player -> { + player.closeInventory(); + new CountryMenu(player, country.getContinent()); + }).entrySet()) { + getMenu().getSlot(entry.getKey()).setItem(entry.getValue().item); + } + + getMenu().getSlot(4) + .setItem(new ItemBuilder(Material.valueOf(PlotSystem.getPlugin().getConfigManager().getConfig().getString(ConfigPaths.NAVIGATOR_ITEM)), 1) + .setName("§6§l" + LangUtil.get(getMenuPlayer(), LangPaths.MenuTitle.NAVIGATOR)).setLore(new LoreBuilder() + .addLine(LangUtil.get(getMenuPlayer(), LangPaths.MenuDescription.NAVIGATOR)).build()) + .build()); + + // Set loading item for plots difficulty item + getMenu().getSlot(7).setItem(MenuItems.loadingItem(Material.SKULL_ITEM, (byte) 3, getMenuPlayer())); + + super.setPreviewItems(); + } + + @Override + protected void setMenuItemsAsync() { + // Set previous page item + if (hasPreviousPage()) { + getMenu().getSlot(45).setItem(MenuItems.previousPageItem(getMenuPlayer())); + } + + // Set next page item + if (hasNextPage()) { + getMenu().getSlot(53).setItem(MenuItems.nextPageItem(getMenuPlayer())); + } + + // difficulty selector + getMenu().getSlot(7).setItem(CompanionMenu.getDifficultyItem(getMenuPlayer(), selectedPlotDifficulty)); + } + + @Override + protected void setItemClickEventsAsync() { + getMenu().getSlot(1).setClickHandler((clickPlayer, clickInformation) -> { + clickPlayer.closeInventory(); + new CountryMenu(clickPlayer, country.getContinent(), selectedPlotDifficulty); + }); + + // Set click event for navigator item + getMenu().getSlot(4).setClickHandler((clickPlayer, clickInformation) -> { + clickPlayer.closeInventory(); + clickPlayer.performCommand(PlotSystem.getPlugin().getConfigManager().getConfig().getString(ConfigPaths.NAVIGATOR_COMMAND)); + }); + + // Set click event for previous page item + getMenu().getSlot(45).setClickHandler((clickPlayer, clickInformation) -> { + if (hasPreviousPage()) { + previousPage(); + clickPlayer.playSound(clickPlayer.getLocation(), Utils.INVENTORY_CLICK, 1, 1); + } + }); + + // Set click event for next page item + getMenu().getSlot(53).setClickHandler((clickPlayer, clickInformation) -> { + if (hasNextPage()) { + nextPage(); + clickPlayer.playSound(clickPlayer.getLocation(), Utils.INVENTORY_CLICK, 1, 1); + } + }); + + for (Map.Entry entry : CompanionMenu.getFooterItems(45, getMenuPlayer(), player -> { + player.closeInventory(); + new CountryMenu(player, country.getContinent()); + }).entrySet()) { + getMenu().getSlot(entry.getKey()).setClickHandler(entry.getValue().clickHandler); + } + + // Set click event for plots difficulty item + getMenu().getSlot(7).setClickHandler(((clickPlayer, clickInformation) -> { + selectedPlotDifficulty = (selectedPlotDifficulty == null ? + PlotDifficulty.values()[0] : selectedPlotDifficulty.ordinal() != PlotDifficulty.values().length - 1 ? + PlotDifficulty.values()[selectedPlotDifficulty.ordinal() + 1] : null); + + getMenu().getSlot(7).setItem(CompanionMenu.getDifficultyItem(getMenuPlayer(), selectedPlotDifficulty)); + clickPlayer.playSound(clickPlayer.getLocation(), Utils.Done, 1, 1); + + // reload displayed cities + reloadMenuAsync(); + })); + } + + @Override + protected Mask getMask() { + return BinaryMask.builder(getMenu()) + .item(new ItemBuilder(Material.STAINED_GLASS_PANE, 1, (byte) 7).setName(" ").build()) + .pattern("101101101") + .pattern("000000000") + .pattern("000000000") + .pattern("000000000") + .pattern("000000000") + .pattern("100010001") + .build(); + } + + @Override + protected List getSource() { + if(projects == null) { + projects = CityProject.getCityProjects(country, true); + } + return projects; + } + + @Override + protected void setPaginatedMenuItemsAsync(List source) { + List cities = source.stream().map(l -> (CityProject) l).collect(Collectors.toList()); + int slot = 9; + for (CityProject city : cities) { + try { + getMenu().getSlot(slot).setItem(city.getItem(getMenuPlayer(), selectedPlotDifficulty)); + } catch (SQLException e) { + Bukkit.getLogger().log(Level.SEVERE, "A SQL error occurred!", e); + getMenu().getSlot(slot).setItem(MenuItems.errorItem(getMenuPlayer())); + } + slot++; + } + } + + @Override + protected void setPaginatedItemClickEventsAsync(List source) { + List cities = source.stream().map(l -> (CityProject) l).collect(Collectors.toList()); + int slot = 9; + for(CityProject city : cities) { + final int _slot = slot; + getMenu().getSlot(_slot).setClickHandler((clickPlayer, clickInformation) -> { + if (!getMenu().getSlot(_slot).getItem(clickPlayer).equals(MenuItems.errorItem(getMenuPlayer()))) { + try { + clickPlayer.closeInventory(); + Builder builder = Builder.byUUID(clickPlayer.getUniqueId()); + int cityID = city.getID(); + + PlotDifficulty plotDifficultyForCity = selectedPlotDifficulty != null ? selectedPlotDifficulty : PlotManager.getPlotDifficultyForBuilder(cityID, builder).get(); + if (plotDifficultyForCity != null && PlotManager.getPlots(cityID, plotDifficultyForCity, Status.unclaimed).size() != 0) { + if (selectedPlotDifficulty != null && PlotSystem.getPlugin().getConfigManager().getConfig().getBoolean(ConfigPaths.ENABLE_SCORE_REQUIREMENT) && !PlotManager.hasPlotDifficultyScoreRequirement(builder, selectedPlotDifficulty)) { + clickPlayer.sendMessage(Utils.getErrorMessageFormat(LangUtil.get(clickPlayer, LangPaths.Message.Error.PLAYER_NEEDS_HIGHER_SCORE))); + clickPlayer.playSound(clickPlayer.getLocation(), Utils.ErrorSound, 1, 1); + return; + } + + new DefaultPlotGenerator(cityID, plotDifficultyForCity, builder); + } else { + clickPlayer.sendMessage(Utils.getErrorMessageFormat(LangUtil.get(clickPlayer, LangPaths.Message.Error.NO_PLOTS_LEFT))); + clickPlayer.playSound(clickPlayer.getLocation(), Utils.ErrorSound, 1, 1); + } + } catch (SQLException | ExecutionException | InterruptedException ex) { + Bukkit.getLogger().log(Level.SEVERE, "A SQL error occurred!", ex); + clickPlayer.sendMessage(Utils.getErrorMessageFormat(LangUtil.get(clickPlayer, LangPaths.Message.Error.ERROR_OCCURRED))); + clickPlayer.playSound(clickPlayer.getLocation(), Utils.ErrorSound, 1, 1); + } + } else { + clickPlayer.playSound(clickPlayer.getLocation(), Utils.ErrorSound, 1, 1); + } + }); + slot++; + } + } +} diff --git a/src/main/java/com/alpsbte/plotsystem/core/menus/companion/CompanionMenu.java b/src/main/java/com/alpsbte/plotsystem/core/menus/companion/CompanionMenu.java new file mode 100644 index 00000000..ffb7916d --- /dev/null +++ b/src/main/java/com/alpsbte/plotsystem/core/menus/companion/CompanionMenu.java @@ -0,0 +1,167 @@ +package com.alpsbte.plotsystem.core.menus.companion; + +import com.alpsbte.plotsystem.core.menus.BuilderUtilitiesMenu; +import com.alpsbte.plotsystem.core.menus.PlayerPlotsMenu; +import com.alpsbte.plotsystem.core.menus.PlotActionsMenu; +import com.alpsbte.plotsystem.core.menus.SettingsMenu; +import com.alpsbte.plotsystem.core.system.Builder; +import com.alpsbte.plotsystem.core.system.Country; +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.Continent; +import com.alpsbte.plotsystem.utils.enums.PlotDifficulty; +import com.alpsbte.plotsystem.utils.enums.Slot; +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.Bukkit; +import org.bukkit.Material; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; + +import java.sql.SQLException; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Optional; +import java.util.function.Consumer; +import java.util.logging.Level; + +public class CompanionMenu { + public static boolean hasContinentView() { + return Arrays.stream(Continent.values()).map(continent -> Country.getCountries(continent).size()).filter(count -> count > 0).count() > 1; + } + + /** + * Determine what menu to open for the player + * + * @param player player to open the menu for + */ + public static void open(Player player) { + if (hasContinentView()) { + new ContinentMenu(player); + } else { + Optional continent = Arrays.stream(Continent.values()).filter(c -> Country.getCountries(c).size() > 0).findFirst(); + + if (!continent.isPresent()) { + player.sendMessage(Utils.getErrorMessageFormat(LangUtil.get(player, LangPaths.Message.Error.ERROR_OCCURRED))); + return; + } + + new CountryMenu(player, continent.get()); + } + } + + /** + * Get common footer items between all companion menus + * + * @param startingSlot slot to start drawing items at + * @param player player that is viewing this (translation purposes) + * @param returnToMenu a lambda to call when needing to return to current menu + * @return FooterItems indexed by slot number + */ + public static HashMap getFooterItems(int startingSlot, Player player, Consumer returnToMenu) { + HashMap items = new HashMap<>(); + // Set builder utilities menu item + items.put(startingSlot + 5, new FooterItem(BuilderUtilitiesMenu.getMenuItem(player), (clickPlayer, clickInformation) -> { + clickPlayer.closeInventory(); + new BuilderUtilitiesMenu(clickPlayer); + })); + + // Set player plots menu item + items.put(startingSlot + 6, new FooterItem(PlayerPlotsMenu.getMenuItem(player), (clickPlayer, clickInformation) -> { + clickPlayer.closeInventory(); + clickPlayer.performCommand("plots " + clickPlayer.getName()); + })); + + // Set player settings menu item + items.put(startingSlot + 7, new FooterItem(new ItemBuilder(Material.REDSTONE_COMPARATOR) + .setName("§b§l" + LangUtil.get(player, LangPaths.MenuTitle.SETTINGS)) + .setLore(new LoreBuilder() + .addLine(LangUtil.get(player, LangPaths.MenuDescription.SETTINGS)).build()) + .build(), (clickPlayer, clickInformation) -> new SettingsMenu(clickPlayer, returnToMenu))); + + for (int i = 0; i < 3; i++) { + try { + Builder builder = Builder.byUUID(player.getUniqueId()); + + final int i_ = i; + + Plot plot = builder.getPlot(Slot.values()[i]); + items.put(startingSlot + 1 + i, new FooterItem(builder.getPlotMenuItem(plot, Slot.values()[i].ordinal(), player), (clickPlayer, clickInformation) -> { + if (plot != null) { + clickPlayer.closeInventory(); + try { + new PlotActionsMenu(clickPlayer, builder.getPlot(Slot.values()[i_])); + } catch (SQLException ex) { + clickPlayer.sendMessage(Utils.getErrorMessageFormat(LangUtil.get(clickPlayer, LangPaths.Message.Error.ERROR_OCCURRED))); + clickPlayer.playSound(clickPlayer.getLocation(), Utils.ErrorSound, 1, 1); + Bukkit.getLogger().log(Level.SEVERE, "An error occurred while opening the plot actions menu!", ex); + } + } + })); + } catch (NullPointerException | SQLException ex) { + Bukkit.getLogger().log(Level.SEVERE, "An error occurred while placing player slot items!", ex); + items.put(startingSlot + 1 + i, new FooterItem(MenuItems.errorItem(player))); + } + } + + return items; + } + + public static ItemStack getDifficultyItem(Player player, PlotDifficulty selectedPlotDifficulty) { + ItemStack item = Utils.getItemHead(Utils.CustomHead.WHITE_CONCRETE); + + if (selectedPlotDifficulty != null) { + if (selectedPlotDifficulty == PlotDifficulty.EASY) { + item = Utils.getItemHead(Utils.CustomHead.GREEN_CONCRETE); + } else if (selectedPlotDifficulty == PlotDifficulty.MEDIUM) { + item = Utils.getItemHead(Utils.CustomHead.YELLOW_CONCRETE); + } else if (selectedPlotDifficulty == PlotDifficulty.HARD) { + item = Utils.getItemHead(Utils.CustomHead.RED_CONCRETE); + } + } + + try { + return new ItemBuilder(item) + .setName("§b§l" + LangUtil.get(player, LangPaths.MenuTitle.PLOT_DIFFICULTY).toUpperCase()) + .setLore(new LoreBuilder() + .addLines("", + selectedPlotDifficulty != null ? Utils.getFormattedDifficulty(selectedPlotDifficulty) : "§f§l" + LangUtil.get(player, LangPaths.Difficulty.AUTOMATIC), + selectedPlotDifficulty != null ? "§7" + LangUtil.get(player, LangPaths.Difficulty.SCORE_MULTIPLIER) + ": §fx" + PlotManager.getMultiplierByDifficulty(selectedPlotDifficulty) : "", + "", + "§7" + LangUtil.get(player, LangPaths.MenuDescription.PLOT_DIFFICULTY)) + .build()) + .build(); + } catch (SQLException ex) { + Bukkit.getLogger().log(Level.SEVERE, "A SQL error occurred!", ex); + return MenuItems.errorItem(player); + } + } + + /** + * @return Menu item + */ + 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) + ")") + .setEnchanted(true) + .build(); + } + + static class FooterItem { + public ItemStack item; + public org.ipvp.canvas.slot.Slot.ClickHandler clickHandler = null; + + FooterItem(ItemStack item, org.ipvp.canvas.slot.Slot.ClickHandler clickHandler) { + this.item = item; + this.clickHandler = clickHandler; + } + + FooterItem(ItemStack item) { + this.item = item; + } + } +} diff --git a/src/main/java/com/alpsbte/plotsystem/core/menus/companion/ContinentMenu.java b/src/main/java/com/alpsbte/plotsystem/core/menus/companion/ContinentMenu.java new file mode 100644 index 00000000..142f71ff --- /dev/null +++ b/src/main/java/com/alpsbte/plotsystem/core/menus/companion/ContinentMenu.java @@ -0,0 +1,77 @@ +package com.alpsbte.plotsystem.core.menus.companion; + +import com.alpsbte.plotsystem.core.menus.AbstractMenu; +import com.alpsbte.plotsystem.utils.enums.Continent; +import com.alpsbte.plotsystem.utils.io.language.LangPaths; +import com.alpsbte.plotsystem.utils.io.language.LangUtil; +import com.alpsbte.plotsystem.utils.items.builder.ItemBuilder; +import org.bukkit.Material; +import org.bukkit.entity.Player; +import org.ipvp.canvas.mask.BinaryMask; +import org.ipvp.canvas.mask.Mask; + +import java.util.HashMap; +import java.util.Map; + +public class ContinentMenu extends AbstractMenu { + private final HashMap layout = new HashMap<>(); + + ContinentMenu(Player menuPlayer) { + super(5, LangUtil.get(menuPlayer, LangPaths.MenuTitle.COMPANION_SELECT_CONTINENT), menuPlayer); + + layout.put(9, Continent.NORTH_AMERICA); + layout.put(11, Continent.SOUTH_AMERICA); + layout.put(13, Continent.EUROPE); + layout.put(15, Continent.AFRICA); + layout.put(17, Continent.ASIA); + layout.put(22, Continent.OCEANIA); + } + + @Override + protected void setPreviewItems() { + for(Map.Entry entry : CompanionMenu.getFooterItems(9 * 4,getMenuPlayer(), player -> { + player.closeInventory(); + new ContinentMenu(player); + }).entrySet()) { + getMenu().getSlot(entry.getKey()).setItem(entry.getValue().item); + } + + super.setPreviewItems(); + } + + @Override + protected void setMenuItemsAsync() { + for(Map.Entry continent : layout.entrySet()) { + getMenu().getSlot(continent.getKey()).setItem(continent.getValue().getItem(getMenuPlayer())); + } + } + + @Override + protected void setItemClickEventsAsync() { + for(Map.Entry continent : layout.entrySet()) { + getMenu().getSlot(continent.getKey()).setClickHandler((clickPlayer, clickInfo) -> { + clickPlayer.closeInventory(); + new CountryMenu(clickPlayer, continent.getValue()); + }); + } + + for(Map.Entry entry : CompanionMenu.getFooterItems(9 * 4,getMenuPlayer(), player -> { + player.closeInventory(); + new ContinentMenu(player); + }).entrySet()) { + getMenu().getSlot(entry.getKey()).setClickHandler(entry.getValue().clickHandler); + } + } + + @Override + protected Mask getMask() { + return BinaryMask.builder(getMenu()) + .item(new ItemBuilder(Material.STAINED_GLASS_PANE, 1, (byte) 7).setName(" ").build()) + .pattern("111111111") + .pattern("010101010") + .pattern("111101111") + .pattern("111111111") + .pattern("100010001") + .build(); + } +} diff --git a/src/main/java/com/alpsbte/plotsystem/core/menus/companion/CountryMenu.java b/src/main/java/com/alpsbte/plotsystem/core/menus/companion/CountryMenu.java new file mode 100644 index 00000000..de090a04 --- /dev/null +++ b/src/main/java/com/alpsbte/plotsystem/core/menus/companion/CountryMenu.java @@ -0,0 +1,202 @@ +/* + * 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.menus.companion; + +import com.alpsbte.plotsystem.PlotSystem; +import com.alpsbte.plotsystem.core.menus.*; +import com.alpsbte.plotsystem.core.system.CityProject; +import com.alpsbte.plotsystem.core.system.Country; +import com.alpsbte.plotsystem.core.system.plot.PlotManager; +import com.alpsbte.plotsystem.utils.enums.Continent; +import com.alpsbte.plotsystem.utils.io.config.ConfigPaths; +import com.alpsbte.plotsystem.utils.Utils; +import com.alpsbte.plotsystem.utils.enums.PlotDifficulty; +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.alpsbte.plotsystem.utils.items.MenuItems; +import com.alpsbte.plotsystem.utils.items.builder.ItemBuilder; +import com.alpsbte.plotsystem.utils.items.builder.LoreBuilder; +import org.bukkit.Bukkit; +import org.bukkit.Material; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; +import org.ipvp.canvas.mask.BinaryMask; +import org.ipvp.canvas.mask.Mask; + +import java.sql.SQLException; +import java.util.*; +import java.util.logging.Level; + +public class CountryMenu extends AbstractMenu { + private List countryProjects; + private final Continent selectedContinent; + private PlotDifficulty selectedPlotDifficulty = null; + + CountryMenu(Player player, Continent continent) { + super(6, LangUtil.get(player, continent.langPath) + " -> " + LangUtil.get(player, LangPaths.MenuTitle.COMPANION_SELECT_COUNTRY) , player); + selectedContinent = continent; + } + + CountryMenu(Player player, Continent continent, PlotDifficulty plotDifficulty) { + this(player, continent); + this.selectedPlotDifficulty = plotDifficulty; + } + + @Override + protected void setPreviewItems() { + // Set navigator item + getMenu().getSlot(4) + .setItem(new ItemBuilder(Material.valueOf(PlotSystem.getPlugin().getConfigManager().getConfig().getString(ConfigPaths.NAVIGATOR_ITEM)), 1) + .setName("§6§l" + LangUtil.get(getMenuPlayer(), LangPaths.MenuTitle.NAVIGATOR)).setLore(new LoreBuilder() + .addLine(LangUtil.get(getMenuPlayer(), LangPaths.MenuDescription.NAVIGATOR)).build()) + .build()); + + // Set loading item for plots difficulty item + getMenu().getSlot(7).setItem(MenuItems.loadingItem(Material.SKULL_ITEM, (byte) 3, getMenuPlayer())); + + for (Map.Entry entry : CompanionMenu.getFooterItems(45, getMenuPlayer(), player -> { + player.closeInventory(); + new CountryMenu(player, selectedContinent); + }).entrySet()) { + getMenu().getSlot(entry.getKey()).setItem(entry.getValue().item); + } + + super.setPreviewItems(); + } + + @Override + protected void setMenuItemsAsync() { + // Set plots difficulty item head + getMenu().getSlot(7).setItem(CompanionMenu.getDifficultyItem(getMenuPlayer(), selectedPlotDifficulty)); + + // Set city project items + try { + countryProjects = Country.getCountries(selectedContinent); + setCountryItems(); + } catch (SQLException ex) { + Bukkit.getLogger().log(Level.SEVERE, "A SQL error occurred!", ex); + } + } + + @Override + protected void setItemClickEventsAsync() { + // Set click event for navigator item + getMenu().getSlot(4).setClickHandler((clickPlayer, clickInformation) -> { + clickPlayer.closeInventory(); + clickPlayer.performCommand(PlotSystem.getPlugin().getConfigManager().getConfig().getString(ConfigPaths.NAVIGATOR_COMMAND)); + }); + + // Set click event for plots difficulty item + getMenu().getSlot(7).setClickHandler(((clickPlayer, clickInformation) -> { + selectedPlotDifficulty = (selectedPlotDifficulty == null ? + PlotDifficulty.values()[0] : selectedPlotDifficulty.ordinal() != PlotDifficulty.values().length - 1 ? + PlotDifficulty.values()[selectedPlotDifficulty.ordinal() + 1] : null); + + getMenu().getSlot(7).setItem(CompanionMenu.getDifficultyItem(getMenuPlayer(), selectedPlotDifficulty)); + clickPlayer.playSound(clickPlayer.getLocation(), Utils.Done, 1, 1); + + try { + setCountryItems(); + } catch (SQLException ex) { + Bukkit.getLogger().log(Level.SEVERE, "A SQL error occurred!", ex); + } + })); + + int startingSlot = 9; + if (CompanionMenu.hasContinentView()) { + getMenu().getSlot(0).setClickHandler((clickPlayer, clickInformation) -> { + clickPlayer.closeInventory(); + new ContinentMenu(clickPlayer); + }); + } + + for (Country country : countryProjects) { + int i = countryProjects.indexOf(country); + getMenu().getSlot(startingSlot + i).setClickHandler((clickPlayer, clickInformation) -> { + clickPlayer.closeInventory(); + new CityProjectMenu(clickPlayer, country, selectedPlotDifficulty); + }); + } + + for (Map.Entry entry : CompanionMenu.getFooterItems(45, getMenuPlayer(), player -> { + player.closeInventory(); + new CountryMenu(player, selectedContinent); + }).entrySet()) { + getMenu().getSlot(entry.getKey()).setClickHandler(entry.getValue().clickHandler); + } + } + + @Override + protected Mask getMask() { + return BinaryMask.builder(getMenu()) + .item(new ItemBuilder(Material.STAINED_GLASS_PANE, 1, (byte) 7).setName(" ").build()) + .pattern("011101111") + .pattern("000000000") + .pattern("000000000") + .pattern("000000000") + .pattern("000000000") + .pattern("100010001") + .build(); + } + + private void setCountryItems() throws SQLException { + int startingSlot = 9; + if (CompanionMenu.hasContinentView()) { + getMenu().getSlot(0).setItem(new ItemBuilder(Utils.getItemHead(new Utils.CustomHead("9219"))) + .setName("§b§lBack") + .build()); + } else { + getMenu().getSlot(0).setItem(new ItemBuilder(Material.STAINED_GLASS_PANE, 1, (byte) 7).setName(" ").build()); + } + + for (Country country : countryProjects) { + ItemStack item = country.getHead(); + + List cities = country.getCityProjects(); + int plotsOpen = PlotManager.getPlots(cities, Status.unclaimed).size(); + int plotsInProgress = PlotManager.getPlots(cities, Status.unfinished, Status.unreviewed).size(); + int plotsCompleted = PlotManager.getPlots(cities, Status.completed).size(); + int plotsUnclaimed = PlotManager.getPlots(cities, Status.unclaimed).size(); + + getMenu().getSlot(startingSlot + countryProjects.indexOf(country)).setItem(new ItemBuilder(item) + .setName("§b§l" + country.getName()) + .setLore(new LoreBuilder() + .addLines( + "§6" + cities.size() + " §7" + LangUtil.get(getMenuPlayer(), LangPaths.CityProject.CITIES), + "", + "§6" + plotsOpen + " §7" + LangUtil.get(getMenuPlayer(), LangPaths.CityProject.PROJECT_OPEN), + "§8---------------------", + "§6" + plotsInProgress + " §7" + LangUtil.get(getMenuPlayer(), LangPaths.CityProject.PROJECT_IN_PROGRESS), + "§6" + plotsCompleted + " §7" + LangUtil.get(getMenuPlayer(), LangPaths.CityProject.PROJECT_COMPLETED), + "", + (plotsUnclaimed > 0 ? "§a§l" + LangUtil.get(getMenuPlayer(), LangPaths.CityProject.PROJECT_PLOTS_AVAILABLE) : "§f§l" + LangUtil.get(getMenuPlayer(), LangPaths.CityProject.PROJECT_NO_PLOTS_AVAILABLE)) + ) + .build()) + .build()); + } + } + +} \ No newline at end of file diff --git a/src/main/java/com/alpsbte/plotsystem/core/system/BuildTeam.java b/src/main/java/com/alpsbte/plotsystem/core/system/BuildTeam.java new file mode 100644 index 00000000..c3c8bb5c --- /dev/null +++ b/src/main/java/com/alpsbte/plotsystem/core/system/BuildTeam.java @@ -0,0 +1,146 @@ +/* + * The MIT License (MIT) + * + * Copyright © 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; + +import com.alpsbte.plotsystem.core.database.DatabaseConnection; +import org.bukkit.Bukkit; + +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; +import java.util.logging.Level; + +public class BuildTeam { + private final int ID; + private String name; + + private BuildTeam(int ID) throws SQLException { + this.ID = ID; + + try (ResultSet rs = DatabaseConnection.createStatement("SELECT name FROM plotsystem_buildteams WHERE id = ?") + .setValue(ID).executeQuery()) { + + if (rs.next()) this.name = rs.getString(1); + DatabaseConnection.closeResultSet(rs); + } + } + + public int getID() { + return ID; + } + + public String getName() { + return name; + } + + public List getCountries() throws SQLException { + try (ResultSet rs = DatabaseConnection.createStatement("SELECT country_id FROM plotsystem_buildteam_has_countries WHERE buildteam_id = ?") + .setValue(ID).executeQuery()) { + + List countries = new ArrayList<>(); + while (rs.next()) countries.add(new Country(rs.getInt(1))); + DatabaseConnection.closeResultSet(rs); + return countries; + } + } + + public List getReviewers() throws SQLException { + try (ResultSet rs = DatabaseConnection.createStatement("SELECT builder_uuid FROM plotsystem_builder_is_reviewer WHERE buildteam_id = ?") + .setValue(ID).executeQuery()) { + + List builders = new ArrayList<>(); + while (rs.next()) builders.add(Builder.byUUID(UUID.fromString(rs.getString(1)))); + DatabaseConnection.closeResultSet(rs); + return builders; + } + } + + public static List getBuildTeamsByReviewer(UUID reviewerUUID) throws SQLException { + try (ResultSet rs = DatabaseConnection.createStatement("SELECT buildteam_id FROM plotsystem_builder_is_reviewer WHERE builder_uuid = ?") + .setValue(reviewerUUID.toString()).executeQuery()) { + + List buildTeams = new ArrayList<>(); + while (rs.next()) buildTeams.add(new BuildTeam(rs.getInt(1))); + DatabaseConnection.closeResultSet(rs); + return buildTeams; + } + } + + public static List getBuildTeams() { + try (ResultSet rs = DatabaseConnection.createStatement("SELECT id FROM plotsystem_buildteams").executeQuery()) { + List buildTeams = new ArrayList<>(); + while (rs.next()) buildTeams.add(new BuildTeam(rs.getInt(1))); + DatabaseConnection.closeResultSet(rs); + return buildTeams; + } catch (SQLException ex) { + Bukkit.getLogger().log(Level.SEVERE, "A SQL error occurred!", ex); + } + return new ArrayList<>(); + } + + public static void addBuildTeam(String name) throws SQLException { + int id = DatabaseConnection.getTableID("plotsystem_buildteams"); + DatabaseConnection.createStatement("INSERT INTO plotsystem_buildteams (id, name) VALUES (?, ?)") + .setValue(id) + .setValue(name).executeUpdate(); + } + + public static void removeBuildTeam(int serverID) throws SQLException { + DatabaseConnection.createStatement("DELETE FROM plotsystem_buildteams WHERE id = ?") + .setValue(serverID).executeUpdate(); + } + + public static void setBuildTeamName(int id, String newName) throws SQLException { + DatabaseConnection.createStatement("UPDATE plotsystem_buildteams SET name = ? WHERE id = ?") + .setValue(newName) + .setValue(id).executeUpdate(); + } + + public static void addCountry(int id, int countryID) throws SQLException { + DatabaseConnection.createStatement("INSERT plotsystem_buildteam_has_countries SET country_id = ?, buildteam_id = ?") + .setValue(countryID) + .setValue(id).executeUpdate(); + } + + public static void removeCountry(int id, int countryID) throws SQLException { + DatabaseConnection.createStatement("DELETE FROM plotsystem_buildteam_has_countries WHERE country_id = ? AND buildteam_id = ?") + .setValue(countryID) + .setValue(id).executeUpdate(); + } + + public static void addReviewer(int id, String reviewerUUID) throws SQLException { + DatabaseConnection.createStatement("INSERT plotsystem_builder_is_reviewer SET builder_uuid = ?, buildteam_id = ?") + .setValue(reviewerUUID) + .setValue(id).executeUpdate(); + } + + public static void removeReviewer(int id, String reviewerUUID) throws SQLException { + DatabaseConnection.createStatement("DELETE FROM plotsystem_builder_is_reviewer WHERE builder_uuid = ? AND buildteam_id = ?") + .setValue(reviewerUUID) + .setValue(id).executeUpdate(); + } +} 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 62db4fc8..7bd1f542 100644 --- a/src/main/java/com/alpsbte/plotsystem/core/system/Builder.java +++ b/src/main/java/com/alpsbte/plotsystem/core/system/Builder.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 @@ -25,39 +25,60 @@ package com.alpsbte.plotsystem.core.system; import com.alpsbte.plotsystem.PlotSystem; +import com.alpsbte.plotsystem.core.holograms.HologramManager; import com.alpsbte.plotsystem.core.holograms.HolographicDisplay; +import com.alpsbte.plotsystem.core.holograms.ScoreLeaderboard; import com.alpsbte.plotsystem.core.system.plot.Plot; 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 com.alpsbte.plotsystem.utils.io.language.LangPaths; +import com.alpsbte.plotsystem.utils.io.language.LangUtil; +import com.alpsbte.plotsystem.utils.items.builder.ItemBuilder; +import com.alpsbte.plotsystem.utils.items.builder.LoreBuilder; import org.bukkit.Bukkit; +import org.bukkit.Material; import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; import java.sql.ResultSet; import java.sql.SQLException; -import java.util.ArrayList; -import java.util.List; -import java.util.UUID; +import java.util.*; import java.util.logging.Level; +import java.util.stream.Collectors; public class Builder { - private final UUID UUID; + public static HashMap builders = new HashMap<>(); + + private final UUID uuid; + public PlotType plotType; - public Builder(UUID UUID) { - this.UUID = UUID; + 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 = ?") @@ -110,8 +131,8 @@ public Slot getFreeSlot() throws SQLException { .setValue(getUUID().toString()).executeQuery()) { if (rs.next()) { - for(int i = 1; i <= 3; i++) { - if(rs.getString(i) == null) { + for (int i = 1; i <= 3; i++) { + if (rs.getString(i) == null) { DatabaseConnection.closeResultSet(rs); return Slot.values()[i - 1]; } @@ -137,12 +158,36 @@ public Plot getPlot(Slot slot) throws SQLException { } } + public ItemStack getPlotMenuItem(Plot plot, int slotIndex, Player langPlayer) throws SQLException { + if (plot == null) { + return new ItemBuilder(Material.EMPTY_MAP, 1 + slotIndex) + .setName("§b§l" + LangUtil.get(getPlayer(), LangPaths.MenuTitle.SLOT).toUpperCase() + " " + (slotIndex + 1)) + .setLore(new LoreBuilder() + .addLines("§7" + LangUtil.get(langPlayer, LangPaths.MenuDescription.SLOT), + "", + "§6§l" + LangUtil.get(langPlayer, LangPaths.Plot.STATUS) + ": §7§lUnassigned") // Cant translate because name is stored in the database + .build()) + .build(); + } + + return new ItemBuilder(Material.MAP, 1 + slotIndex) + .setName("§b§l" + LangUtil.get(langPlayer, LangPaths.MenuTitle.SLOT).toUpperCase() + " " + (slotIndex + 1)) + .setLore(new LoreBuilder() + .addLines("§7" + LangUtil.get(langPlayer, LangPaths.Plot.ID) + ": §f" + plot.getID(), + "§7" + LangUtil.get(langPlayer, LangPaths.Plot.CITY) + ": §f" + plot.getCity().getName(), + "§7" + LangUtil.get(langPlayer, LangPaths.Plot.DIFFICULTY) + ": §f" + plot.getDifficulty().name().charAt(0) + plot.getDifficulty().name().substring(1).toLowerCase(), + "", + "§6§l" + LangUtil.get(langPlayer, LangPaths.Plot.STATUS) + ": §7§l" + plot.getStatus().name().substring(0, 1).toUpperCase() + plot.getStatus().name().substring(1) + ).build()) + .build(); + } + public void addScore(int score) throws SQLException { DatabaseConnection.createStatement("UPDATE plotsystem_builders SET score = ? WHERE uuid = ?") .setValue(getScore() + score).setValue(getUUID().toString()) .executeUpdate(); - Bukkit.getScheduler().runTask(PlotSystem.getPlugin(), () -> PlotSystem.getHolograms().stream().filter(holo -> holo instanceof ScoreLeaderboard).findFirst().ifPresent(HolographicDisplay::updateHologram)); + Bukkit.getScheduler().runTask(PlotSystem.getPlugin(), () -> HologramManager.getHolograms().stream().filter(holo -> holo instanceof ScoreLeaderboard).findFirst().ifPresent(HolographicDisplay::updateHologram)); } public void addCompletedBuild(int amount) throws SQLException { @@ -150,7 +195,7 @@ public void addCompletedBuild(int amount) throws SQLException { .setValue(getCompletedBuilds() + amount).setValue(getUUID().toString()) .executeUpdate(); - Bukkit.getScheduler().runTask(PlotSystem.getPlugin(), () -> PlotSystem.getHolograms().stream().filter(holo -> holo instanceof PlotsLeaderboard).findFirst().ifPresent(HolographicDisplay::updateHologram)); + Bukkit.getScheduler().runTask(PlotSystem.getPlugin(), () -> HologramManager.getHolograms().stream().filter(holo -> holo instanceof PlotsLeaderboard).findFirst().ifPresent(HolographicDisplay::updateHologram)); } public void setPlot(int plotID, Slot slot) throws SQLException { @@ -174,7 +219,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); @@ -182,35 +227,139 @@ public static Builder getBuilderByName(String name) throws SQLException { } } - public static List getBuildersByScore(int limit) throws SQLException { - try (ResultSet rs = DatabaseConnection.createStatement("SELECT name, score FROM plotsystem_builders ORDER BY score DESC LIMIT ?") - .setValue(limit).executeQuery()) { + private static String getBuildersByScoreQuery(ScoreLeaderboard.LeaderboardTimeframe sortBy, int limit) { + String minimumDate = null; + switch (sortBy) { + case DAILY: + minimumDate = "(NOW() - INTERVAL 1 DAY)"; + break; + case WEEKLY: + minimumDate = "(NOW() - INTERVAL 1 WEEK)"; + break; + case MONTHLY: + minimumDate = "(NOW() - INTERVAL 1 MONTH)"; + break; + case YEARLY: + minimumDate = "(NOW() - INTERVAL 1 YEAR)"; + break; + default: + // no limits + break; + } - List scoreAsFormat = new ArrayList<>(); - while (rs.next()) { - scoreAsFormat.add(rs.getString(1) + "," + rs.getInt(2)); + // get plot id, owner username, owner uuid, score & date + // sort by score & limit (if set above) by timeframe + return "SELECT plots.id, builders.name, plots.owner_uuid, SUM(plots.score) AS score, reviews.review_date FROM plotsystem_plots AS plots\n" + + "INNER JOIN plotsystem_reviews AS reviews ON plots.review_id = reviews.id\n" + + "INNER JOIN plotsystem_builders AS builders ON builders.uuid = plots.owner_uuid\n" + + (minimumDate != null + ? "WHERE reviews.review_date BETWEEN " + minimumDate + " AND NOW()\n" + : "") + + "GROUP BY plots.owner_uuid \n" + + "ORDER BY score DESC, builders.name\n" + + (limit > 0 ? "LIMIT " + limit : ""); + } + + public static int getBuilderScore(UUID uuid, ScoreLeaderboard.LeaderboardTimeframe sortBy) throws SQLException { + String query = getBuildersByScoreQuery(sortBy, 0); + + try(ResultSet rs = DatabaseConnection.createStatement(query).executeQuery()) { + boolean found = false; + int score = 0; + while(rs.next() && !found) { + if(rs.getString(3).equals(uuid.toString())) { + found = true; + score = rs.getInt(4); + } + } + + if(!found) score = -1; + + DatabaseConnection.closeResultSet(rs); + return score; + } + } + + public static int getBuilderScorePosition(UUID uuid, ScoreLeaderboard.LeaderboardTimeframe sortBy) throws SQLException { + String query = getBuildersByScoreQuery(sortBy, 0); + + try(ResultSet rs = DatabaseConnection.createStatement(query).executeQuery()) { + boolean found = false; + int position = 0; + while(rs.next() && !found) { + position++; + if(rs.getString(3).equals(uuid.toString())) { + found = true; + } } + if(!found) position = -1; + + DatabaseConnection.closeResultSet(rs); + return position; + } + } + + public static int getBuildersInSort(ScoreLeaderboard.LeaderboardTimeframe sortBy) throws SQLException { + String query = "SELECT COUNT(*) FROM (" + getBuildersByScoreQuery(sortBy, 0) + ") results"; + + try(ResultSet rs = DatabaseConnection.createStatement(query).executeQuery()) { + rs.next(); + int position = rs.getInt(1); + DatabaseConnection.closeResultSet(rs); - return scoreAsFormat; + return position; } } - public static List getBuildersByCompletedBuilds(int limit) throws SQLException { + public static class DatabaseEntry { + private final K key; + private final V value; + + DatabaseEntry(K k, V v) { + this.key = k; + this.value = v; + } + + public K getKey() { + return key; + } + + public V getValue() { + return value; + } + } + + public static List> getBuildersByScore(ScoreLeaderboard.LeaderboardTimeframe sortBy) throws SQLException { + String query = getBuildersByScoreQuery(sortBy, 10); + + try(ResultSet rs = DatabaseConnection.createStatement(query).executeQuery()) { + ArrayList> lines = new ArrayList<>(); + + while(rs.next()) { + lines.add(new DatabaseEntry<>(rs.getString(2), rs.getInt(4))); + } + + DatabaseConnection.closeResultSet(rs); + return lines; + } + } + + public static List> getBuildersByCompletedBuilds(int limit) throws SQLException { try (ResultSet rs = DatabaseConnection.createStatement("SELECT name, completed_plots FROM plotsystem_builders ORDER BY completed_plots DESC LIMIT ?") .setValue(limit).executeQuery()) { - List scoreAsFormat = new ArrayList<>(); + ArrayList> results = new ArrayList<>(); while (rs.next()) { - scoreAsFormat.add(rs.getString(1) + "," + rs.getInt(2)); + results.add(new DatabaseEntry<>(rs.getString(1), rs.getInt(2))); } DatabaseConnection.closeResultSet(rs); - return scoreAsFormat; + return results; } } - public Slot getSlot (Plot plot) throws SQLException { + public Slot getSlot(Plot plot) throws SQLException { for (Slot slot : Slot.values()) { Plot slotPlot = getPlot(slot); if (slotPlot != null && slotPlot.getID() == plot.getID()) { @@ -230,7 +379,7 @@ public String getLanguageTag() { } DatabaseConnection.closeResultSet(rs); } catch (SQLException ex) { - Bukkit.getLogger().log(Level.SEVERE,"An error occurred while getting language setting from database", ex); + Bukkit.getLogger().log(Level.SEVERE, "An error occurred while getting language setting from database", ex); } return null; } @@ -245,4 +394,83 @@ 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; + } + + public Reviewer getAsReviewer() throws SQLException { + return new Reviewer(getUUID()); + } + + public boolean isReviewer() throws SQLException { + try (ResultSet rs = DatabaseConnection.createStatement("SELECT COUNT(builder_uuid) FROM plotsystem_builder_is_reviewer WHERE builder_uuid = ?") + .setValue(getUUID().toString()).executeQuery()) { + + int count = 0; + if (rs.next()) count = rs.getInt(1); + DatabaseConnection.closeResultSet(rs); + return count > 0; + } + } + + public static class Reviewer { + private final List buildTeams; + + public Reviewer(UUID reviewerUUID) throws SQLException { + this.buildTeams = BuildTeam.getBuildTeamsByReviewer(reviewerUUID); + } + + public List getCountries() { + Set countries = new HashSet<>(); + buildTeams.forEach(b -> { + try { + countries.addAll(b.getCountries().stream().map(Country::getID).collect(Collectors.toList())); + } catch (SQLException ex) { + Bukkit.getLogger().log(Level.SEVERE, "A SQL error occurred!", ex); + } + }); + + return countries.stream().map(c -> { + try { + return new Country(c); + } catch (SQLException ex) { Bukkit.getLogger().log(Level.SEVERE, "A SQL error occurred!", ex); } + return null; + }).collect(Collectors.toList()); + } + } } diff --git a/src/main/java/com/alpsbte/plotsystem/core/system/CityProject.java b/src/main/java/com/alpsbte/plotsystem/core/system/CityProject.java index 0da09787..f922a8a1 100644 --- a/src/main/java/com/alpsbte/plotsystem/core/system/CityProject.java +++ b/src/main/java/com/alpsbte/plotsystem/core/system/CityProject.java @@ -25,12 +25,24 @@ package com.alpsbte.plotsystem.core.system; import com.alpsbte.plotsystem.core.database.DatabaseConnection; +import com.alpsbte.plotsystem.core.system.plot.PlotManager; +import com.alpsbte.plotsystem.utils.Utils; +import com.alpsbte.plotsystem.utils.enums.PlotDifficulty; +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.alpsbte.plotsystem.utils.items.MenuItems; +import com.alpsbte.plotsystem.utils.items.builder.ItemBuilder; +import com.alpsbte.plotsystem.utils.items.builder.LoreBuilder; import org.bukkit.Bukkit; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; import java.util.List; import java.sql.ResultSet; import java.sql.SQLException; import java.util.*; +import java.util.concurrent.ExecutionException; import java.util.logging.Level; public class CityProject { @@ -79,12 +91,50 @@ public boolean isVisible() { return visible; } - public static List getCityProjects(boolean onlyVisible) { - try (ResultSet rs = DatabaseConnection.createStatement("SELECT id FROM plotsystem_city_projects ORDER BY country_id").executeQuery()) { + public ItemStack getItem(Player player, PlotDifficulty selectedPlotDifficulty) throws SQLException { + ItemStack cpItem = getCountry().getHead(); + try { + PlotDifficulty cpPlotDifficulty = selectedPlotDifficulty != null ? + selectedPlotDifficulty : PlotManager.getPlotDifficultyForBuilder(getID(), Builder.byUUID(player.getUniqueId())).get(); + + int plotsOpen = PlotManager.getPlots(getID(), Status.unclaimed).size(); + int plotsInProgress = PlotManager.getPlots(getID(), Status.unfinished, Status.unreviewed).size(); + int plotsCompleted = PlotManager.getPlots(getID(), Status.completed).size(); + int plotsUnclaimed = cpPlotDifficulty != null ? PlotManager.getPlots(getID(), cpPlotDifficulty, Status.unclaimed).size() : 0; + int plotsOpenForPlayer = cpPlotDifficulty != null && plotsUnclaimed != 0 ? getOpenPlotsForPlayer(getID(), cpPlotDifficulty) : 0; + + return new ItemBuilder(cpItem) + .setName("§b§l" + getName()) + .setLore(new LoreBuilder() + .addLines(getDescription(), + "", + "§6" + plotsOpen + " §7" + LangUtil.get(player, LangPaths.CityProject.PROJECT_OPEN) + " §8" + LangUtil.get(player, LangPaths.CityProject.FOR_YOUR_DIFFICULTY, (plotsOpenForPlayer == 0 ? "§c" : "§a") + plotsOpenForPlayer + "§8"), + "§8---------------------", + "§6" + plotsInProgress + " §7" + LangUtil.get(player, LangPaths.CityProject.PROJECT_IN_PROGRESS), + "§6" + plotsCompleted + " §7" + LangUtil.get(player, LangPaths.CityProject.PROJECT_COMPLETED), + "", + plotsUnclaimed != 0 ? Utils.getFormattedDifficulty(cpPlotDifficulty) : "§f§l" + LangUtil.get(player, LangPaths.CityProject.PROJECT_NO_PLOTS_AVAILABLE) + ).build()) + .build(); + + } catch (SQLException | ExecutionException | InterruptedException ex) { + Bukkit.getLogger().log(Level.SEVERE, "A SQL error occurred!", ex); + return MenuItems.errorItem(player); + } + } + + public static List getCityProjects(Country country, boolean onlyVisible) { + // if country is not null, only get country's city projects, otherwise load all + DatabaseConnection.StatementBuilder statement = DatabaseConnection.createStatement("SELECT id FROM plotsystem_city_projects " + (country == null ? "" : "WHERE country_id = ?") + " ORDER BY country_id"); + if (country != null) { + statement.setValue(country.getID()); + } + + try (ResultSet rs = statement.executeQuery()) { List cityProjects = new ArrayList<>(); while (rs.next()) { CityProject city = new CityProject(rs.getInt(1)); - if(city.isVisible() || !onlyVisible) { + if (city.isVisible() || !onlyVisible) { cityProjects.add(city); } } @@ -97,6 +147,15 @@ public static List getCityProjects(boolean onlyVisible) { return new ArrayList<>(); } + private int getOpenPlotsForPlayer(int plotID, PlotDifficulty plotDifficulty) throws SQLException { + return PlotManager.getPlots(plotID, plotDifficulty, Status.unclaimed).size(); + } + + + public static List getCityProjects(boolean onlyVisible) { + return getCityProjects(null, onlyVisible); + } + public static void addCityProject(Country country, String name) throws SQLException { DatabaseConnection.createStatement("INSERT INTO plotsystem_city_projects (id, name, country_id, description, visible) VALUES (?, ?, ?, ?, ?)") .setValue(DatabaseConnection.getTableID("plotsystem_city_projects")) diff --git a/src/main/java/com/alpsbte/plotsystem/core/system/Country.java b/src/main/java/com/alpsbte/plotsystem/core/system/Country.java index 8d6eab39..2dd123a1 100644 --- a/src/main/java/com/alpsbte/plotsystem/core/system/Country.java +++ b/src/main/java/com/alpsbte/plotsystem/core/system/Country.java @@ -2,6 +2,7 @@ import com.alpsbte.plotsystem.core.database.DatabaseConnection; import com.alpsbte.plotsystem.utils.Utils; +import com.alpsbte.plotsystem.utils.enums.Continent; import org.bukkit.Bukkit; import org.bukkit.inventory.ItemStack; @@ -19,16 +20,19 @@ public class Country { private String name; private String headID; + private String continent; + public Country(int ID) throws SQLException { this.ID = ID; - try (ResultSet rs = DatabaseConnection.createStatement("SELECT server_id, name, head_id FROM plotsystem_countries WHERE id = ?") + try (ResultSet rs = DatabaseConnection.createStatement("SELECT server_id, name, head_id, continent FROM plotsystem_countries WHERE id = ?") .setValue(this.ID).executeQuery()) { if (rs.next()) { this.serverID = rs.getInt(1); this.name = rs.getString(2); this.headID = rs.getString(3); + this.continent = rs.getString(4); } DatabaseConnection.closeResultSet(rs); @@ -48,7 +52,33 @@ public String getName() { } public ItemStack getHead() { - return Utils.getItemHead( new Utils.CustomHead(headID)); + return Utils.getItemHead(new Utils.CustomHead(headID)); + } + + /** + * Get city projects that are inside of this country + *

+ * Might be a good idea to put this in CityProject but could work in both classes + * + * @return CityProjects inside this country + */ + public List getCityProjects() { + try (ResultSet rs = DatabaseConnection.createStatement("SELECT id FROM plotsystem_city_projects WHERE country_id = ?").setValue(getID()).executeQuery()) { + List cityProjects = new ArrayList<>(); + while (rs.next()) { + cityProjects.add(new CityProject(rs.getInt(1))); + } + + DatabaseConnection.closeResultSet(rs); + return cityProjects; + } catch (SQLException ex) { + Bukkit.getLogger().log(Level.SEVERE, "A SQL error occurred!", ex); + } + return new ArrayList<>(); + } + + public Continent getContinent() { + return Continent.fromDatabase(continent); } public static List getCountries() { @@ -66,11 +96,26 @@ public static List getCountries() { return new ArrayList<>(); } - public static void addCountry(int serverID, String name) throws SQLException { - DatabaseConnection.createStatement("INSERT INTO plotsystem_countries (id, name, server_id) VALUES (?, ?, ?)") + public static List getCountries(Continent continent) { + try (ResultSet rs = DatabaseConnection.createStatement("SELECT id FROM plotsystem_countries WHERE continent = ? ORDER BY server_id").setValue(continent.databaseEnum).executeQuery()) { + List countries = new ArrayList<>(); + while (rs.next()) { + countries.add(new Country(rs.getInt(1))); + } + + DatabaseConnection.closeResultSet(rs); + return countries; + } catch (SQLException ex) { + Bukkit.getLogger().log(Level.SEVERE, "A SQL error occurred!", ex); + } + return new ArrayList<>(); + } + + public static void addCountry(int serverID, String name, Continent continent) throws SQLException { + DatabaseConnection.createStatement("INSERT INTO plotsystem_countries (id, name, server_id, continent) VALUES (?, ?, ?, ?)") .setValue(DatabaseConnection.getTableID("plotsystem_countries")) .setValue(name) - .setValue(serverID).executeUpdate(); + .setValue(serverID).setValue(continent.databaseEnum).executeUpdate(); } public static void removeCountry(int countryID) throws SQLException { diff --git a/src/main/java/com/alpsbte/plotsystem/core/system/Payout.java b/src/main/java/com/alpsbte/plotsystem/core/system/Payout.java new file mode 100644 index 00000000..8258ab5e --- /dev/null +++ b/src/main/java/com/alpsbte/plotsystem/core/system/Payout.java @@ -0,0 +1,82 @@ +/* + * 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; + +import com.alpsbte.plotsystem.core.database.DatabaseConnection; +import com.alpsbte.plotsystem.core.holograms.ScoreLeaderboard; + +import java.sql.ResultSet; +import java.sql.SQLException; + +public class Payout { + private final int id; + private final ScoreLeaderboard.LeaderboardTimeframe timeframe; + private final int position; + private final String payoutAmount; + + private Payout(int id, ScoreLeaderboard.LeaderboardTimeframe timeframe, int position, String payoutAmount) { + this.id = id; + this.timeframe = timeframe; + this.position = position; + this.payoutAmount = payoutAmount; + } + + public static Payout getPayout(ScoreLeaderboard.LeaderboardTimeframe timeframe, int position) throws SQLException { + if(timeframe == ScoreLeaderboard.LeaderboardTimeframe.LIFETIME) { + throw new IllegalArgumentException("Invalid option LIFETIME"); + } + if(position < 1 || position > 10){ + throw new IllegalArgumentException("Illegal position " + position); + } + + try (ResultSet rs = DatabaseConnection.createStatement("SELECT id, timeframe, position, payout_amount FROM plotsystem_payouts WHERE timeframe = ? AND position = ?") + .setValue(timeframe.name()).setValue(position).executeQuery()) { + Payout instance = null; + + if (rs.next()) { + instance = new Payout(rs.getInt(1), ScoreLeaderboard.LeaderboardTimeframe.valueOf(rs.getString(2)), rs.getInt(3), rs.getString(4)); + } + + DatabaseConnection.closeResultSet(rs); + return instance; + } + } + + public int getId() { + return id; + } + + public ScoreLeaderboard.LeaderboardTimeframe getTimeframe() { + return timeframe; + } + + public int getPosition() { + return position; + } + + public String getPayoutAmount() { + return payoutAmount; + } +} \ No newline at end of file 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..62d460e6 100644 --- a/src/main/java/com/alpsbte/plotsystem/core/system/Review.java +++ b/src/main/java/com/alpsbte/plotsystem/core/system/Review.java @@ -24,13 +24,19 @@ package com.alpsbte.plotsystem.core.system; +import com.alpsbte.plotsystem.PlotSystem; import com.alpsbte.plotsystem.core.database.DatabaseConnection; import com.alpsbte.plotsystem.core.system.plot.Plot; import com.alpsbte.plotsystem.core.system.plot.PlotManager; +import com.alpsbte.plotsystem.utils.ChatFeedbackInput; +import com.alpsbte.plotsystem.utils.Utils; import com.alpsbte.plotsystem.utils.enums.Category; import com.alpsbte.plotsystem.utils.enums.Status; import com.alpsbte.plotsystem.utils.ftp.FTPManager; +import com.alpsbte.plotsystem.utils.io.language.LangPaths; +import com.alpsbte.plotsystem.utils.io.language.LangUtil; import org.bukkit.Bukkit; +import org.bukkit.entity.Player; import java.io.IOException; import java.net.URISyntaxException; @@ -38,11 +44,14 @@ import java.nio.file.Paths; import java.sql.*; import java.time.LocalDate; +import java.time.LocalDateTime; +import java.util.HashMap; import java.util.UUID; import java.util.concurrent.CompletableFuture; import java.util.logging.Level; public class Review { + public static HashMap awaitReviewerFeedbackList = new HashMap<>(); private final int reviewID; @@ -93,7 +102,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); @@ -244,7 +253,7 @@ public static void undoReview(Review review) throws SQLException { Files.deleteIfExists(Paths.get(PlotManager.getDefaultSchematicPath(), String.valueOf(plot.getCity().getCountry().getServer().getID()), "finishedSchematics", String.valueOf(plot.getCity().getID()), plot.getID() + ".schematic")); Server plotServer = plot.getCity().getCountry().getServer(); if (plotServer.getFTPConfiguration() != null) { - FTPManager.deleteSchematics(FTPManager.getFTPUrl(plotServer, plot.getCity().getID()), plot.getID() + ".schematic", true); + FTPManager.deleteSchematic(FTPManager.getFTPUrl(plotServer, plot.getCity().getID()), plot.getID() + ".schematic"); } DatabaseConnection.createStatement("UPDATE plotsystem_plots SET review_id = DEFAULT(review_id) WHERE id = ?") @@ -260,4 +269,18 @@ public static void undoReview(Review review) throws SQLException { } }); } + + public static void checkReviewerFeedbackList() { + Bukkit.getScheduler().runTaskTimerAsynchronously(PlotSystem.getPlugin(), () -> { + if (!awaitReviewerFeedbackList.isEmpty()) { + for (Player player : Bukkit.getOnlinePlayers()) { + if (awaitReviewerFeedbackList.containsKey(player.getUniqueId()) && awaitReviewerFeedbackList.get(player.getUniqueId()).getDateTime().isBefore(LocalDateTime.now().minusMinutes(5))) { + awaitReviewerFeedbackList.remove(player.getUniqueId()); + player.sendMessage(Utils.getErrorMessageFormat(LangUtil.get(player, LangPaths.Message.Error.FEEDBACK_INPUT_EXPIRED))); + player.playSound(player.getLocation(), Utils.ErrorSound, 1f, 1f); + } + } + } + }, 0L, 20 * 60); + } } 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..95369980 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,56 +81,86 @@ 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 { - if (plot.getWorld().isWorldGenerated() && abandonPlot(plot)) { + if (abandonPlot(plot)) { try { CompletableFuture.runAsync(() -> { try { @@ -131,9 +168,12 @@ public static boolean deletePlot(Plot plot) throws SQLException { Files.deleteIfExists(Paths.get(PlotManager.getDefaultSchematicPath(), String.valueOf(plotServer.getID()), "finishedSchematics", String.valueOf(plot.getCity().getID()), plot.getID() + ".schematic")); Files.deleteIfExists(Paths.get(PlotManager.getDefaultSchematicPath(), String.valueOf(plotServer.getID()), String.valueOf(plot.getCity().getID()), plot.getID() + ".schematic")); + Files.deleteIfExists(Paths.get(PlotManager.getDefaultSchematicPath(), String.valueOf(plotServer.getID()), String.valueOf(plot.getCity().getID()), plot.getID() + "-env.schematic")); if (plotServer.getFTPConfiguration() != null) { - FTPManager.deleteSchematics(FTPManager.getFTPUrl(plotServer, plot.getCity().getID()), plot.getID() + ".schematic", false); + FTPManager.deleteSchematic(FTPManager.getFTPUrl(plotServer, plot.getCity().getID()), plot.getID() + ".schematic"); + FTPManager.deleteSchematic(FTPManager.getFTPUrl(plotServer, plot.getCity().getID()).replaceFirst("finishedSchematics/",""), plot.getID() + ".schematic"); + FTPManager.deleteSchematic(FTPManager.getFTPUrl(plotServer, plot.getCity().getID()).replaceFirst("finishedSchematics/",""), plot.getID() + "-env.schematic"); } DatabaseConnection.createStatement("DELETE FROM plotsystem_plots WHERE id = ?") @@ -184,8 +224,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 +241,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..7c302dad 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,18 @@ package com.alpsbte.plotsystem.core.system.plot; +import com.alpsbte.plotsystem.core.system.Country; +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.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,28 +53,96 @@ 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 com.sk89q.worldguard.protection.regions.ProtectedRegion; 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; import java.io.FileOutputStream; import java.io.IOException; import java.net.URISyntaxException; 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,14 +160,42 @@ 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().toString() + "'", statuses)).executeQuery()); + plots.addAll(getPlotsAsMember(builder, statuses)); + return plots; + } + + public static List getPlots(List countries, Status status) throws SQLException { + List cities = new ArrayList<>(); + countries.forEach(c -> cities.addAll(c.getCityProjects())); + return getPlots(cities, status); + } + + // 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; } public static List getPlots(int cityID, Status... statuses) throws SQLException { - return listPlots(DatabaseConnection.createStatement(getStatusQuery("' AND city_project_id = '" + cityID, statuses)).executeQuery()); + return listPlots(DatabaseConnection.createStatement(getStatusQuery(" AND city_project_id = '" + cityID + "'", statuses)).executeQuery()); + } + + public static List getPlots(List cities, Status... statuses) throws SQLException { + if(cities.size() == 0) { + return new ArrayList<>(); + } + StringBuilder query = new StringBuilder(" AND (city_project_id = "); + + for (int i = 0; i < cities.size(); i++) { + query.append(cities.get(i).getID()); + query.append((i != cities.size() - 1) ? " OR city_project_id = " : ")"); + } + + return listPlots(DatabaseConnection.createStatement(getStatusQuery(query.toString(), statuses)).executeQuery()); } public static List getPlots(int cityID, PlotDifficulty plotDifficulty, Status status) throws SQLException { @@ -103,8 +209,8 @@ public static List getPlots(int cityID, PlotDifficulty plotDifficulty, Sta private static String getStatusQuery(String additionalQuery, Status... statuses) { StringBuilder query = new StringBuilder("SELECT id FROM plotsystem_plots WHERE status = "); - for(int i = 0; i < statuses.length; i++) { - query.append("'").append(statuses[i].name()).append(additionalQuery).append("'"); + for (int i = 0; i < statuses.length; i++) { + query.append("'").append(statuses[i].name()).append("'").append(additionalQuery); query.append((i != statuses.length - 1) ? " OR status = " : ""); } return query.toString(); @@ -143,145 +249,149 @@ private static List listPlots(ResultSet rs) throws SQLException { List plots = new ArrayList<>(); while (rs.next()) { - plots.add(new Plot(rs.getInt(1))); + plots.add(new Plot(rs.getInt(1))); } DatabaseConnection.closeResultSet(rs); 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 + if (plot.getPlotType() != PlotType.CITY_INSPIRATION_MODE && plot.getVersion() >= 3) { + AbstractPlotGenerator.pasteSchematic(null, plot.getFinishedSchematic(), new CityPlotWorld(plot), false); + } + return true; } - return null; - }); + } } - - return true; + return false; } public static CompletableFuture convertTerraToPlotXZ(Plot plot, double[] terraCoords) throws IOException { - // Load plot outlines schematic as clipboard - Clipboard outlinesClipboard = ClipboardFormat.SCHEMATIC.getReader(new FileInputStream(plot.getOutlinesSchematic())).read(null); - - // 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); - - Vector schematicMinPoint = Vector.toBlockPoint( - PlotManager.getPlotCenter().getX() - outlinesClipboardCenterX + ((outlinesClipboard.getRegion().getWidth() % 2 == 0 ? 1 : 0)), - 0, - PlotManager.getPlotCenter().getZ() - outlinesClipboardCenterZ + ((outlinesClipboard.getRegion().getLength() % 2 == 0 ? 1 : 0)) - ); - - Vector schematicMaxPoint = Vector.toBlockPoint( - PlotManager.getPlotCenter().getX() + outlinesClipboardCenterX, - 256, - PlotManager.getPlotCenter().getZ() + outlinesClipboardCenterZ - ); - - // Convert terra schematic coordinates into relative plot schematic coordinates - double[] schematicCoords = { - terraCoords[0] - outlinesClipboard.getMinimumPoint().getX(), - terraCoords[1] - outlinesClipboard.getMinimumPoint().getZ() - }; - - // Add additional plot sizes to relative plot schematic coordinates - double[] plotCoords = { - schematicCoords[0] + schematicMinPoint.getX(), - schematicCoords[1] + schematicMinPoint.getZ() - }; - - // Return coordinates if they are in the schematic plot region - if(new CuboidRegion(schematicMinPoint, schematicMaxPoint).contains(new Vector((int)plotCoords[0], 15, (int)plotCoords[1]))) { - return CompletableFuture.completedFuture(plotCoords); + Clipboard clipboard = FaweAPI.load(plot.getOutlinesSchematic()).getClipboard(); + + if (clipboard != null) { + // Calculate min and max points of schematic + CuboidRegion plotRegion = getPlotAsRegion(plot); + + if (plotRegion != null) { + // Convert terra schematic coordinates into relative plot schematic coordinates + double[] schematicCoords = { + terraCoords[0] - clipboard.getMinimumPoint().getX(), + terraCoords[1] - clipboard.getMinimumPoint().getZ() + }; + + // Add additional plot sizes to relative plot schematic coordinates + double[] plotCoords = { + schematicCoords[0] + plotRegion.getMinimumPoint().getX(), + schematicCoords[1] + plotRegion.getMinimumPoint().getZ() + }; + + // Return coordinates if they are in the schematic plot region + ProtectedRegion protectedPlotRegion = plot.getWorld().getProtectedRegion() != null ? plot.getWorld().getProtectedRegion() : plot.getWorld().getProtectedBuildRegion(); + if (protectedPlotRegion.contains(new Vector((int) plotCoords[0], plot.getWorld().getPlotHeightCentered(), (int) plotCoords[1]))) { + return CompletableFuture.completedFuture(plotCoords); + } + } } - return null; + return null; } public static void checkPlotsForLastActivity() { @@ -291,12 +401,13 @@ public static void checkPlotsForLastActivity() { FileConfiguration config = PlotSystem.getPlugin().getConfigManager().getConfig(); long millisInDays = config.getLong(ConfigPaths.INACTIVITY_INTERVAL) * 24 * 60 * 60 * 1000; // Remove all plots which have no activity for the last x days - for(Plot plot : plots) { - if(plot.getLastActivity() != null && plot.getLastActivity().getTime() < (new Date().getTime() - millisInDays)) { + for (Plot plot : plots) { + if (plot.getLastActivity() != null && plot.getLastActivity().getTime() < (new Date().getTime() - millisInDays)) { Bukkit.getScheduler().runTask(PlotSystem.getPlugin(), () -> { if (PlotHandler.abandonPlot(plot)) { Bukkit.getLogger().log(Level.INFO, "Abandoned plot #" + plot.getID() + " due to inactivity!"); - } else Bukkit.getLogger().log(Level.WARNING, "An error occurred while abandoning plot #" + plot.getID() + " due to inactivity!"); + } else + Bukkit.getLogger().log(Level.WARNING, "An error occurred while abandoning plot #" + plot.getID() + " due to inactivity!"); }); } } @@ -311,30 +422,71 @@ public static void syncPlotSchematicFiles() { if (config.getBoolean(ConfigPaths.SYNC_FTP_FILES_ENABLED)) { long interval = config.getLong(ConfigPaths.SYNC_FTP_FILES_INTERVAL); - Bukkit.getScheduler().runTaskTimerAsynchronously(PlotSystem.getPlugin(), () -> { - CityProject.getCityProjects(false).forEach(c -> { - try { - if (c.getCountry().getServer().getFTPConfiguration() != null) { - List plots = PlotManager.getPlots(c.getID(), Status.unclaimed); - plots.forEach(Plot::getOutlinesSchematic); - } - } catch (SQLException ex) { - Bukkit.getLogger().log(Level.INFO, "A SQL error occurred!", ex); + Bukkit.getScheduler().runTaskTimerAsynchronously(PlotSystem.getPlugin(), () -> CityProject.getCityProjects(false).forEach(c -> { + try { + if (c.getCountry().getServer().getFTPConfiguration() != null) { + List plots = PlotManager.getPlots(c.getID(), Status.unclaimed); + plots.forEach(Plot::getOutlinesSchematic); } - }); - }, 0L, 20 * interval); + } catch (SQLException ex) { + Bukkit.getLogger().log(Level.INFO, "A SQL error occurred!", ex); + } + }), 0L, 20 * interval); } } - 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 + * + * @return the current plot of the player + */ + 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.getPlotType() == PlotType.CITY_INSPIRATION_MODE && plot.getCenter().setY(playerVector.getY()).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) { try (ResultSet rs = DatabaseConnection.createStatement("SELECT COUNT(id) FROM plotsystem_plots WHERE id = ?") .setValue(ID).executeQuery()) { - if (rs.next() && rs.getInt(1) > 0){ + if (rs.next() && rs.getInt(1) > 0) { DatabaseConnection.closeResultSet(rs); return true; } @@ -355,11 +507,11 @@ public static boolean hasPlotDifficultyScoreRequirement(Builder builder, PlotDif public static CompletableFuture getPlotDifficultyForBuilder(int cityID, Builder builder) throws SQLException { // Check if plot difficulties are available boolean easyHasPlots = false, mediumHasPlots = false, hardHasPlots = false; - if(PlotManager.getPlots(cityID, PlotDifficulty.EASY, Status.unclaimed).size() != 0) easyHasPlots = true; - if(PlotManager.getPlots(cityID, PlotDifficulty.MEDIUM, Status.unclaimed).size() != 0) mediumHasPlots = true; - if(PlotManager.getPlots(cityID, PlotDifficulty.HARD, Status.unclaimed).size() != 0) hardHasPlots = true; + if (PlotManager.getPlots(cityID, PlotDifficulty.EASY, Status.unclaimed).size() != 0) easyHasPlots = true; + if (PlotManager.getPlots(cityID, PlotDifficulty.MEDIUM, Status.unclaimed).size() != 0) mediumHasPlots = true; + if (PlotManager.getPlots(cityID, PlotDifficulty.HARD, Status.unclaimed).size() != 0) hardHasPlots = true; - if(hardHasPlots && hasPlotDifficultyScoreRequirement(builder, PlotDifficulty.HARD)) { // Return hard + if (hardHasPlots && hasPlotDifficultyScoreRequirement(builder, PlotDifficulty.HARD)) { // Return hard return CompletableFuture.completedFuture(PlotDifficulty.HARD); } else if (mediumHasPlots && hasPlotDifficultyScoreRequirement(builder, PlotDifficulty.MEDIUM)) { // Return medium return CompletableFuture.completedFuture(PlotDifficulty.MEDIUM); @@ -376,30 +528,55 @@ public static CompletableFuture getPlotDifficultyForBuilder(int return CompletableFuture.completedFuture(PlotDifficulty.MEDIUM); } } - return CompletableFuture.completedFuture(PlotDifficulty.HARD); // If nothing is available return hard (plot availability will be checked later additionally) + return CompletableFuture.completedFuture(null); // If nothing is available return null } 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() || plot.getVersion() <= 2) + 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..9efa6126 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,37 @@ 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); - return this; - } - - public PlotPermissions addReviewerPerms() { - plotWorld.getProtectedRegion().getOwners().addGroup("staff"); - return this; - } - - public PlotPermissions removeReviewerPerms() { - plotWorld.getProtectedRegion().getOwners().removeGroup("staff"); + if (world.getProtectedRegion() != null) world.getProtectedRegion().getOwners().removePlayer(builder); + world.getProtectedBuildRegion().getOwners().removePlayer(builder); + PlotManager.clearCache(builder); 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"); + public boolean hasBuildingPerms(UUID builder) { + return world.getProtectedBuildRegion().getOwners().contains(builder); } 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..1f6aff6c 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); + 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()) { + 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..fe1fd6b4 --- /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 Math.min(MIN_WORLD_HEIGHT + getWorldHeight() + super.getPlotHeightCentered(), PlotWorld.MAX_WORLD_HEIGHT); + } + + /** + * 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/ChatFeedbackInput.java b/src/main/java/com/alpsbte/plotsystem/utils/ChatFeedbackInput.java new file mode 100644 index 00000000..c4b7afde --- /dev/null +++ b/src/main/java/com/alpsbte/plotsystem/utils/ChatFeedbackInput.java @@ -0,0 +1,47 @@ +/* + * The MIT License (MIT) + * + * Copyright © 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.utils; + +import com.alpsbte.plotsystem.core.system.Review; + +import java.time.LocalDateTime; + +public class ChatFeedbackInput { + private final Review review; + private final LocalDateTime dateTime; + + public ChatFeedbackInput(Review review) { + this.review = review; + this.dateTime = LocalDateTime.now(); + } + + public Review getReview() { + return review; + } + + public LocalDateTime getDateTime() { + return dateTime; + } +} 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..0dd0a94e 100644 --- a/src/main/java/com/alpsbte/plotsystem/utils/Utils.java +++ b/src/main/java/com/alpsbte/plotsystem/utils/Utils.java @@ -25,11 +25,12 @@ package com.alpsbte.plotsystem.utils; import com.alpsbte.plotsystem.PlotSystem; -import com.alpsbte.plotsystem.core.menus.CompanionMenu; +import com.alpsbte.plotsystem.core.menus.companion.CompanionMenu; import com.alpsbte.plotsystem.core.menus.ReviewMenu; 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,12 @@ 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.Arrays; +import java.util.List; import java.util.UUID; import java.util.logging.Level; @@ -162,6 +168,132 @@ 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) + */ + 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.replaceAll("//", " ").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--; + } + + } + } + + /** + * Get next enum in order of the enum + * + * @param The enum type + * @param haystack The enum class (YourEnum.class) + * @param needle Current value that you want to get the next one of + * @return Next enum in line + */ + public static > Enum getNextEnum(Class> haystack, T needle) { + List> enums = Arrays.asList(haystack.getEnumConstants()); + return getNextListItem(enums, needle); + } + + public static T getNextListItem(List haystack, T needle) { + if(!haystack.contains(needle) || haystack.indexOf(needle) + 1 >= haystack.size()) { + return null; + } + return haystack.get(haystack.indexOf(needle) + 1); + } + public static class CustomHead { private final ItemStack headItem; @@ -187,8 +319,12 @@ public ItemStack getAsItemStack() { public static CustomHead BACK_BUTTON; public static CustomHead NEXT_BUTTON; public static CustomHead PREVIOUS_BUTTON; + public static CustomHead INFO_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; @@ -204,9 +340,13 @@ public static void loadHeadsAsync(HeadDatabaseAPI api) { BACK_BUTTON = new CustomHead("9226"); NEXT_BUTTON = new CustomHead("9223"); PREVIOUS_BUTTON = new CustomHead("9226"); + INFO_BUTTON = new CustomHead("46488"); GLOBE = new CustomHead("49973"); + PLOT_TYPE = new CustomHead("4159"); + FOCUS_MODE = new CustomHead("38199"); + CITY_INSPIRATION_MODE = new CustomHead("38094"); }); } } -} +} \ No newline at end of file diff --git a/src/main/java/com/alpsbte/plotsystem/utils/enums/Continent.java b/src/main/java/com/alpsbte/plotsystem/utils/enums/Continent.java new file mode 100644 index 00000000..628db828 --- /dev/null +++ b/src/main/java/com/alpsbte/plotsystem/utils/enums/Continent.java @@ -0,0 +1,50 @@ +package com.alpsbte.plotsystem.utils.enums; + +import com.alpsbte.plotsystem.core.system.Country; +import com.alpsbte.plotsystem.utils.io.language.LangPaths; +import com.alpsbte.plotsystem.utils.io.language.LangUtil; +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.bukkit.inventory.ItemStack; + +import java.util.Arrays; +import java.util.List; + +public enum Continent { + EUROPE("europe", LangPaths.Continent.EUROPE), + ASIA("asia", LangPaths.Continent.ASIA), + AFRICA("africa", LangPaths.Continent.AFRICA), + OCEANIA("oceania", LangPaths.Continent.OCEANIA), + SOUTH_AMERICA("south america", LangPaths.Continent.SOUTH_AMERICA), + NORTH_AMERICA("north america", LangPaths.Continent.NORTH_AMERICA); + + public final String databaseEnum; + public final String langPath; + + Continent(String databaseEnum, String langPath) { + this.databaseEnum = databaseEnum; + // although LangPath.Continent keys match the enum name, you cannot get the value without reflection + this.langPath = langPath; + } + + public static Continent fromDatabase(String databaseEnum) { + return Arrays.stream(Continent.values()).filter(c -> c.databaseEnum.equals(databaseEnum)).findFirst().orElse(null); + } + + /** + * Get menu item for this continent + * + * @param player Used to translate the menu item + * @return Menu item + */ + public ItemStack getItem(Player player) { + List countries = Country.getCountries(this); + + return new ItemBuilder(Material.COMPASS) + .setName("§e§l" + LangUtil.get(player, langPath)) + .setLore(new LoreBuilder().addLines("§6" + countries.size() + " §7" + LangUtil.get(player, LangPaths.Country.COUNTRIES)).build()) + .build(); + } +} 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..8364eb35 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(); @@ -90,22 +90,11 @@ public static CompletableFuture downloadSchematic(String ftpURL, File sche return CompletableFuture.completedFuture(null); } - public static CompletableFuture deleteSchematics(String ftpURL, String schematicName, boolean onlyFinished) throws FileSystemException { + public static CompletableFuture deleteSchematic(String ftpURL, String schematicName) throws FileSystemException { try (StandardFileSystemManager fileManager = new StandardFileSystemManager()) { fileManager.init(); FileObject remote, remoteSchematic; - if (!onlyFinished) { - remote = fileManager.resolveFile(ftpURL.replaceFirst("finishedSchematics/",""), fileOptions); - remoteSchematic = remote.resolveFile(schematicName); - if (remoteSchematic.exists()) { - remoteSchematic.delete(); - if (remote.getChildren().length == 0) { - remote.delete(); - } - } - } - remote = fileManager.resolveFile(ftpURL, fileOptions); remoteSchematic = remote.resolveFile(schematicName); if (remoteSchematic.exists()) { diff --git a/src/main/java/com/alpsbte/plotsystem/utils/io/config/ConfigPaths.java b/src/main/java/com/alpsbte/plotsystem/utils/io/config/ConfigPaths.java index 1c96ac8b..48c454a7 100644 --- a/src/main/java/com/alpsbte/plotsystem/utils/io/config/ConfigPaths.java +++ b/src/main/java/com/alpsbte/plotsystem/utils/io/config/ConfigPaths.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 @@ -60,6 +60,9 @@ public abstract class ConfigPaths { public static final String DISPLAY_OPTIONS_SHOW_WEEKLY = DISPLAY_OPTIONS + "show-weekly"; public static final String DISPLAY_OPTIONS_SHOW_MONTHLY = DISPLAY_OPTIONS + "show-monthly"; public static final String DISPLAY_OPTIONS_SHOW_YEARLY = DISPLAY_OPTIONS + "show-yearly"; + public static final String DISPLAY_OPTIONS_SHOW_LIFETIME = DISPLAY_OPTIONS + "show-lifetime"; + public static final String DISPLAY_OPTIONS_ACTION_BAR_ENABLED = DISPLAY_OPTIONS + "action-bar-enabled"; + public static final String DISPLAY_OPTIONS_ACTION_BAR_RADIUS = DISPLAY_OPTIONS + "action-bar-radius"; // Navigator @@ -87,4 +90,4 @@ public abstract class ConfigPaths { // CONFIG VERSION public static final String CONFIG_VERSION = "config-version"; -} +} \ No newline at end of file diff --git a/src/main/java/com/alpsbte/plotsystem/utils/io/config/ConfigUtil.java b/src/main/java/com/alpsbte/plotsystem/utils/io/config/ConfigUtil.java index d3cf4715..11e4b676 100644 --- a/src/main/java/com/alpsbte/plotsystem/utils/io/config/ConfigUtil.java +++ b/src/main/java/com/alpsbte/plotsystem/utils/io/config/ConfigUtil.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 @@ -35,19 +35,19 @@ public class ConfigUtil extends YamlFileFactory { - // Register configuration files - private static final ConfigFile[] configs = new ConfigFile[] { - new ConfigFile(Paths.get("config.yml"), 1.5), - new ConfigFile(Paths.get("commands.yml"), 1.0) + // Register configuration files + private static final ConfigFile[] configs = new ConfigFile[] { + new ConfigFile(Paths.get("config.yml"), 1.6), + new ConfigFile(Paths.get("commands.yml"), 1.0) }; - public ConfigUtil() throws ConfigNotImplementedException { - super(configs); + public ConfigUtil() throws ConfigNotImplementedException { + super(configs); - if (!getConfig().getFile().exists() && createFile(getConfig())) { - throw new ConfigNotImplementedException("The config file must be configured!"); + if (!getConfig().getFile().exists() && createFile(getConfig())) { + throw new ConfigNotImplementedException("The config file must be configured!"); } else if (reloadFile(getConfig()) && getConfig().getDouble(ConfigPaths.CONFIG_VERSION) != getConfig().getVersion()) { - updateFile(getConfig()); + updateFile(getConfig()); } if (!getCommandsConfig().getFile().exists()) { @@ -56,7 +56,7 @@ public ConfigUtil() throws ConfigNotImplementedException { updateFile(getCommandsConfig()); } - reloadFiles(); + reloadFiles(); } public ConfigFile getConfig() { @@ -88,4 +88,4 @@ public int getMaxConfigWidth() { return 400; } } -} +} \ No newline at end of file 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..c4e14adb 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 @@ -13,6 +13,7 @@ public static final class Plot { public static final String MEMBERS = PLOT + "members"; public static final String MEMBER = PLOT + "member"; public static final String CITY = PLOT + "city"; + public static final String COUNTRY = PLOT + "country"; public static final String DIFFICULTY = PLOT + "difficulty"; public static final String STATUS = PLOT + "status"; public static final String SCORE = PLOT + "score"; @@ -29,10 +30,28 @@ public static final class GroupSystem { public static final class CityProject { private static final String CITY_PROJECT = "city-project."; + public static final String CITIES = CITY_PROJECT + "cities"; public static final String PROJECT_OPEN = CITY_PROJECT + "open"; public static final String PROJECT_IN_PROGRESS = CITY_PROJECT + "in-progress"; public static final String PROJECT_COMPLETED = CITY_PROJECT + "completed"; - public static final String PROJECT_NO_PLOTS = CITY_PROJECT + "no-plots-available"; + public static final String PROJECT_PLOTS_AVAILABLE = CITY_PROJECT + "plots-available"; + public static final String PROJECT_NO_PLOTS_AVAILABLE = CITY_PROJECT + "no-plots-available"; + public static final String FOR_YOUR_DIFFICULTY = CITY_PROJECT + "for-your-difficulty"; + } + + public static final class Country { + private static final String COUNTRY = "country."; + public static final String COUNTRIES = COUNTRY + "countries"; + } + + public static final class Continent { + private static final String CONTINENT = "continent."; + public static final String EUROPE = CONTINENT + "europe"; + public static final String ASIA = CONTINENT + "asia"; + public static final String AFRICA = CONTINENT + "africa"; + public static final String OCEANIA = CONTINENT + "oceania"; + public static final String SOUTH_AMERICA = CONTINENT + "south-america"; + public static final String NORTH_AMERICA = CONTINENT + "north-america"; } public static final class Difficulty { @@ -69,6 +88,9 @@ public static final class MenuTitle { public static final String CANCEL = MENU_TITLES + "cancel"; public static final String ADD_MEMBER_TO_PLOT = MENU_TITLES + "add-member-to-plot"; public static final String COMPANION = MENU_TITLES + "companion"; + public static final String COMPANION_SELECT_CONTINENT = MENU_TITLES + "companion-select-continent"; + public static final String COMPANION_SELECT_COUNTRY = MENU_TITLES + "companion-select-country"; + public static final String COMPANION_SELECT_CITY = MENU_TITLES + "companion-select-city"; public static final String PLAYER_PLOTS = MENU_TITLES + "player-plots"; public static final String LEAVE_PLOT = MENU_TITLES + "leave-plot"; public static final String REVIEW_PLOTS = MENU_TITLES + "review-plots"; @@ -76,6 +98,12 @@ public static final class MenuTitle { 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 AUTO_DETECT_LANGUAGE = MENU_TITLES + "auto-detect-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 FILTER_BY_COUNTRY = MENU_TITLES + "filter-by-country"; + public static final String INFORMATION = MENU_TITLES + "information"; } public static final class MenuDescription { @@ -101,7 +129,13 @@ 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"; + public static final String FILTER = MENU_DESCRIPTIONS + "filter-desc"; + public static final String INFORMATION = MENU_DESCRIPTIONS + "information-desc"; } public static final class Review { @@ -110,9 +144,11 @@ public static final class Review { public static final String REVIEW_PLOT = REVIEW + "review-plot"; public static final String MANAGE_PLOT = REVIEW + "manage-plot"; public static final String ACCEPTED = REVIEW + "accepted"; + public static final String ABANDONED = REVIEW + "abandoned"; public static final String REJECTED = REVIEW + "rejected"; public static final String FEEDBACK = REVIEW + "feedback"; public static final String REVIEWER = REVIEW + "reviewer"; + public static final String PLAYER_LANGUAGE = REVIEW + "player-language"; public static final class Criteria { private static final String CRITERIA = REVIEW + "criteria."; @@ -187,6 +223,8 @@ public static final class Info { public static final String CREATING_PLOT = INFO + "creating-plot"; public static final String CREATED_NEW_PLOT = INFO + "created-new-plot"; public static final String CHANGED_LANGUAGE = INFO + "changed-language"; + public static final String ENTER_FEEDBACK = INFO + "enter-feedback"; + public static final String INPUT_EXPIRES_AFTER = INFO + "input-expires-after"; } public static final class Error { @@ -199,7 +237,7 @@ public static final class Error { public static final String CAN_ONLY_SUBMIT_UNFINISHED_PLOTS = ERROR + "can-only-submit-unfinished-plots"; public static final String CAN_ONLY_UNDO_SUBMISSIONS_UNREVIEWED_PLOTS = ERROR + "can-only-undo-submissions-unreviewed-plots"; public static final String CAN_ONLY_MANAGE_MEMBERS_UNFINISHED = ERROR + "can-only-manage-members-unfinished-plots"; - public static final String CAN_ONLY_TELEPORT_TO_PLOT = ERROR + "can-only-teleport-to-plot"; + public static final String CANNOT_TELEPORT_OUTSIDE_PLOT = ERROR + "cannot-teleport-outside-plot"; public static final String CANNOT_UNDO_REVIEW = ERROR + "cannot-undo-review"; public static final String CANNOT_SEND_FEEDBACK = ERROR + "cannot-send-feedback"; public static final String CANNOT_REVIEW_OWN_PLOT = ERROR + "cannot-review-own-plot"; @@ -220,8 +258,18 @@ public static final class Error { public static final String NO_PLOTS_LEFT = ERROR + "no-plots-left"; public static final String PLEASE_WAIT = ERROR + "please-wait"; public static final String ALL_SLOTS_OCCUPIED = ERROR + "all-slots-occupied"; + public static final String NO_ASSIGNMENT_AS_REVIEWER = ERROR + "no-assignment-as-reviewer"; + public static final String FEEDBACK_INPUT_EXPIRED = ERROR + "feedback-input-expired"; } } + public static final class Leaderboards { + private static final String LBS = "leaderboards."; + public static final String PAGES = LBS + "pages."; + public static final String ACTIONBAR_POSITION = LBS + "actionbar-position"; + public static final String ACTIONBAR_PERCENTAGE = LBS + "actionbar-percentage"; + public static final String NOT_ON_LEADERBOARD = LBS + "not-on-leaderboard"; + } + public static final String CONFIG_VERSION = "config-version"; -} +} \ No newline at end of file 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..3834294b 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.2), + new LanguageFile("de_DE", 1.2, "de_AT", "de_CH"), + new LanguageFile("fr_FR", 1.2, "fr_CA"), + new LanguageFile("ko_KR", 1.2), + new LanguageFile("ru_RU", 1.2, "ba_RU", "tt_RU"), + new LanguageFile("zh_CN", 1.2), + new LanguageFile("zh_TW", 1.2, "zh_HK"), }; public LangUtil() { @@ -48,7 +48,7 @@ public static String get(CommandSender sender, String key, String... args) { return getLanguageFileByLocale(sender instanceof Player ? getLocaleTagByPlayer((Player) sender) : languages[0].tag).getTranslation(key, args); } - private static LanguageFile getLanguageFileByLocale(String locale) { + public static LanguageFile getLanguageFileByLocale(String locale) { return Arrays.stream(languages) .filter(lang -> lang.tag.equalsIgnoreCase(locale)) .findFirst() @@ -59,18 +59,12 @@ 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(); } - public static void broadcast(String key) { - for (Player player : Bukkit.getOnlinePlayers()) { - player.sendMessage(Utils.getInfoMessageFormat(get(player, key))); - } - } - public static void broadcast(String key, String... args) { for (Player player : Bukkit.getOnlinePlayers()) { player.sendMessage(Utils.getInfoMessageFormat(get(player, key, args))); diff --git a/src/main/java/com/alpsbte/plotsystem/utils/items/MenuItems.java b/src/main/java/com/alpsbte/plotsystem/utils/items/MenuItems.java index 2c61e639..d1eaeccf 100644 --- a/src/main/java/com/alpsbte/plotsystem/utils/items/MenuItems.java +++ b/src/main/java/com/alpsbte/plotsystem/utils/items/MenuItems.java @@ -78,4 +78,10 @@ public static ItemStack loadingItem(Material material, byte subId, Player player .setName("§6§l" + LangUtil.get(player, LangPaths.MenuTitle.LOADING)) .build(); } + + public static ItemStack filterItem(Player langPlayer) { + return new ItemBuilder(Material.HOPPER, 1) + .setName("§6§l" + LangUtil.get(langPlayer, LangPaths.MenuTitle.FILTER_BY_COUNTRY)) + .build(); + } } 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/defaultConfig.yml b/src/main/resources/defaultConfig.yml index 3771e757..7facd767 100644 --- a/src/main/resources/defaultConfig.yml +++ b/src/main/resources/defaultConfig.yml @@ -64,13 +64,16 @@ holograms: z: 0 # Switch hologram statistics between different time stamps -# [interval] -> default: 5 seconds +# [interval] -> default: 10 seconds display-options: - interval: 5 + interval: 10 show-daily: false show-weekly: true show-monthly: true show-yearly: false + show-lifetime: false + action-bar-enabled: true + action-bar-radius: 30 # ----------------------------------------------------- @@ -98,4 +101,4 @@ shortlink: host: https://your.shortlink.host # NOTE: Do not change -config-version: 1.5 \ No newline at end of file +config-version: 1.6 \ No newline at end of file diff --git a/src/main/resources/lang/de_DE.yml b/src/main/resources/lang/de_DE.yml index 97fb276c..61ba3a9a 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: @@ -25,6 +25,7 @@ plot: members: "Plot Mitglieder" member: "Plot Mitglied" city: "Stadt" + country: "Land" difficulty: "Schwierigkeitsgrad" status: "Status" score: "Punktestand" @@ -39,10 +40,30 @@ plot: # | City Projects # ----------------------------------------------------- city-project: + cities: "Städte" open: "Offene Plots" in-progress: "Plots in Arbeit" completed: "Abgeschlossene Plots" - no-plots-available: "Keine Plots verfügbar" + plots-available: 'Plots Verfügbar' + no-plots-available: "Keine Plots Verfügbar" + for-your-difficulty: "({0} für deinen Schwierigkeitsgrad)" + +# ----------------------------------------------------- +# | Countries +# ----------------------------------------------------- +country: + countries: "Länder" + +# ----------------------------------------------------- +# | Continents +# ----------------------------------------------------- +continent: + europe: "Europa" + asia: "Asien" + africa: "Afrika" + oceania: "Ozeanien" + south-america: "Südamerika" + north-america: "Nordamerika" # ----------------------------------------------------- # | Difficulty @@ -81,6 +102,9 @@ menu-title: cancel: "Abbrechen" add-member-to-plot: "Mitglied zum Plot Hinzufügen" companion: "Companion" + companion-select-continent: 'Wähle Ein Kontinent' + companion-select-country: 'Wähle Ein Land' + companion-select-city: 'Wähle Eine Stadt' player-plots: "{0}s Plots" leave-plot: "Plot Verlassen" review-plots: "Plots Bewerten" @@ -88,7 +112,12 @@ 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" + filter-by-country: "Nach Land Filtern" + information: "Info" # ----------------------------------------------------- # | Menu Descriptions @@ -100,7 +129,7 @@ menu-description: slot-desc: "Klicke auf eine Stadt, um einen neuen Plot zu erstellen" builder-utilities-desc: "Erhalte Zugang zu benutzerdefinierten Köpfen, Bannern und speziellen Blöcken" show-plots-desc: "Alle deine Plots anzeigen" - settings-desc: "Bearbeite deine Benutzer-Einstellungen" + settings-desc: "Bearbeite deine Benutzereinstellungen" submit-plot-desc: "Klicke hier, um diesen Plot abzuschließen und ihn zur Bewertung einzureichen" teleport-desc: "Klicke hier, um dich zum Plot zu teleportieren" abandon-desc: "Klicke hier, um deinen Plot zurückzusetzen und ihn jemand anderem zu geben" @@ -116,7 +145,12 @@ 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" + filter-desc: "Alle Anzeigen" + information-desc: "Ein Plot kann maximal 20 Punkte erhalten. Erhält das Plot weniger als 8 Punkte oder eine Kategorie 0 Punkte, wird das Plot abgelehnt und der Builder bekommt das Plot zurück, um es zu verbessern. Bei 0 Punkten wird das Plot gelöscht." # ----------------------------------------------------- # | Review @@ -126,9 +160,11 @@ review: manage-plot: "Plot Verwalten" manage-and-review-plots: "Plots Verwalten & Bewerten" accepted: "Angenommen" + abandoned: "Gelöscht" rejected: "Abgelehnt" feedback: "Feedback" reviewer: "Reviewer" + player-language: "Spielersprache" criteria: accuracy: "Genauigkeit" accuracy-desc: "Wie akkurat ist das Gebäude?////- Sieht aus wie in RL//- Korrekte Umrisse//- Korrekte Höhen//- Ist vollständig" @@ -139,7 +175,6 @@ review: technique: "Technik" technique-desc: "Welche Bautechniken wurden verwendet und wie kreativ sind sie?////- World-Edit//- Spezialblöcke" - # ----------------------------------------------------- # | Notes # ----------------------------------------------------- @@ -177,7 +212,7 @@ message: abandoned-plot: "§aPlot mit ID §6#{0}§a gelöscht!" finished-plot: "§a§6{1}§a hat den Plot §6#{0}§a fertiggestellt!" plot-marked-as-reviewed: "§aPlot §6#{0}§a von §6{1}§a wurde als geprüft markiert!" - plot-rejected: "§aPlot §6#{0}§a von §6{1}§a wurde abgelehnt! Verwende den Befehl §6/sendFeedback §a um ein Feedback zu hinterlassen!" + plot-rejected: "§aPlot §6#{0}§a von §6{1}§a wurde abgelehnt!" undid-submission: "§aDie Einreichung des Plots §6#{0}§a wurde rückgängig gemacht!" undid-review: "§aDie Bewertung des Plots §6#{0}§a von §6#{1}§a wurde rückgängig gemacht!" reviewed-plot: "§aDein Plot §6#{0}§a wurde bewertet!" @@ -196,6 +231,8 @@ message: creating-plot: "§aErstelle neuen Plot..." created-new-plot: "§aEin neuer Plot§a wurde für §6{0}§a erstellt!" changed-language: "§aAlle Systemnachrichten sind nun auf §6{0}§a!" + enter-feedback: "Bitte gebe eine Bewertung des Plots für den Spieler im Chat ein." + input-expires-after: "§9Die Chat-Eingabe läuft nach §6{0} §9Minuten ab." error: plot-does-not-exist: "Dieser Plot existiert nicht!" plot-either-unclaimed-or-unreviewed: "Dieser Plot ist entweder unbeansprucht oder wurde noch nicht bewertet!" @@ -204,7 +241,7 @@ message: can-only-submit-unfinished-plots: "Du kannst nur unfertige Plots abgeben!" can-only-undo-submissions-unreviewed-plots: "Du kannst nur Einreichungen von unbewerteten Plots rückgängig machen!" can-only-manage-members-unfinished-plots: "Du kannst nur Mitglieder von unfertigen Plots verwalten!" - can-only-tpll-to-plot: "Du kannst /tpll nur auf einem Plot verwenden!" + cannot-teleport-outside-plot: "Du kannst dich nicht ausserhalb des Plotes teleportieren!" cannot-undo-review: "Du kannst eine Bewertung nicht rückgängig machen, wenn du sie nicht selbst erstellt hast!" cannot-send-feedback: "Du kannst auf einen Plot kein Feedback geben, wenn du ihn nicht selbst bewertet hast!" cannot-review-own-plot: "Du kannst deine eigenen Plots nicht bewerten!" @@ -223,8 +260,19 @@ message: no-plots-left: "Für diese Stadt gibt es keine freien Plots mehr. Bitte wähle einen anderen Ort." please-wait: "Bitte warte ein paar Sekunden, bevor du einen weiteren neuen Plot erstellst!" all-slots-occupied: "Alle deine Slots sind belegt! Bitte stelle deine aktuellen Plots fertig, bevor du einen neuen erstellst." + no-assignment-as-reviewer: "Du wurdest keinem Build Team als Reviewer zugewiesen." + feedback-input-expired: "Die Chat-Eingabe ist abgelaufen! Nutze §7/editfeedback §cum das Feedback zu bearbeiten." - +leaderboards: + pages: + DAILY: "Heute" + WEEKLY: "Woche" + MONTHLY: "Monat" + YEARLY: "Jahr" + LIFETIME: "Gesamt" + actionbar-position: "Position #{0}" + actionbar-percentage: "Top {0}%" + not-on-leaderboard: "Nicht auf Leaderboard" # NOTE: Do not change -config-version: "1.0" \ No newline at end of file +config-version: "1.2" \ 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..1b424906 100644 --- a/src/main/resources/lang/en_GB.yml +++ b/src/main/resources/lang/en_GB.yml @@ -25,6 +25,7 @@ plot: members: "Plot Members" member: "Plot Member" city: "City" + country: "Country" difficulty: "Difficulty" status: "Status" score: "Score" @@ -39,10 +40,30 @@ plot: # | City Projects # ----------------------------------------------------- city-project: + cities: "Cities" open: "Plots Open" in-progress: "Plots In Progress" completed: "Plots Completed" + plots-available: 'Plots Available' no-plots-available: "No Plots Available" + for-your-difficulty: "({0} for your difficulty)" + +# ----------------------------------------------------- +# | Countries +# ----------------------------------------------------- +country: + countries: "Countries" + +# ----------------------------------------------------- +# | Continents +# ----------------------------------------------------- +continent: + europe: "Europe" + asia: "Asia" + africa: "Africa" + oceania: "Oceania" + south-america: "South America" + north-america: "North America" # ----------------------------------------------------- # | Difficulty @@ -55,68 +76,81 @@ 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' + companion-select-continent: 'Select A Continent' + companion-select-country: 'Select A Country' + companion-select-city: 'Select A City' + 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' + filter-by-country: "Filter By Country" + information: "Info" # ----------------------------------------------------- # | 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" + filter-desc: "Show All" + information-desc: "A plot can receive a maximum of 20 points. If the plot receives less than 8 points or one category has 0 points, the plot is rejected and the builder gets the plot back to improve it. If the plot receives 0 points, it gets abandoned." # ----------------------------------------------------- # | Review @@ -127,8 +161,10 @@ review: manage-and-review-plots: "Manage & Review Plots" accepted: "Accepted" rejected: "Rejected" + abandoned: "Abandoned" feedback: "Feedback" reviewer: "Reviewer" + player-language: "Player Language" criteria: accuracy: "Accuracy" accuracy-desc: "How accurate is the building?////- Looks like in RL//- Correct outlines//- Correct height//- Is completed" @@ -139,7 +175,6 @@ review: technique: "Technique" technique-desc: "What building techniques have been used and how creative are they?////- World-Edit//- Special Blocks" - # ----------------------------------------------------- # | Notes # ----------------------------------------------------- @@ -177,7 +212,7 @@ message: abandoned-plot: "§aAbandoned plot with ID §6#{0}§a!" finished-plot: "§aPlot §6#{0}§a by §6{1}§a has been finished!" plot-marked-as-reviewed: "§aPlot §6#{0}§a by §6{1}§a has been marked as reviewed!" - plot-rejected: "§aPlot §6#{0}§a by §6{1}§a has been rejected! Send feedback using §6/sendFeedback §a!" + plot-rejected: "§aPlot §6#{0}§a by §6{1}§a has been rejected!" undid-submission: "§aUndid submission of plot §6#{0}§a!" undid-review: "§aUndid review of plot §6#{0}§a by §6#{1}§a!" reviewed-plot: "§aYour plot §6#{0}§a has been reviewed!" @@ -196,6 +231,8 @@ message: creating-plot: "§aCreating new plot..." created-new-plot: "§aCreated new plot§a for §6{0}§a!" changed-language: "§aChanged your language to §6{0}§a!" + enter-feedback: "Please enter a feedback for the player in the chat." + input-expires-after: "§9Chat input expires after §6{0} §9minutes." error: plot-does-not-exist: "This plot does not exist!" plot-either-unclaimed-or-unreviewed: "This plot is either unclaimed or has not been reviewed yet!" @@ -204,7 +241,7 @@ message: can-only-submit-unfinished-plots: "You can only submit unfinished plots!" can-only-undo-submissions-unreviewed-plots: "You can only undo submissions of unreviewed plots!" can-only-manage-members-unfinished-plots: "You can only manage members of unfinished plots!" - can-only-tpll-to-plot: "You can only use /tpll on a plot!" + cannot-teleport-outside-plot: "You cannot teleport outside the plot!" cannot-undo-review: "You cannot undo a review that you have not reviewed yourself!" cannot-send-feedback: "You cannot send feedback to a plot that you have not reviewed yourself!" cannot-review-own-plot: "You cannot review your own plot!" @@ -223,8 +260,19 @@ message: no-plots-left: "This city project does not have any more plots left. Please select another project." please-wait: "Please wait a few seconds before creating a new plot!" all-slots-occupied: "All your slots are occupied! Please finish your current plots before creating a new one." + no-assignment-as-reviewer: "You have not been assigned to a build team as a reviewer." + feedback-input-expired: "The chat input has expired! Use §7/editfeedback §cto edit the feedback." - +leaderboards: + pages: + DAILY: "Daily" + WEEKLY: "Weekly" + MONTHLY: "Monthly" + YEARLY: "Yearly" + LIFETIME: "Lifetime" + actionbar-position: "Position #{0}" + actionbar-percentage: "Top {0}%" + not-on-leaderboard: "Not on Leaderboard" # NOTE: Do not change -config-version: "1.0" +config-version: "1.2" diff --git a/src/main/resources/lang/fr_FR.yml b/src/main/resources/lang/fr_FR.yml index b251a783..ec114aba 100644 --- a/src/main/resources/lang/fr_FR.yml +++ b/src/main/resources/lang/fr_FR.yml @@ -25,6 +25,7 @@ plot: members: 'Membres du Plot' member: 'Membre du Plot' city: 'City' + country: "Country" difficulty: 'Difficulté' status: 'Statut' score: 'Score' @@ -39,10 +40,30 @@ plot: # | City Projects # ----------------------------------------------------- city-project: + cities: "Cities" open: 'Plots Ouvert' in-progress: 'Plots En Progrès' completed: 'Plots Complété' + plots-available: 'Plots Available' no-plots-available: 'Aucun Plots Disponibles' + for-your-difficulty: "({0} for your difficulty)" + +# ----------------------------------------------------- +# | Countries +# ----------------------------------------------------- +country: + countries: "Countries" + +# ----------------------------------------------------- +# | Continents +# ----------------------------------------------------- +continent: + europe: "Europe" + asia: "Asia" + africa: "Africa" + oceania: "Oceania" + south-america: "South America" + north-america: "North America" # ----------------------------------------------------- # | Difficulty @@ -81,6 +102,9 @@ menu-title: cancel: 'Annuler' add-member-to-plot: 'Ajouter Membre au Plot' companion: 'Compagnon' + companion-select-continent: 'Select A Continent' + companion-select-country: 'Select A Country' + companion-select-city: 'Select A City' player-plots: '{0}s Plots' leave-plot: 'Quitter Plot' review-plots: 'Review Plots' @@ -88,7 +112,12 @@ 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" + filter-by-country: "Filter By Country" + information: "Info" # ----------------------------------------------------- # | Menu Descriptions @@ -116,7 +145,12 @@ 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" + filter-desc: "Show All" + information-desc: "A plot can receive a maximum of 20 points. If the plot receives less than 8 points or one category has 0 points, the plot is rejected and the builder gets the plot back to improve it. If the plot receives 0 points, it gets abandoned." # ----------------------------------------------------- # | Review @@ -126,9 +160,11 @@ review: manage-plot: "Gérer le tracé" manage-and-review-plots: "Gérer et réviser les tracés" accepted: "Accepté" + abandoned: "Abandoned" rejected: "Refusé" feedback: "Commentaires" reviewer: "Relecteur" + player-language: "Player Language" criteria: accuracy: "Précision" accuracy-desc: "Quelle est la précision du bâtiment?////- Ressemble à RL//- Contours corrects//- Hauteur correcte//- Est terminé" @@ -139,7 +175,6 @@ review: technique: "Technique" technique-desc: "Quelles techniques de construction ont été utilisées et à quel point sont-elles créatives?////- World-Edit//- Blocs spéciaux" - # ----------------------------------------------------- # | Notes # ----------------------------------------------------- @@ -174,13 +209,13 @@ message: teleporting-plot: "§aTéléportation pour plot §6#{0}§a..." teleporting-spawn: "§aTéléportation pour spawn..." teleporting-tpll: "§aTéléportation au §6{0}§a, §6{1}§a..." - abandon-plot: "§aParcelle abandonnée avec ID §6#{0}§a!" - done-plot: "§aLe tracé §6#{0}§a par §6{1}§a est terminé!" + abandoned-plot: "§aParcelle abandonnée avec ID §6#{0}§a!" + finished-plot: "§aLe tracé §6#{0}§a par §6{1}§a est terminé!" plot-marked-as-reviewed: "§aLe terrain §6#{0}§a par §6{1}§a a été marqué comme révisé!" - plot-rejected: "§aLe tracé §6#{0}§a par §6{1}§a a été rejeté! Envoyez des commentaires en utilisant §6/sendFeedback §a!" + plot-rejected: "§aLe tracé §6#{0}§a par §6{1}§a a été rejeté!" undid-submission: "§aUndid soumission du complot §6#{0}§a!" undid-review: "§aUndid review of plot §6#{0}§a by §6#{1}§a!" - review-plot: "§aVotre parcelle §6#{0}§a a été revue!" + reviewed-plot: "§aVotre parcelle §6#{0}§a a été revue!" unreviewed-plot: "§aIl y a §6{0}§a un complot non révisé!" unreviewed-plots: "§aIl y a §6{0}§a des parcelles non revues!" unfinished-plot: "§aVous avez §6{0}§a un terrain inachevé!" @@ -188,7 +223,7 @@ message: enabled-build-permissions: "§aPermissions de construction activées pour les examinateurs sur le tracé §6#{0}§a!" disabled-build-permissions: "§aAutorisations de construction désactivées pour les examinateurs sur le tracé §6#{0}§a!" updated-plot-feedback: "§aFeedback for plot §6#{0}§a has been updated!" - remove-plot-member: "§aSupprimé §6{0}§a du tracé §6#{1}§a!" + removed-plot-member: "§aSupprimé §6{0}§a du tracé §6#{1}§a!" left-plot: "§aTracé de gauche §6#{0}§a!" plot-will-get-abandoned-warning: "§c§lATTENTION: §cCette parcelle sera automatiquement abandonnée!" plot-will-get-rejected-warning: "§c§lATTENTION: §cCette parcelle sera rejetée!" @@ -196,6 +231,8 @@ message: creating-plot: "§aCréation d'un nouveau tracé..." created-new-plot: "§aCréé un nouveau tracé§a pour §6{0}§a!" changed-language: "§aChangement de langue en §6{0}§a!" + enter-feedback: "Please enter a feedback for the player in the chat." + input-expires-after: "§9Chat input expires after §6{0} §9minutes." error: plot-does-not-exist: "Ce complot n'existe pas!" plot-either-unclaimed-or-unreviewed: "Cette parcelle est soit non réclamée, soit n'a pas encore été examinée!" @@ -204,10 +241,10 @@ message: can-only-submit-unfinished-plots: "Vous ne pouvez soumettre que des tracés inachevés!" can-only-undo-submissions-unreviewed-plots: "Vous ne pouvez annuler que les soumissions de parcelles non révisées!" can-only-manage-members-unfinished-plots: "Vous ne pouvez gérer que les membres des parcelles inachevées!" - can-only-tpll-to-plot: "Vous ne pouvez utiliser /tpll que sur un tracé!" - can-undo-review: "Vous ne pouvez pas annuler une révision que vous n'avez pas révisée vous-même!" - cant-send-feedback: "Vous ne pouvez pas envoyer de commentaires à un tracé que vous n'avez pas révisé vous-même!" - can-review-own-plot: "Vous ne pouvez pas réviser votre propre intrigue!" + cannot-teleport-outside-plot: "Vous ne pouvez utiliser /tpll que sur un tracé!" + cannot-undo-review: "Vous ne pouvez pas annuler une révision que vous n'avez pas révisée vous-même!" + cannot-send-feedback: "Vous ne pouvez pas envoyer de commentaires à un tracé que vous n'avez pas révisé vous-même!" + cannot-review-own-plot: "Vous ne pouvez pas réviser votre propre intrigue!" player-has-no-permissions: "Vous n'avez pas la permission de faire ça!" player-has-no-invitations: "Vous n'avez aucune invitation!" player-is-not-allowed: "Vous n'êtes pas autorisé à faire ça!" @@ -223,8 +260,19 @@ message: no-plots-left: "Ce projet de ville n'a plus de parcelles restantes. Veuillez sélectionner un autre projet." please-wait: "Veuillez patienter quelques secondes avant de créer un nouveau tracé!" all-slots-occupied: "Tous vos slots sont occupés! Veuillez terminer vos tracés actuels avant d'en créer un nouveau." + no-assignment-as-reviewer: "You have not been assigned to a build team as a reviewer." + feedback-input-expired: "The chat input has expired! Use §7/editfeedback §cto edit the feedback." - +leaderboards: + pages: + DAILY: "Daily" + WEEKLY: "Weekly" + MONTHLY: "Monthly" + YEARLY: "Yearly" + LIFETIME: "Lifetime" + actionbar-position: "Position #{0}" + actionbar-percentage: "Top {0}%" + not-on-leaderboard: "Not on leaderboard" # NOTE: Do not change -config-version: "1.0" \ No newline at end of file +config-version: "1.2" \ 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..214bcde4 100644 --- a/src/main/resources/lang/ko_KR.yml +++ b/src/main/resources/lang/ko_KR.yml @@ -25,6 +25,7 @@ plot: members: "플롯 멤버들" member: "플롯 멤버" city: "도시" + country: "Country" difficulty: "난이도" status: "상태" score: "점수" @@ -39,10 +40,30 @@ plot: # | City Projects # ----------------------------------------------------- city-project: + cities: "Cities" open: "개의 빈 플롯" in-progress: "개의 진행 중인 플롯" completed: "개의 완성된 플롯" + plots-available: 'Plots Available' no-plots-available: "건축할 수 있는 플롯이 없음" + for-your-difficulty: "({0} for your difficulty)" + +# ----------------------------------------------------- +# | Countries +# ----------------------------------------------------- +country: + countries: "Countries" + +# ----------------------------------------------------- +# | Continents +# ----------------------------------------------------- +continent: + europe: "Europe" + asia: "Asia" + africa: "Africa" + oceania: "Oceania" + south-america: "South America" + north-america: "North America" # ----------------------------------------------------- # | Difficulty @@ -81,6 +102,9 @@ menu-title: cancel: "취소" add-member-to-plot: "플롯에 멤버 추가하기" companion: "메뉴" + companion-select-continent: 'Select A Continent' + companion-select-country: 'Select A Country' + companion-select-city: 'Select A City' player-plots: "{0}님의 플롯" leave-plot: "플롯 떠나기" review-plots: "플롯 리뷰하기" @@ -88,7 +112,12 @@ 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" + filter-by-country: "Filter By Country" + information: "Info" # ----------------------------------------------------- # | Menu Descriptions @@ -116,7 +145,12 @@ 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" + filter-desc: "Show All" + information-desc: "A plot can receive a maximum of 20 points. If the plot receives less than 8 points or one category has 0 points, the plot is rejected and the builder gets the plot back to improve it. If the plot receives 0 points, it gets abandoned." # ----------------------------------------------------- # | Review @@ -126,9 +160,11 @@ review: manage-plot: "플롯 관리하기" manage-and-review-plots: "플롯 리뷰 / 관리하기" accepted: "승낙됨" + abandoned: "Abandoned" rejected: "거절됨" feedback: "피드백" reviewer: "검토자" + player-language: "Player Language" criteria: accuracy: "정확도" accuracy-desc: "얼마나 정확하게 건축되었나요?////- 현실과의 유사성//- 올바른 외곽선//- 올바른 높이//- 완성도" @@ -139,7 +175,6 @@ review: technique: "기법" technique-desc: "사용된 건축 기법들은 무엇이고 얼마나 창의적인가요?////- 월드에딧//- 특수 블록" - # ----------------------------------------------------- # | Notes # ----------------------------------------------------- @@ -177,7 +212,7 @@ message: abandoned-plot: "§aID §6#{0}§a의 플롯을 버렸습니다!" finished-plot: "§6{1}§a님의 플롯 §6#{0}§a(이)가 완성되었습니다!" plot-marked-as-reviewed: "§6{1}§a님의 플롯 §6#{0}§a(이)가 리뷰되었습니다!" - plot-rejected: "§6{1}§a님의 플롯 §6#{0}§a(이)가 거절되었습니다. §6/sendFeedback <텍스트>§a 명령어로 피드백을 보내세요!" + plot-rejected: "§6{1}§a님의 플롯 §6#{0}§a(이)가 거절되었습니다." undid-submission: "§a플롯 §6#{0}§a의 제출을 취소하였습니다!" undid-review: "§6{1}§a님의 플롯 §6#{0}§a의 리뷰를 취소하였습니다!" reviewed-plot: "§a당신의 플롯 §6#{0}§a(이)가 리뷰되었습니다!" @@ -196,6 +231,8 @@ message: creating-plot: "§a새로운 플롯 생성 중..." created-new-plot: "§6{0}§a님의 플롯을 생성하였습니다!" changed-language: "§a언어를 §6{0}§a(으)로 변경하였습니다!" + enter-feedback: "Please enter a feedback for the player in the chat." + input-expires-after: "§9Chat input expires after §6{0} §9minutes." error: plot-does-not-exist: "존재하지 않는 플롯입니다!" plot-either-unclaimed-or-unreviewed: "아직 소유되거나 검토되지 않은 플롯입니다!" @@ -204,7 +241,7 @@ message: can-only-submit-unfinished-plots: "미완성된 플롯만 제출하실 수 있습니다!" can-only-undo-submissions-unreviewed-plots: "이미 리뷰된 플롯의 제출을 취소하실 수 없습니다!" can-only-manage-members-unfinished-plots: "멤버 관리는 미완성된 플롯에서만 가능합니다!" - can-only-tpll-to-plot: "플롯에서는 /tpll만 사용할 수 있습니다!" + cannot-teleport-outside-plot: "플롯에서는 /tpll만 사용할 수 있습니다!" cannot-undo-review: "오직 자신의 리뷰만 취소할 수 있습니다!" cannot-send-feedback: "오직 자신이 리뷰한 플롯에만 피드백을 보낼 수 있습니다!" cannot-review-own-plot: "자신의 플롯은 검토할 수 없습니다!" @@ -223,8 +260,19 @@ message: no-plots-left: "이 도시 프로젝트에 남아있는 플롯이 없습니다. 다른 프로젝트를 선택해주세요." please-wait: "새 플롯이 생성될 때까지 기다려주세요!" all-slots-occupied: "슬롯이 모두 꽉 찼습니다! 새 플롯을 생성하기 전에 현재 남아있는 플롯을 먼저 완성해주세요." + no-assignment-as-reviewer: "You have not been assigned to a build team as a reviewer." + feedback-input-expired: "The chat input has expired! Use §7/editfeedback §cto edit the feedback." - +leaderboards: + pages: + DAILY: "Daily" + WEEKLY: "Weekly" + MONTHLY: "Monthly" + YEARLY: "Yearly" + LIFETIME: "Lifetime" + actionbar-position: "Position #{0}" + actionbar-percentage: "Top {0}%" + not-on-leaderboard: "Not on leaderboard" # NOTE: Do not change -config-version: "1.0" \ No newline at end of file +config-version: "1.2" \ 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..2d136e69 100644 --- a/src/main/resources/lang/ru_RU.yml +++ b/src/main/resources/lang/ru_RU.yml @@ -15,7 +15,6 @@ lang: name: "Русский (Россия)" head-id: "4406" - # ----------------------------------------------------- # | Plot # ----------------------------------------------------- @@ -26,6 +25,7 @@ plot: members: "Участник собственности" member: "Участник Участка" city: "Город" + country: "Country" difficulty: "Сложность" status: "Статус" score: "Оценка" @@ -36,16 +36,34 @@ plot: empty-member-slot: "Пустое место для участника" shared-by-members: "(разделен {0} участниками)" - # ----------------------------------------------------- # | City Projects # ----------------------------------------------------- city-project: + cities: "Cities" open: "Свободных Участков" in-progress: "Участков в Процессе Постройки" completed: "Завершённых Участков" + plots-available: 'Plots Available' no-plots-available: "Доступных Участков Нет" + for-your-difficulty: "({0} for your difficulty)" + +# ----------------------------------------------------- +# | Countries +# ----------------------------------------------------- +country: + countries: "Countries" +# ----------------------------------------------------- +# | Continents +# ----------------------------------------------------- +continent: + europe: "Europe" + asia: "Asia" + africa: "Africa" + oceania: "Oceania" + south-america: "South America" + north-america: "North America" # ----------------------------------------------------- # | Difficulty @@ -54,7 +72,6 @@ difficulty: automatic: "Автоматическая" score-multiplier: "Множитель Оценки" - # ----------------------------------------------------- # | Menu Titles # ----------------------------------------------------- @@ -85,6 +102,9 @@ menu-title: cancel: "Отменить" add-member-to-plot: "Добавить Участника к Участку" companion: "Компаньонка" + companion-select-continent: 'Select A Continent' + companion-select-country: 'Select A Country' + companion-select-city: 'Select A City' player-plots: "{0} Участков" leave-plot: "Покинуть Участок" review-plots: "Оценить Участки" @@ -92,7 +112,12 @@ 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" + filter-by-country: "Filter By Country" + information: "Info" # ----------------------------------------------------- # | Menu Descriptions @@ -120,7 +145,12 @@ 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" + filter-desc: "Show All" + information-desc: "A plot can receive a maximum of 20 points. If the plot receives less than 8 points or one category has 0 points, the plot is rejected and the builder gets the plot back to improve it. If the plot receives 0 points, it gets abandoned." # ----------------------------------------------------- # | Review @@ -130,9 +160,11 @@ review: manage-plot: "Управлять участком" manage-and-review-plots: "Управление и Оценка Участков" accepted: "Одобрено" + abandoned: "Abandoned" rejected: "Отклонено" feedback: "Отзыв" reviewer: "Оценщик" + player-language: "Player Language" criteria: accuracy: "Точность Воссоздания" accuracy-desc: "Насколько точно исполнено здание?////- Выглядит как в настоящей жизни//- Правильные контуры//- Правильная высота//- Полностью завершен" @@ -143,7 +175,6 @@ review: technique: "Техника" technique-desc: "Какие строительные техники были применены и насколько они креативны?////- World-Edit//- Специальные Блоки" - # ----------------------------------------------------- # | Notes # ----------------------------------------------------- @@ -181,7 +212,7 @@ message: abandoned-plot: "§aПокидание участка с ID §6#{0}§a!" finished-plot: "§aУчасток §6#{0}§a построенный §6{1}§a был завершён!" plot-marked-as-reviewed: "§aУчасток §6#{0}§a построенный §6{1}§aбыл помечена как оценённый!!" - plot-rejected: "§aУчасток §6#{0}§a построенный §6{1}§a был отклонен! Отправьте отзыв через §6/sendFeedback §a!" + plot-rejected: "§aУчасток §6#{0}§a построенный §6{1}§a был отклонен!" undid-submission: "§aОтмена отправки участка §6#{0}§a!" undid-review: "§aОтмена оценки участка §6#{0}§a построенным §6#{1}§a!" reviewed-plot: "§aВаш участок §6#{0}§a был оценён!" @@ -200,6 +231,8 @@ message: creating-plot: "§aСоздание нового участка..." created-new-plot: "§aСоздан новый участок§a для §6{0}§a!" changed-language: "§aВаш язык изменён на §6{0}§a!" + enter-feedback: "Please enter a feedback for the player in the chat." + input-expires-after: "§9Chat input expires after §6{0} §9minutes." error: plot-does-not-exist: "Этот участок не существует!" plot-either-unclaimed-or-unreviewed: "Этот участок не занят либо ещё не был оценён!!" @@ -208,7 +241,7 @@ message: can-only-submit-unfinished-plots: "Вы только можете отправить незавёршенные участки!Y!" can-only-undo-submissions-unreviewed-plots: "Вы только можете отменить заявки незавершённых участков!" can-only-manage-members-unfinished-plots: "Вы только можете управлять участниками незавершённых участков!" - can-only-tpll-to-plot: "Вы только можете использовать /tpll на участке!" + cannot-teleport-outside-plot: "Вы только можете использовать /tpll на участке!" cannot-undo-review: "Вы не можете отменить оценку которую выставляли не вы!" cannot-send-feedback: "Вы не можете отправить отзыв к участку который оценивали не вы!" cannot-review-own-plot: "Вы не можете оценить свой участок!" @@ -227,8 +260,19 @@ message: no-plots-left: "У этого градостроительного проекта больше не осталось участков. Пожалуйста, выберите другой проект." please-wait: "Пожалуйста, подождите несколько секунд перед созданием нового участка!" all-slots-occupied: "Все ваши слоты заняты! Пожалуйста, завершите текущие участки, прежде чем создавать новый." + no-assignment-as-reviewer: "You have not been assigned to a build team as a reviewer." + feedback-input-expired: "The chat input has expired! Use §7/editfeedback §cto edit the feedback." - +leaderboards: + pages: + DAILY: "Daily" + WEEKLY: "Weekly" + MONTHLY: "Monthly" + YEARLY: "Yearly" + LIFETIME: "Lifetime" + actionbar-position: "Position #{0}" + actionbar-percentage: "Top {0}%" + not-on-leaderboard: "Not on leaderboard" # NOTE: Do not change -config-version: "1.0" \ No newline at end of file +config-version: "1.2" \ 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..46bb0f16 100644 --- a/src/main/resources/lang/zh_CN.yml +++ b/src/main/resources/lang/zh_CN.yml @@ -25,6 +25,7 @@ plot: members: "建地成员" member: "建地成员" city: "城市" + country: "Country" difficulty: "难度" status: "状态" score: "积分" @@ -39,10 +40,30 @@ plot: # | City Projects # ----------------------------------------------------- city-project: + cities: "Cities" open: "开启建地" in-progress: "进行中建地" completed: "已完成建地" + plots-available: 'Plots Available' no-plots-available: "无可用建地" + for-your-difficulty: "({0} for your difficulty)" + +# ----------------------------------------------------- +# | Countries +# ----------------------------------------------------- +country: + countries: "Countries" + +# ----------------------------------------------------- +# | Continents +# ----------------------------------------------------- +continent: + europe: "Europe" + asia: "Asia" + africa: "Africa" + oceania: "Oceania" + south-america: "South America" + north-america: "North America" # ----------------------------------------------------- # | Difficulty @@ -81,6 +102,9 @@ menu-title: cancel: "取消" add-member-to-plot: "添加成员到建地" companion: "伙伴" + companion-select-continent: 'Select A Continent' + companion-select-country: 'Select A Country' + companion-select-city: 'Select A City' player-plots: "{0}块建地" leave-plot: "离开建地" review-plots: "审核建地" @@ -88,7 +112,12 @@ 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" + filter-by-country: "Filter By Country" + information: "Info" # ----------------------------------------------------- # | Menu Descriptions @@ -116,7 +145,12 @@ 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" + filter-desc: "Show All" + information-desc: "A plot can receive a maximum of 20 points. If the plot receives less than 8 points or one category has 0 points, the plot is rejected and the builder gets the plot back to improve it. If the plot receives 0 points, it gets abandoned." # ----------------------------------------------------- # | Review @@ -126,9 +160,11 @@ review: manage-plot: "管理建地" manage-and-review-plots: "管理与审核建地" accepted: "接受" + abandoned: "Abandoned" rejected: "驳回" feedback: "回馈" reviewer: "审核员" + player-language: "Player Language" criteria: accuracy: "准确性" accuracy-desc: "建筑的精确度如何? ////- 看起来像在真实世界//- 正确的轮廓//- 正确的高度//- 完成了" @@ -139,7 +175,6 @@ review: technique: "技巧" technique-desc: "使用了什么建筑技巧,它们的创意如何? ////- World-Edit//- 特殊方块" - # ----------------------------------------------------- # | Notes # ----------------------------------------------------- @@ -177,7 +212,7 @@ message: abandoned-plot: "§a有ID之废弃建地 §6#{0}§a!" finished-plot: "§a §6{1}§a 的建地 §6#{0}§a 已完成! " plot-marked-as-reviewed: "§a §6{1}§a 的建地 §6#{0}§a 已标记供审核! " - plot-rejected: "§a §6{1}§a 的建地 §6#{0}§a 已被驳回!使用 §6/sendFeedback §a发送回馈! " + plot-rejected: "§a §6{1}§a 的建地 §6#{0}§a 已被驳回!" undid-submission: "§a尚未提交的建地 §6#{0}§a! " undid-review: "§a尚未审核的建地 §6#{0}§a by §6#{1}§a! " reviewed-plot: "§a你的建地 §6#{0}§a 已被审核! " @@ -196,6 +231,8 @@ message: creating-plot: "§a创建新建地..." created-new-plot: "§a创建新建地§a 为 §6{0}§a! " changed-language: "§a将你的语言变更为 §6{0}§a! " + enter-feedback: "Please enter a feedback for the player in the chat." + input-expires-after: "§9Chat input expires after §6{0} §9minutes." error: plot-does-not-exist: "此建地不存在! " plot-either-unclaimed-or-unreviewed: "此建地无人认领或尚未审核! " @@ -204,7 +241,7 @@ message: can-only-submit-unfinished-plots: "你只能提交尚未完成的建地! " can-only-undo-submissions-unreviewed-plots: "你只能撤回尚未审核的建地! " can-only-manage-members-unfinished-plots: "你只能管理尚未完成建地的成员! " - can-only-tpll-to-plot: "你在建地上只能使用 /tpll ! " + cannot-teleport-outside-plot: "你在建地上只能使用 /tpll ! " cannot-undo-review: "你无法撤回你自己未审核过的审核! " cannot-send-feedback: "你无法发送你自己未审核过的回馈! " cannot-review-own-plot: "你无法审核你所有的建地! " @@ -223,8 +260,19 @@ message: no-plots-left: "此城市计画区没有剩余更多建地了。请选择其他计画区。" please-wait: "请稍后再创建一个新的建地!" all-slots-occupied: "你的所有槽位都被占用了!请在创建新的建地之前先完成您当前的建地。" + no-assignment-as-reviewer: "You have not been assigned to a build team as a reviewer." + feedback-input-expired: "The chat input has expired! Use §7/editfeedback §cto edit the feedback." - +leaderboards: + pages: + DAILY: "Daily" + WEEKLY: "Weekly" + MONTHLY: "Monthly" + YEARLY: "Yearly" + LIFETIME: "Lifetime" + actionbar-position: "Position #{0}" + actionbar-percentage: "Top {0}%" + not-on-leaderboard: "Not on leaderboard" # NOTE: Do not change -config-version: "1.0" \ No newline at end of file +config-version: "1.2" \ 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..4389700a 100644 --- a/src/main/resources/lang/zh_TW.yml +++ b/src/main/resources/lang/zh_TW.yml @@ -25,6 +25,7 @@ plot: members: "建地成員" member: "建地成員" city: "城市" + country: "Country" difficulty: "難度" status: "狀態" score: "積分" @@ -39,10 +40,30 @@ plot: # | City Projects # ----------------------------------------------------- city-project: + cities: "Cities" open: "開啟建地" in-progress: "進行中建地" completed: "已完成建地" + plots-available: 'Plots Available' no-plots-available: "無可用建地" + for-your-difficulty: "({0} for your difficulty)" + +# ----------------------------------------------------- +# | Countries +# ----------------------------------------------------- +country: + countries: "Countries" + +# ----------------------------------------------------- +# | Continents +# ----------------------------------------------------- +continent: + europe: "Europe" + asia: "Asia" + africa: "Africa" + oceania: "Oceania" + south-america: "South America" + north-america: "North America" # ----------------------------------------------------- # | Difficulty @@ -81,6 +102,9 @@ menu-title: cancel: "取消" add-member-to-plot: "添加成員到建地" companion: "夥伴" + companion-select-continent: 'Select A Continent' + companion-select-country: 'Select A Country' + companion-select-city: 'Select A City' player-plots: "{0}塊建地" leave-plot: "離開建地" review-plots: "審核建地" @@ -88,7 +112,12 @@ 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" + filter-by-country: "Filter By Country" + information: "Info" # ----------------------------------------------------- # | Menu Descriptions @@ -116,7 +145,12 @@ 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" + filter-desc: "Show All" + information-desc: "A plot can receive a maximum of 20 points. If the plot receives less than 8 points or one category has 0 points, the plot is rejected and the builder gets the plot back to improve it. If the plot receives 0 points, it gets abandoned." # ----------------------------------------------------- # | Review @@ -126,9 +160,11 @@ review: manage-plot: "管理建地" manage-and-review-plots: "管理與審核建地" accepted: "接受" + abandoned: "Abandoned" rejected: "駁回" feedback: "回饋" reviewer: "審核員" + player-language: "Player Language" criteria: accuracy: "準確性" accuracy-desc: "建築的精確度如何?////- 看起來像在真實世界//- 正確的輪廓//- 正確的高度//- 完成了" @@ -139,7 +175,6 @@ review: technique: "技巧" technique-desc: "使用了什麼建築技巧,它們的創意如何?////- World-Edit//- 特殊方塊" - # ----------------------------------------------------- # | Notes # ----------------------------------------------------- @@ -177,7 +212,7 @@ message: abandoned-plot: "§a有ID之廢棄建地 §6#{0}§a!" finished-plot: "§a §6{1}§a 的建地 §6#{0}§a 已完成!" plot-marked-as-reviewed: "§a §6{1}§a 的建地 §6#{0}§a 已標記供審核!" - plot-rejected: "§a §6{1}§a 的建地 §6#{0}§a 已被駁回! 使用 §6/sendFeedback §a發送回饋!" + plot-rejected: "§a §6{1}§a 的建地 §6#{0}§a 已被駁回!" undid-submission: "§a尚未提交的建地 §6#{0}§a!" undid-review: "§a尚未審核的建地 §6#{0}§a by §6#{1}§a!" reviewed-plot: "§a你的建地 §6#{0}§a 已被審核!" @@ -196,6 +231,8 @@ message: creating-plot: "§a創建新建地..." created-new-plot: "§a創建新建地§a 為 §6{0}§a!" changed-language: "§a將你的語言變更為 §6{0}§a!" + enter-feedback: "Please enter a feedback for the player in the chat." + input-expires-after: "§9Chat input expires after §6{0} §9minutes." error: plot-does-not-exist: "此建地不存在!" plot-either-unclaimed-or-unreviewed: "此建地無人認領或尚未審核!" @@ -204,7 +241,7 @@ message: can-only-submit-unfinished-plots: "你只能提交尚未完成的建地!" can-only-undo-submissions-unreviewed-plots: "你只能撤回尚未審核的建地!" can-only-manage-members-unfinished-plots: "你只能管理尚未完成建地的成員!" - can-only-tpll-to-plot: "你在建地上只能使用 /tpll !" + cannot-teleport-outside-plot: "你在建地上只能使用 /tpll !" cannot-undo-review: "你無法撤回你自己未審核過的審核!" cannot-send-feedback: "你無法發送你自己未審核過的回饋!" cannot-review-own-plot: "你無法審核你所有的建地!" @@ -223,8 +260,19 @@ message: no-plots-left: "此城市計畫區沒有剩餘更多建地了。請選擇其他計畫區。" please-wait: "請稍後再創建一個新的建地!" all-slots-occupied: "你的所有槽位都被占用了!請在創建新的建地之前先完成您當前的建地。" + no-assignment-as-reviewer: "You have not been assigned to a build team as a reviewer." + feedback-input-expired: "The chat input has expired! Use §7/editfeedback §cto edit the feedback." - +leaderboards: + pages: + DAILY: "Daily" + WEEKLY: "Weekly" + MONTHLY: "Monthly" + YEARLY: "Yearly" + LIFETIME: "Lifetime" + actionbar-position: "Position #{0}" + actionbar-percentage: "Top {0}%" + not-on-leaderboard: "Not on leaderboard" # NOTE: Do not change -config-version: "1.0" \ No newline at end of file +config-version: "1.2" \ No newline at end of file diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index d37a700d..a5946d7b 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -1,9 +1,9 @@ main: com.alpsbte.plotsystem.PlotSystem -version: 2.3 +version: 3.0 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: @@ -30,9 +30,9 @@ commands: undoreview: description: Undo a review of a plot. usage: /undoreview - sendfeedback: + editfeedback: description: Updates the feedback of a plot. - usage: /sendfeedback + usage: /editfeedback editplot: description: Enable/disable build permissions for reviewers on a plot. usage: /editplot