diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml index 717a9cdfc..9b0dbc13e 100644 --- a/.github/FUNDING.yml +++ b/.github/FUNDING.yml @@ -9,4 +9,4 @@ community_bridge: # Replace with a single Community Bridge project-name e.g., cl liberapay: # Replace with a single Liberapay username issuehunt: # Replace with a single IssueHunt username otechie: # Replace with a single Otechie username -custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] +custom: https://www.paypal.me/AlexanderBrandes # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md index a70ab837c..f1ee68845 100644 --- a/.github/ISSUE_TEMPLATE.md +++ b/.github/ISSUE_TEMPLATE.md @@ -28,6 +28,7 @@ assignees: '' +**/plot debugpaste:** ### Server type: **Select one** @@ -97,4 +98,4 @@ for short (20 lines or less) text blobs, or a paste service for large blobs --> - [] I made sure there are no duplicates of this report [(Use Search)](https://github.com/IntellectualSites/PlotSquared/issues?utf8=%E2%9C%93&q=is%3Aissue) - [] I made sure I am using an up-to-date version of PlotSquared - [] I made sure the bug/error is not caused by any other plugin -- [x] I didn't read but checked everything above. +- [x] I didn't read but checked everything above. \ No newline at end of file diff --git a/.github/ISSUE_TEMPLATE/bug-issue-report-for-plotsquared.md b/.github/ISSUE_TEMPLATE/bug-issue-report-for-plotsquared.md deleted file mode 100644 index c619a6d14..000000000 --- a/.github/ISSUE_TEMPLATE/bug-issue-report-for-plotsquared.md +++ /dev/null @@ -1,101 +0,0 @@ ---- -name: Bug/Issue report for PlotSquared -about: Bug / Issue report about this plugin -title: '' -labels: "[?] Testing Required" -assignees: '' - ---- - - - - - - - -# Bug Report Template: - -## Required Information section: -> ALL FIELDS IN THIS SECTION ARE REQUIRED, and must contain appropriate information -### Server config info (/plot debugpaste / file paste links): - - - -**/plot debugpaste:** - -### Server type: -**Select one** - -- [] Spigot / Paper *(CraftBukkit should not be used, re-test with Spigot first!)* -- [] Sponge -- [] NukkitX - -### PlotSquared version: - -``` -Paste the output here, between the tick marks, replacing this text -``` - -### Minecraft Version: -**Select one** - -- [] Minecraft 1.15.2 -- [] Minecraft 1.14.4 -- [] Minecraft 1.13.2 -- [] Minecraft 1.12.2 -- [] Minecraft 1.11.2 -- [] Minecraft 1.10.2 -- [] Minecraft 1.9.4 -- [] Minecraft 1.8.8 -- [] Minecraft Java Edition *other versions, please specify*: -- [] Minecraft Bedrock Edition *specify version*: -- [] Minecraft Sponge *specify version*: - -### Server build info: - -``` -Paste the output here, between the tick marks, replacing this text -``` - -### WorldEdit/FAWE versions: - -- [] FAWE version: -- [] WorldEdit version: - -### Description of the problem: - - - -### How to replicate: - - -## Additional Information: -> The information here is optional for you to provide, however it may help us to more readily diagnose any compatibility and bug issues. - -### Other plugins being used on the server: - - -### Relevant console output, log lines, and/or screenshots: - - -### Additional relevant comments/remarks: - - -# AFFIRMATION OF COMPLETION: - -- [] I included all information required in the sections above -- [] I made sure there are no duplicates of this report [(Use Search)](https://github.com/IntellectualSites/PlotSquared/issues?utf8=%E2%9C%93&q=is%3Aissue) -- [] I made sure I am using an up-to-date version of PlotSquared -- [] I made sure the bug/error is not caused by any other plugin -- [x] I didn't read but checked everything above. diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index 83661f8c6..fd39e3738 100644 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -1,5 +1,8 @@ blank_issues_enabled: false contact_links: + - name: PlotSquared Issue Tracker + url: https://issues.intellectualsites.com/projects/ps + about: Click here to move to our new issue tracker - name: PlotSquared Suggestions url: https://github.com/IntellectualSites/PlotSquaredSuggestions about: If you want to submit feature or suggestion ideas, do that here \ No newline at end of file diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 60cba3066..f55841917 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -2,10 +2,10 @@ -**Fixes #{issue number}** +**Fixes {Link to issue}** ## Description diff --git a/.gitignore b/.gitignore index 24f46cd56..3423dd222 100644 --- a/.gitignore +++ b/.gitignore @@ -142,3 +142,4 @@ p2error.txt *.bat Nukkit/build/resources/main/plugin.yml docs/ +build/ diff --git a/Bukkit/build.gradle b/Bukkit/build.gradle index 9fa1f8cf1..61ae5e54f 100644 --- a/Bukkit/build.gradle +++ b/Bukkit/build.gradle @@ -11,7 +11,9 @@ repositories { name = "papermc" url = "https://papermc.io/repo/repository/maven-public/" } + maven { url = "https://ci.ender.zone/plugin/repository/everything/" } maven { url = "https://mvn.intellectualsites.com/content/repositories/snapshots" } + maven { url = "https://repo.wea-ondara.net/repository/public/" } mavenLocal() } @@ -20,17 +22,24 @@ dependencies { implementation(project(":PlotSquared-Core")) compile("org.bstats:bstats-bukkit:1.7") compile(project(":PlotSquared-Core")) - compile("com.destroystokyo.paper:paper-api:1.15.2-R0.1-SNAPSHOT") + compile("com.destroystokyo.paper:paper-api:1.16.1-R0.1-SNAPSHOT") //implementation 'com.onarandombox.multiversecore:Multiverse-Core:3.0.0-SNAPSHOT' - implementation("org.spigotmc:spigot-api:1.15.2-R0.1-SNAPSHOT") - compile(group: "com.sk89q.worldedit", name: "worldedit-bukkit", version: "7.0.1") + implementation("org.spigotmc:spigot-api:1.16.1-R0.1-SNAPSHOT") + compile(group: "com.sk89q.worldedit", name: "worldedit-bukkit", version: "7.1.0") { + exclude(module: "bukkit") + + } compile("io.papermc:paperlib:1.0.2") implementation("net.kyori:text-adapter-bukkit:3.0.3") compile("com.github.MilkBowl:VaultAPI:1.7") { exclude(module: "bukkit") } - implementation("me.clip:placeholderapi:2.10.4") + implementation("me.clip:placeholderapi:2.10.6") + implementation("net.luckperms:api:5.1") + implementation("net.ess3:EssentialsX:2.17.2") + implementation("net.alpenblock:BungeePerms:4.0-dev-106") compile("se.hyperver.hyperverse:Core:0.6.0-SNAPSHOT"){ transitive = false } + compile('com.sk89q:squirrelid:1.0.0-SNAPSHOT'){ transitive = false } } sourceCompatibility = 1.8 @@ -87,10 +96,14 @@ shadowJar { include(dependency("io.papermc:paperlib:1.0.2")) include(dependency("net.kyori:text-adapter-bukkit:3.0.3")) include(dependency("org.bstats:bstats-bukkit:1.7")) + include(dependency("org.khelekore:prtree:1.7.0-SNAPSHOT")) + include(dependency("com.sk89q:squirrelid:1.0.0-SNAPSHOT")) } relocate('net.kyori.text', 'com.plotsquared.formatting.text') relocate("io.papermc.lib", "com.plotsquared.bukkit.paperlib") relocate("org.bstats", "com.plotsquared.metrics") + relocate('com.sk89q.squirrelid', 'com.plotsquared.squirrelid') + relocate('org.khelekore.prtree', 'com.plotsquared.prtree') archiveFileName = "${project.name}-${parent.version}.jar" destinationDirectory = file "../target" } diff --git a/Bukkit/pom.xml b/Bukkit/pom.xml index 40202c32e..d70af5d57 100644 --- a/Bukkit/pom.xml +++ b/Bukkit/pom.xml @@ -9,7 +9,7 @@ org.json json - 20190722 + 20200518 compile @@ -21,20 +21,26 @@ com.plotsquared PlotSquared-Core - 5.11.2 + 5.12.2 compile com.destroystokyo.paper paper-api - 1.15.2-R0.1-SNAPSHOT + 1.16.1-R0.1-SNAPSHOT compile com.sk89q.worldedit worldedit-bukkit - 7.0.1 + 7.1.0 compile + + + bukkit + * + + io.papermc @@ -59,6 +65,24 @@ Core 0.6.0-SNAPSHOT compile + + + * + * + + + + + com.sk89q + squirrelid + 1.0.0-SNAPSHOT + compile + + + * + * + + com.sk89q.worldedit @@ -113,7 +137,7 @@ org.spigotmc spigot-api - 1.15.2-R0.1-SNAPSHOT + 1.16.1-R0.1-SNAPSHOT runtime @@ -125,7 +149,25 @@ me.clip placeholderapi - 2.10.4 + 2.10.6 + runtime + + + net.luckperms + api + 5.1 + runtime + + + net.ess3 + EssentialsX + 2.17.2 + runtime + + + net.alpenblock + BungeePerms + 4.0-dev-106 runtime diff --git a/Bukkit/src/main/java/com/plotsquared/bukkit/BukkitCommand.java b/Bukkit/src/main/java/com/plotsquared/bukkit/BukkitCommand.java index 2d3737ee0..1f5b0de02 100644 --- a/Bukkit/src/main/java/com/plotsquared/bukkit/BukkitCommand.java +++ b/Bukkit/src/main/java/com/plotsquared/bukkit/BukkitCommand.java @@ -25,7 +25,6 @@ */ package com.plotsquared.bukkit; -import com.plotsquared.bukkit.command.DebugUUID; import com.plotsquared.bukkit.util.BukkitUtil; import com.plotsquared.core.command.MainCommand; import com.plotsquared.core.player.ConsolePlayer; @@ -46,10 +45,6 @@ import java.util.List; public class BukkitCommand implements CommandExecutor, TabCompleter { - public BukkitCommand() { - new DebugUUID(); - } - @Override public boolean onCommand(CommandSender commandSender, Command command, String commandLabel, String[] args) { @@ -83,6 +78,6 @@ public class BukkitCommand implements CommandExecutor, TabCompleter { for (com.plotsquared.core.command.Command o : objects) { result.add(o.toString()); } - return result.isEmpty() ? null : result; + return result; } } diff --git a/Bukkit/src/main/java/com/plotsquared/bukkit/BukkitMain.java b/Bukkit/src/main/java/com/plotsquared/bukkit/BukkitMain.java index 779aec999..2132fefac 100644 --- a/Bukkit/src/main/java/com/plotsquared/bukkit/BukkitMain.java +++ b/Bukkit/src/main/java/com/plotsquared/bukkit/BukkitMain.java @@ -38,23 +38,27 @@ import com.plotsquared.bukkit.managers.HyperverseWorldManager; import com.plotsquared.bukkit.managers.MultiverseWorldManager; import com.plotsquared.bukkit.placeholder.PlaceholderFormatter; import com.plotsquared.bukkit.placeholder.Placeholders; +import com.plotsquared.bukkit.player.BukkitPlayerManager; import com.plotsquared.bukkit.queue.BukkitLocalQueue; import com.plotsquared.bukkit.schematic.BukkitSchematicHandler; import com.plotsquared.bukkit.util.BukkitChatManager; import com.plotsquared.bukkit.util.BukkitChunkManager; import com.plotsquared.bukkit.util.BukkitEconHandler; import com.plotsquared.bukkit.util.BukkitInventoryUtil; +import com.plotsquared.bukkit.util.BukkitPermHandler; import com.plotsquared.bukkit.util.BukkitRegionManager; import com.plotsquared.bukkit.util.BukkitSetupUtils; import com.plotsquared.bukkit.util.BukkitTaskManager; import com.plotsquared.bukkit.util.BukkitUtil; import com.plotsquared.bukkit.util.SetGenCB; import com.plotsquared.bukkit.util.UpdateUtility; -import com.plotsquared.bukkit.util.uuid.DefaultUUIDWrapper; -import com.plotsquared.bukkit.util.uuid.FileUUIDHandler; -import com.plotsquared.bukkit.util.uuid.LowerOfflineUUIDWrapper; -import com.plotsquared.bukkit.util.uuid.OfflineUUIDWrapper; -import com.plotsquared.bukkit.util.uuid.SQLUUIDHandler; +import com.plotsquared.bukkit.uuid.BungeePermsUUIDService; +import com.plotsquared.bukkit.uuid.EssentialsUUIDService; +import com.plotsquared.bukkit.uuid.LuckPermsUUIDService; +import com.plotsquared.bukkit.uuid.OfflinePlayerUUIDService; +import com.plotsquared.bukkit.uuid.PaperUUIDService; +import com.plotsquared.bukkit.uuid.SQLiteUUIDService; +import com.plotsquared.bukkit.uuid.SquirrelIdUUIDService; import com.plotsquared.core.IPlotMain; import com.plotsquared.core.PlotSquared; import com.plotsquared.core.backup.BackupManager; @@ -65,6 +69,7 @@ import com.plotsquared.core.configuration.ChatFormatter; import com.plotsquared.core.configuration.ConfigurationNode; import com.plotsquared.core.configuration.ConfigurationSection; import com.plotsquared.core.configuration.Settings; +import com.plotsquared.core.database.DBFunc; import com.plotsquared.core.generator.GeneratorWrapper; import com.plotsquared.core.generator.HybridGen; import com.plotsquared.core.generator.HybridUtils; @@ -77,19 +82,22 @@ import com.plotsquared.core.plot.PlotArea; import com.plotsquared.core.plot.PlotAreaTerrainType; import com.plotsquared.core.plot.PlotAreaType; import com.plotsquared.core.plot.PlotId; -import com.plotsquared.core.plot.SetupObject; import com.plotsquared.core.plot.message.PlainChatManager; import com.plotsquared.core.plot.world.PlotAreaManager; import com.plotsquared.core.plot.world.SinglePlotArea; import com.plotsquared.core.plot.world.SinglePlotAreaManager; import com.plotsquared.core.queue.QueueProvider; +import com.plotsquared.core.setup.PlotAreaBuilder; +import com.plotsquared.core.setup.SettingsNodesWrapper; import com.plotsquared.core.util.ChatManager; import com.plotsquared.core.util.ChunkManager; import com.plotsquared.core.util.ConsoleColors; import com.plotsquared.core.util.EconHandler; import com.plotsquared.core.util.InventoryUtil; import com.plotsquared.core.util.MainUtil; +import com.plotsquared.core.util.PermHandler; import com.plotsquared.core.util.PlatformWorldManager; +import com.plotsquared.core.util.PlayerManager; import com.plotsquared.core.util.PremiumVerification; import com.plotsquared.core.util.ReflectionUtils; import com.plotsquared.core.util.RegionManager; @@ -98,9 +106,9 @@ import com.plotsquared.core.util.SetupUtils; import com.plotsquared.core.util.StringMan; import com.plotsquared.core.util.WorldUtil; import com.plotsquared.core.util.task.TaskManager; -import com.plotsquared.core.util.uuid.UUIDHandler; -import com.plotsquared.core.util.uuid.UUIDHandlerImplementation; -import com.plotsquared.core.util.uuid.UUIDWrapper; +import com.plotsquared.core.uuid.CacheUUIDService; +import com.plotsquared.core.uuid.UUIDPipeline; +import com.plotsquared.core.uuid.offline.OfflineModeUUIDService; import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.bukkit.WorldEditPlugin; import com.sk89q.worldedit.extension.platform.Actor; @@ -117,6 +125,7 @@ import org.bukkit.World; import org.bukkit.command.ConsoleCommandSender; import org.bukkit.command.PluginCommand; import org.bukkit.entity.Entity; +import org.bukkit.entity.EntityType; import org.bukkit.entity.LivingEntity; import org.bukkit.entity.Player; import org.bukkit.event.Listener; @@ -134,17 +143,24 @@ import java.util.AbstractMap; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; +import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; +import java.util.Queue; +import java.util.Set; import java.util.UUID; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Executors; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.TimeUnit; import static com.plotsquared.core.util.PremiumVerification.getDownloadID; import static com.plotsquared.core.util.PremiumVerification.getResourceID; import static com.plotsquared.core.util.PremiumVerification.getUserID; import static com.plotsquared.core.util.ReflectionUtils.getRefClass; -public final class BukkitMain extends JavaPlugin implements Listener, IPlotMain { +public final class BukkitMain extends JavaPlugin implements Listener, IPlotMain { private static final int BSTATS_ID = 1404; @Getter private static WorldEdit worldEdit; @@ -163,7 +179,10 @@ public final class BukkitMain extends JavaPlugin implements Listener, IPlotMain private boolean methodUnloadSetup = false; private boolean metricsStarted; @Getter private BackupManager backupManager; - @Getter private PlatformWorldManager worldManager; + @Getter private PlatformWorldManager worldManager; + private final BukkitPlayerManager playerManager = new BukkitPlayerManager(); + private EconHandler econ; + private PermHandler perm; @Override public int[] getServerVersion() { if (this.version == null) { @@ -221,6 +240,122 @@ public final class BukkitMain extends JavaPlugin implements Listener, IPlotMain PlotSquared.log(Captions.PREFIX + "&6Couldn't verify purchase :("); } + final UUIDPipeline impromptuPipeline = PlotSquared.get().getImpromptuUUIDPipeline(); + final UUIDPipeline backgroundPipeline = PlotSquared.get().getBackgroundUUIDPipeline(); + + // Services are accessed in order + final CacheUUIDService cacheUUIDService = + new CacheUUIDService(Settings.UUID.UUID_CACHE_SIZE); + impromptuPipeline.registerService(cacheUUIDService); + backgroundPipeline.registerService(cacheUUIDService); + impromptuPipeline.registerConsumer(cacheUUIDService); + backgroundPipeline.registerConsumer(cacheUUIDService); + + // Now, if the server is in offline mode we can only use profiles and direct UUID + // access, and so we skip the player profile stuff as well as SquirrelID (Mojang lookups) + if (Settings.UUID.OFFLINE) { + final OfflineModeUUIDService offlineModeUUIDService = new OfflineModeUUIDService(); + impromptuPipeline.registerService(offlineModeUUIDService); + backgroundPipeline.registerService(offlineModeUUIDService); + PlotSquared.log(Captions.PREFIX + "(UUID) Using the offline mode UUID service"); + } + + final OfflinePlayerUUIDService offlinePlayerUUIDService = new OfflinePlayerUUIDService(); + impromptuPipeline.registerService(offlinePlayerUUIDService); + backgroundPipeline.registerService(offlinePlayerUUIDService); + + final SQLiteUUIDService sqLiteUUIDService = new SQLiteUUIDService("user_cache.db"); + + final SQLiteUUIDService legacyUUIDService; + if (Settings.UUID.LEGACY_DATABASE_SUPPORT && MainUtil + .getFile(PlotSquared.get().IMP.getDirectory(), "usercache.db").exists()) { + legacyUUIDService = new SQLiteUUIDService("usercache.db"); + } else { + legacyUUIDService = null; + } + + final LuckPermsUUIDService luckPermsUUIDService; + if (Bukkit.getPluginManager().getPlugin("LuckPerms") != null) { + luckPermsUUIDService = new LuckPermsUUIDService(); + PlotSquared + .log(Captions.PREFIX + "(UUID) Using LuckPerms as a complementary UUID service"); + } else { + luckPermsUUIDService = null; + } + + final BungeePermsUUIDService bungeePermsUUIDService; + if (Bukkit.getPluginManager().getPlugin("BungeePerms") != null) { + bungeePermsUUIDService = new BungeePermsUUIDService(); + PlotSquared + .log(Captions.PREFIX + "(UUID) Using BungeePerms as a complementary UUID service"); + } else { + bungeePermsUUIDService = null; + } + + final EssentialsUUIDService essentialsUUIDService; + if (Bukkit.getPluginManager().getPlugin("Essentials") != null) { + essentialsUUIDService = new EssentialsUUIDService(); + PlotSquared + .log(Captions.PREFIX + "(UUID) Using Essentials as a complementary UUID service"); + } else { + essentialsUUIDService = null; + } + + if (!Settings.UUID.OFFLINE) { + // If running Paper we'll also try to use their profiles + if (PaperLib.isPaper()) { + final PaperUUIDService paperUUIDService = new PaperUUIDService(); + impromptuPipeline.registerService(paperUUIDService); + backgroundPipeline.registerService(paperUUIDService); + PlotSquared + .log(Captions.PREFIX + "(UUID) Using Paper as a complementary UUID service"); + } + + impromptuPipeline.registerService(sqLiteUUIDService); + backgroundPipeline.registerService(sqLiteUUIDService); + impromptuPipeline.registerConsumer(sqLiteUUIDService); + backgroundPipeline.registerConsumer(sqLiteUUIDService); + + if (legacyUUIDService != null) { + impromptuPipeline.registerService(legacyUUIDService); + backgroundPipeline.registerService(legacyUUIDService); + } + + // Plugin providers + if (luckPermsUUIDService != null) { + impromptuPipeline.registerService(luckPermsUUIDService); + backgroundPipeline.registerService(luckPermsUUIDService); + } + if (bungeePermsUUIDService != null) { + impromptuPipeline.registerService(bungeePermsUUIDService); + backgroundPipeline.registerService(bungeePermsUUIDService); + } + if (essentialsUUIDService != null) { + impromptuPipeline.registerService(essentialsUUIDService); + backgroundPipeline.registerService(essentialsUUIDService); + } + + final SquirrelIdUUIDService impromptuMojangService = + new SquirrelIdUUIDService(Settings.UUID.IMPROMPTU_LIMIT); + impromptuPipeline.registerService(impromptuMojangService); + final SquirrelIdUUIDService backgroundMojangService = + new SquirrelIdUUIDService(Settings.UUID.BACKGROUND_LIMIT); + backgroundPipeline.registerService(backgroundMojangService); + } else { + impromptuPipeline.registerService(sqLiteUUIDService); + backgroundPipeline.registerService(sqLiteUUIDService); + impromptuPipeline.registerConsumer(sqLiteUUIDService); + backgroundPipeline.registerConsumer(sqLiteUUIDService); + + if (legacyUUIDService != null) { + impromptuPipeline.registerService(legacyUUIDService); + backgroundPipeline.registerService(legacyUUIDService); + } + } + + impromptuPipeline.storeImmediately("*", DBFunc.EVERYONE); + this.startUuidCatching(sqLiteUUIDService, cacheUUIDService); + if (Bukkit.getPluginManager().getPlugin("PlaceholderAPI") != null) { new Placeholders().register(); if (Settings.Enabled_Components.EXTERNAL_PLACEHOLDERS) { @@ -259,8 +394,22 @@ public final class BukkitMain extends JavaPlugin implements Listener, IPlotMain this.worldManager = new BukkitWorldManager(); } - PlotSquared.log(Captions.PREFIX.getTranslated() + "Using platform world manager: " + - this.worldManager.getName()); + PlotSquared.log( + Captions.PREFIX.getTranslated() + "Using platform world manager: " + this.worldManager + .getName()); + + // Clean up potential memory leak + Bukkit.getScheduler().runTaskTimer(this, () -> { + try { + for (final PlotPlayer player : this.getPlayerManager().getPlayers()) { + if (player.getPlatformPlayer() == null || !player.getPlatformPlayer().isOnline()) { + this.getPlayerManager().removePlayer(player); + } + } + } catch (final Exception e) { + getLogger().warning("Failed to clean up players: " + e.getMessage()); + } + }, 100L, 100L); } private void unload() { @@ -342,6 +491,77 @@ public final class BukkitMain extends JavaPlugin implements Listener, IPlotMain } } + private void startUuidCatching(@NotNull final SQLiteUUIDService sqLiteUUIDService, + @NotNull final CacheUUIDService cacheUUIDService) { + // Load all uuids into a big chunky boi queue + final Queue uuidQueue = new LinkedBlockingQueue<>(); + PlotSquared.get().forEachPlotRaw(plot -> { + final Set uuids = new HashSet<>(); + uuids.add(plot.getOwnerAbs()); + uuids.addAll(plot.getMembers()); + uuids.addAll(plot.getTrusted()); + uuids.addAll(plot.getDenied()); + for (final UUID uuid : uuids) { + if (!uuidQueue.contains(uuid)) { + uuidQueue.add(uuid); + } + } + }); + PlotSquared.log(Captions.PREFIX.getTranslated() + "(UUID) " + uuidQueue.size() + + " UUIDs will be cached."); + + Executors.newSingleThreadScheduledExecutor().schedule(() -> { + // Begin by reading all the SQLite cache at once + cacheUUIDService.accept(sqLiteUUIDService.getAll()); + // Now fetch names for all known UUIDs + final int totalSize = uuidQueue.size(); + int read = 0; + PlotSquared.log(Captions.PREFIX.getTranslated() + + "(UUID) PlotSquared will fetch UUIDs in groups of " + + Settings.UUID.BACKGROUND_LIMIT); + final List uuidList = new ArrayList<>(Settings.UUID.BACKGROUND_LIMIT); + + // Used to indicate that the second retrieval has been attempted + boolean secondRun = false; + + while (!uuidQueue.isEmpty() || !uuidList.isEmpty()) { + if (!uuidList.isEmpty() && secondRun) { + PlotSquared.log("Giving up on last batch. Fetching new batch instead."); + uuidList.clear(); + } + if (uuidList.isEmpty()) { + // Retrieve the secondRun variable to indicate that we're retrieving a + // fresh batch + secondRun = false; + // Populate the request list + for (int i = 0; + i < Settings.UUID.BACKGROUND_LIMIT && !uuidQueue.isEmpty(); i++) { + uuidList.add(uuidQueue.poll()); + read++; + } + } else { + // If the list isn't empty then this is a second run for + // an old batch, so we re-use the patch + secondRun = true; + } + try { + PlotSquared.get().getBackgroundUUIDPipeline().getNames(uuidList).get(); + // Clear the list if we successfully index all the names + uuidList.clear(); + // Print progress + final double percentage = ((double) read / (double) totalSize) * 100.0D; + PlotSquared.log(Captions.PREFIX.getTranslated() + String + .format("(UUID) PlotSquared has cached %.1f%% of UUIDs", percentage)); + } catch (final InterruptedException | ExecutionException e) { + PlotSquared.log("Failed to retrieve that batch. Will try again."); + e.printStackTrace(); + } + } + PlotSquared + .log(Captions.PREFIX.getTranslated() + "(UUID) PlotSquared has cached all UUIDs"); + }, 10, TimeUnit.SECONDS); + } + @Override public void onDisable() { PlotSquared.get().disable(); Bukkit.getScheduler().cancelTasks(this); @@ -411,46 +631,46 @@ public final class BukkitMain extends JavaPlugin implements Listener, IPlotMain Iterator iterator = entities.iterator(); while (iterator.hasNext()) { Entity entity = iterator.next(); - switch (entity.getType()) { - case EGG: - case FISHING_HOOK: - case ENDER_SIGNAL: - case AREA_EFFECT_CLOUD: - case EXPERIENCE_ORB: - case LEASH_HITCH: - case FIREWORK: - case LIGHTNING: - case WITHER_SKULL: - case UNKNOWN: - case PLAYER: + switch (entity.getType().toString()) { + case "EGG": + case "FISHING_HOOK": + case "ENDER_SIGNAL": + case "AREA_EFFECT_CLOUD": + case "EXPERIENCE_ORB": + case "LEASH_HITCH": + case "FIREWORK": + case "LIGHTNING": + case "WITHER_SKULL": + case "UNKNOWN": + case "PLAYER": // non moving / unmovable continue; - case THROWN_EXP_BOTTLE: - case SPLASH_POTION: - case SNOWBALL: - case SHULKER_BULLET: - case SPECTRAL_ARROW: - case ENDER_PEARL: - case ARROW: - case LLAMA_SPIT: - case TRIDENT: + case "THROWN_EXP_BOTTLE": + case "SPLASH_POTION": + case "SNOWBALL": + case "SHULKER_BULLET": + case "SPECTRAL_ARROW": + case "ENDER_PEARL": + case "ARROW": + case "LLAMA_SPIT": + case "TRIDENT": // managed elsewhere | projectile continue; - case ITEM_FRAME: - case PAINTING: + case "ITEM_FRAME": + case "PAINTING": // Not vehicles continue; - case ARMOR_STAND: + case "ARMOR_STAND": // Temporarily classify as vehicle - case MINECART: - case MINECART_CHEST: - case MINECART_COMMAND: - case MINECART_FURNACE: - case MINECART_HOPPER: - case MINECART_MOB_SPAWNER: - case ENDER_CRYSTAL: - case MINECART_TNT: - case BOAT: + case "MINECART": + case "MINECART_CHEST": + case "MINECART_COMMAND": + case "MINECART_FURNACE": + case "MINECART_HOPPER": + case "MINECART_MOB_SPAWNER": + case "ENDER_CRYSTAL": + case "MINECART_TNT": + case "BOAT": if (Settings.Enabled_Components.KILL_ROAD_VEHICLES) { com.plotsquared.core.location.Location location = BukkitUtil.getLocation(entity.getLocation()); @@ -479,10 +699,10 @@ public final class BukkitMain extends JavaPlugin implements Listener, IPlotMain } } continue; - case SMALL_FIREBALL: - case FIREBALL: - case DRAGON_FIREBALL: - case DROPPED_ITEM: + case "SMALL_FIREBALL": + case "FIREBALL": + case "DRAGON_FIREBALL": + case "DROPPED_ITEM": if (Settings.Enabled_Components.KILL_ROAD_ITEMS && plotArea .getOwnedPlotAbs(BukkitUtil.getLocation(entity.getLocation())) == null) { @@ -490,11 +710,11 @@ public final class BukkitMain extends JavaPlugin implements Listener, IPlotMain } // dropped item continue; - case PRIMED_TNT: - case FALLING_BLOCK: + case "PRIMED_TNT": + case "FALLING_BLOCK": // managed elsewhere continue; - case SHULKER: + case "SHULKER": if (Settings.Enabled_Components.KILL_ROAD_MOBS) { LivingEntity livingEntity = (LivingEntity) entity; List meta = entity.getMetadata("shulkerPlot"); @@ -542,71 +762,76 @@ public final class BukkitMain extends JavaPlugin implements Listener, IPlotMain } } continue; - case LLAMA: - case DONKEY: - case MULE: - case ZOMBIE_HORSE: - case SKELETON_HORSE: - case HUSK: - case ELDER_GUARDIAN: - case WITHER_SKELETON: - case STRAY: - case ZOMBIE_VILLAGER: - case EVOKER: - case EVOKER_FANGS: - case VEX: - case VINDICATOR: - case POLAR_BEAR: - case BAT: - case BLAZE: - case CAVE_SPIDER: - case CHICKEN: - case COW: - case CREEPER: - case ENDERMAN: - case ENDERMITE: - case ENDER_DRAGON: - case GHAST: - case GIANT: - case GUARDIAN: - case HORSE: - case IRON_GOLEM: - case MAGMA_CUBE: - case MUSHROOM_COW: - case OCELOT: - case PIG: - case PIG_ZOMBIE: - case RABBIT: - case SHEEP: - case SILVERFISH: - case SKELETON: - case SLIME: - case SNOWMAN: - case SPIDER: - case SQUID: - case VILLAGER: - case WITCH: - case WITHER: - case WOLF: - case ZOMBIE: - case PARROT: - case SALMON: - case DOLPHIN: - case TROPICAL_FISH: - case DROWNED: - case COD: - case TURTLE: - case PUFFERFISH: - case PHANTOM: - case ILLUSIONER: - case CAT: - case PANDA: - case FOX: - case PILLAGER: - case TRADER_LLAMA: - case WANDERING_TRADER: - case RAVAGER: - //case BEE: + case "ZOMBIFIED_PIGLIN": + case "LLAMA": + case "DONKEY": + case "MULE": + case "ZOMBIE_HORSE": + case "SKELETON_HORSE": + case "HUSK": + case "ELDER_GUARDIAN": + case "WITHER_SKELETON": + case "STRAY": + case "ZOMBIE_VILLAGER": + case "EVOKER": + case "EVOKER_FANGS": + case "VEX": + case "VINDICATOR": + case "POLAR_BEAR": + case "BAT": + case "BLAZE": + case "CAVE_SPIDER": + case "CHICKEN": + case "COW": + case "CREEPER": + case "ENDERMAN": + case "ENDERMITE": + case "ENDER_DRAGON": + case "GHAST": + case "GIANT": + case "GUARDIAN": + case "HORSE": + case "IRON_GOLEM": + case "MAGMA_CUBE": + case "MUSHROOM_COW": + case "OCELOT": + case "PIG": + case "PIG_ZOMBIE": + case "RABBIT": + case "SHEEP": + case "SILVERFISH": + case "SKELETON": + case "SLIME": + case "SNOWMAN": + case "SPIDER": + case "SQUID": + case "VILLAGER": + case "WITCH": + case "WITHER": + case "WOLF": + case "ZOMBIE": + case "PARROT": + case "SALMON": + case "DOLPHIN": + case "TROPICAL_FISH": + case "DROWNED": + case "COD": + case "TURTLE": + case "PUFFERFISH": + case "PHANTOM": + case "ILLUSIONER": + case "CAT": + case "PANDA": + case "FOX": + case "PILLAGER": + case "TRADER_LLAMA": + case "WANDERING_TRADER": + case "RAVAGER": + case "BEE": + case "HOGLIN": + case "PIGLIN": + case "ZOGLIN": + break; default: { if (Settings.Enabled_Components.KILL_ROAD_MOBS) { Location location = entity.getLocation(); @@ -687,8 +912,16 @@ public final class BukkitMain extends JavaPlugin implements Listener, IPlotMain } @Override public EconHandler getEconomyHandler() { + if (econ != null) { + if (econ.init() /* is inited */) { + return econ; + } else { + return null; + } + } + try { - BukkitEconHandler econ = new BukkitEconHandler(); + econ = new BukkitEconHandler(); if (econ.init()) { return econ; } @@ -698,6 +931,26 @@ public final class BukkitMain extends JavaPlugin implements Listener, IPlotMain return null; } + @Override public PermHandler getPermissionHandler() { + if (perm != null) { + if (perm.init() /* is inited */) { + return perm; + } else { + return null; + } + } + + try { + perm = new BukkitPermHandler(); + if (perm.init()) { + return perm; + } + } catch (Throwable ignored) { + PlotSquared.debug("No permissions detected!"); + } + return null; + } + @Override public QueueProvider initBlockQueue() { //TODO Figure out why this code is still here yet isn't being called anywhere. // try { @@ -715,8 +968,7 @@ public final class BukkitMain extends JavaPlugin implements Listener, IPlotMain return new BukkitUtil(); } - @Override @Nullable - public GeneratorWrapper getGenerator(@NonNull final String world, + @Override @Nullable public GeneratorWrapper getGenerator(@NonNull final String world, @Nullable final String name) { if (name == null) { return null; @@ -767,7 +1019,9 @@ public final class BukkitMain extends JavaPlugin implements Listener, IPlotMain metrics.addCustomChart(new Metrics.SimplePie("premium", () -> PremiumVerification.isPremium() ? "Premium" : "Non-Premium")); metrics.addCustomChart(new Metrics.SimplePie("worldedit_implementation", - () -> Bukkit.getPluginManager().getPlugin("FastAsyncWorldEdit") != null ? "FastAsyncWorldEdit" : "WorldEdit")); + () -> Bukkit.getPluginManager().getPlugin("FastAsyncWorldEdit") != null ? + "FastAsyncWorldEdit" : + "WorldEdit")); } @Override public ChunkManager initChunkManager() { @@ -779,7 +1033,7 @@ public final class BukkitMain extends JavaPlugin implements Listener, IPlotMain } @Override public void unregister(@NonNull final PlotPlayer player) { - BukkitUtil.removePlayer(player.getName()); + BukkitUtil.removePlayer(player.getUUID()); } @Override public void registerChunkProcessor() { @@ -798,39 +1052,6 @@ public final class BukkitMain extends JavaPlugin implements Listener, IPlotMain return new BukkitInventoryUtil(); } - @Override public UUIDHandlerImplementation initUUIDHandler() { - final UUIDWrapper wrapper; - if (Settings.UUID.OFFLINE) { - if (Settings.UUID.FORCE_LOWERCASE) { - wrapper = new LowerOfflineUUIDWrapper(); - } else { - wrapper = new OfflineUUIDWrapper(); - } - Settings.UUID.OFFLINE = true; - } else { - wrapper = new DefaultUUIDWrapper(); - Settings.UUID.OFFLINE = false; - } - if (!Bukkit.getVersion().contains("git-Spigot")) { - if (wrapper instanceof DefaultUUIDWrapper - || wrapper.getClass() == OfflineUUIDWrapper.class && !Bukkit.getOnlineMode()) { - Settings.UUID.NATIVE_UUID_PROVIDER = true; - } - } - if (Settings.UUID.OFFLINE) { - PlotSquared.log(Captions.PREFIX + "&6" + getPluginName() - + " is using Offline Mode UUIDs either because of user preference, or because you are using an old version of " - + "Bukkit"); - } else { - PlotSquared.log(Captions.PREFIX + "&6" + getPluginName() + " is using online UUIDs"); - } - if (Settings.UUID.USE_SQLUUIDHANDLER) { - return new SQLUUIDHandler(wrapper); - } else { - return new FileUUIDHandler(wrapper); - } - } - @Override public void setGenerator(@NonNull final String worldName) { World world = BukkitUtil.getWorld(worldName); if (world == null) { @@ -838,14 +1059,13 @@ public final class BukkitMain extends JavaPlugin implements Listener, IPlotMain ConfigurationSection worldConfig = PlotSquared.get().worlds.getConfigurationSection("worlds." + worldName); String manager = worldConfig.getString("generator.plugin", getPluginName()); - SetupObject setup = new SetupObject(); - setup.plotManager = manager; - setup.setupGenerator = worldConfig.getString("generator.init", manager); - setup.type = MainUtil.getType(worldConfig); - setup.terrain = MainUtil.getTerrain(worldConfig); - setup.step = new ConfigurationNode[0]; - setup.world = worldName; - SetupUtils.manager.setupWorld(setup); + PlotAreaBuilder builder = new PlotAreaBuilder().plotManager(manager) + .generatorName(worldConfig.getString("generator.init", manager)) + .plotAreaType(MainUtil.getType(worldConfig)) + .terrainType(MainUtil.getTerrain(worldConfig)) + .settingsNodesWrapper(new SettingsNodesWrapper(new ConfigurationNode[0], null)) + .worldName(worldName); + SetupUtils.manager.setupWorld(builder); world = Bukkit.getWorld(worldName); } else { try { @@ -873,7 +1093,22 @@ public final class BukkitMain extends JavaPlugin implements Listener, IPlotMain return new BukkitSchematicHandler(); } - @Override @Nullable public PlotPlayer wrapPlayer(final Object player) { + /** + * Attempt to retrieve a {@link PlotPlayer} from a player identifier. + * This method accepts: + * - {@link Player} objects, + * - {@link OfflinePlayer} objects, + * - {@link String} usernames for online players, and + * - {@link UUID} UUIDs for online players + *

+ * In the case of offline players, a fake {@link Player} instance will be created. + * This is a rather expensive operation, and should be avoided if possible. + * + * @param player The player to convert to a PlotPlayer + * @return The plot player instance that corresponds to the identifier, or null + * if no such player object could be created + */ + @Override @Nullable public PlotPlayer wrapPlayer(final Object player) { if (player instanceof Player) { return BukkitUtil.getPlayer((Player) player); } @@ -881,10 +1116,12 @@ public final class BukkitMain extends JavaPlugin implements Listener, IPlotMain return BukkitUtil.getPlayer((OfflinePlayer) player); } if (player instanceof String) { - return UUIDHandler.getPlayer((String) player); + return (PlotPlayer) PlotSquared.imp().getPlayerManager() + .getPlayerIfExists((String) player); } if (player instanceof UUID) { - return UUIDHandler.getPlayer((UUID) player); + return (PlotPlayer) PlotSquared.imp().getPlayerManager() + .getPlayerIfExists((UUID) player); } return null; } @@ -902,8 +1139,7 @@ public final class BukkitMain extends JavaPlugin implements Listener, IPlotMain } } - @Override - public GeneratorWrapper wrapPlotGenerator(@Nullable final String world, + @Override public GeneratorWrapper wrapPlotGenerator(@Nullable final String world, @NonNull final IndependentPlotGenerator generator) { return new BukkitPlotGenerator(world, generator); } @@ -925,4 +1161,9 @@ public final class BukkitMain extends JavaPlugin implements Listener, IPlotMain return wePlugin.wrapCommandSender(console); } + @Override @NotNull + public PlayerManager, ? extends Player> getPlayerManager() { + return this.playerManager; + } + } diff --git a/Bukkit/src/main/java/com/plotsquared/bukkit/command/DebugUUID.java b/Bukkit/src/main/java/com/plotsquared/bukkit/command/DebugUUID.java deleted file mode 100644 index 79b411791..000000000 --- a/Bukkit/src/main/java/com/plotsquared/bukkit/command/DebugUUID.java +++ /dev/null @@ -1,323 +0,0 @@ -/* - * _____ _ _ _____ _ - * | __ \| | | | / ____| | | - * | |__) | | ___ | |_| (___ __ _ _ _ __ _ _ __ ___ __| | - * | ___/| |/ _ \| __|\___ \ / _` | | | |/ _` | '__/ _ \/ _` | - * | | | | (_) | |_ ____) | (_| | |_| | (_| | | | __/ (_| | - * |_| |_|\___/ \__|_____/ \__, |\__,_|\__,_|_| \___|\__,_| - * | | - * |_| - * PlotSquared plot management system for Minecraft - * Copyright (C) 2020 IntellectualSites - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package com.plotsquared.bukkit.command; - -import com.google.common.collect.Sets; -import com.plotsquared.bukkit.util.uuid.DatFileFilter; -import com.plotsquared.bukkit.util.uuid.DefaultUUIDWrapper; -import com.plotsquared.bukkit.util.uuid.LowerOfflineUUIDWrapper; -import com.plotsquared.bukkit.util.uuid.OfflineUUIDWrapper; -import com.plotsquared.core.PlotSquared; -import com.plotsquared.core.command.Argument; -import com.plotsquared.core.command.CommandCategory; -import com.plotsquared.core.command.CommandDeclaration; -import com.plotsquared.core.command.RequiredType; -import com.plotsquared.core.command.SubCommand; -import com.plotsquared.core.configuration.Captions; -import com.plotsquared.core.database.DBFunc; -import com.plotsquared.core.player.OfflinePlotPlayer; -import com.plotsquared.core.player.PlotPlayer; -import com.plotsquared.core.plot.Plot; -import com.plotsquared.core.util.MainUtil; -import com.plotsquared.core.util.StringMan; -import com.plotsquared.core.util.StringWrapper; -import com.plotsquared.core.util.WorldUtil; -import com.plotsquared.core.util.task.TaskManager; -import com.plotsquared.core.util.uuid.UUIDHandler; -import com.plotsquared.core.util.uuid.UUIDWrapper; - -import java.io.File; -import java.io.IOException; -import java.nio.charset.StandardCharsets; -import java.nio.file.Files; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map.Entry; -import java.util.UUID; - -@CommandDeclaration(command = "uuidconvert", - permission = "plots.admin", - description = "Debug UUID conversion", - usage = "/plot uuidconvert ", - requiredType = RequiredType.CONSOLE, - category = CommandCategory.DEBUG) -public class DebugUUID extends SubCommand { - - public DebugUUID() { - super(Argument.String); - } - - @Override public boolean onCommand(final PlotPlayer player, String[] args) { - final UUIDWrapper currentUUIDWrapper = UUIDHandler.getUUIDWrapper(); - final UUIDWrapper newWrapper; - - switch (args[0].toLowerCase()) { - case "lower": - newWrapper = new LowerOfflineUUIDWrapper(); - break; - case "offline": - newWrapper = new OfflineUUIDWrapper(); - break; - case "online": - newWrapper = new DefaultUUIDWrapper(); - break; - default: - try { - Class clazz = Class.forName(args[0]); - newWrapper = (UUIDWrapper) clazz.newInstance(); - } catch (ClassNotFoundException | IllegalAccessException | InstantiationException ignored) { - MainUtil.sendMessage(player, Captions.COMMAND_SYNTAX, - "/plot uuidconvert "); - return false; - } - } - - if (args.length != 2 || !"-o".equals(args[1])) { - MainUtil.sendMessage(player, Captions.COMMAND_SYNTAX, - "/plot uuidconvert " + args[0] + " -o"); - MainUtil.sendMessage(player, "&cBe aware of the following!"); - MainUtil.sendMessage(player, - "&8 - &cUse the database command or another method to backup your plots beforehand"); - MainUtil.sendMessage(player, - "&8 - &cIf the process is interrupted, all plots could be deleted"); - MainUtil.sendMessage(player, "&8 - &cIf an error occurs, all plots could be deleted"); - MainUtil.sendMessage(player, "&8 - &cPlot settings WILL be lost upon conversion"); - MainUtil - .sendMessage(player, "&cTO REITERATE: BACK UP YOUR DATABASE BEFORE USING THIS!!!"); - MainUtil.sendMessage(player, - "&7Retype the command with the override parameter when ready :)"); - return false; - } - - if (currentUUIDWrapper.getClass().getCanonicalName() - .equals(newWrapper.getClass().getCanonicalName())) { - MainUtil.sendMessage(player, "&cUUID mode already in use!"); - return false; - } - MainUtil.sendMessage(player, "&6Beginning UUID mode conversion"); - MainUtil.sendMessage(player, "&7 - Disconnecting players"); - for (Entry entry : UUIDHandler.getPlayers().entrySet()) { - entry.getValue() - .kick("UUID conversion has been initiated. You may reconnect when finished."); - } - - MainUtil.sendMessage(player, "&7 - Initializing map"); - - final HashMap uCMap = new HashMap<>(); - final HashMap uCReverse = new HashMap<>(); - - MainUtil.sendMessage(player, "&7 - Collecting playerdata"); - - HashSet worlds = Sets.newHashSet(WorldUtil.IMP.getMainWorld(), "world"); - HashSet uuids = new HashSet<>(); - HashSet names = new HashSet<>(); - for (String worldName : worlds) { - File playerDataFolder = new File(worldName + File.separator + "playerdata"); - String[] dat = playerDataFolder.list(new DatFileFilter()); - if (dat != null) { - for (String current : dat) { - String s = current.replaceAll(".dat$", ""); - try { - UUID uuid = UUID.fromString(s); - uuids.add(uuid); - } catch (Exception ignored) { - MainUtil.sendMessage(player, - Captions.PREFIX + "Invalid playerdata: " + current); - } - } - } - File playersFolder = new File(worldName + File.separator + "players"); - dat = playersFolder.list(new DatFileFilter()); - if (dat != null) { - for (String current : dat) { - names.add(current.replaceAll(".dat$", "")); - } - } - } - - MainUtil.sendMessage(player, "&7 - Populating map"); - UUID uuid2; - UUIDWrapper wrapper = new DefaultUUIDWrapper(); - for (UUID uuid : uuids) { - try { - OfflinePlotPlayer op = wrapper.getOfflinePlayer(uuid); - uuid = currentUUIDWrapper.getUUID(op); - uuid2 = newWrapper.getUUID(op); - if (!uuid.equals(uuid2) && !uCMap.containsKey(uuid) && !uCReverse - .containsKey(uuid2)) { - uCMap.put(uuid, uuid2); - uCReverse.put(uuid2, uuid); - } - } catch (Throwable ignored) { - MainUtil.sendMessage(player, - Captions.PREFIX + "&6Invalid playerdata: " + uuid.toString() + ".dat"); - } - } - for (String name : names) { - UUID uuid = currentUUIDWrapper.getUUID(name); - uuid2 = newWrapper.getUUID(name); - if (!uuid.equals(uuid2)) { - uCMap.put(uuid, uuid2); - uCReverse.put(uuid2, uuid); - } - } - if (uCMap.isEmpty()) { - MainUtil.sendMessage(player, "&c - Error! Attempting to repopulate"); - for (OfflinePlotPlayer op : currentUUIDWrapper.getOfflinePlayers()) { - if (op.getLastPlayed() != 0) { - // String name = op.getPluginName(); - // StringWrapper wrap = new StringWrapper(name); - UUID uuid = currentUUIDWrapper.getUUID(op); - uuid2 = newWrapper.getUUID(op); - if (!uuid.equals(uuid2)) { - uCMap.put(uuid, uuid2); - uCReverse.put(uuid2, uuid); - } - } - } - if (uCMap.isEmpty()) { - MainUtil.sendMessage(player, "&cError. Failed to collect UUIDs!"); - return false; - } else { - MainUtil.sendMessage(player, "&a - Successfully repopulated"); - } - } - - MainUtil.sendMessage(player, "&7 - Replacing cache"); - TaskManager.runTaskAsync(() -> { - for (Entry entry : uCMap.entrySet()) { - String name = UUIDHandler.getName(entry.getKey()); - if (name != null) { - UUIDHandler.add(new StringWrapper(name), entry.getValue()); - } - } - - MainUtil.sendMessage(player, "&7 - Scanning for applicable files (uuids.txt)"); - - File file = new File(PlotSquared.get().IMP.getDirectory(), "uuids.txt"); - if (file.exists()) { - try { - List lines = Files.readAllLines(file.toPath(), StandardCharsets.UTF_8); - for (String line : lines) { - try { - line = line.trim(); - if (line.isEmpty()) { - continue; - } - line = line.replaceAll("[\\|][0-9]+[\\|][0-9]+[\\|]", ""); - String[] split = line.split("\\|"); - String name = split[0]; - if (name.isEmpty() || name.length() > 16 || !StringMan - .isAlphanumericUnd(name)) { - continue; - } - UUID old = currentUUIDWrapper.getUUID(name); - if (old == null) { - continue; - } - UUID now = newWrapper.getUUID(name); - UUIDHandler.add(new StringWrapper(name), now); - uCMap.put(old, now); - uCReverse.put(now, old); - } catch (Exception e2) { - e2.printStackTrace(); - } - } - } catch (IOException e) { - e.printStackTrace(); - } - } - - MainUtil.sendMessage(player, "&7 - Replacing wrapper"); - UUIDHandler.setUUIDWrapper(newWrapper); - - MainUtil.sendMessage(player, "&7 - Updating plot objects"); - - for (Plot plot : PlotSquared.get().getPlots()) { - UUID value = uCMap.get(plot.getOwnerAbs()); - if (value != null) { - plot.setOwnerAbs(value); - } - plot.getTrusted().clear(); - plot.getMembers().clear(); - plot.getDenied().clear(); - } - - MainUtil.sendMessage(player, "&7 - Deleting database"); - boolean result = DBFunc.deleteTables(); - - MainUtil.sendMessage(player, "&7 - Creating tables"); - - try { - DBFunc.createTables(); - if (!result) { - MainUtil.sendMessage(player, "&cConversion failed! Attempting recovery"); - for (Plot plot : PlotSquared.get().getPlots()) { - UUID value = uCReverse.get(plot.getOwnerAbs()); - if (value != null) { - plot.setOwnerAbs(value); - } - } - DBFunc.createPlotsAndData(new ArrayList<>(PlotSquared.get().getPlots()), - () -> MainUtil.sendMessage(player, "&6Recovery was successful!")); - return; - } - } catch (Exception e) { - e.printStackTrace(); - return; - } - - if (newWrapper instanceof OfflineUUIDWrapper) { - PlotSquared.get().worlds.set("UUID.force-lowercase", false); - PlotSquared.get().worlds.set("UUID.offline", true); - } else if (newWrapper instanceof DefaultUUIDWrapper) { - PlotSquared.get().worlds.set("UUID.force-lowercase", false); - PlotSquared.get().worlds.set("UUID.offline", false); - } - try { - PlotSquared.get().worlds.save(PlotSquared.get().worldsFile); - } catch (IOException ignored) { - MainUtil.sendMessage(player, - "Could not save configuration. It will need to be manual set!"); - } - - MainUtil.sendMessage(player, "&7 - Populating tables"); - - TaskManager.runTaskAsync(() -> { - ArrayList plots = new ArrayList<>(PlotSquared.get().getPlots()); - DBFunc.createPlotsAndData(plots, - () -> MainUtil.sendMessage(player, "&aConversion complete!")); - }); - - MainUtil.sendMessage(player, "&aIt is now safe for players to join"); - MainUtil.sendMessage(player, - "&cConversion is still in progress, you will be notified when it is complete"); - }); - return true; - } -} diff --git a/Bukkit/src/main/java/com/plotsquared/bukkit/entity/ReplicatingEntityWrapper.java b/Bukkit/src/main/java/com/plotsquared/bukkit/entity/ReplicatingEntityWrapper.java index f0ef20fba..83740e9db 100644 --- a/Bukkit/src/main/java/com/plotsquared/bukkit/entity/ReplicatingEntityWrapper.java +++ b/Bukkit/src/main/java/com/plotsquared/bukkit/entity/ReplicatingEntityWrapper.java @@ -103,51 +103,51 @@ public final class ReplicatingEntityWrapper extends EntityWrapper { if (!entity.hasGravity()) { this.noGravity = true; } - switch (entity.getType()) { - case BOAT: + switch (entity.getType().toString()) { + case "BOAT": Boat boat = (Boat) entity; this.dataByte = getOrdinal(TreeSpecies.values(), boat.getWoodType()); return; - case ARROW: - case EGG: - case ENDER_CRYSTAL: - case ENDER_PEARL: - case ENDER_SIGNAL: - case EXPERIENCE_ORB: - case FALLING_BLOCK: - case FIREBALL: - case FIREWORK: - case FISHING_HOOK: - case LEASH_HITCH: - case LIGHTNING: - case MINECART: - case MINECART_COMMAND: - case MINECART_MOB_SPAWNER: - case MINECART_TNT: - case PLAYER: - case PRIMED_TNT: - case SLIME: - case SMALL_FIREBALL: - case SNOWBALL: - case MINECART_FURNACE: - case SPLASH_POTION: - case THROWN_EXP_BOTTLE: - case WITHER_SKULL: - case UNKNOWN: - case SPECTRAL_ARROW: - case SHULKER_BULLET: - case DRAGON_FIREBALL: - case AREA_EFFECT_CLOUD: - case TRIDENT: - case LLAMA_SPIT: + case "ARROW": + case "EGG": + case "ENDER_CRYSTAL": + case "ENDER_PEARL": + case "ENDER_SIGNAL": + case "EXPERIENCE_ORB": + case "FALLING_BLOCK": + case "FIREBALL": + case "FIREWORK": + case "FISHING_HOOK": + case "LEASH_HITCH": + case "LIGHTNING": + case "MINECART": + case "MINECART_COMMAND": + case "MINECART_MOB_SPAWNER": + case "MINECART_TNT": + case "PLAYER": + case "PRIMED_TNT": + case "SLIME": + case "SMALL_FIREBALL": + case "SNOWBALL": + case "MINECART_FURNACE": + case "SPLASH_POTION": + case "THROWN_EXP_BOTTLE": + case "WITHER_SKULL": + case "UNKNOWN": + case "SPECTRAL_ARROW": + case "SHULKER_BULLET": + case "DRAGON_FIREBALL": + case "AREA_EFFECT_CLOUD": + case "TRIDENT": + case "LLAMA_SPIT": // Do this stuff later return; // MISC // - case DROPPED_ITEM: + case "DROPPED_ITEM": Item item = (Item) entity; this.stack = item.getItemStack(); return; - case ITEM_FRAME: + case "ITEM_FRAME": this.x = Math.floor(this.x); this.y = Math.floor(this.y); this.z = Math.floor(this.z); @@ -155,7 +155,7 @@ public final class ReplicatingEntityWrapper extends EntityWrapper { this.dataByte = getOrdinal(Rotation.values(), itemFrame.getRotation()); this.stack = itemFrame.getItem().clone(); return; - case PAINTING: + case "PAINTING": this.x = Math.floor(this.x); this.y = Math.floor(this.y); this.z = Math.floor(this.z); @@ -170,18 +170,18 @@ public final class ReplicatingEntityWrapper extends EntityWrapper { return; // END MISC // // INVENTORY HOLDER // - case MINECART_CHEST: - case MINECART_HOPPER: + case "MINECART_CHEST": + case "MINECART_HOPPER": storeInventory((InventoryHolder) entity); return; // START LIVING ENTITY // // START AGEABLE // // START TAMEABLE // - case HORSE: - case DONKEY: - case LLAMA: - case MULE: - case SKELETON_HORSE: + case "HORSE": + case "DONKEY": + case "LLAMA": + case "MULE": + case "SKELETON_HORSE": AbstractHorse horse = (AbstractHorse) entity; this.horse = new HorseStats(); this.horse.jump = horse.getJumpStrength(); @@ -199,15 +199,15 @@ public final class ReplicatingEntityWrapper extends EntityWrapper { storeInventory(horse); return; // END INVENTORY HOLDER // - case WOLF: - case OCELOT: + case "WOLF": + case "OCELOT": storeTameable((Tameable) entity); storeAgeable((Ageable) entity); storeLiving((LivingEntity) entity); return; // END TAMEABLE // //todo fix sheep - case SHEEP: + case "SHEEP": Sheep sheep = (Sheep) entity; if (sheep.isSheared()) { this.dataByte = (byte) 1; @@ -218,23 +218,23 @@ public final class ReplicatingEntityWrapper extends EntityWrapper { storeAgeable(sheep); storeLiving(sheep); return; - case VILLAGER: - case CHICKEN: - case COW: - case MUSHROOM_COW: - case PIG: - case TURTLE: - case POLAR_BEAR: + case "VILLAGER": + case "CHICKEN": + case "COW": + case "MUSHROOM_COW": + case "PIG": + case "TURTLE": + case "POLAR_BEAR": storeAgeable((Ageable) entity); storeLiving((LivingEntity) entity); return; - case RABBIT: + case "RABBIT": this.dataByte = getOrdinal(Rabbit.Type.values(), ((Rabbit) entity).getRabbitType()); storeAgeable((Ageable) entity); storeLiving((LivingEntity) entity); return; // END AGEABLE // - case ARMOR_STAND: + case "ARMOR_STAND": ArmorStand stand = (ArmorStand) entity; this.inventory = new ItemStack[] {stand.getItemInHand().clone(), stand.getHelmet().clone(), @@ -286,42 +286,45 @@ public final class ReplicatingEntityWrapper extends EntityWrapper { this.stand.small = true; } return; - case ENDERMITE: + case "ENDERMITE": return; - case BAT: + case "BAT": if (((Bat) entity).isAwake()) { this.dataByte = (byte) 1; } else { this.dataByte = (byte) 0; } return; - case ENDER_DRAGON: + case "ENDER_DRAGON": EnderDragon entity1 = (EnderDragon) entity; this.dataByte = (byte) entity1.getPhase().ordinal(); return; - case SKELETON: - case WITHER_SKELETON: - case GUARDIAN: - case ELDER_GUARDIAN: - case GHAST: - case MAGMA_CUBE: - case SQUID: - case PIG_ZOMBIE: - case ZOMBIE: - case WITHER: - case WITCH: - case SPIDER: - case CAVE_SPIDER: - case SILVERFISH: - case GIANT: - case ENDERMAN: - case CREEPER: - case BLAZE: - case SHULKER: - case SNOWMAN: + case "SKELETON": + case "WITHER_SKELETON": + case "GUARDIAN": + case "ELDER_GUARDIAN": + case "GHAST": + case "MAGMA_CUBE": + case "SQUID": + case "PIG_ZOMBIE": + case "HOGLIN": + case "ZOMBIFIED_PIGLIN": + case "PIGLIN": + case "ZOMBIE": + case "WITHER": + case "WITCH": + case "SPIDER": + case "CAVE_SPIDER": + case "SILVERFISH": + case "GIANT": + case "ENDERMAN": + case "CREEPER": + case "BLAZE": + case "SHULKER": + case "SNOWMAN": storeLiving((LivingEntity) entity); return; - case IRON_GOLEM: + case "IRON_GOLEM": if (((IronGolem) entity).isPlayerCreated()) { this.dataByte = (byte) 1; } else { @@ -463,16 +466,16 @@ public final class ReplicatingEntityWrapper extends EntityWrapper { return null; } Entity entity; - switch (this.getType()) { - case DROPPED_ITEM: + switch (this.getType().toString()) { + case "DROPPED_ITEM": return world.dropItem(location, this.stack); - case PLAYER: - case LEASH_HITCH: + case "PLAYER": + case "LEASH_HITCH": return null; - case ITEM_FRAME: + case "ITEM_FRAME": entity = world.spawn(location, ItemFrame.class); break; - case PAINTING: + case "PAINTING": entity = world.spawn(location, Painting.class); break; default: @@ -504,73 +507,73 @@ public final class ReplicatingEntityWrapper extends EntityWrapper { if (this.noGravity) { entity.setGravity(false); } - switch (entity.getType()) { - case BOAT: + switch (entity.getType().toString()) { + case "BOAT": Boat boat = (Boat) entity; boat.setWoodType(TreeSpecies.values()[dataByte]); return entity; - case SLIME: + case "SLIME": ((Slime) entity).setSize(this.dataByte); return entity; - case ARROW: - case EGG: - case ENDER_CRYSTAL: - case ENDER_PEARL: - case ENDER_SIGNAL: - case DROPPED_ITEM: - case EXPERIENCE_ORB: - case FALLING_BLOCK: - case FIREBALL: - case FIREWORK: - case FISHING_HOOK: - case LEASH_HITCH: - case LIGHTNING: - case MINECART: - case MINECART_COMMAND: - case MINECART_MOB_SPAWNER: - case MINECART_TNT: - case PLAYER: - case PRIMED_TNT: - case SMALL_FIREBALL: - case SNOWBALL: - case SPLASH_POTION: - case THROWN_EXP_BOTTLE: - case SPECTRAL_ARROW: - case SHULKER_BULLET: - case AREA_EFFECT_CLOUD: - case DRAGON_FIREBALL: - case WITHER_SKULL: - case MINECART_FURNACE: - case LLAMA_SPIT: - case TRIDENT: - case UNKNOWN: + case "ARROW": + case "EGG": + case "ENDER_CRYSTAL": + case "ENDER_PEARL": + case "ENDER_SIGNAL": + case "DROPPED_ITEM": + case "EXPERIENCE_ORB": + case "FALLING_BLOCK": + case "FIREBALL": + case "FIREWORK": + case "FISHING_HOOK": + case "LEASH_HITCH": + case "LIGHTNING": + case "MINECART": + case "MINECART_COMMAND": + case "MINECART_MOB_SPAWNER": + case "MINECART_TNT": + case "PLAYER": + case "PRIMED_TNT": + case "SMALL_FIREBALL": + case "SNOWBALL": + case "SPLASH_POTION": + case "THROWN_EXP_BOTTLE": + case "SPECTRAL_ARROW": + case "SHULKER_BULLET": + case "AREA_EFFECT_CLOUD": + case "DRAGON_FIREBALL": + case "WITHER_SKULL": + case "MINECART_FURNACE": + case "LLAMA_SPIT": + case "TRIDENT": + case "UNKNOWN": // Do this stuff later return entity; // MISC // - case ITEM_FRAME: + case "ITEM_FRAME": ItemFrame itemframe = (ItemFrame) entity; itemframe.setRotation(Rotation.values()[this.dataByte]); itemframe.setItem(this.stack); return entity; - case PAINTING: + case "PAINTING": Painting painting = (Painting) entity; painting.setFacingDirection(BlockFace.values()[this.dataByte], true); painting.setArt(Art.getByName(this.dataString), true); return entity; // END MISC // // INVENTORY HOLDER // - case MINECART_CHEST: - case MINECART_HOPPER: + case "MINECART_CHEST": + case "MINECART_HOPPER": restoreInventory((InventoryHolder) entity); return entity; // START LIVING ENTITY // // START AGEABLE // // START TAMEABLE // - case HORSE: - case LLAMA: - case SKELETON_HORSE: - case DONKEY: - case MULE: + case "HORSE": + case "LLAMA": + case "SKELETON_HORSE": + case "DONKEY": + case "MULE": AbstractHorse horse = (AbstractHorse) entity; horse.setJumpStrength(this.horse.jump); if (horse instanceof ChestedHorse) { @@ -586,14 +589,14 @@ public final class ReplicatingEntityWrapper extends EntityWrapper { restoreInventory(horse); return entity; // END INVENTORY HOLDER // - case WOLF: - case OCELOT: + case "WOLF": + case "OCELOT": restoreTameable((Tameable) entity); restoreAgeable((Ageable) entity); restoreLiving((LivingEntity) entity); return entity; // END AGEABLE // - case SHEEP: + case "SHEEP": Sheep sheep = (Sheep) entity; if (this.dataByte == 1) { sheep.setSheared(true); @@ -604,25 +607,25 @@ public final class ReplicatingEntityWrapper extends EntityWrapper { restoreAgeable(sheep); restoreLiving(sheep); return sheep; - case VILLAGER: - case CHICKEN: - case COW: - case TURTLE: - case POLAR_BEAR: - case MUSHROOM_COW: - case PIG: + case "VILLAGER": + case "CHICKEN": + case "COW": + case "TURTLE": + case "POLAR_BEAR": + case "MUSHROOM_COW": + case "PIG": restoreAgeable((Ageable) entity); restoreLiving((LivingEntity) entity); return entity; // END AGEABLE // - case RABBIT: + case "RABBIT": if (this.dataByte != 0) { ((Rabbit) entity).setRabbitType(Rabbit.Type.values()[this.dataByte]); } restoreAgeable((Ageable) entity); restoreLiving((LivingEntity) entity); return entity; - case ARMOR_STAND: + case "ARMOR_STAND": // CHECK positions ArmorStand stand = (ArmorStand) entity; if (this.inventory[0] != null) { @@ -688,42 +691,45 @@ public final class ReplicatingEntityWrapper extends EntityWrapper { } restoreLiving(stand); return stand; - case BAT: + case "BAT": if (this.dataByte != 0) { ((Bat) entity).setAwake(true); } restoreLiving((LivingEntity) entity); return entity; - case ENDER_DRAGON: + case "ENDER_DRAGON": if (this.dataByte != 0) { ((EnderDragon) entity).setPhase(EnderDragon.Phase.values()[this.dataByte]); } restoreLiving((LivingEntity) entity); return entity; - case ENDERMITE: - case GHAST: - case MAGMA_CUBE: - case SQUID: - case PIG_ZOMBIE: - case ZOMBIE: - case WITHER: - case WITCH: - case SPIDER: - case CAVE_SPIDER: - case SILVERFISH: - case GIANT: - case ENDERMAN: - case CREEPER: - case BLAZE: - case SNOWMAN: - case SHULKER: - case GUARDIAN: - case ELDER_GUARDIAN: - case SKELETON: - case WITHER_SKELETON: + case "ENDERMITE": + case "GHAST": + case "MAGMA_CUBE": + case "SQUID": + case "PIG_ZOMBIE": + case "HOGLIN": + case "PIGLIN": + case "ZOMBIFIED_PIGLIN": + case "ZOMBIE": + case "WITHER": + case "WITCH": + case "SPIDER": + case "CAVE_SPIDER": + case "SILVERFISH": + case "GIANT": + case "ENDERMAN": + case "CREEPER": + case "BLAZE": + case "SNOWMAN": + case "SHULKER": + case "GUARDIAN": + case "ELDER_GUARDIAN": + case "SKELETON": + case "WITHER_SKELETON": restoreLiving((LivingEntity) entity); return entity; - case IRON_GOLEM: + case "IRON_GOLEM": if (this.dataByte != 0) { ((IronGolem) entity).setPlayerCreated(true); } diff --git a/Bukkit/src/main/java/com/plotsquared/bukkit/listener/EntitySpawnListener.java b/Bukkit/src/main/java/com/plotsquared/bukkit/listener/EntitySpawnListener.java index e094baf9c..0bf5e75e8 100644 --- a/Bukkit/src/main/java/com/plotsquared/bukkit/listener/EntitySpawnListener.java +++ b/Bukkit/src/main/java/com/plotsquared/bukkit/listener/EntitySpawnListener.java @@ -100,15 +100,15 @@ public class EntitySpawnListener implements Listener { if (!originWorld.equals(world)) { if (!ignoreTP) { if (!world.getName().equalsIgnoreCase(originWorld + "_the_end")) { + if (entity.getType() == EntityType.PLAYER) { + return; + } try { ignoreTP = true; PaperLib.teleportAsync(entity, origin); } finally { ignoreTP = false; } - if (entity.getType() == EntityType.PLAYER) { - return; - } if (entity.getLocation().getWorld().equals(world)) { entity.remove(); } diff --git a/Bukkit/src/main/java/com/plotsquared/bukkit/listener/PaperListener.java b/Bukkit/src/main/java/com/plotsquared/bukkit/listener/PaperListener.java index 6c7e4c9eb..a512189f7 100644 --- a/Bukkit/src/main/java/com/plotsquared/bukkit/listener/PaperListener.java +++ b/Bukkit/src/main/java/com/plotsquared/bukkit/listener/PaperListener.java @@ -31,8 +31,11 @@ import com.destroystokyo.paper.event.entity.PreCreatureSpawnEvent; import com.destroystokyo.paper.event.entity.PreSpawnerSpawnEvent; import com.destroystokyo.paper.event.entity.SlimePathfindEvent; import com.destroystokyo.paper.event.player.PlayerLaunchProjectileEvent; +import com.destroystokyo.paper.event.server.AsyncTabCompleteEvent; import com.plotsquared.bukkit.util.BukkitUtil; import com.plotsquared.core.PlotSquared; +import com.plotsquared.core.command.Command; +import com.plotsquared.core.command.MainCommand; import com.plotsquared.core.configuration.Captions; import com.plotsquared.core.configuration.Settings; import com.plotsquared.core.location.Location; @@ -56,6 +59,12 @@ import org.bukkit.event.block.BlockPlaceEvent; import org.bukkit.event.entity.CreatureSpawnEvent; import org.bukkit.projectiles.ProjectileSource; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Locale; +import java.util.regex.Pattern; + /** * Events specific to Paper. Some toit nups here */ @@ -270,7 +279,7 @@ public class PaperListener implements Listener { } final int tileEntityCount = event.getBlock().getChunk().getTileEntities(false).length; if (tileEntityCount >= Settings.Chunk_Processor.MAX_TILES) { - final PlotPlayer plotPlayer = BukkitUtil.getPlayer(event.getPlayer()); + final PlotPlayer plotPlayer = BukkitUtil.getPlayer(event.getPlayer()); Captions.TILE_ENTITY_CAP_REACHED.send(plotPlayer, Settings.Chunk_Processor.MAX_TILES); event.setCancelled(true); event.setBuild(false); @@ -299,11 +308,50 @@ public class PaperListener implements Listener { if (!PlotSquared.get().hasPlotArea(location.getWorld())) { return; } - PlotPlayer pp = BukkitUtil.getPlayer((Player) shooter); + PlotPlayer pp = BukkitUtil.getPlayer((Player) shooter); Plot plot = location.getOwnedPlot(); if (plot != null && !plot.isAdded(pp.getUUID())) { entity.remove(); event.setCancelled(true); } } + + @EventHandler public void onAsyncTabCompletion(final AsyncTabCompleteEvent event) { + if (!Settings.Paper_Components.ASYNC_TAB_COMPLETION) { + return; + } + String buffer = event.getBuffer(); + if (!(event.getSender() instanceof Player)) { + return; + } + if ((!event.isCommand() && !buffer.startsWith("/")) || buffer.indexOf(' ') == -1) { + return; + } + if (buffer.startsWith("/")) { + buffer = buffer.substring(1); + } + final String[] unprocessedArgs = buffer.split(Pattern.quote(" ")); + if (unprocessedArgs.length == 1) { + return; // We don't do anything in this case + } else if (!Settings.Enabled_Components.TAB_COMPLETED_ALIASES + .contains(unprocessedArgs[0].toLowerCase(Locale.ENGLISH))) { + return; + } + final String[] args = new String[unprocessedArgs.length - 1]; + System.arraycopy(unprocessedArgs, 1, args, 0, args.length); + try { + final PlotPlayer player = BukkitUtil.getPlayer((Player) event.getSender()); + final Collection objects = MainCommand.getInstance().tab(player, args, buffer.endsWith(" ")); + if (objects == null) { + return; + } + final List result = new ArrayList<>(); + for (final com.plotsquared.core.command.Command o : objects) { + result.add(o.toString()); + } + event.setCompletions(result); + event.setHandled(true); + } catch (final Exception ignored) {} + } + } diff --git a/Bukkit/src/main/java/com/plotsquared/bukkit/listener/PlayerEvents.java b/Bukkit/src/main/java/com/plotsquared/bukkit/listener/PlayerEvents.java index 421de869b..530b7a8ec 100644 --- a/Bukkit/src/main/java/com/plotsquared/bukkit/listener/PlayerEvents.java +++ b/Bukkit/src/main/java/com/plotsquared/bukkit/listener/PlayerEvents.java @@ -26,6 +26,7 @@ package com.plotsquared.bukkit.listener; import com.destroystokyo.paper.MaterialTags; +import com.google.common.base.Charsets; import com.plotsquared.bukkit.player.BukkitPlayer; import com.plotsquared.bukkit.util.BukkitUtil; import com.plotsquared.bukkit.util.UpdateUtility; @@ -104,10 +105,8 @@ import com.plotsquared.core.util.MathMan; import com.plotsquared.core.util.Permissions; import com.plotsquared.core.util.PremiumVerification; import com.plotsquared.core.util.RegExUtil; -import com.plotsquared.core.util.StringWrapper; import com.plotsquared.core.util.entity.EntityCategories; import com.plotsquared.core.util.task.TaskManager; -import com.plotsquared.core.util.uuid.UUIDHandler; import com.sk89q.worldedit.bukkit.BukkitAdapter; import com.sk89q.worldedit.world.block.BlockType; import io.papermc.lib.PaperLib; @@ -179,6 +178,7 @@ import org.bukkit.event.inventory.ClickType; import org.bukkit.event.inventory.InventoryClickEvent; import org.bukkit.event.inventory.InventoryCloseEvent; import org.bukkit.event.player.AsyncPlayerChatEvent; +import org.bukkit.event.player.AsyncPlayerPreLoginEvent; import org.bukkit.event.player.PlayerBucketEmptyEvent; import org.bukkit.event.player.PlayerBucketFillEvent; import org.bukkit.event.player.PlayerChangedWorldEvent; @@ -216,7 +216,6 @@ import java.util.ArrayList; import java.util.HashSet; import java.util.Iterator; import java.util.List; -import java.util.Map.Entry; import java.util.Objects; import java.util.Set; import java.util.UUID; @@ -254,8 +253,8 @@ public class PlayerEvents extends PlotListener implements Listener { int x = bloc.getBlockX(); int z = bloc.getBlockZ(); int distance = Bukkit.getViewDistance() * 16; - for (Entry entry : UUIDHandler.getPlayers().entrySet()) { - PlotPlayer player = entry.getValue(); + + for (final PlotPlayer player : PlotSquared.imp().getPlayerManager().getPlayers()) { Location location = player.getLocation(); if (location.getWorld().equals(world)) { if (16 * Math.abs(location.getX() - x) / 16 > distance @@ -315,7 +314,7 @@ public class PlayerEvents extends PlotListener implements Listener { Location location = BukkitUtil.getLocation(e.getEntity()); if (location.isPlotArea()) { if (e.getEntity() instanceof Player) { - PlotPlayer player = BukkitUtil.getPlayer((Player) e.getEntity()); + PlotPlayer player = BukkitUtil.getPlayer((Player) e.getEntity()); Plot plot = player.getCurrentPlot(); if (plot != null) { if (!plot.isAdded(player.getUUID())) { @@ -352,6 +351,7 @@ public class PlayerEvents extends PlotListener implements Listener { } if (!plot.getFlag(RedstoneFlag.class)) { event.setNewCurrent(0); + plot.debug("Redstone event was cancelled because redstone = false"); return; } if (Settings.Redstone.DISABLE_OFFLINE) { @@ -360,31 +360,35 @@ public class PlayerEvents extends PlotListener implements Listener { if (plot.isMerged()) { disable = true; for (UUID owner : plot.getOwners()) { - if (UUIDHandler.getPlayer(owner) != null) { + if (PlotSquared.imp().getPlayerManager().getPlayerIfExists(owner) != null) { disable = false; break; } } } else { - disable = UUIDHandler.getPlayer(plot.guessOwner()) == null; + disable = + PlotSquared.imp().getPlayerManager().getPlayerIfExists(plot.getOwnerAbs()) + == null; } } if (disable) { for (UUID trusted : plot.getTrusted()) { - if (UUIDHandler.getPlayer(trusted) != null) { + if (PlotSquared.imp().getPlayerManager().getPlayerIfExists(trusted) != null) { disable = false; break; } } if (disable) { event.setNewCurrent(0); + plot.debug( + "Redstone event was cancelled because no trusted player was in the plot"); return; } } } if (Settings.Redstone.DISABLE_UNOCCUPIED) { - for (Entry entry : UUIDHandler.getPlayers().entrySet()) { - if (plot.equals(entry.getValue().getCurrentPlot())) { + for (final PlotPlayer player : PlotSquared.imp().getPlayerManager().getPlayers()) { + if (plot.equals(player.getCurrentPlot())) { return; } } @@ -407,6 +411,7 @@ public class PlayerEvents extends PlotListener implements Listener { } if (!plot.getFlag(RedstoneFlag.class)) { event.setCancelled(true); + plot.debug("Prevented comparator update because redstone = false"); } return; } @@ -429,6 +434,7 @@ public class PlayerEvents extends PlotListener implements Listener { } if (plot.getFlag(DisablePhysicsFlag.class)) { event.setCancelled(true); + plot.debug("Prevented block physics because disable-physics = true"); } return; } @@ -466,6 +472,8 @@ public class PlayerEvents extends PlotListener implements Listener { Plot newPlot = area.getOwnedPlotAbs(location); if (!plot.equals(newPlot)) { event.setCancelled(true); + plot.debug( + "Prevented piston update because of invalid edge piston detection"); return; } } @@ -487,7 +495,7 @@ public class PlayerEvents extends PlotListener implements Listener { if (!PlotSquared.get().hasPlotArea(location.getWorld())) { return; } - PlotPlayer pp = BukkitUtil.getPlayer((Player) shooter); + PlotPlayer pp = BukkitUtil.getPlayer((Player) shooter); Plot plot = location.getOwnedPlot(); if (plot != null && !plot.isAdded(pp.getUUID())) { entity.remove(); @@ -508,7 +516,7 @@ public class PlayerEvents extends PlotListener implements Listener { Plot plot = area.getPlot(location); ProjectileSource shooter = entity.getShooter(); if (shooter instanceof Player) { - PlotPlayer pp = BukkitUtil.getPlayer((Player) shooter); + PlotPlayer pp = BukkitUtil.getPlayer((Player) shooter); if (plot == null) { if (!Permissions.hasPermission(pp, Captions.PERMISSION_PROJECTILE_UNOWNED)) { entity.remove(); @@ -550,7 +558,7 @@ public class PlayerEvents extends PlotListener implements Listener { return; } Player player = event.getPlayer(); - PlotPlayer plotPlayer = BukkitUtil.getPlayer(player); + PlotPlayer plotPlayer = BukkitUtil.getPlayer(player); Location location = plotPlayer.getLocation(); PlotArea area = location.getPlotArea(); if (area == null) { @@ -638,17 +646,28 @@ public class PlayerEvents extends PlotListener implements Listener { } } - @EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true) + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + public void onPreLoin(final AsyncPlayerPreLoginEvent event) { + final UUID uuid; + if (Settings.UUID.OFFLINE) { + if (Settings.UUID.FORCE_LOWERCASE) { + uuid = UUID.nameUUIDFromBytes( + ("OfflinePlayer:" + event.getName().toLowerCase()).getBytes(Charsets.UTF_8)); + } else { + uuid = UUID.nameUUIDFromBytes( + ("OfflinePlayer:" + event.getName()).getBytes(Charsets.UTF_8)); + } + } else { + uuid = event.getUniqueId(); + } + PlotSquared.get().getImpromptuUUIDPipeline().storeImmediately(event.getName(), uuid); + } + + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) public void onConnect(PlayerJoinEvent event) { final Player player = event.getPlayer(); - UUIDHandler.getPlayers().remove(player.getName()); - BukkitUtil.removePlayer(player.getName()); - final PlotPlayer pp = BukkitUtil.getPlayer(player); - // Now - String name = pp.getName(); - StringWrapper sw = new StringWrapper(name); - UUID uuid = pp.getUUID(); - UUIDHandler.add(sw, uuid); + BukkitUtil.removePlayer(player.getUniqueId()); + final PlotPlayer pp = BukkitUtil.getPlayer(player); Location location = pp.getLocation(); PlotArea area = location.getPlotArea(); @@ -687,14 +706,14 @@ public class PlayerEvents extends PlotListener implements Listener { @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) public void playerRespawn(PlayerRespawnEvent event) { Player player = event.getPlayer(); - PlotPlayer pp = BukkitUtil.getPlayer(player); + PlotPlayer pp = BukkitUtil.getPlayer(player); PlotSquared.get().getEventDispatcher().doRespawnTask(pp); } @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) public void onTeleport(PlayerTeleportEvent event) { Player player = event.getPlayer(); - PlotPlayer pp = BukkitUtil.getPlayer(player); + BukkitPlayer pp = BukkitUtil.getPlayer(player); Plot lastPlot = pp.getMeta(PlotPlayer.META_LAST_PLOT); org.bukkit.Location to = event.getTo(); //noinspection ConstantConditions @@ -804,7 +823,7 @@ public class PlayerEvents extends PlotListener implements Listener { int x2; if (MathMan.roundInt(from.getX()) != (x2 = MathMan.roundInt(to.getX()))) { Player player = event.getPlayer(); - PlotPlayer pp = BukkitUtil.getPlayer(player); + BukkitPlayer pp = BukkitUtil.getPlayer(player); // Cancel teleport TaskManager.TELEPORT_QUEUE.remove(pp.getName()); // Set last location @@ -864,7 +883,7 @@ public class PlayerEvents extends PlotListener implements Listener { int z2; if (MathMan.roundInt(from.getZ()) != (z2 = MathMan.roundInt(to.getZ()))) { Player player = event.getPlayer(); - PlotPlayer pp = BukkitUtil.getPlayer(player); + BukkitPlayer pp = BukkitUtil.getPlayer(player); // Cancel teleport TaskManager.TELEPORT_QUEUE.remove(pp.getName()); // Set last location @@ -928,7 +947,7 @@ public class PlayerEvents extends PlotListener implements Listener { return; } - PlotPlayer plotPlayer = BukkitUtil.getPlayer(event.getPlayer()); + BukkitPlayer plotPlayer = BukkitUtil.getPlayer(event.getPlayer()); Location location = plotPlayer.getLocation(); PlotArea area = location.getPlotArea(); if (area == null) { @@ -954,8 +973,7 @@ public class PlayerEvents extends PlotListener implements Listener { Set recipients = event.getRecipients(); recipients.clear(); Set spies = new HashSet<>(); - for (Entry entry : UUIDHandler.getPlayers().entrySet()) { - PlotPlayer pp = entry.getValue(); + for (final PlotPlayer pp : PlotSquared.imp().getPlayerManager().getPlayers()) { if (pp.getAttribute("chatspy")) { spies.add(((BukkitPlayer) pp).player); } else { @@ -979,9 +997,6 @@ public class PlayerEvents extends PlotListener implements Listener { .replace("%plot_id%", id.x + ";" + id.y).replace("%sender%", sender) .replace("%msg%", message); for (Player player : spies) { - if (player.equals(event.getPlayer())) { - continue; - } player.sendMessage(spyMessage); } } @@ -997,7 +1012,7 @@ public class PlayerEvents extends PlotListener implements Listener { } Plot plot = area.getPlot(location); if (plot != null) { - PlotPlayer plotPlayer = BukkitUtil.getPlayer(player); + BukkitPlayer plotPlayer = BukkitUtil.getPlayer(player); if (event.getBlock().getY() == 0) { if (!Permissions .hasPermission(plotPlayer, Captions.PERMISSION_ADMIN_DESTROY_GROUNDLEVEL)) { @@ -1046,7 +1061,7 @@ public class PlayerEvents extends PlotListener implements Listener { } return; } - PlotPlayer pp = BukkitUtil.getPlayer(player); + BukkitPlayer pp = BukkitUtil.getPlayer(player); if (Permissions.hasPermission(pp, Captions.PERMISSION_ADMIN_DESTROY_ROAD)) { return; } @@ -1106,6 +1121,8 @@ public class PlayerEvents extends PlotListener implements Listener { } } return; + } else { + plot.debug("Explosion was cancelled because explosion = false"); } } event.setCancelled(true); @@ -1114,7 +1131,7 @@ public class PlayerEvents extends PlotListener implements Listener { @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) public void onWorldChanged(PlayerChangedWorldEvent event) { Player player = event.getPlayer(); - PlotPlayer pp = BukkitUtil.getPlayer(player); + BukkitPlayer pp = BukkitUtil.getPlayer(player); // Delete last location Plot plot = (Plot) pp.deleteMeta(PlotPlayer.META_LAST_PLOT); pp.deleteMeta(PlotPlayer.META_LOCATION); @@ -1150,6 +1167,7 @@ public class PlayerEvents extends PlotListener implements Listener { if (area != null) { Plot plot = area.getOwnedPlot(location); if (plot != null && plot.getFlag(MobPlaceFlag.class)) { + plot.debug(e.getType() + " could not change block because mob-place = false"); return; } event.setCancelled(true); @@ -1177,16 +1195,18 @@ public class PlayerEvents extends PlotListener implements Listener { if (entity instanceof Player) { Player player = (Player) entity; if (!plot.hasOwner()) { - PlotPlayer plotPlayer = BukkitUtil.getPlayer(player); + BukkitPlayer plotPlayer = BukkitUtil.getPlayer(player); if (plot.getFlag(IceFormFlag.class)) { + plot.debug("Ice could not be formed because ice-form = false"); return; } event.setCancelled(true); return; } - PlotPlayer plotPlayer = BukkitUtil.getPlayer(player); + BukkitPlayer plotPlayer = BukkitUtil.getPlayer(player); if (!plot.isAdded(plotPlayer.getUUID())) { if (plot.getFlag(IceFormFlag.class)) { + plot.debug("Ice could not be formed because ice-form = false"); return; } event.setCancelled(true); @@ -1216,23 +1236,27 @@ public class PlayerEvents extends PlotListener implements Listener { return; } switch (event.getSource().getType()) { - case GRASS: + case GRASS_BLOCK: if (!plot.getFlag(GrassGrowFlag.class)) { + plot.debug("Grass could not grow because grass-grow = false"); event.setCancelled(true); } break; case MYCELIUM: if (!plot.getFlag(MycelGrowFlag.class)) { + plot.debug("Mycelium could not grow because mycel-grow = false"); event.setCancelled(true); } break; case VINE: if (!plot.getFlag(VineGrowFlag.class)) { + plot.debug("Vine could not grow because vine-grow = false"); event.setCancelled(true); } break; case KELP: if (!plot.getFlag(KelpGrowFlag.class)) { + plot.debug("Kelp could not grow because kelp-grow = false"); event.setCancelled(true); } break; @@ -1259,6 +1283,7 @@ public class PlayerEvents extends PlotListener implements Listener { case SNOW: case SNOW_BLOCK: if (!plot.getFlag(SnowFormFlag.class)) { + plot.debug("Snow could not form because snow-form = false"); event.setCancelled(true); } return; @@ -1266,6 +1291,7 @@ public class PlayerEvents extends PlotListener implements Listener { case FROSTED_ICE: case PACKED_ICE: if (!plot.getFlag(IceFormFlag.class)) { + plot.debug("Ice could not form because ice-form = false"); event.setCancelled(true); } } @@ -1297,7 +1323,7 @@ public class PlayerEvents extends PlotListener implements Listener { return; } if (!plot.hasOwner()) { - PlotPlayer plotPlayer = BukkitUtil.getPlayer(player); + BukkitPlayer plotPlayer = BukkitUtil.getPlayer(player); if (Permissions .hasPermission(plotPlayer, Captions.PERMISSION_ADMIN_DESTROY_UNOWNED)) { return; @@ -1305,7 +1331,7 @@ public class PlayerEvents extends PlotListener implements Listener { event.setCancelled(true); return; } - PlotPlayer plotPlayer = BukkitUtil.getPlayer(player); + BukkitPlayer plotPlayer = BukkitUtil.getPlayer(player); if (!plot.isAdded(plotPlayer.getUUID())) { List destroy = plot.getFlag(BreakFlag.class); Block block = event.getBlock(); @@ -1315,12 +1341,14 @@ public class PlayerEvents extends PlotListener implements Listener { .hasPermission(plotPlayer, Captions.PERMISSION_ADMIN_DESTROY_OTHER)) { return; } + plot.debug(player.getName() + " could not break " + block.getType() + + " because it was not in the break flag"); event.setCancelled(true); return; } return; } - PlotPlayer plotPlayer = BukkitUtil.getPlayer(player); + BukkitPlayer plotPlayer = BukkitUtil.getPlayer(player); if (Permissions.hasPermission(plotPlayer, Captions.PERMISSION_ADMIN_DESTROY_ROAD)) { return; } @@ -1343,16 +1371,19 @@ public class PlayerEvents extends PlotListener implements Listener { switch (block.getType()) { case ICE: if (!plot.getFlag(IceMeltFlag.class)) { + plot.debug("Ice could not melt because ice-melt = false"); event.setCancelled(true); } break; case SNOW: if (!plot.getFlag(SnowMeltFlag.class)) { + plot.debug("Snow could not melt because snow-melt = false"); event.setCancelled(true); } break; case FARMLAND: if (!plot.getFlag(SoilDryFlag.class)) { + plot.debug("Soil could not dry because soil-dry = false"); event.setCancelled(true); } break; @@ -1371,7 +1402,13 @@ public class PlayerEvents extends PlotListener implements Listener { case BUBBLE_CORAL_FAN: case FIRE_CORAL_FAN: case HORN_CORAL_FAN: + case BRAIN_CORAL_WALL_FAN: + case BUBBLE_CORAL_WALL_FAN: + case FIRE_CORAL_WALL_FAN: + case HORN_CORAL_WALL_FAN: + case TUBE_CORAL_WALL_FAN: if (!plot.getFlag(CoralDryFlag.class)) { + plot.debug("Coral could not dry because coral-dry = false"); event.setCancelled(true); } break; @@ -1390,6 +1427,7 @@ public class PlayerEvents extends PlotListener implements Listener { if (plot != null && plot.getFlag(LiquidFlowFlag.class) == LiquidFlowFlag.FlowStatus.DISABLED && event .getBlock().isLiquid()) { + plot.debug("Liquid could now flow because liquid-flow = disabled"); event.setCancelled(true); return; } @@ -1413,11 +1451,14 @@ public class PlayerEvents extends PlotListener implements Listener { return; } if (plot.getFlag(DisablePhysicsFlag.class)) { + plot.debug(event.getBlock().getType() + + " could not update because disable-physics = true"); event.setCancelled(true); return; } if (plot.getFlag(LiquidFlowFlag.class) == LiquidFlowFlag.FlowStatus.DISABLED && event .getBlock().isLiquid()) { + plot.debug("Liquid could not flow because liquid-flow = disabled"); event.setCancelled(true); } } else if (!area.contains(fLocation.getX(), fLocation.getZ()) || !Objects @@ -1671,7 +1712,7 @@ public class PlayerEvents extends PlotListener implements Listener { return; } Player player = (Player) clicker; - PlotPlayer pp = BukkitUtil.getPlayer(player); + BukkitPlayer pp = BukkitUtil.getPlayer(player); final PlotInventory inventory = PlotInventory.getOpenPlotInventory(pp); if (inventory != null && event.getRawSlot() == event.getSlot()) { if (!inventory.onClick(event.getSlot())) { @@ -1699,6 +1740,8 @@ public class PlayerEvents extends PlotListener implements Listener { final ItemStack newStack = new ItemStack(newItem.getType(), newItem.getAmount()); event.setCursor(newStack); + plot.debug(player.getName() + + " could not creative-copy an item because prevent-creative-copy = true"); } } else { PlotArea area = pp.getPlotAreaAbs(); @@ -1707,6 +1750,8 @@ public class PlayerEvents extends PlotListener implements Listener { final ItemStack newStack = new ItemStack(newItem.getType(), newItem.getAmount()); event.setCursor(newStack); + plot.debug(player.getName() + + " could not creative-copy an item because prevent-creative-copy = true"); } } return; @@ -1822,7 +1867,7 @@ public class PlayerEvents extends PlotListener implements Listener { } EntitySpawnListener.testNether(entity); Plot plot = location.getPlotAbs(); - PlotPlayer pp = BukkitUtil.getPlayer(e.getPlayer()); + BukkitPlayer pp = BukkitUtil.getPlayer(e.getPlayer()); if (plot == null) { if (!area.isRoadRespectingGlobalFlags() && !area.getFlag(MiscInteractFlag.class) && !Permissions.hasPermission(pp, "plots.admin.interact.road")) { @@ -1857,6 +1902,8 @@ public class PlayerEvents extends PlotListener implements Listener { MainUtil.sendMessage(pp, Captions.NO_PERMISSION_EVENT, "plots.admin.interact.other"); e.setCancelled(true); + plot.debug(pp.getName() + " could not interact with " + entity.getType() + + " bcause misc-interact = false"); } } } @@ -1884,6 +1931,9 @@ public class PlayerEvents extends PlotListener implements Listener { Plot plot = area.getOwnedPlot(location); if (plot == null || !plot.getFlag(ExplosionFlag.class)) { event.setCancelled(true); + if (plot != null) { + plot.debug("Explosion was cancelled because explosion = false"); + } } event.blockList().removeIf( blox -> !plot.equals(area.getOwnedPlot(BukkitUtil.getLocation(blox.getLocation())))); @@ -1893,7 +1943,7 @@ public class PlayerEvents extends PlotListener implements Listener { public void onCancelledInteract(PlayerInteractEvent event) { if (event.isCancelled() && event.getAction() == Action.RIGHT_CLICK_AIR) { Player player = event.getPlayer(); - PlotPlayer pp = BukkitUtil.getPlayer(player); + BukkitPlayer pp = BukkitUtil.getPlayer(player); PlotArea area = pp.getPlotAreaAbs(); if (area == null) { return; @@ -1930,7 +1980,7 @@ public class PlayerEvents extends PlotListener implements Listener { @EventHandler(priority = EventPriority.LOW, ignoreCancelled = true) public void onInteract(PlayerInteractEvent event) { Player player = event.getPlayer(); - PlotPlayer pp = BukkitUtil.getPlayer(player); + BukkitPlayer pp = BukkitUtil.getPlayer(player); PlotArea area = pp.getPlotAreaAbs(); if (area == null) { return; @@ -2149,6 +2199,7 @@ public class PlayerEvents extends PlotListener implements Listener { Plot plot = area.getOwnedPlotAbs(location); if (plot == null || plot.getFlag(DisablePhysicsFlag.class)) { event.setCancelled(true); + plot.debug("Falling block event was cancelled because disable-physics = true"); return; } if (event.getTo().hasGravity()) { @@ -2184,6 +2235,7 @@ public class PlayerEvents extends PlotListener implements Listener { Plot plot = location.getOwnedPlot(); if (plot == null || !plot.getFlag(BlockBurnFlag.class)) { + plot.debug("Block burning was cancelled because block-burn = false"); event.setCancelled(true); } @@ -2207,7 +2259,7 @@ public class PlayerEvents extends PlotListener implements Listener { Plot plot = area.getOwnedPlot(location1); if (player != null) { - PlotPlayer pp = BukkitUtil.getPlayer(player); + BukkitPlayer pp = BukkitUtil.getPlayer(player); if (plot == null) { if (!Permissions.hasPermission(pp, Captions.PERMISSION_ADMIN_BUILD_ROAD)) { MainUtil.sendMessage(pp, Captions.NO_PERMISSION_EVENT, @@ -2237,6 +2289,7 @@ public class PlayerEvents extends PlotListener implements Listener { if (ignitingEntity != null) { if (!plot.getFlag(BlockIgnitionFlag.class)) { event.setCancelled(true); + plot.debug("Block ignition was cancelled because block-ignition = false"); return; } if (igniteCause == BlockIgniteEvent.IgniteCause.FIREBALL) { @@ -2283,7 +2336,7 @@ public class PlayerEvents extends PlotListener implements Listener { if (area == null) { return; } - PlotPlayer pp = BukkitUtil.getPlayer(event.getPlayer()); + BukkitPlayer pp = BukkitUtil.getPlayer(event.getPlayer()); Plot plot = area.getPlot(location); if (plot == null) { if (Permissions.hasPermission(pp, Captions.PERMISSION_ADMIN_BUILD_ROAD)) { @@ -2334,7 +2387,7 @@ public class PlayerEvents extends PlotListener implements Listener { @EventHandler(priority = EventPriority.MONITOR) public void onLeave(PlayerQuitEvent event) { TaskManager.TELEPORT_QUEUE.remove(event.getPlayer().getName()); - PlotPlayer pp = BukkitUtil.getPlayer(event.getPlayer()); + BukkitPlayer pp = BukkitUtil.getPlayer(event.getPlayer()); pp.unregister(); PlotListener.logout(pp.getUUID()); } @@ -2348,7 +2401,7 @@ public class PlayerEvents extends PlotListener implements Listener { return; } Player player = event.getPlayer(); - PlotPlayer plotPlayer = BukkitUtil.getPlayer(player); + BukkitPlayer plotPlayer = BukkitUtil.getPlayer(player); Plot plot = area.getPlot(location); if (plot == null) { if (Permissions.hasPermission(plotPlayer, Captions.PERMISSION_ADMIN_BUILD_ROAD)) { @@ -2421,7 +2474,7 @@ public class PlayerEvents extends PlotListener implements Listener { event.setCancelled(true); return; } - PlotPlayer pp = BukkitUtil.getPlayer(p); + BukkitPlayer pp = BukkitUtil.getPlayer(p); Plot plot = area.getPlot(location); if (plot == null) { if (!Permissions.hasPermission(pp, Captions.PERMISSION_ADMIN_BUILD_ROAD)) { @@ -2465,7 +2518,7 @@ public class PlayerEvents extends PlotListener implements Listener { if (area == null) { return; } - PlotPlayer pp = BukkitUtil.getPlayer(p); + BukkitPlayer pp = BukkitUtil.getPlayer(p); Plot plot = area.getPlot(location); if (plot == null) { if (!Permissions.hasPermission(pp, Captions.PERMISSION_ADMIN_DESTROY_ROAD)) { @@ -2487,6 +2540,8 @@ public class PlayerEvents extends PlotListener implements Listener { MainUtil.sendMessage(pp, Captions.NO_PERMISSION_EVENT, Captions.PERMISSION_ADMIN_DESTROY_OTHER); event.setCancelled(true); + plot.debug(p.getName() + + " could not break hanging entity because hanging-break = false"); } } } else if (remover instanceof Projectile) { @@ -2498,7 +2553,7 @@ public class PlayerEvents extends PlotListener implements Listener { if (area == null) { return; } - PlotPlayer player = BukkitUtil.getPlayer(shooter); + BukkitPlayer player = BukkitUtil.getPlayer(shooter); Plot plot = area.getPlot(BukkitUtil.getLocation(event.getEntity())); if (plot != null) { if (!plot.hasOwner()) { @@ -2515,6 +2570,8 @@ public class PlayerEvents extends PlotListener implements Listener { MainUtil.sendMessage(player, Captions.NO_PERMISSION_EVENT, Captions.PERMISSION_ADMIN_DESTROY_OTHER); event.setCancelled(true); + plot.debug(player.getName() + + " could not break hanging entity because hanging-break = false"); } } } @@ -2533,7 +2590,7 @@ public class PlayerEvents extends PlotListener implements Listener { return; } Player p = event.getPlayer(); - PlotPlayer pp = BukkitUtil.getPlayer(p); + BukkitPlayer pp = BukkitUtil.getPlayer(p); Plot plot = area.getPlot(location); if (plot == null && !area.isRoadRespectingGlobalFlags()) { if (!Permissions.hasPermission(pp, Captions.PERMISSION_ADMIN_INTERACT_ROAD)) { @@ -2616,7 +2673,7 @@ public class PlayerEvents extends PlotListener implements Listener { Entity attacker = event.getAttacker(); if (attacker instanceof Player) { Player p = (Player) attacker; - PlotPlayer pp = BukkitUtil.getPlayer(p); + BukkitPlayer pp = BukkitUtil.getPlayer(p); Plot plot = area.getPlot(location); if (plot == null) { if (!Permissions.hasPermission(pp, "plots.admin.vehicle.break.road")) { @@ -2642,6 +2699,8 @@ public class PlayerEvents extends PlotListener implements Listener { MainUtil.sendMessage(pp, Captions.NO_PERMISSION_EVENT, "plots.admin.vehicle.break.other"); event.setCancelled(true); + plot.debug(pp.getName() + + " could not break vehicle because vehicle-break = false"); } } } @@ -2805,7 +2864,7 @@ public class PlayerEvents extends PlotListener implements Listener { player = null; } if (player != null) { - PlotPlayer plotPlayer = BukkitUtil.getPlayer(player); + BukkitPlayer plotPlayer = BukkitUtil.getPlayer(player); final com.sk89q.worldedit.world.entity.EntityType entityType; @@ -2842,6 +2901,10 @@ public class PlayerEvents extends PlotListener implements Listener { if (!Permissions.hasPermission(plotPlayer, "plots.admin.destroy." + stub)) { MainUtil.sendMessage(plotPlayer, Captions.NO_PERMISSION_EVENT, "plots.admin.destroy." + stub); + if (plot != null) { + plot.debug(player.getName() + + " could not break armor stand because misc-break = false"); + } return false; } } else if (EntityCategories.HOSTILE.contains(entityType)) { @@ -2857,6 +2920,10 @@ public class PlayerEvents extends PlotListener implements Listener { if (!Permissions.hasPermission(plotPlayer, "plots.admin.pve." + stub)) { MainUtil.sendMessage(plotPlayer, Captions.NO_PERMISSION_EVENT, "plots.admin.pve." + stub); + if (plot != null) { + plot.debug(player.getName() + " could not attack " + entityType + + " because pve = false OR hostile-attack = false"); + } return false; } } else if (EntityCategories.TAMEABLE.contains(entityType)) { // victim is tameable @@ -2872,6 +2939,10 @@ public class PlayerEvents extends PlotListener implements Listener { if (!Permissions.hasPermission(plotPlayer, "plots.admin.pve." + stub)) { MainUtil.sendMessage(plotPlayer, Captions.NO_PERMISSION_EVENT, "plots.admin.pve." + stub); + if (plot != null) { + plot.debug(player.getName() + " could not attack " + entityType + + " because pve = false OR tamned-attack = false"); + } return false; } } else if (EntityCategories.PLAYER.contains(entityType)) { @@ -2880,6 +2951,8 @@ public class PlayerEvents extends PlotListener implements Listener { .hasPermission(plotPlayer, "plots.admin.pvp." + stub)) { MainUtil.sendMessage(plotPlayer, Captions.NO_PERMISSION_EVENT, "plots.admin.pvp." + stub); + plot.debug(player.getName() + " could not attack " + entityType + + " because pve = false"); return false; } else { return true; @@ -2893,232 +2966,262 @@ public class PlayerEvents extends PlotListener implements Listener { return false; } } else if (EntityCategories.ANIMAL.contains(entityType)) { // victim is animal - if (isPlot) { +<<<<<<>>>>>>v5 return true; + } if (!Permissions.hasPermission(plotPlayer, "plots.admin.pve." + stub)) { + MainUtil.sendMessage(plotPlayer, Captions.NO_PERMISSION_EVENT, + "plots.admin.pve." + stub); + return false; + } + } else if (EntityCategories.VEHICLE + .contains(entityType)) { // Vehicles are managed in vehicle destroy event return true; - } - if (!Permissions.hasPermission(plotPlayer, "plots.admin.pve." + stub)) { - MainUtil.sendMessage(plotPlayer, Captions.NO_PERMISSION_EVENT, - "plots.admin.pve." + stub); - return false; - } - } else if (EntityCategories.VEHICLE - .contains(entityType)) { // Vehicles are managed in vehicle destroy event - return true; - } else { // victim is something else - if (isPlot) { - if (plot.getFlag(PveFlag.class) || plot.isAdded(plotPlayer.getUUID())) { + } else { // victim is something else + if (isPlot) { + if (plot.getFlag(PveFlag.class) || plot.isAdded(plotPlayer.getUUID())) { + return true; + } + } else if (roadFlags && area.getFlag(PveFlag.class)) { return true; } - } else if (roadFlags && area.getFlag(PveFlag.class)) { - return true; - } - if (!Permissions.hasPermission(plotPlayer, "plots.admin.pve." + stub)) { - MainUtil.sendMessage(plotPlayer, Captions.NO_PERMISSION_EVENT, - "plots.admin.pve." + stub); + if (!Permissions.hasPermission(plotPlayer, "plots.admin.pve." + stub)) { + MainUtil.sendMessage(plotPlayer, Captions.NO_PERMISSION_EVENT, + "plots.admin.pve." + stub); + if (plot != null) { + plot.debug(player.getName() + " could not attack " + entityType + + " because pve = false"); + } + return false; + } + } return true; + } else if (dplot != null && (!dplot.equals(vplot) || Objects + .equals(dplot.getOwnerAbs(), vplot.getOwnerAbs()))) { + return vplot != null && vplot.getFlag(PveFlag.class); + } + //disable the firework damage. too much of a headache to support at the moment. + if (vplot != null) { + if (EntityDamageEvent.DamageCause.ENTITY_EXPLOSION == cause + && damager.getType() == EntityType.FIREWORK) { return false; } } - return true; - } else if (dplot != null && (!dplot.equals(vplot) || Objects - .equals(dplot.guessOwner(), vplot.guessOwner()))) { - return vplot != null && vplot.getFlag(PveFlag.class); - } - //disable the firework damage. too much of a headache to support at the moment. - if (vplot != null) { - if (EntityDamageEvent.DamageCause.ENTITY_EXPLOSION == cause - && damager.getType() == EntityType.FIREWORK) { - return false; + if (vplot == null && roadFlags && area.getFlag(PveFlag.class)) { + return true; } + return ((vplot != null && vplot.getFlag(PveFlag.class)) || !(damager instanceof Arrow + && !(victim instanceof Creature))); } - if (vplot == null && roadFlags && area.getFlag(PveFlag.class)) { - return true; - } - return ((vplot != null && vplot.getFlag(PveFlag.class)) || !(damager instanceof Arrow - && !(victim instanceof Creature))); - } - @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) - public void onPlayerEggThrow(PlayerEggThrowEvent event) { - Location location = BukkitUtil.getLocation(event.getEgg().getLocation()); - PlotArea area = location.getPlotArea(); - if (area == null) { - return; - } - Player player = event.getPlayer(); - PlotPlayer plotPlayer = BukkitUtil.getPlayer(player); - Plot plot = area.getPlot(location); - if (plot == null) { - if (!Permissions.hasPermission(plotPlayer, "plots.admin.projectile.road")) { - MainUtil.sendMessage(plotPlayer, Captions.NO_PERMISSION_EVENT, - "plots.admin.projectile.road"); - event.setHatching(false); + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + public void onPlayerEggThrow (PlayerEggThrowEvent event){ + Location location = BukkitUtil.getLocation(event.getEgg().getLocation()); + PlotArea area = location.getPlotArea(); + if (area == null) { + return; } - } else if (!plot.hasOwner()) { - if (!Permissions.hasPermission(plotPlayer, "plots.admin.projectile.unowned")) { - MainUtil.sendMessage(plotPlayer, Captions.NO_PERMISSION_EVENT, - "plots.admin.projectile.unowned"); - event.setHatching(false); - } - } else if (!plot.isAdded(plotPlayer.getUUID())) { - if (!Permissions.hasPermission(plotPlayer, "plots.admin.projectile.other")) { - MainUtil.sendMessage(plotPlayer, Captions.NO_PERMISSION_EVENT, - "plots.admin.projectile.other"); - event.setHatching(false); - } - } - } - - @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) - public void blockCreate(BlockPlaceEvent event) { - Location location = BukkitUtil.getLocation(event.getBlock().getLocation()); - PlotArea area = location.getPlotArea(); - if (area == null) { - return; - } - Player player = event.getPlayer(); - PlotPlayer pp = BukkitUtil.getPlayer(player); - Plot plot = area.getPlot(location); - if (plot != null) { - if ((location.getY() > area.getMaxBuildHeight() || location.getY() < area - .getMinBuildHeight()) && !Permissions - .hasPermission(pp, Captions.PERMISSION_ADMIN_BUILD_HEIGHT_LIMIT)) { - event.setCancelled(true); - MainUtil.sendMessage(pp, Captions.HEIGHT_LIMIT.getTranslated() - .replace("{limit}", String.valueOf(area.getMaxBuildHeight()))); - } - if (!plot.hasOwner()) { - if (!Permissions.hasPermission(pp, Captions.PERMISSION_ADMIN_BUILD_UNOWNED)) { - MainUtil.sendMessage(pp, Captions.NO_PERMISSION_EVENT, - Captions.PERMISSION_ADMIN_BUILD_UNOWNED); - event.setCancelled(true); - return; + Player player = event.getPlayer(); + BukkitPlayer plotPlayer = BukkitUtil.getPlayer(player); + Plot plot = area.getPlot(location); + if (plot == null) { + if (!Permissions.hasPermission(plotPlayer, "plots.admin.projectile.road")) { + MainUtil.sendMessage(plotPlayer, Captions.NO_PERMISSION_EVENT, + "plots.admin.projectile.road"); + event.setHatching(false); } - } else if (!plot.isAdded(pp.getUUID())) { - List place = plot.getFlag(PlaceFlag.class); - if (place != null) { - Block block = event.getBlock(); - if (place.contains( - BlockTypeWrapper.get(BukkitAdapter.asBlockType(block.getType())))) { + } else if (!plot.hasOwner()) { + if (!Permissions.hasPermission(plotPlayer, "plots.admin.projectile.unowned")) { + MainUtil.sendMessage(plotPlayer, Captions.NO_PERMISSION_EVENT, + "plots.admin.projectile.unowned"); + event.setHatching(false); + } + } else if (!plot.isAdded(plotPlayer.getUUID())) { + if (!Permissions.hasPermission(plotPlayer, "plots.admin.projectile.other")) { + MainUtil.sendMessage(plotPlayer, Captions.NO_PERMISSION_EVENT, + "plots.admin.projectile.other"); + event.setHatching(false); + } + } + } + + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + public void blockCreate (BlockPlaceEvent event){ + Location location = BukkitUtil.getLocation(event.getBlock().getLocation()); + PlotArea area = location.getPlotArea(); + if (area == null) { + return; + } + Player player = event.getPlayer(); + BukkitPlayer pp = BukkitUtil.getPlayer(player); + Plot plot = area.getPlot(location); + if (plot != null) { + if ((location.getY() > area.getMaxBuildHeight() || location.getY() < area + .getMinBuildHeight()) && !Permissions + .hasPermission(pp, Captions.PERMISSION_ADMIN_BUILD_HEIGHT_LIMIT)) { + event.setCancelled(true); + MainUtil.sendMessage(pp, Captions.HEIGHT_LIMIT.getTranslated() + .replace("{limit}", String.valueOf(area.getMaxBuildHeight()))); + } + if (!plot.hasOwner()) { + if (!Permissions.hasPermission(pp, Captions.PERMISSION_ADMIN_BUILD_UNOWNED)) { + MainUtil.sendMessage(pp, Captions.NO_PERMISSION_EVENT, + Captions.PERMISSION_ADMIN_BUILD_UNOWNED); + event.setCancelled(true); + return; + } + } else if (!plot.isAdded(pp.getUUID())) { + List place = plot.getFlag(PlaceFlag.class); + if (place != null) { + Block block = event.getBlock(); + if (place.contains( + BlockTypeWrapper.get(BukkitAdapter.asBlockType(block.getType())))) { + return; + } + } + if (!Permissions.hasPermission(pp, Captions.PERMISSION_ADMIN_BUILD_OTHER)) { + MainUtil.sendMessage(pp, Captions.NO_PERMISSION_EVENT, + Captions.PERMISSION_ADMIN_BUILD_OTHER); + event.setCancelled(true); + plot.debug( + player.getName() + " could not place " + event.getBlock().getType() + + " because of the place flag"); + return; + } + } else if (Settings.Done.RESTRICT_BUILDING && DoneFlag.isDone(plot)) { + if (!Permissions.hasPermission(pp, Captions.PERMISSION_ADMIN_BUILD_OTHER)) { + MainUtil.sendMessage(pp, Captions.NO_PERMISSION_EVENT, + Captions.PERMISSION_ADMIN_BUILD_OTHER); + event.setCancelled(true); return; } } - if (!Permissions.hasPermission(pp, Captions.PERMISSION_ADMIN_BUILD_OTHER)) { - MainUtil.sendMessage(pp, Captions.NO_PERMISSION_EVENT, - Captions.PERMISSION_ADMIN_BUILD_OTHER); - event.setCancelled(true); - return; + if (plot.getFlag(DisablePhysicsFlag.class)) { + Block block = event.getBlockPlaced(); + if (block.getType().hasGravity()) { + sendBlockChange(block.getLocation(), block.getBlockData()); + plot.debug(event.getBlock().getType() + + " did not fall because of disable-physics = true"); + } } - } else if (Settings.Done.RESTRICT_BUILDING && DoneFlag.isDone(plot)) { - if (!Permissions.hasPermission(pp, Captions.PERMISSION_ADMIN_BUILD_OTHER)) { - MainUtil.sendMessage(pp, Captions.NO_PERMISSION_EVENT, - Captions.PERMISSION_ADMIN_BUILD_OTHER); - event.setCancelled(true); - return; - } - } - if (plot.getFlag(DisablePhysicsFlag.class)) { - Block block = event.getBlockPlaced(); - if (block.getType().hasGravity()) { - sendBlockChange(block.getLocation(), block.getBlockData()); - } - } - } else if (!Permissions.hasPermission(pp, Captions.PERMISSION_ADMIN_BUILD_ROAD)) { - MainUtil.sendMessage(pp, Captions.NO_PERMISSION_EVENT, - Captions.PERMISSION_ADMIN_BUILD_ROAD); - event.setCancelled(true); - } - } - - @EventHandler(priority = EventPriority.HIGH) public void onDamage(EntityDamageEvent event) { - if (event.getEntityType() != EntityType.PLAYER) { - return; - } - Location location = BukkitUtil.getLocation(event.getEntity()); - PlotArea area = location.getPlotArea(); - if (area == null) { - return; - } - Plot plot = location.getOwnedPlot(); - if (plot == null) { - if (area.isRoadRespectingGlobalFlags() && area.getFlag(InvincibleFlag.class)) { - event.setCancelled(true); - } - return; - } - if (plot.getFlag(InvincibleFlag.class)) { - event.setCancelled(true); - } - } - - @EventHandler public void onItemDrop(PlayerDropItemEvent event) { - Player player = event.getPlayer(); - PlotPlayer pp = BukkitUtil.getPlayer(player); - Location location = pp.getLocation(); - PlotArea area = location.getPlotArea(); - if (area == null) { - return; - } - Plot plot = location.getOwnedPlot(); - if (plot == null) { - if (area.isRoadRespectingGlobalFlags() && area.getFlag(ItemDropFlag.class)) { - event.setCancelled(true); - } - return; - } - UUID uuid = pp.getUUID(); - if (!plot.isAdded(uuid)) { - if (!plot.getFlag(ItemDropFlag.class)) { + } else if (!Permissions.hasPermission(pp, Captions.PERMISSION_ADMIN_BUILD_ROAD)) { + MainUtil.sendMessage(pp, Captions.NO_PERMISSION_EVENT, + Captions.PERMISSION_ADMIN_BUILD_ROAD); event.setCancelled(true); } } - } - @EventHandler public void onItemPickup(EntityPickupItemEvent event) { - LivingEntity ent = event.getEntity(); - if (ent instanceof Player) { - Player player = (Player) ent; - PlotPlayer pp = BukkitUtil.getPlayer(player); - Location location = pp.getLocation(); + @EventHandler(priority = EventPriority.HIGH) public void onDamage (EntityDamageEvent event){ + if (event.getEntityType() != EntityType.PLAYER) { + return; + } + Location location = BukkitUtil.getLocation(event.getEntity()); PlotArea area = location.getPlotArea(); if (area == null) { return; } Plot plot = location.getOwnedPlot(); if (plot == null) { - if (area.isRoadRespectingGlobalFlags() && area.getFlag(DropProtectionFlag.class)) { + if (area.isRoadRespectingGlobalFlags() && area.getFlag(InvincibleFlag.class)) { + event.setCancelled(true); + } + return; + } + if (plot.getFlag(InvincibleFlag.class)) { + plot.debug(event.getEntity().getName() + + " could not take damage because invincible = true"); + event.setCancelled(true); + } + } + + @EventHandler public void onItemDrop (PlayerDropItemEvent event){ + Player player = event.getPlayer(); +<<<<<<>>>>>>v5 if (plot == null) { + if (area.isRoadRespectingGlobalFlags() && area.getFlag(ItemDropFlag.class)) { event.setCancelled(true); } return; } UUID uuid = pp.getUUID(); - if (!plot.isAdded(uuid) && plot.getFlag(DropProtectionFlag.class)) { - event.setCancelled(true); + if (!plot.isAdded(uuid)) { + if (!plot.getFlag(ItemDropFlag.class)) { + plot.debug( + player.getName() + " could not drop item because of item-drop = false"); + event.setCancelled(true); + } } } - } - @EventHandler public void onDeath(final PlayerDeathEvent event) { - Location location = BukkitUtil.getLocation(event.getEntity()); - PlotArea area = location.getPlotArea(); - if (area == null) { - return; - } - Plot plot = location.getOwnedPlot(); - if (plot == null) { - if (area.isRoadRespectingGlobalFlags() && area.getFlag(KeepInventoryFlag.class)) { - event.setCancelled(true); + @EventHandler public void onItemPickup (EntityPickupItemEvent event){ + LivingEntity ent = event.getEntity(); + if (ent instanceof Player) { + Player player = (Player) ent; +<<<<<<>>>>>>v5 if (plot == null) { + if (area.isRoadRespectingGlobalFlags() && area + .getFlag(DropProtectionFlag.class)) { + event.setCancelled(true); + } + return; + } + UUID uuid = pp.getUUID(); + if (!plot.isAdded(uuid) && plot.getFlag(DropProtectionFlag.class)) { + plot.debug(player.getName() + + " could not pick up item because of drop-protection = true"); + event.setCancelled(true); + } } - return; } - if (plot.getFlag(KeepInventoryFlag.class)) { - event.setKeepInventory(true); - } - } -} + @EventHandler public void onDeath ( final PlayerDeathEvent event){ +<<<<<<>>>>>>v5 event.setKeepInventory(true); + } + } + + } diff --git a/Bukkit/src/main/java/com/plotsquared/bukkit/managers/BukkitWorldManager.java b/Bukkit/src/main/java/com/plotsquared/bukkit/managers/BukkitWorldManager.java index 482d02896..4646868a1 100644 --- a/Bukkit/src/main/java/com/plotsquared/bukkit/managers/BukkitWorldManager.java +++ b/Bukkit/src/main/java/com/plotsquared/bukkit/managers/BukkitWorldManager.java @@ -36,6 +36,9 @@ import org.jetbrains.annotations.Nullable; import java.io.File; import java.io.IOException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; /** * Default Bukkit world manager. It will handle world creation by @@ -76,4 +79,13 @@ public class BukkitWorldManager implements PlatformWorldManager { return "bukkit"; } + @Override public Collection getWorlds() { + final List worlds = Bukkit.getWorlds(); + final List worldNames = new ArrayList<>(); + for (final World world : worlds) { + worldNames.add(world.getName()); + } + return worldNames; + } + } diff --git a/Bukkit/src/main/java/com/plotsquared/bukkit/placeholder/Placeholders.java b/Bukkit/src/main/java/com/plotsquared/bukkit/placeholder/Placeholders.java index bf2a7a8b9..5457dbe0f 100644 --- a/Bukkit/src/main/java/com/plotsquared/bukkit/placeholder/Placeholders.java +++ b/Bukkit/src/main/java/com/plotsquared/bukkit/placeholder/Placeholders.java @@ -25,9 +25,12 @@ */ package com.plotsquared.bukkit.placeholder; +import com.plotsquared.core.PlotSquared; +import com.plotsquared.core.configuration.Settings; import com.plotsquared.core.player.PlotPlayer; import com.plotsquared.core.plot.Plot; -import com.plotsquared.core.util.uuid.UUIDHandler; +import com.plotsquared.core.plot.flag.GlobalFlagContainer; +import com.plotsquared.core.plot.flag.PlotFlag; import me.clip.placeholderapi.PlaceholderAPIPlugin; import me.clip.placeholderapi.expansion.PlaceholderExpansion; import org.bukkit.Bukkit; @@ -58,31 +61,31 @@ public class Placeholders extends PlaceholderExpansion { } @Override public String getVersion() { - return "2.4"; + return "2.5"; } @Override public String onPlaceholderRequest(Player p, String identifier) { - final PlotPlayer pl = PlotPlayer.get(p.getName()); + final PlotPlayer pl = PlotSquared.imp().getPlayerManager().getPlayerIfExists(p.getUniqueId()); if (pl == null) { return ""; } if (identifier.startsWith("has_plot_")) { - if (identifier.split("has_plot_").length != 2) + identifier = identifier.substring("has_plot_".length()); + if (identifier.isEmpty()) return ""; - identifier = identifier.split("has_plot_")[1]; return pl.getPlotCount(identifier) > 0 ? PlaceholderAPIPlugin.booleanTrue() : PlaceholderAPIPlugin.booleanFalse(); } if (identifier.startsWith("plot_count_")) { - if (identifier.split("plot_count_").length != 2) + identifier = identifier.substring("plot_count_".length()); + if (identifier.isEmpty()) return ""; - identifier = identifier.split("plot_count_")[1]; return String.valueOf(pl.getPlotCount(identifier)); } @@ -122,7 +125,9 @@ public class Placeholders extends PlaceholderExpansion { if (uid == null) { return ""; } - String name = UUIDHandler.getName(uid); + + String name = PlotSquared.get().getImpromptuUUIDPipeline() + .getSingle(uid, Settings.UUID.BLOCKING_TIMEOUT); if (name != null) { return name; @@ -178,6 +183,39 @@ public class Placeholders extends PlaceholderExpansion { default: break; } + if (identifier.startsWith("currentplot_localflag_")) { + return getFlagValue(plot, identifier.substring("currentplot_localflag_".length()), + false); + } + if (identifier.startsWith("currentplot_flag_")) { + return getFlagValue(plot, identifier.substring("currentplot_flag_".length()), true); + } return ""; } + + /** + * Return the flag value from its name on the current plot. + * If the flag doesn't exist it returns an empty string. + * If the flag exists but it is not set on current plot and the parameter inherit is set to true, + * it returns the default value. + * + * @param plot Current plot where the player is + * @param flagName Name of flag to get from current plot + * @param inherit Define if it returns only the flag set on currentplot or also inherited flag + * @return The value of flag serialized in string + */ + private String getFlagValue(final Plot plot, final String flagName, final boolean inherit) { + if (flagName.isEmpty()) + return ""; + final PlotFlag flag = GlobalFlagContainer.getInstance().getFlagFromString(flagName); + if (flag == null) + return ""; + + if (inherit) { + return plot.getFlag(flag).toString(); + } else { + final PlotFlag plotFlag = plot.getFlagContainer().queryLocal(flag.getClass()); + return (plotFlag != null) ? plotFlag.getValue().toString() : ""; + } + } } diff --git a/Bukkit/src/main/java/com/plotsquared/bukkit/player/BukkitPlayer.java b/Bukkit/src/main/java/com/plotsquared/bukkit/player/BukkitPlayer.java index 854cc6ec0..643039600 100644 --- a/Bukkit/src/main/java/com/plotsquared/bukkit/player/BukkitPlayer.java +++ b/Bukkit/src/main/java/com/plotsquared/bukkit/player/BukkitPlayer.java @@ -25,9 +25,11 @@ */ package com.plotsquared.bukkit.player; +import com.google.common.base.Charsets; import com.plotsquared.bukkit.util.BukkitUtil; import com.plotsquared.core.PlotSquared; import com.plotsquared.core.configuration.Captions; +import com.plotsquared.core.configuration.Settings; import com.plotsquared.core.events.TeleportCause; import com.plotsquared.core.location.Location; import com.plotsquared.core.player.PlotPlayer; @@ -35,7 +37,6 @@ import com.plotsquared.core.plot.PlotWeather; import com.plotsquared.core.util.EconHandler; import com.plotsquared.core.util.MathMan; import com.plotsquared.core.util.StringMan; -import com.plotsquared.core.util.uuid.UUIDHandler; import com.sk89q.worldedit.bukkit.BukkitAdapter; import com.sk89q.worldedit.extension.platform.Actor; import com.sk89q.worldedit.world.item.ItemType; @@ -62,12 +63,11 @@ import static com.sk89q.worldedit.world.gamemode.GameModes.CREATIVE; import static com.sk89q.worldedit.world.gamemode.GameModes.SPECTATOR; import static com.sk89q.worldedit.world.gamemode.GameModes.SURVIVAL; -public class BukkitPlayer extends PlotPlayer { +public class BukkitPlayer extends PlotPlayer { private static boolean CHECK_EFFECTIVE = true; public final Player player; private boolean offline; - private UUID uuid; private String name; /** @@ -77,30 +77,45 @@ public class BukkitPlayer extends PlotPlayer { * @param player Bukkit player instance */ public BukkitPlayer(@NotNull final Player player) { - this.player = player; - super.populatePersistentMetaMap(); + this(player, false); } public BukkitPlayer(@NotNull final Player player, final boolean offline) { + this(player, offline, true); + } + + public BukkitPlayer(@NotNull final Player player, final boolean offline, final boolean realPlayer) { this.player = player; this.offline = offline; - super.populatePersistentMetaMap(); + if (realPlayer) { + super.populatePersistentMetaMap(); + } } @Override public Actor toActor() { return BukkitAdapter.adapt(player); } + @Override public Player getPlatformPlayer() { + return this.player; + } + @NotNull @Override public Location getLocation() { final Location location = super.getLocation(); return location == null ? BukkitUtil.getLocation(this.player) : location; } @NotNull @Override public UUID getUUID() { - if (this.uuid == null) { - this.uuid = UUIDHandler.getUUID(this); + if (Settings.UUID.OFFLINE) { + if (Settings.UUID.FORCE_LOWERCASE) { + return UUID.nameUUIDFromBytes(("OfflinePlayer:" + + getName().toLowerCase()).getBytes(Charsets.UTF_8)); + } else { + return UUID.nameUUIDFromBytes(("OfflinePlayer:" + + getName()).getBytes(Charsets.UTF_8)); + } } - return this.uuid; + return player.getUniqueId(); } @Override public long getLastPlayed() { @@ -140,8 +155,8 @@ public class BukkitPlayer extends PlotPlayer { } @Override public boolean hasPermission(final String permission) { - if (this.offline && EconHandler.manager != null) { - return EconHandler.manager.hasPermission(getName(), permission); + if (this.offline && EconHandler.getEconHandler() != null) { + return EconHandler.getEconHandler().hasPermission(getName(), permission); } return this.player.hasPermission(permission); } diff --git a/Bukkit/src/main/java/com/plotsquared/bukkit/util/uuid/DefaultUUIDWrapper.java b/Bukkit/src/main/java/com/plotsquared/bukkit/player/BukkitPlayerManager.java similarity index 55% rename from Bukkit/src/main/java/com/plotsquared/bukkit/util/uuid/DefaultUUIDWrapper.java rename to Bukkit/src/main/java/com/plotsquared/bukkit/player/BukkitPlayerManager.java index a2898ee91..a15718a5f 100644 --- a/Bukkit/src/main/java/com/plotsquared/bukkit/util/uuid/DefaultUUIDWrapper.java +++ b/Bukkit/src/main/java/com/plotsquared/bukkit/player/BukkitPlayerManager.java @@ -23,44 +23,46 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ -package com.plotsquared.bukkit.util.uuid; +package com.plotsquared.bukkit.player; -import com.plotsquared.bukkit.player.BukkitOfflinePlayer; -import com.plotsquared.bukkit.player.BukkitPlayer; -import com.plotsquared.core.player.OfflinePlotPlayer; -import com.plotsquared.core.player.PlotPlayer; -import com.plotsquared.core.util.uuid.UUIDWrapper; +import com.plotsquared.core.util.PlayerManager; import org.bukkit.Bukkit; -import org.bukkit.OfflinePlayer; +import org.bukkit.entity.Player; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; -import java.util.Arrays; import java.util.UUID; -public class DefaultUUIDWrapper extends UUIDWrapper { +/** + * Player manager providing {@link BukkitPlayer Bukkit players} + */ +public class BukkitPlayerManager extends PlayerManager { - @NotNull @Override public UUID getUUID(PlotPlayer player) { - return ((BukkitPlayer) player).player.getUniqueId(); + @NotNull @Override public BukkitPlayer getPlayer(@NotNull final Player object) { + try { + return getPlayer(object.getUniqueId()); + } catch (final NoSuchPlayerException exception) { + return new BukkitPlayer(object, object.isOnline(), false); + } } - @Override public UUID getUUID(OfflinePlotPlayer player) { - return player.getUUID(); + @Override @NotNull public BukkitPlayer createPlayer(@NotNull final UUID uuid) { + final Player player = Bukkit.getPlayer(uuid); + if (player == null || !player.isOnline()) { + throw new NoSuchPlayerException(uuid); + } + return new BukkitPlayer(player); } - @Override public OfflinePlotPlayer getOfflinePlayer(UUID uuid) { + @Nullable @Override public BukkitOfflinePlayer getOfflinePlayer(@Nullable final UUID uuid) { + if (uuid == null) { + return null; + } return new BukkitOfflinePlayer(Bukkit.getOfflinePlayer(uuid)); } - @Override public UUID getUUID(String name) { - return Bukkit.getOfflinePlayer(name).getUniqueId(); + @NotNull @Override public BukkitOfflinePlayer getOfflinePlayer(@NotNull final String username) { + return new BukkitOfflinePlayer(Bukkit.getOfflinePlayer(username)); } - @Override public OfflinePlotPlayer[] getOfflinePlayers() { - OfflinePlayer[] ops = Bukkit.getOfflinePlayers(); - return Arrays.stream(ops).map(BukkitOfflinePlayer::new).toArray(BukkitOfflinePlayer[]::new); - } - - @Override public OfflinePlotPlayer getOfflinePlayer(String name) { - return new BukkitOfflinePlayer(Bukkit.getOfflinePlayer(name)); - } } diff --git a/Bukkit/src/main/java/com/plotsquared/bukkit/queue/BukkitLocalQueue.java b/Bukkit/src/main/java/com/plotsquared/bukkit/queue/BukkitLocalQueue.java index 3f93ebb63..c8d6d929f 100644 --- a/Bukkit/src/main/java/com/plotsquared/bukkit/queue/BukkitLocalQueue.java +++ b/Bukkit/src/main/java/com/plotsquared/bukkit/queue/BukkitLocalQueue.java @@ -31,6 +31,7 @@ import com.plotsquared.core.PlotSquared; import com.plotsquared.core.queue.BasicLocalBlockQueue; import com.plotsquared.core.util.BlockUtil; import com.plotsquared.core.util.MainUtil; +import com.plotsquared.core.util.task.TaskManager; import com.sk89q.jnbt.CompoundTag; import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.WorldEdit; @@ -50,7 +51,6 @@ import org.bukkit.block.Biome; import org.bukkit.block.Block; import org.bukkit.block.Container; import org.bukkit.block.data.BlockData; -import org.bukkit.inventory.BlockInventoryHolder; import java.util.concurrent.ExecutionException; import java.util.function.Consumer; @@ -117,9 +117,6 @@ public class BukkitLocalQueue extends BasicLocalBlockQueue { @Override public final void setComponents(LocalChunk lc) throws ExecutionException, InterruptedException { setBaseBlocks(lc); - if (setBiome() && lc.biomes != null) { - setBiomes(lc); - } } public void setBaseBlocks(LocalChunk localChunk) { @@ -165,6 +162,22 @@ public class BukkitLocalQueue extends BasicLocalBlockQueue { } } } + if (setBiome() && localChunk.biomes != null) { + for (int x = 0; x < localChunk.biomes.length; x++) { + BiomeType[] biomeZ = localChunk.biomes[x]; + if (biomeZ != null) { + for (int z = 0; z < biomeZ.length; z++) { + if (biomeZ[z] != null) { + BiomeType biomeType = biomeZ[z]; + + Biome biome = BukkitAdapter.adapt(biomeType); + worldObj.setBiome((chunk.getX() << 4) + x, (chunk.getZ() << 4) + z, + biome); + } + } + } + } + } }; if (isForceSync()) { chunkConsumer.accept(getChunk(worldObj, localChunk)); diff --git a/Bukkit/src/main/java/com/plotsquared/bukkit/util/BukkitEconHandler.java b/Bukkit/src/main/java/com/plotsquared/bukkit/util/BukkitEconHandler.java index 1efd7fea5..e71c48158 100644 --- a/Bukkit/src/main/java/com/plotsquared/bukkit/util/BukkitEconHandler.java +++ b/Bukkit/src/main/java/com/plotsquared/bukkit/util/BukkitEconHandler.java @@ -27,49 +27,39 @@ package com.plotsquared.bukkit.util; import com.plotsquared.bukkit.player.BukkitOfflinePlayer; import com.plotsquared.bukkit.player.BukkitPlayer; +import com.plotsquared.core.PlotSquared; import com.plotsquared.core.player.OfflinePlotPlayer; import com.plotsquared.core.player.PlotPlayer; import com.plotsquared.core.util.EconHandler; +import com.plotsquared.core.util.PermHandler; import net.milkbowl.vault.economy.Economy; -import net.milkbowl.vault.permission.Permission; import org.bukkit.Bukkit; import org.bukkit.plugin.RegisteredServiceProvider; public class BukkitEconHandler extends EconHandler { private Economy econ; - private Permission perms; + @Override public boolean init() { - if (this.econ == null || this.perms == null) { - setupPermissions(); + if (this.econ == null) { setupEconomy(); } - return this.econ != null && this.perms != null; + return this.econ != null; } - private boolean setupPermissions() { - RegisteredServiceProvider permissionProvider = - Bukkit.getServer().getServicesManager().getRegistration(Permission.class); - if (permissionProvider != null) { - this.perms = permissionProvider.getProvider(); - } - return this.perms != null; - } - - private boolean setupEconomy() { + private void setupEconomy() { if (Bukkit.getServer().getPluginManager().getPlugin("Vault") == null) { - return false; + return; } RegisteredServiceProvider economyProvider = Bukkit.getServer().getServicesManager().getRegistration(Economy.class); if (economyProvider != null) { this.econ = economyProvider.getProvider(); } - return this.econ != null; } - @Override public double getMoney(PlotPlayer player) { + @Override public double getMoney(PlotPlayer player) { double bal = super.getMoney(player); if (Double.isNaN(bal)) { return this.econ.getBalance(((BukkitPlayer) player).player); @@ -77,11 +67,11 @@ public class BukkitEconHandler extends EconHandler { return bal; } - @Override public void withdrawMoney(PlotPlayer player, double amount) { + @Override public void withdrawMoney(PlotPlayer player, double amount) { this.econ.withdrawPlayer(((BukkitPlayer) player).player, amount); } - @Override public void depositMoney(PlotPlayer player, double amount) { + @Override public void depositMoney(PlotPlayer player, double amount) { this.econ.depositPlayer(((BukkitPlayer) player).player, amount); } @@ -89,20 +79,19 @@ public class BukkitEconHandler extends EconHandler { this.econ.depositPlayer(((BukkitOfflinePlayer) player).player, amount); } - @Override public boolean hasPermission(String world, String player, String perm) { - return this.perms.playerHas(world, Bukkit.getOfflinePlayer(player), perm); - } - - @Override public double getBalance(PlotPlayer player) { - return this.econ.getBalance(player.getName()); - } - - public void setPermission(String world, String player, String perm, boolean value) { - if (value) { - this.perms.playerAdd(world, player, perm); + /** + * @deprecated Use {@link PermHandler#hasPermission(String, String, String)} instead + */ + @Deprecated @Override public boolean hasPermission(String world, String player, String perm) { + if (PlotSquared.imp().getPermissionHandler() != null) { + return PlotSquared.imp().getPermissionHandler().hasPermission(world, player, perm); } else { - this.perms.playerRemove(world, player, perm); + return false; } } + @Override public double getBalance(PlotPlayer player) { + return this.econ.getBalance(player.getName()); + } + } diff --git a/Bukkit/src/main/java/com/plotsquared/bukkit/util/BukkitPermHandler.java b/Bukkit/src/main/java/com/plotsquared/bukkit/util/BukkitPermHandler.java new file mode 100644 index 000000000..fee00a66d --- /dev/null +++ b/Bukkit/src/main/java/com/plotsquared/bukkit/util/BukkitPermHandler.java @@ -0,0 +1,59 @@ +/* + * _____ _ _ _____ _ + * | __ \| | | | / ____| | | + * | |__) | | ___ | |_| (___ __ _ _ _ __ _ _ __ ___ __| | + * | ___/| |/ _ \| __|\___ \ / _` | | | |/ _` | '__/ _ \/ _` | + * | | | | (_) | |_ ____) | (_| | |_| | (_| | | | __/ (_| | + * |_| |_|\___/ \__|_____/ \__, |\__,_|\__,_|_| \___|\__,_| + * | | + * |_| + * PlotSquared plot management system for Minecraft + * Copyright (C) 2020 IntellectualSites + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.plotsquared.bukkit.util; + +import com.plotsquared.core.util.PermHandler; +import net.milkbowl.vault.permission.Permission; +import org.bukkit.Bukkit; +import org.bukkit.plugin.RegisteredServiceProvider; + +public class BukkitPermHandler extends PermHandler { + + private Permission perms; + + @Override + public boolean init() { + if (this.perms == null) { + setupPermissions(); + } + return this.perms != null; + } + + private void setupPermissions() { + if (Bukkit.getServer().getPluginManager().getPlugin("Vault") == null) { + return; + } + RegisteredServiceProvider permissionProvider = + Bukkit.getServer().getServicesManager().getRegistration(Permission.class); + if (permissionProvider != null) { + this.perms = permissionProvider.getProvider(); + } + } + + @Override public boolean hasPermission(String world, String player, String perm) { + return this.perms.playerHas(world, Bukkit.getOfflinePlayer(player), perm); + } +} diff --git a/Bukkit/src/main/java/com/plotsquared/bukkit/util/BukkitRegionManager.java b/Bukkit/src/main/java/com/plotsquared/bukkit/util/BukkitRegionManager.java index 16c63d093..158f90928 100644 --- a/Bukkit/src/main/java/com/plotsquared/bukkit/util/BukkitRegionManager.java +++ b/Bukkit/src/main/java/com/plotsquared/bukkit/util/BukkitRegionManager.java @@ -348,7 +348,7 @@ public class BukkitRegionManager extends RegionManager { CuboidRegion currentPlotClear = RegionUtil .createRegion(pos1.getX(), pos2.getX(), pos1.getZ(), pos2.getZ()); map.saveEntitiesOut(chunkObj, currentPlotClear); - AugmentedUtils.bypass(ignoreAugment, () -> ChunkManager.manager + AugmentedUtils.bypass(ignoreAugment, () -> ChunkManager .setChunkInPlotArea(null, new RunnableVal() { @Override public void run(ScopedLocalBlockQueue value) { Location min = value.getMin(); diff --git a/Bukkit/src/main/java/com/plotsquared/bukkit/util/BukkitSetupUtils.java b/Bukkit/src/main/java/com/plotsquared/bukkit/util/BukkitSetupUtils.java index af529c251..53185b608 100644 --- a/Bukkit/src/main/java/com/plotsquared/bukkit/util/BukkitSetupUtils.java +++ b/Bukkit/src/main/java/com/plotsquared/bukkit/util/BukkitSetupUtils.java @@ -33,6 +33,7 @@ import com.plotsquared.core.generator.GeneratorWrapper; import com.plotsquared.core.plot.PlotArea; import com.plotsquared.core.plot.PlotAreaType; import com.plotsquared.core.plot.SetupObject; +import com.plotsquared.core.setup.PlotAreaBuilder; import com.plotsquared.core.util.SetupUtils; import io.papermc.lib.PaperLib; import org.bukkit.Bukkit; @@ -97,7 +98,7 @@ public class BukkitSetupUtils extends SetupUtils { Bukkit.unloadWorld(world, false); } - @Override public String setupWorld(SetupObject object) { + @Deprecated @Override public String setupWorld(SetupObject object) { SetupUtils.manager.updateGenerators(); ConfigurationNode[] steps = object.step == null ? new ConfigurationNode[0] : object.step; String world = object.world; @@ -209,6 +210,119 @@ public class BukkitSetupUtils extends SetupUtils { return object.world; } + @Override public String setupWorld(PlotAreaBuilder builder) { + SetupUtils.manager.updateGenerators(); + ConfigurationNode[] steps = builder.settingsNodesWrapper() == null ? + new ConfigurationNode[0] : builder.settingsNodesWrapper().getSettingsNodes(); + String world = builder.worldName(); + PlotAreaType type = builder.plotAreaType(); + String worldPath = "worlds." + builder.worldName(); + switch (type) { + case PARTIAL: { + if (builder.areaName() != null) { + if (!PlotSquared.get().worlds.contains(worldPath)) { + PlotSquared.get().worlds.createSection(worldPath); + } + ConfigurationSection worldSection = + PlotSquared.get().worlds.getConfigurationSection(worldPath); + String areaName = builder.areaName() + "-" + builder.minimumId() + "-" + builder.maximumId(); + String areaPath = "areas." + areaName; + if (!worldSection.contains(areaPath)) { + worldSection.createSection(areaPath); + } + ConfigurationSection areaSection = + worldSection.getConfigurationSection(areaPath); + HashMap options = new HashMap<>(); + for (ConfigurationNode step : steps) { + options.put(step.getConstant(), step.getValue()); + } + options.put("generator.type", builder.plotAreaType().toString()); + options.put("generator.terrain", builder.terrainType().toString()); + options.put("generator.plugin", builder.plotManager()); + if (builder.generatorName() != null && !builder.generatorName() + .equals(builder.plotManager())) { + options.put("generator.init", builder.generatorName()); + } + for (Entry entry : options.entrySet()) { + String key = entry.getKey(); + Object value = entry.getValue(); + if (worldSection.contains(key)) { + Object current = worldSection.get(key); + if (!Objects.equals(value, current)) { + areaSection.set(key, value); + } + } else { + worldSection.set(key, value); + } + } + } + GeneratorWrapper gen = SetupUtils.generators.get(builder.generatorName()); + if (gen != null && gen.isFull()) { + builder.generatorName(null); + } + break; + } + case AUGMENTED: { + if (!builder.plotManager().endsWith(":single")) { + if (!PlotSquared.get().worlds.contains(worldPath)) { + PlotSquared.get().worlds.createSection(worldPath); + } + if (steps.length != 0) { + ConfigurationSection worldSection = + PlotSquared.get().worlds.getConfigurationSection(worldPath); + for (ConfigurationNode step : steps) { + worldSection.set(step.getConstant(), step.getValue()); + } + } + PlotSquared.get().worlds + .set("worlds." + world + ".generator.type", builder.plotAreaType().toString()); + PlotSquared.get().worlds + .set("worlds." + world + ".generator.terrain", builder.terrainType().toString()); + PlotSquared.get().worlds + .set("worlds." + world + ".generator.plugin", builder.plotManager()); + if (builder.generatorName() != null && !builder.generatorName() + .equals(builder.plotManager())) { + PlotSquared.get().worlds + .set("worlds." + world + ".generator.init", builder.generatorName()); + } + } + GeneratorWrapper gen = SetupUtils.generators.get(builder.generatorName()); + if (gen != null && gen.isFull()) { + builder.generatorName(null); + } + break; + } + case NORMAL: { + if (steps.length != 0) { + if (!PlotSquared.get().worlds.contains(worldPath)) { + PlotSquared.get().worlds.createSection(worldPath); + } + ConfigurationSection worldSection = + PlotSquared.get().worlds.getConfigurationSection(worldPath); + for (ConfigurationNode step : steps) { + worldSection.set(step.getConstant(), step.getValue()); + } + } + break; + } + } + + try { + PlotSquared.get().worlds.save(PlotSquared.get().worldsFile); + } catch (IOException e) { + e.printStackTrace(); + } + + Objects.requireNonNull(PlotSquared.imp()).getWorldManager() + .handleWorldCreation(builder.worldName(), builder.generatorName()); + + if (Bukkit.getWorld(world) != null) { + return world; + } + + return builder.worldName(); + } + @Override public String getGenerator(PlotArea plotArea) { if (SetupUtils.generators.isEmpty()) { updateGenerators(); diff --git a/Bukkit/src/main/java/com/plotsquared/bukkit/util/BukkitUtil.java b/Bukkit/src/main/java/com/plotsquared/bukkit/util/BukkitUtil.java index 23fd8937b..5acdde298 100644 --- a/Bukkit/src/main/java/com/plotsquared/bukkit/util/BukkitUtil.java +++ b/Bukkit/src/main/java/com/plotsquared/bukkit/util/BukkitUtil.java @@ -27,6 +27,7 @@ package com.plotsquared.bukkit.util; import com.plotsquared.bukkit.BukkitMain; import com.plotsquared.bukkit.player.BukkitPlayer; +import com.plotsquared.bukkit.player.BukkitPlayerManager; import com.plotsquared.core.PlotSquared; import com.plotsquared.core.configuration.Captions; import com.plotsquared.core.location.Location; @@ -35,11 +36,11 @@ import com.plotsquared.core.plot.Plot; import com.plotsquared.core.util.BlockUtil; import com.plotsquared.core.util.MainUtil; import com.plotsquared.core.util.MathMan; +import com.plotsquared.core.util.PlayerManager; import com.plotsquared.core.util.StringComparison; import com.plotsquared.core.util.WorldUtil; import com.plotsquared.core.util.task.RunnableVal; import com.plotsquared.core.util.task.TaskManager; -import com.plotsquared.core.util.uuid.UUIDHandler; import com.sk89q.worldedit.bukkit.BukkitAdapter; import com.sk89q.worldedit.bukkit.BukkitWorld; import com.sk89q.worldedit.math.BlockVector2; @@ -113,14 +114,16 @@ public class BukkitUtil extends WorldUtil { private static World lastWorld = null; private static Player lastPlayer = null; - private static PlotPlayer lastPlotPlayer = null; + private static BukkitPlayer lastPlotPlayer = null; - public static void removePlayer(String player) { + public static void removePlayer(UUID uuid) { lastPlayer = null; lastPlotPlayer = null; + // Make sure that it's removed internally + PlotSquared.imp().getPlayerManager().removePlayer(uuid); } - public static PlotPlayer getPlayer(@NonNull final OfflinePlayer op) { + public static PlotPlayer getPlayer(@NonNull final OfflinePlayer op) { if (op.isOnline()) { return getPlayer(op.getPlayer()); } @@ -165,7 +168,7 @@ public class BukkitUtil extends WorldUtil { * @return a {@code PlotPlayer} * @see PlotPlayer#wrap(Object) */ - public static PlotPlayer wrapPlayer(OfflinePlayer player) { + public static PlotPlayer wrapPlayer(OfflinePlayer player) { return PlotPlayer.wrap(player); } @@ -177,7 +180,7 @@ public class BukkitUtil extends WorldUtil { * @return a {@code PlotPlayer} * @see PlotPlayer#wrap(Object) */ - public static PlotPlayer wrapPlayer(Player player) { + public static PlotPlayer wrapPlayer(Player player) { return PlotPlayer.wrap(player); } @@ -189,7 +192,7 @@ public class BukkitUtil extends WorldUtil { * @return a {@code PlotPlayer} * @see PlotPlayer#wrap(Object) */ - @Override public PlotPlayer wrapPlayer(UUID uuid) { + @Override public PlotPlayer wrapPlayer(UUID uuid) { return PlotPlayer.wrap(Bukkit.getOfflinePlayer(uuid)); } @@ -200,7 +203,7 @@ public class BukkitUtil extends WorldUtil { * @return the number of allowed plots */ public static int getAllowedPlots(Player player) { - PlotPlayer plotPlayer = PlotPlayer.wrap(player); + PlotPlayer plotPlayer = PlotPlayer.wrap(player); return plotPlayer.getAllowedPlots(); } @@ -226,7 +229,7 @@ public class BukkitUtil extends WorldUtil { if (world == null) { return new HashSet<>(); } - return PlotPlayer.wrap(player).getPlots(world); + return BukkitPlayer.wrap(player).getPlots(world); } /** @@ -264,19 +267,12 @@ public class BukkitUtil extends WorldUtil { MainUtil.sendMessage(BukkitUtil.getPlayer(player), caption); } - public static PlotPlayer getPlayer(@NonNull final Player player) { + public static BukkitPlayer getPlayer(@NonNull final Player player) { if (player == lastPlayer) { return lastPlotPlayer; } - final String name = player.getName(); - final PlotPlayer plotPlayer = UUIDHandler.getPlayer(name); - if (plotPlayer != null) { - return plotPlayer; - } - lastPlotPlayer = new BukkitPlayer(player); - UUIDHandler.getPlayers().put(name, lastPlotPlayer); - lastPlayer = player; - return lastPlotPlayer; + final PlayerManager playerManager = PlotSquared.imp().getPlayerManager(); + return ((BukkitPlayerManager) playerManager).getPlayer(player); } public static Location getLocation(@NonNull final org.bukkit.Location location) { diff --git a/Bukkit/src/main/java/com/plotsquared/bukkit/util/SendChunk.java b/Bukkit/src/main/java/com/plotsquared/bukkit/util/SendChunk.java deleted file mode 100644 index 7a920fc8b..000000000 --- a/Bukkit/src/main/java/com/plotsquared/bukkit/util/SendChunk.java +++ /dev/null @@ -1,167 +0,0 @@ -/* - * _____ _ _ _____ _ - * | __ \| | | | / ____| | | - * | |__) | | ___ | |_| (___ __ _ _ _ __ _ _ __ ___ __| | - * | ___/| |/ _ \| __|\___ \ / _` | | | |/ _` | '__/ _ \/ _` | - * | | | | (_) | |_ ____) | (_| | |_| | (_| | | | __/ (_| | - * |_| |_|\___/ \__|_____/ \__, |\__,_|\__,_|_| \___|\__,_| - * | | - * |_| - * PlotSquared plot management system for Minecraft - * Copyright (C) 2020 IntellectualSites - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package com.plotsquared.bukkit.util; - -import com.plotsquared.bukkit.player.BukkitPlayer; -import com.plotsquared.core.PlotSquared; -import com.plotsquared.core.location.Location; -import com.plotsquared.core.player.PlotPlayer; -import com.plotsquared.core.plot.Plot; -import com.plotsquared.core.util.ReflectionUtils.RefClass; -import com.plotsquared.core.util.ReflectionUtils.RefConstructor; -import com.plotsquared.core.util.ReflectionUtils.RefField; -import com.plotsquared.core.util.ReflectionUtils.RefMethod; -import com.plotsquared.core.util.task.TaskManager; -import com.plotsquared.core.util.uuid.UUIDHandler; -import com.sk89q.worldedit.math.BlockVector2; -import io.papermc.lib.PaperLib; -import org.bukkit.Bukkit; -import org.bukkit.Chunk; -import org.bukkit.World; -import org.bukkit.entity.Player; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map.Entry; - -import static com.plotsquared.core.util.ReflectionUtils.getRefClass; - -/** - * An utility that can be used to send chunks, rather than using bukkit code - * to do so (uses heavy NMS). - */ -public class SendChunk { - - private final RefMethod methodGetHandlePlayer; - private final RefMethod methodGetHandleChunk; - private final RefConstructor mapChunk; - private final RefField connection; - private final RefMethod send; - private final RefMethod methodInitLighting; - - /** - * Constructor. - */ - public SendChunk() throws ClassNotFoundException, NoSuchMethodException, NoSuchFieldException { - RefClass classCraftPlayer = getRefClass("{cb}.entity.CraftPlayer"); - this.methodGetHandlePlayer = classCraftPlayer.getMethod("getHandle"); - RefClass classCraftChunk = getRefClass("{cb}.CraftChunk"); - this.methodGetHandleChunk = classCraftChunk.getMethod("getHandle"); - RefClass classChunk = getRefClass("{nms}.Chunk"); - this.methodInitLighting = classChunk.getMethod("initLighting"); - RefClass classMapChunk = getRefClass("{nms}.PacketPlayOutMapChunk"); - this.mapChunk = classMapChunk.getConstructor(classChunk.getRealClass(), int.class); - RefClass classEntityPlayer = getRefClass("{nms}.EntityPlayer"); - this.connection = classEntityPlayer.getField("playerConnection"); - RefClass classPacket = getRefClass("{nms}.Packet"); - RefClass classConnection = getRefClass("{nms}.PlayerConnection"); - this.send = classConnection.getMethod("sendPacket", classPacket.getRealClass()); - } - - public void sendChunk(Collection input) { - HashSet chunks = new HashSet<>(input); - HashMap> map = new HashMap<>(); - int view = Bukkit.getServer().getViewDistance(); - for (Chunk chunk : chunks) { - String world = chunk.getWorld().getName(); - ArrayList list = map.computeIfAbsent(world, k -> new ArrayList<>()); - list.add(chunk); - Object c = this.methodGetHandleChunk.of(chunk).call(); - this.methodInitLighting.of(c).call(); - } - for (Entry entry : UUIDHandler.getPlayers().entrySet()) { - PlotPlayer pp = entry.getValue(); - Plot plot = pp.getCurrentPlot(); - Location location = null; - String world; - if (plot != null) { - world = plot.getWorldName(); - } else { - location = pp.getLocation(); - world = location.getWorld(); - } - ArrayList list = map.get(world); - if (list == null) { - continue; - } - if (location == null) { - location = pp.getLocation(); - } - int chunkX = location.getX() >> 4; - int chunkZ = location.getZ() >> 4; - Player player = ((BukkitPlayer) pp).player; - Object entity = this.methodGetHandlePlayer.of(player).call(); - - for (Chunk chunk : list) { - int dx = Math.abs(chunkX - chunk.getX()); - int dz = Math.abs(chunkZ - chunk.getZ()); - if ((dx > view) || (dz > view)) { - continue; - } - Object c = this.methodGetHandleChunk.of(chunk).call(); - chunks.remove(chunk); - Object con = this.connection.of(entity).get(); - Object packet = null; - try { - packet = this.mapChunk.create(c, 65535); - } catch (Exception ignored) { - } - if (packet == null) { - PlotSquared.debug("Error with PacketPlayOutMapChunk reflection."); - } - this.send.of(con).call(packet); - } - } - for (final Chunk chunk : chunks) { - TaskManager.runTask(() -> { - try { - chunk.unload(true); - } catch (Throwable ignored) { - String worldName = chunk.getWorld().getName(); - PlotSquared.debug( - "$4Could not save chunk: " + worldName + ';' + chunk.getX() + ";" + chunk - .getZ()); - PlotSquared.debug("$3 - $4File may be open in another process (e.g. MCEdit)"); - PlotSquared.debug("$3 - $4" + worldName + "/level.dat or " + worldName - + "/level_old.dat may be corrupt (try repairing or removing these)"); - } - }); - } - } - - public void sendChunk(String worldName, Collection chunkLocations) { - World myWorld = Bukkit.getWorld(worldName); - ArrayList chunks = new ArrayList<>(); - for (BlockVector2 loc : chunkLocations) { - if (myWorld.isChunkLoaded(loc.getX(), loc.getZ())) { - PaperLib.getChunkAtAsync(myWorld, loc.getX(), loc.getZ()).thenAccept(chunks::add); - } - } - sendChunk(chunks); - } -} diff --git a/Bukkit/src/main/java/com/plotsquared/bukkit/util/uuid/FileUUIDHandler.java b/Bukkit/src/main/java/com/plotsquared/bukkit/util/uuid/FileUUIDHandler.java deleted file mode 100644 index c5620ffa1..000000000 --- a/Bukkit/src/main/java/com/plotsquared/bukkit/util/uuid/FileUUIDHandler.java +++ /dev/null @@ -1,289 +0,0 @@ -/* - * _____ _ _ _____ _ - * | __ \| | | | / ____| | | - * | |__) | | ___ | |_| (___ __ _ _ _ __ _ _ __ ___ __| | - * | ___/| |/ _ \| __|\___ \ / _` | | | |/ _` | '__/ _ \/ _` | - * | | | | (_) | |_ ____) | (_| | |_| | (_| | | | __/ (_| | - * |_| |_|\___/ \__|_____/ \__, |\__,_|\__,_|_| \___|\__,_| - * | | - * |_| - * PlotSquared plot management system for Minecraft - * Copyright (C) 2020 IntellectualSites - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package com.plotsquared.bukkit.util.uuid; - -import com.google.common.collect.HashBiMap; -import com.google.common.collect.Sets; -import com.plotsquared.core.PlotSquared; -import com.plotsquared.core.configuration.Captions; -import com.plotsquared.core.configuration.Settings; -import com.plotsquared.core.player.OfflinePlotPlayer; -import com.plotsquared.core.plot.expiration.ExpireManager; -import com.plotsquared.core.util.StringMan; -import com.plotsquared.core.util.StringWrapper; -import com.plotsquared.core.util.task.RunnableVal; -import com.plotsquared.core.util.task.TaskManager; -import com.plotsquared.core.util.uuid.UUIDHandler; -import com.plotsquared.core.util.uuid.UUIDHandlerImplementation; -import com.plotsquared.core.util.uuid.UUIDWrapper; -import com.sk89q.jnbt.CompoundTag; -import com.sk89q.jnbt.NBTInputStream; -import com.sk89q.jnbt.Tag; -import org.bukkit.Bukkit; -import org.bukkit.World; - -import java.io.BufferedInputStream; -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.nio.charset.StandardCharsets; -import java.nio.file.Files; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.UUID; -import java.util.zip.GZIPInputStream; - -public class FileUUIDHandler extends UUIDHandlerImplementation { - - public FileUUIDHandler(UUIDWrapper wrapper) { - super(wrapper); - } - - @Override public boolean startCaching(Runnable whenDone) { - return super.startCaching(whenDone) && cache(whenDone); - } - - private Tag readTag(File file) throws IOException { - // Don't chain the creation of the GZIP stream and the NBT stream, because their - // constructors may throw an IOException. - try (BufferedInputStream inputStream = new BufferedInputStream(new FileInputStream(file)); - GZIPInputStream gzipInputStream = new GZIPInputStream(inputStream); - NBTInputStream nbtInputStream = new NBTInputStream(gzipInputStream)) { - return nbtInputStream.readNamedTag().getTag(); - } - } - - public boolean cache(final Runnable whenDone) { - final File container = Bukkit.getWorldContainer(); - List worlds = Bukkit.getWorlds(); - final String world; - if (worlds.isEmpty()) { - world = "world"; - } else { - world = worlds.get(0).getName(); - } - TaskManager.runTaskAsync(() -> { - PlotSquared.debug(Captions.PREFIX + "Starting player data caching for: " + world); - File uuidFile = new File(PlotSquared.get().IMP.getDirectory(), "uuids.txt"); - if (uuidFile.exists()) { - try { - List lines = - Files.readAllLines(uuidFile.toPath(), StandardCharsets.UTF_8); - for (String line : lines) { - try { - line = line.trim(); - if (line.isEmpty()) { - continue; - } - line = line.replaceAll("[\\|][0-9]+[\\|][0-9]+[\\|]", ""); - String[] split = line.split("\\|"); - String name = split[0]; - if (name.isEmpty() || (name.length() > 16) || !StringMan - .isAlphanumericUnd(name)) { - continue; - } - UUID uuid = FileUUIDHandler.this.uuidWrapper.getUUID(name); - if (uuid == null) { - continue; - } - UUIDHandler.add(new StringWrapper(name), uuid); - } catch (Exception e2) { - e2.printStackTrace(); - } - } - } catch (IOException e) { - e.printStackTrace(); - } - } - HashBiMap toAdd = HashBiMap.create(new HashMap<>()); - if (Settings.UUID.NATIVE_UUID_PROVIDER) { - HashSet all = UUIDHandler.getAllUUIDS(); - PlotSquared.debug("Fast mode UUID caching enabled!"); - File playerDataFolder = new File(container, world + File.separator + "playerdata"); - String[] dat = playerDataFolder.list(new DatFileFilter()); - boolean check = all.isEmpty(); - if (dat != null) { - for (String current : dat) { - String s = current.replaceAll(".dat$", ""); - try { - UUID uuid = UUID.fromString(s); - if (check || all.remove(uuid)) { - File file = new File(playerDataFolder, current); - CompoundTag compound = (CompoundTag) readTag(file); - if (!compound.containsKey("bukkit")) { - PlotSquared.debug("ERROR: Player data (" + uuid.toString() - + ".dat) does not contain the the key \"bukkit\""); - } else { - Map compoundMap = compound.getValue(); - CompoundTag bukkit = (CompoundTag) compoundMap.get("bukkit"); - Map bukkitMap = bukkit.getValue(); - String name = - (String) bukkitMap.get("lastKnownName").getValue(); - long last = (long) bukkitMap.get("lastPlayed").getValue(); - long first = (long) bukkitMap.get("firstPlayed").getValue(); - if (ExpireManager.IMP != null) { - ExpireManager.IMP.storeDate(uuid, last); - ExpireManager.IMP.storeAccountAge(uuid, last - first); - } - toAdd.put(new StringWrapper(name), uuid); - } - } - } catch (Exception e) { - e.printStackTrace(); - PlotSquared.debug(Captions.PREFIX + "Invalid playerdata: " + current); - } - } - } - add(toAdd); - if (all.isEmpty()) { - if (whenDone != null) { - whenDone.run(); - } - return; - } else { - PlotSquared.debug( - "Failed to cache: " + all.size() + " uuids - slowly processing all files"); - } - } - HashSet worlds1 = Sets.newHashSet(world, "world"); - HashSet uuids = new HashSet<>(); - HashSet names = new HashSet<>(); - File playerDataFolder = null; - for (String worldName : worlds1) { - // Getting UUIDs - playerDataFolder = new File(container, worldName + File.separator + "playerdata"); - String[] dat = playerDataFolder.list(new DatFileFilter()); - if ((dat != null) && (dat.length != 0)) { - for (String current : dat) { - String s = current.replaceAll(".dat$", ""); - try { - UUID uuid = UUID.fromString(s); - uuids.add(uuid); - } catch (Exception ignored) { - PlotSquared.debug(Captions.PREFIX + "Invalid PlayerData: " + current); - } - } - break; - } - // Getting names - File playersFolder = new File(worldName + File.separator + "players"); - dat = playersFolder.list(new DatFileFilter()); - if ((dat != null) && (dat.length != 0)) { - for (String current : dat) { - names.add(current.replaceAll(".dat$", "")); - } - break; - } - } - for (UUID uuid : uuids) { - try { - File file = - new File(playerDataFolder + File.separator + uuid.toString() + ".dat"); - if (!file.exists()) { - continue; - } - CompoundTag compound = (CompoundTag) readTag(file); - if (!compound.containsKey("bukkit")) { - PlotSquared.debug("ERROR: Player data (" + uuid.toString() - + ".dat) does not contain the the key \"bukkit\""); - } else { - Map compoundMap = compound.getValue(); - CompoundTag bukkit = (CompoundTag) compoundMap.get("bukkit"); - Map bukkitMap = bukkit.getValue(); - String name = (String) bukkitMap.get("lastKnownName").getValue(); - StringWrapper wrap = new StringWrapper(name); - if (!toAdd.containsKey(wrap)) { - long last = (long) bukkitMap.get("lastPlayed").getValue(); - long first = (long) bukkitMap.get("firstPlayed").getValue(); - if (Settings.UUID.OFFLINE) { - if (Settings.UUID.FORCE_LOWERCASE && !name.toLowerCase() - .equals(name)) { - uuid = FileUUIDHandler.this.uuidWrapper.getUUID(name); - } else { - long most = (long) compoundMap.get("UUIDMost").getValue(); - long least = (long) compoundMap.get("UUIDLeast").getValue(); - uuid = new UUID(most, least); - } - } - if (ExpireManager.IMP != null) { - ExpireManager.IMP.storeDate(uuid, last); - ExpireManager.IMP.storeAccountAge(uuid, last - first); - } - toAdd.put(wrap, uuid); - } - } - } catch (Exception ignored) { - PlotSquared.debug( - Captions.PREFIX + "&6Invalid PlayerData: " + uuid.toString() + ".dat"); - } - } - for (String name : names) { - UUID uuid = FileUUIDHandler.this.uuidWrapper.getUUID(name); - StringWrapper nameWrap = new StringWrapper(name); - toAdd.put(nameWrap, uuid); - } - - if (getUUIDMap().isEmpty()) { - for (OfflinePlotPlayer offlinePlotPlayer : FileUUIDHandler.this.uuidWrapper - .getOfflinePlayers()) { - long last = offlinePlotPlayer.getLastPlayed(); - if (last != 0) { - String name = offlinePlotPlayer.getName(); - StringWrapper wrap = new StringWrapper(name); - if (!toAdd.containsKey(wrap)) { - UUID uuid = FileUUIDHandler.this.uuidWrapper.getUUID(offlinePlotPlayer); - if (toAdd.containsValue(uuid)) { - StringWrapper duplicate = toAdd.inverse().get(uuid); - PlotSquared.debug( - "The UUID: " + uuid.toString() + " is already mapped to " - + duplicate - + "\n It cannot be added to the Map with a key of " + wrap); - } - toAdd.putIfAbsent(wrap, uuid); - if (ExpireManager.IMP != null) { - ExpireManager.IMP.storeDate(uuid, last); - } - } - } - } - } - add(toAdd); - if (whenDone != null) { - whenDone.run(); - } - }); - return true; - } - - @Override public void fetchUUID(final String name, final RunnableVal ifFetch) { - TaskManager.runTaskAsync(() -> { - ifFetch.value = FileUUIDHandler.this.uuidWrapper.getUUID(name); - TaskManager.runTask(ifFetch); - }); - } -} diff --git a/Bukkit/src/main/java/com/plotsquared/bukkit/util/uuid/OfflineUUIDWrapper.java b/Bukkit/src/main/java/com/plotsquared/bukkit/util/uuid/OfflineUUIDWrapper.java deleted file mode 100644 index 66ca52814..000000000 --- a/Bukkit/src/main/java/com/plotsquared/bukkit/util/uuid/OfflineUUIDWrapper.java +++ /dev/null @@ -1,131 +0,0 @@ -/* - * _____ _ _ _____ _ - * | __ \| | | | / ____| | | - * | |__) | | ___ | |_| (___ __ _ _ _ __ _ _ __ ___ __| | - * | ___/| |/ _ \| __|\___ \ / _` | | | |/ _` | '__/ _ \/ _` | - * | | | | (_) | |_ ____) | (_| | |_| | (_| | | | __/ (_| | - * |_| |_|\___/ \__|_____/ \__, |\__,_|\__,_|_| \___|\__,_| - * | | - * |_| - * PlotSquared plot management system for Minecraft - * Copyright (C) 2020 IntellectualSites - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package com.plotsquared.bukkit.util.uuid; - -import com.google.common.base.Charsets; -import com.google.common.collect.BiMap; -import com.plotsquared.bukkit.player.BukkitOfflinePlayer; -import com.plotsquared.core.PlotSquared; -import com.plotsquared.core.player.OfflinePlotPlayer; -import com.plotsquared.core.player.PlotPlayer; -import com.plotsquared.core.util.StringWrapper; -import com.plotsquared.core.util.uuid.UUIDHandler; -import com.plotsquared.core.util.uuid.UUIDWrapper; -import org.bukkit.Bukkit; -import org.bukkit.OfflinePlayer; -import org.bukkit.Server; -import org.bukkit.entity.Player; -import org.jetbrains.annotations.NotNull; - -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.util.Arrays; -import java.util.Collection; -import java.util.UUID; - -public class OfflineUUIDWrapper extends UUIDWrapper { - - private final Object[] arg = new Object[0]; - private Method getOnline = null; - - public OfflineUUIDWrapper() { - try { - this.getOnline = Server.class.getMethod("getOnlinePlayers"); - } catch (NoSuchMethodException | SecurityException e) { - e.printStackTrace(); - } - } - - @NotNull @Override public UUID getUUID(PlotPlayer player) { - return UUID - .nameUUIDFromBytes(("OfflinePlayer:" + player.getName()).getBytes(Charsets.UTF_8)); - } - - @Override public UUID getUUID(OfflinePlotPlayer player) { - return UUID - .nameUUIDFromBytes(("OfflinePlayer:" + player.getName()).getBytes(Charsets.UTF_8)); - } - - public UUID getUUID(OfflinePlayer player) { - return UUID - .nameUUIDFromBytes(("OfflinePlayer:" + player.getName()).getBytes(Charsets.UTF_8)); - } - - @Override public OfflinePlotPlayer getOfflinePlayer(UUID uuid) { - BiMap map = UUIDHandler.getUuidMap().inverse(); - String name = null; - if (map.containsKey(uuid)) { - name = map.get(uuid).value; - } - if (name != null) { - OfflinePlayer op = Bukkit.getOfflinePlayer(name); - if (op.hasPlayedBefore()) { - return new BukkitOfflinePlayer(op); - } - } - for (OfflinePlayer player : Bukkit.getOfflinePlayers()) { - if (getUUID(player).equals(uuid)) { - return new BukkitOfflinePlayer(player); - } - } - return null; - } - - public Player[] getOnlinePlayers() { - if (this.getOnline == null) { - Collection onlinePlayers = Bukkit.getOnlinePlayers(); - return onlinePlayers.toArray(new Player[0]); - } - try { - Object players = this.getOnline.invoke(Bukkit.getServer(), this.arg); - if (players instanceof Player[]) { - return (Player[]) players; - } else { - @SuppressWarnings("unchecked") Collection p = - (Collection) players; - return p.toArray(new Player[0]); - } - } catch (IllegalAccessException | InvocationTargetException | IllegalArgumentException ignored) { - PlotSquared.debug("Failed to resolve online players"); - this.getOnline = null; - Collection onlinePlayers = Bukkit.getOnlinePlayers(); - return onlinePlayers.toArray(new Player[0]); - } - } - - @Override public UUID getUUID(String name) { - return UUID.nameUUIDFromBytes(("OfflinePlayer:" + name).getBytes(Charsets.UTF_8)); - } - - @Override public OfflinePlotPlayer[] getOfflinePlayers() { - OfflinePlayer[] ops = Bukkit.getOfflinePlayers(); - return Arrays.stream(ops).map(BukkitOfflinePlayer::new).toArray(BukkitOfflinePlayer[]::new); - } - - @Override public OfflinePlotPlayer getOfflinePlayer(String name) { - return new BukkitOfflinePlayer(Bukkit.getOfflinePlayer(name)); - } -} diff --git a/Bukkit/src/main/java/com/plotsquared/bukkit/util/uuid/SQLUUIDHandler.java b/Bukkit/src/main/java/com/plotsquared/bukkit/util/uuid/SQLUUIDHandler.java deleted file mode 100644 index a08956369..000000000 --- a/Bukkit/src/main/java/com/plotsquared/bukkit/util/uuid/SQLUUIDHandler.java +++ /dev/null @@ -1,270 +0,0 @@ -/* - * _____ _ _ _____ _ - * | __ \| | | | / ____| | | - * | |__) | | ___ | |_| (___ __ _ _ _ __ _ _ __ ___ __| | - * | ___/| |/ _ \| __|\___ \ / _` | | | |/ _` | '__/ _ \/ _` | - * | | | | (_) | |_ ____) | (_| | |_| | (_| | | | __/ (_| | - * |_| |_|\___/ \__|_____/ \__, |\__,_|\__,_|_| \___|\__,_| - * | | - * |_| - * PlotSquared plot management system for Minecraft - * Copyright (C) 2020 IntellectualSites - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package com.plotsquared.bukkit.util.uuid; - -import com.google.common.collect.HashBiMap; -import com.plotsquared.core.PlotSquared; -import com.plotsquared.core.configuration.Captions; -import com.plotsquared.core.configuration.Settings; -import com.plotsquared.core.database.SQLite; -import com.plotsquared.core.util.MainUtil; -import com.plotsquared.core.util.StringWrapper; -import com.plotsquared.core.util.task.RunnableVal; -import com.plotsquared.core.util.task.TaskManager; -import com.plotsquared.core.util.uuid.UUIDHandler; -import com.plotsquared.core.util.uuid.UUIDHandlerImplementation; -import com.plotsquared.core.util.uuid.UUIDWrapper; -import org.json.simple.JSONArray; -import org.json.simple.JSONObject; -import org.json.simple.parser.JSONParser; -import org.json.simple.parser.ParseException; - -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.OutputStream; -import java.net.HttpURLConnection; -import java.net.URL; -import java.sql.Connection; -import java.sql.PreparedStatement; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.util.ArrayDeque; -import java.util.Collections; -import java.util.HashMap; -import java.util.UUID; -import java.util.concurrent.TimeUnit; - -public class SQLUUIDHandler extends UUIDHandlerImplementation { - - final int MAX_REQUESTS = 500; - private final String PROFILE_URL = - "https://sessionserver.mojang.com/session/minecraft/profile/"; - private final JSONParser jsonParser = new JSONParser(); - private final SQLite sqlite; - - public SQLUUIDHandler(UUIDWrapper wrapper) { - super(wrapper); - this.sqlite = - new SQLite(MainUtil.getFile(PlotSquared.get().IMP.getDirectory(), "usercache.db")); - try { - this.sqlite.openConnection(); - } catch (ClassNotFoundException | SQLException e) { - e.printStackTrace(); - } - - try (PreparedStatement stmt = getConnection().prepareStatement( - "CREATE TABLE IF NOT EXISTS `usercache` (uuid VARCHAR(32) NOT NULL, username VARCHAR(32) NOT NULL, PRIMARY KEY (uuid, username))")) { - stmt.execute(); - } catch (SQLException e) { - e.printStackTrace(); - } - startCaching(null); - } - - private Connection getConnection() { - synchronized (this.sqlite) { - return this.sqlite.getConnection(); - } - } - - @Override public boolean startCaching(final Runnable whenDone) { - if (!super.startCaching(whenDone)) { - return false; - } - TaskManager.runTaskAsync(() -> { - try { - HashBiMap toAdd = HashBiMap.create(new HashMap<>()); - try (PreparedStatement statement = getConnection() - .prepareStatement("SELECT `uuid`, `username` FROM `usercache`"); - ResultSet resultSet = statement.executeQuery()) { - while (resultSet.next()) { - StringWrapper username = new StringWrapper(resultSet.getString("username")); - UUID uuid = UUID.fromString(resultSet.getString("uuid")); - toAdd.put(new StringWrapper(username.value), uuid); - } - } - add(toAdd); - // This should be called as long as there are some unknown plots - final ArrayDeque toFetch = new ArrayDeque<>(); - for (UUID u : UUIDHandler.getAllUUIDS()) { - if (!uuidExists(u)) { - toFetch.add(u); - } - } - if (toFetch.isEmpty()) { - if (whenDone != null) { - whenDone.run(); - } - return; - } - FileUUIDHandler fileHandler = new FileUUIDHandler(SQLUUIDHandler.this.uuidWrapper); - fileHandler.startCaching(() -> { - // If the file based UUID handler didn't cache it, then we can't cache offline mode - // Also, trying to cache based on files again, is useless as that's what the file based uuid cacher does - if (Settings.UUID.OFFLINE) { - if (whenDone != null) { - whenDone.run(); - } - return; - } - - TaskManager.runTaskAsync(() -> { - while (!toFetch.isEmpty()) { - try { - for (int i = 0; i < Math.min(MAX_REQUESTS, toFetch.size()); i++) { - UUID uuid = toFetch.pop(); - HttpURLConnection connection = (HttpURLConnection) new URL( - SQLUUIDHandler.this.PROFILE_URL + uuid.toString() - .replace("-", "")).openConnection(); - try (InputStream con = connection.getInputStream()) { - InputStreamReader reader = new InputStreamReader(con); - JSONObject response = - (JSONObject) SQLUUIDHandler.this.jsonParser - .parse(reader); - String name = (String) response.get("name"); - if (name != null) { - add(new StringWrapper(name), uuid); - } - } - connection.disconnect(); - } - } catch (IOException | ParseException e) { - PlotSquared.debug( - "Invalid response from Mojang: Some UUIDs will be cached later. (`unknown` until then or player joins)"); - } - try { - //Mojang allows requests every 10 minutes according to https://wiki.vg/Mojang_API - //15 Minutes is chosen here since system timers are not always precise - //and it should provide enough time where Mojang won't block requests. - TimeUnit.MINUTES.sleep(15); - } catch (InterruptedException e) { - e.printStackTrace(); - break; - } - } - if (whenDone != null) { - whenDone.run(); - } - }); - }); - } catch (SQLException e) { - throw new SQLUUIDHandlerException("Couldn't select :s", e); - } - }); - return true; - } - - @Override public void fetchUUID(final String name, final RunnableVal ifFetch) { - PlotSquared.debug(Captions.PREFIX + "UUID for '" + name - + "' was null. We'll cache this from the Mojang servers!"); - if (ifFetch == null) { - return; - } - TaskManager.runTaskAsync(() -> { - try { - URL url = new URL(SQLUUIDHandler.this.PROFILE_URL); - HttpURLConnection connection = (HttpURLConnection) url.openConnection(); - connection.setRequestMethod("POST"); - connection.setRequestProperty("Content-Type", "application/json"); - connection.setUseCaches(false); - connection.setDoInput(true); - connection.setDoOutput(true); - String body = JSONArray.toJSONString(Collections.singletonList(name)); - OutputStream stream = connection.getOutputStream(); - stream.write(body.getBytes()); - stream.flush(); - stream.close(); - JSONArray array = (JSONArray) SQLUUIDHandler.this.jsonParser - .parse(new InputStreamReader(connection.getInputStream())); - JSONObject jsonProfile = (JSONObject) array.get(0); - String id = (String) jsonProfile.get("id"); - String name1 = (String) jsonProfile.get("name"); - ifFetch.value = UUID.fromString( - id.substring(0, 8) + '-' + id.substring(8, 12) + '-' + id.substring(12, 16) - + '-' + id.substring(16, 20) + '-' + id.substring(20, 32)); - } catch (IOException | ParseException e) { - e.printStackTrace(); - } - TaskManager.runTask(ifFetch); - }); - } - - @Override public void handleShutdown() { - super.handleShutdown(); - try { - getConnection().close(); - } catch (SQLException e) { - throw new SQLUUIDHandlerException("Couldn't close database connection", e); - } - } - - /** - * This is useful for name changes - */ - @Override public void rename(final UUID uuid, final StringWrapper name) { - super.rename(uuid, name); - TaskManager.runTaskAsync(() -> { - try (PreparedStatement statement = getConnection() - .prepareStatement("UPDATE usercache SET `username`=? WHERE `uuid`=?")) { - statement.setString(1, name.value); - statement.setString(2, uuid.toString()); - statement.execute(); - PlotSquared.debug( - Captions.PREFIX + "Name change for '" + uuid + "' to '" + name.value + '\''); - } catch (SQLException e) { - e.printStackTrace(); - } - }); - } - - @Override public boolean add(final StringWrapper name, final UUID uuid) { - // Ignoring duplicates - if (super.add(name, uuid)) { - TaskManager.runTaskAsync(() -> { - try (PreparedStatement statement = getConnection() - .prepareStatement("REPLACE INTO usercache (`uuid`, `username`) VALUES(?, ?)")) { - statement.setString(1, uuid.toString()); - statement.setString(2, name.toString()); - statement.execute(); - PlotSquared - .debug(Captions.PREFIX + "&cAdded '&6" + uuid + "&c' - '&6" + name + "&c'"); - } catch (SQLException e) { - e.printStackTrace(); - } - }); - return true; - } - return false; - } - - private static class SQLUUIDHandlerException extends RuntimeException { - - SQLUUIDHandlerException(String s, Throwable c) { - super("SQLUUIDHandler caused an exception: " + s, c); - } - } -} diff --git a/Bukkit/src/main/java/com/plotsquared/bukkit/uuid/BungeePermsUUIDService.java b/Bukkit/src/main/java/com/plotsquared/bukkit/uuid/BungeePermsUUIDService.java new file mode 100644 index 000000000..4de1bdb92 --- /dev/null +++ b/Bukkit/src/main/java/com/plotsquared/bukkit/uuid/BungeePermsUUIDService.java @@ -0,0 +1,85 @@ +/* + * _____ _ _ _____ _ + * | __ \| | | | / ____| | | + * | |__) | | ___ | |_| (___ __ _ _ _ __ _ _ __ ___ __| | + * | ___/| |/ _ \| __|\___ \ / _` | | | |/ _` | '__/ _ \/ _` | + * | | | | (_) | |_ ____) | (_| | |_| | (_| | | | __/ (_| | + * |_| |_|\___/ \__|_____/ \__, |\__,_|\__,_|_| \___|\__,_| + * | | + * |_| + * PlotSquared plot management system for Minecraft + * Copyright (C) 2020 IntellectualSites + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.plotsquared.bukkit.uuid; + +import com.plotsquared.core.uuid.UUIDMapping; +import com.plotsquared.core.uuid.UUIDService; +import net.luckperms.api.model.user.UserManager; +import org.bukkit.Bukkit; +import org.bukkit.plugin.RegisteredServiceProvider; +import org.jetbrains.annotations.NotNull; + +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; +import net.alpenblock.bungeeperms.BungeePerms; +import net.alpenblock.bungeeperms.io.UUIDPlayerDB; + +/** + * UUID service that uses the BungeePerms API + */ +public class BungeePermsUUIDService implements UUIDService { + + private final BungeePerms bp; + + public BungeePermsUUIDService() { + final RegisteredServiceProvider provider = Bukkit.getServicesManager().getRegistration(BungeePerms.class); + if (provider != null) { + this.bp = provider.getProvider(); + } else { + throw new IllegalStateException("BungeePerms is not available"); + } + } + + @Override @NotNull public List getNames(@NotNull final List uuids) { + final List mappings = new ArrayList<>(uuids.size()); + final UUIDPlayerDB uuiddb = BungeePerms.getInstance().getPermissionsManager().getUUIDPlayerDB(); + for (final UUID uuid : uuids) { + try { + final String username = uuiddb.getPlayerName(uuid); + if (username != null) { + mappings.add(new UUIDMapping(uuid, username)); + } + } catch (final Exception ignored) {} + } + return mappings; + } + + @Override @NotNull public List getUUIDs(@NotNull final List usernames) { + final List mappings = new ArrayList<>(usernames.size()); + final UUIDPlayerDB uuiddb = BungeePerms.getInstance().getPermissionsManager().getUUIDPlayerDB(); + for (final String username : usernames) { + try { + final UUID uuid = uuiddb.getUUID(username); + if (username != null) { + mappings.add(new UUIDMapping(uuid, username)); + } + } catch (final Exception ignored) {} + } + return mappings; + } + +} diff --git a/Bukkit/src/main/java/com/plotsquared/bukkit/uuid/EssentialsUUIDService.java b/Bukkit/src/main/java/com/plotsquared/bukkit/uuid/EssentialsUUIDService.java new file mode 100644 index 000000000..eb473d67e --- /dev/null +++ b/Bukkit/src/main/java/com/plotsquared/bukkit/uuid/EssentialsUUIDService.java @@ -0,0 +1,70 @@ +/* + * _____ _ _ _____ _ + * | __ \| | | | / ____| | | + * | |__) | | ___ | |_| (___ __ _ _ _ __ _ _ __ ___ __| | + * | ___/| |/ _ \| __|\___ \ / _` | | | |/ _` | '__/ _ \/ _` | + * | | | | (_) | |_ ____) | (_| | |_| | (_| | | | __/ (_| | + * |_| |_|\___/ \__|_____/ \__, |\__,_|\__,_|_| \___|\__,_| + * | | + * |_| + * PlotSquared plot management system for Minecraft + * Copyright (C) 2020 IntellectualSites + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.plotsquared.bukkit.uuid; + +import com.earth2me.essentials.Essentials; +import com.earth2me.essentials.User; +import com.plotsquared.core.uuid.UUIDMapping; +import com.plotsquared.core.uuid.UUIDService; +import org.jetbrains.annotations.NotNull; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.UUID; + +/** + * UUID service using the EssentialsX API + */ +public class EssentialsUUIDService implements UUIDService { + + private final Essentials essentials; + + public EssentialsUUIDService() { + this.essentials = Essentials.getPlugin(Essentials.class); + } + + @Override @NotNull public List getNames(@NotNull final List uuids) { + return Collections.emptyList(); + } + + @Override @NotNull public List getUUIDs(@NotNull final List usernames) { + final List mappings = new ArrayList<>(usernames.size()); + for (final String username : usernames) { + try { + final User user = essentials.getUser(username); + if (user != null) { + final UUID uuid = user.getConfigUUID(); + if (uuid != null) { + mappings.add(new UUIDMapping(uuid, username)); + } + } + } catch (final Exception ignored){} + } + return mappings; + } + +} diff --git a/Bukkit/src/main/java/com/plotsquared/bukkit/uuid/LuckPermsUUIDService.java b/Bukkit/src/main/java/com/plotsquared/bukkit/uuid/LuckPermsUUIDService.java new file mode 100644 index 000000000..47bcc9bb3 --- /dev/null +++ b/Bukkit/src/main/java/com/plotsquared/bukkit/uuid/LuckPermsUUIDService.java @@ -0,0 +1,84 @@ +/* + * _____ _ _ _____ _ + * | __ \| | | | / ____| | | + * | |__) | | ___ | |_| (___ __ _ _ _ __ _ _ __ ___ __| | + * | ___/| |/ _ \| __|\___ \ / _` | | | |/ _` | '__/ _ \/ _` | + * | | | | (_) | |_ ____) | (_| | |_| | (_| | | | __/ (_| | + * |_| |_|\___/ \__|_____/ \__, |\__,_|\__,_|_| \___|\__,_| + * | | + * |_| + * PlotSquared plot management system for Minecraft + * Copyright (C) 2020 IntellectualSites + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.plotsquared.bukkit.uuid; + +import com.plotsquared.core.uuid.UUIDMapping; +import com.plotsquared.core.uuid.UUIDService; +import net.luckperms.api.LuckPerms; +import net.luckperms.api.model.user.UserManager; +import org.bukkit.Bukkit; +import org.bukkit.plugin.RegisteredServiceProvider; +import org.jetbrains.annotations.NotNull; + +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + +/** + * UUID service that uses the LuckPerms API + */ +public class LuckPermsUUIDService implements UUIDService { + + private final LuckPerms luckPerms; + + public LuckPermsUUIDService() { + final RegisteredServiceProvider provider = Bukkit.getServicesManager().getRegistration(LuckPerms.class); + if (provider != null) { + this.luckPerms = provider.getProvider(); + } else { + throw new IllegalStateException("LuckPerms not available"); + } + } + + @Override @NotNull public List getNames(@NotNull final List uuids) { + final List mappings = new ArrayList<>(uuids.size()); + final UserManager userManager = this.luckPerms.getUserManager(); + for (final UUID uuid : uuids) { + try { + final String username = userManager.lookupUsername(uuid).get(); + if (username != null) { + mappings.add(new UUIDMapping(uuid, username)); + } + } catch (final Exception ignored) {} + } + return mappings; + } + + @Override @NotNull public List getUUIDs(@NotNull final List usernames) { + final List mappings = new ArrayList<>(usernames.size()); + final UserManager userManager = this.luckPerms.getUserManager(); + for (final String username : usernames) { + try { + final UUID uuid = userManager.lookupUniqueId(username).get(); + if (username != null) { + mappings.add(new UUIDMapping(uuid, username)); + } + } catch (final Exception ignored) {} + } + return mappings; + } + +} diff --git a/Bukkit/src/main/java/com/plotsquared/bukkit/uuid/OfflinePlayerUUIDService.java b/Bukkit/src/main/java/com/plotsquared/bukkit/uuid/OfflinePlayerUUIDService.java new file mode 100644 index 000000000..7b904e627 --- /dev/null +++ b/Bukkit/src/main/java/com/plotsquared/bukkit/uuid/OfflinePlayerUUIDService.java @@ -0,0 +1,85 @@ +/* + * _____ _ _ _____ _ + * | __ \| | | | / ____| | | + * | |__) | | ___ | |_| (___ __ _ _ _ __ _ _ __ ___ __| | + * | ___/| |/ _ \| __|\___ \ / _` | | | |/ _` | '__/ _ \/ _` | + * | | | | (_) | |_ ____) | (_| | |_| | (_| | | | __/ (_| | + * |_| |_|\___/ \__|_____/ \__, |\__,_|\__,_|_| \___|\__,_| + * | | + * |_| + * PlotSquared plot management system for Minecraft + * Copyright (C) 2020 IntellectualSites + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.plotsquared.bukkit.uuid; + +import com.google.common.base.Charsets; +import com.plotsquared.core.configuration.Settings; +import com.plotsquared.core.uuid.UUIDMapping; +import com.plotsquared.core.uuid.UUIDService; +import org.bukkit.Bukkit; +import org.bukkit.OfflinePlayer; +import org.jetbrains.annotations.NotNull; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.UUID; + +/** + * UUID service that use {@link org.bukkit.OfflinePlayer offline players} + */ +public class OfflinePlayerUUIDService implements UUIDService { + + @Override @NotNull public List getNames(@NotNull final List uuids) { + if (Settings.UUID.FORCE_LOWERCASE || Bukkit.getWorlds().isEmpty()) { + return Collections.emptyList(); // This is useless now + } + final List wrappers = new ArrayList<>(uuids.size()); + for (final UUID uuid : uuids) { + final OfflinePlayer offlinePlayer = Bukkit.getOfflinePlayer(uuid); + try { + if (offlinePlayer.hasPlayedBefore()) { + wrappers.add(new UUIDMapping(uuid, offlinePlayer.getName())); + } + } catch (final Exception ignored) {} /* This can be safely ignored. If this happens, it is + probably because it's called before the worlds have + been loaded. This is bad, but does not break anything */ + } + return wrappers; + } + + @Override @NotNull public List getUUIDs(@NotNull final List usernames) { + final List wrappers = new ArrayList<>(usernames.size()); + for (final String username : usernames) { + if (Settings.UUID.OFFLINE) { + if (Settings.UUID.FORCE_LOWERCASE) { + wrappers.add(new UUIDMapping(UUID.nameUUIDFromBytes(("OfflinePlayer:" + + username.toLowerCase()).getBytes(Charsets.UTF_8)), username)); + } else { + wrappers.add(new UUIDMapping(UUID.nameUUIDFromBytes(("OfflinePlayer:" + + username).getBytes(Charsets.UTF_8)), username)); + } + } else { + final OfflinePlayer offlinePlayer = Bukkit.getOfflinePlayer(username); + if (offlinePlayer.hasPlayedBefore()) { + wrappers.add(new UUIDMapping(offlinePlayer.getUniqueId(), offlinePlayer.getName())); + } + } + } + return wrappers; + } + +} diff --git a/Bukkit/src/main/java/com/plotsquared/bukkit/uuid/PaperUUIDService.java b/Bukkit/src/main/java/com/plotsquared/bukkit/uuid/PaperUUIDService.java new file mode 100644 index 000000000..4f370c8b3 --- /dev/null +++ b/Bukkit/src/main/java/com/plotsquared/bukkit/uuid/PaperUUIDService.java @@ -0,0 +1,65 @@ +/* + * _____ _ _ _____ _ + * | __ \| | | | / ____| | | + * | |__) | | ___ | |_| (___ __ _ _ _ __ _ _ __ ___ __| | + * | ___/| |/ _ \| __|\___ \ / _` | | | |/ _` | '__/ _ \/ _` | + * | | | | (_) | |_ ____) | (_| | |_| | (_| | | | __/ (_| | + * |_| |_|\___/ \__|_____/ \__, |\__,_|\__,_|_| \___|\__,_| + * | | + * |_| + * PlotSquared plot management system for Minecraft + * Copyright (C) 2020 IntellectualSites + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.plotsquared.bukkit.uuid; + +import com.destroystokyo.paper.profile.PlayerProfile; +import com.plotsquared.core.uuid.UUIDMapping; +import com.plotsquared.core.uuid.UUIDService; +import org.bukkit.Bukkit; +import org.jetbrains.annotations.NotNull; + +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + +/** + * UUID service that uses the Paper profile API + */ +public class PaperUUIDService implements UUIDService { + + @Override @NotNull public List getNames(@NotNull final List uuids) { + final List mappings = new ArrayList<>(uuids.size()); + for (final UUID uuid : uuids) { + final PlayerProfile playerProfile = Bukkit.createProfile(uuid); + if ((playerProfile.isComplete() || playerProfile.completeFromCache()) && playerProfile.getId() != null) { + mappings.add(new UUIDMapping(playerProfile.getId(), playerProfile.getName())); + } + } + return mappings; + } + + @Override @NotNull public List getUUIDs(@NotNull final List usernames) { + final List mappings = new ArrayList<>(usernames.size()); + for (final String username : usernames) { + final PlayerProfile playerProfile = Bukkit.createProfile(username); + if ((playerProfile.isComplete() || playerProfile.completeFromCache()) && playerProfile.getId() != null) { + mappings.add(new UUIDMapping(playerProfile.getId(), playerProfile.getName())); + } + } + return mappings; + } + +} diff --git a/Bukkit/src/main/java/com/plotsquared/bukkit/uuid/SQLiteUUIDService.java b/Bukkit/src/main/java/com/plotsquared/bukkit/uuid/SQLiteUUIDService.java new file mode 100644 index 000000000..16b3abff5 --- /dev/null +++ b/Bukkit/src/main/java/com/plotsquared/bukkit/uuid/SQLiteUUIDService.java @@ -0,0 +1,145 @@ +/* + * _____ _ _ _____ _ + * | __ \| | | | / ____| | | + * | |__) | | ___ | |_| (___ __ _ _ _ __ _ _ __ ___ __| | + * | ___/| |/ _ \| __|\___ \ / _` | | | |/ _` | '__/ _ \/ _` | + * | | | | (_) | |_ ____) | (_| | |_| | (_| | | | __/ (_| | + * |_| |_|\___/ \__|_____/ \__, |\__,_|\__,_|_| \___|\__,_| + * | | + * |_| + * PlotSquared plot management system for Minecraft + * Copyright (C) 2020 IntellectualSites + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.plotsquared.bukkit.uuid; + +import com.plotsquared.core.PlotSquared; +import com.plotsquared.core.database.SQLite; +import com.plotsquared.core.util.MainUtil; +import com.plotsquared.core.uuid.UUIDMapping; +import com.plotsquared.core.uuid.UUIDService; +import org.jetbrains.annotations.NotNull; + +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; +import java.util.UUID; +import java.util.function.Consumer; + +/** + * UUID service that uses the (legacy) SQL UUID cache + */ +public class SQLiteUUIDService implements UUIDService, Consumer> { + + private final SQLite sqlite; + + public SQLiteUUIDService(final String fileName) { + this.sqlite = + new SQLite(MainUtil.getFile(PlotSquared.get().IMP.getDirectory(), fileName)); + try { + this.sqlite.openConnection(); + } catch (ClassNotFoundException | SQLException e) { + e.printStackTrace(); + } + + try (PreparedStatement stmt = getConnection().prepareStatement( + "CREATE TABLE IF NOT EXISTS `usercache` (uuid VARCHAR(32) NOT NULL, username VARCHAR(32) NOT NULL, PRIMARY KEY (uuid))")) { + stmt.execute(); + } catch (SQLException e) { + e.printStackTrace(); + } + } + + private Connection getConnection() { + synchronized (this.sqlite) { + return this.sqlite.getConnection(); + } + } + + @Override @NotNull public List getNames(@NotNull final List uuids) { + final List mappings = new ArrayList<>(uuids.size()); + try (final PreparedStatement statement = getConnection() + .prepareStatement("SELECT `username` FROM `usercache` WHERE `uuid` = ?")) { + for (final UUID uuid : uuids) { + statement.setString(1, uuid.toString()); + try (final ResultSet resultSet = statement.executeQuery()) { + if (resultSet.next()) { + mappings.add(new UUIDMapping(uuid, resultSet.getString("username"))); + } + } + } + } catch (final Exception e) { + e.printStackTrace(); + } + return mappings; + } + + @Override @NotNull public List getUUIDs(@NotNull List usernames) { + final List mappings = new ArrayList<>(usernames.size()); + try (final PreparedStatement statement = getConnection() + .prepareStatement("SELECT `uuid` FROM `usercache` WHERE `username` = ?")) { + for (final String username : usernames) { + statement.setString(1, username); + try (final ResultSet resultSet = statement.executeQuery()) { + if (resultSet.next()) { + mappings.add(new UUIDMapping(UUID.fromString(resultSet.getString("uuid")), + username)); + } + } + } + } catch (final Exception e) { + e.printStackTrace(); + } + return mappings; + } + + @Override public void accept(final List uuidWrappers) { + try (final PreparedStatement statement = getConnection() + .prepareStatement("INSERT OR REPLACE INTO `usercache` (`uuid`, `username`) VALUES(?, ?)")) { + for (final UUIDMapping mapping : uuidWrappers) { + statement.setString(1, mapping.getUuid().toString()); + statement.setString(2, mapping.getUsername()); + statement.executeUpdate(); + } + } catch (SQLException e) { + e.printStackTrace(); + } + } + + /** + * Read the entire cache at once + * + * @return All read mappings + */ + @NotNull public List getAll() { + final List mappings = new LinkedList<>(); + try (final PreparedStatement statement = getConnection().prepareStatement("SELECT * FROM `usercache`")) { + try (final ResultSet resultSet = statement.executeQuery()) { + while (resultSet.next()) { + mappings.add(new UUIDMapping(UUID.fromString(resultSet.getString("uuid")), resultSet.getString("username"))); + } + } + } catch (final Exception e) { + e.printStackTrace(); + } + return mappings; + } + + +} diff --git a/Bukkit/src/main/java/com/plotsquared/bukkit/uuid/SquirrelIdUUIDService.java b/Bukkit/src/main/java/com/plotsquared/bukkit/uuid/SquirrelIdUUIDService.java new file mode 100644 index 000000000..4580519aa --- /dev/null +++ b/Bukkit/src/main/java/com/plotsquared/bukkit/uuid/SquirrelIdUUIDService.java @@ -0,0 +1,90 @@ +/* + * _____ _ _ _____ _ + * | __ \| | | | / ____| | | + * | |__) | | ___ | |_| (___ __ _ _ _ __ _ _ __ ___ __| | + * | ___/| |/ _ \| __|\___ \ / _` | | | |/ _` | '__/ _ \/ _` | + * | | | | (_) | |_ ____) | (_| | |_| | (_| | | | __/ (_| | + * |_| |_|\___/ \__|_____/ \__, |\__,_|\__,_|_| \___|\__,_| + * | | + * |_| + * PlotSquared plot management system for Minecraft + * Copyright (C) 2020 IntellectualSites + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.plotsquared.bukkit.uuid; + +import com.google.common.util.concurrent.RateLimiter; +import com.plotsquared.core.uuid.UUIDMapping; +import com.plotsquared.core.uuid.UUIDService; +import com.sk89q.squirrelid.Profile; +import com.sk89q.squirrelid.resolver.HttpRepositoryService; +import com.sk89q.squirrelid.resolver.ProfileService; +import org.jetbrains.annotations.NotNull; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + +/** + * UUID service using SquirrelID + */ +@SuppressWarnings("UnstableApiUsage") +public class SquirrelIdUUIDService implements UUIDService { + + private final ProfileService profileService; + private final RateLimiter rateLimiter; + + /** + * Create a new SquirrelID UUID service + * + * @param rateLimit Mojangs rate limit is 600 requests per 10 minutes. + * This parameter specifies how many of those requests + * we can use before our internal rate limit kicks in. + */ + public SquirrelIdUUIDService(final int rateLimit) { + this.profileService = HttpRepositoryService.forMinecraft(); + // RateLimiter uses request per seconds. The constructor + // parameter rateLimit is requests per 600 seconds + this.rateLimiter = RateLimiter.create(rateLimit / 600.0D); + } + + @Override @NotNull public List getNames(@NotNull final List uuids) { + final List results = new ArrayList<>(uuids.size()); + this.rateLimiter.acquire(uuids.size()); + try { + for (final Profile profile : this.profileService.findAllById(uuids)) { + results.add(new UUIDMapping(profile.getUniqueId(), profile.getName())); + } + } catch (IOException | InterruptedException e) { + e.printStackTrace(); + } + return results; + } + + @Override @NotNull public List getUUIDs(@NotNull final List usernames) { + final List results = new ArrayList<>(usernames.size()); + this.rateLimiter.acquire(usernames.size()); + try { + for (final Profile profile : this.profileService.findAllByName(usernames)) { + results.add(new UUIDMapping(profile.getUniqueId(), profile.getName())); + } + } catch (IOException | InterruptedException e) { + e.printStackTrace(); + } + return results; + } + +} diff --git a/Bukkit/src/main/resources/plugin.yml b/Bukkit/src/main/resources/plugin.yml index 05d2aa6e2..41967220c 100644 --- a/Bukkit/src/main/resources/plugin.yml +++ b/Bukkit/src/main/resources/plugin.yml @@ -5,8 +5,8 @@ version: "${version}" load: STARTUP description: "Easy, yet powerful Plot World generation and management." authors: [Citymonstret, Empire92, MattBDev, dordsor21, NotMyFault, SirYwell] -website: https://github.com/IntellectualSites/ -softdepend: [Vault, PlaceholderAPI] +website: https://www.spigotmc.org/resources/77506/ +softdepend: [Vault, PlaceholderAPI, Essentials, LuckPerms, BungeePerms] loadbefore: [MultiWorld, Multiverse-Core] depend: [WorldEdit] database: false diff --git a/Core/build.gradle b/Core/build.gradle index ee6edfda2..51f56e187 100644 --- a/Core/build.gradle +++ b/Core/build.gradle @@ -1,5 +1,6 @@ repositories { maven { url = "https://jitpack.io" } + maven { url = "https://mvn.intellectualsites.com/content/repositories/snapshots" } } def textVersion = "3.0.2" @@ -16,6 +17,7 @@ dependencies { testAnnotationProcessor("org.projectlombok:lombok:1.18.8") implementation("org.jetbrains.kotlin:kotlin-stdlib:1.3.72") implementation("org.jetbrains:annotations:19.0.0") + implementation("org.khelekore:prtree:1.7.0-SNAPSHOT") } sourceCompatibility = 1.8 @@ -73,6 +75,7 @@ shadowJar { include(dependency("net.kyori:text-serializer-gson:3.0.2")) include(dependency("net.kyori:text-serializer-legacy:3.0.2")) include(dependency("net.kyori:text-serializer-plain:3.0.2")) + include(dependency("org.khelekore:prtree:1.7.0-SNAPSHOT")) } relocate('net.kyori.text', 'com.plotsquared.formatting.text') relocate("org.json", "com.plotsquared.json") { diff --git a/Core/pom.xml b/Core/pom.xml index 280cd8b1a..d69f10a99 100644 --- a/Core/pom.xml +++ b/Core/pom.xml @@ -9,7 +9,7 @@ org.json json - 20190722 + 20200518 compile @@ -92,6 +92,12 @@ 1.3.72 runtime + + org.khelekore + prtree + 1.7.0-SNAPSHOT + runtime + junit junit diff --git a/Core/src/main/java/com/plotsquared/core/IPlotMain.java b/Core/src/main/java/com/plotsquared/core/IPlotMain.java index ed6694e01..a38045acb 100644 --- a/Core/src/main/java/com/plotsquared/core/IPlotMain.java +++ b/Core/src/main/java/com/plotsquared/core/IPlotMain.java @@ -35,22 +35,29 @@ import com.plotsquared.core.util.ChatManager; import com.plotsquared.core.util.ChunkManager; import com.plotsquared.core.util.EconHandler; import com.plotsquared.core.util.InventoryUtil; +import com.plotsquared.core.util.PermHandler; import com.plotsquared.core.util.PlatformWorldManager; +import com.plotsquared.core.util.PlayerManager; import com.plotsquared.core.util.RegionManager; import com.plotsquared.core.util.SchematicHandler; import com.plotsquared.core.util.SetupUtils; import com.plotsquared.core.util.WorldUtil; import com.plotsquared.core.util.logger.ILogger; import com.plotsquared.core.util.task.TaskManager; -import com.plotsquared.core.util.uuid.UUIDHandlerImplementation; import com.sk89q.worldedit.extension.platform.Actor; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.io.File; import java.util.List; import java.util.Map; -public interface IPlotMain extends ILogger { +/** + * PlotSquared main utility class + * + * @param

Player type + */ +public interface IPlotMain

extends ILogger { /** * Logs a message to console. @@ -79,7 +86,7 @@ public interface IPlotMain extends ILogger { * @param player The player to convert to a PlotPlayer * @return A PlotPlayer */ - PlotPlayer wrapPlayer(Object player); + @Nullable PlotPlayer

wrapPlayer(Object player); /** * Completely shuts down the plugin. @@ -168,11 +175,18 @@ public interface IPlotMain extends ILogger { boolean initWorldEdit(); /** - * Gets the economy provider. + * Gets the economy provider, if there is one * * @return the PlotSquared economy manager */ - EconHandler getEconomyHandler(); + @Nullable EconHandler getEconomyHandler(); + + /** + * Gets the permission provider, if there is one + * + * @return the PlotSquared permission manager + */ + @Nullable PermHandler getPermissionHandler(); /** * Gets the {@link QueueProvider} class. @@ -220,12 +234,6 @@ public interface IPlotMain extends ILogger { */ void setGenerator(String world); - /** - * Gets the {@link UUIDHandlerImplementation} which will cache and - * provide UUIDs. - */ - UUIDHandlerImplementation initUUIDHandler(); - /** * Gets the {@link InventoryUtil} class (used for implementation specific * inventory guis). @@ -285,6 +293,13 @@ public interface IPlotMain extends ILogger { * * @return World manager */ - @NotNull PlatformWorldManager getWorldManager(); + @NotNull PlatformWorldManager getWorldManager(); + + /** + * Get the player manager implementation for the platform + * + * @return Player manager + */ + @NotNull PlayerManager, ? extends P> getPlayerManager(); } diff --git a/Core/src/main/java/com/plotsquared/core/PlotSquared.java b/Core/src/main/java/com/plotsquared/core/PlotSquared.java index 452493181..30d738afc 100644 --- a/Core/src/main/java/com/plotsquared/core/PlotSquared.java +++ b/Core/src/main/java/com/plotsquared/core/PlotSquared.java @@ -53,6 +53,7 @@ import com.plotsquared.core.player.PlotPlayer; import com.plotsquared.core.plot.BlockBucket; import com.plotsquared.core.plot.Plot; import com.plotsquared.core.plot.PlotArea; +import com.plotsquared.core.plot.PlotAreaTerrainType; import com.plotsquared.core.plot.PlotAreaType; import com.plotsquared.core.plot.PlotCluster; import com.plotsquared.core.plot.PlotFilter; @@ -79,17 +80,18 @@ import com.plotsquared.core.util.RegionManager; import com.plotsquared.core.util.SchematicHandler; import com.plotsquared.core.util.SetupUtils; import com.plotsquared.core.util.StringMan; -import com.plotsquared.core.util.StringWrapper; import com.plotsquared.core.util.WorldUtil; import com.plotsquared.core.util.logger.ILogger; +import com.plotsquared.core.util.query.PlotQuery; import com.plotsquared.core.util.task.TaskManager; -import com.plotsquared.core.util.uuid.UUIDHandler; +import com.plotsquared.core.uuid.UUIDPipeline; import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.math.BlockVector2; import com.sk89q.worldedit.regions.CuboidRegion; import lombok.Getter; import lombok.NonNull; import lombok.Setter; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.io.BufferedReader; @@ -116,6 +118,7 @@ import java.util.Comparator; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; +import java.util.LinkedList; import java.util.List; import java.util.Locale; import java.util.Map; @@ -123,6 +126,7 @@ import java.util.Map.Entry; import java.util.Objects; import java.util.Set; import java.util.UUID; +import java.util.concurrent.Executors; import java.util.function.Consumer; import java.util.regex.Pattern; import java.util.stream.Collectors; @@ -137,9 +141,14 @@ public class PlotSquared { private static final Set EMPTY_SET = Collections.unmodifiableSet(Collections.emptySet()); private static PlotSquared instance; // Implementation - public final IPlotMain IMP; + public final IPlotMain IMP; // Current thread private final Thread thread; + // UUID pipelines + @Getter private final UUIDPipeline impromptuUUIDPipeline = + new UUIDPipeline(Executors.newCachedThreadPool()); + @Getter private final UUIDPipeline backgroundUUIDPipeline = + new UUIDPipeline(Executors.newSingleThreadExecutor()); // WorldEdit instance public WorldEdit worldedit; public File styleFile; @@ -252,15 +261,6 @@ public class PlotSquared { if (Settings.Enabled_Components.CHUNK_PROCESSOR) { this.IMP.registerChunkProcessor(); } - // create UUIDWrapper - UUIDHandler.implementation = this.IMP.initUUIDHandler(); - if (Settings.Enabled_Components.UUID_CACHE) { - startUuidCatching(); - } else { - // Start these separately - UUIDHandler.add(new StringWrapper("*"), DBFunc.EVERYONE); - startExpiryTasks(); - } // Create Event utility class eventDispatcher = new EventDispatcher(); // create Hybrid utility class @@ -270,7 +270,8 @@ public class PlotSquared { // create setup util class SetupUtils.manager = this.IMP.initSetupUtils(); // Set block - GlobalBlockQueue.IMP = new GlobalBlockQueue(IMP.initBlockQueue(), 1); + GlobalBlockQueue.IMP = + new GlobalBlockQueue(IMP.initBlockQueue(), 1, Settings.QUEUE.TARGET_TIME); GlobalBlockQueue.IMP.runTask(); // Set chunk ChunkManager.manager = this.IMP.initChunkManager(); @@ -303,8 +304,7 @@ public class PlotSquared { } // Economy if (Settings.Enabled_Components.ECONOMY) { - TaskManager - .runTask(() -> EconHandler.manager = PlotSquared.this.IMP.getEconomyHandler()); + TaskManager.runTask(() -> EconHandler.initializeEconHandler()); } if (Settings.Enabled_Components.COMPONENT_PRESETS) { @@ -385,11 +385,11 @@ public class PlotSquared { return PlotSquared.instance; } - public static IPlotMain imp() { - if (instance != null) { + @NotNull public static IPlotMain imp() { + if (instance != null && instance.IMP != null) { return instance.IMP; } - return null; + throw new IllegalStateException("Plot main implementation is missing"); } /** @@ -427,23 +427,6 @@ public class PlotSquared { } } - private void startUuidCatching() { - TaskManager.runTaskLater(() -> { - debug("Starting UUID caching"); - UUIDHandler.startCaching(() -> { - UUIDHandler.add(new StringWrapper("*"), DBFunc.EVERYONE); - forEachPlotRaw(plot -> { - if (plot.hasOwner() && plot.temp != -1) { - if (UUIDHandler.getName(plot.getOwnerAbs()) == null) { - UUIDHandler.implementation.unknown.add(plot.getOwnerAbs()); - } - } - }); - startExpiryTasks(); - }); - }, 20); - } - private void startExpiryTasks() { if (Settings.Enabled_Components.PLOT_EXPIRY) { ExpireManager.IMP = new ExpireManager(); @@ -640,17 +623,7 @@ public class PlotSquared { * @return Set of base Plots */ public Set getBasePlots() { - int size = getPlotCount(); - final Set result = new HashSet<>(size); - forEachPlotArea(value -> { - for (Plot plot : value.getPlots()) { - if (!plot.isBasePlot()) { - continue; - } - result.add(plot); - } - }); - return Collections.unmodifiableSet(result); + return PlotQuery.newQuery().whereBasePlot().asSet(); } public List sortPlotsByTemp(Collection plots) { @@ -903,27 +876,25 @@ public class PlotSquared { * * @param filters the filter * @return a filtered set of plots + * @deprecated Use {@link PlotQuery} */ - public Set getPlots(final PlotFilter... filters) { - final HashSet set = new HashSet<>(); - forEachPlotArea(value -> { - for (PlotFilter filter : filters) { - if (!filter.allowsArea(value)) { - return; + @Deprecated public Set getPlots(final PlotFilter... filters) { + final List areas = new LinkedList<>(); + for (final PlotArea plotArea : this.getPlotAreas()) { + for (final PlotFilter filter : filters) { + if (filter.allowsArea(plotArea)) { + areas.add(plotArea); } } - loop: - for (Entry entry2 : value.getPlotEntries()) { - Plot plot = entry2.getValue(); - for (PlotFilter filter : filters) { - if (!filter.allowsPlot(plot)) { - continue loop; - } + } + return PlotQuery.newQuery().inAreas(areas).thatPasses(plot -> { + for (final PlotFilter filter : filters) { + if (!filter.allowsPlot(plot)) { + return false; } - set.add(plot); } - }); - return set; + return true; + }).asSet(); } /** @@ -966,7 +937,7 @@ public class PlotSquared { * @return Set of Plot */ public Set getPlots(String world, String player) { - final UUID uuid = UUIDHandler.getUUID(player, null); + final UUID uuid = this.impromptuUUIDPipeline.getSingle(player, Settings.UUID.BLOCKING_TIMEOUT); return getPlots(world, uuid); } @@ -978,7 +949,7 @@ public class PlotSquared { * @return Set of Plot */ public Set getPlots(PlotArea area, String player) { - UUID uuid = UUIDHandler.getUUID(player, null); + final UUID uuid = this.impromptuUUIDPipeline.getSingle(player, Settings.UUID.BLOCKING_TIMEOUT); return getPlots(area, uuid); } @@ -990,7 +961,7 @@ public class PlotSquared { * @return Set of plot */ public Set getPlots(String world, PlotPlayer player) { - return getPlots(world, player.getUUID()); + return PlotQuery.newQuery().inWorld(world).ownedBy(player).asSet(); } /** @@ -1001,7 +972,7 @@ public class PlotSquared { * @return Set of plot */ public Set getPlots(PlotArea area, PlotPlayer player) { - return getPlots(area, player.getUUID()); + return PlotQuery.newQuery().inArea(area).ownedBy(player).asSet(); } /** @@ -1012,10 +983,7 @@ public class PlotSquared { * @return Set of plot */ public Set getPlots(String world, UUID uuid) { - final Set plots = - getPlots(world).stream().filter(plot -> plot.hasOwner() && plot.isOwnerAbs(uuid)) - .collect(Collectors.toSet()); - return Collections.unmodifiableSet(plots); + return PlotQuery.newQuery().inWorld(world).ownedBy(uuid).asSet(); } /** @@ -1026,13 +994,7 @@ public class PlotSquared { * @return Set of plots */ public Set getPlots(PlotArea area, UUID uuid) { - final Set plots = new HashSet<>(); - for (Plot plot : getPlots(area)) { - if (plot.hasOwner() && plot.isOwnerAbs(uuid)) { - plots.add(plot); - } - } - return Collections.unmodifiableSet(plots); + return PlotQuery.newQuery().inArea(area).ownedBy(uuid).asSet(); } /** @@ -1047,9 +1009,7 @@ public class PlotSquared { } public Collection getPlots(String world) { - final Set set = new HashSet<>(); - forEachPlotArea(world, value -> set.addAll(value.getPlots())); - return set; + return PlotQuery.newQuery().inWorld(world).asCollection(); } /** @@ -1059,7 +1019,7 @@ public class PlotSquared { * @return Set of Plot */ public Set getPlots(PlotPlayer player) { - return getPlots(player.getUUID()); + return PlotQuery.newQuery().ownedBy(player).asSet(); } public Collection getPlots(PlotArea area) { @@ -1081,13 +1041,7 @@ public class PlotSquared { * @return Set of Plot's owned by the player */ public Set getPlots(final UUID uuid) { - final Set plots = new HashSet<>(); - forEachPlot(value -> { - if (value.isOwnerAbs(uuid)) { - plots.add(value); - } - }); - return Collections.unmodifiableSet(plots); + return PlotQuery.newQuery().ownedBy(uuid).asSet(); } public boolean hasPlot(final UUID uuid) { @@ -1096,13 +1050,7 @@ public class PlotSquared { } public Set getBasePlots(final UUID uuid) { - final Set plots = new HashSet<>(); - forEachBasePlot(value -> { - if (value.isOwner(uuid)) { - plots.add(value); - } - }); - return Collections.unmodifiableSet(plots); + return PlotQuery.newQuery().ownedBy(uuid).whereBasePlot().asSet(); } /** @@ -1112,13 +1060,7 @@ public class PlotSquared { * @return Set of Plot */ public Set getPlotsAbs(final UUID uuid) { - final Set plots = new HashSet<>(); - forEachPlot(value -> { - if (value.isOwnerAbs(uuid)) { - plots.add(value); - } - }); - return Collections.unmodifiableSet(plots); + return PlotQuery.newQuery().ownedBy(uuid).asSet(); } /** @@ -1620,7 +1562,6 @@ public class PlotSquared { // Close the connection DBFunc.close(); - UUIDHandler.handleShutdown(); } catch (NullPointerException throwable) { throwable.printStackTrace(); PlotSquared.log("&cCould not close database connection!"); @@ -2014,6 +1955,23 @@ public class PlotSquared { return Collections.unmodifiableSet(set); } + /** + * Check if the chunk uses vanilla/non-PlotSquared generation + * + * @param world World name + * @param chunkCoordinates Chunk coordinates + * @return True if the chunk uses non-standard generation, false if not + */ + public boolean isNonStandardGeneration(@NotNull final String world, + @NotNull final BlockVector2 chunkCoordinates) { + final Location location = new Location(world, chunkCoordinates.getBlockX() << 4, 64, chunkCoordinates.getBlockZ() << 4); + final PlotArea area = plotAreaManager.getApplicablePlotArea(location); + if (area == null) { + return true; + } + return area.getTerrain() != PlotAreaTerrainType.NONE; + } + public boolean isAugmented(@NonNull final String world) { final PlotArea[] areas = plotAreaManager.getPlotAreas(world, null); return areas != null && (areas.length > 1 || areas[0].getType() != PlotAreaType.NORMAL); @@ -2103,16 +2061,7 @@ public class PlotSquared { */ public Set getPlotsByAlias(@Nullable final String alias, @NonNull final String worldname) { - final Set result = new HashSet<>(); - if (alias != null) { - for (final Plot plot : getPlots()) { - if (alias.equals(plot.getAlias()) && (worldname == null || worldname - .equals(plot.getWorldName()))) { - result.add(plot); - } - } - } - return Collections.unmodifiableSet(result); + return PlotQuery.newQuery().inWorld(worldname).withAlias(alias).asSet(); } public Set getPlotAreas(final String world, final CuboidRegion region) { diff --git a/Core/src/main/java/com/plotsquared/core/api/PlotAPI.java b/Core/src/main/java/com/plotsquared/core/api/PlotAPI.java index 70bd11673..3991643a3 100644 --- a/Core/src/main/java/com/plotsquared/core/api/PlotAPI.java +++ b/Core/src/main/java/com/plotsquared/core/api/PlotAPI.java @@ -38,8 +38,6 @@ import com.plotsquared.core.util.ChunkManager; import com.plotsquared.core.util.EventDispatcher; import com.plotsquared.core.util.MainUtil; import com.plotsquared.core.util.SchematicHandler; -import com.plotsquared.core.util.uuid.UUIDHandler; -import com.plotsquared.core.util.uuid.UUIDWrapper; import lombok.NoArgsConstructor; import java.util.Collections; @@ -60,9 +58,7 @@ import java.util.UUID; * * @version 5 */ -@SuppressWarnings({"unused", "WeakerAccess"}) -@NoArgsConstructor -public class PlotAPI { +@SuppressWarnings({"unused", "WeakerAccess"}) @NoArgsConstructor public class PlotAPI { /** * Gets all plots. @@ -140,17 +136,6 @@ public class PlotAPI { return GlobalBlockQueue.IMP; } - /** - * UUIDWrapper class has basic methods for getting UUIDS. It's recommended - * to use the UUIDHandler class instead. - * - * @return UUIDWrapper - * @see UUIDWrapper - */ - public UUIDWrapper getUUIDWrapper() { - return UUIDHandler.getUUIDWrapper(); - } - /** * SchematicHandler class contains methods related to pasting, reading * and writing schematics. diff --git a/Core/src/main/java/com/plotsquared/core/backup/PlayerBackupProfile.java b/Core/src/main/java/com/plotsquared/core/backup/PlayerBackupProfile.java index 8853f3dff..c71057ab5 100644 --- a/Core/src/main/java/com/plotsquared/core/backup/PlayerBackupProfile.java +++ b/Core/src/main/java/com/plotsquared/core/backup/PlayerBackupProfile.java @@ -142,7 +142,7 @@ public class PlayerBackupProfile implements BackupProfile { } final List plots = Collections.singletonList(plot); final boolean result = SchematicHandler.manager.exportAll(plots, getBackupDirectory().toFile(), - "%world%-%id%-%owner%-" + System.currentTimeMillis(), () -> + "%world%-%id%-" + System.currentTimeMillis(), () -> future.complete(new Backup(this, System.currentTimeMillis(), null))); if (!result) { future.completeExceptionally(new RuntimeException("Failed to complete the backup")); diff --git a/Core/src/main/java/com/plotsquared/core/command/Add.java b/Core/src/main/java/com/plotsquared/core/command/Add.java index bc4905c68..6d86f7532 100644 --- a/Core/src/main/java/com/plotsquared/core/command/Add.java +++ b/Core/src/main/java/com/plotsquared/core/command/Add.java @@ -32,13 +32,16 @@ import com.plotsquared.core.player.PlotPlayer; import com.plotsquared.core.plot.Plot; import com.plotsquared.core.util.MainUtil; import com.plotsquared.core.util.Permissions; +import com.plotsquared.core.util.TabCompletions; import com.plotsquared.core.util.task.RunnableVal2; import com.plotsquared.core.util.task.RunnableVal3; +import java.util.Collection; +import java.util.Collections; import java.util.Iterator; -import java.util.Set; import java.util.UUID; import java.util.concurrent.CompletableFuture; +import java.util.concurrent.TimeoutException; @CommandDeclaration(command = "add", description = "Allow a user to build in a plot while the plot owner is online.", @@ -53,7 +56,7 @@ public class Add extends Command { } @Override - public CompletableFuture execute(final PlotPlayer player, String[] args, + public CompletableFuture execute(final PlotPlayer player, String[] args, RunnableVal3 confirm, RunnableVal2 whenDone) throws CommandException { final Plot plot = check(player.getCurrentPlot(), Captions.NOT_IN_PLOT); @@ -62,51 +65,73 @@ public class Add extends Command { .hasPermission(player, Captions.PERMISSION_ADMIN_COMMAND_TRUST), Captions.NO_PLOT_PERMS); checkTrue(args.length == 1, Captions.COMMAND_SYNTAX, getUsage()); - final Set uuids = MainUtil.getUUIDsFromString(args[0]); - checkTrue(!uuids.isEmpty(), Captions.INVALID_PLAYER, args[0]); - Iterator iterator = uuids.iterator(); - int size = plot.getTrusted().size() + plot.getMembers().size(); - while (iterator.hasNext()) { - UUID uuid = iterator.next(); - if (uuid == DBFunc.EVERYONE && !( - Permissions.hasPermission(player, Captions.PERMISSION_TRUST_EVERYONE) || Permissions - .hasPermission(player, Captions.PERMISSION_ADMIN_COMMAND_TRUST))) { - MainUtil.sendMessage(player, Captions.INVALID_PLAYER, MainUtil.getName(uuid)); - iterator.remove(); - continue; - } - if (plot.isOwner(uuid)) { - MainUtil.sendMessage(player, Captions.ALREADY_ADDED, MainUtil.getName(uuid)); - iterator.remove(); - continue; - } - if (plot.getMembers().contains(uuid)) { - MainUtil.sendMessage(player, Captions.ALREADY_ADDED, MainUtil.getName(uuid)); - iterator.remove(); - continue; - } - size += plot.getTrusted().contains(uuid) ? 0 : 1; - } - checkTrue(!uuids.isEmpty(), null); - checkTrue(size <= plot.getArea().getMaxPlotMembers() || Permissions - .hasPermission(player, Captions.PERMISSION_ADMIN_COMMAND_TRUST), - Captions.PLOT_MAX_MEMBERS); - // Success - confirm.run(this, () -> { - for (UUID uuid : uuids) { - if (uuid != DBFunc.EVERYONE) { - if (!plot.removeTrusted(uuid)) { - if (plot.getDenied().contains(uuid)) { - plot.removeDenied(uuid); - } - } - } - plot.addMember(uuid); - PlotSquared.get().getEventDispatcher().callMember(player, plot, uuid, true); - MainUtil.sendMessage(player, Captions.MEMBER_ADDED); - } - }, null); - return CompletableFuture.completedFuture(true); + final CompletableFuture future = new CompletableFuture<>(); + MainUtil.getUUIDsFromString(args[0], (uuids, throwable) -> { + if (throwable != null) { + if (throwable instanceof TimeoutException) { + Captions.FETCHING_PLAYERS_TIMEOUT.send(player); + } else { + Captions.INVALID_PLAYER.send(player, args[0]); + } + future.completeExceptionally(throwable); + return; + } else { + try { + checkTrue(!uuids.isEmpty(), Captions.INVALID_PLAYER, args[0]); + Iterator iterator = uuids.iterator(); + int size = plot.getTrusted().size() + plot.getMembers().size(); + while (iterator.hasNext()) { + UUID uuid = iterator.next(); + if (uuid == DBFunc.EVERYONE && !( + Permissions.hasPermission(player, Captions.PERMISSION_TRUST_EVERYONE) || Permissions + .hasPermission(player, Captions.PERMISSION_ADMIN_COMMAND_TRUST))) { + MainUtil.sendMessage(player, Captions.INVALID_PLAYER, MainUtil.getName(uuid)); + iterator.remove(); + continue; + } + if (plot.isOwner(uuid)) { + MainUtil.sendMessage(player, Captions.ALREADY_ADDED, MainUtil.getName(uuid)); + iterator.remove(); + continue; + } + if (plot.getMembers().contains(uuid)) { + MainUtil.sendMessage(player, Captions.ALREADY_ADDED, MainUtil.getName(uuid)); + iterator.remove(); + continue; + } + size += plot.getTrusted().contains(uuid) ? 0 : 1; + } + checkTrue(!uuids.isEmpty(), null); + checkTrue(size <= plot.getArea().getMaxPlotMembers() || Permissions.hasPermission(player, Captions.PERMISSION_ADMIN_COMMAND_TRUST), + Captions.PLOT_MAX_MEMBERS); + // Success + confirm.run(this, () -> { + for (UUID uuid : uuids) { + if (uuid != DBFunc.EVERYONE) { + if (!plot.removeTrusted(uuid)) { + if (plot.getDenied().contains(uuid)) { + plot.removeDenied(uuid); + } + } + } + plot.addMember(uuid); + PlotSquared.get().getEventDispatcher().callMember(player, plot, uuid, true); + MainUtil.sendMessage(player, Captions.MEMBER_ADDED); + } + }, null); + } catch (final Throwable exception) { + future.completeExceptionally(exception); + return; + } + } + future.complete(true); + }); + return future; } + + @Override public Collection tab(final PlotPlayer player, final String[] args, final boolean space) { + return TabCompletions.completePlayers(String.join(",", args).trim(), Collections.emptyList()); + } + } diff --git a/Core/src/main/java/com/plotsquared/core/command/Alias.java b/Core/src/main/java/com/plotsquared/core/command/Alias.java index b1d8d8161..59c0da49c 100644 --- a/Core/src/main/java/com/plotsquared/core/command/Alias.java +++ b/Core/src/main/java/com/plotsquared/core/command/Alias.java @@ -33,19 +33,26 @@ import com.plotsquared.core.plot.Plot; import com.plotsquared.core.util.MainUtil; import com.plotsquared.core.util.MathMan; import com.plotsquared.core.util.Permissions; -import com.plotsquared.core.util.StringWrapper; -import com.plotsquared.core.util.uuid.UUIDHandler; +import com.plotsquared.core.util.query.PlotQuery; -@CommandDeclaration(command = "setalias", +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.concurrent.TimeoutException; + +@CommandDeclaration(command = "alias", permission = "plots.alias", description = "Set the plot name", usage = "/plot alias ", - aliases = {"alias", "sa", "name", "rename", "setname", "seta", "nameplot"}, + aliases = {"setalias", "sa", "name", "rename", "setname", "seta", "nameplot"}, category = CommandCategory.SETTINGS, requiredType = RequiredType.PLAYER) public class Alias extends SubCommand { + private static final Command SET_COMMAND = new Command(null, false, "set", null, RequiredType.NONE, null) {}; + private static final Command REMOVE_COMMAND = new Command(null, false, "remove", null, RequiredType.NONE, null) {}; - @Override public boolean onCommand(PlotPlayer player, String[] args) { + @Override public boolean onCommand(PlotPlayer player, String[] args) { if (args.length == 0) { Captions.COMMAND_SYNTAX.send(player, getUsage()); @@ -63,13 +70,11 @@ public class Alias extends SubCommand { return false; } - if (!plot.isOwner(player.getUUID())) { - MainUtil.sendMessage(player, Captions.NO_PLOT_PERMS); - return false; - } - boolean result = false; + boolean owner = plot.isOwner(player.getUUID()); + boolean permission; + boolean admin; switch (args[0].toLowerCase()) { case "set": if (args.length != 2) { @@ -77,17 +82,34 @@ public class Alias extends SubCommand { return false; } - if (canExecuteCommand(player, Captions.PERMISSION_ALIAS_SET, false) - || canExecuteCommand(player, Captions.PERMISSION_ALIAS_SET_OBSOLETE, false)) { - result = setAlias(player, plot, args[1]); + permission = isPermitted(player, Captions.PERMISSION_ALIAS_SET) + || isPermitted(player, Captions.PERMISSION_ALIAS_SET_OBSOLETE); + admin = isPermitted(player, Captions.PERMISSION_ADMIN_ALIAS_SET); + if (!admin && !owner) { + MainUtil.sendMessage(player, Captions.NO_PLOT_PERMS); + return false; + } + if (permission) { // is either admin or owner + setAlias(player, plot, args[1]); + return true; } else { - MainUtil.sendMessage(player, Captions.NO_PERMISSION); + MainUtil.sendMessage(player, Captions.NO_PERMISSION, + Captions.PERMISSION_ALIAS_SET.getTranslated()); } break; case "remove": - if (canExecuteCommand(player, Captions.PERMISSION_ALIAS_REMOVE, true)) { + permission = isPermitted(player, Captions.PERMISSION_ALIAS_REMOVE); + admin = isPermitted(player, Captions.PERMISSION_ADMIN_ALIAS_REMOVE); + if (!admin && !owner) { + MainUtil.sendMessage(player, Captions.NO_PLOT_PERMS); + return false; + } + if (permission) { result = removeAlias(player, plot); + } else { + MainUtil.sendMessage(player, Captions.NO_PERMISSION, + Captions.PERMISSION_ALIAS_REMOVE.getTranslated()); } break; default: @@ -98,54 +120,58 @@ public class Alias extends SubCommand { return result; } - - private boolean setAlias(PlotPlayer player, Plot plot, String alias) { - if (alias.isEmpty()) { - Captions.COMMAND_SYNTAX.send(player, getUsage()); - return false; - } - if (alias.length() >= 50) { - MainUtil.sendMessage(player, Captions.ALIAS_TOO_LONG); - return false; - } - if (alias.contains(" ")) { - Captions.NOT_VALID_VALUE.send(player); - return false; - } - if (MathMan.isInteger(alias)) { - Captions.NOT_VALID_VALUE.send(player); - return false; - } - for (Plot p : PlotSquared.get().getPlots(plot.getArea())) { - if (p.getAlias().equalsIgnoreCase(alias)) { - MainUtil.sendMessage(player, Captions.ALIAS_IS_TAKEN); - return false; + @Override + public Collection tab(PlotPlayer player, String[] args, boolean space) { + final List commands = new ArrayList<>(2); + if (args.length == 1) { + if ("set".startsWith(args[0])) { + commands.add(SET_COMMAND); } + if ("remove".startsWith(args[0])) { + commands.add(REMOVE_COMMAND); + } + return commands; } - if (UUIDHandler.nameExists(new StringWrapper(alias)) || PlotSquared.get() - .hasPlotArea(alias)) { - MainUtil.sendMessage(player, Captions.ALIAS_IS_TAKEN); - return false; - } - plot.setAlias(alias); - MainUtil.sendMessage(player, - Captions.ALIAS_SET_TO.getTranslated().replaceAll("%alias%", alias)); - return true; + return Collections.emptySet(); } - private boolean removeAlias(PlotPlayer player, Plot plot) { + private void setAlias(PlotPlayer player, Plot plot, String alias) { + if (alias.isEmpty()) { + Captions.COMMAND_SYNTAX.send(player, getUsage()); + } else if (alias.length() >= 50) { + MainUtil.sendMessage(player, Captions.ALIAS_TOO_LONG); + } else if (alias.contains(" ")) { + Captions.NOT_VALID_VALUE.send(player); + } else if (MathMan.isInteger(alias)) { + Captions.NOT_VALID_VALUE.send(player); + } else { + if (PlotQuery.newQuery().inArea(plot.getArea()) + .withAlias(alias) + .anyMatch()) { + MainUtil.sendMessage(player, Captions.ALIAS_IS_TAKEN); + return; + } + PlotSquared.get().getImpromptuUUIDPipeline().getSingle(alias, ((uuid, throwable) -> { + if (throwable instanceof TimeoutException) { + MainUtil.sendMessage(player, Captions.FETCHING_PLAYERS_TIMEOUT); + } else if (uuid != null) { + MainUtil.sendMessage(player, Captions.ALIAS_IS_TAKEN); + } else { + plot.setAlias(alias); + MainUtil.sendMessage(player, + Captions.ALIAS_SET_TO.getTranslated().replaceAll("%alias%", alias)); + } + })); + } + } + + private boolean removeAlias(PlotPlayer player, Plot plot) { plot.setAlias(null); MainUtil.sendMessage(player, Captions.ALIAS_REMOVED.getTranslated()); return true; } - private boolean canExecuteCommand(PlotPlayer player, Captions caption, boolean sendMessage) { - if (!Permissions.hasPermission(player, caption)) { - if (sendMessage) { - MainUtil.sendMessage(player, Captions.NO_PERMISSION); - } - return false; - } - return true; + private boolean isPermitted(PlotPlayer player, Captions caption) { + return Permissions.hasPermission(player, caption); } } diff --git a/Core/src/main/java/com/plotsquared/core/command/Area.java b/Core/src/main/java/com/plotsquared/core/command/Area.java index f5d494868..383076f0d 100644 --- a/Core/src/main/java/com/plotsquared/core/command/Area.java +++ b/Core/src/main/java/com/plotsquared/core/command/Area.java @@ -33,26 +33,41 @@ import com.plotsquared.core.events.TeleportCause; import com.plotsquared.core.generator.AugmentedUtils; import com.plotsquared.core.generator.HybridPlotWorld; import com.plotsquared.core.location.Location; +import com.plotsquared.core.player.ConsolePlayer; import com.plotsquared.core.player.PlotPlayer; import com.plotsquared.core.plot.PlotArea; import com.plotsquared.core.plot.PlotAreaTerrainType; import com.plotsquared.core.plot.PlotAreaType; import com.plotsquared.core.plot.PlotId; -import com.plotsquared.core.plot.SetupObject; import com.plotsquared.core.plot.message.PlotMessage; +import com.plotsquared.core.setup.PlotAreaBuilder; import com.plotsquared.core.util.MainUtil; import com.plotsquared.core.util.MathMan; import com.plotsquared.core.util.Permissions; import com.plotsquared.core.util.RegionManager; import com.plotsquared.core.util.RegionUtil; +import com.plotsquared.core.util.SchematicHandler; import com.plotsquared.core.util.SetupUtils; import com.plotsquared.core.util.StringMan; import com.plotsquared.core.util.WorldUtil; import com.plotsquared.core.util.task.RunnableVal; import com.plotsquared.core.util.task.RunnableVal3; +import com.sk89q.worldedit.EditSession; +import com.sk89q.worldedit.LocalSession; +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.entity.Player; +import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard; +import com.sk89q.worldedit.extent.clipboard.io.BuiltInClipboardFormat; +import com.sk89q.worldedit.extent.clipboard.io.ClipboardWriter; +import com.sk89q.worldedit.function.operation.ForwardExtentCopy; +import com.sk89q.worldedit.function.operation.Operations; import com.sk89q.worldedit.math.BlockVector2; +import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.regions.CuboidRegion; +import com.sk89q.worldedit.regions.Region; +import java.io.File; +import java.io.FileOutputStream; import java.io.IOException; import java.util.ArrayList; import java.util.Objects; @@ -68,12 +83,140 @@ import java.util.Set; confirmation = true) public class Area extends SubCommand { - @Override public boolean onCommand(final PlotPlayer player, String[] args) { + @Override public boolean onCommand(final PlotPlayer player, String[] args) { if (args.length == 0) { Captions.COMMAND_SYNTAX.send(player, getUsage()); return false; } switch (args[0].toLowerCase()) { + case "single": + if (player instanceof ConsolePlayer) { + MainUtil.sendMessage(player, Captions.IS_CONSOLE); + return false; + } + if (!Permissions.hasPermission(player, Captions.PERMISSION_AREA_CREATE)) { + MainUtil.sendMessage(player, Captions.NO_PERMISSION, Captions.PERMISSION_AREA_CREATE); + return false; + } + if (args.length < 2) { + MainUtil.sendMessage(player, Captions.SINGLE_AREA_NEEDS_NAME); + return false; + } + final PlotArea existingArea = PlotSquared.get().getPlotArea(player.getLocation().getWorld(), args[1]); + if (existingArea != null && existingArea.getId().equalsIgnoreCase(args[1])) { + MainUtil.sendMessage(player, Captions.SINGLE_AREA_NAME_TAKEN); + return false; + } + final LocalSession localSession = WorldEdit.getInstance().getSessionManager().getIfPresent(player.toActor()); + if (localSession == null) { + MainUtil.sendMessage(player, Captions.SINGLE_AREA_MISSING_SELECTION); + return false; + } + Region playerSelectedRegion = null; + try { + playerSelectedRegion = localSession.getSelection(((Player) player.toActor()).getWorld()); + } catch (final Exception ignored) {} + if (playerSelectedRegion == null) { + MainUtil.sendMessage(player, Captions.SINGLE_AREA_MISSING_SELECTION); + return false; + } + if (playerSelectedRegion.getWidth() != playerSelectedRegion.getLength()) { + MainUtil.sendMessage(player, Captions.SINGLE_AREA_NOT_SQUARE); + return false; + } + if (PlotSquared.get().getPlotAreaManager().getPlotAreas( + Objects.requireNonNull(playerSelectedRegion.getWorld()).getName(), CuboidRegion.makeCuboid(playerSelectedRegion)).length != 0) { + MainUtil.sendMessage(player, Captions.SINGLE_AREA_OVERLAPPING); + } + // Alter the region + final BlockVector3 playerSelectionMin = playerSelectedRegion.getMinimumPoint(); + final BlockVector3 playerSelectionMax = playerSelectedRegion.getMaximumPoint(); + // Create a new selection that spans the entire vertical range of the world + final CuboidRegion selectedRegion = new CuboidRegion(playerSelectedRegion.getWorld(), + BlockVector3.at(playerSelectionMin.getX(), 0, playerSelectionMin.getZ()), + BlockVector3.at(playerSelectionMax.getX(), 255, playerSelectionMax.getZ())); + // There's only one plot in the area... + final PlotId plotId = new PlotId(1, 1); + final HybridPlotWorld hybridPlotWorld = new HybridPlotWorld(player.getLocation().getWorld(), args[1], + Objects.requireNonNull(PlotSquared.imp()).getDefaultGenerator(), plotId, plotId); + // Plot size is the same as the region width + hybridPlotWorld.PLOT_WIDTH = hybridPlotWorld.SIZE = (short) selectedRegion.getWidth(); + // We use a schematic generator + hybridPlotWorld.setTerrain(PlotAreaTerrainType.NONE); + // It is always a partial plot world + hybridPlotWorld.setType(PlotAreaType.PARTIAL); + // We save the schematic :D + hybridPlotWorld.PLOT_SCHEMATIC = true; + // Set the road width to 0 + hybridPlotWorld.ROAD_WIDTH = hybridPlotWorld.ROAD_OFFSET_X = hybridPlotWorld.ROAD_OFFSET_Z = 0; + // Set the plot height to the selection height + hybridPlotWorld.PLOT_HEIGHT = hybridPlotWorld.ROAD_HEIGHT = hybridPlotWorld.WALL_HEIGHT = playerSelectionMin.getBlockY(); + // No sign plz + hybridPlotWorld.setAllowSigns(false); + final File parentFile = MainUtil.getFile(PlotSquared.imp().getDirectory(), "schematics" + File.separator + + "GEN_ROAD_SCHEMATIC" + File.separator + hybridPlotWorld.getWorldName() + File.separator + + hybridPlotWorld.getId()); + if (!parentFile.exists() && !parentFile.mkdirs()) { + MainUtil.sendMessage(player, Captions.SINGLE_AREA_COULD_NOT_MAKE_DIRECTORIES); + return false; + } + final File file = new File(parentFile, "plot.schem"); + try (final ClipboardWriter clipboardWriter = BuiltInClipboardFormat.SPONGE_SCHEMATIC.getWriter(new FileOutputStream(file))) { + final BlockArrayClipboard clipboard = new BlockArrayClipboard(selectedRegion); + final EditSession editSession = WorldEdit.getInstance().getEditSessionFactory().getEditSession(selectedRegion.getWorld(), -1); + final ForwardExtentCopy forwardExtentCopy = new ForwardExtentCopy(editSession, selectedRegion, clipboard, selectedRegion.getMinimumPoint()); + forwardExtentCopy.setCopyingBiomes(true); + forwardExtentCopy.setCopyingEntities(true); + Operations.complete(forwardExtentCopy); + clipboardWriter.write(clipboard); + } catch (final Exception e) { + MainUtil.sendMessage(player, Captions.SINGLE_AREA_FAILED_TO_SAVE); + e.printStackTrace(); + return false; + } + + // Setup schematic + try { + hybridPlotWorld.setupSchematics(); + } catch (final SchematicHandler.UnsupportedFormatException e) { + e.printStackTrace(); + } + + // Calculate the offset + final BlockVector3 singlePos1 = selectedRegion.getMinimumPoint(); + + // Now the schematic is saved, which is wonderful! + PlotAreaBuilder singleBuilder = PlotAreaBuilder.ofPlotArea(hybridPlotWorld) + .plotManager(PlotSquared.imp().getPluginName()) + .generatorName(PlotSquared.imp().getPluginName()) + .maximumId(plotId) + .minimumId(plotId); + Runnable singleRun = () -> { + final String path = + "worlds." + hybridPlotWorld.getWorldName() + ".areas." + hybridPlotWorld.getId() + '-' + + singleBuilder.minimumId() + '-' + singleBuilder.maximumId(); + final int offsetX = singlePos1.getX(); + final int offsetZ = singlePos1.getZ(); + if (offsetX != 0) { + PlotSquared.get().worlds + .set(path + ".road.offset.x", offsetX); + } + if (offsetZ != 0) { + PlotSquared.get().worlds + .set(path + ".road.offset.z", offsetZ); + } + final String world = SetupUtils.manager.setupWorld(singleBuilder); + if (WorldUtil.IMP.isWorld(world)) { + PlotSquared.get().loadWorld(world, null); + MainUtil.sendMessage(player, Captions.SINGLE_AREA_CREATED); + } else { + MainUtil.sendMessage(player, + "An error occurred while creating the world: " + hybridPlotWorld + .getWorldName()); + } + }; + singleRun.run(); + return true; case "c": case "setup": case "create": @@ -138,19 +281,14 @@ public class Area extends SubCommand { .send(player, areas.iterator().next().toString()); return false; } - final SetupObject object = new SetupObject(); - object.world = area.getWorldName(); - object.id = area.getId(); - object.terrain = area.getTerrain(); - object.type = area.getType(); - object.min = new PlotId(1, 1); - object.max = new PlotId(numX, numZ); - object.plotManager = PlotSquared.imp().getPluginName(); - object.setupGenerator = PlotSquared.imp().getPluginName(); - object.step = area.getSettingNodes(); + PlotAreaBuilder builder = PlotAreaBuilder.ofPlotArea(area) + .plotManager(PlotSquared.imp().getPluginName()) + .generatorName(PlotSquared.imp().getPluginName()) + .minimumId(new PlotId(1, 1)) + .maximumId(new PlotId(numX, numZ)); final String path = "worlds." + area.getWorldName() + ".areas." + area.getId() + '-' - + object.min + '-' + object.max; + + builder.minimumId() + '-' + builder.maximumId(); Runnable run = () -> { if (offsetX != 0) { PlotSquared.get().worlds @@ -160,7 +298,7 @@ public class Area extends SubCommand { PlotSquared.get().worlds .set(path + ".road.offset.z", offsetZ); } - final String world = SetupUtils.manager.setupWorld(object); + final String world = SetupUtils.manager.setupWorld(builder); if (WorldUtil.IMP.isWorld(world)) { PlotSquared.get().loadWorld(world, null); Captions.SETUP_FINISHED.send(player); @@ -198,9 +336,9 @@ public class Area extends SubCommand { } else { id = null; } - final SetupObject object = new SetupObject(); - object.world = split[0]; - final HybridPlotWorld pa = new HybridPlotWorld(object.world, id, + PlotAreaBuilder builder = new PlotAreaBuilder(); + builder.worldName(split[0]); + final HybridPlotWorld pa = new HybridPlotWorld(builder.worldName(), id, PlotSquared.get().IMP.getDefaultGenerator(), null, null); PlotArea other = PlotSquared.get().getPlotArea(pa.getWorldName(), id); if (other != null && Objects.equals(pa.getId(), other.getId())) { @@ -262,13 +400,13 @@ public class Area extends SubCommand { pa.setTerrain(PlotAreaTerrainType.fromString(pair[1]) .orElseThrow(() -> new IllegalArgumentException( pair[1] + " is not a valid terrain."))); - object.terrain = pa.getTerrain(); + builder.terrainType(pa.getTerrain()); break; case "type": pa.setType(PlotAreaType.fromString(pair[1]).orElseThrow( () -> new IllegalArgumentException( pair[1] + " is not a valid type."))); - object.type = pa.getType(); + builder.plotAreaType(pa.getType()); break; default: Captions.COMMAND_SYNTAX.send(player, getCommandString() @@ -290,9 +428,9 @@ public class Area extends SubCommand { PlotSquared.get().worlds.getConfigurationSection(path); pa.saveConfiguration(section); pa.loadConfiguration(section); - object.plotManager = PlotSquared.imp().getPluginName(); - object.setupGenerator = PlotSquared.imp().getPluginName(); - String world = SetupUtils.manager.setupWorld(object); + builder.plotManager(PlotSquared.imp().getPluginName()); + builder.generatorName(PlotSquared.imp().getPluginName()); + String world = SetupUtils.manager.setupWorld(builder); if (WorldUtil.IMP.isWorld(world)) { Captions.SETUP_FINISHED.send(player); player.teleport(WorldUtil.IMP.getSpawn(world), @@ -327,9 +465,9 @@ public class Area extends SubCommand { TeleportCause.COMMAND); } } else { - object.terrain = PlotAreaTerrainType.NONE; - object.type = PlotAreaType.NORMAL; - SetupUtils.manager.setupWorld(object); + builder.terrainType(PlotAreaTerrainType.NONE); + builder.plotAreaType(PlotAreaType.NORMAL); + SetupUtils.manager.setupWorld(builder); player.teleport(WorldUtil.IMP.getSpawn(pa.getWorldName()), TeleportCause.COMMAND); } diff --git a/Core/src/main/java/com/plotsquared/core/command/Auto.java b/Core/src/main/java/com/plotsquared/core/command/Auto.java index 518a017d6..4c75de3f8 100644 --- a/Core/src/main/java/com/plotsquared/core/command/Auto.java +++ b/Core/src/main/java/com/plotsquared/core/command/Auto.java @@ -154,12 +154,12 @@ public class Auto extends SubCommand { () -> autoClaimFromDatabase(player, area, plot.getId(), whenDone)); } - @Override public boolean onCommand(final PlotPlayer player, String[] args) { + @Override public boolean onCommand(final PlotPlayer player, String[] args) { PlotArea plotarea = player.getApplicablePlotArea(); if (plotarea == null) { - if (EconHandler.manager != null) { + if (EconHandler.getEconHandler() != null) { for (PlotArea area : PlotSquared.get().getPlotAreaManager().getAllPlotAreas()) { - if (EconHandler.manager + if (EconHandler.getEconHandler() .hasPermission(area.getWorldName(), player.getName(), "plots.auto")) { if (plotarea != null) { plotarea = null; @@ -253,18 +253,18 @@ public class Auto extends SubCommand { return true; } } - if (EconHandler.manager != null && plotarea.useEconomy()) { + if (EconHandler.getEconHandler() != null && plotarea.useEconomy()) { Expression costExp = plotarea.getPrices().get("claim"); double cost = costExp.evaluate((double) (Settings.Limit.GLOBAL ? player.getPlotCount() : player.getPlotCount(plotarea.getWorldName()))); cost = (size_x * size_z) * cost; if (cost > 0d) { - if (!force && EconHandler.manager.getMoney(player) < cost) { + if (!force && EconHandler.getEconHandler().getMoney(player) < cost) { sendMessage(player, Captions.CANNOT_AFFORD_PLOT, "" + cost); return true; } - EconHandler.manager.withdrawMoney(player, cost); + EconHandler.getEconHandler().withdrawMoney(player, cost); sendMessage(player, Captions.REMOVED_BALANCE, cost + ""); } } diff --git a/Core/src/main/java/com/plotsquared/core/command/Backup.java b/Core/src/main/java/com/plotsquared/core/command/Backup.java index e06d8208a..944eaaf6b 100644 --- a/Core/src/main/java/com/plotsquared/core/command/Backup.java +++ b/Core/src/main/java/com/plotsquared/core/command/Backup.java @@ -70,7 +70,7 @@ public final class Backup extends Command { } @Override - public CompletableFuture execute(PlotPlayer player, String[] args, + public CompletableFuture execute(PlotPlayer player, String[] args, RunnableVal3 confirm, RunnableVal2 whenDone) throws CommandException { if (args.length == 0 || !Arrays.asList("save", "list", "load") diff --git a/Core/src/main/java/com/plotsquared/core/command/Buy.java b/Core/src/main/java/com/plotsquared/core/command/Buy.java index a660a39a1..337801385 100644 --- a/Core/src/main/java/com/plotsquared/core/command/Buy.java +++ b/Core/src/main/java/com/plotsquared/core/command/Buy.java @@ -37,7 +37,6 @@ import com.plotsquared.core.util.EconHandler; import com.plotsquared.core.util.MainUtil; import com.plotsquared.core.util.task.RunnableVal2; import com.plotsquared.core.util.task.RunnableVal3; -import com.plotsquared.core.util.uuid.UUIDHandler; import java.util.Set; import java.util.concurrent.CompletableFuture; @@ -55,11 +54,11 @@ public class Buy extends Command { } @Override - public CompletableFuture execute(final PlotPlayer player, String[] args, + public CompletableFuture execute(final PlotPlayer player, String[] args, RunnableVal3 confirm, final RunnableVal2 whenDone) { - check(EconHandler.manager, Captions.ECON_DISABLED); + check(EconHandler.getEconHandler(), Captions.ECON_DISABLED); final Plot plot; if (args.length != 0) { checkTrue(args.length == 1, Captions.COMMAND_SYNTAX, getUsage()); @@ -82,10 +81,10 @@ public class Buy extends Command { // Success confirm.run(this, () -> { Captions.REMOVED_BALANCE.send(player, price); - EconHandler.manager - .depositMoney(UUIDHandler.getUUIDWrapper().getOfflinePlayer(plot.getOwnerAbs()), - price); - PlotPlayer owner = UUIDHandler.getPlayer(plot.getOwnerAbs()); + + EconHandler.getEconHandler().depositMoney(PlotSquared.imp().getPlayerManager().getOfflinePlayer(plot.getOwnerAbs()), price); + + PlotPlayer owner = PlotSquared.imp().getPlayerManager().getPlayerIfExists(plot.getOwnerAbs()); if (owner != null) { Captions.PLOT_SOLD.send(owner, plot.getId(), player.getName(), price); } diff --git a/Core/src/main/java/com/plotsquared/core/command/Caps.java b/Core/src/main/java/com/plotsquared/core/command/Caps.java index 372e415b8..b56d33dc0 100644 --- a/Core/src/main/java/com/plotsquared/core/command/Caps.java +++ b/Core/src/main/java/com/plotsquared/core/command/Caps.java @@ -50,7 +50,7 @@ import static com.plotsquared.core.util.entity.EntityCategories.CAP_VEHICLE; usage = "/plot caps") public class Caps extends SubCommand { - @Override public boolean onCommand(final PlotPlayer player, final String[] args) { + @Override public boolean onCommand(final PlotPlayer player, final String[] args) { final Plot plot = player.getCurrentPlot(); if (plot == null) { return Captions.NOT_IN_PLOT.send(player); diff --git a/Core/src/main/java/com/plotsquared/core/command/Chat.java b/Core/src/main/java/com/plotsquared/core/command/Chat.java index e8c9e395c..3bf04f223 100644 --- a/Core/src/main/java/com/plotsquared/core/command/Chat.java +++ b/Core/src/main/java/com/plotsquared/core/command/Chat.java @@ -37,7 +37,7 @@ import com.plotsquared.core.util.MainUtil; requiredType = RequiredType.PLAYER) public class Chat extends SubCommand { - @Override public boolean onCommand(PlotPlayer player, String[] args) { + @Override public boolean onCommand(PlotPlayer player, String[] args) { if (player.getPlotAreaAbs().isForcingPlotChat()) { MainUtil.sendMessage(player, Captions.PLOT_CHAT_FORCED); return true; diff --git a/Core/src/main/java/com/plotsquared/core/command/Claim.java b/Core/src/main/java/com/plotsquared/core/command/Claim.java index 2f4ee7781..481a25bf5 100644 --- a/Core/src/main/java/com/plotsquared/core/command/Claim.java +++ b/Core/src/main/java/com/plotsquared/core/command/Claim.java @@ -54,7 +54,7 @@ import com.plotsquared.core.util.task.TaskManager; usage = "/plot claim") public class Claim extends SubCommand { - @Override public boolean onCommand(final PlotPlayer player, String[] args) { + @Override public boolean onCommand(final PlotPlayer player, String[] args) { String schematic = null; if (args.length >= 1) { schematic = args[0]; @@ -105,14 +105,14 @@ public class Claim extends SubCommand { } } } - if ((EconHandler.manager != null) && area.useEconomy() && !force) { + if ((EconHandler.getEconHandler() != null) && area.useEconomy() && !force) { Expression costExr = area.getPrices().get("claim"); double cost = costExr.evaluate((double) currentPlots); if (cost > 0d) { - if (EconHandler.manager.getMoney(player) < cost) { + if (EconHandler.getEconHandler().getMoney(player) < cost) { return sendMessage(player, Captions.CANNOT_AFFORD_PLOT, "" + cost); } - EconHandler.manager.withdrawMoney(player, cost); + EconHandler.getEconHandler().withdrawMoney(player, cost); sendMessage(player, Captions.REMOVED_BALANCE, cost + ""); } } diff --git a/Core/src/main/java/com/plotsquared/core/command/Clear.java b/Core/src/main/java/com/plotsquared/core/command/Clear.java index 5e8c2757a..9d8279eda 100644 --- a/Core/src/main/java/com/plotsquared/core/command/Clear.java +++ b/Core/src/main/java/com/plotsquared/core/command/Clear.java @@ -64,7 +64,7 @@ public class Clear extends Command { } @Override - public CompletableFuture execute(final PlotPlayer player, String[] args, + public CompletableFuture execute(final PlotPlayer player, String[] args, RunnableVal3 confirm, RunnableVal2 whenDone) throws CommandException { checkTrue(args.length == 0, Captions.COMMAND_SYNTAX, getUsage()); diff --git a/Core/src/main/java/com/plotsquared/core/command/Cluster.java b/Core/src/main/java/com/plotsquared/core/command/Cluster.java index ae220831e..557ba084b 100644 --- a/Core/src/main/java/com/plotsquared/core/command/Cluster.java +++ b/Core/src/main/java/com/plotsquared/core/command/Cluster.java @@ -39,12 +39,12 @@ import com.plotsquared.core.plot.PlotCluster; import com.plotsquared.core.plot.PlotId; import com.plotsquared.core.util.MainUtil; import com.plotsquared.core.util.Permissions; -import com.plotsquared.core.util.uuid.UUIDHandler; import java.util.ArrayList; import java.util.HashSet; import java.util.Set; import java.util.UUID; +import java.util.concurrent.TimeoutException; @CommandDeclaration(command = "cluster", aliases = "clusters", @@ -54,7 +54,7 @@ import java.util.UUID; description = "Manage a plot cluster") public class Cluster extends SubCommand { - @Override public boolean onCommand(PlotPlayer player, String[] args) { + @Override public boolean onCommand(PlotPlayer player, String[] args) { // list, create, delete, resize, invite, kick, leave, helpers, tp, sethome if (args.length == 0) { @@ -371,22 +371,29 @@ public class Cluster extends SubCommand { return false; } } - // check uuid - UUID uuid = UUIDHandler.getUUID(args[1], null); - if (uuid == null) { - MainUtil.sendMessage(player, Captions.INVALID_PLAYER, args[2]); - return false; - } - if (!cluster.isAdded(uuid)) { - // add the user if not added - cluster.invited.add(uuid); - DBFunc.setInvited(cluster, uuid); - PlotPlayer player2 = UUIDHandler.getPlayer(uuid); - if (player2 != null) { - MainUtil.sendMessage(player2, Captions.CLUSTER_INVITED, cluster.getName()); - } - } - MainUtil.sendMessage(player, Captions.CLUSTER_ADDED_USER); + + PlotSquared.get().getImpromptuUUIDPipeline() + .getSingle(args[1], (uuid, throwable) -> { + if (throwable instanceof TimeoutException) { + MainUtil.sendMessage(player, Captions.FETCHING_PLAYERS_TIMEOUT); + } else if (throwable != null) { + MainUtil.sendMessage(player, Captions.INVALID_PLAYER, args[1]); + } else { + if (!cluster.isAdded(uuid)) { + // add the user if not added + cluster.invited.add(uuid); + DBFunc.setInvited(cluster, uuid); + + final PlotPlayer otherPlayer = + PlotSquared.imp().getPlayerManager().getPlayerIfExists(uuid); + if (otherPlayer != null) { + MainUtil.sendMessage(otherPlayer, Captions.CLUSTER_INVITED, + cluster.getName()); + } + } + MainUtil.sendMessage(player, Captions.CLUSTER_ADDED_USER); + } + }); return true; } case "k": @@ -420,35 +427,43 @@ public class Cluster extends SubCommand { } } // check uuid - UUID uuid = UUIDHandler.getUUID(args[1], null); - if (uuid == null) { - MainUtil.sendMessage(player, Captions.INVALID_PLAYER, args[1]); - return false; - } - // Can't kick if the player is yourself, the owner, or not added to the cluster - if (uuid.equals(player.getUUID()) || uuid.equals(cluster.owner) || !cluster - .isAdded(uuid)) { - MainUtil.sendMessage(player, Captions.CANNOT_KICK_PLAYER, cluster.getName()); - return false; - } - if (cluster.helpers.contains(uuid)) { - cluster.helpers.remove(uuid); - DBFunc.removeHelper(cluster, uuid); - } - cluster.invited.remove(uuid); - DBFunc.removeInvited(cluster, uuid); - PlotPlayer player2 = UUIDHandler.getPlayer(uuid); - if (player2 != null) { - MainUtil.sendMessage(player2, Captions.CLUSTER_REMOVED, cluster.getName()); - } - for (Plot plot : new ArrayList<>( - PlotSquared.get().getPlots(player2.getLocation().getWorld(), uuid))) { - PlotCluster current = plot.getCluster(); - if (current != null && current.equals(cluster)) { - plot.unclaim(); - } - } - MainUtil.sendMessage(player2, Captions.CLUSTER_KICKED_USER); + PlotSquared.get().getImpromptuUUIDPipeline() + .getSingle(args[1], (uuid, throwable) -> { + if (throwable instanceof TimeoutException) { + MainUtil.sendMessage(player, Captions.FETCHING_PLAYERS_TIMEOUT); + } else if (throwable != null) { + MainUtil.sendMessage(player, Captions.INVALID_PLAYER, args[1]); + } else { + // Can't kick if the player is yourself, the owner, or not added to the cluster + if (uuid.equals(player.getUUID()) || uuid.equals(cluster.owner) + || !cluster.isAdded(uuid)) { + MainUtil.sendMessage(player, Captions.CANNOT_KICK_PLAYER, + cluster.getName()); + } else { + if (cluster.helpers.contains(uuid)) { + cluster.helpers.remove(uuid); + DBFunc.removeHelper(cluster, uuid); + } + cluster.invited.remove(uuid); + DBFunc.removeInvited(cluster, uuid); + + final PlotPlayer player2 = + PlotSquared.imp().getPlayerManager().getPlayerIfExists(uuid); + if (player2 != null) { + MainUtil.sendMessage(player2, Captions.CLUSTER_REMOVED, + cluster.getName()); + } + for (Plot plot : new ArrayList<>(PlotSquared.get() + .getPlots(player2.getLocation().getWorld(), uuid))) { + PlotCluster current = plot.getCluster(); + if (current != null && current.equals(cluster)) { + plot.unclaim(); + } + } + MainUtil.sendMessage(player2, Captions.CLUSTER_KICKED_USER); + } + } + }); return true; } case "quit": @@ -529,24 +544,29 @@ public class Cluster extends SubCommand { MainUtil.sendMessage(player, Captions.NOT_IN_CLUSTER); return false; } - UUID uuid = UUIDHandler.getUUID(args[2], null); - if (uuid == null) { - MainUtil.sendMessage(player, Captions.INVALID_PLAYER, args[2]); - return false; - } - if (args[1].equalsIgnoreCase("add")) { - cluster.helpers.add(uuid); - DBFunc.setHelper(cluster, uuid); - return MainUtil.sendMessage(player, Captions.CLUSTER_ADDED_HELPER); - } - if (args[1].equalsIgnoreCase("remove")) { - cluster.helpers.remove(uuid); - DBFunc.removeHelper(cluster, uuid); - return MainUtil.sendMessage(player, Captions.CLUSTER_REMOVED_HELPER); - } - MainUtil.sendMessage(player, Captions.COMMAND_SYNTAX, - "/plot cluster helpers "); - return false; + + PlotSquared.get().getImpromptuUUIDPipeline() + .getSingle(args[2], (uuid, throwable) -> { + if (throwable instanceof TimeoutException) { + MainUtil.sendMessage(player, Captions.FETCHING_PLAYERS_TIMEOUT); + } else if (throwable != null) { + MainUtil.sendMessage(player, Captions.INVALID_PLAYER, args[2]); + } else { + if (args[1].equalsIgnoreCase("add")) { + cluster.helpers.add(uuid); + DBFunc.setHelper(cluster, uuid); + MainUtil.sendMessage(player, Captions.CLUSTER_ADDED_HELPER); + } else if (args[1].equalsIgnoreCase("remove")) { + cluster.helpers.remove(uuid); + DBFunc.removeHelper(cluster, uuid); + MainUtil.sendMessage(player, Captions.CLUSTER_REMOVED_HELPER); + } else { + MainUtil.sendMessage(player, Captions.COMMAND_SYNTAX, + "/plot cluster helpers "); + } + } + }); + return true; } case "spawn": case "home": @@ -615,21 +635,31 @@ public class Cluster extends SubCommand { } } String id = cluster.toString(); - String owner = UUIDHandler.getName(cluster.owner); - if (owner == null) { - owner = "unknown"; - } - String name = cluster.getName(); - String size = (cluster.getP2().x - cluster.getP1().x + 1) + "x" + ( - cluster.getP2().y - cluster.getP1().y + 1); - String rights = cluster.isAdded(player.getUUID()) + ""; - String message = Captions.CLUSTER_INFO.getTranslated(); - message = message.replaceAll("%id%", id); - message = message.replaceAll("%owner%", owner); - message = message.replaceAll("%name%", name); - message = message.replaceAll("%size%", size); - message = message.replaceAll("%rights%", rights); - MainUtil.sendMessage(player, message); + + PlotSquared.get().getImpromptuUUIDPipeline() + .getSingle(cluster.owner, (username, throwable) -> { + if (throwable instanceof TimeoutException) { + MainUtil.sendMessage(player, Captions.FETCHING_PLAYERS_TIMEOUT); + } else { + final String owner; + if (username == null) { + owner = "unknown"; + } else { + owner = username; + } + String name = cluster.getName(); + String size = (cluster.getP2().x - cluster.getP1().x + 1) + "x" + ( + cluster.getP2().y - cluster.getP1().y + 1); + String rights = cluster.isAdded(player.getUUID()) + ""; + String message = Captions.CLUSTER_INFO.getTranslated(); + message = message.replaceAll("%id%", id); + message = message.replaceAll("%owner%", owner); + message = message.replaceAll("%name%", name); + message = message.replaceAll("%size%", size); + message = message.replaceAll("%rights%", rights); + MainUtil.sendMessage(player, message); + } + }); return true; } case "sh": diff --git a/Core/src/main/java/com/plotsquared/core/command/CmdConfirm.java b/Core/src/main/java/com/plotsquared/core/command/CmdConfirm.java index 8b657992d..f7096834b 100644 --- a/Core/src/main/java/com/plotsquared/core/command/CmdConfirm.java +++ b/Core/src/main/java/com/plotsquared/core/command/CmdConfirm.java @@ -32,15 +32,15 @@ import com.plotsquared.core.util.task.TaskManager; public class CmdConfirm { - public static CmdInstance getPending(PlotPlayer player) { + public static CmdInstance getPending(PlotPlayer player) { return player.getMeta("cmdConfirm"); } - public static void removePending(PlotPlayer player) { + public static void removePending(PlotPlayer player) { player.deleteMeta("cmdConfirm"); } - public static void addPending(final PlotPlayer player, String commandStr, + public static void addPending(final PlotPlayer player, String commandStr, final Runnable runnable) { removePending(player); if (commandStr != null) { diff --git a/Core/src/main/java/com/plotsquared/core/command/Command.java b/Core/src/main/java/com/plotsquared/core/command/Command.java index 6535e3b2c..7238d4566 100644 --- a/Core/src/main/java/com/plotsquared/core/command/Command.java +++ b/Core/src/main/java/com/plotsquared/core/command/Command.java @@ -37,6 +37,8 @@ import com.plotsquared.core.util.StringComparison; import com.plotsquared.core.util.StringMan; import com.plotsquared.core.util.task.RunnableVal2; import com.plotsquared.core.util.task.RunnableVal3; +import lombok.SneakyThrows; +import org.jetbrains.annotations.NotNull; import java.io.IOException; import java.lang.reflect.InvocationTargetException; @@ -104,7 +106,7 @@ public abstract class Command { && types[4] == RunnableVal2.class) { Command tmp = new Command(this, true) { @Override - public CompletableFuture execute(PlotPlayer player, String[] args, + public CompletableFuture execute(PlotPlayer player, String[] args, RunnableVal3 confirm, RunnableVal2 whenDone) { try { @@ -298,7 +300,7 @@ public abstract class Command { * @return CompletableFuture true if the command executed fully, false in * any other case */ - public CompletableFuture execute(PlotPlayer player, String[] args, + public CompletableFuture execute(PlotPlayer player, String[] args, RunnableVal3 confirm, RunnableVal2 whenDone) throws CommandException { if (args.length == 0 || args[0] == null) { @@ -603,6 +605,10 @@ public abstract class Command { return object; } + @SneakyThrows protected static void sneakyThrow(@NotNull final Throwable throwable) { + throw throwable; + } + public enum CommandResult { FAILURE, SUCCESS } diff --git a/Core/src/main/java/com/plotsquared/core/command/Comment.java b/Core/src/main/java/com/plotsquared/core/command/Comment.java index 284587106..a5615533f 100644 --- a/Core/src/main/java/com/plotsquared/core/command/Comment.java +++ b/Core/src/main/java/com/plotsquared/core/command/Comment.java @@ -25,6 +25,7 @@ */ package com.plotsquared.core.command; +import com.plotsquared.core.PlotSquared; import com.plotsquared.core.configuration.Captions; import com.plotsquared.core.player.PlotPlayer; import com.plotsquared.core.plot.Plot; @@ -33,11 +34,9 @@ import com.plotsquared.core.plot.comment.CommentManager; import com.plotsquared.core.plot.comment.PlotComment; import com.plotsquared.core.util.MainUtil; import com.plotsquared.core.util.StringMan; -import com.plotsquared.core.util.uuid.UUIDHandler; import java.util.Arrays; import java.util.Locale; -import java.util.Map.Entry; @CommandDeclaration(command = "comment", aliases = {"msg"}, @@ -47,7 +46,7 @@ import java.util.Map.Entry; permission = "plots.comment") public class Comment extends SubCommand { - @Override public boolean onCommand(PlotPlayer player, String[] args) { + @Override public boolean onCommand(PlotPlayer player, String[] args) { if (args.length < 2) { sendMessage(player, Captions.COMMENT_SYNTAX, StringMan.join(CommentManager.inboxes.keySet(), "|")); @@ -96,12 +95,13 @@ public class Comment extends SubCommand { StringMan.join(CommentManager.inboxes.keySet(), "|")); return false; } - for (Entry entry : UUIDHandler.getPlayers().entrySet()) { - PlotPlayer pp = entry.getValue(); + + for (final PlotPlayer pp : PlotSquared.imp().getPlayerManager().getPlayers()) { if (pp.getAttribute("chatspy")) { MainUtil.sendMessage(pp, "/plot comment " + StringMan.join(args, " ")); } } + sendMessage(player, Captions.COMMENT_ADDED); return true; } diff --git a/Core/src/main/java/com/plotsquared/core/command/Condense.java b/Core/src/main/java/com/plotsquared/core/command/Condense.java index f8a65407d..8f792ee7e 100644 --- a/Core/src/main/java/com/plotsquared/core/command/Condense.java +++ b/Core/src/main/java/com/plotsquared/core/command/Condense.java @@ -54,7 +54,7 @@ public class Condense extends SubCommand { public static boolean TASK = false; - @Override public boolean onCommand(final PlotPlayer player, String[] args) { + @Override public boolean onCommand(final PlotPlayer player, String[] args) { if (args.length != 2 && args.length != 3) { MainUtil.sendMessage(player, getUsage()); return false; diff --git a/Core/src/main/java/com/plotsquared/core/command/Confirm.java b/Core/src/main/java/com/plotsquared/core/command/Confirm.java index 04723ac48..311c1c437 100644 --- a/Core/src/main/java/com/plotsquared/core/command/Confirm.java +++ b/Core/src/main/java/com/plotsquared/core/command/Confirm.java @@ -37,7 +37,7 @@ import com.plotsquared.core.util.task.TaskManager; category = CommandCategory.INFO) public class Confirm extends SubCommand { - @Override public boolean onCommand(PlotPlayer player, String[] args) { + @Override public boolean onCommand(PlotPlayer player, String[] args) { CmdInstance command = CmdConfirm.getPending(player); if (command == null) { MainUtil.sendMessage(player, Captions.FAILED_CONFIRM); diff --git a/Core/src/main/java/com/plotsquared/core/command/Continue.java b/Core/src/main/java/com/plotsquared/core/command/Continue.java index d366b2ff6..23f5e93a0 100644 --- a/Core/src/main/java/com/plotsquared/core/command/Continue.java +++ b/Core/src/main/java/com/plotsquared/core/command/Continue.java @@ -44,7 +44,7 @@ import com.plotsquared.core.util.Permissions; requiredType = RequiredType.PLAYER) public class Continue extends SubCommand { - @Override public boolean onCommand(PlotPlayer player, String[] args) { + @Override public boolean onCommand(PlotPlayer player, String[] args) { Plot plot = player.getCurrentPlot(); if ((plot == null) || !plot.hasOwner()) { return !sendMessage(player, Captions.NOT_IN_PLOT); diff --git a/Core/src/main/java/com/plotsquared/core/command/Copy.java b/Core/src/main/java/com/plotsquared/core/command/Copy.java index 702255064..6743074ff 100644 --- a/Core/src/main/java/com/plotsquared/core/command/Copy.java +++ b/Core/src/main/java/com/plotsquared/core/command/Copy.java @@ -41,7 +41,7 @@ import com.plotsquared.core.util.Permissions; requiredType = RequiredType.NONE) public class Copy extends SubCommand { - @Override public boolean onCommand(final PlotPlayer player, String[] args) { + @Override public boolean onCommand(final PlotPlayer player, String[] args) { Location location = player.getLocation(); Plot plot1 = location.getPlotAbs(); if (plot1 == null) { diff --git a/Core/src/main/java/com/plotsquared/core/command/CreateRoadSchematic.java b/Core/src/main/java/com/plotsquared/core/command/CreateRoadSchematic.java index 258467500..d5800896a 100644 --- a/Core/src/main/java/com/plotsquared/core/command/CreateRoadSchematic.java +++ b/Core/src/main/java/com/plotsquared/core/command/CreateRoadSchematic.java @@ -42,7 +42,7 @@ import com.plotsquared.core.util.MainUtil; usage = "/plot createroadschematic") public class CreateRoadSchematic extends SubCommand { - @Override public boolean onCommand(PlotPlayer player, String[] args) { + @Override public boolean onCommand(PlotPlayer player, String[] args) { Location location = player.getLocation(); Plot plot = location.getPlotAbs(); if (plot == null) { diff --git a/Core/src/main/java/com/plotsquared/core/command/DatabaseCommand.java b/Core/src/main/java/com/plotsquared/core/command/DatabaseCommand.java index c652957e4..41690b5af 100644 --- a/Core/src/main/java/com/plotsquared/core/command/DatabaseCommand.java +++ b/Core/src/main/java/com/plotsquared/core/command/DatabaseCommand.java @@ -74,7 +74,7 @@ public class DatabaseCommand extends SubCommand { }); } - @Override public boolean onCommand(final PlotPlayer player, String[] args) { + @Override public boolean onCommand(final PlotPlayer player, String[] args) { if (args.length < 1) { MainUtil.sendMessage(player, getUsage()); return false; diff --git a/Core/src/main/java/com/plotsquared/core/command/Debug.java b/Core/src/main/java/com/plotsquared/core/command/Debug.java index 7d0ced991..91997a4ec 100644 --- a/Core/src/main/java/com/plotsquared/core/command/Debug.java +++ b/Core/src/main/java/com/plotsquared/core/command/Debug.java @@ -34,8 +34,10 @@ import com.plotsquared.core.util.StringMan; import com.plotsquared.core.util.entity.EntityCategories; import com.plotsquared.core.util.entity.EntityCategory; import com.plotsquared.core.util.task.TaskManager; +import com.plotsquared.core.uuid.UUIDMapping; import com.sk89q.worldedit.world.entity.EntityType; +import java.util.Collection; import java.util.Comparator; import java.util.Map; @@ -46,7 +48,7 @@ import java.util.Map; permission = "plots.admin") public class Debug extends SubCommand { - @Override public boolean onCommand(PlotPlayer player, String[] args) { + @Override public boolean onCommand(PlotPlayer player, String[] args) { if (args.length > 0) { if ("player".equalsIgnoreCase(args[0])) { for (Map.Entry meta : player.getMeta().entrySet()) { @@ -65,6 +67,18 @@ public class Debug extends SubCommand { .currentThread().getName())); return true; } + if (args.length > 0 && "uuids".equalsIgnoreCase(args[0])) { + final Collection mappings = PlotSquared.get().getImpromptuUUIDPipeline().getAllImmediately(); + MainUtil.sendMessage(player, String.format("There are %d cached UUIDs", mappings.size())); + return true; + } + if (args.length > 0 && "debug-players".equalsIgnoreCase(args[0])) { + MainUtil.sendMessage(player, "Player in debug mode: " ); + for (final PlotPlayer pp : PlotPlayer.getDebugModePlayers()) { + MainUtil.sendMessage(player, "- " + pp.getName()); + } + return true; + } if (args.length > 0 && "entitytypes".equalsIgnoreCase(args[0])) { EntityCategories.init(); player.sendMessage(Captions.PREFIX.getTranslated() + "§cEntity Categories: "); diff --git a/Core/src/main/java/com/plotsquared/core/command/DebugAllowUnsafe.java b/Core/src/main/java/com/plotsquared/core/command/DebugAllowUnsafe.java index e4de7e351..d424b809f 100644 --- a/Core/src/main/java/com/plotsquared/core/command/DebugAllowUnsafe.java +++ b/Core/src/main/java/com/plotsquared/core/command/DebugAllowUnsafe.java @@ -42,7 +42,7 @@ public class DebugAllowUnsafe extends SubCommand { public static final List unsafeAllowed = new ArrayList<>(); - @Override public boolean onCommand(PlotPlayer player, String[] args) { + @Override public boolean onCommand(PlotPlayer player, String[] args) { if (unsafeAllowed.contains(player.getUUID())) { unsafeAllowed.remove(player.getUUID()); diff --git a/Core/src/main/java/com/plotsquared/core/command/DebugClaimTest.java b/Core/src/main/java/com/plotsquared/core/command/DebugClaimTest.java deleted file mode 100644 index 5412ed6a2..000000000 --- a/Core/src/main/java/com/plotsquared/core/command/DebugClaimTest.java +++ /dev/null @@ -1,134 +0,0 @@ -/* - * _____ _ _ _____ _ - * | __ \| | | | / ____| | | - * | |__) | | ___ | |_| (___ __ _ _ _ __ _ _ __ ___ __| | - * | ___/| |/ _ \| __|\___ \ / _` | | | |/ _` | '__/ _ \/ _` | - * | | | | (_) | |_ ____) | (_| | |_| | (_| | | | __/ (_| | - * |_| |_|\___/ \__|_____/ \__, |\__,_|\__,_|_| \___|\__,_| - * | | - * |_| - * PlotSquared plot management system for Minecraft - * Copyright (C) 2020 IntellectualSites - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package com.plotsquared.core.command; - -import com.google.common.collect.BiMap; -import com.plotsquared.core.PlotSquared; -import com.plotsquared.core.configuration.Captions; -import com.plotsquared.core.location.Location; -import com.plotsquared.core.player.PlotPlayer; -import com.plotsquared.core.plot.Plot; -import com.plotsquared.core.plot.PlotArea; -import com.plotsquared.core.plot.PlotId; -import com.plotsquared.core.plot.PlotManager; -import com.plotsquared.core.util.ChunkManager; -import com.plotsquared.core.util.MainUtil; -import com.plotsquared.core.util.StringWrapper; -import com.plotsquared.core.util.WorldUtil; -import com.plotsquared.core.util.uuid.UUIDHandler; -import com.sk89q.worldedit.math.BlockVector2; - -import java.util.ArrayList; -import java.util.Map; -import java.util.UUID; -import java.util.concurrent.CompletableFuture; - -@CommandDeclaration(command = "debugclaimtest", - description = - "If you accidentally delete your database, this command will attempt to restore all plots based on the data from plot signs. " - + "Execution time may vary", - category = CommandCategory.DEBUG, - requiredType = RequiredType.CONSOLE, - permission = "plots.debugclaimtest") -public class DebugClaimTest extends SubCommand { - - @Override public boolean onCommand(final PlotPlayer player, String[] args) { - if (args.length < 3) { - return !MainUtil.sendMessage(null, - "If you accidentally delete your database, this command will attempt to restore all plots based on the data from the " - + "plot signs. \n\n&cMissing world arg /plot debugclaimtest {world} {PlotId min} {PlotId max}"); - } - PlotArea area = PlotSquared.get().getPlotAreaByString(args[0]); - if (area == null || !WorldUtil.IMP.isWorld(area.getWorldName())) { - Captions.NOT_VALID_PLOT_WORLD.send(player, args[0]); - return false; - } - PlotId min, max; - try { - args[1].split(";"); - args[2].split(";"); - min = PlotId.fromString(args[1]); - max = PlotId.fromString(args[2]); - } catch (Exception ignored) { - return !MainUtil.sendMessage(player, - "&cInvalid min/max values. &7The values are to Plot IDs in the format &cX;Y &7where X;Y are the plot coords\nThe conversion " - + "will only check the plots in the selected area."); - } - MainUtil.sendMessage(player, - "&3Sign Block&8->&3Plot&8: &7Beginning sign to plot conversion. This may take a while..."); - MainUtil.sendMessage(player, - "&3Sign Block&8->&3Plot&8: Found an excess of 250,000 chunks. Limiting search radius... (~3.8 min)"); - PlotManager manager = area.getPlotManager(); - CompletableFuture.runAsync(() -> { - ArrayList ids = MainUtil.getPlotSelectionIds(min, max); - MainUtil.sendMessage(player, - "&3Sign Block&8->&3Plot&8: " + ids.size() + " plot ids to check!"); - for (PlotId id : ids) { - Plot plot = area.getPlotAbs(id); - if (plot.hasOwner()) { - MainUtil.sendMessage(player, " - &cDB Already contains: " + plot.getId()); - continue; - } - Location location = manager.getSignLoc(plot); - BlockVector2 chunk = BlockVector2.at(location.getX() >> 4, location.getZ() >> 4); - ChunkManager.manager.loadChunk(area.getWorldName(), chunk, false).thenRun(() -> { - String[] lines = WorldUtil.IMP.getSignSynchronous(location); - if (lines != null) { - String line = lines[2]; - if (line != null && line.length() > 2) { - line = line.substring(2); - BiMap map = UUIDHandler.getUuidMap(); - UUID uuid = map.get(new StringWrapper(line)); - if (uuid == null) { - for (Map.Entry stringWrapperUUIDEntry : map - .entrySet()) { - if (stringWrapperUUIDEntry.getKey().value.toLowerCase() - .startsWith(line.toLowerCase())) { - uuid = stringWrapperUUIDEntry.getValue(); - break; - } - } - } - if (uuid == null) { - uuid = UUIDHandler.getUUID(line, null); - } - if (uuid != null) { - MainUtil.sendMessage(player, - " - &aFound plot: " + plot.getId() + " : " + line); - plot.setOwner(uuid); - MainUtil.sendMessage(player, " - &8Updated plot: " + plot.getId()); - } else { - MainUtil.sendMessage(player, - " - &cInvalid PlayerName: " + plot.getId() + " : " + line); - } - } - } - }).join(); - } - }).thenRun(() -> MainUtil.sendMessage(player, "&3Sign Block&8->&3Plot&8: Finished scan.")); - return true; - } -} diff --git a/Core/src/main/java/com/plotsquared/core/command/DebugExec.java b/Core/src/main/java/com/plotsquared/core/command/DebugExec.java index 8976c3348..3d6af68f1 100644 --- a/Core/src/main/java/com/plotsquared/core/command/DebugExec.java +++ b/Core/src/main/java/com/plotsquared/core/command/DebugExec.java @@ -35,7 +35,6 @@ import com.plotsquared.core.events.Result; import com.plotsquared.core.generator.HybridUtils; import com.plotsquared.core.location.Location; import com.plotsquared.core.player.ConsolePlayer; -import com.plotsquared.core.player.OfflinePlotPlayer; import com.plotsquared.core.player.PlotPlayer; import com.plotsquared.core.plot.Plot; import com.plotsquared.core.plot.PlotArea; @@ -59,7 +58,6 @@ import com.plotsquared.core.util.task.RunnableVal; import com.plotsquared.core.util.task.RunnableVal2; import com.plotsquared.core.util.task.RunnableVal3; import com.plotsquared.core.util.task.TaskManager; -import com.plotsquared.core.util.uuid.UUIDHandler; import com.sk89q.worldedit.world.block.BlockState; import javax.script.Bindings; @@ -71,13 +69,10 @@ import javax.script.SimpleScriptContext; import java.io.File; import java.io.IOException; import java.nio.charset.StandardCharsets; -import java.sql.Timestamp; import java.util.Arrays; -import java.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.List; -import java.util.UUID; import java.util.concurrent.CompletableFuture; @CommandDeclaration(command = "debugexec", @@ -171,8 +166,7 @@ public class DebugExec extends SubCommand { this.scope.put("BlockManager", WorldUtil.IMP); this.scope.put("SetupUtils", SetupUtils.manager); this.scope.put("EventUtil", PlotSquared.get().getEventDispatcher()); - this.scope.put("EconHandler", EconHandler.manager); - this.scope.put("UUIDHandler", UUIDHandler.implementation); + this.scope.put("EconHandler", EconHandler.getEconHandler()); this.scope.put("DBFunc", DBFunc.dbManager); this.scope.put("HybridUtils", HybridUtils.manager); this.scope.put("IMP", PlotSquared.get().IMP); @@ -184,7 +178,7 @@ public class DebugExec extends SubCommand { } } - @Override public boolean onCommand(final PlotPlayer player, String[] args) { + @Override public boolean onCommand(final PlotPlayer player, String[] args) { List allowed_params = Arrays .asList("analyze", "calibrate-analysis", "remove-flag", "stop-expire", "start-expire", "seen", "list-scripts", "start-rgar", "stop-rgar", "help", "addcmd", "runasync", @@ -301,27 +295,6 @@ public class DebugExec extends SubCommand { } else { return MainUtil.sendMessage(player, "Plot expiry task already started"); } - case "seen": - if (args.length != 2) { - return MainUtil.sendMessage(player, "Use /plot debugexec seen "); - } - UUID uuid = UUIDHandler.getUUID(args[1], null); - if (uuid == null) { - return MainUtil.sendMessage(player, "Player not found: " + args[1]); - } - OfflinePlotPlayer op = UUIDHandler.getUUIDWrapper().getOfflinePlayer(uuid); - if (op == null || op.getLastPlayed() == 0) { - return MainUtil - .sendMessage(player, "Player hasn't connected before: " + args[1]); - } - Timestamp stamp = new Timestamp(op.getLastPlayed()); - Date date = new Date(stamp.getTime()); - MainUtil.sendMessage(player, "PLAYER: " + args[1]); - MainUtil.sendMessage(player, "UUID: " + uuid); - MainUtil.sendMessage(player, "Object: " + date.toGMTString()); - MainUtil.sendMessage(player, "GMT: " + date.toGMTString()); - MainUtil.sendMessage(player, "Local: " + date.toLocaleString()); - return true; case "h": case "he": case "?": @@ -339,7 +312,7 @@ public class DebugExec extends SubCommand { new Command(MainCommand.getInstance(), true, args[1].split("\\.")[0], null, RequiredType.NONE, CommandCategory.DEBUG) { @Override - public CompletableFuture execute(PlotPlayer player, + public CompletableFuture execute(PlotPlayer player, String[] args, RunnableVal3 confirm, RunnableVal2 whenDone) { try { diff --git a/Core/src/main/java/com/plotsquared/core/command/DebugImportWorlds.java b/Core/src/main/java/com/plotsquared/core/command/DebugImportWorlds.java index 9cca145a5..bdb5a13b2 100644 --- a/Core/src/main/java/com/plotsquared/core/command/DebugImportWorlds.java +++ b/Core/src/main/java/com/plotsquared/core/command/DebugImportWorlds.java @@ -27,6 +27,7 @@ package com.plotsquared.core.command; import com.google.common.base.Charsets; import com.plotsquared.core.PlotSquared; +import com.plotsquared.core.configuration.Captions; import com.plotsquared.core.player.PlotPlayer; import com.plotsquared.core.plot.PlotId; import com.plotsquared.core.plot.world.PlotAreaManager; @@ -35,7 +36,6 @@ import com.plotsquared.core.plot.world.SinglePlotAreaManager; import com.plotsquared.core.util.WorldUtil; import com.plotsquared.core.util.task.RunnableVal2; import com.plotsquared.core.util.task.RunnableVal3; -import com.plotsquared.core.util.uuid.UUIDHandler; import java.io.File; import java.util.UUID; @@ -52,7 +52,7 @@ public class DebugImportWorlds extends Command { } @Override - public CompletableFuture execute(PlotPlayer player, String[] args, + public CompletableFuture execute(PlotPlayer player, String[] args, RunnableVal3 confirm, RunnableVal2 whenDone) throws CommandException { // UUID.nameUUIDFromBytes(("OfflinePlayer:" + player.getName()).getBytes(Charsets.UTF_8)) @@ -76,7 +76,8 @@ public class DebugImportWorlds extends Command { if (name.length() > 16) { uuid = UUID.fromString(name); } else { - uuid = UUIDHandler.getUUID(name, null); + Captions.FETCHING_PLAYER.send(player); + uuid = PlotSquared.get().getImpromptuUUIDPipeline().getSingle(name, 60000L); } if (uuid == null) { uuid = diff --git a/Core/src/main/java/com/plotsquared/core/command/DebugLoadTest.java b/Core/src/main/java/com/plotsquared/core/command/DebugLoadTest.java index 47bf4d6c5..387c5204e 100644 --- a/Core/src/main/java/com/plotsquared/core/command/DebugLoadTest.java +++ b/Core/src/main/java/com/plotsquared/core/command/DebugLoadTest.java @@ -37,7 +37,7 @@ import com.plotsquared.core.player.PlotPlayer; requiredType = RequiredType.CONSOLE) public class DebugLoadTest extends SubCommand { - @Override public boolean onCommand(PlotPlayer player, String[] args) { + @Override public boolean onCommand(PlotPlayer player, String[] args) { PlotSquared.get().plots_tmp = DBFunc.getPlots(); return true; } diff --git a/Core/src/main/java/com/plotsquared/core/command/DebugPaste.java b/Core/src/main/java/com/plotsquared/core/command/DebugPaste.java index c5c42a4c2..441fbdd84 100644 --- a/Core/src/main/java/com/plotsquared/core/command/DebugPaste.java +++ b/Core/src/main/java/com/plotsquared/core/command/DebugPaste.java @@ -35,7 +35,6 @@ import com.plotsquared.core.util.MainUtil; import com.plotsquared.core.util.PremiumVerification; import com.plotsquared.core.util.net.IncendoPaster; import com.plotsquared.core.util.task.TaskManager; -import com.plotsquared.core.util.uuid.UUIDHandler; import lombok.NonNull; import java.io.BufferedReader; @@ -72,7 +71,7 @@ public class DebugPaste extends SubCommand { return content.toString(); } - @Override public boolean onCommand(final PlotPlayer player, String[] args) { + @Override public boolean onCommand(final PlotPlayer player, String[] args) { TaskManager.runTaskAsync(() -> { try { @@ -90,7 +89,7 @@ public class DebugPaste extends SubCommand { b.append("# Server Information\n"); b.append("Server Version: ").append(PlotSquared.get().IMP.getServerImplementation()) .append("\n"); - b.append("online_mode: ").append(UUIDHandler.getUUIDWrapper()).append(';') + b.append("online_mode: ").append(!Settings.UUID.OFFLINE).append(';') .append(!Settings.UUID.OFFLINE).append('\n'); b.append("Plugins:"); for (Map.Entry, Boolean> pluginInfo : PlotSquared @@ -122,7 +121,7 @@ public class DebugPaste extends SubCommand { b.append("OS Arch: ").append(System.getProperty("os.arch")).append('\n'); b.append("# Okay :D Great. You are now ready to create your bug report!"); b.append( - "\n# You can do so at https://github.com/IntellectualSites/PlotSquared/issues"); + "\n# You can do so at https://issues.intellectualsites.com/projects/ps"); b.append("\n# or via our Discord at https://discord.gg/KxkjDVg"); final IncendoPaster incendoPaster = new IncendoPaster("plotsquared"); diff --git a/Core/src/main/java/com/plotsquared/core/command/DebugRoadRegen.java b/Core/src/main/java/com/plotsquared/core/command/DebugRoadRegen.java index 07ce9a516..b20924586 100644 --- a/Core/src/main/java/com/plotsquared/core/command/DebugRoadRegen.java +++ b/Core/src/main/java/com/plotsquared/core/command/DebugRoadRegen.java @@ -46,7 +46,7 @@ import java.util.Arrays; public class DebugRoadRegen extends SubCommand { public static final String USAGE = "/plot debugroadregen "; - @Override public boolean onCommand(PlotPlayer player, String[] args) { + @Override public boolean onCommand(PlotPlayer player, String[] args) { if (args.length < 1) { MainUtil.sendMessage(player, Captions.COMMAND_SYNTAX, DebugRoadRegen.USAGE); return false; diff --git a/Core/src/main/java/com/plotsquared/core/command/DebugSaveTest.java b/Core/src/main/java/com/plotsquared/core/command/DebugSaveTest.java index dc2fc612d..7307ca185 100644 --- a/Core/src/main/java/com/plotsquared/core/command/DebugSaveTest.java +++ b/Core/src/main/java/com/plotsquared/core/command/DebugSaveTest.java @@ -41,7 +41,7 @@ import java.util.ArrayList; description = "This command will force the recreation of all plots in the DB") public class DebugSaveTest extends SubCommand { - @Override public boolean onCommand(final PlotPlayer player, String[] args) { + @Override public boolean onCommand(final PlotPlayer player, String[] args) { ArrayList plots = new ArrayList<>(PlotSquared.get().getPlots()); MainUtil.sendMessage(player, "&6Starting `DEBUGSAVETEST`"); DBFunc.createPlotsAndData(plots, diff --git a/Core/src/main/java/com/plotsquared/core/command/Delete.java b/Core/src/main/java/com/plotsquared/core/command/Delete.java index 1a95046df..5f8178e06 100644 --- a/Core/src/main/java/com/plotsquared/core/command/Delete.java +++ b/Core/src/main/java/com/plotsquared/core/command/Delete.java @@ -53,7 +53,7 @@ public class Delete extends SubCommand { // Note: To delete a specific plot use /plot delete // The syntax also works with any command: /plot - @Override public boolean onCommand(final PlotPlayer player, String[] args) { + @Override public boolean onCommand(final PlotPlayer player, String[] args) { Location location = player.getLocation(); final Plot plot = location.getPlotAbs(); if (plot == null) { @@ -86,11 +86,11 @@ public class Delete extends SubCommand { final long start = System.currentTimeMillis(); boolean result = plot.deletePlot(() -> { plot.removeRunning(); - if ((EconHandler.manager != null) && plotArea.useEconomy()) { + if ((EconHandler.getEconHandler() != null) && plotArea.useEconomy()) { Expression valueExr = plotArea.getPrices().get("sell"); double value = plots.size() * valueExr.evaluate((double) currentPlots); if (value > 0d) { - EconHandler.manager.depositMoney(player, value); + EconHandler.getEconHandler().depositMoney(player, value); sendMessage(player, Captions.ADDED_BALANCE, String.valueOf(value)); } } diff --git a/Core/src/main/java/com/plotsquared/core/command/Deny.java b/Core/src/main/java/com/plotsquared/core/command/Deny.java index d591bfa1a..1cb862304 100644 --- a/Core/src/main/java/com/plotsquared/core/command/Deny.java +++ b/Core/src/main/java/com/plotsquared/core/command/Deny.java @@ -33,12 +33,14 @@ import com.plotsquared.core.player.PlotPlayer; import com.plotsquared.core.plot.Plot; import com.plotsquared.core.util.MainUtil; import com.plotsquared.core.util.Permissions; +import com.plotsquared.core.util.TabCompletions; import com.plotsquared.core.util.WorldUtil; -import com.plotsquared.core.util.uuid.UUIDHandler; import com.sk89q.worldedit.world.gamemode.GameModes; -import java.util.Set; +import java.util.Collection; +import java.util.Collections; import java.util.UUID; +import java.util.concurrent.TimeoutException; @CommandDeclaration(command = "deny", aliases = {"d", "ban"}, @@ -52,7 +54,7 @@ public class Deny extends SubCommand { super(Argument.PlayerName); } - @Override public boolean onCommand(PlotPlayer player, String[] args) { + @Override public boolean onCommand(PlotPlayer player, String[] args) { Location location = player.getLocation(); Plot plot = location.getPlotAbs(); @@ -68,51 +70,55 @@ public class Deny extends SubCommand { MainUtil.sendMessage(player, Captions.NO_PLOT_PERMS); return true; } - Set uuids = MainUtil.getUUIDsFromString(args[0]); - if (uuids.isEmpty()) { - MainUtil.sendMessage(player, Captions.INVALID_PLAYER, args[0]); - return false; - } - for (UUID uuid : uuids) { - if (uuid == DBFunc.EVERYONE && !( - Permissions.hasPermission(player, Captions.PERMISSION_DENY_EVERYONE) || Permissions - .hasPermission(player, Captions.PERMISSION_ADMIN_COMMAND_DENY))) { - MainUtil.sendMessage(player, Captions.INVALID_PLAYER, MainUtil.getName(uuid)); - continue; - } - if (plot.isOwner(uuid)) { - MainUtil.sendMessage(player, Captions.CANT_REMOVE_OWNER, MainUtil.getName(uuid)); - return false; - } - if (plot.getDenied().contains(uuid)) { - MainUtil.sendMessage(player, Captions.ALREADY_ADDED, MainUtil.getName(uuid)); - return false; - } - if (uuid != DBFunc.EVERYONE) { - plot.removeMember(uuid); - plot.removeTrusted(uuid); - } - plot.addDenied(uuid); - PlotSquared.get().getEventDispatcher().callDenied(player, plot, uuid, true); - if (!uuid.equals(DBFunc.EVERYONE)) { - handleKick(UUIDHandler.getPlayer(uuid), plot); + MainUtil.getUUIDsFromString(args[0], (uuids, throwable) -> { + if (throwable instanceof TimeoutException) { + MainUtil.sendMessage(player, Captions.FETCHING_PLAYERS_TIMEOUT); + } else if (throwable != null || uuids.isEmpty()) { + MainUtil.sendMessage(player, Captions.INVALID_PLAYER, args[0]); } else { - for (PlotPlayer plotPlayer : plot.getPlayersInPlot()) { - // Ignore plot-owners - if (plot.isAdded(plotPlayer.getUUID())) { - continue; + for (UUID uuid : uuids) { + if (uuid == DBFunc.EVERYONE && !( + Permissions.hasPermission(player, Captions.PERMISSION_DENY_EVERYONE) || Permissions + .hasPermission(player, Captions.PERMISSION_ADMIN_COMMAND_DENY))) { + MainUtil.sendMessage(player, Captions.INVALID_PLAYER, MainUtil.getName(uuid)); + } else if (plot.isOwner(uuid)) { + MainUtil.sendMessage(player, Captions.CANT_REMOVE_OWNER, MainUtil.getName(uuid)); + return; + } else if (plot.getDenied().contains(uuid)) { + MainUtil.sendMessage(player, Captions.ALREADY_ADDED, MainUtil.getName(uuid)); + return; + } else { + if (uuid != DBFunc.EVERYONE) { + plot.removeMember(uuid); + plot.removeTrusted(uuid); + } + plot.addDenied(uuid); + PlotSquared.get().getEventDispatcher().callDenied(player, plot, uuid, true); + if (!uuid.equals(DBFunc.EVERYONE)) { + handleKick(PlotSquared.imp().getPlayerManager().getPlayerIfExists(uuid), plot); + } else { + for (PlotPlayer plotPlayer : plot.getPlayersInPlot()) { + // Ignore plot-owners + if (plot.isAdded(plotPlayer.getUUID())) { + continue; + } + handleKick(plotPlayer, plot); + } + } } - handleKick(plotPlayer, plot); } + MainUtil.sendMessage(player, Captions.DENIED_ADDED); } - } - if (!uuids.isEmpty()) { - MainUtil.sendMessage(player, Captions.DENIED_ADDED); - } + }); + return true; } + @Override public Collection tab(final PlotPlayer player, final String[] args, final boolean space) { + return TabCompletions.completePlayers(String.join(",", args).trim(), Collections.emptyList()); + } + private void handleKick(PlotPlayer player, Plot plot) { if (player == null) { return; diff --git a/Core/src/main/java/com/plotsquared/core/command/Dislike.java b/Core/src/main/java/com/plotsquared/core/command/Dislike.java index ee6664f81..410e13b57 100644 --- a/Core/src/main/java/com/plotsquared/core/command/Dislike.java +++ b/Core/src/main/java/com/plotsquared/core/command/Dislike.java @@ -35,7 +35,7 @@ import com.plotsquared.core.player.PlotPlayer; requiredType = RequiredType.PLAYER) public class Dislike extends SubCommand { - @Override public boolean onCommand(PlotPlayer player, String[] args) { + @Override public boolean onCommand(PlotPlayer player, String[] args) { return Like.handleLike(player, args, false); } diff --git a/Core/src/main/java/com/plotsquared/core/command/Done.java b/Core/src/main/java/com/plotsquared/core/command/Done.java index 4e9015e04..258454f8a 100644 --- a/Core/src/main/java/com/plotsquared/core/command/Done.java +++ b/Core/src/main/java/com/plotsquared/core/command/Done.java @@ -51,7 +51,7 @@ import com.plotsquared.core.util.task.RunnableVal; requiredType = RequiredType.NONE) public class Done extends SubCommand { - @Override public boolean onCommand(final PlotPlayer player, String[] args) { + @Override public boolean onCommand(final PlotPlayer player, String[] args) { Location location = player.getLocation(); final Plot plot = location.getPlotAbs(); if ((plot == null) || !plot.hasOwner()) { diff --git a/Core/src/main/java/com/plotsquared/core/command/Download.java b/Core/src/main/java/com/plotsquared/core/command/Download.java index 25e3c13d7..efd4079d5 100644 --- a/Core/src/main/java/com/plotsquared/core/command/Download.java +++ b/Core/src/main/java/com/plotsquared/core/command/Download.java @@ -50,7 +50,7 @@ import java.net.URL; permission = "plots.download") public class Download extends SubCommand { - @Override public boolean onCommand(final PlotPlayer player, String[] args) { + @Override public boolean onCommand(final PlotPlayer player, String[] args) { String world = player.getLocation().getWorld(); if (!PlotSquared.get().hasPlotArea(world)) { return !sendMessage(player, Captions.NOT_IN_PLOT_WORLD); diff --git a/Core/src/main/java/com/plotsquared/core/command/FlagCommand.java b/Core/src/main/java/com/plotsquared/core/command/FlagCommand.java index 80ee2512a..d6b5a58e8 100644 --- a/Core/src/main/java/com/plotsquared/core/command/FlagCommand.java +++ b/Core/src/main/java/com/plotsquared/core/command/FlagCommand.java @@ -207,7 +207,7 @@ public final class FlagCommand extends Command { } @Override - public CompletableFuture execute(PlotPlayer player, String[] args, + public CompletableFuture execute(PlotPlayer player, String[] args, RunnableVal3 confirm, RunnableVal2 whenDone) throws CommandException { if (args.length == 0 || !Arrays diff --git a/Core/src/main/java/com/plotsquared/core/command/Grant.java b/Core/src/main/java/com/plotsquared/core/command/Grant.java index acec1b084..2d41da2e3 100644 --- a/Core/src/main/java/com/plotsquared/core/command/Grant.java +++ b/Core/src/main/java/com/plotsquared/core/command/Grant.java @@ -26,6 +26,7 @@ package com.plotsquared.core.command; import com.google.common.primitives.Ints; +import com.plotsquared.core.PlotSquared; import com.plotsquared.core.configuration.CaptionUtility; import com.plotsquared.core.configuration.Captions; import com.plotsquared.core.database.DBFunc; @@ -35,10 +36,10 @@ import com.plotsquared.core.util.Permissions; import com.plotsquared.core.util.task.RunnableVal; import com.plotsquared.core.util.task.RunnableVal2; import com.plotsquared.core.util.task.RunnableVal3; -import com.plotsquared.core.util.uuid.UUIDHandler; import java.util.UUID; import java.util.concurrent.CompletableFuture; +import java.util.concurrent.TimeoutException; @CommandDeclaration(command = "grant", category = CommandCategory.CLAIMING, @@ -52,7 +53,7 @@ public class Grant extends Command { } @Override - public CompletableFuture execute(final PlotPlayer player, String[] args, + public CompletableFuture execute(final PlotPlayer player, String[] args, RunnableVal3 confirm, RunnableVal2 whenDone) throws CommandException { checkTrue(args.length >= 1 && args.length <= 2, Captions.COMMAND_SYNTAX, getUsage()); @@ -69,43 +70,44 @@ public class Grant extends Command { if (args.length > 2) { break; } - final UUID uuid; - if (args.length == 2) { - uuid = UUIDHandler.getUUIDFromString(args[1]); - } else { - uuid = player.getUUID(); - } - if (uuid == null) { - Captions.INVALID_PLAYER.send(player, args[1]); - return CompletableFuture.completedFuture(false); - } - MainUtil.getPersistentMeta(uuid, "grantedPlots", new RunnableVal() { - @Override public void run(byte[] array) { - if (arg0.equals("check")) { // check - int granted; - if (array == null) { - granted = 0; - } else { - granted = Ints.fromByteArray(array); + MainUtil.getUUIDsFromString(args[1], (uuids, throwable) -> { + if (throwable instanceof TimeoutException) { + MainUtil.sendMessage(player, Captions.FETCHING_PLAYERS_TIMEOUT); + } else if (throwable != null || uuids.size() != 1) { + MainUtil.sendMessage(player, Captions.INVALID_PLAYER); + } else { + final UUID uuid = uuids.toArray(new UUID[0])[0]; + MainUtil.getPersistentMeta(uuid, + "grantedPlots", new RunnableVal() { + @Override public void run(byte[] array) { + if (arg0.equals("check")) { // check + int granted; + if (array == null) { + granted = 0; + } else { + granted = Ints.fromByteArray(array); + } + Captions.GRANTED_PLOTS.send(player, granted); + } else { // add + int amount; + if (array == null) { + amount = 1; + } else { + amount = 1 + Ints.fromByteArray(array); + } + boolean replace = array != null; + String key = "grantedPlots"; + byte[] rawData = Ints.toByteArray(amount); + + PlotPlayer online = PlotSquared.imp().getPlayerManager().getPlayerIfExists(uuid); + if (online != null) { + online.setPersistentMeta(key, rawData); + } else { + DBFunc.addPersistentMeta(uuid, key, rawData, replace); + } + } } - Captions.GRANTED_PLOTS.send(player, granted); - } else { // add - int amount; - if (array == null) { - amount = 1; - } else { - amount = 1 + Ints.fromByteArray(array); - } - boolean replace = array != null; - String key = "grantedPlots"; - byte[] rawData = Ints.toByteArray(amount); - PlotPlayer online = UUIDHandler.getPlayer(uuid); - if (online != null) { - online.setPersistentMeta(key, rawData); - } else { - DBFunc.addPersistentMeta(uuid, key, rawData, replace); - } - } + }); } }); return CompletableFuture.completedFuture(true); diff --git a/Core/src/main/java/com/plotsquared/core/command/Help.java b/Core/src/main/java/com/plotsquared/core/command/Help.java index a1bbdc244..ef4b5a753 100644 --- a/Core/src/main/java/com/plotsquared/core/command/Help.java +++ b/Core/src/main/java/com/plotsquared/core/command/Help.java @@ -52,7 +52,7 @@ public class Help extends Command { } @Override - public CompletableFuture execute(PlotPlayer player, String[] args, + public CompletableFuture execute(PlotPlayer player, String[] args, RunnableVal3 confirm, RunnableVal2 whenDone) { switch (args.length) { diff --git a/Core/src/main/java/com/plotsquared/core/command/Inbox.java b/Core/src/main/java/com/plotsquared/core/command/Inbox.java index 938033758..a042e72cb 100644 --- a/Core/src/main/java/com/plotsquared/core/command/Inbox.java +++ b/Core/src/main/java/com/plotsquared/core/command/Inbox.java @@ -86,7 +86,7 @@ public class Inbox extends SubCommand { MainUtil.sendMessage(player, string.toString()); } - @Override public boolean onCommand(final PlotPlayer player, String[] args) { + @Override public boolean onCommand(final PlotPlayer player, String[] args) { final Plot plot = player.getCurrentPlot(); if (plot == null) { sendMessage(player, Captions.NOT_IN_PLOT); diff --git a/Core/src/main/java/com/plotsquared/core/command/Info.java b/Core/src/main/java/com/plotsquared/core/command/Info.java index 23c63450b..125d0008d 100644 --- a/Core/src/main/java/com/plotsquared/core/command/Info.java +++ b/Core/src/main/java/com/plotsquared/core/command/Info.java @@ -41,7 +41,7 @@ import com.plotsquared.core.util.task.RunnableVal; category = CommandCategory.INFO) public class Info extends SubCommand { - @Override public boolean onCommand(final PlotPlayer player, String[] args) { + @Override public boolean onCommand(final PlotPlayer player, String[] args) { Plot plot; String arg; if (args.length > 0) { diff --git a/Core/src/main/java/com/plotsquared/core/command/Kick.java b/Core/src/main/java/com/plotsquared/core/command/Kick.java index 1d113a874..911ea9810 100644 --- a/Core/src/main/java/com/plotsquared/core/command/Kick.java +++ b/Core/src/main/java/com/plotsquared/core/command/Kick.java @@ -33,12 +33,15 @@ import com.plotsquared.core.player.PlotPlayer; import com.plotsquared.core.plot.Plot; import com.plotsquared.core.util.MainUtil; import com.plotsquared.core.util.Permissions; +import com.plotsquared.core.util.TabCompletions; import com.plotsquared.core.util.WorldUtil; -import com.plotsquared.core.util.uuid.UUIDHandler; +import java.util.Collection; +import java.util.Collections; import java.util.HashSet; import java.util.Set; import java.util.UUID; +import java.util.concurrent.TimeoutException; @CommandDeclaration(command = "kick", aliases = "k", @@ -53,7 +56,7 @@ public class Kick extends SubCommand { super(Argument.PlayerName); } - @Override public boolean onCommand(PlotPlayer player, String[] args) { + @Override public boolean onCommand(PlotPlayer player, String[] args) { Location location = player.getLocation(); Plot plot = location.getPlot(); if (plot == null) { @@ -64,57 +67,72 @@ public class Kick extends SubCommand { MainUtil.sendMessage(player, Captions.NO_PLOT_PERMS); return false; } - Set uuids = MainUtil.getUUIDsFromString(args[0]); - if (uuids.isEmpty()) { - MainUtil.sendMessage(player, Captions.INVALID_PLAYER, args[0]); - return false; - } - Set players = new HashSet<>(); - for (UUID uuid : uuids) { - if (uuid == DBFunc.EVERYONE) { - for (PlotPlayer pp : plot.getPlayersInPlot()) { - if (pp == player || Permissions - .hasPermission(pp, Captions.PERMISSION_ADMIN_ENTRY_DENIED)) { + + MainUtil.getUUIDsFromString(args[0], (uuids, throwable) -> { + if (throwable instanceof TimeoutException) { + MainUtil.sendMessage(player, Captions.FETCHING_PLAYERS_TIMEOUT); + } else if (throwable != null || uuids.isEmpty()) { + MainUtil.sendMessage(player, Captions.INVALID_PLAYER, args[0]); + } else { + Set> players = new HashSet<>(); + for (UUID uuid : uuids) { + if (uuid == DBFunc.EVERYONE) { + for (PlotPlayer pp : plot.getPlayersInPlot()) { + if (pp == player || Permissions + .hasPermission(pp, Captions.PERMISSION_ADMIN_ENTRY_DENIED)) { + continue; + } + players.add(pp); + } continue; } - players.add(pp); + PlotPlayer pp = PlotSquared.imp().getPlayerManager().getPlayerIfExists(uuid); + if (pp != null) { + players.add(pp); + } } - continue; - } - PlotPlayer pp = UUIDHandler.getPlayer(uuid); - if (pp != null) { - players.add(pp); - } - } - players.remove(player); // Don't ever kick the calling player - if (players.isEmpty()) { - MainUtil.sendMessage(player, Captions.INVALID_PLAYER, args[0]); - return false; - } - for (PlotPlayer player2 : players) { - if (!plot.equals(player2.getCurrentPlot())) { - MainUtil.sendMessage(player, Captions.INVALID_PLAYER, args[0]); - return false; - } - if (Permissions.hasPermission(player2, Captions.PERMISSION_ADMIN_ENTRY_DENIED)) { - Captions.CANNOT_KICK_PLAYER.send(player, player2.getName()); - return false; - } - Location spawn = WorldUtil.IMP.getSpawn(location.getWorld()); - Captions.YOU_GOT_KICKED.send(player2); - if (plot.equals(spawn.getPlot())) { - Location newSpawn = WorldUtil.IMP - .getSpawn(PlotSquared.get().getPlotAreaManager().getAllWorlds()[0]); - if (plot.equals(newSpawn.getPlot())) { - // Kick from server if you can't be teleported to spawn - player2.kick(Captions.YOU_GOT_KICKED.getTranslated()); - } else { - player2.plotkick(newSpawn); + players.remove(player); // Don't ever kick the calling player + if (players.isEmpty()) { + MainUtil.sendMessage(player, Captions.INVALID_PLAYER, args[0]); + return; + } + for (PlotPlayer player2 : players) { + if (!plot.equals(player2.getCurrentPlot())) { + MainUtil.sendMessage(player, Captions.INVALID_PLAYER, args[0]); + return; + } + if (Permissions.hasPermission(player2, Captions.PERMISSION_ADMIN_ENTRY_DENIED)) { + Captions.CANNOT_KICK_PLAYER.send(player, player2.getName()); + return; + } + Location spawn = WorldUtil.IMP.getSpawn(location.getWorld()); + Captions.YOU_GOT_KICKED.send(player2); + if (plot.equals(spawn.getPlot())) { + Location newSpawn = WorldUtil.IMP + .getSpawn(PlotSquared.get().getPlotAreaManager().getAllWorlds()[0]); + if (plot.equals(newSpawn.getPlot())) { + // Kick from server if you can't be teleported to spawn + player2.kick(Captions.YOU_GOT_KICKED.getTranslated()); + } else { + player2.plotkick(newSpawn); + } + } else { + player2.plotkick(spawn); + } } - } else { - player2.plotkick(spawn); } - } + }); + return true; } + + @Override public Collection tab(final PlotPlayer player, final String[] args, final boolean space) { + Location location = player.getLocation(); + Plot plot = location.getPlotAbs(); + if (plot == null) { + return Collections.emptyList(); + } + return TabCompletions.completePlayersInPlot(plot, String.join(",", args).trim(), + Collections.singletonList(player.getName())); + } } diff --git a/Core/src/main/java/com/plotsquared/core/command/Leave.java b/Core/src/main/java/com/plotsquared/core/command/Leave.java index fdd2d70b4..3a0d7f09d 100644 --- a/Core/src/main/java/com/plotsquared/core/command/Leave.java +++ b/Core/src/main/java/com/plotsquared/core/command/Leave.java @@ -48,7 +48,7 @@ public class Leave extends Command { } @Override - public CompletableFuture execute(PlotPlayer player, String[] args, + public CompletableFuture execute(PlotPlayer player, String[] args, RunnableVal3 confirm, RunnableVal2 whenDone) throws CommandException { final Plot plot = check(player.getCurrentPlot(), Captions.NOT_IN_PLOT); diff --git a/Core/src/main/java/com/plotsquared/core/command/Like.java b/Core/src/main/java/com/plotsquared/core/command/Like.java index 9414985c3..216c6524c 100644 --- a/Core/src/main/java/com/plotsquared/core/command/Like.java +++ b/Core/src/main/java/com/plotsquared/core/command/Like.java @@ -175,7 +175,7 @@ public class Like extends SubCommand { return numLikes / (numLikes + numDislikes); } - @Override public boolean onCommand(PlotPlayer player, String[] args) { + @Override public boolean onCommand(PlotPlayer player, String[] args) { return handleLike(player, args, true); } diff --git a/Core/src/main/java/com/plotsquared/core/command/ListCmd.java b/Core/src/main/java/com/plotsquared/core/command/ListCmd.java index 8d151fb10..a08de0cd0 100644 --- a/Core/src/main/java/com/plotsquared/core/command/ListCmd.java +++ b/Core/src/main/java/com/plotsquared/core/command/ListCmd.java @@ -26,13 +26,12 @@ package com.plotsquared.core.command; import com.plotsquared.core.PlotSquared; -import com.plotsquared.core.PlotSquared.SortType; import com.plotsquared.core.configuration.CaptionUtility; import com.plotsquared.core.configuration.Captions; +import com.plotsquared.core.configuration.Settings; import com.plotsquared.core.player.PlotPlayer; import com.plotsquared.core.plot.Plot; import com.plotsquared.core.plot.PlotArea; -import com.plotsquared.core.plot.Rating; import com.plotsquared.core.plot.expiration.ExpireManager; import com.plotsquared.core.plot.flag.implementations.DoneFlag; import com.plotsquared.core.plot.flag.implementations.PriceFlag; @@ -43,26 +42,36 @@ import com.plotsquared.core.util.MathMan; import com.plotsquared.core.util.Permissions; import com.plotsquared.core.util.StringComparison; import com.plotsquared.core.util.StringMan; +import com.plotsquared.core.util.TabCompletions; +import com.plotsquared.core.util.query.PlotQuery; +import com.plotsquared.core.util.query.SortingStrategy; import com.plotsquared.core.util.task.RunnableVal3; -import com.plotsquared.core.util.uuid.UUIDHandler; +import com.plotsquared.core.uuid.UUIDMapping; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.LinkedList; import java.util.List; -import java.util.Map.Entry; import java.util.UUID; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +import java.util.function.Consumer; +import java.util.stream.Collectors; @CommandDeclaration(command = "list", aliases = {"l", "find", "search"}, description = "List plots", permission = "plots.list", category = CommandCategory.INFO, - usage = "/plot list > [#]") + usage = "/plot list > [#]") public class ListCmd extends SubCommand { private String[] getArgumentList(PlotPlayer player) { List args = new ArrayList<>(); - if (EconHandler.manager != null && Permissions + if (EconHandler.getEconHandler() != null && Permissions .hasPermission(player, Captions.PERMISSION_LIST_FOR_SALE)) { args.add("forsale"); } @@ -84,9 +93,6 @@ public class ListCmd extends SubCommand { if (Permissions.hasPermission(player, Captions.PERMISSION_LIST_UNOWNED)) { args.add("unowned"); } - if (Permissions.hasPermission(player, Captions.PERMISSION_LIST_UNKNOWN)) { - args.add("unknown"); - } if (Permissions.hasPermission(player, Captions.PERMISSION_LIST_PLAYER)) { args.add(""); } @@ -110,30 +116,58 @@ public class ListCmd extends SubCommand { .toString(getArgumentList(player))); } - @Override public boolean onCommand(PlotPlayer player, String[] args) { + @Override public boolean onCommand(PlotPlayer player, String[] args) { if (args.length < 1) { noArgs(player); return false; } - int page = 0; + + final int page; if (args.length > 1) { + int tempPage = -1; try { - page = Integer.parseInt(args[args.length - 1]); - --page; - if (page < 0) { - page = 0; + tempPage = Integer.parseInt(args[args.length - 1]); + --tempPage; + if (tempPage < 0) { + tempPage = 0; } } catch (NumberFormatException ignored) { - page = -1; } + page = tempPage; + } else { + page = 0; } - List plots = null; - String world = player.getLocation().getWorld(); PlotArea area = player.getApplicablePlotArea(); String arg = args[0].toLowerCase(); - boolean sort = true; + final boolean[] sort = new boolean[] {true}; + + final Consumer plotConsumer = query -> { + if (query == null) { + sendMessage(player, Captions.DID_YOU_MEAN, + new StringComparison<>(args[0], new String[] {"mine", "shared", "world", "all"}) + .getBestMatch()); + return; + } + + if (area != null) { + query.relativeToArea(area); + } + + if (sort[0]) { + query.withSortingStrategy(SortingStrategy.SORT_BY_CREATION); + } + + final List plots = query.asList(); + + if (plots.isEmpty()) { + MainUtil.sendMessage(player, Captions.FOUND_NO_PLOTS); + return; + } + displayPlots(player, plots, 12, page, args); + }; + switch (arg) { case "mine": if (!Permissions.hasPermission(player, Captions.PERMISSION_LIST_MINE)) { @@ -141,8 +175,8 @@ public class ListCmd extends SubCommand { .sendMessage(player, Captions.NO_PERMISSION, Captions.PERMISSION_LIST_MINE); return false; } - sort = false; - plots = PlotSquared.get().sortPlotsByTemp(PlotSquared.get().getBasePlots(player)); + sort[0] = false; + plotConsumer.accept(PlotQuery.newQuery().ownedBy(player).whereBasePlot().withSortingStrategy(SortingStrategy.SORT_BY_TEMP)); break; case "shared": if (!Permissions.hasPermission(player, Captions.PERMISSION_LIST_SHARED)) { @@ -150,13 +184,7 @@ public class ListCmd extends SubCommand { Captions.PERMISSION_LIST_SHARED); return false; } - plots = new ArrayList<>(); - for (Plot plot : PlotSquared.get().getPlots()) { - if (plot.getTrusted().contains(player.getUUID()) || plot.getMembers() - .contains(player.getUUID())) { - plots.add(plot); - } - } + plotConsumer.accept(PlotQuery.newQuery().withMember(player.getUUID()).thatPasses(plot -> !plot.isOwnerAbs(player.getUUID()))); break; case "world": if (!Permissions.hasPermission(player, Captions.PERMISSION_LIST_WORLD)) { @@ -171,7 +199,7 @@ public class ListCmd extends SubCommand { world)); return false; } - plots = new ArrayList<>(PlotSquared.get().getPlots(world)); + plotConsumer.accept(PlotQuery.newQuery().inWorld(world)); break; case "expired": if (!Permissions.hasPermission(player, Captions.PERMISSION_LIST_EXPIRED)) { @@ -179,9 +207,11 @@ public class ListCmd extends SubCommand { Captions.PERMISSION_LIST_EXPIRED); return false; } - plots = ExpireManager.IMP == null ? - new ArrayList() : - new ArrayList<>(ExpireManager.IMP.getPendingExpired()); + if (ExpireManager.IMP == null) { + plotConsumer.accept(PlotQuery.newQuery().noPlots()); + } else { + plotConsumer.accept(PlotQuery.newQuery().expiredPlots()); + } break; case "area": if (!Permissions.hasPermission(player, Captions.PERMISSION_LIST_AREA)) { @@ -196,7 +226,11 @@ public class ListCmd extends SubCommand { world)); return false; } - plots = area == null ? new ArrayList() : new ArrayList<>(area.getPlots()); + if (area == null) { + plotConsumer.accept(PlotQuery.newQuery().noPlots()); + } else { + plotConsumer.accept(PlotQuery.newQuery().inArea(area)); + } break; case "all": if (!Permissions.hasPermission(player, Captions.PERMISSION_LIST_ALL)) { @@ -204,7 +238,7 @@ public class ListCmd extends SubCommand { .sendMessage(player, Captions.NO_PERMISSION, Captions.PERMISSION_LIST_ALL); return false; } - plots = new ArrayList<>(PlotSquared.get().getPlots()); + plotConsumer.accept(PlotQuery.newQuery().allPlots()); break; case "done": if (!Permissions.hasPermission(player, Captions.PERMISSION_LIST_DONE)) { @@ -212,24 +246,8 @@ public class ListCmd extends SubCommand { .sendMessage(player, Captions.NO_PERMISSION, Captions.PERMISSION_LIST_DONE); return false; } - plots = new ArrayList<>(); - for (Plot plot : PlotSquared.get().getPlots()) { - if (DoneFlag.isDone(plot)) { - plots.add(plot); - } - } - plots.sort((a, b) -> { - String va = a.getFlag(DoneFlag.class); - String vb = b.getFlag(DoneFlag.class); - if (MathMan.isInteger(va)) { - if (MathMan.isInteger(vb)) { - return Integer.parseInt(vb) - Integer.parseInt(va); - } - return -1; - } - return 1; - }); - sort = false; + sort[0] = false; + plotConsumer.accept(PlotQuery.newQuery().allPlots().thatPasses(DoneFlag::isDone).withSortingStrategy(SortingStrategy.SORT_BY_DONE)); break; case "top": if (!Permissions.hasPermission(player, Captions.PERMISSION_LIST_TOP)) { @@ -237,32 +255,8 @@ public class ListCmd extends SubCommand { .sendMessage(player, Captions.NO_PERMISSION, Captions.PERMISSION_LIST_TOP); return false; } - plots = new ArrayList<>(PlotSquared.get().getPlots()); - plots.sort((p1, p2) -> { - double v1 = 0; - int p1s = p1.getSettings().getRatings().size(); - int p2s = p2.getRatings().size(); - if (!p1.getSettings().getRatings().isEmpty()) { - v1 = p1.getRatings().values().stream().mapToDouble(Rating::getAverageRating) - .map(av -> av * av).sum(); - v1 /= p1s; - v1 += p1s; - } - double v2 = 0; - if (!p2.getSettings().getRatings().isEmpty()) { - for (Entry entry : p2.getRatings().entrySet()) { - double av = entry.getValue().getAverageRating(); - v2 += av * av; - } - v2 /= p2s; - v2 += p2s; - } - if (v2 == v1 && v2 != 0) { - return p2s - p1s; - } - return (int) Math.signum(v2 - v1); - }); - sort = false; + sort[0] = false; + plotConsumer.accept(PlotQuery.newQuery().allPlots().withSortingStrategy(SortingStrategy.SORT_BY_RATING)); break; case "forsale": if (!Permissions.hasPermission(player, Captions.PERMISSION_LIST_FOR_SALE)) { @@ -270,15 +264,10 @@ public class ListCmd extends SubCommand { Captions.PERMISSION_LIST_FOR_SALE); return false; } - if (EconHandler.manager == null) { + if (EconHandler.getEconHandler() == null) { break; } - plots = new ArrayList<>(); - for (Plot plot : PlotSquared.get().getPlots()) { - if (plot.getFlag(PriceFlag.class) > 0) { - plots.add(plot); - } - } + plotConsumer.accept(PlotQuery.newQuery().allPlots().thatPasses(plot -> plot.getFlag(PriceFlag.class) > 0)); break; case "unowned": if (!Permissions.hasPermission(player, Captions.PERMISSION_LIST_UNOWNED)) { @@ -286,28 +275,7 @@ public class ListCmd extends SubCommand { Captions.PERMISSION_LIST_UNOWNED); return false; } - plots = new ArrayList<>(); - for (Plot plot : PlotSquared.get().getPlots()) { - if (plot.getOwner() == null) { - plots.add(plot); - } - } - break; - case "unknown": - if (!Permissions.hasPermission(player, Captions.PERMISSION_LIST_UNKNOWN)) { - MainUtil.sendMessage(player, Captions.NO_PERMISSION, - Captions.PERMISSION_LIST_UNKNOWN); - return false; - } - plots = new ArrayList<>(); - for (Plot plot : PlotSquared.get().getPlots()) { - if (plot.getOwner() == null) { - continue; - } - if (UUIDHandler.getName(plot.getOwner()) == null) { - plots.add(plot); - } - } + plotConsumer.accept(PlotQuery.newQuery().allPlots().thatPasses(plot -> plot.getOwner() == null)); break; case "fuzzy": if (!Permissions.hasPermission(player, Captions.PERMISSION_LIST_FUZZY)) { @@ -325,8 +293,8 @@ public class ListCmd extends SubCommand { } else { term = StringMan.join(Arrays.copyOfRange(args, 1, args.length), " "); } - plots = MainUtil.getPlotsBySearch(term); - sort = false; + sort[0] = false; + plotConsumer.accept(PlotQuery.newQuery().plotsBySearch(term)); break; default: if (PlotSquared.get().hasPlotArea(args[0])) { @@ -343,50 +311,43 @@ public class ListCmd extends SubCommand { args[0])); return false; } - plots = new ArrayList<>(PlotSquared.get().getPlots(args[0])); - break; - } - UUID uuid = UUIDHandler.getUUID(args[0], null); - if (uuid == null) { - try { - uuid = UUID.fromString(args[0]); - } catch (Exception ignored) { - } - } - if (uuid != null) { - if (!Permissions.hasPermission(player, Captions.PERMISSION_LIST_PLAYER)) { - MainUtil.sendMessage(player, Captions.NO_PERMISSION, - Captions.PERMISSION_LIST_PLAYER); - return false; - } - sort = false; - plots = PlotSquared.get().sortPlotsByTemp(PlotSquared.get().getPlots(uuid)); + plotConsumer.accept(PlotQuery.newQuery().inWorld(args[0])); break; } + + PlotSquared.get().getImpromptuUUIDPipeline() + .getSingle(args[0], (uuid, throwable) -> { + if (throwable instanceof TimeoutException) { + MainUtil.sendMessage(player, Captions.FETCHING_PLAYERS_TIMEOUT); + } else if (throwable != null) { + if (uuid == null) { + try { + uuid = UUID.fromString(args[0]); + } catch (Exception ignored) { + } + } + } + if (uuid == null) { + MainUtil.sendMessage(player, Captions.INVALID_PLAYER, args[0]); + } else { + if (!Permissions + .hasPermission(player, Captions.PERMISSION_LIST_PLAYER)) { + MainUtil.sendMessage(player, Captions.NO_PERMISSION, + Captions.PERMISSION_LIST_PLAYER); + } else { + sort[0] = false; + plotConsumer.accept(PlotQuery.newQuery().ownedBy(uuid).withSortingStrategy(SortingStrategy.SORT_BY_TEMP)); + } + } + }); } - if (plots == null) { - sendMessage(player, Captions.DID_YOU_MEAN, - new StringComparison<>(args[0], new String[] {"mine", "shared", "world", "all"}) - .getBestMatch()); - return false; - } - - if (plots.isEmpty()) { - MainUtil.sendMessage(player, Captions.FOUND_NO_PLOTS); - return false; - } - displayPlots(player, plots, 12, page, area, args, sort); return true; } - public void displayPlots(final PlotPlayer player, List plots, int pageSize, int page, - PlotArea area, String[] args, boolean sort) { + public void displayPlots(final PlotPlayer player, List plots, int pageSize, int page, String[] args) { // Header plots.removeIf(plot -> !plot.isBasePlot()); - if (sort) { - plots = PlotSquared.get().sortPlots(plots, SortType.CREATION_DATE, area); - } this.paginate(player, plots, pageSize, page, new RunnableVal3() { @Override public void run(Integer i, Plot plot, PlotMessage message) { @@ -417,25 +378,72 @@ public class ListCmd extends SubCommand { .command("/plot info " + plot.getArea() + ";" + plot.getId()).color(color) .text(" - ").color("$2"); String prefix = ""; - for (UUID uuid : plot.getOwners()) { - String name = UUIDHandler.getName(uuid); - if (name == null) { - message = message.text(prefix).color("$4").text("unknown").color("$2") - .tooltip(uuid.toString()).suggest(uuid.toString()); - } else { - PlotPlayer pp = UUIDHandler.getPlayer(uuid); + + try { + final List names = PlotSquared.get().getImpromptuUUIDPipeline() + .getNames(plot.getOwners()).get(Settings.UUID.BLOCKING_TIMEOUT, TimeUnit.MILLISECONDS); + for (final UUIDMapping uuidMapping : names) { + PlotPlayer pp = PlotSquared.imp().getPlayerManager().getPlayerIfExists(uuidMapping.getUuid()); if (pp != null) { - message = message.text(prefix).color("$4").text(name).color("$1") + message = message.text(prefix).color("$4").text(uuidMapping.getUsername()).color("$1") .tooltip(new PlotMessage("Online").color("$4")); } else { - message = message.text(prefix).color("$4").text(name).color("$1") + message = message.text(prefix).color("$4").text(uuidMapping.getUsername()).color("$1") .tooltip(new PlotMessage("Offline").color("$3")); } + prefix = ", "; } - prefix = ", "; + } catch (InterruptedException | ExecutionException e) { + MainUtil.sendMessage(player, Captions.INVALID_PLAYER); + } catch (TimeoutException e) { + MainUtil.sendMessage(player, Captions.FETCHING_PLAYERS_TIMEOUT); } } }, "/plot list " + args[0], Captions.PLOT_LIST_HEADER_PAGED.getTranslated()); } + @Override public Collection tab(PlotPlayer player, String[] args, boolean space) { + final List completions = new LinkedList<>(); + if (EconHandler.getEconHandler() != null && Permissions + .hasPermission(player, Captions.PERMISSION_LIST_FOR_SALE)) { + completions.add("forsale"); + } + if (Permissions.hasPermission(player, Captions.PERMISSION_LIST_MINE)) { + completions.add("mine"); + } + if (Permissions.hasPermission(player, Captions.PERMISSION_LIST_SHARED)) { + completions.add("shared"); + } + if (Permissions.hasPermission(player, Captions.PERMISSION_LIST_WORLD)) { + completions.addAll(PlotSquared.imp().getWorldManager().getWorlds()); + } + if (Permissions.hasPermission(player, Captions.PERMISSION_LIST_TOP)) { + completions.add("top"); + } + if (Permissions.hasPermission(player, Captions.PERMISSION_LIST_ALL)) { + completions.add("all"); + } + if (Permissions.hasPermission(player, Captions.PERMISSION_LIST_UNOWNED)) { + completions.add("unowned"); + } + if (Permissions.hasPermission(player, Captions.PERMISSION_LIST_DONE)) { + completions.add("done"); + } + if (Permissions.hasPermission(player, Captions.PERMISSION_LIST_EXPIRED)) { + completions.add("expired"); + } + + final List commands = new LinkedList<>(); + commands.addAll(completions.stream() + .filter(completion -> completion.toLowerCase().startsWith(args[0].toLowerCase())) + .map(completion -> new Command(null, true, completion, "", RequiredType.NONE, CommandCategory.TELEPORT) {}) + .collect(Collectors.toList())); + + if (Permissions.hasPermission(player, Captions.PERMISSION_LIST_PLAYER) && args[0].length() > 0) { + commands.addAll(TabCompletions.completePlayers(args[0], Collections.emptyList())); + } + + return commands; + } + } diff --git a/Core/src/main/java/com/plotsquared/core/command/Load.java b/Core/src/main/java/com/plotsquared/core/command/Load.java index 58e2197b9..aa952a007 100644 --- a/Core/src/main/java/com/plotsquared/core/command/Load.java +++ b/Core/src/main/java/com/plotsquared/core/command/Load.java @@ -52,7 +52,7 @@ import java.util.List; usage = "/plot load") public class Load extends SubCommand { - @Override public boolean onCommand(final PlotPlayer player, String[] args) { + @Override public boolean onCommand(final PlotPlayer player, String[] args) { String world = player.getLocation().getWorld(); if (!PlotSquared.get().hasPlotArea(world)) { return !sendMessage(player, Captions.NOT_IN_PLOT_WORLD); @@ -152,7 +152,7 @@ public class Load extends SubCommand { return true; } - public void displaySaves(PlotPlayer player) { + public void displaySaves(PlotPlayer player) { List schematics = player.getMeta("plot_schematics"); for (int i = 0; i < Math.min(schematics.size(), 32); i++) { try { diff --git a/Core/src/main/java/com/plotsquared/core/command/MainCommand.java b/Core/src/main/java/com/plotsquared/core/command/MainCommand.java index 03be061ca..a5c42b117 100644 --- a/Core/src/main/java/com/plotsquared/core/command/MainCommand.java +++ b/Core/src/main/java/com/plotsquared/core/command/MainCommand.java @@ -99,7 +99,6 @@ public class MainCommand extends Command { new DebugPaste(); new Unlink(); new Kick(); - new DebugClaimTest(); new Inbox(); new Comment(); new DatabaseCommand(); @@ -165,14 +164,14 @@ public class MainCommand extends Command { public void run(final Command cmd, final Runnable success, final Runnable failure) { if (cmd.hasConfirmation(player)) { CmdConfirm.addPending(player, cmd.getUsage(), () -> { - if (EconHandler.manager != null) { + if (EconHandler.getEconHandler() != null) { PlotArea area = player.getApplicablePlotArea(); if (area != null) { Expression priceEval = area.getPrices().get(cmd.getFullId()); Double price = priceEval != null ? priceEval.evaluate(0d) : 0d; if (price != null - && EconHandler.manager.getMoney(player) < price) { + && EconHandler.getEconHandler().getMoney(player) < price) { if (failure != null) { failure.run(); } @@ -186,12 +185,12 @@ public class MainCommand extends Command { }); return; } - if (EconHandler.manager != null) { + if (EconHandler.getEconHandler() != null) { PlotArea area = player.getApplicablePlotArea(); if (area != null) { Expression priceEval = area.getPrices().get(cmd.getFullId()); Double price = priceEval != null ? priceEval.evaluate(0d) : 0d; - if (price != 0d && EconHandler.manager.getMoney(player) < price) { + if (price != 0d && EconHandler.getEconHandler().getMoney(player) < price) { if (failure != null) { failure.run(); } @@ -218,7 +217,7 @@ public class MainCommand extends Command { } @Override - public CompletableFuture execute(final PlotPlayer player, String[] args, + public CompletableFuture execute(final PlotPlayer player, String[] args, RunnableVal3 confirm, RunnableVal2 whenDone) { // Clear perm caching // @@ -253,14 +252,14 @@ public class MainCommand extends Command { if ("f".equals(args[0].substring(1))) { confirm = new RunnableVal3() { @Override public void run(Command cmd, Runnable success, Runnable failure) { - if (EconHandler.manager != null) { + if (EconHandler.getEconHandler() != null) { PlotArea area = player.getApplicablePlotArea(); if (area != null) { Expression priceEval = area.getPrices().get(cmd.getFullId()); Double price = priceEval != null ? priceEval.evaluate(0d) : 0d; if (price != 0d - && EconHandler.manager.getMoney(player) < price) { + && EconHandler.getEconHandler().getMoney(player) < price) { if (failure != null) { failure.run(); } diff --git a/Core/src/main/java/com/plotsquared/core/command/Merge.java b/Core/src/main/java/com/plotsquared/core/command/Merge.java index 480112c14..33754c4b8 100644 --- a/Core/src/main/java/com/plotsquared/core/command/Merge.java +++ b/Core/src/main/java/com/plotsquared/core/command/Merge.java @@ -40,7 +40,6 @@ import com.plotsquared.core.util.Expression; import com.plotsquared.core.util.MainUtil; import com.plotsquared.core.util.Permissions; import com.plotsquared.core.util.StringMan; -import com.plotsquared.core.util.uuid.UUIDHandler; import java.util.UUID; @@ -79,7 +78,7 @@ public class Merge extends SubCommand { } } - @Override public boolean onCommand(final PlotPlayer player, String[] args) { + @Override public boolean onCommand(final PlotPlayer player, String[] args) { Location location = player.getLocationFull(); final Plot plot = location.getPlotAbs(); if (plot == null) { @@ -157,8 +156,8 @@ public class Merge extends SubCommand { return true; } if (plot.autoMerge(Direction.ALL, maxSize, uuid, terrain)) { - if (EconHandler.manager != null && plotArea.useEconomy() && price > 0d) { - EconHandler.manager.withdrawMoney(player, price); + if (EconHandler.getEconHandler() != null && plotArea.useEconomy() && price > 0d) { + EconHandler.getEconHandler().withdrawMoney(player, price); sendMessage(player, Captions.REMOVED_BALANCE, String.valueOf(price)); } MainUtil.sendMessage(player, Captions.SUCCESS_MERGE); @@ -172,11 +171,11 @@ public class Merge extends SubCommand { MainUtil.sendMessage(player, Captions.NO_PLOT_PERMS); return false; } else { - uuid = plot.guessOwner(); + uuid = plot.getOwnerAbs(); } } - if (!force && EconHandler.manager != null && plotArea.useEconomy() && price > 0d - && EconHandler.manager.getMoney(player) < price) { + if (!force && EconHandler.getEconHandler() != null && plotArea.useEconomy() && price > 0d + && EconHandler.getEconHandler().getMoney(player) < price) { sendMessage(player, Captions.CANNOT_AFFORD_MERGE, String.valueOf(price)); return false; } @@ -193,8 +192,8 @@ public class Merge extends SubCommand { return true; } if (plot.autoMerge(direction, maxSize - size, uuid, terrain)) { - if (EconHandler.manager != null && plotArea.useEconomy() && price > 0d) { - EconHandler.manager.withdrawMoney(player, price); + if (EconHandler.getEconHandler() != null && plotArea.useEconomy() && price > 0d) { + EconHandler.getEconHandler().withdrawMoney(player, price); sendMessage(player, Captions.REMOVED_BALANCE, String.valueOf(price)); } MainUtil.sendMessage(player, Captions.SUCCESS_MERGE); @@ -213,7 +212,7 @@ public class Merge extends SubCommand { java.util.Set uuids = adjacent.getOwners(); boolean isOnline = false; for (final UUID owner : uuids) { - final PlotPlayer accepter = UUIDHandler.getPlayer(owner); + final PlotPlayer accepter = PlotSquared.imp().getPlayerManager().getPlayerIfExists(owner); if (!force && accepter == null) { continue; } @@ -222,17 +221,17 @@ public class Merge extends SubCommand { Runnable run = () -> { MainUtil.sendMessage(accepter, Captions.MERGE_ACCEPTED); plot.autoMerge(dir, maxSize - size, owner, terrain); - PlotPlayer plotPlayer = UUIDHandler.getPlayer(player.getUUID()); + PlotPlayer plotPlayer = PlotSquared.imp().getPlayerManager().getPlayerIfExists(player.getUUID()); if (plotPlayer == null) { sendMessage(accepter, Captions.MERGE_NOT_VALID); return; } - if (EconHandler.manager != null && plotArea.useEconomy() && price > 0d) { - if (!force && EconHandler.manager.getMoney(player) < price) { + if (EconHandler.getEconHandler() != null && plotArea.useEconomy() && price > 0d) { + if (!force && EconHandler.getEconHandler().getMoney(player) < price) { sendMessage(player, Captions.CANNOT_AFFORD_MERGE, String.valueOf(price)); return; } - EconHandler.manager.withdrawMoney(player, price); + EconHandler.getEconHandler().withdrawMoney(player, price); sendMessage(player, Captions.REMOVED_BALANCE, String.valueOf(price)); } MainUtil.sendMessage(player, Captions.SUCCESS_MERGE); diff --git a/Core/src/main/java/com/plotsquared/core/command/Middle.java b/Core/src/main/java/com/plotsquared/core/command/Middle.java index 58e7e437b..14c760eef 100644 --- a/Core/src/main/java/com/plotsquared/core/command/Middle.java +++ b/Core/src/main/java/com/plotsquared/core/command/Middle.java @@ -42,7 +42,7 @@ import com.plotsquared.core.plot.Plot; requiredType = RequiredType.PLAYER) public class Middle extends SubCommand { - @Override public boolean onCommand(PlotPlayer player, String[] arguments) { + @Override public boolean onCommand(PlotPlayer player, String[] arguments) { Location location = player.getLocation(); Plot plot = location.getPlot(); if (plot == null) { diff --git a/Core/src/main/java/com/plotsquared/core/command/Move.java b/Core/src/main/java/com/plotsquared/core/command/Move.java index e95c35a1c..136bbcfaa 100644 --- a/Core/src/main/java/com/plotsquared/core/command/Move.java +++ b/Core/src/main/java/com/plotsquared/core/command/Move.java @@ -47,7 +47,7 @@ import java.util.concurrent.CompletableFuture; public class Move extends SubCommand { @Override - public CompletableFuture execute(PlotPlayer player, String[] args, + public CompletableFuture execute(PlotPlayer player, String[] args, RunnableVal3 confirm, RunnableVal2 whenDone) { Location location = player.getLocation(); @@ -107,7 +107,7 @@ public class Move extends SubCommand { }); } - @Override public boolean onCommand(final PlotPlayer player, String[] args) { + @Override public boolean onCommand(final PlotPlayer player, String[] args) { return true; } diff --git a/Core/src/main/java/com/plotsquared/core/command/Music.java b/Core/src/main/java/com/plotsquared/core/command/Music.java index 78e0b74e1..91b756a81 100644 --- a/Core/src/main/java/com/plotsquared/core/command/Music.java +++ b/Core/src/main/java/com/plotsquared/core/command/Music.java @@ -55,7 +55,7 @@ public class Music extends SubCommand { "music_disc_far", "music_disc_mall", "music_disc_mellohi", "music_disc_stal", "music_disc_strad", "music_disc_ward", "music_disc_11", "music_disc_wait"); - @Override public boolean onCommand(PlotPlayer player, String[] args) { + @Override public boolean onCommand(PlotPlayer player, String[] args) { Location location = player.getLocation(); final Plot plot = location.getPlotAbs(); if (plot == null) { diff --git a/Core/src/main/java/com/plotsquared/core/command/Near.java b/Core/src/main/java/com/plotsquared/core/command/Near.java index a7c020762..20780613a 100644 --- a/Core/src/main/java/com/plotsquared/core/command/Near.java +++ b/Core/src/main/java/com/plotsquared/core/command/Near.java @@ -46,7 +46,7 @@ public class Near extends Command { } @Override - public CompletableFuture execute(PlotPlayer player, String[] args, + public CompletableFuture execute(PlotPlayer player, String[] args, RunnableVal3 confirm, RunnableVal2 whenDone) throws CommandException { final Plot plot = check(player.getCurrentPlot(), Captions.NOT_IN_PLOT); diff --git a/Core/src/main/java/com/plotsquared/core/command/Owner.java b/Core/src/main/java/com/plotsquared/core/command/Owner.java index 2c3d8e965..f19790dc5 100644 --- a/Core/src/main/java/com/plotsquared/core/command/Owner.java +++ b/Core/src/main/java/com/plotsquared/core/command/Owner.java @@ -36,10 +36,11 @@ import com.plotsquared.core.plot.Plot; import com.plotsquared.core.util.MainUtil; import com.plotsquared.core.util.Permissions; import com.plotsquared.core.util.task.TaskManager; -import com.plotsquared.core.util.uuid.UUIDHandler; import java.util.Set; import java.util.UUID; +import java.util.concurrent.TimeoutException; +import java.util.function.Consumer; @CommandDeclaration(command = "setowner", permission = "plots.set.owner", @@ -57,91 +58,103 @@ public class Owner extends SetCommand { return false; } Set plots = plot.getConnectedPlots(); - UUID uuid = null; + + final Consumer uuidConsumer = uuid -> { + if (uuid == null && !value.equalsIgnoreCase("none") && !value.equalsIgnoreCase("null") + && !value.equalsIgnoreCase("-")) { + Captions.INVALID_PLAYER.send(player, value); + return; + } + PlotChangeOwnerEvent event = PlotSquared.get().getEventDispatcher() + .callOwnerChange(player, plot, plot.hasOwner() ? plot.getOwnerAbs() : null, uuid, + plot.hasOwner()); + if (event.getEventResult() == Result.DENY) { + sendMessage(player, Captions.EVENT_DENIED, "Owner change"); + return; + } + uuid = event.getNewOwner(); + boolean force = event.getEventResult() == Result.FORCE; + if (uuid == null) { + if (!force && !Permissions + .hasPermission(player, Captions.PERMISSION_ADMIN_COMMAND_SET_OWNER.getTranslated(), + true)) { + return; + } + PlotUnlinkEvent unlinkEvent = PlotSquared.get().getEventDispatcher() + .callUnlink(plot.getArea(), plot, false, false, PlotUnlinkEvent.REASON.NEW_OWNER); + if (unlinkEvent.getEventResult() == Result.DENY) { + sendMessage(player, Captions.EVENT_DENIED, "Unlink on owner change"); + return; + } + plot.unlinkPlot(unlinkEvent.isCreateRoad(), unlinkEvent.isCreateRoad()); + Set connected = plot.getConnectedPlots(); + for (Plot current : connected) { + current.unclaim(); + current.removeSign(); + } + MainUtil.sendMessage(player, Captions.SET_OWNER); + return; + } + final PlotPlayer other = PlotSquared.imp().getPlayerManager().getPlayerIfExists(uuid); + if (plot.isOwner(uuid)) { + Captions.ALREADY_OWNER.send(player, MainUtil.getName(uuid)); + return; + } + if (!force && !Permissions + .hasPermission(player, Captions.PERMISSION_ADMIN_COMMAND_SET_OWNER)) { + if (other == null) { + Captions.INVALID_PLAYER_OFFLINE.send(player, value); + return; + } + int size = plots.size(); + int currentPlots = (Settings.Limit.GLOBAL ? + other.getPlotCount() : + other.getPlotCount(plot.getWorldName())) + size; + if (currentPlots > other.getAllowedPlots()) { + sendMessage(player, Captions.CANT_TRANSFER_MORE_PLOTS); + return; + } + } + final UUID finalUUID = uuid; + PlotSquared.get().getImpromptuUUIDPipeline().getSingle(uuid, (finalName, throwable) -> { + final boolean removeDenied = plot.isDenied(finalUUID); + Runnable run = () -> { + if (plot.setOwner(finalUUID, player)) { + if (removeDenied) + plot.removeDenied(finalUUID); + plot.setSign(finalName); + MainUtil.sendMessage(player, Captions.SET_OWNER); + if (other != null) { + MainUtil.sendMessage(other, Captions.NOW_OWNER, + plot.getArea() + ";" + plot.getId()); + } + } else { + MainUtil.sendMessage(player, Captions.SET_OWNER_CANCELLED); + } + }; + if (hasConfirmation(player)) { + CmdConfirm.addPending(player, "/plot set owner " + value, run); + } else { + TaskManager.runTask(run); + } + }); + }; + if (value.length() == 36) { try { - uuid = UUID.fromString(value); + uuidConsumer.accept(UUID.fromString(value)); } catch (Exception ignored) { } } else { - uuid = UUIDHandler.getUUID(value, null); - } - if (uuid == null && !value.equalsIgnoreCase("none") && !value.equalsIgnoreCase("null") - && !value.equalsIgnoreCase("-")) { - Captions.INVALID_PLAYER.send(player, value); - return false; - } - PlotChangeOwnerEvent event = PlotSquared.get().getEventDispatcher() - .callOwnerChange(player, plot, plot.hasOwner() ? plot.getOwnerAbs() : null, uuid, - plot.hasOwner()); - if (event.getEventResult() == Result.DENY) { - sendMessage(player, Captions.EVENT_DENIED, "Owner change"); - return false; - } - uuid = event.getNewOwner(); - boolean force = event.getEventResult() == Result.FORCE; - if (uuid == null) { - if (!force && !Permissions - .hasPermission(player, Captions.PERMISSION_ADMIN_COMMAND_SET_OWNER.getTranslated(), - true)) { - return false; - } - PlotUnlinkEvent unlinkEvent = PlotSquared.get().getEventDispatcher() - .callUnlink(plot.getArea(), plot, false, false, PlotUnlinkEvent.REASON.NEW_OWNER); - if (unlinkEvent.getEventResult() == Result.DENY) { - sendMessage(player, Captions.EVENT_DENIED, "Unlink on owner change"); - return true; - } - plot.unlinkPlot(unlinkEvent.isCreateRoad(), unlinkEvent.isCreateRoad()); - Set connected = plot.getConnectedPlots(); - for (Plot current : connected) { - current.unclaim(); - current.removeSign(); - } - MainUtil.sendMessage(player, Captions.SET_OWNER); - return true; - } - final PlotPlayer other = UUIDHandler.getPlayer(uuid); - if (plot.isOwner(uuid)) { - Captions.ALREADY_OWNER.send(player, MainUtil.getName(uuid)); - return false; - } - if (!force && !Permissions - .hasPermission(player, Captions.PERMISSION_ADMIN_COMMAND_SET_OWNER)) { - if (other == null) { - Captions.INVALID_PLAYER_OFFLINE.send(player, value); - return false; - } - int size = plots.size(); - int currentPlots = (Settings.Limit.GLOBAL ? - other.getPlotCount() : - other.getPlotCount(plot.getWorldName())) + size; - if (currentPlots > other.getAllowedPlots()) { - sendMessage(player, Captions.CANT_TRANSFER_MORE_PLOTS); - return false; - } - } - final String finalName = UUIDHandler.getName(uuid); - final UUID finalUUID = uuid; - final boolean removeDenied = plot.isDenied(finalUUID); - Runnable run = () -> { - if (plot.setOwner(finalUUID, player)) { - if (removeDenied) - plot.removeDenied(finalUUID); - plot.setSign(finalName); - MainUtil.sendMessage(player, Captions.SET_OWNER); - if (other != null) { - MainUtil.sendMessage(other, Captions.NOW_OWNER, - plot.getArea() + ";" + plot.getId()); - } - } else { - MainUtil.sendMessage(player, Captions.SET_OWNER_CANCELLED); - } - }; - if (hasConfirmation(player)) { - CmdConfirm.addPending(player, "/plot set owner " + value, run); - } else { - TaskManager.runTask(run); + PlotSquared.get().getImpromptuUUIDPipeline().getSingle(value, (uuid, throwable) -> { + if (throwable instanceof TimeoutException) { + MainUtil.sendMessage(player, Captions.FETCHING_PLAYERS_TIMEOUT); + } else if (throwable != null) { + MainUtil.sendMessage(player, Captions.INVALID_PLAYER, value); + } else { + uuidConsumer.accept(uuid); + } + }); } return true; } diff --git a/Core/src/main/java/com/plotsquared/core/command/PluginCmd.java b/Core/src/main/java/com/plotsquared/core/command/PluginCmd.java index 503e65586..b0bf24d40 100644 --- a/Core/src/main/java/com/plotsquared/core/command/PluginCmd.java +++ b/Core/src/main/java/com/plotsquared/core/command/PluginCmd.java @@ -39,7 +39,7 @@ import com.plotsquared.core.util.task.TaskManager; category = CommandCategory.INFO) public class PluginCmd extends SubCommand { - @Override public boolean onCommand(final PlotPlayer player, String[] args) { + @Override public boolean onCommand(final PlotPlayer player, String[] args) { TaskManager.IMP.taskAsync(() -> { MainUtil.sendMessage(player, String.format( "$2>> $1&l" + PlotSquared.imp().getPluginName() + " $2($1Version$2: $1%s$2)", diff --git a/Core/src/main/java/com/plotsquared/core/command/Purge.java b/Core/src/main/java/com/plotsquared/core/command/Purge.java index 3691f44c9..9a89b2230 100644 --- a/Core/src/main/java/com/plotsquared/core/command/Purge.java +++ b/Core/src/main/java/com/plotsquared/core/command/Purge.java @@ -36,7 +36,6 @@ import com.plotsquared.core.plot.PlotArea; import com.plotsquared.core.plot.PlotId; import com.plotsquared.core.util.StringMan; import com.plotsquared.core.util.task.TaskManager; -import com.plotsquared.core.util.uuid.UUIDHandler; import java.util.HashMap; import java.util.HashSet; @@ -54,7 +53,7 @@ import java.util.concurrent.atomic.AtomicBoolean; confirmation = true) public class Purge extends SubCommand { - @Override public boolean onCommand(final PlotPlayer player, String[] args) { + @Override public boolean onCommand(final PlotPlayer player, String[] args) { if (args.length == 0) { Captions.COMMAND_SYNTAX.send(player, getUsage()); return false; @@ -65,7 +64,6 @@ public class Purge extends SubCommand { PlotId id = null; UUID owner = null; UUID added = null; - boolean unknown = false; boolean clear = false; for (String arg : args) { String[] split = arg.split(":"); @@ -97,7 +95,7 @@ public class Purge extends SubCommand { break; case "owner": case "o": - owner = UUIDHandler.getUUID(split[1], null); + owner = PlotSquared.get().getImpromptuUUIDPipeline().getSingle(split[1], Settings.UUID.BLOCKING_TIMEOUT); if (owner == null) { Captions.INVALID_PLAYER.send(player, split[1]); return false; @@ -105,17 +103,12 @@ public class Purge extends SubCommand { break; case "shared": case "s": - added = UUIDHandler.getUUID(split[1], null); + added = PlotSquared.get().getImpromptuUUIDPipeline().getSingle(split[1], Settings.UUID.BLOCKING_TIMEOUT); if (added == null) { Captions.INVALID_PLAYER.send(player, split[1]); return false; } break; - case "unknown": - case "?": - case "u": - unknown = Boolean.parseBoolean(split[1]); - break; case "clear": case "c": case "delete": @@ -145,9 +138,6 @@ public class Purge extends SubCommand { if (added != null && !plot.isAdded(added)) { continue; } - if (unknown && UUIDHandler.getName(plot.getOwnerAbs()) != null) { - continue; - } toDelete.addAll(plot.getConnectedPlots()); } if (PlotSquared.get().plots_tmp != null) { @@ -168,9 +158,6 @@ public class Purge extends SubCommand { if (added != null && !plot.isAdded(added)) { continue; } - if (unknown && UUIDHandler.getName(plot.getOwnerAbs()) != null) { - continue; - } toDelete.add(plot); } } diff --git a/Core/src/main/java/com/plotsquared/core/command/Rate.java b/Core/src/main/java/com/plotsquared/core/command/Rate.java index 1d80a0c37..23affc37d 100644 --- a/Core/src/main/java/com/plotsquared/core/command/Rate.java +++ b/Core/src/main/java/com/plotsquared/core/command/Rate.java @@ -56,7 +56,7 @@ import java.util.UUID; requiredType = RequiredType.PLAYER) public class Rate extends SubCommand { - @Override public boolean onCommand(final PlotPlayer player, String[] args) { + @Override public boolean onCommand(final PlotPlayer player, String[] args) { if (args.length == 1) { switch (args[0].toLowerCase()) { case "next": { diff --git a/Core/src/main/java/com/plotsquared/core/command/RegenAllRoads.java b/Core/src/main/java/com/plotsquared/core/command/RegenAllRoads.java index c5334241e..69d0022f6 100644 --- a/Core/src/main/java/com/plotsquared/core/command/RegenAllRoads.java +++ b/Core/src/main/java/com/plotsquared/core/command/RegenAllRoads.java @@ -43,7 +43,7 @@ import com.plotsquared.core.util.MainUtil; permission = "plots.regenallroads") public class RegenAllRoads extends SubCommand { - @Override public boolean onCommand(PlotPlayer player, String[] args) { + @Override public boolean onCommand(PlotPlayer player, String[] args) { int height = 0; if (args.length == 2) { try { diff --git a/Core/src/main/java/com/plotsquared/core/command/Relight.java b/Core/src/main/java/com/plotsquared/core/command/Relight.java index b41e80baa..4a2475b5f 100644 --- a/Core/src/main/java/com/plotsquared/core/command/Relight.java +++ b/Core/src/main/java/com/plotsquared/core/command/Relight.java @@ -47,7 +47,7 @@ public class Relight extends Command { } @Override - public CompletableFuture execute(final PlotPlayer player, String[] args, + public CompletableFuture execute(final PlotPlayer player, String[] args, RunnableVal3 confirm, RunnableVal2 whenDone) { final Plot plot = player.getCurrentPlot(); diff --git a/Core/src/main/java/com/plotsquared/core/command/Reload.java b/Core/src/main/java/com/plotsquared/core/command/Reload.java index 2fc594d23..0b8f4b6fe 100644 --- a/Core/src/main/java/com/plotsquared/core/command/Reload.java +++ b/Core/src/main/java/com/plotsquared/core/command/Reload.java @@ -45,7 +45,7 @@ import java.util.Objects; category = CommandCategory.ADMINISTRATION) public class Reload extends SubCommand { - @Override public boolean onCommand(PlotPlayer player, String[] args) { + @Override public boolean onCommand(PlotPlayer player, String[] args) { try { // The following won't affect world generation, as that has to be // loaded during startup unfortunately. diff --git a/Core/src/main/java/com/plotsquared/core/command/Remove.java b/Core/src/main/java/com/plotsquared/core/command/Remove.java index 2ed34aca9..871bd2b60 100644 --- a/Core/src/main/java/com/plotsquared/core/command/Remove.java +++ b/Core/src/main/java/com/plotsquared/core/command/Remove.java @@ -33,12 +33,12 @@ import com.plotsquared.core.player.PlotPlayer; import com.plotsquared.core.plot.Plot; import com.plotsquared.core.util.MainUtil; import com.plotsquared.core.util.Permissions; -import com.plotsquared.core.util.uuid.UUIDHandler; +import com.plotsquared.core.util.TabCompletions; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.Set; +import java.util.Collection; +import java.util.Collections; import java.util.UUID; +import java.util.concurrent.TimeoutException; @CommandDeclaration(command = "remove", aliases = {"r", "untrust", "ut", "undeny", "unban", "ud"}, @@ -53,7 +53,7 @@ public class Remove extends SubCommand { super(Argument.PlayerName); } - @Override public boolean onCommand(PlotPlayer player, String[] args) { + @Override public boolean onCommand(PlotPlayer player, String[] args) { Location location = player.getLocation(); Plot plot = location.getPlotAbs(); if (plot == null) { @@ -68,74 +68,69 @@ public class Remove extends SubCommand { MainUtil.sendMessage(player, Captions.NO_PLOT_PERMS); return true; } - int count = 0; - switch (args[0]) { - case "unknown": { - HashSet all = new HashSet<>(); - all.addAll(plot.getMembers()); - all.addAll(plot.getTrusted()); - all.addAll(plot.getDenied()); - ArrayList toRemove = new ArrayList<>(); - for (UUID uuid : all) { - if (UUIDHandler.getName(uuid) == null) { - toRemove.add(uuid); - count++; - } - } - for (UUID uuid : toRemove) { - plot.removeDenied(uuid); - plot.removeTrusted(uuid); - plot.removeMember(uuid); - } - break; - } - default: - Set uuids = MainUtil.getUUIDsFromString(args[0]); - if (!uuids.isEmpty()) { - for (UUID uuid : uuids) { - if (plot.getTrusted().contains(uuid)) { - if (plot.removeTrusted(uuid)) { - PlotSquared.get().getEventDispatcher() - .callTrusted(player, plot, uuid, false); - count++; - } - } else if (plot.getMembers().contains(uuid)) { - if (plot.removeMember(uuid)) { - PlotSquared.get().getEventDispatcher() - .callMember(player, plot, uuid, false); - count++; - } - } else if (plot.getDenied().contains(uuid)) { - if (plot.removeDenied(uuid)) { - PlotSquared.get().getEventDispatcher() - .callDenied(player, plot, uuid, false); - count++; - } - } else if (uuid == DBFunc.EVERYONE) { - if (plot.removeTrusted(uuid)) { - PlotSquared.get().getEventDispatcher() - .callTrusted(player, plot, uuid, false); - count++; - } else if (plot.removeMember(uuid)) { - PlotSquared.get().getEventDispatcher() - .callMember(player, plot, uuid, false); - count++; - } else if (plot.removeDenied(uuid)) { - PlotSquared.get().getEventDispatcher() - .callDenied(player, plot, uuid, false); - count++; - } + + MainUtil.getUUIDsFromString(args[0], (uuids, throwable) -> { + int count = 0; + if (throwable instanceof TimeoutException) { + MainUtil.sendMessage(player, Captions.FETCHING_PLAYERS_TIMEOUT); + return; + } else if (throwable != null) { + MainUtil.sendMessage(player, Captions.INVALID_PLAYER, args[0]); + return; + } else if (!uuids.isEmpty()) { + for (UUID uuid : uuids) { + if (plot.getTrusted().contains(uuid)) { + if (plot.removeTrusted(uuid)) { + PlotSquared.get().getEventDispatcher() + .callTrusted(player, plot, uuid, false); + count++; + } + } else if (plot.getMembers().contains(uuid)) { + if (plot.removeMember(uuid)) { + PlotSquared.get().getEventDispatcher() + .callMember(player, plot, uuid, false); + count++; + } + } else if (plot.getDenied().contains(uuid)) { + if (plot.removeDenied(uuid)) { + PlotSquared.get().getEventDispatcher() + .callDenied(player, plot, uuid, false); + count++; + } + } else if (uuid == DBFunc.EVERYONE) { + if (plot.removeTrusted(uuid)) { + PlotSquared.get().getEventDispatcher() + .callTrusted(player, plot, uuid, false); + count++; + } else if (plot.removeMember(uuid)) { + PlotSquared.get().getEventDispatcher() + .callMember(player, plot, uuid, false); + count++; + } else if (plot.removeDenied(uuid)) { + PlotSquared.get().getEventDispatcher() + .callDenied(player, plot, uuid, false); + count++; } } } - break; - } - if (count == 0) { - MainUtil.sendMessage(player, Captions.INVALID_PLAYER, args[0]); - return false; - } else { - MainUtil.sendMessage(player, Captions.REMOVED_PLAYERS, count + ""); - } + } + if (count == 0) { + MainUtil.sendMessage(player, Captions.INVALID_PLAYER, args[0]); + } else { + MainUtil.sendMessage(player, Captions.REMOVED_PLAYERS, count + ""); + } + }); return true; } + + @Override public Collection tab(final PlotPlayer player, final String[] args, final boolean space) { + Location location = player.getLocation(); + Plot plot = location.getPlotAbs(); + if (plot == null) { + return Collections.emptyList(); + } + return TabCompletions.completeAddedPlayers(plot, String.join(",", args).trim(), + Collections.singletonList(player.getName())); + } + } diff --git a/Core/src/main/java/com/plotsquared/core/command/Save.java b/Core/src/main/java/com/plotsquared/core/command/Save.java index 6196f08b7..480167576 100644 --- a/Core/src/main/java/com/plotsquared/core/command/Save.java +++ b/Core/src/main/java/com/plotsquared/core/command/Save.java @@ -49,7 +49,7 @@ import java.util.UUID; permission = "plots.save") public class Save extends SubCommand { - @Override public boolean onCommand(final PlotPlayer player, String[] args) { + @Override public boolean onCommand(final PlotPlayer player, String[] args) { String world = player.getLocation().getWorld(); if (!PlotSquared.get().hasPlotArea(world)) { return !sendMessage(player, Captions.NOT_IN_PLOT_WORLD); diff --git a/Core/src/main/java/com/plotsquared/core/command/SchematicCmd.java b/Core/src/main/java/com/plotsquared/core/command/SchematicCmd.java index 89c29b6c2..66e4a0662 100644 --- a/Core/src/main/java/com/plotsquared/core/command/SchematicCmd.java +++ b/Core/src/main/java/com/plotsquared/core/command/SchematicCmd.java @@ -57,7 +57,7 @@ public class SchematicCmd extends SubCommand { private boolean running = false; - @Override public boolean onCommand(final PlotPlayer player, String[] args) { + @Override public boolean onCommand(final PlotPlayer player, String[] args) { if (args.length < 1) { sendMessage(player, Captions.SCHEMATIC_MISSING_ARG); return true; diff --git a/Core/src/main/java/com/plotsquared/core/command/Set.java b/Core/src/main/java/com/plotsquared/core/command/Set.java index 4e6fcafc9..ec75fd9eb 100644 --- a/Core/src/main/java/com/plotsquared/core/command/Set.java +++ b/Core/src/main/java/com/plotsquared/core/command/Set.java @@ -37,6 +37,7 @@ import com.plotsquared.core.util.MainUtil; import com.plotsquared.core.util.PatternUtil; import com.plotsquared.core.util.Permissions; import com.plotsquared.core.util.StringMan; +import com.plotsquared.core.util.TabCompletions; import com.plotsquared.core.util.WorldUtil; import com.sk89q.worldedit.function.pattern.Pattern; import com.sk89q.worldedit.world.block.BlockCategory; @@ -76,7 +77,6 @@ public class Set extends SubCommand { @Override public boolean set(PlotPlayer player, final Plot plot, String value) { PlotManager manager = player.getLocation().getPlotManager(); String[] components = manager.getPlotComponents(plot.getId()); - boolean allowUnsafe = DebugAllowUnsafe.unsafeAllowed.contains(player.getUUID()); String[] args = value.split(" "); String material = @@ -159,11 +159,7 @@ public class Set extends SubCommand { @Override public Collection tab(final PlotPlayer player, final String[] args, final boolean space) { - return PatternUtil.getSuggestions(player, StringMan.join(args, ",").trim()).stream() - .map(value -> value.toLowerCase(Locale.ENGLISH).replace("minecraft:", "")) - .filter(value -> value.startsWith(args[0].toLowerCase(Locale.ENGLISH))) - .map(value -> new Command(null, false, value, "", RequiredType.NONE, null) { - }).collect(Collectors.toList()); + return TabCompletions.completePatterns(StringMan.join(args, ",")); } }; } @@ -180,7 +176,7 @@ public class Set extends SubCommand { return false; } - @Override public boolean onCommand(PlotPlayer player, String[] args) { + @Override public boolean onCommand(PlotPlayer player, String[] args) { if (args.length == 0) { return noArgs(player); } diff --git a/Core/src/main/java/com/plotsquared/core/command/SetCommand.java b/Core/src/main/java/com/plotsquared/core/command/SetCommand.java index 9531790cb..aede7e779 100644 --- a/Core/src/main/java/com/plotsquared/core/command/SetCommand.java +++ b/Core/src/main/java/com/plotsquared/core/command/SetCommand.java @@ -36,7 +36,7 @@ import com.plotsquared.core.util.StringMan; public abstract class SetCommand extends SubCommand { - @Override public boolean onCommand(PlotPlayer player, String[] args) { + @Override public boolean onCommand(PlotPlayer player, String[] args) { Location location = player.getLocation(); Plot plot = location.getPlotAbs(); if (plot == null) { @@ -52,7 +52,7 @@ public abstract class SetCommand extends SubCommand { return false; } } - if (!plot.isOwner(player.getUUID()) && !plot.getTrusted().contains(player.getUUID())) { + if (!plot.isOwner(player.getUUID())) { if (!Permissions.hasPermission(player, CaptionUtility .format(player, Captions.PERMISSION_ADMIN_COMMAND.getTranslated(), getFullId()))) { MainUtil.sendMessage(player, Captions.NO_PERMISSION, CaptionUtility diff --git a/Core/src/main/java/com/plotsquared/core/command/Setup.java b/Core/src/main/java/com/plotsquared/core/command/Setup.java index ea76e36cf..bdcd20697 100644 --- a/Core/src/main/java/com/plotsquared/core/command/Setup.java +++ b/Core/src/main/java/com/plotsquared/core/command/Setup.java @@ -27,39 +27,18 @@ package com.plotsquared.core.command; import com.plotsquared.core.PlotSquared; import com.plotsquared.core.configuration.Captions; -import com.plotsquared.core.configuration.ConfigurationNode; -import com.plotsquared.core.configuration.ConfigurationUtil; -import com.plotsquared.core.events.TeleportCause; import com.plotsquared.core.generator.GeneratorWrapper; import com.plotsquared.core.player.PlotPlayer; -import com.plotsquared.core.plot.PlotArea; -import com.plotsquared.core.plot.PlotAreaTerrainType; -import com.plotsquared.core.plot.PlotAreaType; -import com.plotsquared.core.plot.PlotId; -import com.plotsquared.core.plot.SetupObject; -import com.plotsquared.core.plot.message.PlotMessage; +import com.plotsquared.core.setup.SetupProcess; +import com.plotsquared.core.setup.SetupStep; import com.plotsquared.core.util.MainUtil; import com.plotsquared.core.util.SetupUtils; -import com.plotsquared.core.util.StringMan; -import com.plotsquared.core.util.WorldUtil; -import lombok.AccessLevel; -import lombok.AllArgsConstructor; -import lombok.EqualsAndHashCode; -import lombok.Getter; -import lombok.NonNull; -import lombok.RequiredArgsConstructor; -import lombok.ToString; -import org.jetbrains.annotations.Nullable; import java.util.ArrayList; -import java.util.Arrays; import java.util.Collection; -import java.util.HashMap; +import java.util.Collections; import java.util.List; -import java.util.Map; import java.util.Map.Entry; -import java.util.Optional; -import java.util.UUID; @CommandDeclaration(command = "setup", permission = "plots.admin.command.setup", @@ -69,13 +48,7 @@ import java.util.UUID; category = CommandCategory.ADMINISTRATION) public class Setup extends SubCommand { - private static boolean d(String s) { - return s.chars().allMatch((i) -> { - return i == 95 || i == 45 || i >= 97 && i <= 122 || i >= 48 && i <= 57 || i == 46; - }); - } - - public void displayGenerators(PlotPlayer player) { + public void displayGenerators(PlotPlayer player) { StringBuilder message = new StringBuilder(); message.append("&6What generator do you want?"); for (Entry> entry : SetupUtils.generators.entrySet()) { @@ -90,397 +63,60 @@ public class Setup extends SubCommand { MainUtil.sendMessage(player, message.toString()); } - @Override public boolean onCommand(PlotPlayer player, String[] args) { - // going through setup - SetupObject object = player.getMeta("setup"); - if (object == null) { - object = new SetupObject(); - player.setMeta("setup", object); + @Override public boolean onCommand(PlotPlayer player, String[] args) { + SetupProcess process = player.getMeta("setup"); + if (process == null) { + if (args.length > 0) { + MainUtil.sendMessage(player, Captions.SETUP_NOT_STARTED); + return true; + } + process = new SetupProcess(); + player.setMeta("setup", process); SetupUtils.manager.updateGenerators(); - sendMessage(player, Captions.SETUP_INIT); + SetupStep step = process.getCurrentStep(); + step.announce(player); displayGenerators(player); - return false; + return true; } if (args.length == 1) { - if (args[0].equalsIgnoreCase("cancel")) { + if ("back".equalsIgnoreCase(args[0])) { + process.back(); + process.getCurrentStep().announce(player); + } else if ("cancel".equalsIgnoreCase(args[0])) { player.deleteMeta("setup"); MainUtil.sendMessage(player, Captions.SETUP_CANCELLED); - return false; - } - if (args[0].equalsIgnoreCase("back")) { - if (object.setup_index > 0) { - object.setup_index--; - ConfigurationNode node = object.step[object.setup_index]; - sendMessage(player, Captions.SETUP_STEP, object.setup_index + 1, - node.getDescription(), node.getType().getType(), - String.valueOf(node.getDefaultValue())); - return false; - } else if (object.current > 0) { - object.current--; + } else { + process.handleInput(player, args[0]); + if (process.getCurrentStep() != null) { + process.getCurrentStep().announce(player); } } + } else { + process.getCurrentStep().announce(player); } - int index = object.current; - switch (index) { - case 0: // choose generator - if (args.length != 1 || !SetupUtils.generators.containsKey(args[0])) { - String prefix = "\n&8 - &7"; - MainUtil.sendMessage(player, - Captions.SETUP_WORLD_GENERATOR_ERROR + prefix + StringMan - .join(SetupUtils.generators.keySet(), prefix) - .replaceAll(PlotSquared.imp().getPluginName(), - "&2" + PlotSquared.imp().getPluginName())); - sendMessage(player, Captions.SETUP_INIT); - return false; - } - object.setupGenerator = args[0]; - object.current++; - MainUtil.sendMessage(player, Captions.SETUP_WORLD_TYPE); - break; - case 1: // choose world type - List allTypes = Arrays.asList("normal", "augmented", "partial"); - List allDesc = Arrays - .asList("Standard plot generation", "Plot generation with vanilla terrain", - "Vanilla with clusters of plots"); - ArrayList types = new ArrayList<>(); - if (SetupUtils.generators.get(object.setupGenerator).isFull()) { - types.add("normal"); - } - types.add("augmented"); - types.add("partial"); - Optional plotAreaType; - if (args.length != 1 || !(plotAreaType = PlotAreaType.fromString(args[0])) - .isPresent()) { - MainUtil.sendMessage(player, Captions.SETUP_WORLD_TYPE_ERROR); - for (String type : types) { - int i = allTypes.indexOf(type); - if (type.equals("normal")) { - MainUtil - .sendMessage(player, "&8 - &2" + type + " &8-&7 " + allDesc.get(i)); - } else { - MainUtil - .sendMessage(player, "&8 - &7" + type + " &8-&7 " + allDesc.get(i)); - } - } - return false; - } - object.type = plotAreaType.orElse(PlotAreaType.NORMAL); - GeneratorWrapper gen = SetupUtils.generators.get(object.setupGenerator); - if (object.type == PlotAreaType.NORMAL) { - object.current = 6; - if (object.step == null) { - object.plotManager = object.setupGenerator; - object.step = - SetupUtils.generators.get(object.plotManager).getPlotGenerator() - .getNewPlotArea("CheckingPlotSquaredGenerator", null, null, null) - .getSettingNodes(); - SetupUtils.generators.get(object.plotManager).getPlotGenerator() - .processSetup(object); - } - if (object.step.length == 0) { - MainUtil.sendMessage(player, Captions.SETUP_WORLD_NAME); - object.setup_index = 0; - return true; - } - ConfigurationNode step = object.step[object.setup_index]; - sendMessage(player, Captions.SETUP_STEP, object.setup_index + 1, - step.getDescription(), step.getType().getType(), - String.valueOf(step.getDefaultValue())); - } else { - if (gen.isFull()) { - object.plotManager = object.setupGenerator; - object.setupGenerator = null; - object.step = - SetupUtils.generators.get(object.plotManager).getPlotGenerator() - .getNewPlotArea("CheckingPlotSquaredGenerator", null, null, null) - .getSettingNodes(); - SetupUtils.generators.get(object.plotManager).getPlotGenerator() - .processSetup(object); - } else { - object.plotManager = PlotSquared.imp().getPluginName(); - MainUtil.sendMessage(player, Captions.SETUP_WRONG_GENERATOR); - object.step = - SetupUtils.generators.get(object.plotManager).getPlotGenerator() - .getNewPlotArea("CheckingPlotSquaredGenerator", null, null, null) - .getSettingNodes(); - } - if (object.type == PlotAreaType.PARTIAL) { - MainUtil.sendMessage(player, Captions.SETUP_AREA_NAME); - object.current++; - } else { - MainUtil.sendMessage(player, Captions.SETUP_PARTIAL_AREA); - object.current = 5; - } - } - break; - case 2: // area id - if (!StringMan.isAlphanumericUnd(args[0])) { - MainUtil.sendMessage(player, Captions.SETUP_AREA_NON_ALPHANUMERICAL); - return false; - } - for (PlotArea area : PlotSquared.get().getPlotAreas()) { - if (area.getId() != null && area.getId().equalsIgnoreCase(args[0])) { - MainUtil.sendMessage(player, Captions.SETUP_AREA_INVALID_ID); - return false; - } - } - object.id = args[0]; - object.current++; - MainUtil.sendMessage(player, Captions.SETUP_AREA_MIN_PLOT_ID); - break; - case 3: // min - try { - object.min = PlotId.fromString(args[0]); - } catch (IllegalArgumentException ignored) { - MainUtil.sendMessage(player, Captions.SETUP_AREA_MIN_PLOT_ID_ERROR); - return false; - } - object.current++; - MainUtil.sendMessage(player, Captions.SETUP_AREA_MAX_PLOT_ID); - break; - case 4: - // max - PlotId id; - try { - id = PlotId.fromString(args[0]); - } catch (IllegalArgumentException ignored) { - MainUtil.sendMessage(player, Captions.SETUP_AREA_MAX_PLOT_ID_ERROR); - return false; - } - if (id.x <= object.min.x || id.y <= object.min.y) { - MainUtil.sendMessage(player, Captions.SETUP_AREA_PLOT_ID_GREATER_THAN_MINIMUM); - return false; - } - object.max = id; - object.current++; - MainUtil.sendMessage(player, Captions.SETUP_PARTIAL_AREA); - break; - case 5: { // Choose terrain - Optional optTerrain; - if (args.length != 1 || !(optTerrain = PlotAreaTerrainType.fromString(args[0])) - .isPresent()) { - MainUtil.sendMessage(player, Captions.SETUP_PARTIAL_AREA_ERROR, - Captions.SETUP_PARTIAL_AREA); - return false; - } - object.terrain = optTerrain.get(); - object.current++; - if (object.step == null) { - object.step = SetupUtils.generators.get(object.plotManager).getPlotGenerator() - .getNewPlotArea("CheckingPlotSquaredGenerator", null, null, null) - .getSettingNodes(); - } - ConfigurationNode step = object.step[object.setup_index]; - sendMessage(player, Captions.SETUP_STEP, object.setup_index + 1, - step.getDescription(), step.getType().getType(), - String.valueOf(step.getDefaultValue())); - break; - } - case 6: // world setup - if (object.setup_index == object.step.length) { - MainUtil.sendMessage(player, Captions.SETUP_WORLD_NAME); - object.setup_index = 0; - object.current++; - return true; - } - ConfigurationNode step = object.step[object.setup_index]; - if (args.length < 1) { - sendMessage(player, Captions.SETUP_STEP, object.setup_index + 1, - step.getDescription(), step.getType().getType(), - String.valueOf(step.getDefaultValue())); - return false; - } - - boolean valid = false; - try { - valid = step.isValid(args[0]); - } catch (final ConfigurationUtil.UnsafeBlockException e) { - Captions.NOT_ALLOWED_BLOCK.send(player, e.getUnsafeBlock().toString()); - } - if (valid) { - step.setValue(args[0]); - Object value = step.getValue(); - sendMessage(player, Captions.SETUP_VALID_ARG, step.getConstant(), value); - object.setup_index++; - if (object.setup_index == object.step.length) { - onCommand(player, args); - return false; - } - step = object.step[object.setup_index]; - sendMessage(player, Captions.SETUP_STEP, object.setup_index + 1, - step.getDescription(), step.getType().getType(), - String.valueOf(step.getDefaultValue())); - return false; - } else { - sendMessage(player, Captions.SETUP_INVALID_ARG, args[0], step.getConstant()); - sendMessage(player, Captions.SETUP_STEP, object.setup_index + 1, - step.getDescription(), step.getType().getType(), - String.valueOf(step.getDefaultValue())); - return false; - } - case 7: - if (args.length != 1) { - MainUtil.sendMessage(player, Captions.SETUP_WORLD_NAME_ERROR); - return false; - } - if (!d(args[0])) { - MainUtil.sendMessage(player, Captions.SETUP_WORLD_NAME_FORMAT + args[0]); - return false; - } - if (WorldUtil.IMP.isWorld(args[0])) { - if (PlotSquared.get().hasPlotArea(args[0])) { - MainUtil.sendMessage(player, Captions.SETUP_WORLD_NAME_TAKEN); - return false; - } - MainUtil.sendMessage(player, Captions.SETUP_WORLD_APPLY_PLOTSQUARED); - } - object.world = args[0]; - player.deleteMeta("setup"); - String world; - if (object.setupManager == null) { - world = SetupUtils.manager.setupWorld(object); - } else { - world = object.setupManager.setupWorld(object); - } - try { - player.teleport(WorldUtil.IMP.getSpawn(world), TeleportCause.COMMAND); - } catch (Exception e) { - player.sendMessage("&cAn error occurred. See console for more information"); - e.printStackTrace(); - } - sendMessage(player, Captions.SETUP_FINISHED, object.world); - } - return false; - } - - - private static final class StepPickGenerator extends SetupStep { - - @Getter private String generator; - - public StepPickGenerator() { - super("generator"); - } - - @Override public Collection showDescriptionMessage() { - SetupUtils.manager.updateGenerators(); - final List messages = new ArrayList<>(); - messages.add(new PlotMessage("What generator do you want?").color("$6")); - for (Entry> entry : SetupUtils.generators.entrySet()) { - final PlotMessage plotMessage = new PlotMessage(" - ").color("$8"); - if (entry.getKey().equals(PlotSquared.imp().getPluginName())) { - plotMessage.text(entry.getKey()).color("$8").tooltip("Select this generator") - .color("$2").command("/plot setup generator " + entry.getKey()) - .text(" (Default Generator)").color("$7"); - } else if (entry.getValue().isFull()) { - plotMessage.text(entry.getKey()).color("$8").tooltip("Select this generator") - .color("$7").command("/plot setup generator " + entry.getKey()) - .text(" (Plot Generator)").color("$7"); - } else { - plotMessage.text(entry.getKey()).color("$8").tooltip("Select this generator") - .color("$7").command("/plot setup generator " + entry.getKey()) - .text(" (Unknown Structure)").color("$7"); - } - messages.add(plotMessage); - } - return messages; - } - - @Override public boolean parseInput(String input) { - this.generator = input.toLowerCase(); - return true; - } - - @Nullable @Override public String getDefault() { - return null; - } - } - - - private static final class StepWorldType extends SetupStep { - - private static final Map WORLD_TYPES = new HashMap<>(); - - static { - WORLD_TYPES.put("default", "Standard plot generation"); - WORLD_TYPES.put("augmented", "Plot generation with vanilla terrain"); - WORLD_TYPES.put("partial", "Vanilla clusters of plots"); - } - - @Getter private String worldType; - - public StepWorldType() { - super("type"); - } - - @Override public Collection showDescriptionMessage() { - final List messages = new ArrayList<>(); - messages.add(new PlotMessage("What world type do you want?").color("$6")); - for (final Map.Entry worldType : WORLD_TYPES.entrySet()) { - messages.add(new PlotMessage(" - ").color("$8").text(worldType.getKey()) - .color(worldType.getKey().equals(getDefault()) ? "$2" : "$7") - .tooltip("Select this world type") - .command("/plot setup type " + worldType.getKey()) - .text(" (" + worldType.getValue() + ")").color("$7")); - } - return messages; - } - - @Override public boolean parseInput(String input) { - if (!WORLD_TYPES.containsKey(input.toLowerCase())) { - return false; - } - this.worldType = input.toLowerCase(); - return true; - } - - @Override public String getDefault() { - return "default"; - } - } - - - @ToString - @EqualsAndHashCode(of = "uuid") - @AllArgsConstructor - private static class SetupContext { - - private final UUID uuid; - - @Getter private String step; + return true; } - - @RequiredArgsConstructor(access = AccessLevel.PROTECTED) - private abstract static class SetupStep { - - private final String stepName; - - public abstract Collection showDescriptionMessage(); - - public abstract boolean parseInput(String input); - - public final PlotMessage getUsage() { - return new PlotMessage("Usage: ").color("$1") - .text("/plot setup " + this.stepName + " ").color("$2").suggest( - "/plot setup " + this.stepName + (this.getDefault() != null ? - this.getDefault() : - "")); + @Override public Collection tab(PlotPlayer player, String[] args, boolean space) { + SetupProcess process = (SetupProcess) player.getMeta("setup"); // TODO use generics -> auto cast + if (process == null) { + return Collections.emptyList(); } - - @Nullable public abstract String getDefault(); - - public void sendToPlayer(@NonNull final PlotPlayer plotPlayer) { - new PlotMessage("Setup Step: ").color("$6").text(this.stepName).color("$7") - .send(plotPlayer); - this.getUsage().send(plotPlayer); - this.showDescriptionMessage().forEach(plotMessage -> plotMessage.send(plotPlayer)); - if (this.getDefault() != null) { - new PlotMessage("Default: ").color("$6").text(this.getDefault()).color("$7"); - } + // player already provided too many arguments + if (args.length > 1 || (args.length == 1 && space)) { + return Collections.emptyList(); } - + SetupStep setupStep = process.getCurrentStep(); + List commands = new ArrayList<>(setupStep.createSuggestions(player, space ? "" : args[0])); + tryAddSubCommand("back", args[0], commands); + tryAddSubCommand("cancel", args[0], commands); + return commands; } + private void tryAddSubCommand(String subCommand, String argument, List suggestions) { + if (!argument.isEmpty() && subCommand.startsWith(argument)) { + suggestions.add(new Command(null, false, subCommand, "", RequiredType.NONE, null) {}); + } + } } diff --git a/Core/src/main/java/com/plotsquared/core/command/SubCommand.java b/Core/src/main/java/com/plotsquared/core/command/SubCommand.java index 4a8d0e9fd..8692d1cae 100644 --- a/Core/src/main/java/com/plotsquared/core/command/SubCommand.java +++ b/Core/src/main/java/com/plotsquared/core/command/SubCommand.java @@ -54,11 +54,11 @@ public abstract class SubCommand extends Command { } @Override - public CompletableFuture execute(PlotPlayer player, String[] args, + public CompletableFuture execute(PlotPlayer player, String[] args, RunnableVal3 confirm, RunnableVal2 whenDone) { return CompletableFuture.completedFuture(onCommand(player, args)); } - public abstract boolean onCommand(PlotPlayer player, String[] args); + public abstract boolean onCommand(PlotPlayer player, String[] args); } diff --git a/Core/src/main/java/com/plotsquared/core/command/Swap.java b/Core/src/main/java/com/plotsquared/core/command/Swap.java index d8447c84e..9e7ce5208 100644 --- a/Core/src/main/java/com/plotsquared/core/command/Swap.java +++ b/Core/src/main/java/com/plotsquared/core/command/Swap.java @@ -45,7 +45,7 @@ import java.util.concurrent.CompletableFuture; public class Swap extends SubCommand { @Override - public CompletableFuture execute(PlotPlayer player, String[] args, + public CompletableFuture execute(PlotPlayer player, String[] args, RunnableVal3 confirm, RunnableVal2 whenDone) { Location location = player.getLocation(); @@ -93,7 +93,7 @@ public class Swap extends SubCommand { }); } - @Override public boolean onCommand(final PlotPlayer player, String[] args) { + @Override public boolean onCommand(final PlotPlayer player, String[] args) { return true; } } diff --git a/Core/src/main/java/com/plotsquared/core/command/Target.java b/Core/src/main/java/com/plotsquared/core/command/Target.java index 5edc9b5a5..a70ac3451 100644 --- a/Core/src/main/java/com/plotsquared/core/command/Target.java +++ b/Core/src/main/java/com/plotsquared/core/command/Target.java @@ -45,7 +45,7 @@ public class Target extends SubCommand { super(Argument.PlotID); } - @Override public boolean onCommand(PlotPlayer player, String[] args) { + @Override public boolean onCommand(PlotPlayer player, String[] args) { Location location = player.getLocation(); if (!location.isPlotArea()) { MainUtil.sendMessage(player, Captions.NOT_IN_PLOT_WORLD); diff --git a/Core/src/main/java/com/plotsquared/core/command/Template.java b/Core/src/main/java/com/plotsquared/core/command/Template.java index 373f3b38e..02bc7af4d 100644 --- a/Core/src/main/java/com/plotsquared/core/command/Template.java +++ b/Core/src/main/java/com/plotsquared/core/command/Template.java @@ -36,8 +36,9 @@ import com.plotsquared.core.events.TeleportCause; import com.plotsquared.core.player.PlotPlayer; import com.plotsquared.core.plot.PlotArea; import com.plotsquared.core.plot.PlotManager; -import com.plotsquared.core.plot.SetupObject; import com.plotsquared.core.queue.GlobalBlockQueue; +import com.plotsquared.core.setup.PlotAreaBuilder; +import com.plotsquared.core.setup.SettingsNodesWrapper; import com.plotsquared.core.util.FileBytes; import com.plotsquared.core.util.MainUtil; import com.plotsquared.core.util.SetupUtils; @@ -134,7 +135,7 @@ public class Template extends SubCommand { } } - @Override public boolean onCommand(final PlotPlayer player, String[] args) { + @Override public boolean onCommand(final PlotPlayer player, String[] args) { if (args.length != 2 && args.length != 3) { if (args.length == 1) { if (args[0].equalsIgnoreCase("export")) { @@ -181,15 +182,15 @@ public class Template extends SubCommand { String manager = worldConfig.getString("generator.plugin", PlotSquared.imp().getPluginName()); String generator = worldConfig.getString("generator.init", manager); - SetupObject setup = new SetupObject(); - setup.type = MainUtil.getType(worldConfig); - setup.terrain = MainUtil.getTerrain(worldConfig); + PlotAreaBuilder builder = new PlotAreaBuilder() + .plotAreaType(MainUtil.getType(worldConfig)) + .terrainType(MainUtil.getTerrain(worldConfig)) + .plotManager(manager) + .generatorName(generator) + .settingsNodesWrapper(new SettingsNodesWrapper(new ConfigurationNode[0], null)) + .worldName(world); - setup.plotManager = manager; - setup.setupGenerator = generator; - setup.step = new ConfigurationNode[0]; - setup.world = world; - SetupUtils.manager.setupWorld(setup); + SetupUtils.manager.setupWorld(builder); GlobalBlockQueue.IMP.addEmptyTask(() -> { MainUtil.sendMessage(player, "Done!"); player.teleport(WorldUtil.IMP.getSpawn(world), TeleportCause.COMMAND); diff --git a/Core/src/main/java/com/plotsquared/core/command/Toggle.java b/Core/src/main/java/com/plotsquared/core/command/Toggle.java index 8bb25014c..e9e46ac7a 100644 --- a/Core/src/main/java/com/plotsquared/core/command/Toggle.java +++ b/Core/src/main/java/com/plotsquared/core/command/Toggle.java @@ -47,7 +47,7 @@ public class Toggle extends Command { aliases = {"spy"}, permission = "plots.admin.command.chat", description = "Toggle plot chat spy") - public void chatspy(Command command, PlotPlayer player, String[] args, + public void chatspy(Command command, PlotPlayer player, String[] args, RunnableVal3 confirm, RunnableVal2 whenDone) { if (toggle(player, "chatspy")) { @@ -61,7 +61,7 @@ public class Toggle extends Command { aliases = {"we", "wea"}, permission = "plots.worldedit.bypass", description = "Toggle worldedit area restrictions") - public void worldedit(Command command, PlotPlayer player, String[] args, + public void worldedit(Command command, PlotPlayer player, String[] args, RunnableVal3 confirm, RunnableVal2 whenDone) { if (toggle(player, "worldedit")) { @@ -74,7 +74,7 @@ public class Toggle extends Command { @CommandDeclaration(command = "chat", permission = "plots.toggle.chat", description = "Toggle plot chat") - public void chat(Command command, PlotPlayer player, String[] args, + public void chat(Command command, PlotPlayer player, String[] args, RunnableVal3 confirm, RunnableVal2 whenDone) { if (toggle(player, "chat")) { @@ -87,7 +87,7 @@ public class Toggle extends Command { @CommandDeclaration(command = "clear-confirmation", permission = "plots.admin.command.autoclear", description = "Toggle autoclear confirmation") - public void clearConfirmation(Command command, PlotPlayer player, String[] args, + public void clearConfirmation(Command command, PlotPlayer player, String[] args, RunnableVal3 confirm, RunnableVal2 whenDone) { if (toggle(player, "ignoreExpireTask")) { @@ -100,7 +100,7 @@ public class Toggle extends Command { @CommandDeclaration(command = "titles", permission = "plots.toggle.titles", description = "Toggle plot title messages") - public void titles(Command command, PlotPlayer player, String[] args, + public void titles(Command command, PlotPlayer player, String[] args, RunnableVal3 confirm, RunnableVal2 whenDone) { if (toggle(player, "disabletitles")) { @@ -113,7 +113,7 @@ public class Toggle extends Command { @CommandDeclaration(command = "time", permission = "plots.toggle.time", description = "Toggle plot time settings") - public void time(Command command, PlotPlayer player, String[] args, + public void time(Command command, PlotPlayer player, String[] args, RunnableVal3 confirm, RunnableVal2 whenDone) { if (toggle(player, "disabletime")) { @@ -123,7 +123,21 @@ public class Toggle extends Command { } } - public boolean toggle(PlotPlayer player, String key) { + @CommandDeclaration(command = "debug", + permission = "plots.toggle.debug", + description = "Toggle plot debugging") + public void debug(Command command, PlotPlayer player, String[] args, + RunnableVal3 confirm, + RunnableVal2 whenDone) { + if (!toggle(player, "debug")) { + MainUtil.sendMessage(player, Captions.TOGGLE_ENABLED, command.toString()); + } else { + MainUtil.sendMessage(player, Captions.TOGGLE_DISABLED, command.toString()); + } + player.refreshDebug(); + } + + public boolean toggle(PlotPlayer player, String key) { if (player.getAttribute(key)) { player.removeAttribute(key); return true; diff --git a/Core/src/main/java/com/plotsquared/core/command/Trim.java b/Core/src/main/java/com/plotsquared/core/command/Trim.java index 4e4e8e900..ad5e5c0fe 100644 --- a/Core/src/main/java/com/plotsquared/core/command/Trim.java +++ b/Core/src/main/java/com/plotsquared/core/command/Trim.java @@ -159,7 +159,7 @@ public class Trim extends SubCommand { return true; } - @Override public boolean onCommand(final PlotPlayer player, String[] args) { + @Override public boolean onCommand(final PlotPlayer player, String[] args) { if (args.length == 0) { Captions.COMMAND_SYNTAX.send(player, getUsage()); return false; diff --git a/Core/src/main/java/com/plotsquared/core/command/Trust.java b/Core/src/main/java/com/plotsquared/core/command/Trust.java index 8a93e6cd8..1c4064543 100644 --- a/Core/src/main/java/com/plotsquared/core/command/Trust.java +++ b/Core/src/main/java/com/plotsquared/core/command/Trust.java @@ -32,13 +32,16 @@ import com.plotsquared.core.player.PlotPlayer; import com.plotsquared.core.plot.Plot; import com.plotsquared.core.util.MainUtil; import com.plotsquared.core.util.Permissions; +import com.plotsquared.core.util.TabCompletions; import com.plotsquared.core.util.task.RunnableVal2; import com.plotsquared.core.util.task.RunnableVal3; +import java.util.Collection; +import java.util.Collections; import java.util.Iterator; -import java.util.Set; import java.util.UUID; import java.util.concurrent.CompletableFuture; +import java.util.concurrent.TimeoutException; @CommandDeclaration(command = "trust", aliases = {"t"}, @@ -53,7 +56,7 @@ public class Trust extends Command { } @Override - public CompletableFuture execute(final PlotPlayer player, String[] args, + public CompletableFuture execute(final PlotPlayer player, String[] args, RunnableVal3 confirm, RunnableVal2 whenDone) throws CommandException { final Plot currentPlot = player.getCurrentPlot(); @@ -65,51 +68,69 @@ public class Trust extends Command { .hasPermission(player, Captions.PERMISSION_ADMIN_COMMAND_TRUST), Captions.NO_PLOT_PERMS); checkTrue(args.length == 1, Captions.COMMAND_SYNTAX, getUsage()); - final Set uuids = MainUtil.getUUIDsFromString(args[0]); - checkTrue(!uuids.isEmpty(), Captions.INVALID_PLAYER, args[0]); - Iterator iterator = uuids.iterator(); - int size = currentPlot.getTrusted().size() + currentPlot.getMembers().size(); - while (iterator.hasNext()) { - UUID uuid = iterator.next(); - if (uuid == DBFunc.EVERYONE && !( - Permissions.hasPermission(player, Captions.PERMISSION_TRUST_EVERYONE) || Permissions - .hasPermission(player, Captions.PERMISSION_ADMIN_COMMAND_TRUST))) { - MainUtil.sendMessage(player, Captions.INVALID_PLAYER, MainUtil.getName(uuid)); - iterator.remove(); - continue; - } - if (currentPlot.isOwner(uuid)) { - MainUtil.sendMessage(player, Captions.ALREADY_ADDED, MainUtil.getName(uuid)); - iterator.remove(); - continue; - } - if (currentPlot.getTrusted().contains(uuid)) { - MainUtil.sendMessage(player, Captions.ALREADY_ADDED, MainUtil.getName(uuid)); - iterator.remove(); - continue; - } - size += currentPlot.getMembers().contains(uuid) ? 0 : 1; - } - checkTrue(!uuids.isEmpty(), null); - checkTrue(size <= currentPlot.getArea().getMaxPlotMembers() || Permissions - .hasPermission(player, Captions.PERMISSION_ADMIN_COMMAND_TRUST), - Captions.PLOT_MAX_MEMBERS); - // Success - confirm.run(this, () -> { - for (UUID uuid : uuids) { - if (uuid != DBFunc.EVERYONE) { - if (!currentPlot.removeMember(uuid)) { - if (currentPlot.getDenied().contains(uuid)) { - currentPlot.removeDenied(uuid); - } - } - } - currentPlot.addTrusted(uuid); - PlotSquared.get().getEventDispatcher().callTrusted(player, currentPlot, uuid, true); - MainUtil.sendMessage(player, Captions.TRUSTED_ADDED); - } - }, null); + final CompletableFuture future = new CompletableFuture<>(); + MainUtil.getUUIDsFromString(args[0], (uuids, throwable) -> { + if (throwable != null) { + if (throwable instanceof TimeoutException) { + Captions.FETCHING_PLAYERS_TIMEOUT.send(player); + } else { + Captions.INVALID_PLAYER.send(player, args[0]); + } + future.completeExceptionally(throwable); + return; + } else { + checkTrue(!uuids.isEmpty(), Captions.INVALID_PLAYER, args[0]); + Iterator iterator = uuids.iterator(); + int size = currentPlot.getTrusted().size() + currentPlot.getMembers().size(); + while (iterator.hasNext()) { + UUID uuid = iterator.next(); + if (uuid == DBFunc.EVERYONE && !( + Permissions.hasPermission(player, Captions.PERMISSION_TRUST_EVERYONE) || Permissions + .hasPermission(player, Captions.PERMISSION_ADMIN_COMMAND_TRUST))) { + MainUtil.sendMessage(player, Captions.INVALID_PLAYER, MainUtil.getName(uuid)); + iterator.remove(); + continue; + } + if (currentPlot.isOwner(uuid)) { + MainUtil.sendMessage(player, Captions.ALREADY_ADDED, MainUtil.getName(uuid)); + iterator.remove(); + continue; + } + if (currentPlot.getTrusted().contains(uuid)) { + MainUtil.sendMessage(player, Captions.ALREADY_ADDED, MainUtil.getName(uuid)); + iterator.remove(); + continue; + } + size += currentPlot.getMembers().contains(uuid) ? 0 : 1; + } + checkTrue(!uuids.isEmpty(), null); + checkTrue(size <= currentPlot.getArea().getMaxPlotMembers() || Permissions + .hasPermission(player, Captions.PERMISSION_ADMIN_COMMAND_TRUST), + Captions.PLOT_MAX_MEMBERS); + // Success + confirm.run(this, () -> { + for (UUID uuid : uuids) { + if (uuid != DBFunc.EVERYONE) { + if (!currentPlot.removeMember(uuid)) { + if (currentPlot.getDenied().contains(uuid)) { + currentPlot.removeDenied(uuid); + } + } + } + currentPlot.addTrusted(uuid); + PlotSquared.get().getEventDispatcher().callTrusted(player, currentPlot, uuid, true); + MainUtil.sendMessage(player, Captions.TRUSTED_ADDED); + } + }, null); + } + future.complete(true); + }); return CompletableFuture.completedFuture(true); } + + @Override public Collection tab(final PlotPlayer player, final String[] args, final boolean space) { + return TabCompletions.completePlayers(String.join(",", args).trim(), Collections.emptyList()); + } + } diff --git a/Core/src/main/java/com/plotsquared/core/command/Unlink.java b/Core/src/main/java/com/plotsquared/core/command/Unlink.java index d2d5fa8d2..1f309df57 100644 --- a/Core/src/main/java/com/plotsquared/core/command/Unlink.java +++ b/Core/src/main/java/com/plotsquared/core/command/Unlink.java @@ -46,7 +46,7 @@ import com.plotsquared.core.util.task.TaskManager; confirmation = true) public class Unlink extends SubCommand { - @Override public boolean onCommand(final PlotPlayer player, String[] args) { + @Override public boolean onCommand(final PlotPlayer player, String[] args) { Location location = player.getLocation(); final Plot plot = location.getPlotAbs(); if (plot == null) { diff --git a/Core/src/main/java/com/plotsquared/core/command/Visit.java b/Core/src/main/java/com/plotsquared/core/command/Visit.java index 372130a2d..f5243b4ba 100644 --- a/Core/src/main/java/com/plotsquared/core/command/Visit.java +++ b/Core/src/main/java/com/plotsquared/core/command/Visit.java @@ -27,7 +27,6 @@ package com.plotsquared.core.command; import com.plotsquared.core.PlotSquared; import com.plotsquared.core.configuration.Captions; -import com.plotsquared.core.configuration.Settings; import com.plotsquared.core.events.TeleportCause; import com.plotsquared.core.player.PlotPlayer; import com.plotsquared.core.plot.Plot; @@ -36,16 +35,21 @@ import com.plotsquared.core.plot.flag.implementations.UntrustedVisitFlag; import com.plotsquared.core.util.MainUtil; import com.plotsquared.core.util.MathMan; import com.plotsquared.core.util.Permissions; +import com.plotsquared.core.util.TabCompletions; +import com.plotsquared.core.util.query.PlotQuery; +import com.plotsquared.core.util.query.SortingStrategy; import com.plotsquared.core.util.task.RunnableVal2; import com.plotsquared.core.util.task.RunnableVal3; -import com.plotsquared.core.util.uuid.UUIDHandler; +import com.plotsquared.core.uuid.UUIDMapping; +import org.jetbrains.annotations.NotNull; -import java.util.ArrayList; import java.util.Collection; import java.util.Collections; +import java.util.LinkedList; import java.util.List; import java.util.UUID; import java.util.concurrent.CompletableFuture; +import java.util.concurrent.TimeoutException; @CommandDeclaration(command = "visit", permission = "plots.visit", @@ -60,22 +64,96 @@ public class Visit extends Command { super(MainCommand.getInstance(), true); } - @Override public Collection tab(PlotPlayer player, String[] args, boolean space) { - return tabOf(player, args, space, getUsage()); + private void visit(@NotNull final PlotPlayer player, @NotNull final PlotQuery query, final PlotArea sortByArea, + final RunnableVal3 confirm, final RunnableVal2 whenDone) { + this.visit(player, query, sortByArea, confirm, whenDone, 1); + } + + private void visit(@NotNull final PlotPlayer player, @NotNull final PlotQuery query, final PlotArea sortByArea, + final RunnableVal3 confirm, final RunnableVal2 whenDone, int page) { + // We get the query once, + // then we get it another time further on + final List unsorted = query.asList(); + + if (unsorted.isEmpty()) { + Captions.FOUND_NO_PLOTS.send(player); + return; + } + + if (unsorted.size() > 1) { + query.whereBasePlot(); + } + + if (page == Integer.MIN_VALUE) { + page = 1; + } + + if (page < 1 || page > unsorted.size()) { + MainUtil.sendMessage(player, String.format("(1, %d)", unsorted.size())); + return; + } + + if (sortByArea != null) { + query.relativeToArea(sortByArea).withSortingStrategy(SortingStrategy.SORT_BY_CREATION); + } else { + query.withSortingStrategy(SortingStrategy.SORT_BY_TEMP); + } + + final List plots = query.asList(); + + final Plot plot = plots.get(page - 1); + if (!plot.hasOwner()) { + if (!Permissions.hasPermission(player, Captions.PERMISSION_VISIT_UNOWNED)) { + Captions.NO_PERMISSION.send(player, Captions.PERMISSION_VISIT_UNOWNED); + return; + } + } else if (plot.isOwner(player.getUUID())) { + if (!Permissions.hasPermission(player, Captions.PERMISSION_VISIT_OWNED) && !Permissions + .hasPermission(player, Captions.PERMISSION_HOME)) { + Captions.NO_PERMISSION.send(player, Captions.PERMISSION_VISIT_OWNED); + return; + } + } else if (plot.isAdded(player.getUUID())) { + if (!Permissions.hasPermission(player, Captions.PERMISSION_SHARED)) { + Captions.NO_PERMISSION.send(player, Captions.PERMISSION_SHARED); + return; + } + } else { + if (!Permissions.hasPermission(player, Captions.PERMISSION_VISIT_OTHER)) { + Captions.NO_PERMISSION.send(player, Captions.PERMISSION_VISIT_OTHER); + return; + } + if (!plot.getFlag(UntrustedVisitFlag.class) && !Permissions + .hasPermission(player, Captions.PERMISSION_ADMIN_VISIT_UNTRUSTED)) { + Captions.NO_PERMISSION.send(player, Captions.PERMISSION_ADMIN_VISIT_UNTRUSTED); + return; + } + } + + confirm.run(this, () -> plot.teleportPlayer(player, TeleportCause.COMMAND, result -> { + if (result) { + whenDone.run(Visit.this, CommandResult.SUCCESS); + } else { + whenDone.run(Visit.this, CommandResult.FAILURE); + } + }), () -> whenDone.run(Visit.this, CommandResult.FAILURE)); } @Override - public CompletableFuture execute(final PlotPlayer player, String[] args, - RunnableVal3 confirm, + public CompletableFuture execute(final PlotPlayer player, + String[] args, + final RunnableVal3 confirm, final RunnableVal2 whenDone) throws CommandException { if (args.length == 1 && args[0].contains(":")) { args = args[0].split(":"); } + + PlotArea sortByArea; + int page = Integer.MIN_VALUE; - Collection unsorted = null; - PlotArea sortByArea = player.getApplicablePlotArea(); - boolean shouldSortByArea = Settings.Teleport.PER_WORLD_VISIT; + switch (args.length) { + // /p v [...] [...] case 3: if (!MathMan.isInteger(args[1])) { Captions.NOT_VALID_NUMBER.send(player, "(1, ∞)"); @@ -83,6 +161,8 @@ public class Visit extends Command { return CompletableFuture.completedFuture(false); } page = Integer.parseInt(args[2]); + // /p v [page] + // /p v [page] case 2: if (page != Integer.MIN_VALUE || !MathMan.isInteger(args[1])) { sortByArea = PlotSquared.get().getPlotAreaByString(args[1]); @@ -91,101 +171,148 @@ public class Visit extends Command { Captions.COMMAND_SYNTAX.send(player, getUsage()); return CompletableFuture.completedFuture(false); } - UUID user = UUIDHandler.getUUIDFromString(args[0]); - if (user == null) { - Captions.COMMAND_SYNTAX.send(player, getUsage()); - return CompletableFuture.completedFuture(false); - } - unsorted = PlotSquared.get().getBasePlots(user); - shouldSortByArea = true; + + final PlotArea finalSortByArea = sortByArea; + int finalPage1 = page; + MainUtil.getUUIDsFromString(args[0], (uuids, throwable) -> { + if (throwable instanceof TimeoutException) { + Captions.FETCHING_PLAYERS_TIMEOUT.send(player); + } else if (throwable != null || uuids.size() != 1) { + Captions.COMMAND_SYNTAX.send(player, getUsage()); + } else { + final UUID uuid = uuids.toArray(new UUID[0])[0]; + this.visit(player, PlotQuery.newQuery().ownedBy(uuid).whereBasePlot(), finalSortByArea, confirm, whenDone, finalPage1); + } + }); break; } page = Integer.parseInt(args[1]); + // /p v [page] + // /p v [page] + // /p v [page] + // /p v [page] case 1: - UUID user = args[0].length() >= 2 ? UUIDHandler.getUUIDFromString(args[0]) : null; - if (user != null && !PlotSquared.get().hasPlot(user)) { - user = null; + final String[] finalArgs = args; + int finalPage = page; + // Try to determine whether the given argument is a username + // or an ordinal + boolean isNumber = false; + if (args[0].length() < 2) { + isNumber = true; + } else if (args[0].length() <= 4 && MathMan.isInteger(args[0])) { + // Check if it's an all-digit username that is stored in cache + final UUIDMapping mapping = PlotSquared.get().getImpromptuUUIDPipeline().getImmediately(args[0]); + // If no UUID could be found, then we assume it's a number and not a username + isNumber = mapping == null; } - if (page == Integer.MIN_VALUE && user == null && MathMan.isInteger(args[0])) { - page = Integer.parseInt(args[0]); - unsorted = PlotSquared.get().getBasePlots(player); - break; - } - if (user != null) { - unsorted = PlotSquared.get().getBasePlots(user); + if (!isNumber && args[0].length() >= 2 && !args[0].contains(";") && !args[0].contains(",")) { + PlotSquared.get().getImpromptuUUIDPipeline().getSingle(args[0], (uuid, throwable) -> { + if (throwable instanceof TimeoutException) { + // The request timed out + MainUtil.sendMessage(player, Captions.FETCHING_PLAYERS_TIMEOUT); + } else if (uuid != null && !PlotSquared.get().hasPlot(uuid)) { + // It was a valid UUID but the player has no plots + MainUtil.sendMessage(player, Captions.PLAYER_NO_PLOTS); + } else if (uuid == null) { + if (finalPage == Integer.MIN_VALUE && MathMan.isInteger(finalArgs[0])) { + // The argument was a number, so we assume it's the page number + int parsedPage; + try { + parsedPage = Integer.parseInt(finalArgs[0]); + } catch (final Throwable t) { + MainUtil.sendMessage(player, Captions.NOT_A_NUMBER, finalArgs[0]); + return; + } + this.visit(player, PlotQuery.newQuery().ownedBy(player).whereBasePlot(), null, + confirm, whenDone, parsedPage); + } else { + // Try to parse a plot + final Plot plot = MainUtil.getPlotFromString(player, finalArgs[0], true); + if (plot == null) { + MainUtil.sendMessage(player, Captions.NOT_VALID_PLOT_ID); + return; + } + this.visit(player, PlotQuery.newQuery().withPlot(plot), null, confirm, whenDone, 1); + } + } else { + this.visit(player, PlotQuery.newQuery().ownedBy(uuid).whereBasePlot(), null, confirm, whenDone, finalPage); + } + }); } else { - Plot plot = MainUtil.getPlotFromString(player, args[0], true); - if (plot != null) { - unsorted = Collections.singletonList(plot.getBasePlot(false)); + if (finalPage == Integer.MIN_VALUE && MathMan.isInteger(finalArgs[0])) { + // The argument was a number, so we assume it's the page number + int parsedPage; + try { + parsedPage = Integer.parseInt(finalArgs[0]); + this.visit(player, PlotQuery.newQuery().ownedBy(player).whereBasePlot(), null, confirm, + whenDone, parsedPage); + } catch (final Throwable throwable) { + MainUtil.sendMessage(player, Captions.NOT_A_NUMBER, finalArgs[0]); + } + } else { + // Try to parse a plot + final Plot plot = MainUtil.getPlotFromString(player, finalArgs[0], true); + if (plot != null) { + this.visit(player, PlotQuery.newQuery().withPlot(plot), null, confirm, whenDone, 1); + } } } break; case 0: - page = 1; - unsorted = PlotSquared.get().getPlots(player); + // /p v + this.visit(player, PlotQuery.newQuery().ownedBy(player), null, confirm, whenDone); break; default: - } - if (page == Integer.MIN_VALUE) { - page = 1; - } - if (unsorted == null || unsorted.isEmpty()) { - Captions.FOUND_NO_PLOTS.send(player); - return CompletableFuture.completedFuture(false); - } - unsorted = new ArrayList<>(unsorted); - if (unsorted.size() > 1) { - unsorted.removeIf(plot -> !plot.isBasePlot()); - } - if (page < 1 || page > unsorted.size()) { - Captions.NOT_VALID_NUMBER.send(player, "(1, " + unsorted.size() + ")"); - return CompletableFuture.completedFuture(false); - } - List plots; - if (shouldSortByArea) { - plots = PlotSquared.get() - .sortPlots(unsorted, PlotSquared.SortType.CREATION_DATE, sortByArea); - } else { - plots = PlotSquared.get().sortPlotsByTemp(unsorted); - } - final Plot plot = plots.get(page - 1); - if (!plot.hasOwner()) { - if (!Permissions.hasPermission(player, Captions.PERMISSION_VISIT_UNOWNED)) { - Captions.NO_PERMISSION.send(player, Captions.PERMISSION_VISIT_UNOWNED); - return CompletableFuture.completedFuture(false); - } - } else if (plot.isOwner(player.getUUID())) { - if (!Permissions.hasPermission(player, Captions.PERMISSION_VISIT_OWNED) && !Permissions - .hasPermission(player, Captions.PERMISSION_HOME)) { - Captions.NO_PERMISSION.send(player, Captions.PERMISSION_VISIT_OWNED); - return CompletableFuture.completedFuture(false); - } - } else if (plot.isAdded(player.getUUID())) { - if (!Permissions.hasPermission(player, Captions.PERMISSION_SHARED)) { - Captions.NO_PERMISSION.send(player, Captions.PERMISSION_SHARED); - return CompletableFuture.completedFuture(false); - } - } else { - if (!Permissions.hasPermission(player, Captions.PERMISSION_VISIT_OTHER)) { - Captions.NO_PERMISSION.send(player, Captions.PERMISSION_VISIT_OTHER); - return CompletableFuture.completedFuture(false); - } - if (!plot.getFlag(UntrustedVisitFlag.class) && !Permissions - .hasPermission(player, Captions.PERMISSION_ADMIN_VISIT_UNTRUSTED)) { - Captions.NO_PERMISSION.send(player, Captions.PERMISSION_ADMIN_VISIT_UNTRUSTED); - return CompletableFuture.completedFuture(false); - } - } - confirm.run(this, () -> plot.teleportPlayer(player, TeleportCause.COMMAND, result -> { - if (result) { - whenDone.run(Visit.this, CommandResult.SUCCESS); - } else { - whenDone.run(Visit.this, CommandResult.FAILURE); - } - }), () -> whenDone.run(Visit.this, CommandResult.FAILURE)); return CompletableFuture.completedFuture(true); } + public Collection tab(PlotPlayer player, String[] args, boolean space) { + final List completions = new LinkedList<>(); + switch (args.length - 1) { + case 0: + this.completeNumbers(completions, args[0], 0); + completions.addAll(TabCompletions.completePlayers(args[0], Collections.emptyList())); + break; + case 1: + if (MathMan.isInteger(args[0])) { + break; + } + this.completeNumbers(completions, args[1], 0); + this.completeAreas(completions, args[1]); + break; + case 2: + if (MathMan.isInteger(args[1])) { + break; + } + this.completeNumbers(completions, args[2], 0); + break; + } + + return completions; + } + + private void completeNumbers(final List commands, final String arg, final int start) { + for (int i = 0; i < 100; i++) { + final String command = Integer.toString(start + 1); + if (!command.toLowerCase().startsWith(arg.toLowerCase())) { + continue; + } + commands.add(new Command(this, false, command, "", + RequiredType.NONE, CommandCategory.TELEPORT) {}); + } + } + + private void completeAreas(final List commands, final String arg) { + for (final PlotArea area : PlotSquared.get().getPlotAreas()) { + final String areaName = area.getWorldName() + ";" + area.getId(); + if (!areaName.toLowerCase().startsWith(arg.toLowerCase())) { + continue; + } + commands.add(new Command(this, false, area.getWorldName() + ";" + area.getId(), "", + RequiredType.NONE, CommandCategory.TELEPORT) {}); + } + } + } diff --git a/Core/src/main/java/com/plotsquared/core/command/WE_Anywhere.java b/Core/src/main/java/com/plotsquared/core/command/WE_Anywhere.java index 6ac51f57c..50cda457a 100644 --- a/Core/src/main/java/com/plotsquared/core/command/WE_Anywhere.java +++ b/Core/src/main/java/com/plotsquared/core/command/WE_Anywhere.java @@ -37,7 +37,7 @@ import com.plotsquared.core.player.PlotPlayer; @Deprecated public class WE_Anywhere extends SubCommand { - @Override public boolean onCommand(PlotPlayer player, String[] arguments) { + @Override public boolean onCommand(PlotPlayer player, String[] arguments) { MainCommand.getInstance().toggle.worldedit(this, player, new String[0], null, null); return true; } diff --git a/Core/src/main/java/com/plotsquared/core/components/ComponentCommand.java b/Core/src/main/java/com/plotsquared/core/components/ComponentCommand.java index f79b68063..8c158c417 100644 --- a/Core/src/main/java/com/plotsquared/core/components/ComponentCommand.java +++ b/Core/src/main/java/com/plotsquared/core/components/ComponentCommand.java @@ -46,7 +46,7 @@ public class ComponentCommand extends SubCommand { this.componentPresetManager = componentPresetManager; } - @Override public boolean onCommand(final PlotPlayer player, final String[] args) { + @Override public boolean onCommand(final PlotPlayer player, final String[] args) { final PlotInventory inventory = componentPresetManager.buildInventory(player); if (inventory != null) { inventory.openInventory(); diff --git a/Core/src/main/java/com/plotsquared/core/components/ComponentPresetManager.java b/Core/src/main/java/com/plotsquared/core/components/ComponentPresetManager.java index 80ae1deb4..fb10eff9b 100644 --- a/Core/src/main/java/com/plotsquared/core/components/ComponentPresetManager.java +++ b/Core/src/main/java/com/plotsquared/core/components/ComponentPresetManager.java @@ -170,12 +170,12 @@ public class ComponentPresetManager { return false; } - if (componentPreset.getCost() > 0.0D && EconHandler.manager != null && plot.getArea().useEconomy()) { - if (EconHandler.manager.getMoney(player) < componentPreset.getCost()) { + if (componentPreset.getCost() > 0.0D && EconHandler.getEconHandler() != null && plot.getArea().useEconomy()) { + if (EconHandler.getEconHandler().getMoney(player) < componentPreset.getCost()) { Captions.PRESET_CANNOT_AFFORD.send(player); return false; } else { - EconHandler.manager.withdrawMoney(player, componentPreset.getCost()); + EconHandler.getEconHandler().withdrawMoney(player, componentPreset.getCost()); Captions.REMOVED_BALANCE.send(player, componentPreset.getCost() + ""); } } @@ -196,7 +196,7 @@ public class ComponentPresetManager { for (int i = 0; i < allowedPresets.size(); i++) { final ComponentPreset preset = allowedPresets.get(i); final List lore = new ArrayList<>(); - if (preset.getCost() > 0 && EconHandler.manager != null && plot.getArea().useEconomy()){ + if (preset.getCost() > 0 && EconHandler.getEconHandler() != null && plot.getArea().useEconomy()){ lore.add(Captions.PRESET_LORE_COST.getTranslated().replace("%cost%", String.format("%.2f", preset.getCost()))); } diff --git a/Core/src/main/java/com/plotsquared/core/configuration/Captions.java b/Core/src/main/java/com/plotsquared/core/configuration/Captions.java index 6238ec066..dbcf463ac 100644 --- a/Core/src/main/java/com/plotsquared/core/configuration/Captions.java +++ b/Core/src/main/java/com/plotsquared/core/configuration/Captions.java @@ -182,7 +182,9 @@ public enum Captions implements Caption { PERMISSION_HOME("plots.home", "static.permissions"), PERMISSION_ALIAS_SET_OBSOLETE("plots.set.alias", "static.permissions"), // Note this is for backwards compatibility PERMISSION_ALIAS_SET("plots.alias.set", "static.permissions"), + PERMISSION_ADMIN_ALIAS_SET("plots.admin.alias.set", "static.permissions"), PERMISSION_ALIAS_REMOVE("plots.alias.remove", "static.permissions"), + PERMISSION_ADMIN_ALIAS_REMOVE("plots.admin.alias.remove", "static.permissions"), PERMISSION_ADMIN_CHAT_BYPASS("plots.admin.chat.bypass", "static.permissions"), PERMISSION_BACKUP("plots.backup", "static.permissions"), PERMISSION_BACKUP_SAVE("plots.backup.save", "static.permissions"), @@ -190,6 +192,7 @@ public enum Captions implements Caption { PERMISSION_BACKUP_LOAD("plots.backup.load", "static.permissions"), PERMISSION_ADMIN_BACKUP_OTHER("plots.admin.backup.other", "static.permissions"), PERMISSION_ADMIN_ALLOW_UNSAFE("plots.admin.unsafe", "static.permissions"), + PERMISSION_ADMIN_DEBUG_OTHER("plots.admin.debug.other", "static.permissions"), // // EXPIRED_CONFIRM("$2Confirmation has expired, please run the command again!", "Confirm"), @@ -319,6 +322,7 @@ public enum Captions implements Caption { REMOVED_GRANTED_PLOT("$2You used %s0 plot grant(s), you've got $1%s1 $2left", "Economy"), // // + SETUP_NOT_STARTED("$1No setup started. Use $2/plot setup $1to start a setup process.", "Setup"), SETUP_INIT("$1Usage: $2/plot setup ", "Setup"), SETUP_STEP("$3[$1Step %s0$3] $1%s1 $2- $1Expecting: $2%s2 $1Default: $2%s3", "Setup"), SETUP_INVALID_ARG("$2%s0 is not a valid argument for step %s1. To cancel setup use: $1/plot setup cancel", "Setup"), @@ -357,6 +361,11 @@ public enum Captions implements Caption { SETUP_AREA_MAX_PLOT_ID_ERROR("$7You must choose a valid maximum Plot Id!", "Setup"), SETUP_AREA_PLOT_ID_GREATER_THAN_MINIMUM("$7The max PlotId must be greater than the minimum!", "Setup"), // + // + PLOT_AREA_TYPE_NORMAL("Standard plot generation", "PlotAreaType"), + PLOT_AREA_TYPE_AUGMENTED("Plot generation with vanilla terrain", "PlotAreaType"), + PLOT_AREA_TYPE_PARTIAL("Vanilla with clusters of plots", "PlotAreaType"), + // // SCHEMATIC_TOO_LARGE("$2The plot is too large for this action!", "Schematics"), SCHEMATIC_MISSING_ARG("$2You need to specify an argument. Possible values: $1save$2, $1paste $2, $1exportall$2, $1list", "Schematics"), @@ -445,11 +454,14 @@ public enum Captions implements Caption { NOT_VALID_WORLD("$2That is not a valid world (case sensitive)", "Errors"), NOT_VALID_PLOT_WORLD("$2That is not a valid plot area (case sensitive)", "Errors"), NO_PLOTS("$2You don't have any plots", "Errors"), + PLAYER_NO_PLOTS("$2That player does not own any plots", "Errors"), WAIT_FOR_TIMER("$2A set block timer is bound to either the current plot or you. Please wait for it to finish", "Errors"), TILE_ENTITY_CAP_REACHED("$2The total number of tile entities in this chunk may not exceed $1%s", "Errors"), // DEBUG_REPORT_CREATED("$1Uploaded a full debug to: $1%url%", "Paste"), PURGE_SUCCESS("$4Successfully purged %s plots", "Purge"), + FETCHING_PLAYER("$1PlotSquared is attempting to find the specified player from your argument(s). This may take a while.", "Players"), + FETCHING_PLAYERS_TIMEOUT("$2The specified users did not exist in the cache and will be fetched in the background. Please wait a couple of minutes.", "Players"), // TRIM_IN_PROGRESS("A world trim task is already in progress!", "Trim"), // @@ -783,6 +795,21 @@ public enum Captions implements Caption { GENERIC_INVALID_CHOICE("invalid choice", "Generic"), // + // + SINGLE_AREA_MISSING_SELECTION("$2Error! You need to select a square region", "Single"), + SINGLE_AREA_NOT_SQUARE("$2Error! Your selection needs to be a square", "Single"), + SINGLE_AREA_OVERLAPPING("$2Error! Your selection overlaps with an existing plot area", "Single"), + SINGLE_AREA_NEEDS_NAME("$2Error! Please specify a plot name: /plot area single ", "Single"), + SINGLE_AREA_NAME_TAKEN("$2Error! The plot name is already taken", "Single"), + SINGLE_AREA_FAILED_TO_SAVE("$2Error! Failed to save the area schematic", "Single"), + SINGLE_AREA_COULD_NOT_MAKE_DIRECTORIES("$2Error! Failed to create the schematic directory", "Single"), + SINGLE_AREA_CREATED("$1The area was created successfully!", "Single"), + // + + // + PLOT_DEBUG("$2Plot Debug ($1%plot%$2): %message%", "Plot-Debug"), + // + /** * Legacy Configuration Conversion */ diff --git a/Core/src/main/java/com/plotsquared/core/configuration/ConfigurationNode.java b/Core/src/main/java/com/plotsquared/core/configuration/ConfigurationNode.java index c936245b3..cd3d524a8 100644 --- a/Core/src/main/java/com/plotsquared/core/configuration/ConfigurationNode.java +++ b/Core/src/main/java/com/plotsquared/core/configuration/ConfigurationNode.java @@ -28,9 +28,11 @@ package com.plotsquared.core.configuration; import com.plotsquared.core.plot.BlockBucket; import com.plotsquared.core.util.StringMan; import com.sk89q.worldedit.world.block.BlockState; +import lombok.Getter; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collection; import java.util.List; /** @@ -38,19 +40,26 @@ import java.util.List; */ public class ConfigurationNode { - private final String constant; + @Getter private final String constant; private final Object defaultValue; - private final String description; + @Getter private final String description; private final ConfigurationUtil.SettingValue type; + @Getter private final Collection suggestions; private Object value; public ConfigurationNode(String constant, Object defaultValue, String description, ConfigurationUtil.SettingValue type) { + this(constant, defaultValue, description, type, new ArrayList<>()); + } + + public ConfigurationNode(String constant, Object defaultValue, String description, + ConfigurationUtil.SettingValue type, Collection suggestions) { this.constant = constant; this.defaultValue = defaultValue; this.description = description; this.value = defaultValue; this.type = type; + this.suggestions = suggestions; } public ConfigurationUtil.SettingValue getType() { @@ -97,18 +106,10 @@ public class ConfigurationNode { return this.value; } - public String getConstant() { - return this.constant; - } - public Object getDefaultValue() { if (this.defaultValue instanceof Object[]) { return StringMan.join((Object[]) this.defaultValue, ","); } return this.defaultValue; } - - public String getDescription() { - return this.description; - } } diff --git a/Core/src/main/java/com/plotsquared/core/configuration/Settings.java b/Core/src/main/java/com/plotsquared/core/configuration/Settings.java index 044642baa..80d103882 100644 --- a/Core/src/main/java/com/plotsquared/core/configuration/Settings.java +++ b/Core/src/main/java/com/plotsquared/core/configuration/Settings.java @@ -40,13 +40,14 @@ public class Settings extends Config { NOTE: Fields are saved in declaration order, classes in reverse order */ - @Comment("The first value is not configurable") // This is a comment + @Comment("This value is not configurable. It shows the platform you are using.") // This is a comment @Final public static String PLATFORM; // These values are set from P2 before loading - @Comment("Show additional information in console") public static boolean DEBUG = false; - @Comment({"The big annoying text that appears when you enter a plot", - "For a single plot: `/plot flag set titles false`", "For just you: `/plot toggle titles`", - "For all plots: Add `titles: false` in the worlds.yml flags block"}) public static boolean + @Comment({"Show additional information in console. It helps us at IntellectualSites to find out more about an issue.", + "Leave it off if you don't need it, it can spam your console."}) public static boolean DEBUG = false; + @Comment({"The big text that appears when you enter a plot.", + "For a single plot set `/plot flag set titles false` to disable it.", "For just you run `/plot toggle titles` to disable it.", + "For all plots: Add `titles: false` in the worlds.yml flags block to disable it."}) public static boolean TITLES = true; @Create // This value will be generated automatically @@ -207,7 +208,7 @@ public class Settings extends Config { public List WORLDS = new ArrayList<>(Collections.singletonList("*")); - @Comment("See: https://wiki.intellectualsites.com/en/plotsquared/optimization/plot-analysis") + @Comment("See: https://wiki.intellectualsites.com/en/plotsquared/optimization/plot-analysis for a description of each value.") public static final class CALIBRATION { public int VARIETY = 0; public int VARIETY_SD = 0; @@ -223,6 +224,8 @@ public class Settings extends Config { } + @Comment({"Chunk processor related settings", + "See https://wiki.intellectualsites.com/en/plotsquared/optimization/chunk-processor for more information."}) public static class Chunk_Processor { @Comment("Auto trim will not save chunks which aren't claimed") public static boolean AUTO_TRIM = false; @@ -232,13 +235,28 @@ public class Settings extends Config { } + @Comment({"UUID settings", + "DO NOT EDIT them unless you know what you are doing."}) public static class UUID { @Comment("Force using offline UUIDs (it usually detects the right mode)") public static boolean OFFLINE = false; @Comment("Force using lowercase UUIDs") public static boolean FORCE_LOWERCASE = false; @Comment("Use a database to store UUID/name info") public static boolean USE_SQLUUIDHANDLER = false; - @Ignore public static boolean NATIVE_UUID_PROVIDER = false; + @Comment("How many UUIDs that may be stored in the cache") + public static int UUID_CACHE_SIZE = 100000; + @Comment("Rate limit (per 10 minutes) for background UUID fetching from the Mojang API") + public static int BACKGROUND_LIMIT = 200; + @Comment("Rate limit (per 10 minutes) for random UUID fetching from the Mojang API") + public static int IMPROMPTU_LIMIT = 300; + @Comment("Timeout (in milliseconds) for non-blocking UUID requests (mostly commands)") + public static long NON_BLOCKING_TIMEOUT = 3000L; + @Comment("Timeout (in milliseconds) for blocking UUID requests (events)") + public static long BLOCKING_TIMEOUT = 10L; + @Comment("Whether or not PlotSquared should read from the legacy database") + public static boolean LEGACY_DATABASE_SUPPORT = true; + @Comment("Whether or not PlotSquared should return Unknown if it fails to fulfill a request") + public static boolean UNKNOWN_AS_DEFAULT = true; } @@ -246,7 +264,8 @@ public class Settings extends Config { public static final class General { @Comment("Display scientific numbers (4.2E8)") public static boolean SCIENTIFIC = false; @Comment("Replace wall when merging") public static boolean MERGE_REPLACE_WALL = true; - @Comment("Blocks that may not be used in plot components") public static List + @Comment({"Blocks that may not be used in plot components", + "Checkout the wiki article regarding plot components before modifying: https://wiki.intellectualsites.com/en/plotsquared/installation/plot-components"}) public static List INVALID_BLOCKS = Arrays.asList( // Acacia Stuff "acacia_button", "acacia_fence_gate", "acacia_door", "acacia_pressure_plate", @@ -360,7 +379,8 @@ public class Settings extends Config { } - @Comment("Schematic Settings") + @Comment({"Schematic Settings", + "See https://wiki.intellectualsites.com/en/plotsquared/schematics/on-claim for more information."}) public static final class Schematics { @Comment( "Whether schematic based generation should paste schematic on top of plots, or from Y=1") @@ -377,6 +397,7 @@ public class Settings extends Config { } + @Comment("Schematic and Asset interface related settings") public static class Web { @Comment({"The web interface for schematics", " - All schematics are anonymous and private", " - Downloads can be deleted by the user", @@ -389,8 +410,9 @@ public class Settings extends Config { } + @Comment("Misc settings") public static final class Done { - @Comment("Require a plot marked as done to download") public static boolean + @Comment("Require a plot marked as done to download (/plot download)") public static boolean REQUIRED_FOR_DOWNLOAD = false; @Comment("Only plots marked as done can be rated") public static boolean REQUIRED_FOR_RATINGS = false; @@ -401,6 +423,7 @@ public class Settings extends Config { } + @Comment("Chat related settings") public static final class Chat { @Comment("Sometimes console color doesn't work, you can disable it here") public static boolean CONSOLE_COLOR = true; @@ -408,7 +431,7 @@ public class Settings extends Config { } - @Comment("Relating to how many plots someone can claim ") + @Comment("Relating to how many plots someone can claim") public static final class Limit { @Comment("Should the limit be global (over multiple worlds)") public static boolean GLOBAL = false; @@ -419,9 +442,10 @@ public class Settings extends Config { } - @Comment("Backup related settings") + @Comment({"Backup related settings", + "See https://wiki.intellectualsites.com/en/plotsquared/backups for more information."}) public static final class Backup { - @Comment("Automatically backup plots when destructive commands are performed") + @Comment("Automatically backup plots when destructive commands are performed, e.g. /plot clear") public static boolean AUTOMATIC_BACKUPS = true; @Comment("Maximum amount of backups associated with a plot") public static int BACKUP_LIMIT = 3; @@ -430,12 +454,14 @@ public class Settings extends Config { } + @Comment("Confirmation timeout related settings") public static final class Confirmation { @Comment("Timeout before a confirmation prompt expires") public static int CONFIRMATION_TIMEOUT_SECONDS = 20; } + @Comment("Teleportation related settings") public static final class Teleport { @Comment("Teleport to your plot on death") public static boolean ON_DEATH = false; @Comment("Teleport to your plot on login") public static boolean ON_LOGIN = false; @@ -448,6 +474,7 @@ public class Settings extends Config { } + @Comment("Redstone related settings") public static final class Redstone { @Comment("Disable redstone in unoccupied plots") public static boolean DISABLE_UNOCCUPIED = false; @@ -459,12 +486,14 @@ public class Settings extends Config { } + @Comment("Claim related settings") public static final class Claim { @Comment("The max plots claimed in a single `/plot auto ` command") public static int MAX_AUTO_AREA = 4; } + @Comment("Rating related settings") public static final class Ratings { @Comment("Replace the rating system with a like system. Will add /plot like/dislike," + " and remove the rating command") public static boolean USE_LIKES = false; @@ -487,6 +516,22 @@ public class Settings extends Config { public static boolean CREATURE_SPAWN = true; @Comment("Check the tile entity limit on block placement") public static boolean TILE_ENTITY_CHECK = true; + @Comment("Use Paper's async tab completion") + public static boolean ASYNC_TAB_COMPLETION; + } + + @Comment("Settings relating to PlotSquared's GlobalBlockQueue") + public static final class QUEUE { + @Comment({"Average time per tick spent completing chunk tasks in ms.", + "Waits (chunk task time / target_time) ticks before completely the next task."}) + public static int TARGET_TIME = 65; + } + + @Comment("Settings related to tab completion") + public static final class Tab_Completions { + @Comment({"The time in seconds how long tab completions should remain in cache.", + "0 will disable caching. Lower values may be less performant."}) + public static int CACHE_EXPIRATION = 15; } @@ -497,8 +542,6 @@ public class Settings extends Config { @Comment("Events are needed to track a lot of things") public static boolean EVENTS = true; @Comment("Commands are used to interact with the plugin") public static boolean COMMANDS = true; - @Comment("The UUID cacher is used to resolve player names") public static boolean - UUID_CACHE = true; @Comment("Whether we should notify you about updates or not.") public static boolean UPDATE_NOTIFICATIONS = true; @Comment("Stores user metadata in a database") public static boolean PERSISTENT_META = true; @@ -508,29 +551,32 @@ public class Settings extends Config { true; @Comment("Allow WorldEdit to be restricted to plots") public static boolean WORLDEDIT_RESTRICTIONS = true; - @Comment("Allow economy to be used") public static boolean ECONOMY = true; + @Comment("Allow economy to be used to sell, claim or buy plots.") public static boolean ECONOMY = true; @Comment("Expiry will clear old or simplistic plots") public static boolean PLOT_EXPIRY = false; @Comment("Processes chunks (trimming, or entity/tile limits) ") public static boolean CHUNK_PROCESSOR = false; - @Comment("Kill mobs on roads") public static boolean KILL_ROAD_MOBS = false; - @Comment("Kill items on roads") public static boolean KILL_ROAD_ITEMS = false; - @Comment("Kill vehicles on roads") public static boolean KILL_ROAD_VEHICLES = false; - @Comment("Notify a player of any missed comments upon plot entry") public static boolean + @Comment("Kill mobs on roads (Chicken, Cow, etc.)") public static boolean KILL_ROAD_MOBS = false; + @Comment("Kill items on roads (Stick, Paper, etc.)") public static boolean KILL_ROAD_ITEMS = false; + @Comment("Kill vehicles on roads (Boat, Minecart, etc.)") public static boolean KILL_ROAD_VEHICLES = false; + @Comment("Notify a player of any missed plot comments upon plot entry") public static boolean COMMENT_NOTIFIER = false; @Comment("Let players claim entire worlds with PlotSquared") public static boolean WORLDS = false; @Comment("Actively purge invalid database entries") public static boolean DATABASE_PURGER = false; - @Comment("Delete plots when a player is banned") public static boolean BAN_DELETER = false; - @Comment("Allows PlaceholderAPI placeholders to be used in captions, flags, etc") + @Comment({"Delete plots when a player is banned.", + "Note: This only works with the /minecraft:ban command. Any punishment plugin like LiteBans is not supported."}) public static boolean BAN_DELETER = false; + @Comment("Allows PlaceholderAPI placeholders to be used in captions, flags, etc.") public static boolean EXTERNAL_PLACEHOLDERS = true; @Comment("Make road regeneration persistent across restarts") public static boolean PERSISTENT_ROAD_REGEN = false; - @Comment("Try to guess plot owners from sign data. This may decrease server performance") - public static boolean GUESS_PLOT_OWNER = false; - @Comment("Plot component preset GUI") - public static boolean COMPONENT_PRESETS = true; + @Comment({"Enable the `/plot component` preset GUI", + "Read more about components here: https://wiki.intellectualsites.com/en/plotsquared/installation/plot-components"}) public static boolean COMPONENT_PRESETS = true; + @Comment("Use UUID cache to complete usernames") + public static boolean EXTENDED_USERNAME_COMPLETION = true; + @Comment("Command aliases that will be tab completed") + public static List TAB_COMPLETED_ALIASES = Arrays.asList("plot", "plots", "p", "plotsquared", "plot2", "p2", "ps", "2", "plotme", "plotz", "ap"); } } diff --git a/Core/src/main/java/com/plotsquared/core/generator/ClassicPlotManager.java b/Core/src/main/java/com/plotsquared/core/generator/ClassicPlotManager.java index 022f7037d..46333a84c 100644 --- a/Core/src/main/java/com/plotsquared/core/generator/ClassicPlotManager.java +++ b/Core/src/main/java/com/plotsquared/core/generator/ClassicPlotManager.java @@ -36,6 +36,7 @@ import com.plotsquared.core.queue.GlobalBlockQueue; import com.plotsquared.core.queue.LocalBlockQueue; import com.plotsquared.core.util.BlockUtil; import com.plotsquared.core.util.MathMan; +import com.plotsquared.core.util.RegionManager; import com.sk89q.worldedit.function.pattern.Pattern; import com.sk89q.worldedit.regions.CuboidRegion; import com.sk89q.worldedit.world.block.BlockTypes; @@ -92,75 +93,38 @@ public class ClassicPlotManager extends SquarePlotManager { public boolean setFloor(PlotId plotId, Pattern blocks) { Plot plot = classicPlotWorld.getPlotAbs(plotId); - LocalBlockQueue queue = classicPlotWorld.getQueue(false); if (plot.isBasePlot()) { - for (CuboidRegion region : plot.getRegions()) { - Location pos1 = - new Location(classicPlotWorld.getWorldName(), region.getMinimumPoint().getX(), - classicPlotWorld.PLOT_HEIGHT, region.getMinimumPoint().getZ()); - Location pos2 = - new Location(classicPlotWorld.getWorldName(), region.getMaximumPoint().getX(), - classicPlotWorld.PLOT_HEIGHT, region.getMaximumPoint().getZ()); - queue.setCuboid(pos1, pos2, blocks); - } + return RegionManager.manager.setCuboids(classicPlotWorld, plot.getRegions(), blocks, + classicPlotWorld.PLOT_HEIGHT, classicPlotWorld.PLOT_HEIGHT); } - return queue.enqueue(); + return false; } public boolean setAll(PlotId plotId, Pattern blocks) { Plot plot = classicPlotWorld.getPlotAbs(plotId); - if (!plot.isBasePlot()) { - return false; + if (plot.isBasePlot()) { + return RegionManager.manager + .setCuboids(classicPlotWorld, plot.getRegions(), blocks, 1, getWorldHeight()); } - LocalBlockQueue queue = classicPlotWorld.getQueue(false); - int maxY = getWorldHeight(); - for (CuboidRegion region : plot.getRegions()) { - Location pos1 = - new Location(classicPlotWorld.getWorldName(), region.getMinimumPoint().getX(), 1, - region.getMinimumPoint().getZ()); - Location pos2 = - new Location(classicPlotWorld.getWorldName(), region.getMaximumPoint().getX(), maxY, - region.getMaximumPoint().getZ()); - queue.setCuboid(pos1, pos2, blocks); - } - return queue.enqueue(); + return false; } public boolean setAir(PlotId plotId, Pattern blocks) { Plot plot = classicPlotWorld.getPlotAbs(plotId); - if (!plot.isBasePlot()) { - return false; + if (plot.isBasePlot()) { + return RegionManager.manager.setCuboids(classicPlotWorld, plot.getRegions(), blocks, + classicPlotWorld.PLOT_HEIGHT + 1, getWorldHeight()); } - LocalBlockQueue queue = classicPlotWorld.getQueue(false); - int maxY = getWorldHeight(); - for (CuboidRegion region : plot.getRegions()) { - Location pos1 = - new Location(classicPlotWorld.getWorldName(), region.getMinimumPoint().getX(), - classicPlotWorld.PLOT_HEIGHT + 1, region.getMinimumPoint().getZ()); - Location pos2 = - new Location(classicPlotWorld.getWorldName(), region.getMaximumPoint().getX(), maxY, - region.getMaximumPoint().getZ()); - queue.setCuboid(pos1, pos2, blocks); - } - return queue.enqueue(); + return false; } public boolean setMain(PlotId plotId, Pattern blocks) { Plot plot = classicPlotWorld.getPlotAbs(plotId); - if (!plot.isBasePlot()) { - return false; + if (plot.isBasePlot()) { + return RegionManager.manager.setCuboids(classicPlotWorld, plot.getRegions(), blocks, 1, + classicPlotWorld.PLOT_HEIGHT - 1); } - LocalBlockQueue queue = classicPlotWorld.getQueue(false); - for (CuboidRegion region : plot.getRegions()) { - Location pos1 = - new Location(classicPlotWorld.getWorldName(), region.getMinimumPoint().getX(), 1, - region.getMinimumPoint().getZ()); - Location pos2 = - new Location(classicPlotWorld.getWorldName(), region.getMaximumPoint().getX(), - classicPlotWorld.PLOT_HEIGHT - 1, region.getMaximumPoint().getZ()); - queue.setCuboid(pos1, pos2, blocks); - } - return queue.enqueue(); + return false; } public boolean setMiddle(PlotId plotId, Pattern blocks) { @@ -491,17 +455,17 @@ public class ClassicPlotManager extends SquarePlotManager { int sz = location.getZ() + 1; int ez = sz + classicPlotWorld.ROAD_WIDTH - 1; LocalBlockQueue queue = classicPlotWorld.getQueue(false); - queue.setCuboid( - new Location(classicPlotWorld.getWorldName(), sx, classicPlotWorld.ROAD_HEIGHT + 1, sz), - new Location(classicPlotWorld.getWorldName(), ex, - classicPlotWorld.getPlotManager().getWorldHeight(), ez), - BlockTypes.AIR.getDefaultState()); + queue.setCuboid(new Location(classicPlotWorld.getWorldName(), sx, + Math.min(classicPlotWorld.PLOT_HEIGHT, classicPlotWorld.ROAD_HEIGHT) + 1, sz), + new Location(classicPlotWorld.getWorldName(), ex, + classicPlotWorld.getPlotManager().getWorldHeight(), ez), + BlockTypes.AIR.getDefaultState()); queue.setCuboid(new Location(classicPlotWorld.getWorldName(), sx, 1, sz), - new Location(classicPlotWorld.getWorldName(), ex, classicPlotWorld.ROAD_HEIGHT - 1, ez), + new Location(classicPlotWorld.getWorldName(), ex, classicPlotWorld.PLOT_HEIGHT - 1, ez), classicPlotWorld.MAIN_BLOCK.toPattern()); queue.setCuboid( - new Location(classicPlotWorld.getWorldName(), sx, classicPlotWorld.ROAD_HEIGHT, sz), - new Location(classicPlotWorld.getWorldName(), ex, classicPlotWorld.ROAD_HEIGHT, ez), + new Location(classicPlotWorld.getWorldName(), sx, classicPlotWorld.PLOT_HEIGHT, sz), + new Location(classicPlotWorld.getWorldName(), ex, classicPlotWorld.PLOT_HEIGHT, ez), classicPlotWorld.TOP_BLOCK.toPattern()); return queue.enqueue(); } diff --git a/Core/src/main/java/com/plotsquared/core/generator/HybridPlotWorld.java b/Core/src/main/java/com/plotsquared/core/generator/HybridPlotWorld.java index da7f46a47..e322072df 100644 --- a/Core/src/main/java/com/plotsquared/core/generator/HybridPlotWorld.java +++ b/Core/src/main/java/com/plotsquared/core/generator/HybridPlotWorld.java @@ -195,8 +195,16 @@ public class HybridPlotWorld extends ClassicPlotWorld { public void setupSchematics() throws SchematicHandler.UnsupportedFormatException { this.G_SCH = new HashMap<>(); this.G_SCH_B = new HashMap<>(); - File root = MainUtil.getFile(PlotSquared.get().IMP.getDirectory(), - "schematics/GEN_ROAD_SCHEMATIC/" + this.getWorldName()); + + // Try to determine root. This means that plot areas can have separate schematic + // directories + File root; + if (!(root = MainUtil.getFile(PlotSquared.get().IMP.getDirectory(), "schematics/GEN_ROAD_SCHEMATIC/" + + this.getWorldName() + "/" + this.getId())).exists()) { + root = MainUtil.getFile(PlotSquared.get().IMP.getDirectory(), + "schematics/GEN_ROAD_SCHEMATIC/" + this.getWorldName()); + } + File schematic1File = new File(root, "sideroad.schem"); if (!schematic1File.exists()) schematic1File = new File(root, "sideroad.schematic"); @@ -272,37 +280,8 @@ public class HybridPlotWorld extends ClassicPlotWorld { (short) (z + shift + oddshift + centerShiftZ), biome); } } -/* HashMap items = schematic3.getTiles(); - if (!items.isEmpty()) { - this.G_SCH_STATE = new HashMap<>(); - outer: - for (Map.Entry entry : items.entrySet()) { - BlockLoc loc = entry.getKey(); - short x = (short) (loc.x + shift + oddshift + centerShiftX); - short z = (short) (loc.z + shift + oddshift + centerShiftZ); - short y = (short) (loc.y + this.PLOT_HEIGHT); - int pair = MathMan.pair(x, z); - HashMap existing = this.G_SCH_STATE.get(pair); - if (existing == null) { - existing = new HashMap<>(); - this.G_SCH_STATE.put(pair, existing); - } - existing.put((int) y, entry.getValue()); - CompoundTag tag = entry.getValue(); - Map map = ReflectionUtils.getMap(tag.getValue()); - for (int i = 1; i <= 4; i++) { - String ln = tag.getString("Line" + i); - if (ln == null || ln.length() > 11) - continue outer; - } - SIGN_LOCATION = - new Location(worldname, loc.x + centerShiftX, this.PLOT_HEIGHT + loc.y, - loc.z + centerShiftZ); - ALLOW_SIGNS = true; - continue outer; - } - }*/ + PlotSquared.debug(Captions.PREFIX + "&3 - plot schematic: &7" + schematic3File.getPath()); } if (schematic1 == null || schematic2 == null || this.ROAD_WIDTH == 0) { PlotSquared.debug(Captions.PREFIX + "&3 - schematic: &7false"); @@ -356,7 +335,7 @@ public class HybridPlotWorld extends ClassicPlotWorld { (short) (z - shift), id, false, h2); } } - BiomeType biome = blockArrayClipboard1 + BiomeType biome = blockArrayClipboard2 .getBiome(BlockVector2.at(x + min.getBlockX(), z + min.getBlockZ())); addOverlayBiome((short) (x - shift), (short) (z - shift), biome); } diff --git a/Core/src/main/java/com/plotsquared/core/generator/IndependentPlotGenerator.java b/Core/src/main/java/com/plotsquared/core/generator/IndependentPlotGenerator.java index 915f22940..324f6d8d4 100644 --- a/Core/src/main/java/com/plotsquared/core/generator/IndependentPlotGenerator.java +++ b/Core/src/main/java/com/plotsquared/core/generator/IndependentPlotGenerator.java @@ -30,6 +30,8 @@ import com.plotsquared.core.plot.PlotArea; import com.plotsquared.core.plot.PlotId; import com.plotsquared.core.plot.SetupObject; import com.plotsquared.core.queue.ScopedLocalBlockQueue; +import com.plotsquared.core.setup.PlotAreaBuilder; +import com.plotsquared.core.setup.SetupProcess; /** * This class allows for implementation independent world generation. @@ -74,9 +76,18 @@ public abstract class IndependentPlotGenerator { * * @param setup */ + @Deprecated public void processSetup(SetupObject setup) { } + /** + * If any additional setup options need to be changed before world creation. + * - e.g. If setup doesn't support some standard options + * + * @param builder the area builder to modify + */ + public void processAreaSetup(PlotAreaBuilder builder) { } + /** * It is preferred for the PlotArea object to do most of the initialization necessary. * diff --git a/Core/src/main/java/com/plotsquared/core/listener/PlotListener.java b/Core/src/main/java/com/plotsquared/core/listener/PlotListener.java index 08133387e..361a71b28 100644 --- a/Core/src/main/java/com/plotsquared/core/listener/PlotListener.java +++ b/Core/src/main/java/com/plotsquared/core/listener/PlotListener.java @@ -61,7 +61,6 @@ import com.plotsquared.core.util.StringMan; import com.plotsquared.core.util.WorldUtil; import com.plotsquared.core.util.task.RunnableVal; import com.plotsquared.core.util.task.TaskManager; -import com.plotsquared.core.util.uuid.UUIDHandler; import com.sk89q.worldedit.world.gamemode.GameMode; import com.sk89q.worldedit.world.gamemode.GameModes; import com.sk89q.worldedit.world.item.ItemType; @@ -124,7 +123,7 @@ public class PlotListener { }, 20); } - public static boolean plotEntry(final PlotPlayer player, final Plot plot) { + public static boolean plotEntry(final PlotPlayer player, final Plot plot) { if (plot.isDenied(player.getUUID()) && !Permissions .hasPermission(player, "plots.admin.entry.denied")) { return false; @@ -161,7 +160,7 @@ public class PlotListener { if (plot.getFlag(NotifyEnterFlag.class)) { if (!Permissions.hasPermission(player, "plots.flag.notify-enter.bypass")) { for (UUID uuid : plot.getOwners()) { - PlotPlayer owner = UUIDHandler.getPlayer(uuid); + final PlotPlayer owner = PlotSquared.imp().getPlayerManager().getPlayerIfExists(uuid); if (owner != null && !owner.getUUID().equals(player.getUUID())) { MainUtil.sendMessage(owner, Captions.NOTIFY_ENTER.getTranslated() .replace("%player", player.getName()) @@ -294,7 +293,7 @@ public class PlotListener { return true; } - public static boolean plotExit(final PlotPlayer player, Plot plot) { + public static boolean plotExit(final PlotPlayer player, Plot plot) { Object previous = player.deleteMeta(PlotPlayer.META_LAST_PLOT); PlotSquared.get().getEventDispatcher().callLeave(player, plot); if (plot.hasOwner()) { @@ -337,7 +336,7 @@ public class PlotListener { if (plot.getFlag(NotifyLeaveFlag.class)) { if (!Permissions.hasPermission(player, "plots.flag.notify-enter.bypass")) { for (UUID uuid : plot.getOwners()) { - PlotPlayer owner = UUIDHandler.getPlayer(uuid); + final PlotPlayer owner = PlotSquared.imp().getPlayerManager().getPlayerIfExists(uuid); if ((owner != null) && !owner.getUUID().equals(player.getUUID())) { MainUtil.sendMessage(owner, Captions.NOTIFY_LEAVE.getTranslated() .replace("%player", player.getName()) diff --git a/Core/src/main/java/com/plotsquared/core/location/Location.java b/Core/src/main/java/com/plotsquared/core/location/Location.java index a6f2c812b..0505137b1 100644 --- a/Core/src/main/java/com/plotsquared/core/location/Location.java +++ b/Core/src/main/java/com/plotsquared/core/location/Location.java @@ -34,6 +34,8 @@ import com.sk89q.worldedit.math.BlockVector2; import com.sk89q.worldedit.math.BlockVector3; import lombok.Getter; import lombok.Setter; +import org.khelekore.prtree.MBR; +import org.khelekore.prtree.SimpleMBR; public class Location implements Cloneable, Comparable { @@ -221,6 +223,10 @@ public class Location implements Cloneable, Comparable { return this; } + public MBR toMBR() { + return new SimpleMBR(this.getX(), this.getX(), this.getY(), this.getY(), this.getZ(), this.getZ()); + } + @Override public boolean equals(Object o) { if (o == null) { return false; diff --git a/Core/src/main/java/com/plotsquared/core/player/ConsolePlayer.java b/Core/src/main/java/com/plotsquared/core/player/ConsolePlayer.java index bf295c9d7..9a97800e7 100644 --- a/Core/src/main/java/com/plotsquared/core/player/ConsolePlayer.java +++ b/Core/src/main/java/com/plotsquared/core/player/ConsolePlayer.java @@ -41,7 +41,7 @@ import org.jetbrains.annotations.NotNull; import java.util.UUID; -public class ConsolePlayer extends PlotPlayer { +public class ConsolePlayer extends PlotPlayer { private static ConsolePlayer instance; @@ -71,6 +71,10 @@ public class ConsolePlayer extends PlotPlayer { return PlotSquared.get().IMP.getConsole(); } + @Override public Actor getPlatformPlayer() { + return this.toActor(); + } + @Override public boolean canTeleport(@NotNull Location location) { return true; } diff --git a/Core/src/main/java/com/plotsquared/core/player/PlotPlayer.java b/Core/src/main/java/com/plotsquared/core/player/PlotPlayer.java index 911c56adb..13efa6bfb 100644 --- a/Core/src/main/java/com/plotsquared/core/player/PlotPlayer.java +++ b/Core/src/main/java/com/plotsquared/core/player/PlotPlayer.java @@ -49,7 +49,6 @@ import com.plotsquared.core.util.EconHandler; import com.plotsquared.core.util.Permissions; import com.plotsquared.core.util.task.RunnableVal; import com.plotsquared.core.util.task.TaskManager; -import com.plotsquared.core.util.uuid.UUIDHandler; import com.sk89q.worldedit.extension.platform.Actor; import com.sk89q.worldedit.world.gamemode.GameMode; import com.sk89q.worldedit.world.item.ItemType; @@ -57,8 +56,11 @@ import lombok.NonNull; import org.jetbrains.annotations.NotNull; import java.nio.ByteBuffer; +import java.util.Collection; +import java.util.Collections; import java.util.HashMap; import java.util.HashSet; +import java.util.LinkedList; import java.util.Map; import java.util.Set; import java.util.UUID; @@ -69,18 +71,23 @@ import java.util.stream.Collectors; /** * The abstract class supporting {@code BukkitPlayer} and {@code SpongePlayer}. */ -public abstract class PlotPlayer implements CommandCaller, OfflinePlotPlayer { +public abstract class PlotPlayer

implements CommandCaller, OfflinePlotPlayer { public static final String META_LAST_PLOT = "lastplot"; public static final String META_LOCATION = "location"; + + // Used to track debug mode + private static final Set> debugModeEnabled = Collections.synchronizedSet(new HashSet<>()); + private static final Map converters = new HashMap<>(); private Map metaMap = new HashMap<>(); /** * The metadata map. */ private ConcurrentHashMap meta; + private int hash; - public static PlotPlayer from(@NonNull final T object) { + public static PlotPlayer from(@NonNull final T object) { if (!converters.containsKey(object.getClass())) { throw new IllegalArgumentException(String .format("There is no registered PlotPlayer converter for type %s", @@ -94,6 +101,23 @@ public abstract class PlotPlayer implements CommandCaller, OfflinePlotPlayer { converters.put(clazz, converter); } + public static Collection> getDebugModePlayers() { + return Collections.unmodifiableCollection(debugModeEnabled); + } + + public static Collection> getDebugModePlayersInPlot(@NotNull final Plot plot) { + if (debugModeEnabled.isEmpty()) { + return Collections.emptyList(); + } + final Collection> players = new LinkedList<>(); + for (final PlotPlayer player : debugModeEnabled) { + if (player.getCurrentPlot().equals(plot)) { + players.add(player); + } + } + return players; + } + /** * Efficiently wrap a Player, or OfflinePlayer object to get a PlotPlayer (or fetch if it's already cached)
* - Accepts sponge/bukkit Player (online) @@ -101,26 +125,17 @@ public abstract class PlotPlayer implements CommandCaller, OfflinePlotPlayer { * - Accepts UUID * - Accepts bukkit OfflinePlayer (offline) * - * @param player - * @return + * @param player Player object to wrap + * @return Wrapped player */ - public static PlotPlayer wrap(Object player) { + public static PlotPlayer wrap(Object player) { return PlotSquared.get().IMP.wrapPlayer(player); } - /** - * Get the cached PlotPlayer from a username
- * - This will return null if the player has not finished logging in or is not online - * - * @param name - * @return - */ - public static PlotPlayer get(String name) { - return UUIDHandler.getPlayer(name); - } - public abstract Actor toActor(); + public abstract P getPlatformPlayer(); + /** * Set some session only metadata for this player. * @@ -363,8 +378,6 @@ public abstract class PlotPlayer implements CommandCaller, OfflinePlotPlayer { /** * Get this player's full location (including yaw/pitch) - * - * @return */ public abstract Location getLocationFull(); @@ -531,6 +544,15 @@ public abstract class PlotPlayer implements CommandCaller, OfflinePlotPlayer { */ public abstract void kick(String message); + public void refreshDebug() { + final boolean debug = this.getAttribute("debug"); + if (debug && !debugModeEnabled.contains(this)) { + debugModeEnabled.add(this); + } else if (!debug) { + debugModeEnabled.remove(this); + } + } + /** * Called when this player quits. */ @@ -563,12 +585,13 @@ public abstract class PlotPlayer implements CommandCaller, OfflinePlotPlayer { plot.getId(), getName())); } } - String name = getName(); if (ExpireManager.IMP != null) { ExpireManager.IMP.storeDate(getUUID(), System.currentTimeMillis()); } - UUIDHandler.getPlayers().remove(name); + PlotSquared.imp().getPlayerManager().removePlayer(this); PlotSquared.get().IMP.unregister(this); + + debugModeEnabled.remove(this); } /** @@ -616,6 +639,10 @@ public abstract class PlotPlayer implements CommandCaller, OfflinePlotPlayer { return; } + if (PlotPlayer.this.getAttribute("debug")) { + debugModeEnabled.add(PlotPlayer.this); + } + if (!Settings.Teleport.ON_LOGIN) { return; } @@ -706,24 +733,41 @@ public abstract class PlotPlayer implements CommandCaller, OfflinePlotPlayer { public abstract void stopSpectating(); + public boolean hasDebugMode() { + return this.getAttribute("debug"); + } + + @Override public int hashCode() { + if (this.hash == 0 || this.hash == 485) { + this.hash = 485 + this.getUUID().hashCode(); + } + return this.hash; + } + + @Override public boolean equals(final Object obj) { + if (!(obj instanceof PlotPlayer)) { + return false; + } + final PlotPlayer other = (PlotPlayer) obj; + return this.getUUID().equals(other.getUUID()); + } + /** * The amount of money this Player has. - * - * @return */ public double getMoney() { - return EconHandler.manager == null ? 0 : EconHandler.manager.getMoney(this); + return EconHandler.getEconHandler() == null ? 0 : EconHandler.getEconHandler().getMoney(this); } public void withdraw(double amount) { - if (EconHandler.manager != null) { - EconHandler.manager.withdrawMoney(this, amount); + if (EconHandler.getEconHandler() != null) { + EconHandler.getEconHandler().withdrawMoney(this, amount); } } public void deposit(double amount) { - if (EconHandler.manager != null) { - EconHandler.manager.depositMoney(this, amount); + if (EconHandler.getEconHandler() != null) { + EconHandler.getEconHandler().depositMoney(this, amount); } } diff --git a/Core/src/main/java/com/plotsquared/core/plot/Plot.java b/Core/src/main/java/com/plotsquared/core/plot/Plot.java index 9461219ef..46ce9f24c 100644 --- a/Core/src/main/java/com/plotsquared/core/plot/Plot.java +++ b/Core/src/main/java/com/plotsquared/core/plot/Plot.java @@ -25,7 +25,6 @@ */ package com.plotsquared.core.plot; -import com.google.common.collect.BiMap; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Sets; import com.plotsquared.core.PlotSquared; @@ -56,17 +55,14 @@ import com.plotsquared.core.plot.flag.implementations.KeepFlag; import com.plotsquared.core.plot.schematic.Schematic; import com.plotsquared.core.queue.GlobalBlockQueue; import com.plotsquared.core.queue.LocalBlockQueue; -import com.plotsquared.core.util.ChunkManager; import com.plotsquared.core.util.MainUtil; import com.plotsquared.core.util.MathMan; import com.plotsquared.core.util.Permissions; import com.plotsquared.core.util.RegionManager; import com.plotsquared.core.util.SchematicHandler; -import com.plotsquared.core.util.StringWrapper; import com.plotsquared.core.util.WorldUtil; import com.plotsquared.core.util.task.RunnableVal; import com.plotsquared.core.util.task.TaskManager; -import com.plotsquared.core.util.uuid.UUIDHandler; import com.sk89q.jnbt.CompoundTag; import com.sk89q.worldedit.function.pattern.Pattern; import com.sk89q.worldedit.math.BlockVector2; @@ -83,7 +79,6 @@ import java.awt.geom.PathIterator; import java.awt.geom.Rectangle2D; import java.io.File; import java.net.URL; -import java.nio.charset.StandardCharsets; import java.util.ArrayDeque; import java.util.ArrayList; import java.util.Collection; @@ -404,12 +399,11 @@ public class Plot { * * @return list of PlotPlayer(s) or an empty list */ - public List getPlayersInPlot() { - ArrayList players = new ArrayList<>(); - for (Entry entry : UUIDHandler.getPlayers().entrySet()) { - PlotPlayer plotPlayer = entry.getValue(); - if (this.equals(plotPlayer.getCurrentPlot())) { - players.add(plotPlayer); + public List> getPlayersInPlot() { + final List> players = new ArrayList<>(); + for (final PlotPlayer player : PlotSquared.imp().getPlayerManager().getPlayers()) { + if (this.equals(player.getCurrentPlot())) { + players.add(player); } } return players; @@ -502,7 +496,7 @@ public class Plot { } if (isMerged()) { Set plots = getConnectedPlots(); - Plot[] array = plots.toArray(new Plot[plots.size()]); + Plot[] array = plots.toArray(new Plot[0]); ImmutableSet.Builder owners = ImmutableSet.builder(); UUID last = this.getOwner(); owners.add(this.getOwner()); @@ -1052,9 +1046,11 @@ public class Plot { } if (createSign) { GlobalBlockQueue.IMP.addEmptyTask(() -> { - for (Plot current : plots) { - current.setSign(MainUtil.getName(current.getOwnerAbs())); - } + TaskManager.runTaskAsync(() -> { + for (Plot current : plots) { + current.setSign(MainUtil.getName(current.getOwnerAbs())); + } + }); }); } if (createRoad) { @@ -1327,8 +1323,8 @@ public class Plot { return false; } for (Plot current : getConnectedPlots()) { - List players = current.getPlayersInPlot(); - for (PlotPlayer pp : players) { + List> players = current.getPlayersInPlot(); + for (PlotPlayer pp : players) { PlotListener.plotExit(pp, current); } @@ -1717,12 +1713,8 @@ public class Plot { this.setSign("unknown"); return; } - String name = UUIDHandler.getName(this.getOwnerAbs()); - if (name == null) { - this.setSign("unknown"); - } else { - this.setSign(name); - } + PlotSquared.get().getImpromptuUUIDPipeline().getSingle(this.getOwnerAbs(), (username, sign) -> + this.setSign(username)); } /** @@ -1759,6 +1751,7 @@ public class Plot { } } else { area.addPlot(this); + updateWorldBorder(); } setSign(player.getName()); MainUtil.sendMessage(player, Captions.CLAIMED); @@ -2372,7 +2365,6 @@ public class Plot { * Check if a plot can be claimed by the provided player. * * @param player the claiming player - * @return */ public boolean canClaim(@NotNull PlotPlayer player) { PlotCluster cluster = this.getCluster(); @@ -2382,81 +2374,13 @@ public class Plot { return false; } } - final UUID owner = this.guessOwner(); + final UUID owner = this.getOwnerAbs(); if (owner != null) { return false; } return !isMerged(); } - /** - * Guess the owner of a plot either by the value in memory, or the sign data
- * Note: Recovering from sign information is useful if e.g. PlotMe conversion wasn't successful - * - * @return UUID - */ - public UUID guessOwner() { - if (this.hasOwner()) { - return this.getOwnerAbs(); - } - if (!this.area.allowSigns() || !Settings.Enabled_Components.GUESS_PLOT_OWNER) { - return null; - } - try { - final Location location = this.getManager().getSignLoc(this); - String[] lines = TaskManager.IMP.sync(new RunnableVal() { - @Override public void run(String[] value) { - ChunkManager.manager - .loadChunk(location.getWorld(), location.getBlockVector2(), false); - this.value = WorldUtil.IMP.getSignSynchronous(location); - } - }); - if (lines == null) { - return null; - } - loop: - for (int i = 4; i > 0; i--) { - String caption = Captions.valueOf("OWNER_SIGN_LINE_" + i).getTranslated(); - int index = caption.indexOf("%plr%"); - if (index < 0) { - continue; - } - String line = lines[i - 1]; - if (line.length() <= index) { - return null; - } - String name = line.substring(index); - if (name.isEmpty()) { - return null; - } - UUID owner = UUIDHandler.getUUID(name, null); - if (owner != null) { - this.setOwnerAbs(owner); - break; - } - if (lines[i - 1].length() == 15) { - BiMap map = UUIDHandler.getUuidMap(); - for (Entry entry : map.entrySet()) { - String key = entry.getKey().value; - if (key.length() > name.length() && key.startsWith(name)) { - this.setOwnerAbs(entry.getValue()); - break loop; - } - } - } - this.setOwnerAbs(UUID.nameUUIDFromBytes( - ("OfflinePlayer:" + name).getBytes(StandardCharsets.UTF_8))); - break; - } - if (this.hasOwner()) { - this.create(); - } - return this.getOwnerAbs(); - } catch (IllegalArgumentException ignored) { - return null; - } - } - /** * Remove the south road section of a plot
* - Used when a plot is merged
@@ -2994,13 +2918,29 @@ public class Plot { */ public void reEnter() { TaskManager.runTaskLater(() -> { - for (PlotPlayer pp : Plot.this.getPlayersInPlot()) { + for (PlotPlayer pp : Plot.this.getPlayersInPlot()) { PlotListener.plotExit(pp, Plot.this); PlotListener.plotEntry(pp, Plot.this); } }, 1); } + public void debug(@NotNull final String message) { + try { + final Collection> players = PlotPlayer.getDebugModePlayersInPlot(this); + if (players.isEmpty()) { + return; + } + final String string = + Captions.PLOT_DEBUG.getTranslated().replace("%plot%", this.toString()).replace("%message%", message); + for (final PlotPlayer player : players) { + if (isOwner(player.getUUID()) || Permissions.hasPermission(player, Captions.PERMISSION_ADMIN_DEBUG_OTHER)) { + player.sendMessage(string); + } + } + } catch (final Exception ignored) {} + } + /** * Gets all the corners of the plot (supports non-rectangular shapes). * @@ -3099,10 +3039,12 @@ public class Plot { return false; } if (!isMerged()) { - return UUIDHandler.getPlayer(this.getOwnerAbs()) != null; + return PlotSquared.imp().getPlayerManager() + .getPlayerIfExists(Objects.requireNonNull(this.getOwnerAbs())) != null; } for (final Plot current : getConnectedPlots()) { - if (current.hasOwner() && UUIDHandler.getPlayer(current.getOwnerAbs()) != null) { + if (current.hasOwner() && PlotSquared.imp().getPlayerManager() + .getPlayerIfExists(Objects.requireNonNull(current.getOwnerAbs())) != null) { return true; } } @@ -3114,9 +3056,9 @@ public class Plot { * - E.g. floor, wall, border etc.
* - The available components depend on the generator being used
* - * @param component - * @param blocks - * @return + * @param component Component to set + * @param blocks Pattern to use the generation + * @return True if the component was set successfully */ public boolean setComponent(String component, Pattern blocks) { PlotComponentSetEvent event = diff --git a/Core/src/main/java/com/plotsquared/core/plot/PlotArea.java b/Core/src/main/java/com/plotsquared/core/plot/PlotArea.java index b6e630e40..868b9f475 100644 --- a/Core/src/main/java/com/plotsquared/core/plot/PlotArea.java +++ b/Core/src/main/java/com/plotsquared/core/plot/PlotArea.java @@ -1026,7 +1026,7 @@ public abstract class PlotArea { * @return true if plot signs are allow, false otherwise. */ public boolean allowSigns() { - return allowSigns; + return allowSigns && (this.plots.size() > 1) /* Do not generate signs for single plots */; } /** diff --git a/Core/src/main/java/com/plotsquared/core/plot/PlotAreaType.java b/Core/src/main/java/com/plotsquared/core/plot/PlotAreaType.java index 60c9fc7f0..9ed4cb0f0 100644 --- a/Core/src/main/java/com/plotsquared/core/plot/PlotAreaType.java +++ b/Core/src/main/java/com/plotsquared/core/plot/PlotAreaType.java @@ -25,6 +25,10 @@ */ package com.plotsquared.core.plot; +import com.plotsquared.core.configuration.Caption; +import com.plotsquared.core.configuration.Captions; +import lombok.Getter; + import java.util.Map; import java.util.Optional; import java.util.function.Function; @@ -32,11 +36,23 @@ import java.util.stream.Collectors; import java.util.stream.Stream; public enum PlotAreaType { - NORMAL, AUGMENTED, PARTIAL; + NORMAL(Captions.PLOT_AREA_TYPE_NORMAL), + AUGMENTED(Captions.PLOT_AREA_TYPE_AUGMENTED), + PARTIAL(Captions.PLOT_AREA_TYPE_PARTIAL); + + @Getter private final Caption description; private static final Map types = Stream.of(values()) .collect(Collectors.toMap(e -> e.toString().toLowerCase(), Function.identity())); + PlotAreaType(Caption description) { + this.description = description; + } + + public static Map getDescriptionMap() { + return Stream.of(values()).collect(Collectors.toMap(e -> e, PlotAreaType::getDescription)); + } + public static Optional fromString(String typeName) { return Optional.ofNullable(types.get(typeName.toLowerCase())); } diff --git a/Core/src/main/java/com/plotsquared/core/plot/PlotFilter.java b/Core/src/main/java/com/plotsquared/core/plot/PlotFilter.java index f7433a2ae..9319c048e 100644 --- a/Core/src/main/java/com/plotsquared/core/plot/PlotFilter.java +++ b/Core/src/main/java/com/plotsquared/core/plot/PlotFilter.java @@ -25,7 +25,10 @@ */ package com.plotsquared.core.plot; -public abstract class PlotFilter { +/** + * Use {@link com.plotsquared.core.util.query.PlotQuery} instead + */ +@Deprecated public abstract class PlotFilter { public boolean allowsArea(final PlotArea area) { return true; } @@ -33,4 +36,5 @@ public abstract class PlotFilter { public boolean allowsPlot(final Plot plot) { return true; } + } diff --git a/Core/src/main/java/com/plotsquared/core/plot/PlotInventory.java b/Core/src/main/java/com/plotsquared/core/plot/PlotInventory.java index 1a3abd5e0..88f9c100c 100644 --- a/Core/src/main/java/com/plotsquared/core/plot/PlotInventory.java +++ b/Core/src/main/java/com/plotsquared/core/plot/PlotInventory.java @@ -33,40 +33,40 @@ import lombok.NonNull; public class PlotInventory { private static final String META_KEY = "inventory"; - public final PlotPlayer player; + public final PlotPlayer player; public final int size; private final PlotItemStack[] items; private String title; private boolean open = false; - public PlotInventory(PlotPlayer player) { + public PlotInventory(PlotPlayer player) { this.size = 4; this.title = null; this.player = player; this.items = InventoryUtil.manager.getItems(player); } - public PlotInventory(PlotPlayer player, int size, String name) { + public PlotInventory(PlotPlayer player, int size, String name) { this.size = size; this.title = name == null ? "" : name; this.player = player; this.items = new PlotItemStack[size * 9]; } - public static boolean hasPlotInventoryOpen(@NonNull final PlotPlayer plotPlayer) { + public static boolean hasPlotInventoryOpen(@NonNull final PlotPlayer plotPlayer) { return getOpenPlotInventory(plotPlayer) != null; } - public static PlotInventory getOpenPlotInventory(@NonNull final PlotPlayer plotPlayer) { + public static PlotInventory getOpenPlotInventory(@NonNull final PlotPlayer plotPlayer) { return plotPlayer.getMeta(META_KEY, null); } - public static void setPlotInventoryOpen(@NonNull final PlotPlayer plotPlayer, + public static void setPlotInventoryOpen(@NonNull final PlotPlayer plotPlayer, @NonNull final PlotInventory plotInventory) { plotPlayer.setMeta(META_KEY, plotInventory); } - public static void removePlotInventoryOpen(@NonNull final PlotPlayer plotPlayer) { + public static void removePlotInventoryOpen(@NonNull final PlotPlayerplotPlayer) { plotPlayer.deleteMeta(META_KEY); } diff --git a/Core/src/main/java/com/plotsquared/core/plot/PlotWorld.java b/Core/src/main/java/com/plotsquared/core/plot/PlotWorld.java new file mode 100644 index 000000000..ed7b854c2 --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/plot/PlotWorld.java @@ -0,0 +1,105 @@ +/* + * _____ _ _ _____ _ + * | __ \| | | | / ____| | | + * | |__) | | ___ | |_| (___ __ _ _ _ __ _ _ __ ___ __| | + * | ___/| |/ _ \| __|\___ \ / _` | | | |/ _` | '__/ _ \/ _` | + * | | | | (_) | |_ ____) | (_| | |_| | (_| | | | __/ (_| | + * |_| |_|\___/ \__|_____/ \__, |\__,_|\__,_|_| \___|\__,_| + * | | + * |_| + * PlotSquared plot management system for Minecraft + * Copyright (C) 2020 IntellectualSites + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.plotsquared.core.plot; + +import com.plotsquared.core.location.Location; +import com.sk89q.worldedit.regions.CuboidRegion; +import lombok.EqualsAndHashCode; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Collection; + +/** + * A world that contains plots + */ +@EqualsAndHashCode +public abstract class PlotWorld { + + private final String world; + + /** + * Create a new plot world with a given world name + * + * @param world World name + */ + protected PlotWorld(@NotNull final String world) { + this.world = world; + } + + /** + * Get the plot area that contains the given location, or null + * if the location is not a part of a plot area. + * + * @param location Location + * @return Containing plot area, or null + */ + @Nullable public abstract PlotArea getArea(@NotNull final Location location); + + /** + * Get all plot areas in the world + * + * @return All plot areas in the world + */ + @NotNull public abstract Collection getAreas(); + + /** + * Get all plot areas in a specified region + * + * @param region Region + * @return All areas in the region + */ + @NotNull public abstract Collection getAreasInRegion( + @NotNull final CuboidRegion region); + + /** + * Register a new area in the world + * + * @param area Plot area + */ + public void addArea(@NotNull final PlotArea area) { + throw new UnsupportedOperationException("This world type does not allow adding new areas"); + } + + /** + * Remove an area from the world + * + * @param area Plot area + */ + public void removeArea(@NotNull final PlotArea area) { + throw new UnsupportedOperationException("This world type does not allow removing areas"); + } + + /** + * Get the world name + * + * @return World name + */ + public String getWorld() { + return this.world; + } + +} diff --git a/Core/src/main/java/com/plotsquared/core/plot/SetupObject.java b/Core/src/main/java/com/plotsquared/core/plot/SetupObject.java index 8ac5d5cb0..bfca8fe5e 100644 --- a/Core/src/main/java/com/plotsquared/core/plot/SetupObject.java +++ b/Core/src/main/java/com/plotsquared/core/plot/SetupObject.java @@ -28,6 +28,10 @@ package com.plotsquared.core.plot; import com.plotsquared.core.configuration.ConfigurationNode; import com.plotsquared.core.util.SetupUtils; +/** + * @deprecated will be removed in v6 + */ +@Deprecated public class SetupObject { /** diff --git a/Core/src/main/java/com/plotsquared/core/plot/comment/CommentManager.java b/Core/src/main/java/com/plotsquared/core/plot/comment/CommentManager.java index 6c41b905c..141d729c7 100644 --- a/Core/src/main/java/com/plotsquared/core/plot/comment/CommentManager.java +++ b/Core/src/main/java/com/plotsquared/core/plot/comment/CommentManager.java @@ -38,8 +38,7 @@ import java.util.HashMap; import java.util.List; import java.util.concurrent.atomic.AtomicInteger; -@Beta -public class CommentManager { +@Beta public class CommentManager { public static final HashMap inboxes = new HashMap<>(); @@ -76,7 +75,7 @@ public class CommentManager { }, 20); } - public static long getTimestamp(PlotPlayer player, String inbox) { + public static long getTimestamp(PlotPlayer player, String inbox) { return player.getMeta("inbox:" + inbox, player.getLastPlayed()); } diff --git a/Core/src/main/java/com/plotsquared/core/plot/expiration/ExpireManager.java b/Core/src/main/java/com/plotsquared/core/plot/expiration/ExpireManager.java index 6b5f2bbae..532134536 100644 --- a/Core/src/main/java/com/plotsquared/core/plot/expiration/ExpireManager.java +++ b/Core/src/main/java/com/plotsquared/core/plot/expiration/ExpireManager.java @@ -27,7 +27,6 @@ package com.plotsquared.core.plot.expiration; import com.plotsquared.core.PlotSquared; import com.plotsquared.core.configuration.Captions; -import com.plotsquared.core.configuration.Settings; import com.plotsquared.core.database.DBFunc; import com.plotsquared.core.events.PlotFlagAddEvent; import com.plotsquared.core.events.PlotUnlinkEvent; @@ -48,7 +47,6 @@ import com.plotsquared.core.util.StringMan; import com.plotsquared.core.util.task.RunnableVal; import com.plotsquared.core.util.task.RunnableVal3; import com.plotsquared.core.util.task.TaskManager; -import com.plotsquared.core.util.uuid.UUIDHandler; import java.util.ArrayDeque; import java.util.ArrayList; @@ -85,7 +83,7 @@ public class ExpireManager { this.tasks.add(task); } - public void handleJoin(PlotPlayer pp) { + public void handleJoin(PlotPlayer pp) { storeDate(pp.getUUID(), System.currentTimeMillis()); if (plotsToDelete != null && !plotsToDelete.isEmpty()) { for (Plot plot : pp.getPlots()) { @@ -153,11 +151,11 @@ public class ExpireManager { //.text("\n - ").color("$3").text("Delete all (/plot delete expired)").color("$2").command("/plot delete expired") .text("\n - ").color("$3").text("Delete this (/plot delete)") .color("$2").command("/plot delete").tooltip("/plot delete") - .text("\n - ").color("$3").text("Remind later (/plot set keep 1d)") - .color("$2").command("/plot set keep 1d").tooltip("/plot set keep 1d") - .text("\n - ").color("$3").text("Keep this (/plot set keep true)") - .color("$2").command("/plot set keep true") - .tooltip("/plot set keep true").text("\n - ").color("$3") + .text("\n - ").color("$3").text("Remind later (/plot flag set keep 1d)") + .color("$2").command("/plot flag set keep 1d").tooltip("/plot flag set keep 1d") + .text("\n - ").color("$3").text("Keep this (/plot flag set keep true)") + .color("$2").command("/plot flag set keep true") + .tooltip("/plot flag set keep true").text("\n - ").color("$3") .text("Don't show me this").color("$2") .command("/plot toggle clear-confirmation") .tooltip("/plot toggle clear-confirmation"); @@ -411,13 +409,13 @@ public class ExpireManager { } } for (UUID helper : plot.getTrusted()) { - PlotPlayer player = UUIDHandler.getPlayer(helper); + PlotPlayer player = PlotSquared.imp().getPlayerManager().getPlayerIfExists(helper); if (player != null) { MainUtil.sendMessage(player, Captions.PLOT_REMOVED_USER, plot.toString()); } } for (UUID helper : plot.getMembers()) { - PlotPlayer player = UUIDHandler.getPlayer(helper); + PlotPlayer player = PlotSquared.imp().getPlayerManager().getPlayerIfExists(helper); if (player != null) { MainUtil.sendMessage(player, Captions.PLOT_REMOVED_USER, plot.toString()); } @@ -433,56 +431,34 @@ public class ExpireManager { .getString(plots)); PlotSquared.debug("$4 - Area: " + plot.getArea()); if (plot.hasOwner()) { - PlotSquared.debug("$4 - Owner: " + UUIDHandler.getName(plot.getOwner())); + PlotSquared.debug("$4 - Owner: " + plot.getOwner()); } else { PlotSquared.debug("$4 - Owner: Unowned"); } } public long getAge(UUID uuid) { - if (UUIDHandler.getPlayer(uuid) != null) { + if (PlotSquared.imp().getPlayerManager().getPlayerIfExists(uuid) != null) { return 0; } - String name = UUIDHandler.getName(uuid); - if (name != null) { - Long last = this.dates_cache.get(uuid); - if (last == null) { - OfflinePlotPlayer opp; - if (Settings.UUID.NATIVE_UUID_PROVIDER) { - opp = UUIDHandler.getUUIDWrapper().getOfflinePlayer(uuid); - } else { - opp = UUIDHandler.getUUIDWrapper().getOfflinePlayer(name); - } - if (opp != null && (last = opp.getLastPlayed()) != 0) { - this.dates_cache.put(uuid, last); - } else { - return 0; - } - } - if (last == 0) { + Long last = this.dates_cache.get(uuid); + if (last == null) { + OfflinePlotPlayer opp = PlotSquared.imp().getPlayerManager().getOfflinePlayer(uuid); + if (opp != null && (last = opp.getLastPlayed()) != 0) { + this.dates_cache.put(uuid, last); + } else { return 0; } - return System.currentTimeMillis() - last; } - return 0; - } - - public long getAccountAge(Plot plot) { - if (!plot.hasOwner() || Objects.equals(DBFunc.EVERYONE, plot.getOwner()) - || UUIDHandler.getPlayer(plot.getOwner()) != null || plot.getRunning() > 0) { - return Long.MAX_VALUE; + if (last == 0) { + return 0; } - long max = 0; - for (UUID owner : plot.getOwners()) { - long age = getAccountAge(owner); - max = Math.max(age, max); - } - return max; + return System.currentTimeMillis() - last; } public long getAge(Plot plot) { if (!plot.hasOwner() || Objects.equals(DBFunc.EVERYONE, plot.getOwner()) - || UUIDHandler.getPlayer(plot.getOwner()) != null || plot.getRunning() > 0) { + || PlotSquared.imp().getPlayerManager().getPlayerIfExists(plot.getOwner()) != null || plot.getRunning() > 0) { return 0; } diff --git a/Core/src/main/java/com/plotsquared/core/plot/flag/FlagContainer.java b/Core/src/main/java/com/plotsquared/core/plot/flag/FlagContainer.java index 7b60fea97..e0bb40fb8 100644 --- a/Core/src/main/java/com/plotsquared/core/plot/flag/FlagContainer.java +++ b/Core/src/main/java/com/plotsquared/core/plot/flag/FlagContainer.java @@ -42,8 +42,7 @@ import java.util.Map; /** * Container type for {@link PlotFlag plot flags}. */ -@EqualsAndHashCode(of = "flagMap") -public class FlagContainer { +@EqualsAndHashCode(of = "flagMap") public class FlagContainer { private final Map unknownFlags = new HashMap<>(); private final Map, PlotFlag> flagMap = new HashMap<>(); @@ -341,8 +340,7 @@ public class FlagContainer { /** * Handler for update events in {@link FlagContainer flag containers}. */ - @FunctionalInterface - public interface PlotFlagUpdateHandler { + @FunctionalInterface public interface PlotFlagUpdateHandler { /** * Act on the flag update event diff --git a/Core/src/main/java/com/plotsquared/core/plot/flag/PlotFlag.java b/Core/src/main/java/com/plotsquared/core/plot/flag/PlotFlag.java index 513398a39..af3306b25 100644 --- a/Core/src/main/java/com/plotsquared/core/plot/flag/PlotFlag.java +++ b/Core/src/main/java/com/plotsquared/core/plot/flag/PlotFlag.java @@ -41,8 +41,7 @@ import java.util.Collections; * * @param Value contained in the flag. */ -@EqualsAndHashCode(of = "value") -public abstract class PlotFlag> { +@EqualsAndHashCode(of = "value") public abstract class PlotFlag> { private final T value; private final Caption flagCategory; diff --git a/Core/src/main/java/com/plotsquared/core/plot/flag/types/BlockTypeWrapper.java b/Core/src/main/java/com/plotsquared/core/plot/flag/types/BlockTypeWrapper.java index 638653f0e..9af840d4c 100644 --- a/Core/src/main/java/com/plotsquared/core/plot/flag/types/BlockTypeWrapper.java +++ b/Core/src/main/java/com/plotsquared/core/plot/flag/types/BlockTypeWrapper.java @@ -44,6 +44,8 @@ import java.util.Map; */ public class BlockTypeWrapper { + private static final Map blockTypes = new HashMap<>(); + private static final Map blockCategories = new HashMap<>(); @Nullable @Getter private final BlockType blockType; @Nullable private final String blockCategoryId; @Nullable private BlockCategory blockCategory; @@ -66,6 +68,19 @@ public class BlockTypeWrapper { this.blockCategoryId = Preconditions.checkNotNull(blockCategoryId); } + public static BlockTypeWrapper get(final BlockType blockType) { + return blockTypes.computeIfAbsent(blockType, BlockTypeWrapper::new); + } + + public static BlockTypeWrapper get(final BlockCategory blockCategory) { + return blockCategories + .computeIfAbsent(blockCategory.getId(), id -> new BlockTypeWrapper(blockCategory)); + } + + public static BlockTypeWrapper get(final String blockCategoryId) { + return blockCategories.computeIfAbsent(blockCategoryId, BlockTypeWrapper::new); + } + @Override public String toString() { if (this.blockType != null) { final String key = this.blockType.toString(); @@ -135,21 +150,6 @@ public class BlockTypeWrapper { return Objects.hashCode(this.blockType, this.blockCategoryId); } - private static final Map blockTypes = new HashMap<>(); - private static final Map blockCategories = new HashMap<>(); - - public static BlockTypeWrapper get(final BlockType blockType) { - return blockTypes.computeIfAbsent(blockType, BlockTypeWrapper::new); - } - - public static BlockTypeWrapper get(final BlockCategory blockCategory) { - return blockCategories - .computeIfAbsent(blockCategory.getId(), id -> new BlockTypeWrapper(blockCategory)); - } - - public static BlockTypeWrapper get(final String blockCategoryId) { - return blockCategories.computeIfAbsent(blockCategoryId, BlockTypeWrapper::new); - } /** * Prevents exceptions when loading/saving block categories diff --git a/Core/src/main/java/com/plotsquared/core/plot/world/DefaultPlotAreaManager.java b/Core/src/main/java/com/plotsquared/core/plot/world/DefaultPlotAreaManager.java index 833bf3d4f..9ce0b1623 100644 --- a/Core/src/main/java/com/plotsquared/core/plot/world/DefaultPlotAreaManager.java +++ b/Core/src/main/java/com/plotsquared/core/plot/world/DefaultPlotAreaManager.java @@ -25,143 +25,93 @@ */ package com.plotsquared.core.plot.world; -import com.plotsquared.core.collection.QuadMap; import com.plotsquared.core.location.Location; import com.plotsquared.core.plot.PlotArea; +import com.plotsquared.core.plot.PlotAreaType; +import com.plotsquared.core.plot.PlotWorld; import com.plotsquared.core.util.StringMan; import com.sk89q.worldedit.regions.CuboidRegion; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; import java.util.HashMap; import java.util.HashSet; -import java.util.LinkedHashSet; +import java.util.List; +import java.util.Map; import java.util.Set; public class DefaultPlotAreaManager implements PlotAreaManager { final PlotArea[] noPlotAreas = new PlotArea[0]; - // All plot areas mapped by world - private final HashMap plotAreaMap = new HashMap<>(); - // All plot areas mapped by position - private final HashMap> plotAreaGrid = new HashMap<>(); - private final HashSet plotAreaHashCheck = new HashSet<>(); - // All plot areas - private PlotArea[] plotAreas = new PlotArea[0]; - // Optimization if there are no hash collisions - private boolean plotAreaHasCollision = false; - private String[] worlds = new String[0]; + private final Map plotWorlds = new HashMap<>(); @Override public PlotArea[] getAllPlotAreas() { - return plotAreas; - } - - @Override public PlotArea getApplicablePlotArea(Location location) { - switch (this.plotAreas.length) { - case 0: - return null; - case 1: - return this.plotAreas[0].getWorldHash() == location.getWorld().hashCode() - && this.plotAreas[0].contains(location) && (!this.plotAreaHasCollision - || location.getWorld().equals(this.plotAreas[0].getWorldName())) ? - this.plotAreas[0] : - null; - case 2: - case 3: - case 4: - case 5: - case 6: - case 7: - case 8: - String world = location.getWorld(); - int hash = world.hashCode(); - for (PlotArea area : this.plotAreas) { - if (hash == area.getWorldHash()) { - if (area.contains(location.getX(), location.getZ()) && ( - !this.plotAreaHasCollision || world.equals(area.getWorldName()))) { - return area; - } - } - } - return null; - default: - PlotArea[] areas = this.plotAreaMap.get(location.getWorld()); - if (areas == null) { - return null; - } - int z; - int x; - switch (areas.length) { - case 1: - return areas[0]; - case 2: - case 3: - case 4: - case 5: - case 6: - case 7: - case 8: - x = location.getX(); - z = location.getZ(); - for (PlotArea area : areas) { - if (area.contains(x, z)) { - return area; - } - } - return null; - default: - QuadMap search = this.plotAreaGrid.get(location.getWorld()); - return search.get(location.getX(), location.getZ()); - } + final Set area = new HashSet<>(); + for (final PlotWorld world : plotWorlds.values()) { + area.addAll(world.getAreas()); } + return area.toArray(new PlotArea[0]); } - @Override public void addPlotArea(PlotArea plotArea) { - HashSet localAreas = - new HashSet<>(Arrays.asList(getPlotAreas(plotArea.getWorldName(), null))); - HashSet globalAreas = new HashSet<>(Arrays.asList(plotAreas)); - localAreas.add(plotArea); - globalAreas.add(plotArea); - this.plotAreas = globalAreas.toArray(new PlotArea[0]); - this.plotAreaMap.put(plotArea.getWorldName(), localAreas.toArray(new PlotArea[0])); - QuadMap map = this.plotAreaGrid.get(plotArea.getWorldName()); - if (map == null) { - map = new QuadMap(Integer.MAX_VALUE, 0, 0) { - @Override public CuboidRegion getRegion(PlotArea value) { - return value.getRegion(); - } - }; - this.plotAreaGrid.put(plotArea.getWorldName(), map); + @Override @Nullable public PlotArea getApplicablePlotArea(final Location location) { + if (location == null) { + return null; } - map.add(plotArea); + final PlotWorld world = this.plotWorlds.get(location.getWorld()); + if (world == null) { + return null; + } + return world.getArea(location); } - @Override public void removePlotArea(PlotArea area) { - ArrayList globalAreas = new ArrayList<>(Arrays.asList(plotAreas)); - globalAreas.remove(area); - this.plotAreas = globalAreas.toArray(new PlotArea[0]); - if (globalAreas.isEmpty()) { - this.plotAreaMap.remove(area.getWorldName()); - this.plotAreaGrid.remove(area.getWorldName()); + @Override public void addPlotArea(final PlotArea plotArea) { + PlotWorld world = this.plotWorlds.get(plotArea.getWorldName()); + if (world != null) { + if (world instanceof StandardPlotWorld && world.getAreas().isEmpty()) { + this.plotWorlds.remove(plotArea.getWorldName()); + } else { + world.addArea(plotArea); + return; + } + } + if (plotArea.getType() != PlotAreaType.PARTIAL) { + world = new StandardPlotWorld(plotArea.getWorldName(), plotArea); } else { - this.plotAreaMap.put(area.getWorldName(), globalAreas.toArray(new PlotArea[0])); - this.plotAreaGrid.get(area.getWorldName()).remove(area); + world = new ScatteredPlotWorld(plotArea.getWorldName()); + world.addArea(plotArea); + } + this.plotWorlds.put(plotArea.getWorldName(), world); + } + + @Override public void removePlotArea(final PlotArea area) { + final PlotWorld world = this.plotWorlds.get(area.getWorldName()); + if (world == null) { + return; + } + if (world instanceof StandardPlotWorld) { + this.plotWorlds.remove(world.getWorld()); + } else { + world.removeArea(area); + if (world.getAreas().isEmpty()) { + this.plotWorlds.remove(world.getWorld()); + } } } - @Override public PlotArea getPlotArea(String world, String id) { - PlotArea[] areas = this.plotAreaMap.get(world); - if (areas == null) { + @Override public PlotArea getPlotArea(final String world, final String id) { + final PlotWorld plotWorld = this.plotWorlds.get(world); + if (plotWorld == null) { return null; } - if (areas.length == 1) { - return areas[0]; - } else if (id == null) { + final List areas = new ArrayList<>(plotWorld.getAreas()); + if (areas.size() == 1) { + return areas.get(0); + } + if (id == null) { return null; } - for (PlotArea area : areas) { + for (final PlotArea area : areas) { if (StringMan.isEqual(id, area.getId())) { return area; } @@ -169,103 +119,37 @@ public class DefaultPlotAreaManager implements PlotAreaManager { return null; } - @Override public PlotArea getPlotArea(@NotNull Location location) { - switch (this.plotAreas.length) { - case 0: - return null; - case 1: - PlotArea pa = this.plotAreas[0]; - if (pa.contains(location)) { - return pa; - } else { - return null; - } - case 2: - case 3: - case 4: - case 5: - case 6: - case 7: - case 8: - String world = location.getWorld(); - int hash = world.hashCode(); - for (PlotArea area : this.plotAreas) { - if (hash == area.getWorldHash()) { - if (area.contains(location.getX(), location.getZ()) && ( - !this.plotAreaHasCollision || world.equals(area.getWorldName()))) { - return area; - } - } - } - return null; - default: - PlotArea[] areas = this.plotAreaMap.get(location.getWorld()); - if (areas == null) { - return null; - } - int x; - int z; - switch (areas.length) { - case 0: - PlotArea a = areas[0]; - return a.contains(location.getX(), location.getZ()) ? a : null; - case 2: - case 3: - case 4: - case 5: - case 6: - case 7: - case 8: - x = location.getX(); - z = location.getZ(); - for (PlotArea area : areas) { - if (area.contains(x, z)) { - return area; - } - } - return null; - default: - QuadMap search = this.plotAreaGrid.get(location.getWorld()); - return search.get(location.getX(), location.getZ()); - } - } + @Override public PlotArea getPlotArea(@NotNull final Location location) { + return this.getApplicablePlotArea(location); } - @Override public PlotArea[] getPlotAreas(String world, CuboidRegion region) { - if (region == null) { - PlotArea[] areas = this.plotAreaMap.get(world); - if (areas == null) { - return noPlotAreas; - } - return areas; - } - QuadMap areas = this.plotAreaGrid.get(world); - if (areas == null) { + @Override public PlotArea[] getPlotAreas(final String world, final CuboidRegion region) { + final PlotWorld plotWorld = this.plotWorlds.get(world); + if (plotWorld == null) { return noPlotAreas; - } else { - Set found = areas.get(region); - return found.toArray(new PlotArea[0]); } + if (region == null) { + return plotWorld.getAreas().toArray(new PlotArea[0]); + } + return plotWorld.getAreasInRegion(region).toArray(new PlotArea[0]); } - @Override public void addWorld(String worldName) { - if (!this.plotAreaHasCollision && !this.plotAreaHashCheck.add(worldName.hashCode())) { - this.plotAreaHasCollision = true; + @Override public void addWorld(final String worldName) { + PlotWorld world = this.plotWorlds.get(worldName); + if (world != null) { + return; } - Set tmp = new LinkedHashSet<>(); - Collections.addAll(tmp, worlds); - tmp.add(worldName); - worlds = tmp.toArray(new String[0]); + // Create a new empty world. When a new area is added + // the world will be re-recreated with the correct type + world = new StandardPlotWorld(worldName, null); + this.plotWorlds.put(worldName, world); } - @Override public void removeWorld(String worldName) { - Set tmp = new LinkedHashSet<>(); - Collections.addAll(tmp, worlds); - tmp.remove(worldName); - worlds = tmp.toArray(new String[0]); + @Override public void removeWorld(final String worldName) { + this.plotWorlds.remove(worldName); } @Override public String[] getAllWorlds() { - return worlds; + return this.plotWorlds.keySet().toArray(new String[0]); } } diff --git a/Core/src/main/java/com/plotsquared/core/plot/world/PlotAreaManager.java b/Core/src/main/java/com/plotsquared/core/plot/world/PlotAreaManager.java index b6d23b3d4..34033cb2b 100644 --- a/Core/src/main/java/com/plotsquared/core/plot/world/PlotAreaManager.java +++ b/Core/src/main/java/com/plotsquared/core/plot/world/PlotAreaManager.java @@ -29,6 +29,7 @@ import com.plotsquared.core.location.Location; import com.plotsquared.core.plot.PlotArea; import com.sk89q.worldedit.regions.CuboidRegion; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; public interface PlotAreaManager { @@ -44,7 +45,7 @@ public interface PlotAreaManager { * @param location The location * @return An applicable area, or null */ - PlotArea getApplicablePlotArea(Location location); + @Nullable PlotArea getApplicablePlotArea(Location location); /** * Get the plot area, if there is any, for the given diff --git a/Core/src/main/java/com/plotsquared/core/plot/world/ScatteredPlotWorld.java b/Core/src/main/java/com/plotsquared/core/plot/world/ScatteredPlotWorld.java new file mode 100644 index 000000000..40707a8e5 --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/plot/world/ScatteredPlotWorld.java @@ -0,0 +1,126 @@ +/* + * _____ _ _ _____ _ + * | __ \| | | | / ____| | | + * | |__) | | ___ | |_| (___ __ _ _ _ __ _ _ __ ___ __| | + * | ___/| |/ _ \| __|\___ \ / _` | | | |/ _` | '__/ _ \/ _` | + * | | | | (_) | |_ ____) | (_| | |_| | (_| | | | __/ (_| | + * |_| |_|\___/ \__|_____/ \__, |\__,_|\__,_|_| \___|\__,_| + * | | + * |_| + * PlotSquared plot management system for Minecraft + * Copyright (C) 2020 IntellectualSites + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.plotsquared.core.plot.world; + +import com.plotsquared.core.location.Location; +import com.plotsquared.core.plot.PlotArea; +import com.plotsquared.core.plot.PlotWorld; +import com.plotsquared.core.util.PlotAreaConverter; +import com.plotsquared.core.util.RegionUtil; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.regions.CuboidRegion; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.khelekore.prtree.MBR; +import org.khelekore.prtree.PRTree; +import org.khelekore.prtree.SimpleMBR; + +import java.util.Collection; +import java.util.Collections; +import java.util.LinkedList; +import java.util.List; + +/** + * Plot world that contains several plot areas (clusters) + */ +public class ScatteredPlotWorld extends PlotWorld { + + private static final PlotAreaConverter MBR_CONVERTER = new PlotAreaConverter(); + private static final int BRANCH_FACTOR = 30; + + private final List areas = new LinkedList<>(); + private final Object treeLock = new Object(); + private PRTree areaTree; + + /** + * Create a new plot world with a given world name + * + * @param world World name + */ + public ScatteredPlotWorld(@NotNull final String world) { + super(world); + } + + @Override @Nullable public PlotArea getArea(@NotNull final Location location) { + if (this.areas.isEmpty()) { + return null; + } + synchronized (this.treeLock) { + for (final PlotArea area : this.areaTree.find(location.toMBR())) { + if (area.contains(location)) { + return area; + } + } + } + return null; + } + + @Override @NotNull public Collection getAreas() { + return Collections.unmodifiableCollection(this.areas); + } + + @Override public void addArea(@NotNull final PlotArea area) { + this.areas.add(area); + this.buildTree(); + } + + @Override public void removeArea(@NotNull final PlotArea area) { + this.areas.remove(area); + this.buildTree(); + } + + @Override @NotNull public Collection getAreasInRegion(@NotNull final CuboidRegion region) { + if (this.areas.isEmpty()) { + return Collections.emptyList(); + } + synchronized (this.treeLock) { + final List areas = new LinkedList<>(); + + final BlockVector3 min = region.getMinimumPoint(); + final BlockVector3 max = region.getMaximumPoint(); + final MBR mbr = new SimpleMBR(min.getX(), max.getX(), min.getY(), max.getY(), min.getZ(), max.getZ()); + + for (final PlotArea area : this.areaTree.find(mbr)) { + if (RegionUtil.intersects(area.getRegion(), region)) { + areas.add(area); + } + } + + return areas; + } + } + + /** + * Rebuild the area tree + */ + private void buildTree() { + synchronized (this.treeLock) { + this.areaTree = new PRTree<>(MBR_CONVERTER, BRANCH_FACTOR); + this.areaTree.load(this.areas); + } + } + +} diff --git a/Core/src/main/java/com/plotsquared/core/plot/world/SinglePlotArea.java b/Core/src/main/java/com/plotsquared/core/plot/world/SinglePlotArea.java index da1613cee..a212a0506 100644 --- a/Core/src/main/java/com/plotsquared/core/plot/world/SinglePlotArea.java +++ b/Core/src/main/java/com/plotsquared/core/plot/world/SinglePlotArea.java @@ -38,8 +38,9 @@ import com.plotsquared.core.plot.PlotAreaType; import com.plotsquared.core.plot.PlotId; import com.plotsquared.core.plot.PlotManager; import com.plotsquared.core.plot.PlotSettings; -import com.plotsquared.core.plot.SetupObject; import com.plotsquared.core.plot.flag.FlagContainer; +import com.plotsquared.core.setup.PlotAreaBuilder; +import com.plotsquared.core.setup.SettingsNodesWrapper; import com.plotsquared.core.util.SetupUtils; import com.plotsquared.core.util.WorldUtil; import com.plotsquared.core.util.task.RunnableVal; @@ -78,13 +79,13 @@ public class SinglePlotArea extends GridPlotWorld { if (WorldUtil.IMP.isWorld(worldName)) { return; } - SetupObject setup = new SetupObject(); - setup.plotManager = "PlotSquared:single"; - setup.setupGenerator = "PlotSquared:single"; - setup.type = getType(); - setup.terrain = getTerrain(); - setup.step = new ConfigurationNode[0]; - setup.world = worldName; + PlotAreaBuilder builder = new PlotAreaBuilder() + .plotManager("PlotSquared:single") + .generatorName("PlotSquared:single") + .plotAreaType(getType()) + .terrainType(getTerrain()) + .settingsNodesWrapper(new SettingsNodesWrapper(new ConfigurationNode[0], null)) + .worldName(worldName); File container = PlotSquared.imp().getWorldContainer(); File destination = new File(container, worldName); @@ -96,7 +97,7 @@ public class SinglePlotArea extends GridPlotWorld { } } // Duplicate 0;0 - if (setup.type != PlotAreaType.NORMAL) { + if (builder.plotAreaType() != PlotAreaType.NORMAL) { if (!destination.exists()) { File src = new File(container, "0.0"); if (src.exists()) { @@ -132,7 +133,7 @@ public class SinglePlotArea extends GridPlotWorld { return; } - SetupUtils.manager.setupWorld(setup); + SetupUtils.manager.setupWorld(builder); } }); // String worldName = plot.getWorldName(); diff --git a/Core/src/main/java/com/plotsquared/core/plot/world/StandardPlotWorld.java b/Core/src/main/java/com/plotsquared/core/plot/world/StandardPlotWorld.java new file mode 100644 index 000000000..162cf0e9f --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/plot/world/StandardPlotWorld.java @@ -0,0 +1,65 @@ +/* + * _____ _ _ _____ _ + * | __ \| | | | / ____| | | + * | |__) | | ___ | |_| (___ __ _ _ _ __ _ _ __ ___ __| | + * | ___/| |/ _ \| __|\___ \ / _` | | | |/ _` | '__/ _ \/ _` | + * | | | | (_) | |_ ____) | (_| | |_| | (_| | | | __/ (_| | + * |_| |_|\___/ \__|_____/ \__, |\__,_|\__,_|_| \___|\__,_| + * | | + * |_| + * PlotSquared plot management system for Minecraft + * Copyright (C) 2020 IntellectualSites + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.plotsquared.core.plot.world; + +import com.plotsquared.core.location.Location; +import com.plotsquared.core.plot.PlotArea; +import com.plotsquared.core.plot.PlotWorld; +import com.sk89q.worldedit.regions.CuboidRegion; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Collection; +import java.util.Collections; + +/** + * Ordinary plot world with a single plot area + */ +public class StandardPlotWorld extends PlotWorld { + + private final PlotArea area; + + public StandardPlotWorld(@NotNull final String world, @Nullable final PlotArea area) { + super(world); + this.area = area; + } + + @Override @Nullable public PlotArea getArea(@NotNull final Location location) { + return this.area; + } + + @Override @NotNull public Collection getAreas() { + if (this.area == null) { + return Collections.emptyList(); + } + return Collections.singletonList(this.area); + } + + @Override @NotNull public Collection getAreasInRegion(@NotNull final CuboidRegion region) { + return this.getAreas(); + } + +} diff --git a/Core/src/main/java/com/plotsquared/core/queue/GlobalBlockQueue.java b/Core/src/main/java/com/plotsquared/core/queue/GlobalBlockQueue.java index 68a059583..3b63a94c0 100644 --- a/Core/src/main/java/com/plotsquared/core/queue/GlobalBlockQueue.java +++ b/Core/src/main/java/com/plotsquared/core/queue/GlobalBlockQueue.java @@ -44,8 +44,8 @@ public class GlobalBlockQueue { private final ConcurrentLinkedDeque inactiveQueues; private final ConcurrentLinkedDeque runnables; private final AtomicBoolean running; + private final int targetTime; private QueueProvider provider; - /** * Used to calculate elapsed time in milliseconds and ensure block placement doesn't lag the * server @@ -53,6 +53,7 @@ public class GlobalBlockQueue { private long last; private long secondLast; private long lastSuccess; + private double lastPeriod = 0; private final RunnableVal2 SET_TASK = new RunnableVal2() { @Override public void run(Long free, LocalBlockQueue queue) { @@ -65,17 +66,19 @@ public class GlobalBlockQueue { } return; } - } while (((GlobalBlockQueue.this.secondLast = System.currentTimeMillis()) - - GlobalBlockQueue.this.last) < free); + } while ((lastPeriod = + ((GlobalBlockQueue.this.secondLast = System.currentTimeMillis()) + - GlobalBlockQueue.this.last)) < free); } }; - public GlobalBlockQueue(QueueProvider provider, int threads) { + public GlobalBlockQueue(QueueProvider provider, int threads, int targetTime) { this.provider = provider; this.activeQueues = new ConcurrentLinkedDeque<>(); this.inactiveQueues = new ConcurrentLinkedDeque<>(); this.runnables = new ConcurrentLinkedDeque<>(); this.running = new AtomicBoolean(); + this.targetTime = targetTime; this.PARALLEL_THREADS = threads; } @@ -112,9 +115,15 @@ public class GlobalBlockQueue { @Override public void run() { if (inactiveQueues.isEmpty() && activeQueues.isEmpty()) { lastSuccess = System.currentTimeMillis(); + lastPeriod = 0; GlobalBlockQueue.this.runEmptyTasks(); return; } + // Server laggy? Skip. + if (lastPeriod > targetTime) { + lastPeriod -= targetTime; + return; + } SET_TASK.value1 = 50 + Math.min( (50 + GlobalBlockQueue.this.last) - (GlobalBlockQueue.this.last = System.currentTimeMillis()), diff --git a/Core/src/main/java/com/plotsquared/core/queue/LocalBlockQueue.java b/Core/src/main/java/com/plotsquared/core/queue/LocalBlockQueue.java index f979b4e9f..76fa5e28a 100644 --- a/Core/src/main/java/com/plotsquared/core/queue/LocalBlockQueue.java +++ b/Core/src/main/java/com/plotsquared/core/queue/LocalBlockQueue.java @@ -25,13 +25,13 @@ */ package com.plotsquared.core.queue; +import com.plotsquared.core.PlotSquared; import com.plotsquared.core.location.Location; import com.plotsquared.core.player.PlotPlayer; import com.plotsquared.core.util.PatternUtil; import com.plotsquared.core.util.SchematicHandler; import com.plotsquared.core.util.StringMan; import com.plotsquared.core.util.WorldUtil; -import com.plotsquared.core.util.uuid.UUIDHandler; import com.sk89q.jnbt.CompoundTag; import com.sk89q.worldedit.function.pattern.Pattern; import com.sk89q.worldedit.math.BlockVector2; @@ -43,8 +43,6 @@ import lombok.Setter; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.util.Map; - public abstract class LocalBlockQueue { @Getter @Setter private boolean forceSync = false; @@ -124,8 +122,8 @@ public abstract class LocalBlockQueue { regenChunk(x, z); fixChunkLighting(x, z); BlockVector2 loc = BlockVector2.at(x, z); - for (Map.Entry entry : UUIDHandler.getPlayers().entrySet()) { - PlotPlayer pp = entry.getValue(); + + for (final PlotPlayer pp : PlotSquared.imp().getPlayerManager().getPlayers()) { Location pLoc = pp.getLocation(); if (!StringMan.isEqual(getWorld(), pLoc.getWorld()) || !pLoc.getBlockVector2() .equals(loc)) { diff --git a/Core/src/main/java/com/plotsquared/core/setup/CommonSetupSteps.java b/Core/src/main/java/com/plotsquared/core/setup/CommonSetupSteps.java new file mode 100644 index 000000000..0a8c7ba9a --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/setup/CommonSetupSteps.java @@ -0,0 +1,288 @@ +/* + * _____ _ _ _____ _ + * | __ \| | | | / ____| | | + * | |__) | | ___ | |_| (___ __ _ _ _ __ _ _ __ ___ __| | + * | ___/| |/ _ \| __|\___ \ / _` | | | |/ _` | '__/ _ \/ _` | + * | | | | (_) | |_ ____) | (_| | |_| | (_| | | | __/ (_| | + * |_| |_|\___/ \__|_____/ \__, |\__,_|\__,_|_| \___|\__,_| + * | | + * |_| + * PlotSquared plot management system for Minecraft + * Copyright (C) 2020 IntellectualSites + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.plotsquared.core.setup; + +import com.plotsquared.core.PlotSquared; +import com.plotsquared.core.configuration.Caption; +import com.plotsquared.core.configuration.Captions; +import com.plotsquared.core.events.TeleportCause; +import com.plotsquared.core.generator.GeneratorWrapper; +import com.plotsquared.core.player.PlotPlayer; +import com.plotsquared.core.plot.PlotArea; +import com.plotsquared.core.plot.PlotAreaTerrainType; +import com.plotsquared.core.plot.PlotAreaType; +import com.plotsquared.core.plot.PlotId; +import com.plotsquared.core.util.MainUtil; +import com.plotsquared.core.util.SetupUtils; +import com.plotsquared.core.util.StringMan; +import com.plotsquared.core.util.WorldUtil; +import lombok.Getter; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.Optional; +import java.util.stream.Collectors; + +import static com.plotsquared.core.util.MainUtil.sendMessage; + +public enum CommonSetupSteps implements SetupStep { + CHOOSE_GENERATOR(Captions.SETUP_INIT) { + + @Override public SetupStep handleInput(PlotPlayer plotPlayer, PlotAreaBuilder builder, String arg) { + if (!SetupUtils.generators.containsKey(arg)) { + String prefix = "\n&8 - &7"; + sendMessage(plotPlayer, Captions.SETUP_WORLD_GENERATOR_ERROR + prefix + StringMan + .join(SetupUtils.generators.keySet(), prefix) + .replaceAll(PlotSquared.imp().getPluginName(), + "&2" + PlotSquared.imp().getPluginName())); + return this; // invalid input -> same setup step + } + builder.generatorName(arg); + return CommonSetupSteps.CHOOSE_PLOT_AREA_TYPE; // proceed with next step + } + + @NotNull @Override public Collection getSuggestions() { + return Collections.unmodifiableSet(SetupUtils.generators.keySet()); + } + + @Nullable @Override public String getDefaultValue() { + return PlotSquared.imp().getPluginName(); + } + }, + CHOOSE_PLOT_AREA_TYPE(PlotAreaType.class, Captions.SETUP_WORLD_TYPE) { + + @Override public SetupStep handleInput(PlotPlayer plotPlayer, PlotAreaBuilder builder, String arg) { + boolean withNormal = SetupUtils.generators.get(builder.generatorName()).isFull(); + Optional plotAreaType = PlotAreaType.fromString(arg); + if (!plotAreaType.isPresent()) { + MainUtil.sendMessage(plotPlayer, Captions.SETUP_WORLD_TYPE_ERROR); + PlotAreaType.getDescriptionMap().forEach((type, caption) -> { + if (!withNormal && type == PlotAreaType.NORMAL) { + return; // skip + } + String color = type == PlotAreaType.NORMAL ? "&2" : "&7"; + MainUtil.sendMessage(plotPlayer, "&8 - " + color + type + + " &8-&7 " + caption.getTranslated()); + }); + return this; + } + builder.plotAreaType(plotAreaType.get()); + GeneratorWrapper gen = SetupUtils.generators.get(builder.generatorName()); + if (builder.plotAreaType() == PlotAreaType.NORMAL) { + if (builder.settingsNodesWrapper() == null) { + builder.plotManager(builder.generatorName()); + builder.settingsNodesWrapper(CommonSetupSteps.wrap(builder.plotManager())); + SetupUtils.generators.get(builder.plotManager()).getPlotGenerator() + .processAreaSetup(builder); + } + return builder.settingsNodesWrapper().getFirstStep(); + } else { + if (gen.isFull()) { + builder.plotManager(builder.generatorName()); + builder.generatorName(null); + builder.settingsNodesWrapper(CommonSetupSteps.wrap(builder.plotManager())); + SetupUtils.generators.get(builder.plotManager()).getPlotGenerator() + .processAreaSetup(builder); + } else { + builder.plotManager(PlotSquared.imp().getPluginName()); + MainUtil.sendMessage(plotPlayer, Captions.SETUP_WRONG_GENERATOR); + builder.settingsNodesWrapper(CommonSetupSteps.wrap(builder.plotManager())); + // TODO why is processSetup not called here? + } + if (builder.plotAreaType() == PlotAreaType.PARTIAL) { + return CHOOSE_AREA_ID; + } else { + return CHOOSE_TERRAIN_TYPE; + } + } + } + + @Nullable @Override public String getDefaultValue() { + return PlotAreaType.NORMAL.toString(); + } + }, + CHOOSE_AREA_ID(Captions.SETUP_AREA_NAME) { + + @Override public SetupStep handleInput(PlotPlayer plotPlayer, PlotAreaBuilder builder, String argument) { + if (!StringMan.isAlphanumericUnd(argument)) { + MainUtil.sendMessage(plotPlayer, Captions.SETUP_AREA_NON_ALPHANUMERICAL); + return this; + } + for (PlotArea area : PlotSquared.get().getPlotAreas()) { + if (area.getId() != null && area.getId().equalsIgnoreCase(argument)) { + MainUtil.sendMessage(plotPlayer, Captions.SETUP_AREA_INVALID_ID); + return this; + } + } + builder.areaName(argument); + return CHOOSE_MINIMUM_PLOT_ID; + } + + @Nullable @Override public String getDefaultValue() { + return null; + } + }, + CHOOSE_MINIMUM_PLOT_ID(Captions.SETUP_AREA_MIN_PLOT_ID) { + + @Override public SetupStep handleInput(PlotPlayer plotPlayer, PlotAreaBuilder builder, String argument) { + try { + builder.minimumId(PlotId.fromString(argument)); + } catch (IllegalArgumentException ignored) { + MainUtil.sendMessage(plotPlayer, Captions.SETUP_AREA_MIN_PLOT_ID_ERROR); + return this; + } catch (IllegalStateException ignored) { + MainUtil.sendMessage(plotPlayer, Captions.SETUP_AREA_PLOT_ID_GREATER_THAN_MINIMUM); + return this; + } + return CHOOSE_MAXIMUM_PLOT_ID; + } + + @Override public String getDefaultValue() { + return "0;0"; + } + }, + CHOOSE_MAXIMUM_PLOT_ID(Captions.SETUP_AREA_MAX_PLOT_ID) { + + @Override public SetupStep handleInput(PlotPlayer plotPlayer, PlotAreaBuilder builder, String argument) { + try { + builder.maximumId(PlotId.fromString(argument)); + } catch (IllegalArgumentException ignored) { + MainUtil.sendMessage(plotPlayer, Captions.SETUP_AREA_MAX_PLOT_ID_ERROR); + return this; + } catch (IllegalStateException ignored) { + MainUtil.sendMessage(plotPlayer, Captions.SETUP_AREA_PLOT_ID_GREATER_THAN_MINIMUM); + return this; + } + return CHOOSE_TERRAIN_TYPE; + } + + @Override public String getDefaultValue() { + return "0;0"; + } + }, + CHOOSE_TERRAIN_TYPE(PlotAreaTerrainType.class, Captions.SETUP_PARTIAL_AREA) { + + @Override public SetupStep handleInput(PlotPlayer plotPlayer, PlotAreaBuilder builder, String argument) { + Optional optTerrain; + if (!(optTerrain = PlotAreaTerrainType.fromString(argument)) + .isPresent()) { + MainUtil.sendMessage(plotPlayer, Captions.SETUP_PARTIAL_AREA_ERROR, Captions.SETUP_PARTIAL_AREA); + return this; + } + builder.terrainType(optTerrain.get()); + if (builder.settingsNodesWrapper() == null) { + builder.settingsNodesWrapper(CommonSetupSteps.wrap(builder.plotManager())); + } + SettingsNodesWrapper wrapper = builder.settingsNodesWrapper(); + return wrapper.getFirstStep(); + } + + @Nullable @Override public String getDefaultValue() { + return PlotAreaTerrainType.NONE.toString(); + } + }, + CHOOSE_WORLD_NAME(Captions.SETUP_WORLD_NAME) { + + @Override public SetupStep handleInput(PlotPlayer plotPlayer, PlotAreaBuilder builder, String argument) { + if (!isValidWorldName(argument)) { + MainUtil.sendMessage(plotPlayer, Captions.SETUP_WORLD_NAME_FORMAT + argument); + return this; + } + if (WorldUtil.IMP.isWorld(argument)) { + if (PlotSquared.get().hasPlotArea(argument)) { + MainUtil.sendMessage(plotPlayer, Captions.SETUP_WORLD_NAME_TAKEN); + return this; + } + MainUtil.sendMessage(plotPlayer, Captions.SETUP_WORLD_APPLY_PLOTSQUARED); + } + builder.worldName(argument); + plotPlayer.deleteMeta("setup"); + String world; + if (builder.setupManager() == null) { + world = SetupUtils.manager.setupWorld(builder); + } else { + world = builder.setupManager().setupWorld(builder); + } + try { + plotPlayer.teleport(WorldUtil.IMP.getSpawn(world), TeleportCause.COMMAND); + } catch (Exception e) { + plotPlayer.sendMessage("&cAn error occurred. See console for more information"); + e.printStackTrace(); + } + sendMessage(plotPlayer, Captions.SETUP_FINISHED, builder.worldName()); + return null; + } + + @Nullable @Override public String getDefaultValue() { + return null; + } + }; + + @Getter @NotNull private final Collection suggestions; + private final Caption description; + + /** + * + * @param suggestions the input suggestions for this step + * @param description the caption describing this step + */ + CommonSetupSteps(@NotNull Collection suggestions, @NotNull Caption description) { + this.suggestions = suggestions; + this.description = description; + } + + CommonSetupSteps(@NotNull Caption description) { + this.description = description; + this.suggestions = Collections.emptyList(); + } + + > CommonSetupSteps(@NotNull Class argumentType, Caption description) { + this(enumToStrings(argumentType), description); + } + + @Override public void announce(PlotPlayer plotPlayer) { + MainUtil.sendMessage(plotPlayer, this.description); + } + + private static > Collection enumToStrings(Class type) { + return Arrays.stream(type.getEnumConstants()).map(e -> e.toString().toLowerCase()).collect(Collectors.toList()); + } + + private static SettingsNodesWrapper wrap(String plotManager) { + return new SettingsNodesWrapper(SetupUtils.generators.get(plotManager).getPlotGenerator() + .getNewPlotArea("CheckingPlotSquaredGenerator", null, null, null) + .getSettingNodes(), CHOOSE_WORLD_NAME); + } + + private static boolean isValidWorldName(String s) { + return s.chars().allMatch((i) -> { + return i == 95 || i == 45 || i >= 97 && i <= 122 || i >= 48 && i <= 57 || i == 46; + }); + } +} diff --git a/Core/src/main/java/com/plotsquared/core/setup/PlotAreaBuilder.java b/Core/src/main/java/com/plotsquared/core/setup/PlotAreaBuilder.java new file mode 100644 index 000000000..d59e2d8f0 --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/setup/PlotAreaBuilder.java @@ -0,0 +1,83 @@ +/* + * _____ _ _ _____ _ + * | __ \| | | | / ____| | | + * | |__) | | ___ | |_| (___ __ _ _ _ __ _ _ __ ___ __| | + * | ___/| |/ _ \| __|\___ \ / _` | | | |/ _` | '__/ _ \/ _` | + * | | | | (_) | |_ ____) | (_| | |_| | (_| | | | __/ (_| | + * |_| |_|\___/ \__|_____/ \__, |\__,_|\__,_|_| \___|\__,_| + * | | + * |_| + * PlotSquared plot management system for Minecraft + * Copyright (C) 2020 IntellectualSites + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.plotsquared.core.setup; + + +import com.plotsquared.core.PlotSquared; +import com.plotsquared.core.plot.PlotArea; +import com.plotsquared.core.plot.PlotAreaTerrainType; +import com.plotsquared.core.plot.PlotAreaType; +import com.plotsquared.core.plot.PlotId; +import com.plotsquared.core.util.SetupUtils; +import lombok.Getter; +import lombok.Setter; +import lombok.experimental.Accessors; + +@Accessors(fluent = true) +public class PlotAreaBuilder { + @Getter @Setter private String generatorName; + @Getter @Setter private String plotManager; + @Getter @Setter private PlotAreaType plotAreaType; + @Getter @Setter private PlotAreaTerrainType terrainType; + @Getter @Setter private String worldName; + @Getter @Setter private String areaName; + @Getter private PlotId minimumId; + @Getter private PlotId maximumId; + @Getter @Setter private SettingsNodesWrapper settingsNodesWrapper; + @Getter @Setter private SetupUtils setupManager; + + public static PlotAreaBuilder ofPlotArea(PlotArea area) { + return new PlotAreaBuilder() + .worldName(area.getWorldName()) + .areaName(area.getId()) + .plotAreaType(area.getType()) + .terrainType(area.getTerrain()) + .generatorName(area.getGenerator().getName()) + .plotManager(PlotSquared.imp().getPluginName()) + .minimumId(area.getMin()) + .maximumId(area.getMax()) + .settingsNodesWrapper(new SettingsNodesWrapper(area.getSettingNodes(), null)); + } + + public PlotAreaBuilder minimumId(PlotId minimumId) { + if (this.maximumId != null + && (minimumId.getX() > this.maximumId.getX() || minimumId.getY() > this.maximumId.getY())) { + throw new IllegalStateException("minId >= maxId"); + } + this.minimumId = minimumId; + return this; + } + + public PlotAreaBuilder maximumId(PlotId maximumId) { + if (this.minimumId != null + && (maximumId.getX() < this.minimumId.getX() || maximumId.getY() < this.minimumId.getY())) { + throw new IllegalStateException("maxId <= minId"); + } + this.maximumId = maximumId; + return this; + } + +} diff --git a/Core/src/main/java/com/plotsquared/core/setup/SettingsNodeStep.java b/Core/src/main/java/com/plotsquared/core/setup/SettingsNodeStep.java new file mode 100644 index 000000000..d216f067c --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/setup/SettingsNodeStep.java @@ -0,0 +1,95 @@ +/* + * _____ _ _ _____ _ + * | __ \| | | | / ____| | | + * | |__) | | ___ | |_| (___ __ _ _ _ __ _ _ __ ___ __| | + * | ___/| |/ _ \| __|\___ \ / _` | | | |/ _` | '__/ _ \/ _` | + * | | | | (_) | |_ ____) | (_| | |_| | (_| | | | __/ (_| | + * |_| |_|\___/ \__|_____/ \__, |\__,_|\__,_|_| \___|\__,_| + * | | + * |_| + * PlotSquared plot management system for Minecraft + * Copyright (C) 2020 IntellectualSites + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.plotsquared.core.setup; + +import com.plotsquared.core.command.Command; +import com.plotsquared.core.command.RequiredType; +import com.plotsquared.core.configuration.Captions; +import com.plotsquared.core.configuration.ConfigurationNode; +import com.plotsquared.core.player.PlotPlayer; +import com.plotsquared.core.util.MainUtil; +import com.plotsquared.core.util.TabCompletions; +import lombok.Getter; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Collection; +import java.util.Collections; + +/** + * A SettingsNodeStep is a step wrapping a {@link ConfigurationNode}. + */ +public class SettingsNodeStep implements SetupStep { + @Getter private final ConfigurationNode configurationNode; + @Getter private final int id; + private final SetupStep next; + + public SettingsNodeStep(ConfigurationNode configurationNode, int id, SettingsNodesWrapper wrapper) { + this.configurationNode = configurationNode; + this.id = id; + if (wrapper.getSettingsNodes().length > id + 1) { + this.next = new SettingsNodeStep(wrapper.getSettingsNodes()[id + 1], id + 1, wrapper); + } else { + this.next = wrapper.getAfterwards(); + } + } + + @Override public SetupStep handleInput(PlotPlayer plotPlayer, PlotAreaBuilder builder, String argument) { + if (this.configurationNode.isValid(argument)) { + this.configurationNode.setValue(argument); + } + return this.next; + } + + @NotNull @Override public Collection getSuggestions() { + return this.configurationNode.getSuggestions(); + } + + @Nullable @Override public String getDefaultValue() { + return String.valueOf(this.configurationNode.getDefaultValue()); + } + + @Override public void announce(PlotPlayer plotPlayer) { + MainUtil.sendMessage(plotPlayer, Captions.SETUP_STEP, this.getId() + 1, + this.configurationNode.getDescription(), this.configurationNode.getType().getType(), + String.valueOf(this.configurationNode.getDefaultValue())); + } + + @Override public Collection createSuggestions(PlotPlayer plotPlayer, String argument) { + switch (this.configurationNode.getType().getType()) { + case "BLOCK_BUCKET": + return TabCompletions.completePatterns(argument); + case "INTEGER": + if (getDefaultValue() != null && getDefaultValue().startsWith(argument)) { + return Collections.singletonList(new Command(null, false, + getDefaultValue(), "", RequiredType.NONE, null) {}); + } + case "BOOLEAN": + return TabCompletions.completeBoolean(argument); + } + return Collections.emptyList(); + } +} diff --git a/Core/src/main/java/com/plotsquared/core/setup/SettingsNodesWrapper.java b/Core/src/main/java/com/plotsquared/core/setup/SettingsNodesWrapper.java new file mode 100644 index 000000000..153ec7d86 --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/setup/SettingsNodesWrapper.java @@ -0,0 +1,52 @@ +/* + * _____ _ _ _____ _ + * | __ \| | | | / ____| | | + * | |__) | | ___ | |_| (___ __ _ _ _ __ _ _ __ ___ __| | + * | ___/| |/ _ \| __|\___ \ / _` | | | |/ _` | '__/ _ \/ _` | + * | | | | (_) | |_ ____) | (_| | |_| | (_| | | | __/ (_| | + * |_| |_|\___/ \__|_____/ \__, |\__,_|\__,_|_| \___|\__,_| + * | | + * |_| + * PlotSquared plot management system for Minecraft + * Copyright (C) 2020 IntellectualSites + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.plotsquared.core.setup; + +import com.plotsquared.core.configuration.ConfigurationNode; +import lombok.Getter; + +/** + * This class wraps an array of {@link ConfigurationNode}s. + */ +public class SettingsNodesWrapper { + @Getter private final ConfigurationNode[] settingsNodes; + @Getter private final SetupStep afterwards; + + public SettingsNodesWrapper(ConfigurationNode[] settingsNodes, SetupStep afterwards) { + this.settingsNodes = settingsNodes; + this.afterwards = afterwards; + } + + /** + * Returns the first step of this wrapper or the step or the + * {@code afterwards} step if no step is available. + * + * @return the first step or {@code afterwards}. + */ + public SetupStep getFirstStep() { + return this.settingsNodes.length == 0 ? this.afterwards : new SettingsNodeStep(this.settingsNodes[0], 0, this); + } +} diff --git a/Core/src/main/java/com/plotsquared/core/setup/SetupProcess.java b/Core/src/main/java/com/plotsquared/core/setup/SetupProcess.java new file mode 100644 index 000000000..7af19aefb --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/setup/SetupProcess.java @@ -0,0 +1,66 @@ +/* + * _____ _ _ _____ _ + * | __ \| | | | / ____| | | + * | |__) | | ___ | |_| (___ __ _ _ _ __ _ _ __ ___ __| | + * | ___/| |/ _ \| __|\___ \ / _` | | | |/ _` | '__/ _ \/ _` | + * | | | | (_) | |_ ____) | (_| | |_| | (_| | | | __/ (_| | + * |_| |_|\___/ \__|_____/ \__, |\__,_|\__,_|_| \___|\__,_| + * | | + * |_| + * PlotSquared plot management system for Minecraft + * Copyright (C) 2020 IntellectualSites + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.plotsquared.core.setup; + +import com.plotsquared.core.player.PlotPlayer; + +import java.util.Stack; + +/** + * This class keeps track of a setup process. + * It holds the history and the current setup state. + */ +public class SetupProcess { + private final PlotAreaBuilder builder; + private final Stack history; + private SetupStep current; + + public SetupProcess() { + this.builder = new PlotAreaBuilder(); + this.history = new Stack<>(); + this.current = CommonSetupSteps.CHOOSE_GENERATOR; + } + + public SetupStep getCurrentStep() { + return this.current; + } + + public void handleInput(PlotPlayer plotPlayer, String argument) { + SetupStep previous = this.current; + this.current = this.current.handleInput(plotPlayer, this.builder, argument); + // push previous step into history + if (this.current != previous && this.current != null) { + this.history.push(previous); + } + } + + public void back() { + if (!this.history.isEmpty()) { + this.current.onBack(this.builder); + this.current = this.history.pop(); + } + } +} diff --git a/Core/src/main/java/com/plotsquared/core/setup/SetupStep.java b/Core/src/main/java/com/plotsquared/core/setup/SetupStep.java new file mode 100644 index 000000000..5befafc81 --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/setup/SetupStep.java @@ -0,0 +1,86 @@ +/* + * _____ _ _ _____ _ + * | __ \| | | | / ____| | | + * | |__) | | ___ | |_| (___ __ _ _ _ __ _ _ __ ___ __| | + * | ___/| |/ _ \| __|\___ \ / _` | | | |/ _` | '__/ _ \/ _` | + * | | | | (_) | |_ ____) | (_| | |_| | (_| | | | __/ (_| | + * |_| |_|\___/ \__|_____/ \__, |\__,_|\__,_|_| \___|\__,_| + * | | + * |_| + * PlotSquared plot management system for Minecraft + * Copyright (C) 2020 IntellectualSites + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.plotsquared.core.setup; + +import com.plotsquared.core.command.Command; +import com.plotsquared.core.command.RequiredType; +import com.plotsquared.core.player.PlotPlayer; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +public interface SetupStep { + + /** + * Handles the input for this setup step. + * + * @param plotPlayer the plot player executing the command + * @param builder the plot area builder to work on + * @param argument the argument given as input + * @return the next step if input was valid, this setup step otherwise + */ + SetupStep handleInput(final PlotPlayer plotPlayer, PlotAreaBuilder builder, String argument); + + @NotNull Collection getSuggestions(); + + @Nullable String getDefaultValue(); + + /** + * Announces this step to the player. + * + * @param plotPlayer the player to announce this step to. + */ + void announce(PlotPlayer plotPlayer); + + /** + * Creates a collection of suggestions for the current input. + * + * @param plotPlayer the player to receive the suggestions. + * @param argument the argument already typed. + * @return a collection of suggestions. + */ + default Collection createSuggestions(final PlotPlayer plotPlayer, String argument) { + List result = new ArrayList<>(getSuggestions().size()); + for (String suggestion : getSuggestions()) { + if (suggestion.startsWith(argument)) { + result.add(new Command(null, false, suggestion, "", RequiredType.NONE, null) {}); + } + } + return result; + } + + /** + * This method is called when the SetupProcess reverts to a previous step. + * + * @param builder the builder associated with the setup process. + */ + default void onBack(PlotAreaBuilder builder) { + + } +} diff --git a/Core/src/main/java/com/plotsquared/core/util/ChunkManager.java b/Core/src/main/java/com/plotsquared/core/util/ChunkManager.java index 7bbea34d1..3e052737a 100644 --- a/Core/src/main/java/com/plotsquared/core/util/ChunkManager.java +++ b/Core/src/main/java/com/plotsquared/core/util/ChunkManager.java @@ -52,7 +52,7 @@ public abstract class ChunkManager { public static void setChunkInPlotArea(RunnableVal force, RunnableVal add, String world, BlockVector2 loc) { LocalBlockQueue queue = GlobalBlockQueue.IMP.getNewQueue(world, false); - if (PlotSquared.get().isAugmented(world)) { + if (PlotSquared.get().isAugmented(world) && PlotSquared.get().isNonStandardGeneration(world, loc)) { int blockX = loc.getX() << 4; int blockZ = loc.getZ() << 4; ScopedLocalBlockQueue scoped = diff --git a/Core/src/main/java/com/plotsquared/core/util/EconHandler.java b/Core/src/main/java/com/plotsquared/core/util/EconHandler.java index 15180e68e..a593e0cb0 100644 --- a/Core/src/main/java/com/plotsquared/core/util/EconHandler.java +++ b/Core/src/main/java/com/plotsquared/core/util/EconHandler.java @@ -25,42 +25,67 @@ */ package com.plotsquared.core.util; +import com.plotsquared.core.IPlotMain; import com.plotsquared.core.PlotSquared; import com.plotsquared.core.player.ConsolePlayer; import com.plotsquared.core.player.OfflinePlotPlayer; import com.plotsquared.core.player.PlotPlayer; +import org.jetbrains.annotations.Nullable; public abstract class EconHandler { - public static EconHandler manager; - private static boolean initialized; + /** + * @deprecated This will be removed in the future, + * call {@link IPlotMain#getEconomyHandler()} instead. + */ + @Deprecated @Nullable public static EconHandler manager; - public static EconHandler getEconHandler() { - if (initialized) { - return manager; - } - initialized = true; - return manager = PlotSquared.get().IMP.getEconomyHandler(); + /** + * Initialize the economy handler using {@link IPlotMain#getEconomyHandler()} + * @deprecated Call {@link #init} instead or use {@link IPlotMain#getEconomyHandler()} + * which does this already. + */ + @Deprecated public static void initializeEconHandler() { + manager = PlotSquared.get().IMP.getEconomyHandler(); } - public double getMoney(PlotPlayer player) { + /** + * Return the econ handler instance, if one exists + * + * @return Economy handler instance + * @deprecated Call {@link IPlotMain#getEconomyHandler()} instead + */ + @Deprecated @Nullable public static EconHandler getEconHandler() { + manager = PlotSquared.get().IMP.getEconomyHandler(); + return manager; + } + + public abstract boolean init(); + + public double getMoney(PlotPlayer player) { if (player instanceof ConsolePlayer) { return Double.MAX_VALUE; } return getBalance(player); } - public abstract double getBalance(PlotPlayer player); + public abstract double getBalance(PlotPlayer player); - public abstract void withdrawMoney(PlotPlayer player, double amount); + public abstract void withdrawMoney(PlotPlayer player, double amount); - public abstract void depositMoney(PlotPlayer player, double amount); + public abstract void depositMoney(PlotPlayer player, double amount); public abstract void depositMoney(OfflinePlotPlayer player, double amount); - public abstract boolean hasPermission(String world, String player, String perm); + /** + * @deprecated Use {@link PermHandler#hasPermission(String, String, String)} instead + */ + @Deprecated public abstract boolean hasPermission(String world, String player, String perm); - public boolean hasPermission(String player, String perm) { + /** + * @deprecated Use {@link PermHandler#hasPermission(String, String)} instead + */ + @Deprecated public boolean hasPermission(String player, String perm) { return hasPermission(null, player, perm); } } diff --git a/Core/src/main/java/com/plotsquared/core/util/EntityUtil.java b/Core/src/main/java/com/plotsquared/core/util/EntityUtil.java index 91eb4e99d..9bbc4e1aa 100644 --- a/Core/src/main/java/com/plotsquared/core/util/EntityUtil.java +++ b/Core/src/main/java/com/plotsquared/core/util/EntityUtil.java @@ -90,6 +90,7 @@ public final class EntityUtil { if (mobs[i] >= cap) { plot.setMeta("EntityCount", mobs); plot.setMeta("EntityCountTime", System.currentTimeMillis()); + plot.debug("Prevented spawning of mob because it would exceed " + flag.getName()); return true; } } diff --git a/Core/src/main/java/com/plotsquared/core/util/MainUtil.java b/Core/src/main/java/com/plotsquared/core/util/MainUtil.java index 93cb7b3e4..9e2a78853 100644 --- a/Core/src/main/java/com/plotsquared/core/util/MainUtil.java +++ b/Core/src/main/java/com/plotsquared/core/util/MainUtil.java @@ -49,12 +49,13 @@ import com.plotsquared.core.plot.flag.types.DoubleFlag; import com.plotsquared.core.util.net.AbstractDelegateOutputStream; import com.plotsquared.core.util.task.RunnableVal; import com.plotsquared.core.util.task.TaskManager; -import com.plotsquared.core.util.uuid.UUIDHandler; +import com.plotsquared.core.uuid.UUIDMapping; import com.sk89q.worldedit.math.BlockVector2; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.regions.CuboidRegion; import com.sk89q.worldedit.world.biome.BiomeType; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.io.File; import java.io.IOException; @@ -73,6 +74,7 @@ import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; +import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Map.Entry; @@ -81,6 +83,8 @@ import java.util.Optional; import java.util.Scanner; import java.util.Set; import java.util.UUID; +import java.util.concurrent.TimeUnit; +import java.util.function.BiConsumer; import java.util.function.Function; import java.util.function.IntConsumer; import java.util.function.IntFunction; @@ -99,12 +103,6 @@ public class MainUtil { FLAG_DECIMAL_FORMAT.setMaximumFractionDigits(340); } - /** - * If the NMS code for sending chunk updates is functional
- * - E.g. If using an older version of Bukkit, or before the plugin is updated to 1.5
- * - Slower fallback code will be used if not.
- */ - public static boolean canSendChunk = false; /** * Cache of mapping x,y,z coordinates to the chunk array
* - Used for efficient world generation
@@ -152,15 +150,6 @@ public class MainUtil { } } - public static void sendAdmin(final String s) { - for (final PlotPlayer player : UUIDHandler.getPlayers().values()) { - if (player.hasPermission(Captions.PERMISSION_ADMIN.getTranslated())) { - player.sendMessage(Captions.color(s)); - } - } - PlotSquared.debug(s); - } - public static void upload(UUID uuid, String file, String extension, final RunnableVal writeTask, final RunnableVal whenDone) { if (writeTask == null) { @@ -396,7 +385,7 @@ public class MainUtil { if (owner.equals(DBFunc.SERVER)) { return Captions.SERVER.getTranslated(); } - String name = UUIDHandler.getName(owner); + String name = PlotSquared.get().getImpromptuUUIDPipeline().getSingle(owner, Settings.UUID.BLOCKING_TIMEOUT); if (name == null) { return Captions.UNKNOWN.getTranslated(); } @@ -467,7 +456,7 @@ public class MainUtil { for (String term : split) { try { - UUID uuid = UUIDHandler.getUUID(term, null); + UUID uuid = PlotSquared.get().getImpromptuUUIDPipeline().getSingle(term, Settings.UUID.BLOCKING_TIMEOUT); if (uuid == null) { uuid = UUID.fromString(term); } @@ -527,7 +516,7 @@ public class MainUtil { * @param message If a message should be sent to the player if a plot cannot be found * @return The plot if only 1 result is found, or null */ - public static Plot getPlotFromString(PlotPlayer player, String arg, boolean message) { + @Nullable public static Plot getPlotFromString(PlotPlayer player, String arg, boolean message) { if (arg == null) { if (player == null) { if (message) { @@ -738,33 +727,45 @@ public class MainUtil { return ratings; } - public static Set getUUIDsFromString(String list) { + public static void getUUIDsFromString(final String list, final BiConsumer, Throwable> consumer) { String[] split = list.split(","); - HashSet result = new HashSet<>(); - for (String name : split) { + + final Set result = new HashSet<>(); + final List request = new LinkedList<>(); + + for (final String name : split) { if (name.isEmpty()) { - // Invalid - return Collections.emptySet(); - } - if ("*".equals(name)) { + consumer.accept(Collections.emptySet(), null); + return; + } else if ("*".equals(name)) { result.add(DBFunc.EVERYONE); - continue; - } - if (name.length() > 16) { + } else if (name.length() > 16) { try { result.add(UUID.fromString(name)); - continue; } catch (IllegalArgumentException ignored) { - return Collections.emptySet(); + consumer.accept(Collections.emptySet(), null); + return; } + } else { + request.add(name); } - UUID uuid = UUIDHandler.getUUID(name, null); - if (uuid == null) { - return Collections.emptySet(); - } - result.add(uuid); } - return result; + + if (request.isEmpty()) { + consumer.accept(result, null); + } else { + PlotSquared.get().getImpromptuUUIDPipeline().getUUIDs(request, Settings.UUID.NON_BLOCKING_TIMEOUT) + .whenComplete((uuids, throwable) -> { + if (throwable != null) { + consumer.accept(null, throwable); + } else { + for (final UUIDMapping uuid : uuids) { + result.add(uuid.getUuid()); + } + consumer.accept(result, null); + } + }); + } } /** @@ -903,24 +904,61 @@ public class MainUtil { return (directory.delete()); } - /** - * Get a list of names given a list of uuids.
- * - Uses the format {@link Captions#PLOT_USER_LIST} for the returned string - * - * @param uuids - * @return - */ - public static String getPlayerList(Collection uuids) { - ArrayList l = new ArrayList<>(uuids); - if (l.size() < 1) { + /* + @NotNull public static String getName(UUID owner) { + if (owner == null) { return Captions.NONE.getTranslated(); } - List users = - l.stream().map(MainUtil::getName).sorted().collect(Collectors.toList()); + if (owner.equals(DBFunc.EVERYONE)) { + return Captions.EVERYONE.getTranslated(); + } + if (owner.equals(DBFunc.SERVER)) { + return Captions.SERVER.getTranslated(); + } + String name = PlotSquared.get().getImpromptuUUIDPipeline().getSingle(owner, Settings.UUID.BLOCKING_TIMEOUT); + if (name == null) { + return Captions.UNKNOWN.getTranslated(); + } + return name; + } + */ + + /** + * Get a list of names given a list of UUIDs. + * - Uses the format {@link Captions#PLOT_USER_LIST} for the returned string + */ + public static String getPlayerList(final Collection uuids) { + if (uuids.size() < 1) { + return Captions.NONE.getTranslated(); + } + + final List players = new LinkedList<>(); + final List users = new LinkedList<>(); + for (final UUID uuid : uuids) { + if (uuid == null) { + users.add(Captions.NONE.getTranslated()); + } else if (DBFunc.EVERYONE.equals(uuid)) { + users.add(Captions.EVERYONE.getTranslated()); + } else if (DBFunc.SERVER.equals(uuid)) { + users.add(Captions.SERVER.getTranslated()); + } else { + players.add(uuid); + } + } + + try { + for (final UUIDMapping mapping : PlotSquared.get().getImpromptuUUIDPipeline().getNames(players).get(Settings.UUID.BLOCKING_TIMEOUT, + TimeUnit.MILLISECONDS)) { + users.add(mapping.getUsername()); + } + } catch (final Exception e) { + e.printStackTrace(); + } + String c = Captions.PLOT_USER_LIST.getTranslated(); StringBuilder list = new StringBuilder(); for (int x = 0; x < users.size(); x++) { - if (x + 1 == l.size()) { + if (x + 1 == uuids.size()) { list.append(c.replace("%user%", users.get(x)).replace(",", "")); } else { list.append(c.replace("%user%", users.get(x))); @@ -931,7 +969,7 @@ public class MainUtil { public static void getPersistentMeta(UUID uuid, final String key, final RunnableVal result) { - PlotPlayer player = UUIDHandler.getPlayer(uuid); + PlotPlayer player = PlotSquared.imp().getPlayerManager().getPlayerIfExists(uuid); if (player != null) { result.run(player.getPersistentMeta(key)); } else { diff --git a/Core/src/main/java/com/plotsquared/core/util/PatternUtil.java b/Core/src/main/java/com/plotsquared/core/util/PatternUtil.java index ee390cc04..c8d18c136 100644 --- a/Core/src/main/java/com/plotsquared/core/util/PatternUtil.java +++ b/Core/src/main/java/com/plotsquared/core/util/PatternUtil.java @@ -62,7 +62,7 @@ public class PatternUtil { return parse(plotPlayer, input, true); } - public static List getSuggestions(PlotPlayer plotPlayer, String input) { + public static List getSuggestions(String input) { try { return WorldEdit.getInstance().getPatternFactory().getSuggestions(input); } catch (final Exception ignored) { diff --git a/Core/src/main/java/com/plotsquared/core/util/PermHandler.java b/Core/src/main/java/com/plotsquared/core/util/PermHandler.java new file mode 100644 index 000000000..1dec45fd4 --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/util/PermHandler.java @@ -0,0 +1,37 @@ +/* + * _____ _ _ _____ _ + * | __ \| | | | / ____| | | + * | |__) | | ___ | |_| (___ __ _ _ _ __ _ _ __ ___ __| | + * | ___/| |/ _ \| __|\___ \ / _` | | | |/ _` | '__/ _ \/ _` | + * | | | | (_) | |_ ____) | (_| | |_| | (_| | | | __/ (_| | + * |_| |_|\___/ \__|_____/ \__, |\__,_|\__,_|_| \___|\__,_| + * | | + * |_| + * PlotSquared plot management system for Minecraft + * Copyright (C) 2020 IntellectualSites + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.plotsquared.core.util; + +public abstract class PermHandler { + + public abstract boolean init(); + + public abstract boolean hasPermission(String world, String player, String perm); + + public boolean hasPermission(String player, String perm) { + return hasPermission(null, player, perm); + } +} diff --git a/Core/src/main/java/com/plotsquared/core/util/Permissions.java b/Core/src/main/java/com/plotsquared/core/util/Permissions.java index 186439fc9..34754e7c8 100644 --- a/Core/src/main/java/com/plotsquared/core/util/Permissions.java +++ b/Core/src/main/java/com/plotsquared/core/util/Permissions.java @@ -61,7 +61,7 @@ public class Permissions { * @param permission * @return */ - public static boolean hasPermission(PlotPlayer player, String permission) { + public static boolean hasPermission(PlotPlayer player, String permission) { if (!Settings.Enabled_Components.PERMISSION_CACHE) { return hasPermission((CommandCaller) player, permission); } diff --git a/Core/src/main/java/com/plotsquared/core/util/PlatformWorldManager.java b/Core/src/main/java/com/plotsquared/core/util/PlatformWorldManager.java index f57e42a21..c304ff04c 100644 --- a/Core/src/main/java/com/plotsquared/core/util/PlatformWorldManager.java +++ b/Core/src/main/java/com/plotsquared/core/util/PlatformWorldManager.java @@ -28,6 +28,8 @@ package com.plotsquared.core.util; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.util.Collection; + /** * This class should be implemented by each platform to allow PlotSquared to interact * with the world management solution used on the server. @@ -62,4 +64,11 @@ public interface PlatformWorldManager { */ String getName(); + /** + * Get the names of all worlds on the server + * + * @return Worlds + */ + Collection getWorlds(); + } diff --git a/Core/src/main/java/com/plotsquared/core/util/PlayerManager.java b/Core/src/main/java/com/plotsquared/core/util/PlayerManager.java new file mode 100644 index 000000000..8c4ec1bea --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/util/PlayerManager.java @@ -0,0 +1,164 @@ +/* + * _____ _ _ _____ _ + * | __ \| | | | / ____| | | + * | |__) | | ___ | |_| (___ __ _ _ _ __ _ _ __ ___ __| | + * | ___/| |/ _ \| __|\___ \ / _` | | | |/ _` | '__/ _ \/ _` | + * | | | | (_) | |_ ____) | (_| | |_| | (_| | | | __/ (_| | + * |_| |_|\___/ \__|_____/ \__, |\__,_|\__,_|_| \___|\__,_| + * | | + * |_| + * PlotSquared plot management system for Minecraft + * Copyright (C) 2020 IntellectualSites + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.plotsquared.core.util; + +import com.plotsquared.core.player.OfflinePlotPlayer; +import com.plotsquared.core.player.PlotPlayer; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + +/** + * Manages player instances + */ +public abstract class PlayerManager

, T> { + + private final Map playerMap = new HashMap<>(); + private final Object playerLock = new Object(); + + /** + * Remove a player from the player map + * + * @param plotPlayer Player to remove + */ + public void removePlayer(@NotNull final PlotPlayer plotPlayer) { + synchronized (playerLock) { + this.playerMap.remove(plotPlayer.getUUID()); + } + } + + /** + * Remove a player from the player map + * + * @param uuid Player to remove + */ + public void removePlayer(@NotNull final UUID uuid) { + synchronized (playerLock) { + this.playerMap.remove(uuid); + } + } + + /** + * Get the player from its UUID if it is stored in the player map. + * + * @param uuid Player UUID + * @return Player, or null + */ + @Nullable public P getPlayerIfExists(@Nullable final UUID uuid) { + if (uuid == null) { + return null; + } + return this.playerMap.get(uuid); + } + + @Nullable public P getPlayerIfExists(@Nullable final String name) { + for (final P plotPlayer : this.playerMap.values()) { + if (plotPlayer.getName().equalsIgnoreCase(name)) { + return plotPlayer; + } + } + return null; + } + + /** + * Get a plot player from a platform player object. This method requires + * that the caller actually knows that the player exists. + *

+ * The method will throw an exception if there is no such + * player online. + * + * @param object Platform player object + * @return Player object + */ + @NotNull public abstract P getPlayer(@NotNull final T object); + + /** + * Get a plot player from a UUID. This method requires + * that the caller actually knows that the player exists. + *

+ * The method will throw an exception if there is no such + * player online. + * + * @param uuid Player UUID + * @return Player object + */ + @NotNull public P getPlayer(@NotNull final UUID uuid) { + synchronized (playerLock) { + P player = this.playerMap.get(uuid); + if (player == null) { + player = createPlayer(uuid); + this.playerMap.put(uuid, player); + } + return player; + } + } + + @NotNull public abstract P createPlayer(@NotNull final UUID uuid); + + /** + * Get an an offline player object from the player's UUID + * + * @param uuid Player UUID + * @return Offline player object + */ + @Nullable public abstract OfflinePlotPlayer getOfflinePlayer(@Nullable final UUID uuid); + + /** + * Get an offline player object from the player's username + * + * @param username Player name + * @return Offline player object + */ + @Nullable public abstract OfflinePlotPlayer getOfflinePlayer(@NotNull final String username); + + /** + * Get all online players + * + * @return Unmodifiable collection of players + */ + public Collection

getPlayers() { + return Collections.unmodifiableCollection(new ArrayList<>(this.playerMap.values())); + } + + + public static final class NoSuchPlayerException extends IllegalArgumentException { + + public NoSuchPlayerException(@NotNull final UUID uuid) { + super(String.format("There is no online player with UUID '%s'", uuid.toString())); + } + + @Override public synchronized Throwable fillInStackTrace() { + return this; + } + } + +} diff --git a/Core/src/main/java/com/plotsquared/core/util/PlotAreaConverter.java b/Core/src/main/java/com/plotsquared/core/util/PlotAreaConverter.java new file mode 100644 index 000000000..b80195c02 --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/util/PlotAreaConverter.java @@ -0,0 +1,68 @@ +/* + * _____ _ _ _____ _ + * | __ \| | | | / ____| | | + * | |__) | | ___ | |_| (___ __ _ _ _ __ _ _ __ ___ __| | + * | ___/| |/ _ \| __|\___ \ / _` | | | |/ _` | '__/ _ \/ _` | + * | | | | (_) | |_ ____) | (_| | |_| | (_| | | | __/ (_| | + * |_| |_|\___/ \__|_____/ \__, |\__,_|\__,_|_| \___|\__,_| + * | | + * |_| + * PlotSquared plot management system for Minecraft + * Copyright (C) 2020 IntellectualSites + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.plotsquared.core.util; + +import com.plotsquared.core.plot.PlotArea; +import com.sk89q.worldedit.regions.CuboidRegion; +import org.khelekore.prtree.MBRConverter; + +public class PlotAreaConverter implements MBRConverter { + + public static final int AXIS_X = 0; + public static final int AXIS_Y = 1; + public static final int AXIS_Z = 2; + + @Override public int getDimensions() { + return 3; + } + + @Override public double getMin(final int axis, final PlotArea area) { + final CuboidRegion region = area.getRegion(); + if (axis == AXIS_X) { + return region.getMinimumPoint().getX(); + } else if (axis == AXIS_Y) { + return region.getMinimumPoint().getY(); + } else if (axis == AXIS_Z) { + return region.getMinimumPoint().getZ(); + } else { + throw new IllegalArgumentException("Unknown axis: " + axis); + } + } + + @Override public double getMax(final int axis, final PlotArea area) { + final CuboidRegion region = area.getRegion(); + if (axis == AXIS_X) { + return region.getMaximumPoint().getX(); + } else if (axis == AXIS_Y) { + return region.getMaximumPoint().getY(); + } else if (axis == AXIS_Z) { + return region.getMaximumPoint().getZ(); + } else { + throw new IllegalArgumentException("Unknown axis: " + axis); + } + } + +} diff --git a/Core/src/main/java/com/plotsquared/core/util/RegionManager.java b/Core/src/main/java/com/plotsquared/core/util/RegionManager.java index 5ab1a8350..ab3333a19 100644 --- a/Core/src/main/java/com/plotsquared/core/util/RegionManager.java +++ b/Core/src/main/java/com/plotsquared/core/util/RegionManager.java @@ -28,8 +28,11 @@ package com.plotsquared.core.util; import com.plotsquared.core.PlotSquared; import com.plotsquared.core.location.Location; import com.plotsquared.core.plot.Plot; +import com.plotsquared.core.plot.PlotArea; +import com.plotsquared.core.queue.LocalBlockQueue; import com.plotsquared.core.util.task.RunnableVal; import com.plotsquared.core.util.task.TaskManager; +import com.sk89q.worldedit.function.pattern.Pattern; import com.sk89q.worldedit.math.BlockVector2; import com.sk89q.worldedit.regions.CuboidRegion; import com.sk89q.worldedit.world.biome.BiomeType; @@ -147,6 +150,19 @@ public abstract class RegionManager { }); } + public boolean setCuboids(final PlotArea area, final Set regions, + final Pattern blocks, int minY, int maxY) { + LocalBlockQueue queue = area.getQueue(false); + for (CuboidRegion region : regions) { + Location pos1 = new Location(area.getWorldName(), region.getMinimumPoint().getX(), minY, + region.getMinimumPoint().getZ()); + Location pos2 = new Location(area.getWorldName(), region.getMaximumPoint().getX(), maxY, + region.getMaximumPoint().getZ()); + queue.setCuboid(pos1, pos2, blocks); + } + return queue.enqueue(); + } + /** * Copy a region to a new location (in the same world) */ diff --git a/Core/src/main/java/com/plotsquared/core/util/RegionUtil.java b/Core/src/main/java/com/plotsquared/core/util/RegionUtil.java index fe4d83a96..6c16c4a9e 100644 --- a/Core/src/main/java/com/plotsquared/core/util/RegionUtil.java +++ b/Core/src/main/java/com/plotsquared/core/util/RegionUtil.java @@ -26,8 +26,12 @@ package com.plotsquared.core.util; import com.plotsquared.core.plot.Plot; +import com.sk89q.worldedit.math.BlockVector2; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.regions.CuboidRegion; +import org.jetbrains.annotations.NotNull; + +import java.awt.geom.Rectangle2D; public class RegionUtil { public static CuboidRegion createRegion(int pos1x, int pos2x, int pos1z, int pos2z) { @@ -54,6 +58,12 @@ public class RegionUtil { .getY() && y <= max.getY(); } + @NotNull public static Rectangle2D toRectangle(@NotNull final CuboidRegion region) { + final BlockVector2 min = region.getMinimumPoint().toBlockVector2(); + final BlockVector2 max = region.getMaximumPoint().toBlockVector2(); + return new Rectangle2D.Double(min.getX(), min.getZ(), max.getX(), max.getZ()); + } + // Because WE (not fawe) lack this for CuboidRegion public static boolean intersects(CuboidRegion region, CuboidRegion other) { BlockVector3 regionMin = region.getMinimumPoint(); diff --git a/Core/src/main/java/com/plotsquared/core/util/SchematicHandler.java b/Core/src/main/java/com/plotsquared/core/util/SchematicHandler.java index 850cef3e0..92b1b2ef4 100644 --- a/Core/src/main/java/com/plotsquared/core/util/SchematicHandler.java +++ b/Core/src/main/java/com/plotsquared/core/util/SchematicHandler.java @@ -35,7 +35,6 @@ import com.plotsquared.core.plot.schematic.Schematic; import com.plotsquared.core.queue.LocalBlockQueue; import com.plotsquared.core.util.task.RunnableVal; import com.plotsquared.core.util.task.TaskManager; -import com.plotsquared.core.util.uuid.UUIDHandler; import com.sk89q.jnbt.ByteArrayTag; import com.sk89q.jnbt.CompoundTag; import com.sk89q.jnbt.IntArrayTag; @@ -118,27 +117,32 @@ public abstract class SchematicHandler { Iterator i = plots.iterator(); final Plot plot = i.next(); i.remove(); - String owner = UUIDHandler.getName(plot.guessOwner()); - if (owner == null) { + + final String owner; + if (plot.hasOwner()) { + owner = plot.getOwnerAbs().toString(); + } else { owner = "unknown"; } + final String name; if (namingScheme == null) { name = plot.getId().x + ";" + plot.getId().y + ',' + plot.getArea() + ',' + owner; } else { - name = namingScheme.replaceAll("%owner%", owner) - .replaceAll("%id%", plot.getId().toString()) + name = namingScheme.replaceAll("%id%", plot.getId().toString()) .replaceAll("%idx%", plot.getId().x + "") .replaceAll("%idy%", plot.getId().y + "") .replaceAll("%world%", plot.getArea().toString()); } + final String directory; if (outputDir == null) { directory = Settings.Paths.SCHEMATICS; } else { directory = outputDir.getAbsolutePath(); } + final Runnable THIS = this; SchematicHandler.manager.getCompoundTag(plot, new RunnableVal() { @Override public void run(final CompoundTag value) { @@ -561,100 +565,114 @@ public abstract class SchematicHandler { final int p2z = pos2.getZ(); final int ey = pos2.getY(); Iterator yiter = IntStream.range(sy, ey + 1).iterator(); - final Runnable yTask = () -> { - long ystart = System.currentTimeMillis(); - while (yiter.hasNext() && System.currentTimeMillis() - ystart < 20) { - final int y = yiter.next(); - Iterator ziter = IntStream.range(p1z, p2z + 1).iterator(); - final Runnable zTask = () -> { - long zstart = System.currentTimeMillis(); - while (ziter.hasNext() - && System.currentTimeMillis() - zstart < 20) { - final int z = ziter.next(); - Iterator xiter = - IntStream.range(p1x, p2x + 1).iterator(); - final Runnable xTask = () -> { - long xstart = System.currentTimeMillis(); - final int ry = y - sy; - final int rz = z - p1z; - while (xiter.hasNext() - && System.currentTimeMillis() - xstart < 20) { - final int x = xiter.next(); - final int rx = x - p1x; - BlockVector3 point = BlockVector3.at(x, y, z); - BaseBlock block = - cuboidRegion.getWorld().getFullBlock(point); - if (block.getNbtData() != null) { - Map values = new HashMap<>(); - for (Map.Entry entry : block - .getNbtData().getValue().entrySet()) { - values.put(entry.getKey(), entry.getValue()); + final Runnable yTask = new Runnable() { + @Override public void run() { + long ystart = System.currentTimeMillis(); + while (yiter.hasNext() && System.currentTimeMillis() - ystart < 20) { + final int y = yiter.next(); + Iterator ziter = IntStream.range(p1z, p2z + 1).iterator(); + final Runnable zTask = new Runnable() { + @Override public void run() { + long zstart = System.currentTimeMillis(); + while (ziter.hasNext() + && System.currentTimeMillis() - zstart < 20) { + final int z = ziter.next(); + Iterator xiter = + IntStream.range(p1x, p2x + 1).iterator(); + final Runnable xTask = new Runnable() { + @Override public void run() { + long xstart = System.currentTimeMillis(); + final int ry = y - sy; + final int rz = z - p1z; + while (xiter.hasNext() + && System.currentTimeMillis() - xstart + < 20) { + final int x = xiter.next(); + final int rx = x - p1x; + BlockVector3 point = + BlockVector3.at(x, y, z); + BaseBlock block = cuboidRegion.getWorld() + .getFullBlock(point); + if (block.getNbtData() != null) { + Map values = + new HashMap<>(); + for (Map.Entry entry : block + .getNbtData().getValue() + .entrySet()) { + values.put(entry.getKey(), + entry.getValue()); + } + // Remove 'id' if it exists. We want 'Id' + values.remove("id"); + + // Positions are kept in NBT, we don't want that. + values.remove("x"); + values.remove("y"); + values.remove("z"); + + values.put("Id", + new StringTag(block.getNbtId())); + values.put("Pos", new IntArrayTag( + new int[] {rx, ry, rz})); + + tileEntities + .add(new CompoundTag(values)); + } + String blockKey = + block.toImmutableState().getAsString(); + int blockId; + if (palette.containsKey(blockKey)) { + blockId = palette.get(blockKey); + } else { + blockId = palette.size(); + palette.put(blockKey, palette.size()); + } + + while ((blockId & -128) != 0) { + buffer.write(blockId & 127 | 128); + blockId >>>= 7; + } + buffer.write(blockId); + + if (ry > 0) { + continue; + } + BlockVector2 pt = BlockVector2.at(x, z); + BiomeType biome = + cuboidRegion.getWorld().getBiome(pt); + String biomeStr = biome.getId(); + int biomeId; + if (biomePalette.containsKey(biomeStr)) { + biomeId = biomePalette.get(biomeStr); + } else { + biomeId = biomePalette.size(); + biomePalette.put(biomeStr, biomeId); + } + while ((biomeId & -128) != 0) { + biomeBuffer.write(biomeId & 127 | 128); + biomeId >>>= 7; + } + biomeBuffer.write(biomeId); + } + if (xiter.hasNext()) { + this.run(); + } } - // Remove 'id' if it exists. We want 'Id' - values.remove("id"); - - // Positions are kept in NBT, we don't want that. - values.remove("x"); - values.remove("y"); - values.remove("z"); - - values.put("Id", new StringTag(block.getNbtId())); - values.put("Pos", - new IntArrayTag(new int[] {rx, ry, rz})); - - tileEntities.add(new CompoundTag(values)); - } - String blockKey = - block.toImmutableState().getAsString(); - int blockId; - if (palette.containsKey(blockKey)) { - blockId = palette.get(blockKey); - } else { - blockId = palette.size(); - palette.put(blockKey, palette.size()); - } - - while ((blockId & -128) != 0) { - buffer.write(blockId & 127 | 128); - blockId >>>= 7; - } - buffer.write(blockId); - - if (ry > 0) { - continue; - } - BlockVector2 pt = BlockVector2.at(x, z); - BiomeType biome = cuboidRegion.getWorld().getBiome(pt); - String biomeStr = biome.getId(); - int biomeId; - if (biomePalette.containsKey(biomeStr)) { - biomeId = biomePalette.get(biomeStr); - } else { - biomeId = biomePalette.size(); - biomePalette.put(biomeStr, biomeId); - } - while ((biomeId & -128) != 0) { - biomeBuffer.write(biomeId & 127 | 128); - biomeId >>>= 7; - } - biomeBuffer.write(biomeId); + }; + xTask.run(); } - if (xiter.hasNext()) { + if (ziter.hasNext()) { this.run(); } - }; - xTask.run(); - } - if (ziter.hasNext()) { - this.run(); - } - }; - zTask.run(); - } - if (yiter.hasNext()) { - TaskManager.runTaskLater(this, 1); - } else { - regionTask.run(); + } + }; + zTask.run(); + } + if (yiter.hasNext()) { + TaskManager.runTaskLater(this, 1); + } else { + regionTask.run(); + } } }; yTask.run(); diff --git a/Core/src/main/java/com/plotsquared/core/util/SetupUtils.java b/Core/src/main/java/com/plotsquared/core/util/SetupUtils.java index 477c99715..cae6f2ae1 100644 --- a/Core/src/main/java/com/plotsquared/core/util/SetupUtils.java +++ b/Core/src/main/java/com/plotsquared/core/util/SetupUtils.java @@ -28,6 +28,7 @@ package com.plotsquared.core.util; import com.plotsquared.core.generator.GeneratorWrapper; import com.plotsquared.core.plot.PlotArea; import com.plotsquared.core.plot.SetupObject; +import com.plotsquared.core.setup.PlotAreaBuilder; import java.util.HashMap; @@ -41,7 +42,10 @@ public abstract class SetupUtils { public abstract String getGenerator(final PlotArea plotArea); + @Deprecated public abstract String setupWorld(final SetupObject object); + public abstract String setupWorld(final PlotAreaBuilder builder); + public abstract void unload(String world, boolean save); } diff --git a/Core/src/main/java/com/plotsquared/core/util/TabCompletions.java b/Core/src/main/java/com/plotsquared/core/util/TabCompletions.java new file mode 100644 index 000000000..56a3ff8fa --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/util/TabCompletions.java @@ -0,0 +1,187 @@ +/* + * _____ _ _ _____ _ + * | __ \| | | | / ____| | | + * | |__) | | ___ | |_| (___ __ _ _ _ __ _ _ __ ___ __| | + * | ___/| |/ _ \| __|\___ \ / _` | | | |/ _` | '__/ _ \/ _` | + * | | | | (_) | |_ ____) | (_| | |_| | (_| | | | __/ (_| | + * |_| |_|\___/ \__|_____/ \__, |\__,_|\__,_|_| \___|\__,_| + * | | + * |_| + * PlotSquared plot management system for Minecraft + * Copyright (C) 2020 IntellectualSites + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.plotsquared.core.util; + +import com.google.common.cache.Cache; +import com.google.common.cache.CacheBuilder; +import com.plotsquared.core.PlotSquared; +import com.plotsquared.core.command.Command; +import com.plotsquared.core.command.CommandCategory; +import com.plotsquared.core.command.RequiredType; +import com.plotsquared.core.configuration.Settings; +import com.plotsquared.core.player.PlotPlayer; +import com.plotsquared.core.plot.Plot; +import com.plotsquared.core.uuid.UUIDMapping; +import lombok.experimental.UtilityClass; +import org.jetbrains.annotations.NotNull; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Locale; +import java.util.UUID; +import java.util.concurrent.TimeUnit; +import java.util.function.Predicate; +import java.util.stream.Collectors; + +/** + * Tab completion utilities + */ +@UtilityClass +public class TabCompletions { + + private final Cache> cachedCompletionValues = + CacheBuilder.newBuilder() + .expireAfterWrite(Settings.Tab_Completions.CACHE_EXPIRATION, TimeUnit.SECONDS) + .build(); + + private final Command booleanTrueCompletion = new Command(null, false, "true", "", + RequiredType.NONE, null) {}; + private final Command booleanFalseCompletion = new Command(null, false, "false", "", + RequiredType.NONE, null) {}; + + /** + * Get a list of tab completions corresponding to player names. This uses the UUID pipeline + * cache, so it will complete will all names known to PlotSquared + * + * @param input Command input + * @param existing Players that should not be included in completions + * @return List of completions + */ + @NotNull public List completePlayers(@NotNull final String input, + @NotNull final List existing) { + return completePlayers("players", input, existing, uuid -> true); + } + + /** + * Get a list of tab completions corresponding to player names added to the given plot. + * + * @param plot Plot to complete added players for + * @param input Command input + * @param existing Players that should not be included in completions + * @return List of completions + */ + @NotNull public List completeAddedPlayers(@NotNull final Plot plot, @NotNull final String input, + @NotNull final List existing) { + return completePlayers("added" + plot, input, existing, + uuid -> plot.getMembers().contains(uuid) + || plot.getTrusted().contains(uuid) + || plot.getDenied().contains(uuid)); + } + + @NotNull public List completePlayersInPlot(@NotNull final Plot plot, @NotNull final String input, + @NotNull final List existing) { + List players = cachedCompletionValues.getIfPresent("inPlot" + plot); + if (players == null) { + final List> inPlot = plot.getPlayersInPlot(); + players = new ArrayList<>(inPlot.size()); + for (PlotPlayer player : inPlot) { + players.add(player.getName()); + } + cachedCompletionValues.put("inPlot" + plot, players); + } + return filterCached(players, input, existing); + } + + /** + * Get a list of completions corresponding to WorldEdit(/FAWE) patterns. This uses + * WorldEdit's pattern completer internally. + * + * @param input Command input + * @return List of completions + */ + @NotNull public List completePatterns(@NotNull final String input) { + return PatternUtil.getSuggestions(input.trim()).stream() + .map(value -> value.toLowerCase(Locale.ENGLISH).replace("minecraft:", "")) + .filter(value -> value.startsWith(input.toLowerCase(Locale.ENGLISH))) + .map(value -> new Command(null, false, value, "", RequiredType.NONE, null) { + }).collect(Collectors.toList()); + } + + @NotNull public List completeBoolean(@NotNull final String input) { + if (input.isEmpty()) { + return Arrays.asList(booleanTrueCompletion, booleanFalseCompletion); + } + if ("true".startsWith(input)) { + return Collections.singletonList(booleanTrueCompletion); + } + if ("false".startsWith(input)) { + return Collections.singletonList(booleanFalseCompletion); + } + return Collections.emptyList(); + } + + /** + * @param cacheIdentifier Cache key + * @param input Command input + * @param existing Players that should not be included in completions + * @param uuidFilter Filter applied before caching values + * @return List of completions + */ + private List completePlayers(@NotNull final String cacheIdentifier, @NotNull final String input, + @NotNull final List existing, + @NotNull final Predicate uuidFilter) { + List players; + if (Settings.Enabled_Components.EXTENDED_USERNAME_COMPLETION) { + players = cachedCompletionValues.getIfPresent(cacheIdentifier); + if (players == null) { + final Collection mappings = + PlotSquared.get().getImpromptuUUIDPipeline().getAllImmediately(); + players = new ArrayList<>(mappings.size()); + for (final UUIDMapping mapping : mappings) { + if (uuidFilter.test(mapping.getUuid())) { + players.add(mapping.getUsername()); + } + } + cachedCompletionValues.put(cacheIdentifier, players); + } + } else { + final Collection> onlinePlayers = PlotSquared.imp().getPlayerManager().getPlayers(); + players = new ArrayList<>(onlinePlayers.size()); + for (final PlotPlayer player : onlinePlayers) { + if (uuidFilter.test(player.getUUID())) { + players.add(player.getName()); + } + } + } + return filterCached(players, input, existing); + } + + private List filterCached(Collection playerNames, String input, List existing) { + final String processedInput = input.toLowerCase(Locale.ENGLISH); + return playerNames.stream().filter(player -> player.toLowerCase(Locale.ENGLISH).startsWith(processedInput)) + .filter(player -> !existing.contains(player)).map( + player -> new Command(null, false, player, "", RequiredType.NONE, + CommandCategory.INFO) { + }) + /* If there are more than 200 suggestions, just send the first 200 */ + .limit(200) + .collect(Collectors.toList()); + } + +} diff --git a/Core/src/main/java/com/plotsquared/core/util/ThreadUtils.java b/Core/src/main/java/com/plotsquared/core/util/ThreadUtils.java new file mode 100644 index 000000000..c7c011e3d --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/util/ThreadUtils.java @@ -0,0 +1,57 @@ +/* + * _____ _ _ _____ _ + * | __ \| | | | / ____| | | + * | |__) | | ___ | |_| (___ __ _ _ _ __ _ _ __ ___ __| | + * | ___/| |/ _ \| __|\___ \ / _` | | | |/ _` | '__/ _ \/ _` | + * | | | | (_) | |_ ____) | (_| | |_| | (_| | | | __/ (_| | + * |_| |_|\___/ \__|_____/ \__, |\__,_|\__,_|_| \___|\__,_| + * | | + * |_| + * PlotSquared plot management system for Minecraft + * Copyright (C) 2020 IntellectualSites + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.plotsquared.core.util; + +import com.plotsquared.core.PlotSquared; +import lombok.experimental.UtilityClass; + +@UtilityClass public class ThreadUtils { + + /** + * Throws {@link IllegalStateException} if the method + * is called from the server main thread + * + * @param message Message describing the issue + */ + public void catchSync(final String message) { + if (PlotSquared.get().isMainThread(Thread.currentThread())) { + throw new IllegalStateException(message); + } + } + + /** + * Throws {@link IllegalStateException} if the method + * is not called from the server main thread + * + * @param message Message describing the issue + */ + public void catchAsync(final String message) { + if (!PlotSquared.get().isMainThread(Thread.currentThread())) { + throw new IllegalStateException(message); + } + } + +} diff --git a/Core/src/main/java/com/plotsquared/core/util/WEManager.java b/Core/src/main/java/com/plotsquared/core/util/WEManager.java index 110c3ec3e..21654e42b 100644 --- a/Core/src/main/java/com/plotsquared/core/util/WEManager.java +++ b/Core/src/main/java/com/plotsquared/core/util/WEManager.java @@ -83,7 +83,7 @@ public class WEManager { return false; } - public static HashSet getMask(PlotPlayer player) { + public static HashSet getMask(PlotPlayer player) { HashSet regions = new HashSet<>(); UUID uuid = player.getUUID(); Location location = player.getLocation(); diff --git a/Core/src/main/java/com/plotsquared/core/util/query/AliasFilter.java b/Core/src/main/java/com/plotsquared/core/util/query/AliasFilter.java new file mode 100644 index 000000000..808f34797 --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/util/query/AliasFilter.java @@ -0,0 +1,43 @@ +/* + * _____ _ _ _____ _ + * | __ \| | | | / ____| | | + * | |__) | | ___ | |_| (___ __ _ _ _ __ _ _ __ ___ __| | + * | ___/| |/ _ \| __|\___ \ / _` | | | |/ _` | '__/ _ \/ _` | + * | | | | (_) | |_ ____) | (_| | |_| | (_| | | | __/ (_| | + * |_| |_|\___/ \__|_____/ \__, |\__,_|\__,_|_| \___|\__,_| + * | | + * |_| + * PlotSquared plot management system for Minecraft + * Copyright (C) 2020 IntellectualSites + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.plotsquared.core.util.query; + +import com.plotsquared.core.plot.Plot; +import org.jetbrains.annotations.NotNull; + +class AliasFilter implements PlotFilter { + + private final String alias; + + AliasFilter(@NotNull final String alias) { + this.alias = alias; + } + + @Override public boolean accepts(@NotNull final Plot plot) { + return this.alias.equalsIgnoreCase(plot.getAlias()); + } + +} diff --git a/Core/src/main/java/com/plotsquared/core/util/query/AreaLimitedPlotProvider.java b/Core/src/main/java/com/plotsquared/core/util/query/AreaLimitedPlotProvider.java new file mode 100644 index 000000000..2a6e88171 --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/util/query/AreaLimitedPlotProvider.java @@ -0,0 +1,51 @@ +/* + * _____ _ _ _____ _ + * | __ \| | | | / ____| | | + * | |__) | | ___ | |_| (___ __ _ _ _ __ _ _ __ ___ __| | + * | ___/| |/ _ \| __|\___ \ / _` | | | |/ _` | '__/ _ \/ _` | + * | | | | (_) | |_ ____) | (_| | |_| | (_| | | | __/ (_| | + * |_| |_|\___/ \__|_____/ \__, |\__,_|\__,_|_| \___|\__,_| + * | | + * |_| + * PlotSquared plot management system for Minecraft + * Copyright (C) 2020 IntellectualSites + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.plotsquared.core.util.query; + +import com.plotsquared.core.plot.Plot; +import com.plotsquared.core.plot.PlotArea; + +import java.util.Collection; +import java.util.LinkedList; +import java.util.List; + +class AreaLimitedPlotProvider implements PlotProvider { + + private final Collection areas; + + AreaLimitedPlotProvider(Collection areas) { + this.areas = areas; + } + + @Override public Collection getPlots() { + final List plots = new LinkedList<>(); + for (final PlotArea area : areas) { + plots.addAll(area.getPlots()); + } + return plots; + } + +} diff --git a/Core/src/main/java/com/plotsquared/core/util/query/ExpiredPlotProvider.java b/Core/src/main/java/com/plotsquared/core/util/query/ExpiredPlotProvider.java new file mode 100644 index 000000000..9b369dc4e --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/util/query/ExpiredPlotProvider.java @@ -0,0 +1,39 @@ +/* + * _____ _ _ _____ _ + * | __ \| | | | / ____| | | + * | |__) | | ___ | |_| (___ __ _ _ _ __ _ _ __ ___ __| | + * | ___/| |/ _ \| __|\___ \ / _` | | | |/ _` | '__/ _ \/ _` | + * | | | | (_) | |_ ____) | (_| | |_| | (_| | | | __/ (_| | + * |_| |_|\___/ \__|_____/ \__, |\__,_|\__,_|_| \___|\__,_| + * | | + * |_| + * PlotSquared plot management system for Minecraft + * Copyright (C) 2020 IntellectualSites + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.plotsquared.core.util.query; + +import com.plotsquared.core.plot.Plot; +import com.plotsquared.core.plot.expiration.ExpireManager; + +import java.util.Collection; + +class ExpiredPlotProvider implements PlotProvider { + + @Override public Collection getPlots() { + return ExpireManager.IMP.getPendingExpired(); + } + +} diff --git a/Core/src/main/java/com/plotsquared/core/util/query/FixedPlotProvider.java b/Core/src/main/java/com/plotsquared/core/util/query/FixedPlotProvider.java new file mode 100644 index 000000000..3bf79c783 --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/util/query/FixedPlotProvider.java @@ -0,0 +1,46 @@ +/* + * _____ _ _ _____ _ + * | __ \| | | | / ____| | | + * | |__) | | ___ | |_| (___ __ _ _ _ __ _ _ __ ___ __| | + * | ___/| |/ _ \| __|\___ \ / _` | | | |/ _` | '__/ _ \/ _` | + * | | | | (_) | |_ ____) | (_| | |_| | (_| | | | __/ (_| | + * |_| |_|\___/ \__|_____/ \__, |\__,_|\__,_|_| \___|\__,_| + * | | + * |_| + * PlotSquared plot management system for Minecraft + * Copyright (C) 2020 IntellectualSites + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.plotsquared.core.util.query; + +import com.plotsquared.core.plot.Plot; +import org.jetbrains.annotations.NotNull; + +import java.util.Collection; +import java.util.Collections; + +class FixedPlotProvider implements PlotProvider { + + private final Plot plot; + + FixedPlotProvider(@NotNull final Plot plot) { + this.plot = plot; + } + + @Override public Collection getPlots() { + return Collections.singleton(plot); + } + +} diff --git a/Core/src/main/java/com/plotsquared/core/util/query/GlobalPlotProvider.java b/Core/src/main/java/com/plotsquared/core/util/query/GlobalPlotProvider.java new file mode 100644 index 000000000..3fb2420c5 --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/util/query/GlobalPlotProvider.java @@ -0,0 +1,39 @@ +/* + * _____ _ _ _____ _ + * | __ \| | | | / ____| | | + * | |__) | | ___ | |_| (___ __ _ _ _ __ _ _ __ ___ __| | + * | ___/| |/ _ \| __|\___ \ / _` | | | |/ _` | '__/ _ \/ _` | + * | | | | (_) | |_ ____) | (_| | |_| | (_| | | | __/ (_| | + * |_| |_|\___/ \__|_____/ \__, |\__,_|\__,_|_| \___|\__,_| + * | | + * |_| + * PlotSquared plot management system for Minecraft + * Copyright (C) 2020 IntellectualSites + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.plotsquared.core.util.query; + +import com.plotsquared.core.PlotSquared; +import com.plotsquared.core.plot.Plot; + +import java.util.Collection; + +class GlobalPlotProvider implements PlotProvider { + + @Override public Collection getPlots() { + return PlotSquared.get().getPlots(); + } + +} diff --git a/Core/src/main/java/com/plotsquared/core/util/uuid/UUIDWrapper.java b/Core/src/main/java/com/plotsquared/core/util/query/MemberFilter.java similarity index 71% rename from Core/src/main/java/com/plotsquared/core/util/uuid/UUIDWrapper.java rename to Core/src/main/java/com/plotsquared/core/util/query/MemberFilter.java index 14c5a03ce..3f9670d08 100644 --- a/Core/src/main/java/com/plotsquared/core/util/uuid/UUIDWrapper.java +++ b/Core/src/main/java/com/plotsquared/core/util/query/MemberFilter.java @@ -23,25 +23,23 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ -package com.plotsquared.core.util.uuid; +package com.plotsquared.core.util.query; -import com.plotsquared.core.player.OfflinePlotPlayer; -import com.plotsquared.core.player.PlotPlayer; +import com.plotsquared.core.plot.Plot; import org.jetbrains.annotations.NotNull; import java.util.UUID; -public abstract class UUIDWrapper { +class MemberFilter implements PlotFilter { - @NotNull public abstract UUID getUUID(PlotPlayer player); + @NotNull private final UUID uuid; - public abstract UUID getUUID(OfflinePlotPlayer player); + MemberFilter(@NotNull final UUID uuid) { + this.uuid = uuid; + } - public abstract UUID getUUID(String name); + @Override public boolean accepts(@NotNull final Plot plot) { + return plot.isAdded(uuid); + } - public abstract OfflinePlotPlayer getOfflinePlayer(UUID uuid); - - public abstract OfflinePlotPlayer getOfflinePlayer(String name); - - public abstract OfflinePlotPlayer[] getOfflinePlayers(); } diff --git a/Core/src/main/java/com/plotsquared/core/util/query/NullProvider.java b/Core/src/main/java/com/plotsquared/core/util/query/NullProvider.java new file mode 100644 index 000000000..6cf3a70d4 --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/util/query/NullProvider.java @@ -0,0 +1,39 @@ +/* + * _____ _ _ _____ _ + * | __ \| | | | / ____| | | + * | |__) | | ___ | |_| (___ __ _ _ _ __ _ _ __ ___ __| | + * | ___/| |/ _ \| __|\___ \ / _` | | | |/ _` | '__/ _ \/ _` | + * | | | | (_) | |_ ____) | (_| | |_| | (_| | | | __/ (_| | + * |_| |_|\___/ \__|_____/ \__, |\__,_|\__,_|_| \___|\__,_| + * | | + * |_| + * PlotSquared plot management system for Minecraft + * Copyright (C) 2020 IntellectualSites + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.plotsquared.core.util.query; + +import com.plotsquared.core.plot.Plot; + +import java.util.Collection; +import java.util.Collections; + +class NullProvider implements PlotProvider { + + @Override public Collection getPlots() { + return Collections.emptyList(); + } + +} diff --git a/Bukkit/src/main/java/com/plotsquared/bukkit/util/uuid/LowerOfflineUUIDWrapper.java b/Core/src/main/java/com/plotsquared/core/util/query/OwnerFilter.java similarity index 56% rename from Bukkit/src/main/java/com/plotsquared/bukkit/util/uuid/LowerOfflineUUIDWrapper.java rename to Core/src/main/java/com/plotsquared/core/util/query/OwnerFilter.java index ad2be7ce3..cae258722 100644 --- a/Bukkit/src/main/java/com/plotsquared/bukkit/util/uuid/LowerOfflineUUIDWrapper.java +++ b/Core/src/main/java/com/plotsquared/core/util/query/OwnerFilter.java @@ -23,38 +23,24 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ -package com.plotsquared.bukkit.util.uuid; +package com.plotsquared.core.util.query; -import com.google.common.base.Charsets; -import com.plotsquared.core.player.OfflinePlotPlayer; -import com.plotsquared.core.player.PlotPlayer; -import org.bukkit.OfflinePlayer; +import com.plotsquared.core.plot.Plot; import org.jetbrains.annotations.NotNull; import java.util.Objects; import java.util.UUID; -public class LowerOfflineUUIDWrapper extends OfflineUUIDWrapper { +class OwnerFilter implements PlotFilter { - @NotNull @Override public UUID getUUID(PlotPlayer player) { - return UUID.nameUUIDFromBytes( - ("OfflinePlayer:" + player.getName().toLowerCase()).getBytes(Charsets.UTF_8)); + private final UUID owner; + + OwnerFilter(@NotNull final UUID owner) { + this.owner = owner; } - @Override public UUID getUUID(OfflinePlotPlayer player) { - return UUID.nameUUIDFromBytes( - ("OfflinePlayer:" + player.getName().toLowerCase()).getBytes(Charsets.UTF_8)); + @Override public boolean accepts(@NotNull final Plot plot) { + return plot.hasOwner() && Objects.equals(plot.getOwnerAbs(), this.owner); } - - @Override public UUID getUUID(OfflinePlayer player) { - return UUID.nameUUIDFromBytes( - ("OfflinePlayer:" + Objects.requireNonNull(player.getName()).toLowerCase()) - .getBytes(Charsets.UTF_8)); - } - - @Override public UUID getUUID(String name) { - return UUID - .nameUUIDFromBytes(("OfflinePlayer:" + name.toLowerCase()).getBytes(Charsets.UTF_8)); - } - + } diff --git a/Core/src/main/java/com/plotsquared/core/util/query/PaginatedPlotResult.java b/Core/src/main/java/com/plotsquared/core/util/query/PaginatedPlotResult.java new file mode 100644 index 000000000..2c0ed9152 --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/util/query/PaginatedPlotResult.java @@ -0,0 +1,73 @@ +/* + * _____ _ _ _____ _ + * | __ \| | | | / ____| | | + * | |__) | | ___ | |_| (___ __ _ _ _ __ _ _ __ ___ __| | + * | ___/| |/ _ \| __|\___ \ / _` | | | |/ _` | '__/ _ \/ _` | + * | | | | (_) | |_ ____) | (_| | |_| | (_| | | | __/ (_| | + * |_| |_|\___/ \__|_____/ \__, |\__,_|\__,_|_| \___|\__,_| + * | | + * |_| + * PlotSquared plot management system for Minecraft + * Copyright (C) 2020 IntellectualSites + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.plotsquared.core.util.query; + +import com.google.common.base.Preconditions; +import com.plotsquared.core.plot.Plot; +import org.jetbrains.annotations.NotNull; + +import java.util.Collections; +import java.util.List; + +/** + * Paginated collection of plots as a result of a {@link PlotQuery query} + */ +public final class PaginatedPlotResult { + + private final List plots; + private final int pageSize; + + PaginatedPlotResult(@NotNull final List plots, final int pageSize) { + this.plots = plots; + this.pageSize = pageSize; + } + + /** + * Get the plots belonging to a certain page. + * + * @param page Positive page number. Indexed from 1 + * @return Plots that belong to the specified page + */ + public List getPage(final int page) { + Preconditions.checkState(page >= 0, "Page must be positive"); + final int from = (page - 1) * this.pageSize; + if (this.plots.size() < from) { + return Collections.emptyList(); + } + final int to = Math.max(from + pageSize, this.plots.size()); + return this.plots.subList(from, to); + } + + /** + * Get the number of available pages + * + * @return Available pages + */ + public int getPages() { + return (int) Math.ceil((double) plots.size() / (double) pageSize); + } + +} diff --git a/Core/src/main/java/com/plotsquared/core/util/query/PlotFilter.java b/Core/src/main/java/com/plotsquared/core/util/query/PlotFilter.java new file mode 100644 index 000000000..c017b21b0 --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/util/query/PlotFilter.java @@ -0,0 +1,41 @@ +/* + * _____ _ _ _____ _ + * | __ \| | | | / ____| | | + * | |__) | | ___ | |_| (___ __ _ _ _ __ _ _ __ ___ __| | + * | ___/| |/ _ \| __|\___ \ / _` | | | |/ _` | '__/ _ \/ _` | + * | | | | (_) | |_ ____) | (_| | |_| | (_| | | | __/ (_| | + * |_| |_|\___/ \__|_____/ \__, |\__,_|\__,_|_| \___|\__,_| + * | | + * |_| + * PlotSquared plot management system for Minecraft + * Copyright (C) 2020 IntellectualSites + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.plotsquared.core.util.query; + +import com.plotsquared.core.plot.Plot; +import org.jetbrains.annotations.NotNull; + +import java.util.function.Predicate; + +@FunctionalInterface interface PlotFilter extends Predicate { + + @Override default boolean test(@NotNull final Plot plot) { + return this.accepts(plot); + } + + boolean accepts(@NotNull final Plot plot); + +} diff --git a/Bukkit/src/main/java/com/plotsquared/bukkit/util/uuid/DatFileFilter.java b/Core/src/main/java/com/plotsquared/core/util/query/PlotProvider.java similarity index 83% rename from Bukkit/src/main/java/com/plotsquared/bukkit/util/uuid/DatFileFilter.java rename to Core/src/main/java/com/plotsquared/core/util/query/PlotProvider.java index 65657fbff..c8048da1a 100644 --- a/Bukkit/src/main/java/com/plotsquared/bukkit/util/uuid/DatFileFilter.java +++ b/Core/src/main/java/com/plotsquared/core/util/query/PlotProvider.java @@ -23,14 +23,14 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ -package com.plotsquared.bukkit.util.uuid; +package com.plotsquared.core.util.query; -import java.io.File; -import java.io.FilenameFilter; +import com.plotsquared.core.plot.Plot; -public class DatFileFilter implements FilenameFilter { +import java.util.Collection; + +@FunctionalInterface interface PlotProvider { + + Collection getPlots(); - @Override public boolean accept(File dir, String name) { - return name.endsWith(".dat"); - } } diff --git a/Core/src/main/java/com/plotsquared/core/util/query/PlotQuery.java b/Core/src/main/java/com/plotsquared/core/util/query/PlotQuery.java new file mode 100644 index 000000000..27b4352eb --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/util/query/PlotQuery.java @@ -0,0 +1,409 @@ +/* + * _____ _ _ _____ _ + * | __ \| | | | / ____| | | + * | |__) | | ___ | |_| (___ __ _ _ _ __ _ _ __ ___ __| | + * | ___/| |/ _ \| __|\___ \ / _` | | | |/ _` | '__/ _ \/ _` | + * | | | | (_) | |_ ____) | (_| | |_| | (_| | | | __/ (_| | + * |_| |_|\___/ \__|_____/ \__, |\__,_|\__,_|_| \___|\__,_| + * | | + * |_| + * PlotSquared plot management system for Minecraft + * Copyright (C) 2020 IntellectualSites + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.plotsquared.core.util.query; + +import com.google.common.base.Preconditions; +import com.plotsquared.core.PlotSquared; +import com.plotsquared.core.player.PlotPlayer; +import com.plotsquared.core.plot.Plot; +import com.plotsquared.core.plot.PlotArea; +import com.plotsquared.core.plot.Rating; +import com.plotsquared.core.plot.flag.implementations.DoneFlag; +import com.plotsquared.core.util.MathMan; +import org.jetbrains.annotations.NotNull; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.UUID; +import java.util.function.Predicate; +import java.util.stream.Stream; + +/** + * This represents a plot query, and can be used to + * search for plots matching certain criteria. + *

+ * The queries can be reused as no results are stored + * in the query itself + */ +public final class PlotQuery { + + private final Collection filters = new LinkedList<>(); + private PlotProvider plotProvider = new GlobalPlotProvider(); + private SortingStrategy sortingStrategy = SortingStrategy.NO_SORTING; + private PlotArea priorityArea; + private Comparator plotComparator; + + private PlotQuery() { + } + + /** + * Create a new plot query instance + * + * @return New query + */ + public static PlotQuery newQuery() { + return new PlotQuery(); + } + + /** + * Query for plots in a single area + * + * @param area Area + * @return The query instance + */ + @NotNull public PlotQuery inArea(@NotNull final PlotArea area) { + Preconditions.checkNotNull(area, "Area may not be null"); + this.plotProvider = new AreaLimitedPlotProvider(Collections.singletonList(area)); + return this; + } + + /** + * Query for plots in all areas in a world + * + * @param world World name + * @return The query instance + */ + @NotNull public PlotQuery inWorld(@NotNull final String world) { + Preconditions.checkNotNull(world, "World may not be null"); + this.plotProvider = new AreaLimitedPlotProvider(PlotSquared.get().getPlotAreas(world)); + return this; + } + + /** + * Query for plots in specific areas + * + * @param areas Plot areas + * @return The query instance + */ + @NotNull public PlotQuery inAreas(@NotNull final Collection areas) { + Preconditions.checkNotNull(areas, "Areas may not be null"); + Preconditions.checkState(!areas.isEmpty(), "At least one area must be provided"); + this.plotProvider = new AreaLimitedPlotProvider(Collections.unmodifiableCollection(areas)); + return this; + } + + /** + * Query for expired plots + * + * @return The query instance + */ + @NotNull public PlotQuery expiredPlots() { + this.plotProvider = new ExpiredPlotProvider(); + return this; + } + + /** + * Query for all plots + * + * @return The query instance + */ + @NotNull public PlotQuery allPlots() { + this.plotProvider = new GlobalPlotProvider(); + return this; + } + + /** + * Don't query at all + * + * @return The query instance + */ + @NotNull public PlotQuery noPlots() { + this.plotProvider = new NullProvider(); + return this; + } + + /** + * Query for plots based on a search term + * + * @return The query instance + */ + @NotNull public PlotQuery plotsBySearch(@NotNull final String searchTerm) { + Preconditions.checkNotNull(searchTerm, "Search term may not be null"); + this.plotProvider = new SearchPlotProvider(searchTerm); + return this; + } + + /** + * Query with a pre-defined result + * + * @return The query instance + */ + @NotNull public PlotQuery withPlot(@NotNull final Plot plot) { + Preconditions.checkNotNull(plot, "Plot may not be null"); + this.plotProvider = new FixedPlotProvider(plot); + return this; + } + + /** + * Query for base plots only + * + * @return The query instance + */ + @NotNull public PlotQuery whereBasePlot() { + return this.addFilter(new PredicateFilter(Plot::isBasePlot)); + } + + /** + * Query for plots owned by a specific player + * + * @param owner Owner UUID + * @return The query instance + */ + @NotNull public PlotQuery ownedBy(@NotNull final UUID owner) { + Preconditions.checkNotNull(owner, "Owner may not be null"); + return this.addFilter(new OwnerFilter(owner)); + } + + /** + * Query for plots owned by a specific player + * + * @param owner Owner + * @return The query instance + */ + @NotNull public PlotQuery ownedBy(@NotNull final PlotPlayer owner) { + Preconditions.checkNotNull(owner, "Owner may not be null"); + return this.addFilter(new OwnerFilter(owner.getUUID())); + } + + /** + * Query for plots with a specific alias + * + * @param alias Plot alias + * @return The query instance + */ + @NotNull public PlotQuery withAlias(@NotNull final String alias) { + Preconditions.checkNotNull(alias, "Alias may not be null"); + return this.addFilter(new AliasFilter(alias)); + } + + /** + * Query for plots with a specific member (added/trusted/owner) + * + * @param member Member UUID + * @return The query instance + */ + @NotNull public PlotQuery withMember(@NotNull final UUID member) { + Preconditions.checkNotNull(member, "Member may not be null"); + return this.addFilter(new MemberFilter(member)); + } + + /** + * Query for plots that passes a given predicate + * + * @param predicate Predicate + * @return The query instance + */ + @NotNull public PlotQuery thatPasses(@NotNull final Predicate predicate) { + Preconditions.checkNotNull(predicate, "Predicate may not be null"); + return this.addFilter(new PredicateFilter(predicate)); + } + + /** + * Specify the sorting strategy that will decide how to + * sort the results. This only matters if you use {@link #asList()} + * + * @param strategy Strategy + * @return The query instance + */ + @NotNull public PlotQuery withSortingStrategy(@NotNull final SortingStrategy strategy) { + Preconditions.checkNotNull(strategy, "Strategy may not be null"); + this.sortingStrategy = strategy; + return this; + } + + /** + * Use a custom comparator to sort the results + * + * @param comparator Comparator + * @return The query instance + */ + @NotNull public PlotQuery sorted(@NotNull final Comparator comparator) { + Preconditions.checkNotNull(comparator, "Comparator may not be null"); + this.sortingStrategy = SortingStrategy.COMPARATOR; + this.plotComparator = comparator; + return this; + } + + /** + * Defines the area around which plots may be sorted, depending on the + * sorting strategy + * + * @param plotArea Plot area + * @return The query instance + */ + @NotNull public PlotQuery relativeToArea(@NotNull final PlotArea plotArea) { + Preconditions.checkNotNull(plotArea, "Area may not be null"); + this.priorityArea = plotArea; + return this; + } + + /** + * Get all plots that match the given criteria + * + * @return Matching plots + */ + @NotNull public Stream asStream() { + return this.asList().stream(); + } + + /** + * Get all plots that match the given criteria + * + * @return Matching plots as a mutable + */ + @NotNull public List asList() { + final List result; + if (this.filters.isEmpty()) { + result = new ArrayList<>(this.plotProvider.getPlots()); + } else { + final Collection plots = this.plotProvider.getPlots(); + result = new ArrayList<>(plots.size()); + outer: for (final Plot plot : plots) { + for (final PlotFilter filter : this.filters) { + if (!filter.accepts(plot)) { + continue outer; + } + } + result.add(plot); + } + } + if (this.sortingStrategy == SortingStrategy.NO_SORTING) { + return result; + } else if (this.sortingStrategy == SortingStrategy.SORT_BY_TEMP) { + return PlotSquared.get().sortPlotsByTemp(result); + } else if (this.sortingStrategy == SortingStrategy.SORT_BY_DONE) { + result.sort((a, b) -> { + String va = a.getFlag(DoneFlag.class); + String vb = b.getFlag(DoneFlag.class); + if (MathMan.isInteger(va)) { + if (MathMan.isInteger(vb)) { + return Integer.parseInt(vb) - Integer.parseInt(va); + } + return -1; + } + return 1; + }); + } else if (this.sortingStrategy == SortingStrategy.SORT_BY_RATING) { + result.sort((p1, p2) -> { + double v1 = 0; + int p1s = p1.getSettings().getRatings().size(); + int p2s = p2.getRatings().size(); + if (!p1.getSettings().getRatings().isEmpty()) { + v1 = p1.getRatings().values().stream().mapToDouble(Rating::getAverageRating) + .map(av -> av * av).sum(); + v1 /= p1s; + v1 += p1s; + } + double v2 = 0; + if (!p2.getSettings().getRatings().isEmpty()) { + for (Map.Entry entry : p2.getRatings().entrySet()) { + double av = entry.getValue().getAverageRating(); + v2 += av * av; + } + v2 /= p2s; + v2 += p2s; + } + if (v2 == v1 && v2 != 0) { + return p2s - p1s; + } + return (int) Math.signum(v2 - v1); + }); + } else if (this.sortingStrategy == SortingStrategy.SORT_BY_CREATION) { + return PlotSquared.get().sortPlots(result, PlotSquared.SortType.CREATION_DATE, this.priorityArea); + } else if (this.sortingStrategy == SortingStrategy.COMPARATOR) { + result.sort(this.plotComparator); + } + return result; + } + + /** + * Get all plots that match the given criteria + * + * @return Matching plots as a mutable set + */ + @NotNull public Set asSet() { + return new HashSet<>(this.asList()); + } + + /** + * Get all plots that match the given criteria + * in the form of a {@link PaginatedPlotResult} + * + * @param pageSize The size of the pages. Must be positive. + * @return Paginated plot result + */ + @NotNull public PaginatedPlotResult getPaginated(final int pageSize) { + Preconditions.checkState(pageSize > 0, "Page size must be greater than 0"); + return new PaginatedPlotResult(this.asList(), pageSize); + } + + /** + * Get all plots that match the given criteria + * + * @return Matching plots as an immutable collection + */ + @NotNull public Collection asCollection() { + return this.asList(); + } + + /** + * Get whether any provided plot matches the given filters. + * If no plot was provided, false will be returned. + * + * @return true if any provided plot matches the filters. + */ + public boolean anyMatch() { + if (this.filters.isEmpty()) { + return !this.plotProvider.getPlots().isEmpty(); + } else { + final Collection plots = this.plotProvider.getPlots(); + outer: for (final Plot plot : plots) { + // a plot must pass all filters to match the criteria + for (final PlotFilter filter : this.filters) { + if (!filter.accepts(plot)) { + continue outer; + } + } + return true; // a plot passed all filters, so we have a match + } + return false; + } + } + + @NotNull private PlotQuery addFilter(@NotNull final PlotFilter filter) { + this.filters.add(filter); + return this; + } + + +} diff --git a/Core/src/main/java/com/plotsquared/core/util/query/PredicateFilter.java b/Core/src/main/java/com/plotsquared/core/util/query/PredicateFilter.java new file mode 100644 index 000000000..dd68f081d --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/util/query/PredicateFilter.java @@ -0,0 +1,45 @@ +/* + * _____ _ _ _____ _ + * | __ \| | | | / ____| | | + * | |__) | | ___ | |_| (___ __ _ _ _ __ _ _ __ ___ __| | + * | ___/| |/ _ \| __|\___ \ / _` | | | |/ _` | '__/ _ \/ _` | + * | | | | (_) | |_ ____) | (_| | |_| | (_| | | | __/ (_| | + * |_| |_|\___/ \__|_____/ \__, |\__,_|\__,_|_| \___|\__,_| + * | | + * |_| + * PlotSquared plot management system for Minecraft + * Copyright (C) 2020 IntellectualSites + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.plotsquared.core.util.query; + +import com.plotsquared.core.plot.Plot; +import org.jetbrains.annotations.NotNull; + +import java.util.function.Predicate; + +class PredicateFilter implements PlotFilter { + + private final Predicate predicate; + + PredicateFilter(@NotNull final Predicate predicate) { + this.predicate = predicate; + } + + @Override public boolean accepts(@NotNull final Plot plot) { + return predicate.test(plot); + } + +} diff --git a/Core/src/main/java/com/plotsquared/core/util/query/SearchPlotProvider.java b/Core/src/main/java/com/plotsquared/core/util/query/SearchPlotProvider.java new file mode 100644 index 000000000..91193a79e --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/util/query/SearchPlotProvider.java @@ -0,0 +1,46 @@ +/* + * _____ _ _ _____ _ + * | __ \| | | | / ____| | | + * | |__) | | ___ | |_| (___ __ _ _ _ __ _ _ __ ___ __| | + * | ___/| |/ _ \| __|\___ \ / _` | | | |/ _` | '__/ _ \/ _` | + * | | | | (_) | |_ ____) | (_| | |_| | (_| | | | __/ (_| | + * |_| |_|\___/ \__|_____/ \__, |\__,_|\__,_|_| \___|\__,_| + * | | + * |_| + * PlotSquared plot management system for Minecraft + * Copyright (C) 2020 IntellectualSites + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.plotsquared.core.util.query; + +import com.plotsquared.core.plot.Plot; +import com.plotsquared.core.util.MainUtil; +import org.jetbrains.annotations.NotNull; + +import java.util.Collection; + +class SearchPlotProvider implements PlotProvider { + + private final String searchTerm; + + SearchPlotProvider(@NotNull final String searchTerm) { + this.searchTerm = searchTerm; + } + + @Override public Collection getPlots() { + return MainUtil.getPlotsBySearch(this.searchTerm); + } + +} diff --git a/Core/src/main/java/com/plotsquared/core/util/query/SortingStrategy.java b/Core/src/main/java/com/plotsquared/core/util/query/SortingStrategy.java new file mode 100644 index 000000000..7a70b46fd --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/util/query/SortingStrategy.java @@ -0,0 +1,56 @@ +/* + * _____ _ _ _____ _ + * | __ \| | | | / ____| | | + * | |__) | | ___ | |_| (___ __ _ _ _ __ _ _ __ ___ __| | + * | ___/| |/ _ \| __|\___ \ / _` | | | |/ _` | '__/ _ \/ _` | + * | | | | (_) | |_ ____) | (_| | |_| | (_| | | | __/ (_| | + * |_| |_|\___/ \__|_____/ \__, |\__,_|\__,_|_| \___|\__,_| + * | | + * |_| + * PlotSquared plot management system for Minecraft + * Copyright (C) 2020 IntellectualSites + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.plotsquared.core.util.query; + +/** + * Strategy used when sorting plot results + */ +public enum SortingStrategy { + /** + * Plots won't be sorted at all + */ + NO_SORTING, + /** + * Sort by the temporary (magic) plot ID + */ + SORT_BY_TEMP, + /** + * Sort by the value in the plot's {@link com.plotsquared.core.plot.flag.implementations.DoneFlag} + */ + SORT_BY_DONE, + /** + * Sort by the plot rating + */ + SORT_BY_RATING, + /** + * Sort by creation date + */ + SORT_BY_CREATION, + /** + * Sort using a comparator + */ + COMPARATOR; +} diff --git a/Core/src/main/java/com/plotsquared/core/util/uuid/UUIDHandler.java b/Core/src/main/java/com/plotsquared/core/util/uuid/UUIDHandler.java deleted file mode 100644 index 6dd8b1c47..000000000 --- a/Core/src/main/java/com/plotsquared/core/util/uuid/UUIDHandler.java +++ /dev/null @@ -1,198 +0,0 @@ -/* - * _____ _ _ _____ _ - * | __ \| | | | / ____| | | - * | |__) | | ___ | |_| (___ __ _ _ _ __ _ _ __ ___ __| | - * | ___/| |/ _ \| __|\___ \ / _` | | | |/ _` | '__/ _ \/ _` | - * | | | | (_) | |_ ____) | (_| | |_| | (_| | | | __/ (_| | - * |_| |_|\___/ \__|_____/ \__, |\__,_|\__,_|_| \___|\__,_| - * | | - * |_| - * PlotSquared plot management system for Minecraft - * Copyright (C) 2020 IntellectualSites - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package com.plotsquared.core.util.uuid; - -import com.google.common.collect.BiMap; -import com.plotsquared.core.PlotSquared; -import com.plotsquared.core.configuration.Captions; -import com.plotsquared.core.database.DBFunc; -import com.plotsquared.core.player.OfflinePlotPlayer; -import com.plotsquared.core.player.PlotPlayer; -import com.plotsquared.core.util.StringWrapper; -import com.plotsquared.core.util.task.RunnableVal; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.UUID; - -public class UUIDHandler { - - public static UUIDHandlerImplementation implementation; - - public static void add(StringWrapper name, UUID uuid) { - implementation.add(name, uuid); - } - - /** - * Get the map containing all names/uuids. - * - * @return map with names + uuids - * @see BiMap - */ - public static BiMap getUuidMap() { - return implementation.getUUIDMap(); - } - - /** - * Check if a uuid is cached - * - * @param uuid to check - * @return true of the uuid is cached - * @see BiMap#containsValue(Object) - */ - public static boolean uuidExists(UUID uuid) { - return implementation.uuidExists(uuid); - } - - /** - * Check if a name is cached - * - * @param name to check - * @return true of the name is cached - * @see BiMap#containsKey(Object) - */ - public static boolean nameExists(StringWrapper name) { - return implementation.nameExists(name); - } - - public static HashSet getAllUUIDS() { - final HashSet uuids = new HashSet<>(); - PlotSquared.get().forEachPlotRaw(plot -> { - if (plot.hasOwner()) { - uuids.add(plot.getOwnerAbs()); - uuids.addAll(plot.getTrusted()); - uuids.addAll(plot.getMembers()); - uuids.addAll(plot.getDenied()); - } - }); - return uuids; - } - - public static UUIDWrapper getUUIDWrapper() { - return implementation.getUUIDWrapper(); - } - - public static void setUUIDWrapper(UUIDWrapper wrapper) { - implementation.setUUIDWrapper(wrapper); - } - - public static void startCaching(Runnable whenDone) { - implementation.startCaching(whenDone); - } - - public static void cache(BiMap toAdd) { - implementation.add(toAdd); - } - - @NotNull public static UUID getUUID(PlotPlayer player) { - return implementation.getUUID(player); - } - - public static UUID getUUID(OfflinePlotPlayer player) { - if (implementation == null) { - return null; - } - return implementation.getUUID(player); - } - - @Nullable public static String getName(UUID uuid) { - if (implementation == null) { - return null; - } - if (uuid != null && uuid.equals(DBFunc.SERVER)) { - return Captions.SERVER.getTranslated(); - } - return implementation.getName(uuid); - } - - @Nullable public static PlotPlayer getPlayer(@Nullable final UUID uuid) { - if (implementation == null || uuid == null) { - return null; - } - return check(implementation.getPlayer(uuid)); - } - - public static PlotPlayer getPlayer(String name) { - if (implementation == null) { - return null; - } - return check(implementation.getPlayer(name)); - } - - private static PlotPlayer check(@Nullable PlotPlayer player) { - if (player != null && !player.isOnline()) { - UUIDHandler.getPlayers().remove(player.getName()); - PlotSquared.get().IMP.unregister(player); - player = null; - } - return player; - } - - public static UUID getUUIDFromString(String nameOrUUIDString) { - if (implementation == null) { - return null; - } - if (nameOrUUIDString.length() > 16) { - try { - return UUID.fromString(nameOrUUIDString); - } catch (IllegalArgumentException e) { - return null; - } - } - return UUIDHandler.getUUID(nameOrUUIDString, null); - } - - public static UUID getUUID(String name, RunnableVal ifFetch) { - if (implementation == null) { - return null; - } - return implementation.getUUID(name, ifFetch); - } - - public static UUID getCachedUUID(String name, RunnableVal ifFetch) { - if (implementation == null) { - return null; - } - return implementation.getUUIDMap().get(new StringWrapper(name)); - } - - public static Map getPlayers() { - if (implementation == null) { - return new HashMap<>(); - } - return implementation.getPlayers(); - } - - public static void handleShutdown() { - if (implementation == null) { - return; - } - implementation.handleShutdown(); - } -} diff --git a/Core/src/main/java/com/plotsquared/core/util/uuid/UUIDHandlerImplementation.java b/Core/src/main/java/com/plotsquared/core/util/uuid/UUIDHandlerImplementation.java deleted file mode 100644 index 687af58e0..000000000 --- a/Core/src/main/java/com/plotsquared/core/util/uuid/UUIDHandlerImplementation.java +++ /dev/null @@ -1,324 +0,0 @@ -/* - * _____ _ _ _____ _ - * | __ \| | | | / ____| | | - * | |__) | | ___ | |_| (___ __ _ _ _ __ _ _ __ ___ __| | - * | ___/| |/ _ \| __|\___ \ / _` | | | |/ _` | '__/ _ \/ _` | - * | | | | (_) | |_ ____) | (_| | |_| | (_| | | | __/ (_| | - * |_| |_|\___/ \__|_____/ \__, |\__,_|\__,_|_| \___|\__,_| - * | | - * |_| - * PlotSquared plot management system for Minecraft - * Copyright (C) 2020 IntellectualSites - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package com.plotsquared.core.util.uuid; - -import com.google.common.base.Charsets; -import com.google.common.collect.BiMap; -import com.google.common.collect.HashBiMap; -import com.plotsquared.core.PlotSquared; -import com.plotsquared.core.configuration.Captions; -import com.plotsquared.core.configuration.Settings; -import com.plotsquared.core.database.DBFunc; -import com.plotsquared.core.player.OfflinePlotPlayer; -import com.plotsquared.core.player.PlotPlayer; -import com.plotsquared.core.plot.Plot; -import com.plotsquared.core.util.StringMan; -import com.plotsquared.core.util.StringWrapper; -import com.plotsquared.core.util.task.RunnableVal; -import com.plotsquared.core.util.task.TaskManager; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; -import java.util.UUID; -import java.util.concurrent.ConcurrentHashMap; - -public abstract class UUIDHandlerImplementation { - - public final HashSet unknown = new HashSet<>(); - private final ConcurrentHashMap players; - protected UUIDWrapper uuidWrapper; - private boolean cached = false; - private BiMap uuidMap = HashBiMap.create(new HashMap<>()); - - public UUIDHandlerImplementation(UUIDWrapper wrapper) { - this.uuidWrapper = wrapper; - this.players = new ConcurrentHashMap<>(); - } - - /** - * If the UUID is not found, some commands can request to fetch the UUID when possible. - * - * @param name - * @param ifFetch - */ - public abstract void fetchUUID(String name, RunnableVal ifFetch); - - /** - * Start UUID caching (this should be an async task) - * Recommended to override this is you want to cache offline players - */ - public boolean startCaching(Runnable whenDone) { - if (this.cached) { - return false; - } - return this.cached = true; - } - - public UUIDWrapper getUUIDWrapper() { - return this.uuidWrapper; - } - - public void setUUIDWrapper(UUIDWrapper wrapper) { - this.uuidWrapper = wrapper; - } - - public void rename(UUID uuid, StringWrapper name) { - this.uuidMap.inverse().remove(uuid); - this.uuidMap.put(name, uuid); - } - - public void add(BiMap toAdd) { - if (this.uuidMap.isEmpty()) { - this.uuidMap = toAdd; - } - for (Map.Entry entry : toAdd.entrySet()) { - UUID uuid = entry.getValue(); - StringWrapper name = entry.getKey(); - if (uuid == null || name == null) { - continue; - } - StringWrapper oldName = this.uuidMap.inverse().get(uuid); - if (oldName != null) { - if (this.uuidMap.containsKey(name)) { - continue; - } - if (getPlayer(uuid) == null) { - rename(uuid, name); - } - continue; - } - this.uuidMap.put(name, uuid); - } - PlotSquared - .debug(Captions.PREFIX + "&6Cached a total of: " + this.uuidMap.size() + " UUIDs"); - } - - public boolean add(final StringWrapper name, final UUID uuid) { - if (uuid == null) { - PlotSquared.debug("UUID cannot be null!"); - return false; - } - if (name == null) { - try { - this.unknown.add(uuid); - } catch (Exception e) { - PlotSquared.log("&c(minor) Invalid UUID mapping: " + uuid); - e.printStackTrace(); - } - return false; - } - - /* - * lazy UUID conversion: - * - Useful if the person misconfigured the database, or settings before - * PlotMe conversion - */ - if (!Settings.UUID.OFFLINE && !this.unknown.isEmpty()) { - TaskManager.runTaskAsync(() -> { - UUID offline = UUID.nameUUIDFromBytes( - ("OfflinePlayer:" + name.value).getBytes(Charsets.UTF_8)); - if (!UUIDHandlerImplementation.this.unknown.contains(offline) && !name.value - .equals(name.value.toLowerCase())) { - offline = UUID.nameUUIDFromBytes( - ("OfflinePlayer:" + name.value.toLowerCase()).getBytes(Charsets.UTF_8)); - if (!UUIDHandlerImplementation.this.unknown.contains(offline)) { - offline = null; - } - } - if (offline != null && !offline.equals(uuid)) { - UUIDHandlerImplementation.this.unknown.remove(offline); - Set plots = PlotSquared.get().getPlotsAbs(offline); - if (!plots.isEmpty()) { - for (final Plot plot : plots) { - plot.setOwnerAbs(uuid); - } - DBFunc.replaceUUID(offline, uuid); - PlotSquared.debug("&cDetected invalid UUID stored for: " + name.value); - PlotSquared.debug( - "&7 - Did you recently switch to online-mode storage without running `uuidconvert`?"); - PlotSquared.debug("&6" + PlotSquared.imp().getPluginName() - + " will update incorrect entries when the user logs in, or you can reconstruct your database."); - } - } - }); - } else if (Settings.UUID.FORCE_LOWERCASE && !this.unknown.isEmpty() && !name.value - .equals(name.value.toLowerCase())) { - TaskManager.runTaskAsync(() -> { - UUID offlineUpper = UUID.nameUUIDFromBytes( - ("OfflinePlayer:" + name.value).getBytes(Charsets.UTF_8)); - if (UUIDHandlerImplementation.this.unknown.contains(offlineUpper) && !offlineUpper - .equals(uuid)) { - UUIDHandlerImplementation.this.unknown.remove(offlineUpper); - Set plots = PlotSquared.get().getPlotsAbs(offlineUpper); - if (!plots.isEmpty()) { - for (final Plot plot : plots) { - plot.setOwnerAbs(uuid); - } - replace(offlineUpper, uuid, name.value); - } - } - }); - } - try { - UUID existing = this.uuidMap.put(name, uuid); - if (existing != null) { - if (!existing.equals(uuid)) { - Set plots = PlotSquared.get().getPlots(existing); - if (!plots.isEmpty()) { - for (final Plot plot : plots) { - plot.setOwnerAbs(uuid); - } - replace(existing, uuid, name.value); - } - return true; - } else { - StringWrapper oName = this.uuidMap.inverse().get(existing); - if (!oName.equals(name)) { - this.uuidMap.remove(name); - this.uuidMap.put(name, uuid); - } - } - return false; - } - } catch (Exception ignored) { - BiMap inverse = this.uuidMap.inverse(); - StringWrapper oldName = inverse.get(uuid); - if (oldName != null) { - if (this.uuidMap.containsKey(name)) { - return false; - } - PlotPlayer player = getPlayer(uuid); - if (player == null || player.getName().equalsIgnoreCase(name.value)) { - rename(uuid, name); - return false; - } - StringWrapper newName = new StringWrapper(player.getName()); - UUID newUUID = player.getUUID(); - if (newUUID.equals(uuid) && !newName.equals(oldName)) { - inverse.remove(uuid); - this.uuidMap.put(newName, newUUID); - } - return false; - } - this.uuidMap.put(name, uuid); - } - return true; - } - - private void replace(UUID from, UUID to, String name) { - DBFunc.replaceUUID(from, to); - PlotSquared.debug("&cDetected invalid UUID stored for: " + name); - PlotSquared.debug( - "&7 - Did you recently switch to online-mode storage without running `uuidconvert`?"); - PlotSquared.debug("&6" + PlotSquared.imp().getPluginName() - + " will update incorrect entries when the user logs in, or you can reconstruct your database."); - } - - public boolean uuidExists(UUID uuid) { - return this.uuidMap.containsValue(uuid); - } - - public BiMap getUUIDMap() { - return this.uuidMap; - } - - public boolean nameExists(StringWrapper wrapper) { - return this.uuidMap.containsKey(wrapper); - } - - public void handleShutdown() { - this.players.clear(); - this.uuidMap.clear(); - } - - @Nullable public String getName(UUID uuid) { - if (uuid == null) { - return null; - } - StringWrapper name = this.uuidMap.inverse().get(uuid); - if (name != null) { - return name.value; - } - return null; - } - - @Nullable public UUID getUUID(String name, RunnableVal ifFetch) { - if (name.isEmpty()) { - return null; - } - // check online - PlotPlayer player = getPlayer(name); - if (player != null) { - return player.getUUID(); - } - // check cache - StringWrapper wrap = new StringWrapper(name); - UUID uuid = this.uuidMap.get(wrap); - if (uuid != null) { - return uuid; - } - // Read from disk OR convert directly to offline UUID - if (Settings.UUID.OFFLINE && !StringMan.contains(name, ';')) { - uuid = this.uuidWrapper.getUUID(name); - add(new StringWrapper(name), uuid); - return uuid; - } - if ((ifFetch != null)) { - fetchUUID(name, ifFetch); - return null; - } - return null; - } - - @NotNull public UUID getUUID(PlotPlayer player) { - return this.uuidWrapper.getUUID(player); - } - - public UUID getUUID(OfflinePlotPlayer player) { - return this.uuidWrapper.getUUID(player); - } - - @Nullable public PlotPlayer getPlayer(UUID uuid) { - String name = getName(uuid); - if (name != null) { - return getPlayer(name); - } - return null; - } - - public PlotPlayer getPlayer(String name) { - return this.players.get(name); - } - - public Map getPlayers() { - return this.players; - } - -} diff --git a/Core/src/main/java/com/plotsquared/core/uuid/CacheUUIDService.java b/Core/src/main/java/com/plotsquared/core/uuid/CacheUUIDService.java new file mode 100644 index 000000000..563618afa --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/uuid/CacheUUIDService.java @@ -0,0 +1,102 @@ +/* + * _____ _ _ _____ _ + * | __ \| | | | / ____| | | + * | |__) | | ___ | |_| (___ __ _ _ _ __ _ _ __ ___ __| | + * | ___/| |/ _ \| __|\___ \ / _` | | | |/ _` | '__/ _ \/ _` | + * | | | | (_) | |_ ____) | (_| | |_| | (_| | | | __/ (_| | + * |_| |_|\___/ \__|_____/ \__, |\__,_|\__,_|_| \___|\__,_| + * | | + * |_| + * PlotSquared plot management system for Minecraft + * Copyright (C) 2020 IntellectualSites + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.plotsquared.core.uuid; + +import com.google.common.cache.Cache; +import com.google.common.cache.CacheBuilder; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.UUID; +import java.util.function.Consumer; + +/** + * UUID service backed by a Guava Cache + */ +public class CacheUUIDService implements UUIDService, Consumer> { + + private final Cache usernameCache; + private final Cache uuidCache; + + /** + * Construct a new Cache UUID service with a maximum number of entries. + * Because it stores the mappings in two ways, the actual number + * of entries is two times the specified size + * + * @param size Maximum number of entries + */ + public CacheUUIDService(final int size) { + this.usernameCache = CacheBuilder.newBuilder().maximumSize(size).build(); + this.uuidCache = CacheBuilder.newBuilder().maximumSize(size).build(); + } + + @Override @NotNull public List getNames(@NotNull final List uuids) { + final List mappings = new ArrayList<>(uuids.size()); + mappings.addAll(this.uuidCache.getAllPresent(uuids).values()); + return mappings; + } + + @Override @NotNull public List getUUIDs(@NotNull final List usernames) { + final List mappings = new ArrayList<>(usernames.size()); + mappings.addAll(this.usernameCache.getAllPresent(usernames).values()); + return mappings; + } + + @Override public void accept(final List uuidMappings) { + for (final UUIDMapping mapping : uuidMappings) { + this.uuidCache.put(mapping.getUuid(), mapping); + this.usernameCache.put(mapping.getUsername(), mapping); + } + } + + @Override @NotNull public Collection getImmediately() { + return this.usernameCache.asMap().values(); + } + + @Override public boolean canBeSynchronous() { + return true; + } + + @Override @Nullable public UUIDMapping getImmediately(@NotNull final Object object) { + final List list; + if (object instanceof String) { + list = getUUIDs(Collections.singletonList((String) object)); + } else if (object instanceof UUID) { + list = getNames(Collections.singletonList((UUID) object)); + } else { + list = Collections.emptyList(); + } + if (list.isEmpty()) { + return null; + } + return list.get(0); + } + +} diff --git a/Core/src/main/java/com/plotsquared/core/uuid/ServiceError.java b/Core/src/main/java/com/plotsquared/core/uuid/ServiceError.java new file mode 100644 index 000000000..0e248a2c5 --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/uuid/ServiceError.java @@ -0,0 +1,47 @@ +/* + * _____ _ _ _____ _ + * | __ \| | | | / ____| | | + * | |__) | | ___ | |_| (___ __ _ _ _ __ _ _ __ ___ __| | + * | ___/| |/ _ \| __|\___ \ / _` | | | |/ _` | '__/ _ \/ _` | + * | | | | (_) | |_ ____) | (_| | |_| | (_| | | | __/ (_| | + * |_| |_|\___/ \__|_____/ \__, |\__,_|\__,_|_| \___|\__,_| + * | | + * |_| + * PlotSquared plot management system for Minecraft + * Copyright (C) 2020 IntellectualSites + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.plotsquared.core.uuid; + +import org.jetbrains.annotations.NotNull; + +/** + * Thrown by {@link ServiceError} when something goes wrong + */ +public class ServiceError extends RuntimeException { + + public ServiceError(@NotNull final String message) { + super(message); + } + + public ServiceError(@NotNull final String message, @NotNull final Throwable cause) { + super(message, cause); + } + + @Override public Throwable fillInStackTrace() { + return this; + } + +} diff --git a/Core/src/test/java/com/plotsquared/core/plot/util/UUIDHandlerImplementationTest.java b/Core/src/main/java/com/plotsquared/core/uuid/UUIDMapping.java similarity index 66% rename from Core/src/test/java/com/plotsquared/core/plot/util/UUIDHandlerImplementationTest.java rename to Core/src/main/java/com/plotsquared/core/uuid/UUIDMapping.java index 291461478..35a4c6c2c 100644 --- a/Core/src/test/java/com/plotsquared/core/plot/util/UUIDHandlerImplementationTest.java +++ b/Core/src/main/java/com/plotsquared/core/uuid/UUIDMapping.java @@ -23,28 +23,32 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ -package com.plotsquared.core.plot.util; +package com.plotsquared.core.uuid; -import com.plotsquared.core.database.AbstractDBTest; -import com.plotsquared.core.database.DBFunc; -import com.plotsquared.core.util.task.RunnableVal; -import com.plotsquared.core.util.uuid.UUIDHandlerImplementation; -import com.plotsquared.core.util.uuid.UUIDWrapper; -import org.junit.Before; +import lombok.EqualsAndHashCode; +import org.jetbrains.annotations.NotNull; import java.util.UUID; -public class UUIDHandlerImplementationTest extends UUIDHandlerImplementation { +/** + * A pair consisting of a UUID and a username + */ +@EqualsAndHashCode public class UUIDMapping { - public UUIDHandlerImplementationTest(UUIDWrapper wrapper) { - super(wrapper); + private final UUID uuid; + private final String username; + + public UUIDMapping(@NotNull final UUID uuid, final String username) { + this.uuid = uuid; + this.username = username; } - @Before public void setUp() throws Exception { - DBFunc.dbManager = new AbstractDBTest(); + @NotNull public String getUsername() { + return this.username; } - @Override public void fetchUUID(String name, RunnableVal ifFetch) { - + @NotNull public UUID getUuid() { + return this.uuid; } + } diff --git a/Core/src/main/java/com/plotsquared/core/uuid/UUIDPipeline.java b/Core/src/main/java/com/plotsquared/core/uuid/UUIDPipeline.java new file mode 100644 index 000000000..997cdfdc1 --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/uuid/UUIDPipeline.java @@ -0,0 +1,424 @@ +/* + * _____ _ _ _____ _ + * | __ \| | | | / ____| | | + * | |__) | | ___ | |_| (___ __ _ _ _ __ _ _ __ ___ __| | + * | ___/| |/ _ \| __|\___ \ / _` | | | |/ _` | '__/ _ \/ _` | + * | | | | (_) | |_ ____) | (_| | |_| | (_| | | | __/ (_| | + * |_| |_|\___/ \__|_____/ \__, |\__,_|\__,_|_| \___|\__,_| + * | | + * |_| + * PlotSquared plot management system for Minecraft + * Copyright (C) 2020 IntellectualSites + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.plotsquared.core.uuid; + +import com.google.common.collect.Lists; +import com.plotsquared.core.PlotSquared; +import com.plotsquared.core.configuration.Captions; +import com.plotsquared.core.configuration.Settings; +import com.plotsquared.core.util.ThreadUtils; +import com.plotsquared.core.util.task.TaskManager; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Set; +import java.util.UUID; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Executor; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +import java.util.function.BiConsumer; +import java.util.function.Consumer; +import java.util.function.Function; + +/** + * An UUID pipeline is essentially an ordered list of + * {@link UUIDService uuid services} that each get the + * opportunity of providing usernames or UUIDs. + *

+ * Each request is then passed through a secondary list of + * consumers, that can then be used to cache them, etc + */ +public class UUIDPipeline { + + private final Executor executor; + private final List serviceList; + private final List>> consumerList; + private final ScheduledExecutorService timeoutExecutor; + + /** + * Construct a new UUID pipeline + * + * @param executor Executor that is used to run asynchronous tasks inside + * of the pipeline + */ + public UUIDPipeline(@NotNull final Executor executor) { + this.executor = executor; + this.serviceList = Lists.newLinkedList(); + this.consumerList = Lists.newLinkedList(); + this.timeoutExecutor = Executors.newSingleThreadScheduledExecutor(); + } + + /** + * Register a UUID service + * + * @param uuidService UUID service to register + */ + public void registerService(@NotNull final UUIDService uuidService) { + this.serviceList.add(uuidService); + } + + /** + * Register a mapping consumer + * + * @param mappingConsumer Consumer to register + */ + public void registerConsumer(@NotNull final Consumer> mappingConsumer) { + this.consumerList.add(mappingConsumer); + } + + /** + * Get a copy of the service list + * + * @return Copy of service list + */ + public List getServiceListInstance() { + return Collections.unmodifiableList(this.serviceList); + } + + /** + * Let all consumers act on the given mapping. + * + * @param mappings Mappings + */ + public void consume(@NotNull final List mappings) { + final Runnable runnable = () -> { + for (final Consumer> consumer : this.consumerList) { + consumer.accept(mappings); + } + }; + if (PlotSquared.get().isMainThread(Thread.currentThread())) { + TaskManager.runTaskAsync(runnable); + } else { + runnable.run(); + } + } + + /** + * Consume a single mapping + * + * @param mapping Mapping to consume + */ + public void consume(@NotNull final UUIDMapping mapping) { + this.consume(Collections.singletonList(mapping)); + } + + /** + * This will store the given username-UUID pair directly, and overwrite + * any existing caches. This can be used to update usernames automatically + * whenever a player joins the server, to make sure an up-to-date UUID + * mapping is stored + * + * @param username Player username + * @param uuid Player uuid + */ + public void storeImmediately(@NotNull final String username, @NotNull final UUID uuid) { + this.consume(new UUIDMapping(uuid, username)); + } + + /** + * Get a single UUID from a username. This is blocking. + * + * @param username Username + * @param timeout Timeout in milliseconds + * @return The mapped uuid. Will return null if the request timed out. + */ + @Nullable public UUID getSingle(@NotNull final String username, final long timeout) { + ThreadUtils.catchSync("Blocking UUID retrieval from the main thread"); + try { + final List mappings = this.getUUIDs(Collections.singletonList(username)).get(timeout, TimeUnit.MILLISECONDS); + if (mappings.size() == 1) { + return mappings.get(0).getUuid(); + } + } catch (InterruptedException | ExecutionException e) { + e.printStackTrace(); + } catch (TimeoutException ignored) { + PlotSquared.log(Captions.PREFIX + " (UUID) Request for " + username + " timed out"); + // This is completely valid, we just don't care anymore + } + return null; + } + + /** + * Get a single username from a UUID. This is blocking. + * + * @param uuid UUID + * @param timeout Timeout in milliseconds + * @return The mapped username. Will return null if the request timeout. + */ + @Nullable public String getSingle(@NotNull final UUID uuid, final long timeout) { + ThreadUtils.catchSync("Blocking username retrieval from the main thread"); + try { + final List mappings = this.getNames(Collections.singletonList(uuid)).get(timeout, TimeUnit.MILLISECONDS); + if (mappings.size() == 1) { + return mappings.get(0).getUsername(); + } + } catch (InterruptedException | ExecutionException e) { + e.printStackTrace(); + } catch (TimeoutException ignored) { + PlotSquared.log(Captions.PREFIX + " (UUID) Request for " + uuid + " timed out"); + // This is completely valid, we just don't care anymore + } + return null; + } + + /** + * Get a single UUID from a username. This is non-blocking. + * + * @param username Username + * @param uuid UUID consumer + */ + public void getSingle(@NotNull final String username, + @NotNull final BiConsumer uuid) { + this.getUUIDs(Collections.singletonList(username)).applyToEither(timeoutAfter(Settings.UUID.NON_BLOCKING_TIMEOUT), Function.identity()) + .whenComplete((uuids, throwable) -> { + if (throwable != null) { + uuid.accept(null, throwable); + } else { + if (!uuids.isEmpty()) { + uuid.accept(uuids.get(0).getUuid(), null); + } else { + uuid.accept(null, null); + } + } + }); + } + + /** + * Get a single username from a UUID. This is non-blocking. + * + * @param uuid UUID + * @param username Username consumer + */ + public void getSingle(@NotNull final UUID uuid, + @NotNull final BiConsumer username) { + this.getNames(Collections.singletonList(uuid)).applyToEither(timeoutAfter(Settings.UUID.NON_BLOCKING_TIMEOUT), Function.identity()) + .whenComplete((uuids, throwable) -> { + if (throwable != null) { + username.accept(null, throwable); + } else { + if (!uuids.isEmpty()) { + username.accept(uuids.get(0).getUsername(), null); + } else { + username.accept(null, null); + } + } + }); + } + + /** + * Asynchronously attempt to fetch the mapping from a list of UUIDs. + *

+ * This will timeout after the specified time and throws a {@link TimeoutException} + * if this happens + * + * @param requests UUIDs + * @param timeout Timeout in milliseconds + * @return Mappings + */ + public CompletableFuture> getNames(@NotNull final Collection requests, + final long timeout) { + return this.getNames(requests).applyToEither(timeoutAfter(timeout), Function.identity()); + } + + /** + * Asynchronously attempt to fetch the mapping from a list of names. + *

+ * This will timeout after the specified time and throws a {@link TimeoutException} + * if this happens + * + * @param requests Names + * @param timeout Timeout in milliseconds + * @return Mappings + */ + public CompletableFuture> getUUIDs(@NotNull final Collection requests, + final long timeout) { + return this.getUUIDs(requests).applyToEither(timeoutAfter(timeout), Function.identity()); + } + + private CompletableFuture> timeoutAfter(final long timeout) { + final CompletableFuture> result = new CompletableFuture<>(); + this.timeoutExecutor.schedule(() -> result.completeExceptionally(new TimeoutException()), timeout, TimeUnit.MILLISECONDS); + return result; + } + + /** + * Asynchronously attempt to fetch the mapping from a list of UUIDs + * + * @param requests UUIDs + * @return Mappings + */ + public CompletableFuture> getNames(@NotNull final Collection requests) { + if (requests.isEmpty()) { + return CompletableFuture.completedFuture(Collections.emptyList()); + } + + final List serviceList = this.getServiceListInstance(); + final List mappings = new ArrayList<>(requests.size()); + final List remainingRequests = new ArrayList<>(requests); + + for (final UUIDService service : serviceList) { + // We can chain multiple synchronous + // ones in a row + if (service.canBeSynchronous()) { + final List completedRequests = service.getNames(remainingRequests); + for (final UUIDMapping mapping : completedRequests) { + remainingRequests.remove(mapping.getUuid()); + } + mappings.addAll(completedRequests); + } else { + break; + } + if (remainingRequests.isEmpty()) { + return CompletableFuture.completedFuture(mappings); + } + } + + return CompletableFuture.supplyAsync(() -> { + for (final UUIDService service : serviceList) { + final List completedRequests = service.getNames(remainingRequests); + for (final UUIDMapping mapping : completedRequests) { + remainingRequests.remove(mapping.getUuid()); + } + mappings.addAll(completedRequests); + if (remainingRequests.isEmpty()) { + break; + } + } + + if (mappings.size() == requests.size()) { + this.consume(mappings); + return mappings; + } else if (Settings.DEBUG) { + PlotSquared.log("Failed to find all usernames"); + } + + if (Settings.UUID.UNKNOWN_AS_DEFAULT) { + for (final UUID uuid : remainingRequests) { + mappings.add(new UUIDMapping(uuid, Captions.UNKNOWN.getTranslated())); + } + return mappings; + } else { + throw new ServiceError("End of pipeline"); + } + }, this.executor); + } + + /** + * Asynchronously attempt to fetch the mapping from a list of names + * + * @param requests Names + * @return Mappings + */ + public CompletableFuture> getUUIDs( + @NotNull final Collection requests) { + if (requests.isEmpty()) { + return CompletableFuture.completedFuture(Collections.emptyList()); + } + + final List serviceList = this.getServiceListInstance(); + final List mappings = new ArrayList<>(requests.size()); + final List remainingRequests = new ArrayList<>(requests); + + for (final UUIDService service : serviceList) { + // We can chain multiple synchronous + // ones in a row + if (service.canBeSynchronous()) { + final List completedRequests = service.getUUIDs(remainingRequests); + for (final UUIDMapping mapping : completedRequests) { + remainingRequests.remove(mapping.getUsername()); + } + mappings.addAll(completedRequests); + } else { + break; + } + if (remainingRequests.isEmpty()) { + return CompletableFuture.completedFuture(mappings); + } + } + + return CompletableFuture.supplyAsync(() -> { + for (final UUIDService service : serviceList) { + final List completedRequests = service.getUUIDs(remainingRequests); + for (final UUIDMapping mapping : completedRequests) { + remainingRequests.remove(mapping.getUsername()); + } + mappings.addAll(completedRequests); + if (remainingRequests.isEmpty()) { + break; + } + } + + if (mappings.size() == requests.size()) { + this.consume(mappings); + return mappings; + } else if (Settings.DEBUG) { + PlotSquared.log("Failed to find all UUIDs"); + } + + throw new ServiceError("End of pipeline"); + }, this.executor); + } + + /** + * Get as many UUID mappings as possible under the condition + * that the operation cannot be blocking (for an extended amount of time) + * + * @return All mappings that could be provided immediately + */ + @NotNull public final Collection getAllImmediately() { + final Set mappings = new LinkedHashSet<>(); + for (final UUIDService service : this.getServiceListInstance()) { + mappings.addAll(service.getImmediately()); + } + return mappings; + } + + /** + * Get a single UUID mapping immediately, if possible + * + * @param object Username ({@link String}) or {@link UUID} + * @return Mapping, if it could be found immediately + */ + @Nullable public final UUIDMapping getImmediately(@NotNull final Object object) { + for (final UUIDService uuidService : this.getServiceListInstance()) { + final UUIDMapping mapping = uuidService.getImmediately(object); + if (mapping != null) { + return mapping; + } + } + return null; + } + +} diff --git a/Core/src/main/java/com/plotsquared/core/uuid/UUIDService.java b/Core/src/main/java/com/plotsquared/core/uuid/UUIDService.java new file mode 100644 index 000000000..f6fe86f11 --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/uuid/UUIDService.java @@ -0,0 +1,89 @@ +/* + * _____ _ _ _____ _ + * | __ \| | | | / ____| | | + * | |__) | | ___ | |_| (___ __ _ _ _ __ _ _ __ ___ __| | + * | ___/| |/ _ \| __|\___ \ / _` | | | |/ _` | '__/ _ \/ _` | + * | | | | (_) | |_ ____) | (_| | |_| | (_| | | | __/ (_| | + * |_| |_|\___/ \__|_____/ \__, |\__,_|\__,_|_| \___|\__,_| + * | | + * |_| + * PlotSquared plot management system for Minecraft + * Copyright (C) 2020 IntellectualSites + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.plotsquared.core.uuid; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.UUID; + +/** + * Service used to provide usernames from player UUIDs + */ +public interface UUIDService { + + /** + * Attempt to complete the given requests. Returns the mappings + * that could be created by this server + * + * @param uuids Requests + * @return Completed requests + */ + @NotNull List getNames(@NotNull final List uuids); + + /** + * Attempt to complete the given requests. Returns the mappings + * that could be created by this server + * + * @param usernames Requests + * @return Completed requests + */ + @NotNull List getUUIDs(@NotNull final List usernames); + + /** + * Get as many UUID mappings as possible under the condition + * that the operation cannot be blocking (for an extended amount of time) + * + * @return All mappings that could be provided immediately + */ + default @NotNull Collection getImmediately() { + return Collections.emptyList(); + } + + /** + * Check whether or not this service can be safely used synchronously + * without blocking the server for an extended amount of time. + * + * @return True if the service can be used synchronously + */ + default boolean canBeSynchronous() { + return false; + } + + /** + * Get a single UUID mapping immediately, if possible + * + * @param object Username ({@link String}) or {@link UUID} + * @return Mapping, if it could be found immediately + */ + default @Nullable UUIDMapping getImmediately(@NotNull final Object object) { + return null; + } + +} diff --git a/Core/src/main/java/com/plotsquared/core/uuid/offline/OfflineModeUUIDService.java b/Core/src/main/java/com/plotsquared/core/uuid/offline/OfflineModeUUIDService.java new file mode 100644 index 000000000..49f038db8 --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/uuid/offline/OfflineModeUUIDService.java @@ -0,0 +1,64 @@ +/* + * _____ _ _ _____ _ + * | __ \| | | | / ____| | | + * | |__) | | ___ | |_| (___ __ _ _ _ __ _ _ __ ___ __| | + * | ___/| |/ _ \| __|\___ \ / _` | | | |/ _` | '__/ _ \/ _` | + * | | | | (_) | |_ ____) | (_| | |_| | (_| | | | __/ (_| | + * |_| |_|\___/ \__|_____/ \__, |\__,_|\__,_|_| \___|\__,_| + * | | + * |_| + * PlotSquared plot management system for Minecraft + * Copyright (C) 2020 IntellectualSites + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.plotsquared.core.uuid.offline; + +import com.google.common.base.Charsets; +import com.plotsquared.core.configuration.Settings; +import com.plotsquared.core.uuid.UUIDMapping; +import com.plotsquared.core.uuid.UUIDService; +import org.jetbrains.annotations.NotNull; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Locale; +import java.util.UUID; + +/** + * Name provider service that creates UUIDs from usernames + */ +public class OfflineModeUUIDService implements UUIDService { + + @NotNull protected final UUID getFromUsername(@NotNull String username) { + if (Settings.UUID.FORCE_LOWERCASE) { + username = username.toLowerCase(Locale.ENGLISH); + } + return UUID.nameUUIDFromBytes(("OfflinePlayer:" + username).getBytes(Charsets.UTF_8)); + } + + @Override @NotNull public List getNames(@NotNull final List uuids) { + return Collections.emptyList(); + } + + @Override @NotNull public List getUUIDs(@NotNull List usernames) { + final List mappings = new ArrayList<>(usernames.size()); + for (final String username : usernames) { + mappings.add(new UUIDMapping(getFromUsername(username), username)); + } + return mappings; + } + +} diff --git a/README.md b/README.md index 17dc0331c..64a012710 100644 --- a/README.md +++ b/README.md @@ -28,6 +28,7 @@ is to provide a lag-free and smooth experience. * [Download](https://www.spigotmc.org/resources/plotsquared-v5.77506/) * [Discord](https://discord.gg/KxkjDVg) * [Wiki](https://wiki.intellectualsites.com/plotsquared/home) +* [Issues](https://issues.intellectualsites.com/projects/ps) ### Developer Resources * [API Documentation](https://wiki.intellectualsites.com/en/plotsquared/developer/development-portal) diff --git a/build.gradle b/build.gradle index 2b26caee7..c55d34847 100644 --- a/build.gradle +++ b/build.gradle @@ -30,7 +30,7 @@ ext { git = Grgit.open(dir: new File(rootDir.toString() + "/.git")) } -def ver = "5.11.2" +def ver = "5.12.2" def versuffix = "" ext { if (project.hasProperty("versionsuffix")) { @@ -76,8 +76,10 @@ subprojects { delete("../target") } + javadoc.options.encoding = 'UTF-8' + dependencies { - compile group: 'org.json', name: 'json', version: '20190722' + compile group: 'org.json', name: 'json', version: '20200518' implementation("com.sk89q.worldedit:worldedit-core:7.0.0") { exclude(module: "bukkit-classloader-check") @@ -118,7 +120,7 @@ subprojects { shadowJar { dependencies { - include(dependency("org.json:json:20190722")) + include(dependency("org.json:json:20200518")) include(dependency("net.kyori:text-api:3.0.2")) } relocate("io.papermc.lib", "com.plotsquared.bukkit.paperlib") diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 4c5803d13..bb8b2fc26 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-6.4-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-6.5.1-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists