From 7591c440c25027d7eae435bedbee0cb83536dc0f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20S=C3=B6derberg?= Date: Sun, 17 May 2020 12:40:25 +0200 Subject: [PATCH 01/33] Begin working on the new UUID service API --- .../bukkit/util/uuid/OfflineUUIDWrapper.java | 2 +- .../com/plotsquared/core/api/PlotAPI.java | 4 +- .../com/plotsquared/core/command/Set.java | 1 - .../core/plot/comment/CommentManager.java | 3 +- .../core/plot/flag/FlagContainer.java | 6 +- .../plotsquared/core/plot/flag/PlotFlag.java | 3 +- .../plot/flag/types/BlockTypeWrapper.java | 30 ++-- .../core/util/uuid/UUIDWrapper.java | 14 +- .../plotsquared/core/uuid/ServiceError.java | 43 +++++ .../plotsquared/core/uuid/ServiceFailure.java | 49 ++++++ .../plotsquared/core/uuid/UUIDMapping.java | 53 ++++++ .../plotsquared/core/uuid/UUIDPipeline.java | 166 ++++++++++++++++++ .../plotsquared/core/uuid/UUIDService.java | 74 ++++++++ .../uuid/offline/OfflineModeUUIDService.java | 59 +++++++ 14 files changed, 472 insertions(+), 35 deletions(-) create mode 100644 Core/src/main/java/com/plotsquared/core/uuid/ServiceError.java create mode 100644 Core/src/main/java/com/plotsquared/core/uuid/ServiceFailure.java create mode 100644 Core/src/main/java/com/plotsquared/core/uuid/UUIDMapping.java create mode 100644 Core/src/main/java/com/plotsquared/core/uuid/UUIDPipeline.java create mode 100644 Core/src/main/java/com/plotsquared/core/uuid/UUIDService.java create mode 100644 Core/src/main/java/com/plotsquared/core/uuid/offline/OfflineModeUUIDService.java 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 index 66ca52814..405fb940d 100644 --- a/Bukkit/src/main/java/com/plotsquared/bukkit/util/uuid/OfflineUUIDWrapper.java +++ b/Bukkit/src/main/java/com/plotsquared/bukkit/util/uuid/OfflineUUIDWrapper.java @@ -46,7 +46,7 @@ import java.util.Arrays; import java.util.Collection; import java.util.UUID; -public class OfflineUUIDWrapper extends UUIDWrapper { +public class OfflineUUIDWrapper implements UUIDWrapper { private final Object[] arg = new Object[0]; private Method getOnline = null; 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..56e507873 100644 --- a/Core/src/main/java/com/plotsquared/core/api/PlotAPI.java +++ b/Core/src/main/java/com/plotsquared/core/api/PlotAPI.java @@ -60,9 +60,7 @@ import java.util.UUID; * * @version 5 */ -@SuppressWarnings({"unused", "WeakerAccess"}) -@NoArgsConstructor -public class PlotAPI { +@SuppressWarnings({"unused", "WeakerAccess"}) @NoArgsConstructor public class PlotAPI { /** * Gets all plots. 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..413ae3e4b 100644 --- a/Core/src/main/java/com/plotsquared/core/command/Set.java +++ b/Core/src/main/java/com/plotsquared/core/command/Set.java @@ -76,7 +76,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 = 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..1e945a8bb 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<>(); 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/util/uuid/UUIDWrapper.java b/Core/src/main/java/com/plotsquared/core/util/uuid/UUIDWrapper.java index 14c5a03ce..b2e8e0227 100644 --- a/Core/src/main/java/com/plotsquared/core/util/uuid/UUIDWrapper.java +++ b/Core/src/main/java/com/plotsquared/core/util/uuid/UUIDWrapper.java @@ -31,17 +31,17 @@ import org.jetbrains.annotations.NotNull; import java.util.UUID; -public abstract class UUIDWrapper { +public interface UUIDWrapper { - @NotNull public abstract UUID getUUID(PlotPlayer player); + @NotNull UUID getUUID(PlotPlayer player); - public abstract UUID getUUID(OfflinePlotPlayer player); + UUID getUUID(OfflinePlotPlayer player); - public abstract UUID getUUID(String name); + UUID getUUID(String name); - public abstract OfflinePlotPlayer getOfflinePlayer(UUID uuid); + OfflinePlotPlayer getOfflinePlayer(UUID uuid); - public abstract OfflinePlotPlayer getOfflinePlayer(String name); + OfflinePlotPlayer getOfflinePlayer(String name); - public abstract OfflinePlotPlayer[] getOfflinePlayers(); + OfflinePlotPlayer[] getOfflinePlayers(); } 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..b33bd1509 --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/uuid/ServiceError.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.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); + } + +} diff --git a/Core/src/main/java/com/plotsquared/core/uuid/ServiceFailure.java b/Core/src/main/java/com/plotsquared/core/uuid/ServiceFailure.java new file mode 100644 index 000000000..a2ce41555 --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/uuid/ServiceFailure.java @@ -0,0 +1,49 @@ +/* + * _____ _ _ _____ _ + * | __ \| | | | / ____| | | + * | |__) | | ___ | |_| (___ __ _ _ _ __ _ _ __ ___ __| | + * | ___/| |/ _ \| __|\___ \ / _` | | | |/ _` | '__/ _ \/ _` | + * | | | | (_) | |_ ____) | (_| | |_| | (_| | | | __/ (_| | + * |_| |_|\___/ \__|_____/ \__, |\__,_|\__,_|_| \___|\__,_| + * | | + * |_| + * 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 java.util.concurrent.CompletableFuture; + +/** + * Thrown by a {@link UUIDService} when it cannot + * complete a request. This is not an error and + * will be dealt with silently. + */ +public class ServiceFailure extends Throwable { + + private static final ServiceFailure instance = new ServiceFailure(); + + public static CompletableFuture getFuture() { + final CompletableFuture completableFuture = new CompletableFuture<>(); + completableFuture.completeExceptionally(instance); + return completableFuture; + } + + @Override public Throwable fillInStackTrace() { + return this; + } + +} diff --git a/Core/src/main/java/com/plotsquared/core/uuid/UUIDMapping.java b/Core/src/main/java/com/plotsquared/core/uuid/UUIDMapping.java new file mode 100644 index 000000000..798d586ff --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/uuid/UUIDMapping.java @@ -0,0 +1,53 @@ +/* + * _____ _ _ _____ _ + * | __ \| | | | / ____| | | + * | |__) | | ___ | |_| (___ __ _ _ _ __ _ _ __ ___ __| | + * | ___/| |/ _ \| __|\___ \ / _` | | | |/ _` | '__/ _ \/ _` | + * | | | | (_) | |_ ____) | (_| | |_| | (_| | | | __/ (_| | + * |_| |_|\___/ \__|_____/ \__, |\__,_|\__,_|_| \___|\__,_| + * | | + * |_| + * 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 java.util.UUID; + +/** + * A pair consisting of a UUID and a username + */ +public class UUIDMapping { + + private final UUID uuid; + private final String username; + + public UUIDMapping(@NotNull final UUID uuid, final String username) { + this.uuid = uuid; + this.username = username; + } + + @NotNull public String getUsername() { + return this.username; + } + + @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..022bb687a --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/uuid/UUIDPipeline.java @@ -0,0 +1,166 @@ +/* + * _____ _ _ _____ _ + * | __ \| | | | / ____| | | + * | |__) | | ___ | |_| (___ __ _ _ _ __ _ _ __ ___ __| | + * | ___/| |/ _ \| __|\___ \ / _` | | | |/ _` | '__/ _ \/ _` | + * | | | | (_) | |_ ____) | (_| | |_| | (_| | | | __/ (_| | + * |_| |_|\___/ \__|_____/ \__, |\__,_|\__,_|_| \___|\__,_| + * | | + * |_| + * 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 org.jetbrains.annotations.NotNull; + +import java.util.List; +import java.util.ListIterator; +import java.util.UUID; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.Executor; +import java.util.function.Consumer; + +/** + * 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; + + public UUIDPipeline(@NotNull final Executor executor) { + this.executor = executor; + this.serviceList = Lists.newLinkedList(); + this.consumerList = Lists.newLinkedList(); + } + + /** + * 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() { + final List serviceList = Lists.newLinkedList(this.serviceList); + serviceList.add(EndOfPipeline.instance); + return serviceList; + } + + private void consume(@NotNull final UUIDMapping mapping) { + for (final Consumer consumer : this.consumerList) { + consumer.accept(mapping); + } + } + + /** + * Asynchronously attempt to fetch the mapping from a given UUID or username + * + * @param request UUID or username + * @return Future that may complete with the mapping + */ + public CompletableFuture get(@NotNull final Object request) { + if (!(request instanceof String) && !(request instanceof UUID)) { + throw new IllegalArgumentException("Request has to be either a username or UUID"); + } + final CompletableFuture future = new CompletableFuture<>(); + final ListIterator serviceListIterator + = this.getServiceListInstance().listIterator(); + final Runnable[] runnable = new Runnable[1]; + runnable[0] = () -> { + if (serviceListIterator.hasNext()) { + final UUIDService uuidService = serviceListIterator.next(); + uuidService.get(request).whenCompleteAsync(((result, throwable) -> { + if (throwable != null) { + if (throwable instanceof ServiceFailure) { + try { + runnable[0].run(); + } catch (final Throwable inner) { + future.completeExceptionally(inner); + } + } else { + future.completeExceptionally(throwable); + } + } else { + final String username = request instanceof String ? (String) request + : (String) result; + final UUID uuid = request instanceof UUID ? (UUID) request + : (UUID) result; + final UUIDMapping mapping = new UUIDMapping(uuid, username); + future.complete(mapping); + this.consume(mapping); + } + }), this.executor); + } else { + throw new ServiceError("Pipeline is incomplete"); + } + }; + try { + // Start the pipeline traversal + runnable[0].run(); + } catch (final Throwable throwable) { + future.completeExceptionally(throwable); + } + return future; + } + + /** + * Indicates that the end of the pipeline has been reached, this + * will cause the request to fail, as no service was able to + * fulfil the request + */ + private static class EndOfPipeline implements UUIDService { + + public static final EndOfPipeline instance = new EndOfPipeline(); + + @Override @NotNull public CompletableFuture get(@NotNull final UUID uuid) { + final CompletableFuture future = new CompletableFuture<>(); + future.completeExceptionally(new ServiceError("End of pipeline")); + return future; + } + + @Override @NotNull public CompletableFuture get(@NotNull final String username) { + final CompletableFuture future = new CompletableFuture<>(); + future.completeExceptionally(new ServiceError("End of pipeline")); + return future; + } + } + +} 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..98f58b9c4 --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/uuid/UUIDService.java @@ -0,0 +1,74 @@ +/* + * _____ _ _ _____ _ + * | __ \| | | | / ____| | | + * | |__) | | ___ | |_| (___ __ _ _ _ __ _ _ __ ___ __| | + * | ___/| |/ _ \| __|\___ \ / _` | | | |/ _` | '__/ _ \/ _` | + * | | | | (_) | |_ ____) | (_| | |_| | (_| | | | __/ (_| | + * |_| |_|\___/ \__|_____/ \__, |\__,_|\__,_|_| \___|\__,_| + * | | + * |_| + * 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 java.util.UUID; +import java.util.concurrent.CompletableFuture; + +/** + * Service used to provide usernames from player UUIDs + */ +public interface UUIDService { + + default CompletableFuture get(@NotNull final Object request) { + if (request instanceof UUID) { + return get((UUID) request); + } else if (request instanceof String) { + return get((String) request); + } else { + throw new IllegalArgumentException("Request has to be either a username or UUID"); + } + } + + /** + * Get a stored username from the service if it exists. + * This should not trigger any fetching of + * usernames from other services. + *

+ * If the username isn't stored in this service, + * this completes with an empty optional. + * + * @param uuid Player UUID + * @return Future that may contain the username if it exists + */ + @NotNull CompletableFuture get(@NotNull final UUID uuid); + + /** + * Get a stored UUID from the service if it exists. + * This should not trigger any fetching of + * UUID from other services. + *

+ * If the UUID isn't stored in this service, + * this completes with an empty optional. + * + * @param username Player username + * @return Future that may contain the UUID if it exists + */ + @NotNull CompletableFuture get(@NotNull final String username); + +} 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..a58ab0863 --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/uuid/offline/OfflineModeUUIDService.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.core.uuid.offline; + +import com.google.common.base.Charsets; +import com.plotsquared.core.configuration.Settings; +import com.plotsquared.core.uuid.ServiceFailure; +import com.plotsquared.core.uuid.UUIDService; +import org.jetbrains.annotations.NotNull; + +import java.util.Locale; +import java.util.UUID; +import java.util.concurrent.CompletableFuture; + +/** + * 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 CompletableFuture get(@NotNull final UUID uuid) { + // This service can only get UUIDs from usernames + return ServiceFailure.getFuture(); + } + + @Override @NotNull public CompletableFuture get(@NotNull final String username) { + return CompletableFuture.completedFuture(this.getFromUsername(username)); + } + +} From 792fa1f11dbbba13fcbbe5ea43e9094d02fbad38 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20S=C3=B6derberg?= Date: Sun, 17 May 2020 12:55:07 +0200 Subject: [PATCH 02/33] Improve design --- .../plotsquared/core/uuid/ServiceFailure.java | 49 ---------- .../plotsquared/core/uuid/UUIDPipeline.java | 89 ++++++------------- .../plotsquared/core/uuid/UUIDService.java | 12 +-- .../uuid/offline/OfflineModeUUIDService.java | 12 ++- 4 files changed, 36 insertions(+), 126 deletions(-) delete mode 100644 Core/src/main/java/com/plotsquared/core/uuid/ServiceFailure.java diff --git a/Core/src/main/java/com/plotsquared/core/uuid/ServiceFailure.java b/Core/src/main/java/com/plotsquared/core/uuid/ServiceFailure.java deleted file mode 100644 index a2ce41555..000000000 --- a/Core/src/main/java/com/plotsquared/core/uuid/ServiceFailure.java +++ /dev/null @@ -1,49 +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.uuid; - -import java.util.concurrent.CompletableFuture; - -/** - * Thrown by a {@link UUIDService} when it cannot - * complete a request. This is not an error and - * will be dealt with silently. - */ -public class ServiceFailure extends Throwable { - - private static final ServiceFailure instance = new ServiceFailure(); - - public static CompletableFuture getFuture() { - final CompletableFuture completableFuture = new CompletableFuture<>(); - completableFuture.completeExceptionally(instance); - return completableFuture; - } - - @Override public Throwable fillInStackTrace() { - return this; - } - -} diff --git a/Core/src/main/java/com/plotsquared/core/uuid/UUIDPipeline.java b/Core/src/main/java/com/plotsquared/core/uuid/UUIDPipeline.java index 022bb687a..87ef3f529 100644 --- a/Core/src/main/java/com/plotsquared/core/uuid/UUIDPipeline.java +++ b/Core/src/main/java/com/plotsquared/core/uuid/UUIDPipeline.java @@ -28,8 +28,11 @@ package com.plotsquared.core.uuid; import com.google.common.collect.Lists; import org.jetbrains.annotations.NotNull; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; import java.util.List; -import java.util.ListIterator; +import java.util.Optional; import java.util.UUID; import java.util.concurrent.CompletableFuture; import java.util.concurrent.Executor; @@ -79,9 +82,7 @@ public class UUIDPipeline { * @return Copy of service list */ public List getServiceListInstance() { - final List serviceList = Lists.newLinkedList(this.serviceList); - serviceList.add(EndOfPipeline.instance); - return serviceList; + return Collections.unmodifiableList(this.serviceList); } private void consume(@NotNull final UUIDMapping mapping) { @@ -93,74 +94,34 @@ public class UUIDPipeline { /** * Asynchronously attempt to fetch the mapping from a given UUID or username * - * @param request UUID or username + * @param requests UUIDs or usernames * @return Future that may complete with the mapping */ - public CompletableFuture get(@NotNull final Object request) { - if (!(request instanceof String) && !(request instanceof UUID)) { - throw new IllegalArgumentException("Request has to be either a username or UUID"); - } - final CompletableFuture future = new CompletableFuture<>(); - final ListIterator serviceListIterator - = this.getServiceListInstance().listIterator(); - final Runnable[] runnable = new Runnable[1]; - runnable[0] = () -> { - if (serviceListIterator.hasNext()) { - final UUIDService uuidService = serviceListIterator.next(); - uuidService.get(request).whenCompleteAsync(((result, throwable) -> { - if (throwable != null) { - if (throwable instanceof ServiceFailure) { - try { - runnable[0].run(); - } catch (final Throwable inner) { - future.completeExceptionally(inner); - } - } else { - future.completeExceptionally(throwable); - } - } else { + public CompletableFuture> get(@NotNull final Collection requests) { + final List serviceList = this.getServiceListInstance(); + return CompletableFuture.supplyAsync(() -> { + final List mappings = new ArrayList<>(requests.size()); + outer: for (final Object request : requests) { + if (!(request instanceof String) && !(request instanceof UUID)) { + throw new IllegalArgumentException("Request has to be either a username or UUID"); + } + for (final UUIDService service : serviceList) { + final Optional result = service.get(request); + if (result.isPresent()) { final String username = request instanceof String ? (String) request - : (String) result; + : (String) result.get(); final UUID uuid = request instanceof UUID ? (UUID) request - : (UUID) result; + : (UUID) result.get(); final UUIDMapping mapping = new UUIDMapping(uuid, username); - future.complete(mapping); this.consume(mapping); + mappings.add(mapping); + continue outer; } - }), this.executor); - } else { - throw new ServiceError("Pipeline is incomplete"); + } + throw new ServiceError("End of pipeline"); } - }; - try { - // Start the pipeline traversal - runnable[0].run(); - } catch (final Throwable throwable) { - future.completeExceptionally(throwable); - } - return future; - } - - /** - * Indicates that the end of the pipeline has been reached, this - * will cause the request to fail, as no service was able to - * fulfil the request - */ - private static class EndOfPipeline implements UUIDService { - - public static final EndOfPipeline instance = new EndOfPipeline(); - - @Override @NotNull public CompletableFuture get(@NotNull final UUID uuid) { - final CompletableFuture future = new CompletableFuture<>(); - future.completeExceptionally(new ServiceError("End of pipeline")); - return future; - } - - @Override @NotNull public CompletableFuture get(@NotNull final String username) { - final CompletableFuture future = new CompletableFuture<>(); - future.completeExceptionally(new ServiceError("End of pipeline")); - return future; - } + return mappings; + }, this.executor); } } diff --git a/Core/src/main/java/com/plotsquared/core/uuid/UUIDService.java b/Core/src/main/java/com/plotsquared/core/uuid/UUIDService.java index 98f58b9c4..db29480d7 100644 --- a/Core/src/main/java/com/plotsquared/core/uuid/UUIDService.java +++ b/Core/src/main/java/com/plotsquared/core/uuid/UUIDService.java @@ -27,15 +27,15 @@ package com.plotsquared.core.uuid; import org.jetbrains.annotations.NotNull; +import java.util.Optional; import java.util.UUID; -import java.util.concurrent.CompletableFuture; /** * Service used to provide usernames from player UUIDs */ public interface UUIDService { - default CompletableFuture get(@NotNull final Object request) { + default Optional get(@NotNull final Object request) { if (request instanceof UUID) { return get((UUID) request); } else if (request instanceof String) { @@ -54,9 +54,9 @@ public interface UUIDService { * this completes with an empty optional. * * @param uuid Player UUID - * @return Future that may contain the username if it exists + * @return Optional that may contain the username if it exists */ - @NotNull CompletableFuture get(@NotNull final UUID uuid); + @NotNull Optional get(@NotNull final UUID uuid); /** * Get a stored UUID from the service if it exists. @@ -67,8 +67,8 @@ public interface UUIDService { * this completes with an empty optional. * * @param username Player username - * @return Future that may contain the UUID if it exists + * @return Optional that may contain the UUID if it exists */ - @NotNull CompletableFuture get(@NotNull final String username); + @NotNull Optional get(@NotNull final String username); } 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 index a58ab0863..7e397119e 100644 --- a/Core/src/main/java/com/plotsquared/core/uuid/offline/OfflineModeUUIDService.java +++ b/Core/src/main/java/com/plotsquared/core/uuid/offline/OfflineModeUUIDService.java @@ -27,13 +27,12 @@ package com.plotsquared.core.uuid.offline; import com.google.common.base.Charsets; import com.plotsquared.core.configuration.Settings; -import com.plotsquared.core.uuid.ServiceFailure; import com.plotsquared.core.uuid.UUIDService; import org.jetbrains.annotations.NotNull; import java.util.Locale; +import java.util.Optional; import java.util.UUID; -import java.util.concurrent.CompletableFuture; /** * Name provider service that creates UUIDs from usernames @@ -47,13 +46,12 @@ public class OfflineModeUUIDService implements UUIDService { return UUID.nameUUIDFromBytes(("OfflinePlayer:" + username).getBytes(Charsets.UTF_8)); } - @Override @NotNull public CompletableFuture get(@NotNull final UUID uuid) { - // This service can only get UUIDs from usernames - return ServiceFailure.getFuture(); + @Override @NotNull public Optional get(@NotNull final UUID uuid) { + return Optional.empty(); } - @Override @NotNull public CompletableFuture get(@NotNull final String username) { - return CompletableFuture.completedFuture(this.getFromUsername(username)); + @Override @NotNull public Optional get(@NotNull final String username) { + return Optional.of(this.getFromUsername(username)); } } From 29f2863cf41d2392800e596b64f5e4c28844c999 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20S=C3=B6derberg?= Date: Sun, 17 May 2020 17:26:48 +0200 Subject: [PATCH 03/33] Progress --- Bukkit/build.gradle | 3 + Bukkit/pom.xml | 6 ++ .../bukkit/uuid/OfflinePlayerUUIDService.java | 57 ++++++++++++ .../bukkit/uuid/PaperUUIDService.java | 65 ++++++++++++++ .../bukkit/uuid/SquirrelIdUUIDService.java | 90 +++++++++++++++++++ .../plotsquared/core/uuid/UUIDPipeline.java | 68 +++++++++----- .../plotsquared/core/uuid/UUIDService.java | 46 +++------- .../uuid/offline/OfflineModeUUIDService.java | 17 ++-- 8 files changed, 292 insertions(+), 60 deletions(-) create mode 100644 Bukkit/src/main/java/com/plotsquared/bukkit/uuid/OfflinePlayerUUIDService.java create mode 100644 Bukkit/src/main/java/com/plotsquared/bukkit/uuid/PaperUUIDService.java create mode 100644 Bukkit/src/main/java/com/plotsquared/bukkit/uuid/SquirrelIdUUIDService.java diff --git a/Bukkit/build.gradle b/Bukkit/build.gradle index 9fa1f8cf1..9b6b862a6 100644 --- a/Bukkit/build.gradle +++ b/Bukkit/build.gradle @@ -31,6 +31,7 @@ dependencies { } implementation("me.clip:placeholderapi:2.10.4") compile("se.hyperver.hyperverse:Core:0.6.0-SNAPSHOT"){ transitive = false } + compile 'com.github.pavog:SquirrelID:0.6.1' } sourceCompatibility = 1.8 @@ -87,10 +88,12 @@ 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("com.github.pavog:SquirrelID:0.6.1")) } 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') archiveFileName = "${project.name}-${parent.version}.jar" destinationDirectory = file "../target" } diff --git a/Bukkit/pom.xml b/Bukkit/pom.xml index 40202c32e..1eace8462 100644 --- a/Bukkit/pom.xml +++ b/Bukkit/pom.xml @@ -59,6 +59,12 @@ Core 0.6.0-SNAPSHOT compile + + + * + * + + com.sk89q.worldedit 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..8ba2ad76b --- /dev/null +++ b/Bukkit/src/main/java/com/plotsquared/bukkit/uuid/OfflinePlayerUUIDService.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.bukkit.uuid; + +import com.plotsquared.core.uuid.UUIDService; +import org.bukkit.Bukkit; +import org.bukkit.OfflinePlayer; +import org.jetbrains.annotations.NotNull; + +import java.util.Optional; +import java.util.UUID; + +/** + * UUID service that use {@link org.bukkit.OfflinePlayer offline players} + */ +public class OfflinePlayerUUIDService implements UUIDService { + + @Override @NotNull public Optional get(@NotNull final UUID uuid) { + final OfflinePlayer offlinePlayer = Bukkit.getOfflinePlayer(uuid); + if (offlinePlayer.hasPlayedBefore()) { + return Optional.ofNullable(offlinePlayer.getName()); + } + return Optional.empty(); + } + + @Override @NotNull public Optional get(@NotNull final String username) { + final OfflinePlayer offlinePlayer = Bukkit.getOfflinePlayer(username); + if (offlinePlayer.hasPlayedBefore()) { + return Optional.of(offlinePlayer.getUniqueId()); + } + return Optional.empty(); + } + +} 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/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/Core/src/main/java/com/plotsquared/core/uuid/UUIDPipeline.java b/Core/src/main/java/com/plotsquared/core/uuid/UUIDPipeline.java index 87ef3f529..64da919f4 100644 --- a/Core/src/main/java/com/plotsquared/core/uuid/UUIDPipeline.java +++ b/Core/src/main/java/com/plotsquared/core/uuid/UUIDPipeline.java @@ -32,7 +32,6 @@ import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.List; -import java.util.Optional; import java.util.UUID; import java.util.concurrent.CompletableFuture; import java.util.concurrent.Executor; @@ -92,35 +91,58 @@ public class UUIDPipeline { } /** - * Asynchronously attempt to fetch the mapping from a given UUID or username + * Asynchronously attempt to fetch the mapping from a list of UUIDs * - * @param requests UUIDs or usernames - * @return Future that may complete with the mapping + * @param requests UUIDs + * @return Mappings */ - public CompletableFuture> get(@NotNull final Collection requests) { + public CompletableFuture> getNames(@NotNull final Collection requests) { final List serviceList = this.getServiceListInstance(); return CompletableFuture.supplyAsync(() -> { final List mappings = new ArrayList<>(requests.size()); - outer: for (final Object request : requests) { - if (!(request instanceof String) && !(request instanceof UUID)) { - throw new IllegalArgumentException("Request has to be either a username or UUID"); + final List remainingRequests = new ArrayList<>(requests); + + for (final UUIDService service : serviceList) { + final List completedRequests = service.getNames(remainingRequests); + for (final UUIDMapping mapping : completedRequests) { + remainingRequests.remove(mapping.getUuid()); } - for (final UUIDService service : serviceList) { - final Optional result = service.get(request); - if (result.isPresent()) { - final String username = request instanceof String ? (String) request - : (String) result.get(); - final UUID uuid = request instanceof UUID ? (UUID) request - : (UUID) result.get(); - final UUIDMapping mapping = new UUIDMapping(uuid, username); - this.consume(mapping); - mappings.add(mapping); - continue outer; - } - } - throw new ServiceError("End of pipeline"); + mappings.addAll(completedRequests); } - return mappings; + + if (mappings.size() == requests.size()) { + return mappings; + } + + 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) { + final List serviceList = this.getServiceListInstance(); + return CompletableFuture.supplyAsync(() -> { + final List mappings = new ArrayList<>(requests.size()); + final List remainingRequests = new ArrayList<>(requests); + + for (final UUIDService service : serviceList) { + final List completedRequests = service.getUUIDs(remainingRequests); + for (final UUIDMapping mapping : completedRequests) { + remainingRequests.remove(mapping.getUsername()); + } + mappings.addAll(completedRequests); + } + + if (mappings.size() == requests.size()) { + return mappings; + } + + throw new ServiceError("End of pipeline"); }, this.executor); } diff --git a/Core/src/main/java/com/plotsquared/core/uuid/UUIDService.java b/Core/src/main/java/com/plotsquared/core/uuid/UUIDService.java index db29480d7..468de09b2 100644 --- a/Core/src/main/java/com/plotsquared/core/uuid/UUIDService.java +++ b/Core/src/main/java/com/plotsquared/core/uuid/UUIDService.java @@ -27,7 +27,7 @@ package com.plotsquared.core.uuid; import org.jetbrains.annotations.NotNull; -import java.util.Optional; +import java.util.List; import java.util.UUID; /** @@ -35,40 +35,22 @@ import java.util.UUID; */ public interface UUIDService { - default Optional get(@NotNull final Object request) { - if (request instanceof UUID) { - return get((UUID) request); - } else if (request instanceof String) { - return get((String) request); - } else { - throw new IllegalArgumentException("Request has to be either a username or UUID"); - } - } + /** + * 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); /** - * Get a stored username from the service if it exists. - * This should not trigger any fetching of - * usernames from other services. - *

- * If the username isn't stored in this service, - * this completes with an empty optional. + * Attempt to complete the given requests. Returns the mappings + * that could be created by this server * - * @param uuid Player UUID - * @return Optional that may contain the username if it exists + * @param usernames Requests + * @return Completed requests */ - @NotNull Optional get(@NotNull final UUID uuid); - - /** - * Get a stored UUID from the service if it exists. - * This should not trigger any fetching of - * UUID from other services. - *

- * If the UUID isn't stored in this service, - * this completes with an empty optional. - * - * @param username Player username - * @return Optional that may contain the UUID if it exists - */ - @NotNull Optional get(@NotNull final String username); + @NotNull List getUUIDs(@NotNull final List usernames); } 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 index 7e397119e..49f038db8 100644 --- a/Core/src/main/java/com/plotsquared/core/uuid/offline/OfflineModeUUIDService.java +++ b/Core/src/main/java/com/plotsquared/core/uuid/offline/OfflineModeUUIDService.java @@ -27,11 +27,14 @@ 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.Optional; import java.util.UUID; /** @@ -46,12 +49,16 @@ public class OfflineModeUUIDService implements UUIDService { return UUID.nameUUIDFromBytes(("OfflinePlayer:" + username).getBytes(Charsets.UTF_8)); } - @Override @NotNull public Optional get(@NotNull final UUID uuid) { - return Optional.empty(); + @Override @NotNull public List getNames(@NotNull final List uuids) { + return Collections.emptyList(); } - @Override @NotNull public Optional get(@NotNull final String username) { - return Optional.of(this.getFromUsername(username)); + @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; } } From 64cfe240f9292cc300d1a3335aebdcc3e2577999 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20S=C3=B6derberg?= Date: Sun, 17 May 2020 17:36:12 +0200 Subject: [PATCH 04/33] Port OfflinePlayerUUIDService to the new system --- .../bukkit/uuid/OfflinePlayerUUIDService.java | 30 ++++++++++++------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/Bukkit/src/main/java/com/plotsquared/bukkit/uuid/OfflinePlayerUUIDService.java b/Bukkit/src/main/java/com/plotsquared/bukkit/uuid/OfflinePlayerUUIDService.java index 8ba2ad76b..403832f38 100644 --- a/Bukkit/src/main/java/com/plotsquared/bukkit/uuid/OfflinePlayerUUIDService.java +++ b/Bukkit/src/main/java/com/plotsquared/bukkit/uuid/OfflinePlayerUUIDService.java @@ -25,12 +25,14 @@ */ package com.plotsquared.bukkit.uuid; +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.Optional; +import java.util.ArrayList; +import java.util.List; import java.util.UUID; /** @@ -38,20 +40,26 @@ import java.util.UUID; */ public class OfflinePlayerUUIDService implements UUIDService { - @Override @NotNull public Optional get(@NotNull final UUID uuid) { - final OfflinePlayer offlinePlayer = Bukkit.getOfflinePlayer(uuid); - if (offlinePlayer.hasPlayedBefore()) { - return Optional.ofNullable(offlinePlayer.getName()); + @Override public @NotNull List getNames(@NotNull List uuids) { + final List wrappers = new ArrayList<>(uuids.size()); + for (final UUID uuid : uuids) { + final OfflinePlayer offlinePlayer = Bukkit.getOfflinePlayer(uuid); + if (offlinePlayer.hasPlayedBefore()) { + wrappers.add(new UUIDMapping(uuid, offlinePlayer.getName())); + } } - return Optional.empty(); + return wrappers; } - @Override @NotNull public Optional get(@NotNull final String username) { - final OfflinePlayer offlinePlayer = Bukkit.getOfflinePlayer(username); - if (offlinePlayer.hasPlayedBefore()) { - return Optional.of(offlinePlayer.getUniqueId()); + @Override public @NotNull List getUUIDs(@NotNull List usernames) { + final List wrappers = new ArrayList<>(usernames.size()); + for (final String username : usernames) { + final OfflinePlayer offlinePlayer = Bukkit.getOfflinePlayer(username); + if (offlinePlayer.hasPlayedBefore()) { + wrappers.add(new UUIDMapping(offlinePlayer.getUniqueId(), offlinePlayer.getName())); + } } - return Optional.empty(); + return wrappers; } } From 95df62e59b2b19fbb8eb260ce3084d616d63289e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20S=C3=B6derberg?= Date: Sun, 17 May 2020 17:48:42 +0200 Subject: [PATCH 05/33] Add missing consumer API methods --- .../plotsquared/core/uuid/UUIDPipeline.java | 60 ++++++++++++++++--- 1 file changed, 53 insertions(+), 7 deletions(-) diff --git a/Core/src/main/java/com/plotsquared/core/uuid/UUIDPipeline.java b/Core/src/main/java/com/plotsquared/core/uuid/UUIDPipeline.java index 64da919f4..0df18ea94 100644 --- a/Core/src/main/java/com/plotsquared/core/uuid/UUIDPipeline.java +++ b/Core/src/main/java/com/plotsquared/core/uuid/UUIDPipeline.java @@ -26,6 +26,8 @@ package com.plotsquared.core.uuid; import com.google.common.collect.Lists; +import com.plotsquared.core.PlotSquared; +import com.plotsquared.core.util.task.TaskManager; import org.jetbrains.annotations.NotNull; import java.util.ArrayList; @@ -49,8 +51,14 @@ public class UUIDPipeline { private final Executor executor; private final List serviceList; - private final List> consumerList; + private final List>> consumerList; + /** + * 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(); @@ -71,7 +79,7 @@ public class UUIDPipeline { * * @param mappingConsumer Consumer to register */ - public void registerConsumer(@NotNull final Consumer mappingConsumer) { + public void registerConsumer(@NotNull final Consumer> mappingConsumer) { this.consumerList.add(mappingConsumer); } @@ -84,19 +92,54 @@ public class UUIDPipeline { return Collections.unmodifiableList(this.serviceList); } - private void consume(@NotNull final UUIDMapping mapping) { - for (final Consumer consumer : this.consumerList) { - consumer.accept(mapping); + /** + * 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)); + } + /** * Asynchronously attempt to fetch the mapping from a list of UUIDs * * @param requests UUIDs * @return Mappings */ - public CompletableFuture> getNames(@NotNull final Collection requests) { + public CompletableFuture> getNames( + @NotNull final Collection requests) { final List serviceList = this.getServiceListInstance(); return CompletableFuture.supplyAsync(() -> { final List mappings = new ArrayList<>(requests.size()); @@ -111,6 +154,7 @@ public class UUIDPipeline { } if (mappings.size() == requests.size()) { + this.consume(mappings); return mappings; } @@ -124,7 +168,8 @@ public class UUIDPipeline { * @param requests Names * @return Mappings */ - public CompletableFuture> getUUIDs(@NotNull final Collection requests) { + public CompletableFuture> getUUIDs( + @NotNull final Collection requests) { final List serviceList = this.getServiceListInstance(); return CompletableFuture.supplyAsync(() -> { final List mappings = new ArrayList<>(requests.size()); @@ -139,6 +184,7 @@ public class UUIDPipeline { } if (mappings.size() == requests.size()) { + this.consume(mappings); return mappings; } From 49f51f24f7b1c27b787c05a4707cdec98b570607 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20S=C3=B6derberg?= Date: Sun, 17 May 2020 18:02:26 +0200 Subject: [PATCH 06/33] Don't loop services when all mappings have been found --- .../java/com/plotsquared/core/uuid/UUIDPipeline.java | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/Core/src/main/java/com/plotsquared/core/uuid/UUIDPipeline.java b/Core/src/main/java/com/plotsquared/core/uuid/UUIDPipeline.java index 0df18ea94..e14df5de0 100644 --- a/Core/src/main/java/com/plotsquared/core/uuid/UUIDPipeline.java +++ b/Core/src/main/java/com/plotsquared/core/uuid/UUIDPipeline.java @@ -140,12 +140,18 @@ public class UUIDPipeline { */ public CompletableFuture> getNames( @NotNull final Collection requests) { + if (requests.isEmpty()) { + return CompletableFuture.completedFuture(Collections.emptyList()); + } final List serviceList = this.getServiceListInstance(); return CompletableFuture.supplyAsync(() -> { final List mappings = new ArrayList<>(requests.size()); final List remainingRequests = new ArrayList<>(requests); for (final UUIDService service : serviceList) { + if (remainingRequests.isEmpty()) { + break; + } final List completedRequests = service.getNames(remainingRequests); for (final UUIDMapping mapping : completedRequests) { remainingRequests.remove(mapping.getUuid()); @@ -170,12 +176,18 @@ public class UUIDPipeline { */ public CompletableFuture> getUUIDs( @NotNull final Collection requests) { + if (requests.isEmpty()) { + return CompletableFuture.completedFuture(Collections.emptyList()); + } final List serviceList = this.getServiceListInstance(); return CompletableFuture.supplyAsync(() -> { final List mappings = new ArrayList<>(requests.size()); final List remainingRequests = new ArrayList<>(requests); for (final UUIDService service : serviceList) { + if (remainingRequests.isEmpty()) { + break; + } final List completedRequests = service.getUUIDs(remainingRequests); for (final UUIDMapping mapping : completedRequests) { remainingRequests.remove(mapping.getUsername()); From 736004d88bcf37fa86b2989e6d43fe4ab1f4059d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20S=C3=B6derberg?= Date: Sun, 17 May 2020 18:03:04 +0200 Subject: [PATCH 07/33] Don't fill in stacktrace for ServiceError --- .../src/main/java/com/plotsquared/core/uuid/ServiceError.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Core/src/main/java/com/plotsquared/core/uuid/ServiceError.java b/Core/src/main/java/com/plotsquared/core/uuid/ServiceError.java index b33bd1509..0e248a2c5 100644 --- a/Core/src/main/java/com/plotsquared/core/uuid/ServiceError.java +++ b/Core/src/main/java/com/plotsquared/core/uuid/ServiceError.java @@ -40,4 +40,8 @@ public class ServiceError extends RuntimeException { super(message, cause); } + @Override public Throwable fillInStackTrace() { + return this; + } + } From 58989c93111ea54107fcd0967889fbc354709b59 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20S=C3=B6derberg?= Date: Sun, 17 May 2020 23:20:36 +0200 Subject: [PATCH 08/33] Add some missing methods to the pipeline --- .../plotsquared/core/uuid/UUIDPipeline.java | 73 ++++++++++++++++++- 1 file changed, 70 insertions(+), 3 deletions(-) diff --git a/Core/src/main/java/com/plotsquared/core/uuid/UUIDPipeline.java b/Core/src/main/java/com/plotsquared/core/uuid/UUIDPipeline.java index e14df5de0..a59c1d264 100644 --- a/Core/src/main/java/com/plotsquared/core/uuid/UUIDPipeline.java +++ b/Core/src/main/java/com/plotsquared/core/uuid/UUIDPipeline.java @@ -29,6 +29,7 @@ import com.google.common.collect.Lists; import com.plotsquared.core.PlotSquared; 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; @@ -36,7 +37,10 @@ import java.util.Collections; import java.util.List; import java.util.UUID; import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; import java.util.concurrent.Executor; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; import java.util.function.Consumer; /** @@ -132,14 +136,77 @@ public class UUIDPipeline { 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) { + try { + this.getUUIDs(Collections.singletonList(username)).get(timeout, TimeUnit.MILLISECONDS); + } catch (InterruptedException | ExecutionException e) { + e.printStackTrace(); + } catch (TimeoutException ignored) { + // 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) { + try { + this.getNames(Collections.singletonList(uuid)).get(timeout, TimeUnit.MILLISECONDS); + } catch (InterruptedException | ExecutionException e) { + e.printStackTrace(); + } catch (TimeoutException ignored) { + // 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 Consumer uuid) { + this.getUUIDs(Collections.singletonList(username)).thenAccept(uuids -> { + if (!uuids.isEmpty()) { + uuid.accept(uuids.get(0).getUuid()); + } + }); + } + + /** + * 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 Consumer username) { + this.getNames(Collections.singletonList(uuid)).thenAccept(uuids -> { + if (!uuids.isEmpty()) { + username.accept(uuids.get(0).getUsername()); + } + }); + } + /** * Asynchronously attempt to fetch the mapping from a list of UUIDs * * @param requests UUIDs * @return Mappings */ - public CompletableFuture> getNames( - @NotNull final Collection requests) { + public CompletableFuture> getNames(@NotNull final Collection requests) { if (requests.isEmpty()) { return CompletableFuture.completedFuture(Collections.emptyList()); } @@ -174,7 +241,7 @@ public class UUIDPipeline { * @param requests Names * @return Mappings */ - public CompletableFuture> getUUIDs( + public CompletableFuture> getUUIDs( @NotNull final Collection requests) { if (requests.isEmpty()) { return CompletableFuture.completedFuture(Collections.emptyList()); From b5f92f500387bc01e1320999c41ca5eb4e2c9a33 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20S=C3=B6derberg?= Date: Sun, 17 May 2020 23:26:19 +0200 Subject: [PATCH 09/33] Add sync catcher to the blocking pipeline methods --- .../plotsquared/core/util/ThreadUtils.java | 57 +++++++++++++++++++ .../plotsquared/core/uuid/UUIDPipeline.java | 3 + 2 files changed, 60 insertions(+) create mode 100644 Core/src/main/java/com/plotsquared/core/util/ThreadUtils.java 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/uuid/UUIDPipeline.java b/Core/src/main/java/com/plotsquared/core/uuid/UUIDPipeline.java index a59c1d264..7add9ef8a 100644 --- a/Core/src/main/java/com/plotsquared/core/uuid/UUIDPipeline.java +++ b/Core/src/main/java/com/plotsquared/core/uuid/UUIDPipeline.java @@ -27,6 +27,7 @@ package com.plotsquared.core.uuid; import com.google.common.collect.Lists; import com.plotsquared.core.PlotSquared; +import com.plotsquared.core.util.ThreadUtils; import com.plotsquared.core.util.task.TaskManager; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -144,6 +145,7 @@ public class UUIDPipeline { * @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 { this.getUUIDs(Collections.singletonList(username)).get(timeout, TimeUnit.MILLISECONDS); } catch (InterruptedException | ExecutionException e) { @@ -162,6 +164,7 @@ public class UUIDPipeline { * @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 { this.getNames(Collections.singletonList(uuid)).get(timeout, TimeUnit.MILLISECONDS); } catch (InterruptedException | ExecutionException e) { From 67bf90e92f76bb6ff57f677b4bba8153f1b05ea3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20S=C3=B6derberg?= Date: Sun, 17 May 2020 23:41:59 +0200 Subject: [PATCH 10/33] Create the SQLite UUID service and cache --- .../bukkit/uuid/SQLiteUUIDService.java | 124 ++++++++++++++++++ 1 file changed, 124 insertions(+) create mode 100644 Bukkit/src/main/java/com/plotsquared/bukkit/uuid/SQLiteUUIDService.java 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..e71ddd280 --- /dev/null +++ b/Bukkit/src/main/java/com/plotsquared/bukkit/uuid/SQLiteUUIDService.java @@ -0,0 +1,124 @@ +/* + * _____ _ _ _____ _ + * | __ \| | | | / ____| | | + * | |__) | | ___ | |_| (___ __ _ _ _ __ _ _ __ ___ __| | + * | ___/| |/ _ \| __|\___ \ / _` | | | |/ _` | '__/ _ \/ _` | + * | | | | (_) | |_ ____) | (_| | |_| | (_| | | | __/ (_| | + * |_| |_|\___/ \__|_____/ \__, |\__,_|\__,_|_| \___|\__,_| + * | | + * |_| + * 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.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() { + 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(); + } + } + + private Connection getConnection() { + synchronized (this.sqlite) { + return this.sqlite.getConnection(); + } + } + + @Override public @NotNull 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 public @NotNull 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(); + } + } + +} From 12f2cb0d5869c99f427026d2c43cd4b81d6d6bdb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20S=C3=B6derberg?= Date: Sun, 17 May 2020 23:57:40 +0200 Subject: [PATCH 11/33] Add a cache uuid service --- .../core/uuid/CacheUUIDService.java | 76 +++++++++++++++++++ 1 file changed, 76 insertions(+) create mode 100644 Core/src/main/java/com/plotsquared/core/uuid/CacheUUIDService.java 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..81a42bacd --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/uuid/CacheUUIDService.java @@ -0,0 +1,76 @@ +/* + * _____ _ _ _____ _ + * | __ \| | | | / ____| | | + * | |__) | | ___ | |_| (___ __ _ _ _ __ _ _ __ ___ __| | + * | ___/| |/ _ \| __|\___ \ / _` | | | |/ _` | '__/ _ \/ _` | + * | | | | (_) | |_ ____) | (_| | |_| | (_| | | | __/ (_| | + * |_| |_|\___/ \__|_____/ \__, |\__,_|\__,_|_| \___|\__,_| + * | | + * |_| + * 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 java.util.ArrayList; +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); + } + } + +} From a47527857c24a9366f40722cc5d59e36dab05dc6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20S=C3=B6derberg?= Date: Sun, 17 May 2020 23:58:39 +0200 Subject: [PATCH 12/33] Fix wonky annotation placement in SQLiteUUIDService --- .../java/com/plotsquared/bukkit/uuid/SQLiteUUIDService.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Bukkit/src/main/java/com/plotsquared/bukkit/uuid/SQLiteUUIDService.java b/Bukkit/src/main/java/com/plotsquared/bukkit/uuid/SQLiteUUIDService.java index e71ddd280..6ad2f01ce 100644 --- a/Bukkit/src/main/java/com/plotsquared/bukkit/uuid/SQLiteUUIDService.java +++ b/Bukkit/src/main/java/com/plotsquared/bukkit/uuid/SQLiteUUIDService.java @@ -71,7 +71,7 @@ public class SQLiteUUIDService implements UUIDService, Consumer getNames(@NotNull final List uuids) { + @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` = ?")) { @@ -89,7 +89,7 @@ public class SQLiteUUIDService implements UUIDService, Consumer getUUIDs(@NotNull List usernames) { + @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` = ?")) { From 31c84ab18f96e0ba2f3b2261a7cd227ecff002cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20S=C3=B6derberg?= Date: Mon, 18 May 2020 00:22:34 +0200 Subject: [PATCH 13/33] Basic pipeline setup --- .../com/plotsquared/bukkit/BukkitMain.java | 44 +++++++++++++++++++ .../com/plotsquared/core/PlotSquared.java | 7 +++ .../core/configuration/Settings.java | 6 +++ 3 files changed, 57 insertions(+) diff --git a/Bukkit/src/main/java/com/plotsquared/bukkit/BukkitMain.java b/Bukkit/src/main/java/com/plotsquared/bukkit/BukkitMain.java index 779aec999..a03ac3218 100644 --- a/Bukkit/src/main/java/com/plotsquared/bukkit/BukkitMain.java +++ b/Bukkit/src/main/java/com/plotsquared/bukkit/BukkitMain.java @@ -55,6 +55,10 @@ 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.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; @@ -101,6 +105,9 @@ 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; @@ -221,6 +228,43 @@ public final class BukkitMain extends JavaPlugin implements Listener, IPlotMain PlotSquared.log(Captions.PREFIX + "&6Couldn't verify purchase :("); } + // TODO: Do we respect the UUID settings? + 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); + } + final OfflinePlayerUUIDService offlinePlayerUUIDService = new OfflinePlayerUUIDService(); + impromptuPipeline.registerService(offlinePlayerUUIDService); + backgroundPipeline.registerService(offlinePlayerUUIDService); + 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); + } + final SQLiteUUIDService sqLiteUUIDService = new SQLiteUUIDService(); + impromptuPipeline.registerService(sqLiteUUIDService); + backgroundPipeline.registerService(sqLiteUUIDService); + impromptuPipeline.registerConsumer(sqLiteUUIDService); + backgroundPipeline.registerConsumer(sqLiteUUIDService); + final SquirrelIdUUIDService impromptuMojangService = new SquirrelIdUUIDService(Settings.UUID.IMPROMPTU_LIMIT); + impromptuPipeline.registerService(impromptuMojangService); + final SquirrelIdUUIDService backgroundMojangService = new SquirrelIdUUIDService(Settings.UUID.BACKGROUND_LIMIT); + backgroundPipeline.registerService(backgroundMojangService); + } + if (Bukkit.getPluginManager().getPlugin("PlaceholderAPI") != null) { new Placeholders().register(); if (Settings.Enabled_Components.EXTERNAL_PLACEHOLDERS) { diff --git a/Core/src/main/java/com/plotsquared/core/PlotSquared.java b/Core/src/main/java/com/plotsquared/core/PlotSquared.java index 452493181..bbb8b66bc 100644 --- a/Core/src/main/java/com/plotsquared/core/PlotSquared.java +++ b/Core/src/main/java/com/plotsquared/core/PlotSquared.java @@ -84,6 +84,7 @@ 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.UUIDHandler; +import com.plotsquared.core.uuid.UUIDPipeline; import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.math.BlockVector2; import com.sk89q.worldedit.regions.CuboidRegion; @@ -123,6 +124,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; @@ -140,6 +142,11 @@ public class PlotSquared { 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; 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..fff645253 100644 --- a/Core/src/main/java/com/plotsquared/core/configuration/Settings.java +++ b/Core/src/main/java/com/plotsquared/core/configuration/Settings.java @@ -239,6 +239,12 @@ public class Settings extends Config { @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; } From fdfc61cf97870e4e588de3450f83d270bbdc0f7c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20S=C3=B6derberg?= Date: Mon, 18 May 2020 20:45:51 +0200 Subject: [PATCH 14/33] Update username on async pre login event --- .../java/com/plotsquared/bukkit/listener/PlayerEvents.java | 6 ++++++ 1 file changed, 6 insertions(+) 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 069bae68b..11215fcc8 100644 --- a/Bukkit/src/main/java/com/plotsquared/bukkit/listener/PlayerEvents.java +++ b/Bukkit/src/main/java/com/plotsquared/bukkit/listener/PlayerEvents.java @@ -178,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; @@ -629,6 +630,11 @@ public class PlayerEvents extends PlotListener implements Listener { } } + @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) + public void onPreLoin(final AsyncPlayerPreLoginEvent event) { + PlotSquared.get().getImpromptuUUIDPipeline().storeImmediately(event.getName(), event.getUniqueId()); + } + @EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true) public void onConnect(PlayerJoinEvent event) { final Player player = event.getPlayer(); From 37b065a097b05fe68502d5bfb113ad06390ecefe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20S=C3=B6derberg?= Date: Tue, 19 May 2020 00:28:52 +0200 Subject: [PATCH 15/33] Progress. --- .../com/plotsquared/bukkit/BukkitCommand.java | 5 - .../com/plotsquared/bukkit/BukkitMain.java | 51 +-- .../plotsquared/bukkit/command/DebugUUID.java | 323 ----------------- .../bukkit/listener/PaperListener.java | 48 +++ .../bukkit/listener/PlayerEvents.java | 28 +- .../bukkit/placeholder/Placeholders.java | 7 +- .../bukkit/player/BukkitPlayer.java | 6 +- .../bukkit/player/BukkitPlayerManager.java | 28 +- .../plotsquared/bukkit/util/BukkitUtil.java | 11 +- .../plotsquared/bukkit/util/SendChunk.java | 167 --------- .../bukkit/util/uuid/DatFileFilter.java | 36 -- .../bukkit/util/uuid/FileUUIDHandler.java | 289 ---------------- .../util/uuid/LowerOfflineUUIDWrapper.java | 60 ---- .../bukkit/util/uuid/OfflineUUIDWrapper.java | 131 ------- .../bukkit/util/uuid/SQLUUIDHandler.java | 270 --------------- .../java/com/plotsquared/core/IPlotMain.java | 17 +- .../com/plotsquared/core/PlotSquared.java | 34 +- .../com/plotsquared/core/api/PlotAPI.java | 13 - .../com/plotsquared/core/command/Add.java | 104 +++--- .../com/plotsquared/core/command/Alias.java | 49 ++- .../com/plotsquared/core/command/Cluster.java | 177 +++++----- .../com/plotsquared/core/command/Command.java | 6 + .../com/plotsquared/core/command/Comment.java | 8 +- .../core/command/DebugClaimTest.java | 134 -------- .../core/command/DebugImportWorlds.java | 5 +- .../com/plotsquared/core/command/Deny.java | 74 ++-- .../com/plotsquared/core/command/Merge.java | 2 +- .../com/plotsquared/core/command/Visit.java | 204 ++++++----- .../core/configuration/Captions.java | 1 + .../core/listener/PlotListener.java | 5 +- .../plotsquared/core/player/PlotPlayer.java | 17 +- .../java/com/plotsquared/core/plot/Plot.java | 104 +----- .../com/plotsquared/core/util/MainUtil.java | 72 ++-- .../plotsquared/core/util/PlayerManager.java | 120 +++++++ .../core/util/SchematicHandler.java | 2 +- .../plotsquared/core/util/TabCompletions.java | 82 +++++ .../core/util/uuid/UUIDHandler.java | 198 ----------- .../util/uuid/UUIDHandlerImplementation.java | 324 ------------------ .../core/uuid/CacheUUIDService.java | 5 + .../plotsquared/core/uuid/UUIDMapping.java | 3 +- .../plotsquared/core/uuid/UUIDPipeline.java | 45 ++- .../plotsquared/core/uuid/UUIDService.java | 12 + .../util/UUIDHandlerImplementationTest.java | 5 +- 43 files changed, 759 insertions(+), 2523 deletions(-) delete mode 100644 Bukkit/src/main/java/com/plotsquared/bukkit/command/DebugUUID.java rename Core/src/main/java/com/plotsquared/core/util/uuid/UUIDWrapper.java => Bukkit/src/main/java/com/plotsquared/bukkit/player/BukkitPlayerManager.java (71%) delete mode 100644 Bukkit/src/main/java/com/plotsquared/bukkit/util/SendChunk.java delete mode 100644 Bukkit/src/main/java/com/plotsquared/bukkit/util/uuid/DatFileFilter.java delete mode 100644 Bukkit/src/main/java/com/plotsquared/bukkit/util/uuid/FileUUIDHandler.java delete mode 100644 Bukkit/src/main/java/com/plotsquared/bukkit/util/uuid/LowerOfflineUUIDWrapper.java delete mode 100644 Bukkit/src/main/java/com/plotsquared/bukkit/util/uuid/OfflineUUIDWrapper.java delete mode 100644 Bukkit/src/main/java/com/plotsquared/bukkit/util/uuid/SQLUUIDHandler.java delete mode 100644 Core/src/main/java/com/plotsquared/core/command/DebugClaimTest.java create mode 100644 Core/src/main/java/com/plotsquared/core/util/PlayerManager.java create mode 100644 Core/src/main/java/com/plotsquared/core/util/TabCompletions.java delete mode 100644 Core/src/main/java/com/plotsquared/core/util/uuid/UUIDHandler.java delete mode 100644 Core/src/main/java/com/plotsquared/core/util/uuid/UUIDHandlerImplementation.java diff --git a/Bukkit/src/main/java/com/plotsquared/bukkit/BukkitCommand.java b/Bukkit/src/main/java/com/plotsquared/bukkit/BukkitCommand.java index 2d3737ee0..20ab45529 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) { diff --git a/Bukkit/src/main/java/com/plotsquared/bukkit/BukkitMain.java b/Bukkit/src/main/java/com/plotsquared/bukkit/BukkitMain.java index a03ac3218..90a717fd5 100644 --- a/Bukkit/src/main/java/com/plotsquared/bukkit/BukkitMain.java +++ b/Bukkit/src/main/java/com/plotsquared/bukkit/BukkitMain.java @@ -38,6 +38,7 @@ 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; @@ -50,11 +51,6 @@ 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.OfflinePlayerUUIDService; import com.plotsquared.bukkit.uuid.PaperUUIDService; import com.plotsquared.bukkit.uuid.SQLiteUUIDService; @@ -69,6 +65,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; @@ -94,6 +91,7 @@ import com.plotsquared.core.util.EconHandler; import com.plotsquared.core.util.InventoryUtil; import com.plotsquared.core.util.MainUtil; 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; @@ -102,9 +100,6 @@ 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; @@ -171,6 +166,7 @@ public final class BukkitMain extends JavaPlugin implements Listener, IPlotMain private boolean metricsStarted; @Getter private BackupManager backupManager; @Getter private PlatformWorldManager worldManager; + @Getter private final PlayerManager playerManager = new BukkitPlayerManager(); @Override public int[] getServerVersion() { if (this.version == null) { @@ -265,6 +261,8 @@ public final class BukkitMain extends JavaPlugin implements Listener, IPlotMain backgroundPipeline.registerService(backgroundMojangService); } + impromptuPipeline.storeImmediately("*", DBFunc.EVERYONE); + if (Bukkit.getPluginManager().getPlugin("PlaceholderAPI") != null) { new Placeholders().register(); if (Settings.Enabled_Components.EXTERNAL_PLACEHOLDERS) { @@ -842,39 +840,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) { @@ -925,10 +890,10 @@ public final class BukkitMain extends JavaPlugin implements Listener, IPlotMain return BukkitUtil.getPlayer((OfflinePlayer) player); } if (player instanceof String) { - return UUIDHandler.getPlayer((String) player); + return PlotSquared.imp().getPlayerManager().getPlayerIfExists((String) player); } if (player instanceof UUID) { - return UUIDHandler.getPlayer((UUID) player); + return PlotSquared.imp().getPlayerManager().getPlayerIfExists((UUID) player); } return null; } 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/listener/PaperListener.java b/Bukkit/src/main/java/com/plotsquared/bukkit/listener/PaperListener.java index 6c7e4c9eb..2ff395c52 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,13 @@ import org.bukkit.event.block.BlockPlaceEvent; import org.bukkit.event.entity.CreatureSpawnEvent; import org.bukkit.projectiles.ProjectileSource; +import java.util.ArrayList; +import java.util.Arrays; +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 */ @@ -306,4 +316,42 @@ public class PaperListener implements Listener { event.setCancelled(true); } } + + @EventHandler public void onAsyncTabCompletion(final AsyncTabCompleteEvent event) { + PlotSquared.debug("ASYNC COMPLETION"); + 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 (!Arrays.asList("plots", "p", "plotsquared", "plot2", "p2", "ps", "2", "plotme", "plotz", "ap") + .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); + PlotSquared.debug("ASYNC COMPLETION HANDLED"); + } 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 11215fcc8..ddcc15320 100644 --- a/Bukkit/src/main/java/com/plotsquared/bukkit/listener/PlayerEvents.java +++ b/Bukkit/src/main/java/com/plotsquared/bukkit/listener/PlayerEvents.java @@ -103,10 +103,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; @@ -216,7 +214,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 +251,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 @@ -356,18 +353,18 @@ 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; } @@ -379,8 +376,8 @@ public class PlayerEvents extends PlotListener implements Listener { } } 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; } } @@ -638,14 +635,8 @@ public class PlayerEvents extends PlotListener implements Listener { @EventHandler(priority = EventPriority.LOWEST, 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); Location location = pp.getLocation(); PlotArea area = location.getPlotArea(); @@ -951,8 +942,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 { @@ -2876,7 +2866,7 @@ public class PlayerEvents extends PlotListener implements Listener { } return true; } else if (dplot != null && (!dplot.equals(vplot) || Objects - .equals(dplot.guessOwner(), vplot.guessOwner()))) { + .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. 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..f8a155d21 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,9 @@ */ package com.plotsquared.bukkit.placeholder; +import com.plotsquared.core.PlotSquared; import com.plotsquared.core.player.PlotPlayer; import com.plotsquared.core.plot.Plot; -import com.plotsquared.core.util.uuid.UUIDHandler; import me.clip.placeholderapi.PlaceholderAPIPlugin; import me.clip.placeholderapi.expansion.PlaceholderExpansion; import org.bukkit.Bukkit; @@ -62,7 +62,7 @@ public class Placeholders extends PlaceholderExpansion { } @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 ""; @@ -122,7 +122,8 @@ public class Placeholders extends PlaceholderExpansion { if (uid == null) { return ""; } - String name = UUIDHandler.getName(uid); + + String name = PlotSquared.get().getImpromptuUUIDPipeline() .getSingle(uid, 5L); if (name != null) { return name; 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..d2e7930fa 100644 --- a/Bukkit/src/main/java/com/plotsquared/bukkit/player/BukkitPlayer.java +++ b/Bukkit/src/main/java/com/plotsquared/bukkit/player/BukkitPlayer.java @@ -35,7 +35,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; @@ -97,10 +96,7 @@ public class BukkitPlayer extends PlotPlayer { } @NotNull @Override public UUID getUUID() { - if (this.uuid == null) { - this.uuid = UUIDHandler.getUUID(this); - } - return this.uuid; + return this.player.getUniqueId(); } @Override public long getLastPlayed() { diff --git a/Core/src/main/java/com/plotsquared/core/util/uuid/UUIDWrapper.java b/Bukkit/src/main/java/com/plotsquared/bukkit/player/BukkitPlayerManager.java similarity index 71% rename from Core/src/main/java/com/plotsquared/core/util/uuid/UUIDWrapper.java rename to Bukkit/src/main/java/com/plotsquared/bukkit/player/BukkitPlayerManager.java index b2e8e0227..6e628a8a7 100644 --- a/Core/src/main/java/com/plotsquared/core/util/uuid/UUIDWrapper.java +++ b/Bukkit/src/main/java/com/plotsquared/bukkit/player/BukkitPlayerManager.java @@ -23,25 +23,27 @@ * 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.bukkit.player; -import com.plotsquared.core.player.OfflinePlotPlayer; import com.plotsquared.core.player.PlotPlayer; +import com.plotsquared.core.util.PlayerManager; +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; import org.jetbrains.annotations.NotNull; import java.util.UUID; -public interface UUIDWrapper { +/** + * Player manager providing {@link BukkitPlayer Bukkit players} + */ +public class BukkitPlayerManager extends PlayerManager { - @NotNull UUID getUUID(PlotPlayer player); + @Override @NotNull public PlotPlayer createPlayer(@NotNull final UUID uuid) { + final Player player = Bukkit.getPlayer(uuid); + if (player == null || !player.isOnline()) { + throw new NoSuchPlayerException(uuid); + } + return new BukkitPlayer(player); + } - UUID getUUID(OfflinePlotPlayer player); - - UUID getUUID(String name); - - OfflinePlotPlayer getOfflinePlayer(UUID uuid); - - OfflinePlotPlayer getOfflinePlayer(String name); - - OfflinePlotPlayer[] getOfflinePlayers(); } 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..8ba3caa9b 100644 --- a/Bukkit/src/main/java/com/plotsquared/bukkit/util/BukkitUtil.java +++ b/Bukkit/src/main/java/com/plotsquared/bukkit/util/BukkitUtil.java @@ -39,7 +39,6 @@ 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; @@ -268,15 +267,7 @@ public class BukkitUtil extends WorldUtil { 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; + return PlotSquared.imp().getPlayerManager().getPlayer(player.getUniqueId()); } 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/DatFileFilter.java b/Bukkit/src/main/java/com/plotsquared/bukkit/util/uuid/DatFileFilter.java deleted file mode 100644 index 65657fbff..000000000 --- a/Bukkit/src/main/java/com/plotsquared/bukkit/util/uuid/DatFileFilter.java +++ /dev/null @@ -1,36 +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 java.io.File; -import java.io.FilenameFilter; - -public class DatFileFilter implements FilenameFilter { - - @Override public boolean accept(File dir, String name) { - return name.endsWith(".dat"); - } -} 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/LowerOfflineUUIDWrapper.java b/Bukkit/src/main/java/com/plotsquared/bukkit/util/uuid/LowerOfflineUUIDWrapper.java deleted file mode 100644 index ad2be7ce3..000000000 --- a/Bukkit/src/main/java/com/plotsquared/bukkit/util/uuid/LowerOfflineUUIDWrapper.java +++ /dev/null @@ -1,60 +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.plotsquared.core.player.OfflinePlotPlayer; -import com.plotsquared.core.player.PlotPlayer; -import org.bukkit.OfflinePlayer; -import org.jetbrains.annotations.NotNull; - -import java.util.Objects; -import java.util.UUID; - -public class LowerOfflineUUIDWrapper extends OfflineUUIDWrapper { - - @NotNull @Override public UUID getUUID(PlotPlayer player) { - return UUID.nameUUIDFromBytes( - ("OfflinePlayer:" + player.getName().toLowerCase()).getBytes(Charsets.UTF_8)); - } - - @Override public UUID getUUID(OfflinePlotPlayer player) { - return UUID.nameUUIDFromBytes( - ("OfflinePlayer:" + player.getName().toLowerCase()).getBytes(Charsets.UTF_8)); - } - - @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/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 405fb940d..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 implements 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/Core/src/main/java/com/plotsquared/core/IPlotMain.java b/Core/src/main/java/com/plotsquared/core/IPlotMain.java index ed6694e01..2705d54c2 100644 --- a/Core/src/main/java/com/plotsquared/core/IPlotMain.java +++ b/Core/src/main/java/com/plotsquared/core/IPlotMain.java @@ -36,13 +36,13 @@ import com.plotsquared.core.util.ChunkManager; import com.plotsquared.core.util.EconHandler; import com.plotsquared.core.util.InventoryUtil; 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; @@ -220,12 +220,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 +279,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 getPlayerManager(); } diff --git a/Core/src/main/java/com/plotsquared/core/PlotSquared.java b/Core/src/main/java/com/plotsquared/core/PlotSquared.java index bbb8b66bc..a19f167d7 100644 --- a/Core/src/main/java/com/plotsquared/core/PlotSquared.java +++ b/Core/src/main/java/com/plotsquared/core/PlotSquared.java @@ -79,11 +79,9 @@ 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.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; @@ -91,6 +89,7 @@ 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; @@ -259,15 +258,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 @@ -392,11 +382,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"); } /** @@ -437,8 +427,7 @@ public class PlotSquared { private void startUuidCatching() { TaskManager.runTaskLater(() -> { debug("Starting UUID caching"); - UUIDHandler.startCaching(() -> { - UUIDHandler.add(new StringWrapper("*"), DBFunc.EVERYONE); + /*UUIDHandler.startCaching(() -> { forEachPlotRaw(plot -> { if (plot.hasOwner() && plot.temp != -1) { if (UUIDHandler.getName(plot.getOwnerAbs()) == null) { @@ -447,7 +436,8 @@ public class PlotSquared { } }); startExpiryTasks(); - }); + });*/ + // TODO: Re-implement }, 20); } @@ -973,7 +963,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, 10L); return getPlots(world, uuid); } @@ -985,7 +975,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, 10L); return getPlots(area, uuid); } @@ -1018,7 +1008,10 @@ public class PlotSquared { * @param uuid the plot owner * @return Set of plot */ - public Set getPlots(String world, UUID uuid) { + public Set getPlots(String world, @Nullable UUID uuid) { + if (uuid == null) { + return Collections.emptySet(); + } final Set plots = getPlots(world).stream().filter(plot -> plot.hasOwner() && plot.isOwnerAbs(uuid)) .collect(Collectors.toSet()); @@ -1627,7 +1620,6 @@ public class PlotSquared { // Close the connection DBFunc.close(); - UUIDHandler.handleShutdown(); } catch (NullPointerException throwable) { throwable.printStackTrace(); PlotSquared.log("&cCould not close database connection!"); 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 56e507873..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; @@ -138,17 +136,6 @@ import java.util.UUID; 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/command/Add.java b/Core/src/main/java/com/plotsquared/core/command/Add.java index bc4905c68..32750f8d9 100644 --- a/Core/src/main/java/com/plotsquared/core/command/Add.java +++ b/Core/src/main/java/com/plotsquared/core/command/Add.java @@ -36,7 +36,6 @@ import com.plotsquared.core.util.task.RunnableVal2; import com.plotsquared.core.util.task.RunnableVal3; import java.util.Iterator; -import java.util.Set; import java.util.UUID; import java.util.concurrent.CompletableFuture; @@ -62,51 +61,64 @@ 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) { + 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; } } 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..1df9848d0 100644 --- a/Core/src/main/java/com/plotsquared/core/command/Alias.java +++ b/Core/src/main/java/com/plotsquared/core/command/Alias.java @@ -33,8 +33,6 @@ 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; @CommandDeclaration(command = "setalias", permission = "plots.alias", @@ -79,7 +77,8 @@ public class Alias extends SubCommand { if (canExecuteCommand(player, Captions.PERMISSION_ALIAS_SET, false) || canExecuteCommand(player, Captions.PERMISSION_ALIAS_SET_OBSOLETE, false)) { - result = setAlias(player, plot, args[1]); + setAlias(player, plot, args[1]); + return true; } else { MainUtil.sendMessage(player, Captions.NO_PERMISSION); } @@ -99,38 +98,32 @@ public class Alias extends SubCommand { } - private boolean setAlias(PlotPlayer player, Plot plot, String alias) { + private void setAlias(PlotPlayer player, Plot plot, String alias) { if (alias.isEmpty()) { Captions.COMMAND_SYNTAX.send(player, getUsage()); - return false; - } - if (alias.length() >= 50) { + } else if (alias.length() >= 50) { MainUtil.sendMessage(player, Captions.ALIAS_TOO_LONG); - return false; - } - if (alias.contains(" ")) { + } else if (alias.contains(" ")) { Captions.NOT_VALID_VALUE.send(player); - return false; - } - if (MathMan.isInteger(alias)) { + } else 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; + } else { + for (Plot p : PlotSquared.get().getPlots(plot.getArea())) { + if (p.getAlias().equalsIgnoreCase(alias)) { + MainUtil.sendMessage(player, Captions.ALIAS_IS_TAKEN); + return; + } } + PlotSquared.get().getImpromptuUUIDPipeline().getSingle(alias, ((uuid, throwable) -> { + 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)); + } + })); } - 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; } private boolean removeAlias(PlotPlayer player, Plot plot) { 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..82f602493 100644 --- a/Core/src/main/java/com/plotsquared/core/command/Cluster.java +++ b/Core/src/main/java/com/plotsquared/core/command/Cluster.java @@ -39,7 +39,6 @@ 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; @@ -371,22 +370,27 @@ 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 != 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 +424,41 @@ 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 != 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 +539,27 @@ 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 != 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 +628,27 @@ 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) -> { + 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/Command.java b/Core/src/main/java/com/plotsquared/core/command/Command.java index 6535e3b2c..6e97eb30a 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; @@ -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..501ba4247 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"}, @@ -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/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/DebugImportWorlds.java b/Core/src/main/java/com/plotsquared/core/command/DebugImportWorlds.java index 9cca145a5..1eedabb71 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; @@ -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/Deny.java b/Core/src/main/java/com/plotsquared/core/command/Deny.java index d591bfa1a..072975226 100644 --- a/Core/src/main/java/com/plotsquared/core/command/Deny.java +++ b/Core/src/main/java/com/plotsquared/core/command/Deny.java @@ -34,10 +34,8 @@ import com.plotsquared.core.plot.Plot; import com.plotsquared.core.util.MainUtil; import com.plotsquared.core.util.Permissions; 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.UUID; @CommandDeclaration(command = "deny", @@ -68,48 +66,46 @@ 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 != 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; } 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..7998e3a84 100644 --- a/Core/src/main/java/com/plotsquared/core/command/Merge.java +++ b/Core/src/main/java/com/plotsquared/core/command/Merge.java @@ -172,7 +172,7 @@ 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 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..0c31076f2 100644 --- a/Core/src/main/java/com/plotsquared/core/command/Visit.java +++ b/Core/src/main/java/com/plotsquared/core/command/Visit.java @@ -38,14 +38,16 @@ import com.plotsquared.core.util.MathMan; import com.plotsquared.core.util.Permissions; import com.plotsquared.core.util.task.RunnableVal2; import com.plotsquared.core.util.task.RunnableVal3; -import com.plotsquared.core.util.uuid.UUIDHandler; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; +import java.util.HashSet; import java.util.List; import java.util.UUID; import java.util.concurrent.CompletableFuture; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.function.Consumer; @CommandDeclaration(command = "visit", permission = "plots.visit", @@ -71,10 +73,71 @@ public class Visit extends Command { if (args.length == 1 && args[0].contains(":")) { args = args[0].split(":"); } - int page = Integer.MIN_VALUE; - Collection unsorted = null; - PlotArea sortByArea = player.getApplicablePlotArea(); - boolean shouldSortByArea = Settings.Teleport.PER_WORLD_VISIT; + + final Collection unsortedPre = new HashSet<>(); + final PlotArea[] sortByArea = new PlotArea[] {player.getApplicablePlotArea()}; + final AtomicBoolean shouldSortByArea = new AtomicBoolean(Settings.Teleport.PER_WORLD_VISIT); + + final Consumer pageConsumer = page -> { + if (page == Integer.MIN_VALUE) { + page = 1; + } + if (unsortedPre.isEmpty()) { + Captions.FOUND_NO_PLOTS.send(player); + } else { + final Collection unsorted = new ArrayList<>(unsortedPre); + if (unsorted.size() > 1) { + unsorted.removeIf(plot -> !plot.isBasePlot()); + } + if (page < 1 || page > unsorted.size()) { + Captions.NOT_VALID_NUMBER.send(player, "(1, " + unsorted.size() + ")"); + } else { + List plots; + if (shouldSortByArea.get()) { + plots = PlotSquared.get().sortPlots(unsorted, PlotSquared.SortType.CREATION_DATE, sortByArea[0]); + } 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; + } + } 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)); + } + } + }; + + final int[] page = new int[]{Integer.MIN_VALUE}; + switch (args.length) { case 3: if (!MathMan.isInteger(args[1])) { @@ -82,109 +145,66 @@ public class Visit extends Command { Captions.COMMAND_SYNTAX.send(player, getUsage()); return CompletableFuture.completedFuture(false); } - page = Integer.parseInt(args[2]); + page[0] = Integer.parseInt(args[2]); case 2: - if (page != Integer.MIN_VALUE || !MathMan.isInteger(args[1])) { - sortByArea = PlotSquared.get().getPlotAreaByString(args[1]); - if (sortByArea == null) { + if (page[0] != Integer.MIN_VALUE || !MathMan.isInteger(args[1])) { + sortByArea[0] = PlotSquared.get().getPlotAreaByString(args[1]); + if (sortByArea[0] == null) { Captions.NOT_VALID_NUMBER.send(player, "(1, ∞)"); 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; + + MainUtil.getUUIDsFromString(args[0], (uuids, throwable) -> { + if (throwable != null || uuids.size() != 1) { + Captions.COMMAND_SYNTAX.send(player, getUsage()); + } else { + unsortedPre.addAll(PlotSquared.get().getBasePlots((UUID) uuids.toArray()[0])); + shouldSortByArea.set(true); + pageConsumer.accept(page[0]); + } + }); break; } - page = Integer.parseInt(args[1]); + page[0] = Integer.parseInt(args[1]); case 1: - UUID user = args[0].length() >= 2 ? UUIDHandler.getUUIDFromString(args[0]) : null; - if (user != null && !PlotSquared.get().hasPlot(user)) { - user = 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); - } else { - Plot plot = MainUtil.getPlotFromString(player, args[0], true); - if (plot != null) { - unsorted = Collections.singletonList(plot.getBasePlot(false)); + final String[] finalArgs = args; + final Consumer uuidConsumer = uuid -> { + if (page[0] == Integer.MIN_VALUE && uuid == null && MathMan.isInteger(finalArgs[0])) { + page[0] = Integer.parseInt(finalArgs[0]); + unsortedPre.addAll(PlotSquared.get().getBasePlots(player)); + } else { + if (uuid != null) { + unsortedPre.addAll(PlotSquared.get().getBasePlots(uuid)); + } else { + Plot plot = MainUtil.getPlotFromString(player, finalArgs[0], true); + if (plot != null) { + unsortedPre.addAll(Collections.singletonList(plot.getBasePlot(false))); + } + } } + pageConsumer.accept(page[0]); + }; + + if (args[0].length() >= 2) { + PlotSquared.get().getImpromptuUUIDPipeline().getSingle(args[0], (uuid, throwable) -> { + if (uuid != null && !PlotSquared.get().hasPlot(uuid)) { + uuidConsumer.accept(null); + } else { + uuidConsumer.accept(uuid); + } + }); + } else { + uuidConsumer.accept(null); } break; case 0: - page = 1; - unsorted = PlotSquared.get().getPlots(player); + unsortedPre.addAll(PlotSquared.get().getPlots(player)); + pageConsumer.accept(1); 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); } 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..9d9251c61 100644 --- a/Core/src/main/java/com/plotsquared/core/configuration/Captions.java +++ b/Core/src/main/java/com/plotsquared/core/configuration/Captions.java @@ -450,6 +450,7 @@ public enum Captions implements Caption { // 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"), // TRIM_IN_PROGRESS("A world trim task is already in progress!", "Trim"), // 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..5a4e43142 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; @@ -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()) @@ -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/player/PlotPlayer.java b/Core/src/main/java/com/plotsquared/core/player/PlotPlayer.java index 911c56adb..586809880 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; @@ -108,17 +107,6 @@ public abstract class PlotPlayer implements CommandCaller, OfflinePlotPlayer { 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(); /** @@ -363,8 +351,6 @@ public abstract class PlotPlayer implements CommandCaller, OfflinePlotPlayer { /** * Get this player's full location (including yaw/pitch) - * - * @return */ public abstract Location getLocationFull(); @@ -563,11 +549,10 @@ 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); } 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..e7cfbcafd 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; @@ -405,11 +400,10 @@ 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); + final List players = new ArrayList<>(); + for (final PlotPlayer player : PlotSquared.imp().getPlayerManager().getPlayers()) { + if (this.equals(player.getCurrentPlot())) { + players.add(player); } } return players; @@ -1717,12 +1711,7 @@ 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(), this::setSign); } /** @@ -2372,7 +2361,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 +2370,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
@@ -3099,10 +3019,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 +3036,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/util/MainUtil.java b/Core/src/main/java/com/plotsquared/core/util/MainUtil.java index 93cb7b3e4..4e887fead 100644 --- a/Core/src/main/java/com/plotsquared/core/util/MainUtil.java +++ b/Core/src/main/java/com/plotsquared/core/util/MainUtil.java @@ -49,7 +49,7 @@ 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; @@ -73,6 +73,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 +82,7 @@ import java.util.Optional; import java.util.Scanner; import java.util.Set; import java.util.UUID; +import java.util.function.BiConsumer; import java.util.function.Function; import java.util.function.IntConsumer; import java.util.function.IntFunction; @@ -99,12 +101,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 +148,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 +383,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, 10L); if (name == null) { return Captions.UNKNOWN.getTranslated(); } @@ -467,7 +454,7 @@ public class MainUtil { for (String term : split) { try { - UUID uuid = UUIDHandler.getUUID(term, null); + UUID uuid = PlotSquared.get().getImpromptuUUIDPipeline().getSingle(term, 10L); if (uuid == null) { uuid = UUID.fromString(term); } @@ -738,33 +725,44 @@ 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).whenComplete((uuids, throwable) -> { + if (throwable != null) { + consumer.accept(null, throwable); + } else { + for (final UUIDMapping uuid : uuids) { + result.add(uuid.getUuid()); + } + consumer.accept(result, null); + } + }); + } } /** @@ -931,7 +929,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/PlayerManager.java b/Core/src/main/java/com/plotsquared/core/util/PlayerManager.java new file mode 100644 index 000000000..fd1eebe4e --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/util/PlayerManager.java @@ -0,0 +1,120 @@ +/* + * _____ _ _ _____ _ + * | __ \| | | | / ____| | | + * | |__) | | ___ | |_| (___ __ _ _ _ __ _ _ __ ___ __| | + * | ___/| |/ _ \| __|\___ \ / _` | | | |/ _` | '__/ _ \/ _` | + * | | | | (_) | |_ ____) | (_| | |_| | (_| | | | __/ (_| | + * |_| |_|\___/ \__|_____/ \__, |\__,_|\__,_|_| \___|\__,_| + * | | + * |_| + * 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.PlotPlayer; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +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 { + + 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()); + } + } + + /** + * Get the player from its UUID if it is stored in the player map. + * + * @param uuid Player UUID + * @return Player, or null + */ + @Nullable public PlotPlayer getPlayerIfExists(@Nullable final UUID uuid) { + if (uuid == null) { + return null; + } + return this.playerMap.get(uuid); + } + + @Nullable public PlotPlayer getPlayerIfExists(@Nullable final String name) { + for (final PlotPlayer plotPlayer : this.playerMap.values()) { + if (plotPlayer.getName().equalsIgnoreCase(name)) { + return plotPlayer; + } + } + return null; + } + + /** + * 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 PlotPlayer getPlayer(@NotNull final UUID uuid) { + synchronized (playerLock) { + PlotPlayer player = this.playerMap.get(uuid); + if (player == null) { + player = createPlayer(uuid); + this.playerMap.put(uuid, player); + } + return player; + } + } + + @NotNull protected abstract PlotPlayer createPlayer(@NotNull final UUID uuid); + + /** + * Get all online players + * + * @return Unmodifiable collection of players + */ + public Collection getPlayers() { + return Collections.unmodifiableCollection(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())); + } + + } + +} 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 3adb8d19e..aa9e7a04c 100644 --- a/Core/src/main/java/com/plotsquared/core/util/SchematicHandler.java +++ b/Core/src/main/java/com/plotsquared/core/util/SchematicHandler.java @@ -104,7 +104,7 @@ public abstract class SchematicHandler { Iterator i = plots.iterator(); final Plot plot = i.next(); i.remove(); - String owner = UUIDHandler.getName(plot.guessOwner()); + String owner = UUIDHandler.getName(plot.getOwnerAbs()); if (owner == null) { owner = "unknown"; } 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..a7c7c2a8f --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/util/TabCompletions.java @@ -0,0 +1,82 @@ +/* + * _____ _ _ _____ _ + * | __ \| | | | / ____| | | + * | |__) | | ___ | |_| (___ __ _ _ _ __ _ _ __ ___ __| | + * | ___/| |/ _ \| __|\___ \ / _` | | | |/ _` | '__/ _ \/ _` | + * | | | | (_) | |_ ____) | (_| | |_| | (_| | | | __/ (_| | + * |_| |_|\___/ \__|_____/ \__, |\__,_|\__,_|_| \___|\__,_| + * | | + * |_| + * 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.uuid.UUIDMapping; +import lombok.experimental.UtilityClass; +import org.jetbrains.annotations.NotNull; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Locale; +import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; + +/** + * Tab completion utilities + */ +@UtilityClass public class TabCompletions { + + private final Cache> cachedCompletionValues = + CacheBuilder.newBuilder().expireAfterWrite(1, TimeUnit.MINUTES).build(); + + /** + * 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) { + List players = cachedCompletionValues.getIfPresent("players"); + if (players == null) { + final Collection mappings = + PlotSquared.get().getImpromptuUUIDPipeline().getAllImmediately(); + players = new ArrayList<>(mappings.size()); + for (final UUIDMapping mapping : mappings) { + players.add(mapping.getUsername()); + } + cachedCompletionValues.put("players", players); + } + final String processedInput = input.toLowerCase(Locale.ENGLISH); + return players.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) { + }).collect(Collectors.toList()); + } + +} 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 index 81a42bacd..32bbbb6bc 100644 --- a/Core/src/main/java/com/plotsquared/core/uuid/CacheUUIDService.java +++ b/Core/src/main/java/com/plotsquared/core/uuid/CacheUUIDService.java @@ -30,6 +30,7 @@ import com.google.common.cache.CacheBuilder; import org.jetbrains.annotations.NotNull; import java.util.ArrayList; +import java.util.Collection; import java.util.List; import java.util.UUID; import java.util.function.Consumer; @@ -73,4 +74,8 @@ public class CacheUUIDService implements UUIDService, Consumer } } + @Override @NotNull public Collection getImmediately() { + return this.usernameCache.asMap().values(); + } + } diff --git a/Core/src/main/java/com/plotsquared/core/uuid/UUIDMapping.java b/Core/src/main/java/com/plotsquared/core/uuid/UUIDMapping.java index 798d586ff..35a4c6c2c 100644 --- a/Core/src/main/java/com/plotsquared/core/uuid/UUIDMapping.java +++ b/Core/src/main/java/com/plotsquared/core/uuid/UUIDMapping.java @@ -25,6 +25,7 @@ */ package com.plotsquared.core.uuid; +import lombok.EqualsAndHashCode; import org.jetbrains.annotations.NotNull; import java.util.UUID; @@ -32,7 +33,7 @@ import java.util.UUID; /** * A pair consisting of a UUID and a username */ -public class UUIDMapping { +@EqualsAndHashCode public class UUIDMapping { private final UUID uuid; private final String username; diff --git a/Core/src/main/java/com/plotsquared/core/uuid/UUIDPipeline.java b/Core/src/main/java/com/plotsquared/core/uuid/UUIDPipeline.java index 7add9ef8a..6d85db51f 100644 --- a/Core/src/main/java/com/plotsquared/core/uuid/UUIDPipeline.java +++ b/Core/src/main/java/com/plotsquared/core/uuid/UUIDPipeline.java @@ -35,13 +35,16 @@ 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.TimeUnit; import java.util.concurrent.TimeoutException; +import java.util.function.BiConsumer; import java.util.function.Consumer; /** @@ -181,10 +184,16 @@ public class UUIDPipeline { * @param username Username * @param uuid UUID consumer */ - public void getSingle(@NotNull final String username, @NotNull final Consumer uuid) { - this.getUUIDs(Collections.singletonList(username)).thenAccept(uuids -> { - if (!uuids.isEmpty()) { - uuid.accept(uuids.get(0).getUuid()); + public void getSingle(@NotNull final String username, @NotNull final BiConsumer uuid) { + this.getUUIDs(Collections.singletonList(username)).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); + } } }); } @@ -195,10 +204,16 @@ public class UUIDPipeline { * @param uuid UUID * @param username Username consumer */ - public void getSingle(@NotNull final UUID uuid, @NotNull final Consumer username) { - this.getNames(Collections.singletonList(uuid)).thenAccept(uuids -> { - if (!uuids.isEmpty()) { - username.accept(uuids.get(0).getUsername()); + public void getSingle(@NotNull final UUID uuid, @NotNull final BiConsumer username) { + this.getNames(Collections.singletonList(uuid)).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); + } } }); } @@ -274,4 +289,18 @@ public class UUIDPipeline { }, 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; + } + } diff --git a/Core/src/main/java/com/plotsquared/core/uuid/UUIDService.java b/Core/src/main/java/com/plotsquared/core/uuid/UUIDService.java index 468de09b2..25588305e 100644 --- a/Core/src/main/java/com/plotsquared/core/uuid/UUIDService.java +++ b/Core/src/main/java/com/plotsquared/core/uuid/UUIDService.java @@ -27,6 +27,8 @@ package com.plotsquared.core.uuid; import org.jetbrains.annotations.NotNull; +import java.util.Collection; +import java.util.Collections; import java.util.List; import java.util.UUID; @@ -53,4 +55,14 @@ public interface UUIDService { */ @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(); + } + } diff --git a/Core/src/test/java/com/plotsquared/core/plot/util/UUIDHandlerImplementationTest.java b/Core/src/test/java/com/plotsquared/core/plot/util/UUIDHandlerImplementationTest.java index 291461478..9bcad05bd 100644 --- a/Core/src/test/java/com/plotsquared/core/plot/util/UUIDHandlerImplementationTest.java +++ b/Core/src/test/java/com/plotsquared/core/plot/util/UUIDHandlerImplementationTest.java @@ -28,15 +28,14 @@ package com.plotsquared.core.plot.util; 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 com.plotsquared.core.util.uuid.OfflinePlayerService; import org.junit.Before; import java.util.UUID; public class UUIDHandlerImplementationTest extends UUIDHandlerImplementation { - public UUIDHandlerImplementationTest(UUIDWrapper wrapper) { + public UUIDHandlerImplementationTest(OfflinePlayerService wrapper) { super(wrapper); } From 123ca8efe9133c57e7aca017fea21f078c510811 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20S=C3=B6derberg?= Date: Tue, 19 May 2020 17:33:59 +0200 Subject: [PATCH 16/33] Update more commands and add proper request timeouts --- .../bukkit/placeholder/Placeholders.java | 4 +- .../com/plotsquared/core/PlotSquared.java | 4 +- .../com/plotsquared/core/command/Add.java | 8 +- .../com/plotsquared/core/command/Alias.java | 6 +- .../com/plotsquared/core/command/Cluster.java | 47 ++++--- .../com/plotsquared/core/command/Deny.java | 5 +- .../com/plotsquared/core/command/Remove.java | 120 ++++++++---------- .../com/plotsquared/core/command/Trust.java | 104 ++++++++------- .../com/plotsquared/core/command/Visit.java | 9 +- .../core/configuration/Captions.java | 1 + .../core/configuration/Settings.java | 4 + .../com/plotsquared/core/util/MainUtil.java | 7 +- .../plotsquared/core/uuid/UUIDPipeline.java | 54 +++++++- 13 files changed, 226 insertions(+), 147 deletions(-) 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 f8a155d21..0ae44fbcb 100644 --- a/Bukkit/src/main/java/com/plotsquared/bukkit/placeholder/Placeholders.java +++ b/Bukkit/src/main/java/com/plotsquared/bukkit/placeholder/Placeholders.java @@ -26,6 +26,7 @@ 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 me.clip.placeholderapi.PlaceholderAPIPlugin; @@ -123,7 +124,8 @@ public class Placeholders extends PlaceholderExpansion { return ""; } - String name = PlotSquared.get().getImpromptuUUIDPipeline() .getSingle(uid, 5L); + String name = PlotSquared.get().getImpromptuUUIDPipeline() .getSingle(uid, + Settings.UUID.BLOCKING_TIMEOUT); if (name != null) { return name; diff --git a/Core/src/main/java/com/plotsquared/core/PlotSquared.java b/Core/src/main/java/com/plotsquared/core/PlotSquared.java index a19f167d7..67c5cab90 100644 --- a/Core/src/main/java/com/plotsquared/core/PlotSquared.java +++ b/Core/src/main/java/com/plotsquared/core/PlotSquared.java @@ -963,7 +963,7 @@ public class PlotSquared { * @return Set of Plot */ public Set getPlots(String world, String player) { - final UUID uuid = this.impromptuUUIDPipeline.getSingle(player, 10L); + final UUID uuid = this.impromptuUUIDPipeline.getSingle(player, Settings.UUID.BLOCKING_TIMEOUT); return getPlots(world, uuid); } @@ -975,7 +975,7 @@ public class PlotSquared { * @return Set of Plot */ public Set getPlots(PlotArea area, String player) { - final UUID uuid = this.impromptuUUIDPipeline.getSingle(player, 10L); + final UUID uuid = this.impromptuUUIDPipeline.getSingle(player, Settings.UUID.BLOCKING_TIMEOUT); return getPlots(area, uuid); } 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 32750f8d9..bbd0b5559 100644 --- a/Core/src/main/java/com/plotsquared/core/command/Add.java +++ b/Core/src/main/java/com/plotsquared/core/command/Add.java @@ -38,6 +38,7 @@ import com.plotsquared.core.util.task.RunnableVal3; import java.util.Iterator; 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.", @@ -65,7 +66,11 @@ public class Add extends Command { final CompletableFuture future = new CompletableFuture<>(); MainUtil.getUUIDsFromString(args[0], (uuids, throwable) -> { if (throwable != null) { - Captions.INVALID_PLAYER.send(player, args[0]); + if (throwable instanceof TimeoutException) { + Captions.FETCHING_PLAYERS_TIMEOUT.send(player); + } else { + Captions.INVALID_PLAYER.send(player, args[0]); + } future.completeExceptionally(throwable); return; } else { @@ -121,4 +126,5 @@ public class Add extends Command { }); return future; } + } 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 1df9848d0..3f1273014 100644 --- a/Core/src/main/java/com/plotsquared/core/command/Alias.java +++ b/Core/src/main/java/com/plotsquared/core/command/Alias.java @@ -34,6 +34,8 @@ import com.plotsquared.core.util.MainUtil; import com.plotsquared.core.util.MathMan; import com.plotsquared.core.util.Permissions; +import java.util.concurrent.TimeoutException; + @CommandDeclaration(command = "setalias", permission = "plots.alias", description = "Set the plot name", @@ -115,7 +117,9 @@ public class Alias extends SubCommand { } } PlotSquared.get().getImpromptuUUIDPipeline().getSingle(alias, ((uuid, throwable) -> { - if (uuid != null) { + 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); 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 82f602493..c9ce3d5ef 100644 --- a/Core/src/main/java/com/plotsquared/core/command/Cluster.java +++ b/Core/src/main/java/com/plotsquared/core/command/Cluster.java @@ -44,6 +44,7 @@ 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", @@ -373,7 +374,9 @@ public class Cluster extends SubCommand { PlotSquared.get().getImpromptuUUIDPipeline() .getSingle(args[1], (uuid, throwable) -> { - if (throwable != null) { + 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)) { @@ -426,7 +429,9 @@ public class Cluster extends SubCommand { // check uuid PlotSquared.get().getImpromptuUUIDPipeline() .getSingle(args[1], (uuid, throwable) -> { - if (throwable != null) { + 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 @@ -542,7 +547,9 @@ public class Cluster extends SubCommand { PlotSquared.get().getImpromptuUUIDPipeline() .getSingle(args[2], (uuid, throwable) -> { - if (throwable != null) { + 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")) { @@ -631,23 +638,27 @@ public class Cluster extends SubCommand { PlotSquared.get().getImpromptuUUIDPipeline() .getSingle(cluster.owner, (username, throwable) -> { - final String owner; - if (username == null) { - owner = "unknown"; + if (throwable instanceof TimeoutException) { + MainUtil.sendMessage(player, Captions.FETCHING_PLAYERS_TIMEOUT); } else { - owner = username; + 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); } - 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; } 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 072975226..3cf742f0c 100644 --- a/Core/src/main/java/com/plotsquared/core/command/Deny.java +++ b/Core/src/main/java/com/plotsquared/core/command/Deny.java @@ -37,6 +37,7 @@ import com.plotsquared.core.util.WorldUtil; import com.sk89q.worldedit.world.gamemode.GameModes; import java.util.UUID; +import java.util.concurrent.TimeoutException; @CommandDeclaration(command = "deny", aliases = {"d", "ban"}, @@ -68,7 +69,9 @@ public class Deny extends SubCommand { } MainUtil.getUUIDsFromString(args[0], (uuids, throwable) -> { - if (throwable != null || uuids.isEmpty()) { + 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 (UUID uuid : uuids) { 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..1a079f709 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,9 @@ 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 java.util.ArrayList; -import java.util.HashSet; -import java.util.Set; import java.util.UUID; +import java.util.concurrent.TimeoutException; @CommandDeclaration(command = "remove", aliases = {"r", "untrust", "ut", "undeny", "unban", "ud"}, @@ -68,74 +65,59 @@ 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; } + } 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..8bcaced4e 100644 --- a/Core/src/main/java/com/plotsquared/core/command/Trust.java +++ b/Core/src/main/java/com/plotsquared/core/command/Trust.java @@ -36,9 +36,9 @@ import com.plotsquared.core.util.task.RunnableVal2; import com.plotsquared.core.util.task.RunnableVal3; 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"}, @@ -65,51 +65,65 @@ 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); } + } 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 0c31076f2..78acbd88e 100644 --- a/Core/src/main/java/com/plotsquared/core/command/Visit.java +++ b/Core/src/main/java/com/plotsquared/core/command/Visit.java @@ -46,6 +46,7 @@ import java.util.HashSet; import java.util.List; import java.util.UUID; import java.util.concurrent.CompletableFuture; +import java.util.concurrent.TimeoutException; import java.util.concurrent.atomic.AtomicBoolean; import java.util.function.Consumer; @@ -156,7 +157,9 @@ public class Visit extends Command { } MainUtil.getUUIDsFromString(args[0], (uuids, throwable) -> { - if (throwable != null || uuids.size() != 1) { + if (throwable instanceof TimeoutException) { + Captions.FETCHING_PLAYERS_TIMEOUT.send(player); + } else if (throwable != null || uuids.size() != 1) { Captions.COMMAND_SYNTAX.send(player, getUsage()); } else { unsortedPre.addAll(PlotSquared.get().getBasePlots((UUID) uuids.toArray()[0])); @@ -188,7 +191,9 @@ public class Visit extends Command { if (args[0].length() >= 2) { PlotSquared.get().getImpromptuUUIDPipeline().getSingle(args[0], (uuid, throwable) -> { - if (uuid != null && !PlotSquared.get().hasPlot(uuid)) { + if (throwable instanceof TimeoutException) { + MainUtil.sendMessage(player, Captions.FETCHING_PLAYERS_TIMEOUT); + } else if (uuid != null && !PlotSquared.get().hasPlot(uuid)) { uuidConsumer.accept(null); } else { uuidConsumer.accept(uuid); 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 9d9251c61..98cb8b9ce 100644 --- a/Core/src/main/java/com/plotsquared/core/configuration/Captions.java +++ b/Core/src/main/java/com/plotsquared/core/configuration/Captions.java @@ -451,6 +451,7 @@ public enum Captions implements Caption { 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"), // 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 fff645253..85e493088 100644 --- a/Core/src/main/java/com/plotsquared/core/configuration/Settings.java +++ b/Core/src/main/java/com/plotsquared/core/configuration/Settings.java @@ -245,6 +245,10 @@ public class Settings extends Config { 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; } 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 4e887fead..e214e382a 100644 --- a/Core/src/main/java/com/plotsquared/core/util/MainUtil.java +++ b/Core/src/main/java/com/plotsquared/core/util/MainUtil.java @@ -383,7 +383,7 @@ public class MainUtil { if (owner.equals(DBFunc.SERVER)) { return Captions.SERVER.getTranslated(); } - String name = PlotSquared.get().getImpromptuUUIDPipeline().getSingle(owner, 10L); + String name = PlotSquared.get().getImpromptuUUIDPipeline().getSingle(owner, Settings.UUID.BLOCKING_TIMEOUT); if (name == null) { return Captions.UNKNOWN.getTranslated(); } @@ -454,7 +454,7 @@ public class MainUtil { for (String term : split) { try { - UUID uuid = PlotSquared.get().getImpromptuUUIDPipeline().getSingle(term, 10L); + UUID uuid = PlotSquared.get().getImpromptuUUIDPipeline().getSingle(term, Settings.UUID.BLOCKING_TIMEOUT); if (uuid == null) { uuid = UUID.fromString(term); } @@ -752,7 +752,8 @@ public class MainUtil { if (request.isEmpty()) { consumer.accept(result, null); } else { - PlotSquared.get().getImpromptuUUIDPipeline().getUUIDs(request).whenComplete((uuids, throwable) -> { + PlotSquared.get().getImpromptuUUIDPipeline().getUUIDs(request, Settings.UUID.NON_BLOCKING_TIMEOUT) + .whenComplete((uuids, throwable) -> { if (throwable != null) { consumer.accept(null, throwable); } else { diff --git a/Core/src/main/java/com/plotsquared/core/uuid/UUIDPipeline.java b/Core/src/main/java/com/plotsquared/core/uuid/UUIDPipeline.java index 6d85db51f..12d49abaa 100644 --- a/Core/src/main/java/com/plotsquared/core/uuid/UUIDPipeline.java +++ b/Core/src/main/java/com/plotsquared/core/uuid/UUIDPipeline.java @@ -27,6 +27,7 @@ package com.plotsquared.core.uuid; import com.google.common.collect.Lists; import com.plotsquared.core.PlotSquared; +import com.plotsquared.core.configuration.Settings; import com.plotsquared.core.util.ThreadUtils; import com.plotsquared.core.util.task.TaskManager; import org.jetbrains.annotations.NotNull; @@ -42,10 +43,13 @@ 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 @@ -60,6 +64,7 @@ public class UUIDPipeline { private final Executor executor; private final List serviceList; private final List>> consumerList; + private final ScheduledExecutorService timeoutExecutor; /** * Construct a new UUID pipeline @@ -71,6 +76,7 @@ public class UUIDPipeline { this.executor = executor; this.serviceList = Lists.newLinkedList(); this.consumerList = Lists.newLinkedList(); + this.timeoutExecutor = Executors.newSingleThreadScheduledExecutor(); } /** @@ -184,8 +190,10 @@ public class UUIDPipeline { * @param username Username * @param uuid UUID consumer */ - public void getSingle(@NotNull final String username, @NotNull final BiConsumer uuid) { - this.getUUIDs(Collections.singletonList(username)).whenComplete((uuids, throwable) -> { + 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 { @@ -204,8 +212,10 @@ public class UUIDPipeline { * @param uuid UUID * @param username Username consumer */ - public void getSingle(@NotNull final UUID uuid, @NotNull final BiConsumer username) { - this.getNames(Collections.singletonList(uuid)).whenComplete((uuids, throwable) -> { + 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 { @@ -218,6 +228,42 @@ public class UUIDPipeline { }); } + /** + * 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 * From 973c18623f4f9899515efd97594a2b37f34a5057 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20S=C3=B6derberg?= Date: Tue, 19 May 2020 19:34:33 +0200 Subject: [PATCH 17/33] Port more commands and add more tab completion utilities --- .../com/plotsquared/core/command/ListCmd.java | 185 ++++++++++-------- .../com/plotsquared/core/command/Set.java | 7 +- .../plotsquared/core/util/PatternUtil.java | 2 +- .../plotsquared/core/util/TabCompletions.java | 18 +- 4 files changed, 118 insertions(+), 94 deletions(-) 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..e9304e53f 100644 --- a/Core/src/main/java/com/plotsquared/core/command/ListCmd.java +++ b/Core/src/main/java/com/plotsquared/core/command/ListCmd.java @@ -29,6 +29,7 @@ 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; @@ -44,20 +45,25 @@ import com.plotsquared.core.util.Permissions; import com.plotsquared.core.util.StringComparison; import com.plotsquared.core.util.StringMan; 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.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; @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) { @@ -84,9 +90,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(""); } @@ -115,25 +118,44 @@ public class ListCmd extends SubCommand { 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 = plots -> { + if (plots == null) { + sendMessage(player, Captions.DID_YOU_MEAN, + new StringComparison<>(args[0], new String[] {"mine", "shared", "world", "all"}) + .getBestMatch()); + return; + } + + if (plots.isEmpty()) { + MainUtil.sendMessage(player, Captions.FOUND_NO_PLOTS); + return; + } + displayPlots(player, new ArrayList<>(plots), 12, page, area, args, sort[0]); + }; + + final List plots = new ArrayList<>(); switch (arg) { case "mine": if (!Permissions.hasPermission(player, Captions.PERMISSION_LIST_MINE)) { @@ -141,8 +163,9 @@ 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( + PlotSquared.get().sortPlotsByTemp(PlotSquared.get().getBasePlots(player))); break; case "shared": if (!Permissions.hasPermission(player, Captions.PERMISSION_LIST_SHARED)) { @@ -150,13 +173,13 @@ 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(plots); break; case "world": if (!Permissions.hasPermission(player, Captions.PERMISSION_LIST_WORLD)) { @@ -171,7 +194,7 @@ public class ListCmd extends SubCommand { world)); return false; } - plots = new ArrayList<>(PlotSquared.get().getPlots(world)); + plotConsumer.accept(PlotSquared.get().getPlots(world)); break; case "expired": if (!Permissions.hasPermission(player, Captions.PERMISSION_LIST_EXPIRED)) { @@ -179,9 +202,9 @@ public class ListCmd extends SubCommand { Captions.PERMISSION_LIST_EXPIRED); return false; } - plots = ExpireManager.IMP == null ? - new ArrayList() : - new ArrayList<>(ExpireManager.IMP.getPendingExpired()); + plotConsumer.accept(ExpireManager.IMP == null ? + new ArrayList<>() : + new ArrayList<>(ExpireManager.IMP.getPendingExpired())); break; case "area": if (!Permissions.hasPermission(player, Captions.PERMISSION_LIST_AREA)) { @@ -196,7 +219,8 @@ public class ListCmd extends SubCommand { world)); return false; } - plots = area == null ? new ArrayList() : new ArrayList<>(area.getPlots()); + plotConsumer.accept( + area == null ? new ArrayList() : new ArrayList<>(area.getPlots())); break; case "all": if (!Permissions.hasPermission(player, Captions.PERMISSION_LIST_ALL)) { @@ -204,7 +228,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(new ArrayList<>(PlotSquared.get().getPlots())); break; case "done": if (!Permissions.hasPermission(player, Captions.PERMISSION_LIST_DONE)) { @@ -212,7 +236,6 @@ 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); @@ -229,7 +252,8 @@ public class ListCmd extends SubCommand { } return 1; }); - sort = false; + sort[0] = false; + plotConsumer.accept(plots); break; case "top": if (!Permissions.hasPermission(player, Captions.PERMISSION_LIST_TOP)) { @@ -237,7 +261,7 @@ public class ListCmd extends SubCommand { .sendMessage(player, Captions.NO_PERMISSION, Captions.PERMISSION_LIST_TOP); return false; } - plots = new ArrayList<>(PlotSquared.get().getPlots()); + plots.addAll(PlotSquared.get().getPlots()); plots.sort((p1, p2) -> { double v1 = 0; int p1s = p1.getSettings().getRatings().size(); @@ -262,7 +286,8 @@ public class ListCmd extends SubCommand { } return (int) Math.signum(v2 - v1); }); - sort = false; + sort[0] = false; + plotConsumer.accept(plots); break; case "forsale": if (!Permissions.hasPermission(player, Captions.PERMISSION_LIST_FOR_SALE)) { @@ -273,12 +298,12 @@ public class ListCmd extends SubCommand { if (EconHandler.manager == null) { break; } - plots = new ArrayList<>(); for (Plot plot : PlotSquared.get().getPlots()) { if (plot.getFlag(PriceFlag.class) > 0) { plots.add(plot); } } + plotConsumer.accept(plots); break; case "unowned": if (!Permissions.hasPermission(player, Captions.PERMISSION_LIST_UNOWNED)) { @@ -286,28 +311,12 @@ 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(plots); break; case "fuzzy": if (!Permissions.hasPermission(player, Captions.PERMISSION_LIST_FUZZY)) { @@ -325,8 +334,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(MainUtil.getPlotsBySearch(term)); break; default: if (PlotSquared.get().hasPlotArea(args[0])) { @@ -343,40 +352,39 @@ 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(new ArrayList<>(PlotSquared.get().getPlots(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(PlotSquared.get() + .sortPlotsByTemp(PlotSquared.get().getPlots(uuid))); + } + } + }); + break; } - 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; } @@ -417,22 +425,25 @@ 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()); 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 413ae3e4b..bf5285691 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; @@ -158,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, ",")); } }; } 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/TabCompletions.java b/Core/src/main/java/com/plotsquared/core/util/TabCompletions.java index a7c7c2a8f..0c1dbf4df 100644 --- a/Core/src/main/java/com/plotsquared/core/util/TabCompletions.java +++ b/Core/src/main/java/com/plotsquared/core/util/TabCompletions.java @@ -45,7 +45,8 @@ import java.util.stream.Collectors; /** * Tab completion utilities */ -@UtilityClass public class TabCompletions { +@UtilityClass +public class TabCompletions { private final Cache> cachedCompletionValues = CacheBuilder.newBuilder().expireAfterWrite(1, TimeUnit.MINUTES).build(); @@ -79,4 +80,19 @@ import java.util.stream.Collectors; }).collect(Collectors.toList()); } + /** + * 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()); + } + } From 8efc78e1c95c1114b4f56fb1ed4e5619b72028e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20S=C3=B6derberg?= Date: Tue, 19 May 2020 23:05:36 +0200 Subject: [PATCH 18/33] IT COMPILES! --- .../bukkit/player/BukkitPlayerManager.java | 17 +- .../bukkit/util/uuid/DefaultUUIDWrapper.java | 66 ------- .../java/com/plotsquared/core/IPlotMain.java | 2 +- .../core/backup/PlayerBackupProfile.java | 2 +- .../com/plotsquared/core/command/Buy.java | 9 +- .../plotsquared/core/command/DebugExec.java | 27 --- .../plotsquared/core/command/DebugPaste.java | 3 +- .../com/plotsquared/core/command/Grant.java | 76 ++++---- .../com/plotsquared/core/command/Kick.java | 99 +++++----- .../plotsquared/core/command/MainCommand.java | 1 - .../com/plotsquared/core/command/Merge.java | 5 +- .../com/plotsquared/core/command/Owner.java | 175 ++++++++++-------- .../com/plotsquared/core/command/Purge.java | 17 +- .../java/com/plotsquared/core/plot/Plot.java | 5 +- .../core/plot/expiration/ExpireManager.java | 52 ++---- .../core/queue/LocalBlockQueue.java | 8 +- .../plotsquared/core/util/PlayerManager.java | 35 +++- .../core/util/SchematicHandler.java | 15 +- .../util/UUIDHandlerImplementationTest.java | 49 ----- 19 files changed, 267 insertions(+), 396 deletions(-) delete mode 100644 Bukkit/src/main/java/com/plotsquared/bukkit/util/uuid/DefaultUUIDWrapper.java delete mode 100644 Core/src/test/java/com/plotsquared/core/plot/util/UUIDHandlerImplementationTest.java diff --git a/Bukkit/src/main/java/com/plotsquared/bukkit/player/BukkitPlayerManager.java b/Bukkit/src/main/java/com/plotsquared/bukkit/player/BukkitPlayerManager.java index 6e628a8a7..cdb770e2f 100644 --- a/Bukkit/src/main/java/com/plotsquared/bukkit/player/BukkitPlayerManager.java +++ b/Bukkit/src/main/java/com/plotsquared/bukkit/player/BukkitPlayerManager.java @@ -25,20 +25,20 @@ */ package com.plotsquared.bukkit.player; -import com.plotsquared.core.player.PlotPlayer; import com.plotsquared.core.util.PlayerManager; import org.bukkit.Bukkit; import org.bukkit.entity.Player; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.util.UUID; /** * Player manager providing {@link BukkitPlayer Bukkit players} */ -public class BukkitPlayerManager extends PlayerManager { +public class BukkitPlayerManager extends PlayerManager { - @Override @NotNull public PlotPlayer createPlayer(@NotNull final UUID uuid) { + @Override @NotNull public BukkitPlayer createPlayer(@NotNull final UUID uuid) { final Player player = Bukkit.getPlayer(uuid); if (player == null || !player.isOnline()) { throw new NoSuchPlayerException(uuid); @@ -46,4 +46,15 @@ public class BukkitPlayerManager extends PlayerManager { return new BukkitPlayer(player); } + @Nullable @Override public BukkitOfflinePlayer getOfflinePlayer(@Nullable final UUID uuid) { + if (uuid == null) { + return null; + } + return new BukkitOfflinePlayer(Bukkit.getOfflinePlayer(uuid)); + } + + @NotNull @Override public BukkitOfflinePlayer getOfflinePlayer(@NotNull final String username) { + return new BukkitOfflinePlayer(Bukkit.getOfflinePlayer(username)); + } + } diff --git a/Bukkit/src/main/java/com/plotsquared/bukkit/util/uuid/DefaultUUIDWrapper.java b/Bukkit/src/main/java/com/plotsquared/bukkit/util/uuid/DefaultUUIDWrapper.java deleted file mode 100644 index a2898ee91..000000000 --- a/Bukkit/src/main/java/com/plotsquared/bukkit/util/uuid/DefaultUUIDWrapper.java +++ /dev/null @@ -1,66 +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.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 org.bukkit.Bukkit; -import org.bukkit.OfflinePlayer; -import org.jetbrains.annotations.NotNull; - -import java.util.Arrays; -import java.util.UUID; - -public class DefaultUUIDWrapper extends UUIDWrapper { - - @NotNull @Override public UUID getUUID(PlotPlayer player) { - return ((BukkitPlayer) player).player.getUniqueId(); - } - - @Override public UUID getUUID(OfflinePlotPlayer player) { - return player.getUUID(); - } - - @Override public OfflinePlotPlayer getOfflinePlayer(UUID uuid) { - return new BukkitOfflinePlayer(Bukkit.getOfflinePlayer(uuid)); - } - - @Override public UUID getUUID(String name) { - return Bukkit.getOfflinePlayer(name).getUniqueId(); - } - - @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/Core/src/main/java/com/plotsquared/core/IPlotMain.java b/Core/src/main/java/com/plotsquared/core/IPlotMain.java index 2705d54c2..9e04d85ec 100644 --- a/Core/src/main/java/com/plotsquared/core/IPlotMain.java +++ b/Core/src/main/java/com/plotsquared/core/IPlotMain.java @@ -286,6 +286,6 @@ public interface IPlotMain extends ILogger { * * @return Player manager */ - @NotNull PlayerManager getPlayerManager(); + @NotNull PlayerManager getPlayerManager(); } 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/Buy.java b/Core/src/main/java/com/plotsquared/core/command/Buy.java index a660a39a1..b986a7983 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; @@ -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.manager.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/DebugExec.java b/Core/src/main/java/com/plotsquared/core/command/DebugExec.java index 8976c3348..9f179803f 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", @@ -172,7 +167,6 @@ public class DebugExec extends SubCommand { 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("DBFunc", DBFunc.dbManager); this.scope.put("HybridUtils", HybridUtils.manager); this.scope.put("IMP", PlotSquared.get().IMP); @@ -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 "?": 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..412d2b066 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; @@ -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 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..39351c27f 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, @@ -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/Kick.java b/Core/src/main/java/com/plotsquared/core/command/Kick.java index 1d113a874..69ace1482 100644 --- a/Core/src/main/java/com/plotsquared/core/command/Kick.java +++ b/Core/src/main/java/com/plotsquared/core/command/Kick.java @@ -34,11 +34,11 @@ import com.plotsquared.core.plot.Plot; import com.plotsquared.core.util.MainUtil; import com.plotsquared.core.util.Permissions; import com.plotsquared.core.util.WorldUtil; -import com.plotsquared.core.util.uuid.UUIDHandler; import java.util.HashSet; import java.util.Set; import java.util.UUID; +import java.util.concurrent.TimeoutException; @CommandDeclaration(command = "kick", aliases = "k", @@ -64,57 +64,62 @@ 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); + } 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; } } 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..133e27ab2 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(); 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 7998e3a84..53f88e2e7 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; @@ -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,7 +221,7 @@ 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; 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..cb436fad2 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); + } else { + uuidConsumer.accept(uuid); + } + }); } return true; } 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..50b323300 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; @@ -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/plot/Plot.java b/Core/src/main/java/com/plotsquared/core/plot/Plot.java index e7cfbcafd..9ac482be6 100644 --- a/Core/src/main/java/com/plotsquared/core/plot/Plot.java +++ b/Core/src/main/java/com/plotsquared/core/plot/Plot.java @@ -496,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()); @@ -1711,7 +1711,8 @@ public class Plot { this.setSign("unknown"); return; } - PlotSquared.get().getImpromptuUUIDPipeline().getSingle(this.getOwnerAbs(), this::setSign); + PlotSquared.get().getImpromptuUUIDPipeline().getSingle(this.getOwnerAbs(), (username, sign) -> + this.setSign(username)); } /** 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..16d4ee41f 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; @@ -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/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/util/PlayerManager.java b/Core/src/main/java/com/plotsquared/core/util/PlayerManager.java index fd1eebe4e..473826b2d 100644 --- a/Core/src/main/java/com/plotsquared/core/util/PlayerManager.java +++ b/Core/src/main/java/com/plotsquared/core/util/PlayerManager.java @@ -25,6 +25,7 @@ */ 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; @@ -38,9 +39,9 @@ import java.util.UUID; /** * Manages player instances */ -public abstract class PlayerManager { +public abstract class PlayerManager

{ - private final Map playerMap = new HashMap<>(); + private final Map playerMap = new HashMap<>(); private final Object playerLock = new Object(); /** @@ -60,15 +61,15 @@ public abstract class PlayerManager { * @param uuid Player UUID * @return Player, or null */ - @Nullable public PlotPlayer getPlayerIfExists(@Nullable final UUID uuid) { + @Nullable public P getPlayerIfExists(@Nullable final UUID uuid) { if (uuid == null) { return null; } return this.playerMap.get(uuid); } - @Nullable public PlotPlayer getPlayerIfExists(@Nullable final String name) { - for (final PlotPlayer plotPlayer : this.playerMap.values()) { + @Nullable public P getPlayerIfExists(@Nullable final String name) { + for (final P plotPlayer : this.playerMap.values()) { if (plotPlayer.getName().equalsIgnoreCase(name)) { return plotPlayer; } @@ -86,9 +87,9 @@ public abstract class PlayerManager { * @param uuid Player UUID * @return Player object */ - @NotNull public PlotPlayer getPlayer(@NotNull final UUID uuid) { + @NotNull public P getPlayer(@NotNull final UUID uuid) { synchronized (playerLock) { - PlotPlayer player = this.playerMap.get(uuid); + P player = this.playerMap.get(uuid); if (player == null) { player = createPlayer(uuid); this.playerMap.put(uuid, player); @@ -97,14 +98,30 @@ public abstract class PlayerManager { } } - @NotNull protected abstract PlotPlayer createPlayer(@NotNull final UUID uuid); + @NotNull protected 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 O 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 O getOfflinePlayer(@NotNull final String username); /** * Get all online players * * @return Unmodifiable collection of players */ - public Collection getPlayers() { + public Collection

getPlayers() { return Collections.unmodifiableCollection(this.playerMap.values()); } 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 aa9e7a04c..78cc7192c 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.CompoundTag; import com.sk89q.jnbt.NBTInputStream; import com.sk89q.jnbt.NBTOutputStream; @@ -104,16 +103,24 @@ public abstract class SchematicHandler { Iterator i = plots.iterator(); final Plot plot = i.next(); i.remove(); - String owner = UUIDHandler.getName(plot.getOwnerAbs()); - if (owner == null) { + + PlotSquared.get().getImpromptuUUIDPipeline().getSingle(plot.getOwnerAbs(), (username, throwable) -> { + + }); + + 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) + name = namingScheme .replaceAll("%id%", plot.getId().toString()) .replaceAll("%idx%", plot.getId().x + "") .replaceAll("%idy%", plot.getId().y + "") diff --git a/Core/src/test/java/com/plotsquared/core/plot/util/UUIDHandlerImplementationTest.java b/Core/src/test/java/com/plotsquared/core/plot/util/UUIDHandlerImplementationTest.java deleted file mode 100644 index 9bcad05bd..000000000 --- a/Core/src/test/java/com/plotsquared/core/plot/util/UUIDHandlerImplementationTest.java +++ /dev/null @@ -1,49 +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.plot.util; - -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.OfflinePlayerService; -import org.junit.Before; - -import java.util.UUID; - -public class UUIDHandlerImplementationTest extends UUIDHandlerImplementation { - - public UUIDHandlerImplementationTest(OfflinePlayerService wrapper) { - super(wrapper); - } - - @Before public void setUp() throws Exception { - DBFunc.dbManager = new AbstractDBTest(); - } - - @Override public void fetchUUID(String name, RunnableVal ifFetch) { - - } -} From ea41c842bc379af8a2ebc8d152da23cd5202b748 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20S=C3=B6derberg?= Date: Wed, 20 May 2020 00:31:59 +0200 Subject: [PATCH 19/33] Fix a bunch of minor issues --- Bukkit/pom.xml | 6 ++ .../bukkit/listener/PaperListener.java | 4 +- .../com/plotsquared/core/command/Add.java | 7 ++ .../com/plotsquared/core/command/Debug.java | 7 ++ .../com/plotsquared/core/command/Owner.java | 2 +- .../com/plotsquared/core/command/Trust.java | 7 ++ .../com/plotsquared/core/util/MainUtil.java | 64 +++++++++++--- .../core/uuid/CacheUUIDService.java | 3 + .../plotsquared/core/uuid/UUIDPipeline.java | 85 +++++++++++++++---- .../plotsquared/core/uuid/UUIDService.java | 10 +++ 10 files changed, 160 insertions(+), 35 deletions(-) diff --git a/Bukkit/pom.xml b/Bukkit/pom.xml index 1eace8462..68e49c901 100644 --- a/Bukkit/pom.xml +++ b/Bukkit/pom.xml @@ -66,6 +66,12 @@ + + com.github.pavog + SquirrelID + 0.6.1 + compile + com.sk89q.worldedit worldedit-core 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 2ff395c52..925798a8a 100644 --- a/Bukkit/src/main/java/com/plotsquared/bukkit/listener/PaperListener.java +++ b/Bukkit/src/main/java/com/plotsquared/bukkit/listener/PaperListener.java @@ -318,7 +318,6 @@ public class PaperListener implements Listener { } @EventHandler public void onAsyncTabCompletion(final AsyncTabCompleteEvent event) { - PlotSquared.debug("ASYNC COMPLETION"); String buffer = event.getBuffer(); if (!(event.getSender() instanceof Player)) { return; @@ -332,7 +331,7 @@ public class PaperListener implements Listener { final String[] unprocessedArgs = buffer.split(Pattern.quote(" ")); if (unprocessedArgs.length == 1) { return; // We don't do anything in this case - } else if (!Arrays.asList("plots", "p", "plotsquared", "plot2", "p2", "ps", "2", "plotme", "plotz", "ap") + } else if (!Arrays.asList("plot", "plots", "p", "plotsquared", "plot2", "p2", "ps", "2", "plotme", "plotz", "ap") .contains(unprocessedArgs[0].toLowerCase(Locale.ENGLISH))) { return; } @@ -350,7 +349,6 @@ public class PaperListener implements Listener { } event.setCompletions(result); event.setHandled(true); - PlotSquared.debug("ASYNC COMPLETION HANDLED"); } catch (final Exception ignored) {} } 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 bbd0b5559..3a3aa7ab7 100644 --- a/Core/src/main/java/com/plotsquared/core/command/Add.java +++ b/Core/src/main/java/com/plotsquared/core/command/Add.java @@ -32,9 +32,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.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.UUID; import java.util.concurrent.CompletableFuture; @@ -127,4 +130,8 @@ public class Add extends Command { 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/Debug.java b/Core/src/main/java/com/plotsquared/core/command/Debug.java index 7d0ced991..e104da337 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; @@ -65,6 +67,11 @@ 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 && "entitytypes".equalsIgnoreCase(args[0])) { EntityCategories.init(); player.sendMessage(Captions.PREFIX.getTranslated() + "§cEntity Categories: "); 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 cb436fad2..f19790dc5 100644 --- a/Core/src/main/java/com/plotsquared/core/command/Owner.java +++ b/Core/src/main/java/com/plotsquared/core/command/Owner.java @@ -150,7 +150,7 @@ public class Owner extends SetCommand { if (throwable instanceof TimeoutException) { MainUtil.sendMessage(player, Captions.FETCHING_PLAYERS_TIMEOUT); } else if (throwable != null) { - MainUtil.sendMessage(player, Captions.INVALID_PLAYER); + MainUtil.sendMessage(player, Captions.INVALID_PLAYER, value); } else { uuidConsumer.accept(uuid); } 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 8bcaced4e..4f9c15e38 100644 --- a/Core/src/main/java/com/plotsquared/core/command/Trust.java +++ b/Core/src/main/java/com/plotsquared/core/command/Trust.java @@ -32,9 +32,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.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.UUID; import java.util.concurrent.CompletableFuture; @@ -126,4 +129,8 @@ public class Trust extends Command { 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/util/MainUtil.java b/Core/src/main/java/com/plotsquared/core/util/MainUtil.java index e214e382a..8546298b6 100644 --- a/Core/src/main/java/com/plotsquared/core/util/MainUtil.java +++ b/Core/src/main/java/com/plotsquared/core/util/MainUtil.java @@ -82,6 +82,7 @@ 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; @@ -902,24 +903,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))); diff --git a/Core/src/main/java/com/plotsquared/core/uuid/CacheUUIDService.java b/Core/src/main/java/com/plotsquared/core/uuid/CacheUUIDService.java index 32bbbb6bc..484146dae 100644 --- a/Core/src/main/java/com/plotsquared/core/uuid/CacheUUIDService.java +++ b/Core/src/main/java/com/plotsquared/core/uuid/CacheUUIDService.java @@ -78,4 +78,7 @@ public class CacheUUIDService implements UUIDService, Consumer return this.usernameCache.asMap().values(); } + @Override public boolean canBeSynchronous() { + return true; + } } diff --git a/Core/src/main/java/com/plotsquared/core/uuid/UUIDPipeline.java b/Core/src/main/java/com/plotsquared/core/uuid/UUIDPipeline.java index 12d49abaa..3518fa5f8 100644 --- a/Core/src/main/java/com/plotsquared/core/uuid/UUIDPipeline.java +++ b/Core/src/main/java/com/plotsquared/core/uuid/UUIDPipeline.java @@ -27,6 +27,7 @@ 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; @@ -156,10 +157,14 @@ public class UUIDPipeline { @Nullable public UUID getSingle(@NotNull final String username, final long timeout) { ThreadUtils.catchSync("Blocking UUID retrieval from the main thread"); try { - this.getUUIDs(Collections.singletonList(username)).get(timeout, TimeUnit.MILLISECONDS); + 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; @@ -175,10 +180,14 @@ public class UUIDPipeline { @Nullable public String getSingle(@NotNull final UUID uuid, final long timeout) { ThreadUtils.catchSync("Blocking username retrieval from the main thread"); try { - this.getNames(Collections.singletonList(uuid)).get(timeout, TimeUnit.MILLISECONDS); + 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; @@ -274,25 +283,45 @@ public class UUIDPipeline { if (requests.isEmpty()) { return CompletableFuture.completedFuture(Collections.emptyList()); } - final List serviceList = this.getServiceListInstance(); - return CompletableFuture.supplyAsync(() -> { - final List mappings = new ArrayList<>(requests.size()); - final List remainingRequests = new ArrayList<>(requests); - for (final UUIDService service : serviceList) { - if (remainingRequests.isEmpty()) { - break; - } + 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"); } throw new ServiceError("End of pipeline"); @@ -310,25 +339,45 @@ public class UUIDPipeline { if (requests.isEmpty()) { return CompletableFuture.completedFuture(Collections.emptyList()); } - final List serviceList = this.getServiceListInstance(); - return CompletableFuture.supplyAsync(() -> { - final List mappings = new ArrayList<>(requests.size()); - final List remainingRequests = new ArrayList<>(requests); - for (final UUIDService service : serviceList) { - if (remainingRequests.isEmpty()) { - break; - } + 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"); diff --git a/Core/src/main/java/com/plotsquared/core/uuid/UUIDService.java b/Core/src/main/java/com/plotsquared/core/uuid/UUIDService.java index 25588305e..3b6419bd6 100644 --- a/Core/src/main/java/com/plotsquared/core/uuid/UUIDService.java +++ b/Core/src/main/java/com/plotsquared/core/uuid/UUIDService.java @@ -65,4 +65,14 @@ public interface UUIDService { 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; + } + } From 2417dace2d9a9d4a6dfd92e068a3f81bb01e4dec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20S=C3=B6derberg?= Date: Wed, 20 May 2020 15:12:09 +0200 Subject: [PATCH 20/33] Add UUID caching --- .../com/plotsquared/bukkit/BukkitMain.java | 60 ++++++++++++++++++- .../bukkit/uuid/SQLiteUUIDService.java | 21 +++++++ .../com/plotsquared/core/PlotSquared.java | 17 ------ 3 files changed, 80 insertions(+), 18 deletions(-) diff --git a/Bukkit/src/main/java/com/plotsquared/bukkit/BukkitMain.java b/Bukkit/src/main/java/com/plotsquared/bukkit/BukkitMain.java index 90a717fd5..7effa5b4a 100644 --- a/Bukkit/src/main/java/com/plotsquared/bukkit/BukkitMain.java +++ b/Bukkit/src/main/java/com/plotsquared/bukkit/BukkitMain.java @@ -136,10 +136,17 @@ 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; @@ -243,6 +250,8 @@ public final class BukkitMain extends JavaPlugin implements Listener, IPlotMain final OfflinePlayerUUIDService offlinePlayerUUIDService = new OfflinePlayerUUIDService(); impromptuPipeline.registerService(offlinePlayerUUIDService); backgroundPipeline.registerService(offlinePlayerUUIDService); + + final SQLiteUUIDService sqLiteUUIDService = new SQLiteUUIDService(); if (!Settings.UUID.OFFLINE) { // If running Paper we'll also try to use their profiles if (PaperLib.isPaper()) { @@ -250,7 +259,6 @@ public final class BukkitMain extends JavaPlugin implements Listener, IPlotMain impromptuPipeline.registerService(paperUUIDService); backgroundPipeline.registerService(paperUUIDService); } - final SQLiteUUIDService sqLiteUUIDService = new SQLiteUUIDService(); impromptuPipeline.registerService(sqLiteUUIDService); backgroundPipeline.registerService(sqLiteUUIDService); impromptuPipeline.registerConsumer(sqLiteUUIDService); @@ -259,9 +267,15 @@ public final class BukkitMain extends JavaPlugin implements Listener, IPlotMain 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); } impromptuPipeline.storeImmediately("*", DBFunc.EVERYONE); + this.startUuidCatching(sqLiteUUIDService, cacheUUIDService); if (Bukkit.getPluginManager().getPlugin("PlaceholderAPI") != null) { new Placeholders().register(); @@ -384,6 +398,50 @@ 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); + while (!uuidQueue.isEmpty()) { + for (int i = 0; i < Settings.UUID.BACKGROUND_LIMIT && !uuidQueue.isEmpty(); i++) { + uuidList.add(uuidQueue.poll()); + read++; + } + try { + PlotSquared.get().getBackgroundUUIDPipeline().getNames(uuidList).get(); + } catch (final InterruptedException | ExecutionException e) { + e.printStackTrace(); + } + final double percentage = ((double) read / (double) totalSize) * 100.0D; + PlotSquared.log(Captions.PREFIX.getTranslated() + String.format("(UUID) PlotSquared has cached %.1f%% of UUIDs", percentage)); + } + 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); diff --git a/Bukkit/src/main/java/com/plotsquared/bukkit/uuid/SQLiteUUIDService.java b/Bukkit/src/main/java/com/plotsquared/bukkit/uuid/SQLiteUUIDService.java index 6ad2f01ce..dc251bec4 100644 --- a/Bukkit/src/main/java/com/plotsquared/bukkit/uuid/SQLiteUUIDService.java +++ b/Bukkit/src/main/java/com/plotsquared/bukkit/uuid/SQLiteUUIDService.java @@ -37,6 +37,7 @@ 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; @@ -121,4 +122,24 @@ public class SQLiteUUIDService implements UUIDService, Consumer 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/Core/src/main/java/com/plotsquared/core/PlotSquared.java b/Core/src/main/java/com/plotsquared/core/PlotSquared.java index 4d632ff2f..6c3b78ba3 100644 --- a/Core/src/main/java/com/plotsquared/core/PlotSquared.java +++ b/Core/src/main/java/com/plotsquared/core/PlotSquared.java @@ -424,23 +424,6 @@ public class PlotSquared { } } - private void startUuidCatching() { - TaskManager.runTaskLater(() -> { - debug("Starting UUID caching"); - /*UUIDHandler.startCaching(() -> { - forEachPlotRaw(plot -> { - if (plot.hasOwner() && plot.temp != -1) { - if (UUIDHandler.getName(plot.getOwnerAbs()) == null) { - UUIDHandler.implementation.unknown.add(plot.getOwnerAbs()); - } - } - }); - startExpiryTasks(); - });*/ - // TODO: Re-implement - }, 20); - } - private void startExpiryTasks() { if (Settings.Enabled_Components.PLOT_EXPIRY) { ExpireManager.IMP = new ExpireManager(); From f01b242e4adac1666b7284755a5df53532dc7f22 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20S=C3=B6derberg?= Date: Wed, 20 May 2020 15:26:20 +0200 Subject: [PATCH 21/33] For sign updating to be scheduled asynchronously. It then forces it back on the main thread, so it's fine, but this way we can safely wait for the UUID mapping to be fetched. --- Core/src/main/java/com/plotsquared/core/plot/Plot.java | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) 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 9ac482be6..df9ee12c4 100644 --- a/Core/src/main/java/com/plotsquared/core/plot/Plot.java +++ b/Core/src/main/java/com/plotsquared/core/plot/Plot.java @@ -1046,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) { From 3b7057ad4fe82ee0b9b451cee95612f771fd4e36 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20S=C3=B6derberg?= Date: Thu, 21 May 2020 21:24:55 +0200 Subject: [PATCH 22/33] do a second attempt at fetching uuid batches even if it errors --- .../com/plotsquared/bukkit/BukkitMain.java | 34 +++++++++++++++---- 1 file changed, 28 insertions(+), 6 deletions(-) diff --git a/Bukkit/src/main/java/com/plotsquared/bukkit/BukkitMain.java b/Bukkit/src/main/java/com/plotsquared/bukkit/BukkitMain.java index 7effa5b4a..84ba2f591 100644 --- a/Bukkit/src/main/java/com/plotsquared/bukkit/BukkitMain.java +++ b/Bukkit/src/main/java/com/plotsquared/bukkit/BukkitMain.java @@ -425,18 +425,40 @@ public final class BukkitMain extends JavaPlugin implements Listener, IPlotMain 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); - while (!uuidQueue.isEmpty()) { - for (int i = 0; i < Settings.UUID.BACKGROUND_LIMIT && !uuidQueue.isEmpty(); i++) { - uuidList.add(uuidQueue.poll()); - read++; + + // 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(); } - final double percentage = ((double) read / (double) totalSize) * 100.0D; - PlotSquared.log(Captions.PREFIX.getTranslated() + String.format("(UUID) PlotSquared has cached %.1f%% of UUIDs", percentage)); } PlotSquared.log(Captions.PREFIX.getTranslated() + "(UUID) PlotSquared has cached all UUIDs"); }, 10, TimeUnit.SECONDS); From 6c6c2b57a127e8a88eb25995fbc805a994d4eefa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20S=C3=B6derberg?= Date: Sat, 23 May 2020 17:20:09 +0200 Subject: [PATCH 23/33] Add options to disable tab completion and extend username completion, also limit the total number of username suggestions to 200 per request --- .../bukkit/listener/PaperListener.java | 3 ++ .../core/configuration/Settings.java | 9 +++--- .../plotsquared/core/util/TabCompletions.java | 32 +++++++++++++------ 3 files changed, 30 insertions(+), 14 deletions(-) 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 925798a8a..ec5384ab5 100644 --- a/Bukkit/src/main/java/com/plotsquared/bukkit/listener/PaperListener.java +++ b/Bukkit/src/main/java/com/plotsquared/bukkit/listener/PaperListener.java @@ -318,6 +318,9 @@ public class PaperListener implements Listener { } @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; 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 f295c465f..0c2e30be9 100644 --- a/Core/src/main/java/com/plotsquared/core/configuration/Settings.java +++ b/Core/src/main/java/com/plotsquared/core/configuration/Settings.java @@ -238,7 +238,6 @@ public class Settings extends Config { @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") @@ -497,6 +496,8 @@ 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") @@ -514,8 +515,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; @@ -544,10 +543,10 @@ public class Settings extends Config { 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("Use UUID cache to complete usernames") + public static boolean EXTENDED_USERNAME_COMPLETION = true; } } diff --git a/Core/src/main/java/com/plotsquared/core/util/TabCompletions.java b/Core/src/main/java/com/plotsquared/core/util/TabCompletions.java index 0c1dbf4df..0369ad730 100644 --- a/Core/src/main/java/com/plotsquared/core/util/TabCompletions.java +++ b/Core/src/main/java/com/plotsquared/core/util/TabCompletions.java @@ -31,6 +31,8 @@ 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.uuid.UUIDMapping; import lombok.experimental.UtilityClass; import org.jetbrains.annotations.NotNull; @@ -61,15 +63,24 @@ public class TabCompletions { */ @NotNull public List completePlayers(@NotNull final String input, @NotNull final List existing) { - List players = cachedCompletionValues.getIfPresent("players"); - if (players == null) { - final Collection mappings = - PlotSquared.get().getImpromptuUUIDPipeline().getAllImmediately(); - players = new ArrayList<>(mappings.size()); - for (final UUIDMapping mapping : mappings) { - players.add(mapping.getUsername()); + List players; + if (Settings.Enabled_Components.EXTENDED_USERNAME_COMPLETION) { + players = cachedCompletionValues.getIfPresent("players"); + if (players == null) { + final Collection mappings = + PlotSquared.get().getImpromptuUUIDPipeline().getAllImmediately(); + players = new ArrayList<>(mappings.size()); + for (final UUIDMapping mapping : mappings) { + players.add(mapping.getUsername()); + } + cachedCompletionValues.put("players", players); + } + } else { + final Collection onlinePlayers = PlotSquared.imp().getPlayerManager().getPlayers(); + players = new ArrayList<>(onlinePlayers.size()); + for (final PlotPlayer player : onlinePlayers) { + players.add(player.getName()); } - cachedCompletionValues.put("players", players); } final String processedInput = input.toLowerCase(Locale.ENGLISH); return players.stream() @@ -77,7 +88,10 @@ public class TabCompletions { .filter(player -> !existing.contains(player)).map( player -> new Command(null, false, player, "", RequiredType.NONE, CommandCategory.INFO) { - }).collect(Collectors.toList()); + }) + /* If there are more than 200 suggestions, just send the first 200 */ + .limit(200) + .collect(Collectors.toList()); } /** From 2875b050c535ea795c0953866060a90dc15e3314 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20S=C3=B6derberg?= Date: Sat, 23 May 2020 19:43:32 +0200 Subject: [PATCH 24/33] Add plugin UUID services. They probably work. --- Bukkit/build.gradle | 3 + .../com/plotsquared/bukkit/BukkitMain.java | 37 +++++++- .../bukkit/uuid/EssentialsUUIDService.java | 70 ++++++++++++++++ .../bukkit/uuid/LuckPermsUUIDService.java | 84 +++++++++++++++++++ 4 files changed, 193 insertions(+), 1 deletion(-) create mode 100644 Bukkit/src/main/java/com/plotsquared/bukkit/uuid/EssentialsUUIDService.java create mode 100644 Bukkit/src/main/java/com/plotsquared/bukkit/uuid/LuckPermsUUIDService.java diff --git a/Bukkit/build.gradle b/Bukkit/build.gradle index 9b6b862a6..965928520 100644 --- a/Bukkit/build.gradle +++ b/Bukkit/build.gradle @@ -11,6 +11,7 @@ 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" } mavenLocal() } @@ -30,6 +31,8 @@ dependencies { exclude(module: "bukkit") } implementation("me.clip:placeholderapi:2.10.4") + implementation("net.luckperms:api:5.0") + implementation("net.ess3:EssentialsX:2.16.1") compile("se.hyperver.hyperverse:Core:0.6.0-SNAPSHOT"){ transitive = false } compile 'com.github.pavog:SquirrelID:0.6.1' } diff --git a/Bukkit/src/main/java/com/plotsquared/bukkit/BukkitMain.java b/Bukkit/src/main/java/com/plotsquared/bukkit/BukkitMain.java index 84ba2f591..588813d5f 100644 --- a/Bukkit/src/main/java/com/plotsquared/bukkit/BukkitMain.java +++ b/Bukkit/src/main/java/com/plotsquared/bukkit/BukkitMain.java @@ -51,6 +51,8 @@ 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.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; @@ -231,38 +233,71 @@ public final class BukkitMain extends JavaPlugin implements Listener, IPlotMain PlotSquared.log(Captions.PREFIX + "&6Couldn't verify purchase :("); } - // TODO: Do we respect the UUID settings? 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(); + + 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 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); + + // Plugin providers + if (luckPermsUUIDService != null) { + impromptuPipeline.registerService(luckPermsUUIDService); + backgroundPipeline.registerService(luckPermsUUIDService); + } + 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); 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; + } + +} From 75dbc2db98446e399cbd8d5faab7505408201b89 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20S=C3=B6derberg?= Date: Sun, 24 May 2020 04:27:20 +0200 Subject: [PATCH 25/33] Fix offline mode UUIDs --- Bukkit/pom.xml | 12 ++++++++++++ .../com/plotsquared/bukkit/BukkitMain.java | 16 ++++++++-------- .../bukkit/listener/PlayerEvents.java | 15 ++++++++++++++- .../bukkit/player/BukkitPlayer.java | 13 ++++++++++++- .../bukkit/uuid/OfflinePlayerUUIDService.java | 19 ++++++++++++++----- 5 files changed, 60 insertions(+), 15 deletions(-) diff --git a/Bukkit/pom.xml b/Bukkit/pom.xml index 68e49c901..57d06b615 100644 --- a/Bukkit/pom.xml +++ b/Bukkit/pom.xml @@ -140,6 +140,18 @@ 2.10.4 runtime
+ + net.luckperms + api + 5.0 + runtime + + + net.ess3 + EssentialsX + 2.16.1 + runtime + junit junit diff --git a/Bukkit/src/main/java/com/plotsquared/bukkit/BukkitMain.java b/Bukkit/src/main/java/com/plotsquared/bukkit/BukkitMain.java index 588813d5f..f75d9ce57 100644 --- a/Bukkit/src/main/java/com/plotsquared/bukkit/BukkitMain.java +++ b/Bukkit/src/main/java/com/plotsquared/bukkit/BukkitMain.java @@ -274,15 +274,15 @@ public final class BukkitMain extends JavaPlugin implements Listener, IPlotMain 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"); - } + // 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"); + } + if (!Settings.UUID.OFFLINE) { impromptuPipeline.registerService(sqLiteUUIDService); backgroundPipeline.registerService(sqLiteUUIDService); impromptuPipeline.registerConsumer(sqLiteUUIDService); 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 ddcc15320..70d3c6d6b 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; @@ -629,7 +630,19 @@ public class PlayerEvents extends PlotListener implements Listener { @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) public void onPreLoin(final AsyncPlayerPreLoginEvent event) { - PlotSquared.get().getImpromptuUUIDPipeline().storeImmediately(event.getName(), event.getUniqueId()); + 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.LOWEST, ignoreCancelled = true) 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 d2e7930fa..23d856860 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; @@ -96,7 +98,16 @@ public class BukkitPlayer extends PlotPlayer { } @NotNull @Override public UUID getUUID() { - return this.player.getUniqueId(); + 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 player.getUniqueId(); } @Override public long getLastPlayed() { diff --git a/Bukkit/src/main/java/com/plotsquared/bukkit/uuid/OfflinePlayerUUIDService.java b/Bukkit/src/main/java/com/plotsquared/bukkit/uuid/OfflinePlayerUUIDService.java index 403832f38..9c9f02344 100644 --- a/Bukkit/src/main/java/com/plotsquared/bukkit/uuid/OfflinePlayerUUIDService.java +++ b/Bukkit/src/main/java/com/plotsquared/bukkit/uuid/OfflinePlayerUUIDService.java @@ -25,6 +25,8 @@ */ 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; @@ -32,6 +34,7 @@ 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; @@ -40,7 +43,10 @@ import java.util.UUID; */ public class OfflinePlayerUUIDService implements UUIDService { - @Override public @NotNull List getNames(@NotNull List uuids) { + @Override @NotNull public List getNames(@NotNull final List uuids) { + if (Settings.UUID.FORCE_LOWERCASE) { + 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); @@ -51,12 +57,15 @@ public class OfflinePlayerUUIDService implements UUIDService { return wrappers; } - @Override public @NotNull List getUUIDs(@NotNull List usernames) { + @Override @NotNull public List getUUIDs(@NotNull final List usernames) { final List wrappers = new ArrayList<>(usernames.size()); for (final String username : usernames) { - final OfflinePlayer offlinePlayer = Bukkit.getOfflinePlayer(username); - if (offlinePlayer.hasPlayedBefore()) { - wrappers.add(new UUIDMapping(offlinePlayer.getUniqueId(), offlinePlayer.getName())); + 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)); } } return wrappers; From d19df3b6ebca7a9bdcd29f89f7536e1152e2a252 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20S=C3=B6derberg?= Date: Sun, 24 May 2020 04:28:29 +0200 Subject: [PATCH 26/33] Fix offline mode UUIDs --- .../java/com/plotsquared/bukkit/BukkitMain.java | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/Bukkit/src/main/java/com/plotsquared/bukkit/BukkitMain.java b/Bukkit/src/main/java/com/plotsquared/bukkit/BukkitMain.java index f75d9ce57..588813d5f 100644 --- a/Bukkit/src/main/java/com/plotsquared/bukkit/BukkitMain.java +++ b/Bukkit/src/main/java/com/plotsquared/bukkit/BukkitMain.java @@ -274,15 +274,15 @@ public final class BukkitMain extends JavaPlugin implements Listener, IPlotMain essentialsUUIDService = null; } - // 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"); - } - 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); From cc168d5ae9821f940cb4bc03d71dca325e3a6630 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20S=C3=B6derberg?= Date: Sun, 24 May 2020 04:48:19 +0200 Subject: [PATCH 27/33] Fix SQLite table creation statement and add legacy SQLite uuids as a provider --- .../src/main/java/com/plotsquared/bukkit/BukkitMain.java | 9 ++++++++- .../com/plotsquared/bukkit/uuid/SQLiteUUIDService.java | 6 +++--- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/Bukkit/src/main/java/com/plotsquared/bukkit/BukkitMain.java b/Bukkit/src/main/java/com/plotsquared/bukkit/BukkitMain.java index 588813d5f..d5e582e8c 100644 --- a/Bukkit/src/main/java/com/plotsquared/bukkit/BukkitMain.java +++ b/Bukkit/src/main/java/com/plotsquared/bukkit/BukkitMain.java @@ -256,7 +256,8 @@ public final class BukkitMain extends JavaPlugin implements Listener, IPlotMain impromptuPipeline.registerService(offlinePlayerUUIDService); backgroundPipeline.registerService(offlinePlayerUUIDService); - final SQLiteUUIDService sqLiteUUIDService = new SQLiteUUIDService(); + final SQLiteUUIDService sqLiteUUIDService = new SQLiteUUIDService("user_cache.db"); + final SQLiteUUIDService legacyUUIDSerivce = new SQLiteUUIDService("usercache.db"); final LuckPermsUUIDService luckPermsUUIDService; if (Bukkit.getPluginManager().getPlugin("LuckPerms") != null) { @@ -288,6 +289,9 @@ public final class BukkitMain extends JavaPlugin implements Listener, IPlotMain impromptuPipeline.registerConsumer(sqLiteUUIDService); backgroundPipeline.registerConsumer(sqLiteUUIDService); + impromptuPipeline.registerService(legacyUUIDSerivce); + backgroundPipeline.registerService(legacyUUIDSerivce); + // Plugin providers if (luckPermsUUIDService != null) { impromptuPipeline.registerService(luckPermsUUIDService); @@ -307,6 +311,9 @@ public final class BukkitMain extends JavaPlugin implements Listener, IPlotMain backgroundPipeline.registerService(sqLiteUUIDService); impromptuPipeline.registerConsumer(sqLiteUUIDService); backgroundPipeline.registerConsumer(sqLiteUUIDService); + + impromptuPipeline.registerService(legacyUUIDSerivce); + backgroundPipeline.registerService(legacyUUIDSerivce); } impromptuPipeline.storeImmediately("*", DBFunc.EVERYONE); diff --git a/Bukkit/src/main/java/com/plotsquared/bukkit/uuid/SQLiteUUIDService.java b/Bukkit/src/main/java/com/plotsquared/bukkit/uuid/SQLiteUUIDService.java index dc251bec4..16b3abff5 100644 --- a/Bukkit/src/main/java/com/plotsquared/bukkit/uuid/SQLiteUUIDService.java +++ b/Bukkit/src/main/java/com/plotsquared/bukkit/uuid/SQLiteUUIDService.java @@ -49,9 +49,9 @@ public class SQLiteUUIDService implements UUIDService, Consumer Date: Sun, 24 May 2020 05:00:36 +0200 Subject: [PATCH 28/33] Add option to disable legacy cache, also add an option to return "Unknown" when a request cannot be fulfilled (old behaviour) This should fix issues where lowercase offline mode UUIDs don't have access to their old cache. --- .../com/plotsquared/bukkit/BukkitMain.java | 20 ++++++++++++++----- .../core/configuration/Settings.java | 4 ++++ .../plotsquared/core/uuid/UUIDPipeline.java | 9 ++++++++- 3 files changed, 27 insertions(+), 6 deletions(-) diff --git a/Bukkit/src/main/java/com/plotsquared/bukkit/BukkitMain.java b/Bukkit/src/main/java/com/plotsquared/bukkit/BukkitMain.java index d5e582e8c..84e474319 100644 --- a/Bukkit/src/main/java/com/plotsquared/bukkit/BukkitMain.java +++ b/Bukkit/src/main/java/com/plotsquared/bukkit/BukkitMain.java @@ -257,7 +257,13 @@ public final class BukkitMain extends JavaPlugin implements Listener, IPlotMain backgroundPipeline.registerService(offlinePlayerUUIDService); final SQLiteUUIDService sqLiteUUIDService = new SQLiteUUIDService("user_cache.db"); - final SQLiteUUIDService legacyUUIDSerivce = new SQLiteUUIDService("usercache.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) { @@ -289,8 +295,10 @@ public final class BukkitMain extends JavaPlugin implements Listener, IPlotMain impromptuPipeline.registerConsumer(sqLiteUUIDService); backgroundPipeline.registerConsumer(sqLiteUUIDService); - impromptuPipeline.registerService(legacyUUIDSerivce); - backgroundPipeline.registerService(legacyUUIDSerivce); + if (legacyUUIDService != null) { + impromptuPipeline.registerService(legacyUUIDService); + backgroundPipeline.registerService(legacyUUIDService); + } // Plugin providers if (luckPermsUUIDService != null) { @@ -312,8 +320,10 @@ public final class BukkitMain extends JavaPlugin implements Listener, IPlotMain impromptuPipeline.registerConsumer(sqLiteUUIDService); backgroundPipeline.registerConsumer(sqLiteUUIDService); - impromptuPipeline.registerService(legacyUUIDSerivce); - backgroundPipeline.registerService(legacyUUIDSerivce); + if (legacyUUIDService != null) { + impromptuPipeline.registerService(legacyUUIDService); + backgroundPipeline.registerService(legacyUUIDService); + } } impromptuPipeline.storeImmediately("*", DBFunc.EVERYONE); 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 0c2e30be9..e5bbd3180 100644 --- a/Core/src/main/java/com/plotsquared/core/configuration/Settings.java +++ b/Core/src/main/java/com/plotsquared/core/configuration/Settings.java @@ -248,6 +248,10 @@ public class Settings extends Config { 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; } diff --git a/Core/src/main/java/com/plotsquared/core/uuid/UUIDPipeline.java b/Core/src/main/java/com/plotsquared/core/uuid/UUIDPipeline.java index 3518fa5f8..8c8baa06d 100644 --- a/Core/src/main/java/com/plotsquared/core/uuid/UUIDPipeline.java +++ b/Core/src/main/java/com/plotsquared/core/uuid/UUIDPipeline.java @@ -324,7 +324,14 @@ public class UUIDPipeline { PlotSquared.log("Failed to find all usernames"); } - throw new ServiceError("End of pipeline"); + 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); } From 172bd6f0f2be60c9abb4a5e3e69aa9fc41a3381a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20S=C3=B6derberg?= Date: Sun, 24 May 2020 19:05:09 +0200 Subject: [PATCH 29/33] This should hopefully fix that broken merge. Maybe. Possibly. Idk. --- .../com/plotsquared/core/command/ListCmd.java | 44 ++++--------------- .../com/plotsquared/core/command/Visit.java | 13 +++--- 2 files changed, 14 insertions(+), 43 deletions(-) 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 dfd582f0f..489208adf 100644 --- a/Core/src/main/java/com/plotsquared/core/command/ListCmd.java +++ b/Core/src/main/java/com/plotsquared/core/command/ListCmd.java @@ -49,7 +49,6 @@ import com.plotsquared.core.uuid.UUIDMapping; import java.util.ArrayList; import java.util.Arrays; -import java.util.Collection; import java.util.List; import java.util.UUID; import java.util.concurrent.ExecutionException; @@ -139,20 +138,19 @@ public class ListCmd extends SubCommand { String arg = args[0].toLowerCase(); final boolean[] sort = new boolean[] {true}; - final Consumer plotConsumer = plots -> { + 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 false; + return; } - if (area != null) { query.relativeToArea(area); } - if (sort) { + if (sort[0]) { query.withSortingStrategy(SortingStrategy.SORT_BY_CREATION); } @@ -160,7 +158,7 @@ public class ListCmd extends SubCommand { if (plots.isEmpty()) { MainUtil.sendMessage(player, Captions.FOUND_NO_PLOTS); - return false; + return; } displayPlots(player, plots, 12, page, args); }; @@ -198,7 +196,6 @@ public class ListCmd extends SubCommand { } plotConsumer.accept(PlotQuery.newQuery().inWorld(world)); break; - plotConsumer.accept(PlotSquared.get().getPlots(world)); case "expired": if (!Permissions.hasPermission(player, Captions.PERMISSION_LIST_EXPIRED)) { MainUtil.sendMessage(player, Captions.NO_PERMISSION, @@ -211,9 +208,6 @@ public class ListCmd extends SubCommand { plotConsumer.accept(PlotQuery.newQuery().expiredPlots()); } break; - plotConsumer.accept(ExpireManager.IMP == null ? - new ArrayList<>() : - new ArrayList<>(ExpireManager.IMP.getPendingExpired())); case "area": if (!Permissions.hasPermission(player, Captions.PERMISSION_LIST_AREA)) { MainUtil @@ -239,7 +233,7 @@ public class ListCmd extends SubCommand { .sendMessage(player, Captions.NO_PERMISSION, Captions.PERMISSION_LIST_ALL); return false; } - plotConsumer.accept(PlotQuery().newQuery().allPlots()); + plotConsumer.accept(PlotQuery.newQuery().allPlots()); break; case "done": if (!Permissions.hasPermission(player, Captions.PERMISSION_LIST_DONE)) { @@ -248,7 +242,7 @@ public class ListCmd extends SubCommand { return false; } sort[0] = false; - plotConsumer.accept(PlotQuery.newQuery().allPlots().thatPasses(DoneFlag::isDone).withSortingStrategy(SortingStrategy.SORT_BY_DONE)) + plotConsumer.accept(PlotQuery.newQuery().allPlots().thatPasses(DoneFlag::isDone).withSortingStrategy(SortingStrategy.SORT_BY_DONE)); break; case "top": if (!Permissions.hasPermission(player, Captions.PERMISSION_LIST_TOP)) { @@ -257,7 +251,7 @@ public class ListCmd extends SubCommand { return false; } sort[0] = false; - plotConsumer.accept(PlotQuery.newQuery().allPlots().withSortingStrategy(SortingStrategy.SORT_BY_RATING)) + plotConsumer.accept(PlotQuery.newQuery().allPlots().withSortingStrategy(SortingStrategy.SORT_BY_RATING)); break; case "forsale": if (!Permissions.hasPermission(player, Captions.PERMISSION_LIST_FOR_SALE)) { @@ -337,36 +331,16 @@ public class ListCmd extends SubCommand { Captions.PERMISSION_LIST_PLAYER); } else { sort[0] = false; - plotConsumer.accept(PlotSquared.get() - .sortPlotsByTemp(PlotSquared.get().getPlots(uuid))); + plotConsumer.accept(PlotQuery.newQuery().ownedBy(uuid).withSortingStrategy(SortingStrategy.SORT_BY_TEMP)); } } }); - - - 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[0] = false; - plotConsumer.accept(PlotQuery.newQuery().ownedBy(uuid).withSortingStrategy(SortingStrategy.SORT_BY_TEMP)); - break; - } } return true; } - public void displayPlots(final PlotPlayer player, List plots, int pageSize, int page, String[] args { + public void displayPlots(final PlotPlayer player, List plots, int pageSize, int page, String[] args) { // Header plots.removeIf(plot -> !plot.isBasePlot()); this.paginate(player, plots, pageSize, page, 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 cd541c33e..3a18fc7d9 100644 --- a/Core/src/main/java/com/plotsquared/core/command/Visit.java +++ b/Core/src/main/java/com/plotsquared/core/command/Visit.java @@ -41,10 +41,7 @@ import com.plotsquared.core.util.query.SortingStrategy; import com.plotsquared.core.util.task.RunnableVal2; import com.plotsquared.core.util.task.RunnableVal3; -import java.util.ArrayList; import java.util.Collection; -import java.util.Collections; -import java.util.HashSet; import java.util.List; import java.util.UUID; import java.util.concurrent.CompletableFuture; @@ -79,7 +76,7 @@ public class Visit extends Command { final PlotQuery query = PlotQuery.newQuery(); final PlotArea[] sortByArea = new PlotArea[] {player.getApplicablePlotArea()}; - final Atomicboolean shouldSortByArea = new AtomicBoolean(Settings.Teleport.PER_WORLD_VISIT); + final AtomicBoolean shouldSortByArea = new AtomicBoolean(Settings.Teleport.PER_WORLD_VISIT); final Consumer pageConsumer = page -> { // We get the query once, @@ -88,7 +85,7 @@ public class Visit extends Command { if (unsorted.isEmpty()) { Captions.FOUND_NO_PLOTS.send(player); - return CompletableFuture.completedFuture(false); + return; } if (unsorted.size() > 1) { @@ -97,11 +94,11 @@ public class Visit extends Command { if (page < 1 || page > unsorted.size()) { Captions.NOT_VALID_NUMBER.send(player, "(1, " + unsorted.size() + ")"); - return CompletableFuture.completedFuture(false); + return; } if (shouldSortByArea.get()) { - query.relativeToArea(sortByArea).withSortingStrategy(SortingStrategy.SORT_BY_CREATION); + query.relativeToArea(sortByArea[0]).withSortingStrategy(SortingStrategy.SORT_BY_CREATION); } else { query.withSortingStrategy(SortingStrategy.SORT_BY_TEMP); } @@ -171,7 +168,7 @@ public class Visit extends Command { } else if (throwable != null || uuids.size() != 1) { Captions.COMMAND_SYNTAX.send(player, getUsage()); } else { - query.ownedBy(user).whereBasePlot(); + query.ownedBy(uuids.toArray(new UUID[0])[0]).whereBasePlot(); shouldSortByArea.set(true); pageConsumer.accept(page[0]); } From 69cfb431b145a26ba2aea50cbf87a0d966e4d6e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20S=C3=B6derberg?= Date: Sun, 24 May 2020 20:18:02 +0200 Subject: [PATCH 30/33] Unstupidify Visit --- .../com/plotsquared/core/command/Visit.java | 248 ++++++++++-------- .../core/configuration/Captions.java | 1 + .../core/util/query/PlotQuery.java | 7 +- 3 files changed, 149 insertions(+), 107 deletions(-) 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 3a18fc7d9..3c1ed70c3 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; @@ -40,14 +39,13 @@ 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 org.jetbrains.annotations.NotNull; import java.util.Collection; import java.util.List; import java.util.UUID; import java.util.concurrent.CompletableFuture; import java.util.concurrent.TimeoutException; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.function.Consumer; @CommandDeclaration(command = "visit", permission = "plots.visit", @@ -66,152 +64,194 @@ public class Visit extends Command { 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(":"); } - final PlotQuery query = PlotQuery.newQuery(); - final PlotArea[] sortByArea = new PlotArea[] {player.getApplicablePlotArea()}; - final AtomicBoolean shouldSortByArea = new AtomicBoolean(Settings.Teleport.PER_WORLD_VISIT); + PlotArea sortByArea; - final Consumer pageConsumer = 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 < 1 || page > unsorted.size()) { - Captions.NOT_VALID_NUMBER.send(player, "(1, " + unsorted.size() + ")"); - return; - } - - if (shouldSortByArea.get()) { - query.relativeToArea(sortByArea[0]).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)); - }; - - final int[] page = new int[]{Integer.MIN_VALUE}; + int page = Integer.MIN_VALUE; switch (args.length) { + // /p v [...] [...] case 3: if (!MathMan.isInteger(args[1])) { Captions.NOT_VALID_NUMBER.send(player, "(1, ∞)"); Captions.COMMAND_SYNTAX.send(player, getUsage()); return CompletableFuture.completedFuture(false); } - page[0] = Integer.parseInt(args[2]); + page = Integer.parseInt(args[2]); + // /p v [page] + // /p v [page] case 2: - if (page[0] != Integer.MIN_VALUE || !MathMan.isInteger(args[1])) { - sortByArea[0] = PlotSquared.get().getPlotAreaByString(args[1]); - if (sortByArea[0] == null) { + if (page != Integer.MIN_VALUE || !MathMan.isInteger(args[1])) { + sortByArea = PlotSquared.get().getPlotAreaByString(args[1]); + if (sortByArea == null) { Captions.NOT_VALID_NUMBER.send(player, "(1, ∞)"); Captions.COMMAND_SYNTAX.send(player, getUsage()); return CompletableFuture.completedFuture(false); } + 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 { - query.ownedBy(uuids.toArray(new UUID[0])[0]).whereBasePlot(); - shouldSortByArea.set(true); - pageConsumer.accept(page[0]); + final UUID uuid = uuids.toArray(new UUID[0])[0]; + this.visit(player, PlotQuery.newQuery().ownedBy(uuid).whereBasePlot(), finalSortByArea, confirm, whenDone, finalPage1); } }); break; } - page[0] = Integer.parseInt(args[1]); + page = Integer.parseInt(args[1]); + // /p v [page] + // /p v [page] + // /p v [page] + // /p v [page] case 1: final String[] finalArgs = args; - final Consumer uuidConsumer = uuid -> { - if (page[0] == Integer.MIN_VALUE && uuid == null && MathMan.isInteger(finalArgs[0])) { - page[0] = Integer.parseInt(finalArgs[0]); - query.ownedBy(player).whereBasePlot(); - } else { - if (uuid != null) { - query.ownedBy(player).whereBasePlot(); - } else { - Plot plot = MainUtil.getPlotFromString(player, finalArgs[0], true); - if (plot != null) { - query.withPlot(plot); - } - } - } - pageConsumer.accept(page[0]); - }; - + int finalPage = page; if (args[0].length() >= 2) { 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)) { - uuidConsumer.accept(null); + // 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 { - uuidConsumer.accept(uuid); + this.visit(player, PlotQuery.newQuery().ownedBy(uuid).whereBasePlot(), null, confirm, whenDone, finalPage); } }); } else { - uuidConsumer.accept(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]); + 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) { + MainUtil.sendMessage(player, Captions.NOT_VALID_PLOT_ID); + } else { + this.visit(player, PlotQuery.newQuery().withPlot(plot), null, confirm, whenDone, 1); + } + } } break; case 0: - query.ownedBy(player); - pageConsumer.accept(1); + // /p v + this.visit(player, PlotQuery.newQuery().ownedBy(player), null, confirm, whenDone); break; default: } 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 98cb8b9ce..eb5f6f444 100644 --- a/Core/src/main/java/com/plotsquared/core/configuration/Captions.java +++ b/Core/src/main/java/com/plotsquared/core/configuration/Captions.java @@ -445,6 +445,7 @@ 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"), // 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 index 6c90e969f..40d883062 100644 --- a/Core/src/main/java/com/plotsquared/core/util/query/PlotQuery.java +++ b/Core/src/main/java/com/plotsquared/core/util/query/PlotQuery.java @@ -288,12 +288,13 @@ public final class PlotQuery { } else { final Collection plots = this.plotProvider.getPlots(); result = new ArrayList<>(plots.size()); - for (final Plot plot : plots) { + outer: for (final Plot plot : plots) { for (final PlotFilter filter : this.filters) { - if (filter.accepts(plot)) { - result.add(plot); + if (!filter.accepts(plot)) { + continue outer; } } + result.add(plot); } } if (this.sortingStrategy == SortingStrategy.NO_SORTING) { From 862467c0fa3eeab412ffa6220eade3c52c1973ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20S=C3=B6derberg?= Date: Sun, 24 May 2020 20:53:16 +0200 Subject: [PATCH 31/33] Tab complete `/plot visit` --- .../com/plotsquared/core/command/Visit.java | 61 +++++++++++++++++-- 1 file changed, 56 insertions(+), 5 deletions(-) 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 3c1ed70c3..2b64746c2 100644 --- a/Core/src/main/java/com/plotsquared/core/command/Visit.java +++ b/Core/src/main/java/com/plotsquared/core/command/Visit.java @@ -35,6 +35,7 @@ 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; @@ -42,6 +43,8 @@ import com.plotsquared.core.util.task.RunnableVal3; import org.jetbrains.annotations.NotNull; 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; @@ -60,10 +63,6 @@ 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); @@ -194,7 +193,7 @@ public class Visit extends Command { case 1: final String[] finalArgs = args; int finalPage = page; - if (args[0].length() >= 2) { + if (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 @@ -259,4 +258,56 @@ public class Visit extends Command { return CompletableFuture.completedFuture(true); } + public Collection tab(PlotPlayer player, String[] args, boolean space) { + final List completions = new LinkedList<>(); + player.sendMessage("u haef " + args.length + " args and they r "); + for (int i = 0; i < args.length; i++) { + player.sendMessage(i + ": " + args[i]); + } + + 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 < 10; 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) {}); + } + } + } From 2436a6a402423581e268457b359f6c06bf7c52f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20S=C3=B6derberg?= Date: Sun, 24 May 2020 20:54:10 +0200 Subject: [PATCH 32/33] remove debug, whoops --- Core/src/main/java/com/plotsquared/core/command/Visit.java | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) 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 2b64746c2..651a1c0b0 100644 --- a/Core/src/main/java/com/plotsquared/core/command/Visit.java +++ b/Core/src/main/java/com/plotsquared/core/command/Visit.java @@ -260,11 +260,6 @@ public class Visit extends Command { public Collection tab(PlotPlayer player, String[] args, boolean space) { final List completions = new LinkedList<>(); - player.sendMessage("u haef " + args.length + " args and they r "); - for (int i = 0; i < args.length; i++) { - player.sendMessage(i + ": " + args[i]); - } - switch (args.length - 1) { case 0: this.completeNumbers(completions, args[0], 0); @@ -289,7 +284,7 @@ public class Visit extends Command { } private void completeNumbers(final List commands, final String arg, final int start) { - for (int i = 0; i < 10; i++) { + for (int i = 0; i < 100; i++) { final String command = Integer.toString(start + 1); if (!command.toLowerCase().startsWith(arg.toLowerCase())) { continue; From 46b68e489d9c90565c0caa877d14f748f3008a0d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20S=C3=B6derberg?= Date: Sun, 24 May 2020 21:08:11 +0200 Subject: [PATCH 33/33] Tab complete `/p list` --- .../bukkit/managers/BukkitWorldManager.java | 12 +++++ .../com/plotsquared/core/command/ListCmd.java | 49 +++++++++++++++++++ .../core/util/PlatformWorldManager.java | 9 ++++ 3 files changed, 70 insertions(+) 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/Core/src/main/java/com/plotsquared/core/command/ListCmd.java b/Core/src/main/java/com/plotsquared/core/command/ListCmd.java index 489208adf..0054df62e 100644 --- a/Core/src/main/java/com/plotsquared/core/command/ListCmd.java +++ b/Core/src/main/java/com/plotsquared/core/command/ListCmd.java @@ -42,6 +42,7 @@ 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; @@ -49,12 +50,16 @@ 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.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"}, @@ -397,4 +402,48 @@ public class ListCmd extends SubCommand { }, "/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.manager != 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/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(); + }