From 1c534d7475de3afe863d5ef2f63456b5c1b3f066 Mon Sep 17 00:00:00 2001 From: Luck Date: Tue, 8 Nov 2016 20:46:29 +0000 Subject: [PATCH] More cleanup --- .../lucko/luckperms/bukkit/BukkitCommand.java | 11 +- .../luckperms/bukkit/BukkitSenderFactory.java | 11 +- .../luckperms/bukkit/LPBukkitPlugin.java | 9 +- .../bukkit/inject/LPPermissible.java | 14 +- .../lucko/luckperms/bungee/BungeeCommand.java | 8 +- .../luckperms/bungee/BungeeSenderFactory.java | 11 +- .../luckperms/bungee/LPBungeePlugin.java | 12 +- .../luckperms/common/LuckPermsPlugin.java | 132 ++++++++++++++---- .../lucko/luckperms/common/data/LogEntry.java | 5 +- .../me/lucko/luckperms/common/users/User.java | 3 + .../common/utils/AbstractFuture.java | 4 + .../common/utils/AbstractListener.java | 3 + .../common/utils/ArgumentChecker.java | 3 + .../lucko/luckperms/common/utils/Buffer.java | 16 ++- .../common/utils/BufferedRequest.java | 11 +- .../luckperms/common/utils/DateUtil.java | 37 +---- .../luckperms/common/utils/DebugHandler.java | 10 +- .../luckperms/common/utils/LocalizedNode.java | 2 +- .../luckperms/common/utils/LogFactory.java | 3 + .../luckperms/common/utils/Predicates.java | 3 + .../luckperms/sponge/LPSpongePlugin.java | 9 +- .../lucko/luckperms/sponge/SpongeCommand.java | 6 +- .../luckperms/sponge/SpongeSenderFactory.java | 11 +- .../sponge/service/LuckPermsSubject.java | 3 +- .../sponge/service/LuckPermsSubjectData.java | 21 +-- .../service/collections/GroupCollection.java | 3 +- .../service/collections/UserCollection.java | 7 - .../persisted/PersistedCollection.java | 4 +- .../service/persisted/PersistedSubject.java | 3 +- .../service/simple/SimpleCollection.java | 14 +- .../sponge/service/simple/SimpleSubject.java | 3 +- 31 files changed, 223 insertions(+), 169 deletions(-) diff --git a/bukkit/src/main/java/me/lucko/luckperms/bukkit/BukkitCommand.java b/bukkit/src/main/java/me/lucko/luckperms/bukkit/BukkitCommand.java index 9ed58111..28d24f24 100644 --- a/bukkit/src/main/java/me/lucko/luckperms/bukkit/BukkitCommand.java +++ b/bukkit/src/main/java/me/lucko/luckperms/bukkit/BukkitCommand.java @@ -25,7 +25,6 @@ package me.lucko.luckperms.bukkit; import com.google.common.base.Joiner; import com.google.common.base.Splitter; import me.lucko.luckperms.api.data.Callback; -import me.lucko.luckperms.common.LuckPermsPlugin; import me.lucko.luckperms.common.commands.CommandManager; import me.lucko.luckperms.common.commands.Util; import me.lucko.luckperms.common.constants.Patterns; @@ -38,14 +37,17 @@ import java.util.Arrays; import java.util.List; class BukkitCommand extends CommandManager implements CommandExecutor, TabExecutor { - BukkitCommand(LuckPermsPlugin plugin) { + private final LPBukkitPlugin plugin; + + BukkitCommand(LPBukkitPlugin plugin) { super(plugin); + this.plugin = plugin; } @Override public boolean onCommand(CommandSender sender, Command command, String label, String[] args) { onCommand( - BukkitSenderFactory.get(getPlugin()).wrap(sender), + plugin.getSenderFactory().wrap(sender), label, Util.stripQuotes(Splitter.on(Patterns.COMMAND_SEPARATOR).omitEmptyStrings().splitToList(Joiner.on(' ').join(args))), Callback.empty() @@ -53,9 +55,8 @@ class BukkitCommand extends CommandManager implements CommandExecutor, TabExecut return true; } - @Override public List onTabComplete(CommandSender sender, Command command, String label, String[] args) { - return onTabComplete(BukkitSenderFactory.get(getPlugin()).wrap(sender), Arrays.asList(args)); + return onTabComplete(plugin.getSenderFactory().wrap(sender), Arrays.asList(args)); } } diff --git a/bukkit/src/main/java/me/lucko/luckperms/bukkit/BukkitSenderFactory.java b/bukkit/src/main/java/me/lucko/luckperms/bukkit/BukkitSenderFactory.java index 6ddb9cd9..013dc41a 100644 --- a/bukkit/src/main/java/me/lucko/luckperms/bukkit/BukkitSenderFactory.java +++ b/bukkit/src/main/java/me/lucko/luckperms/bukkit/BukkitSenderFactory.java @@ -31,19 +31,10 @@ import org.bukkit.entity.Player; import java.util.UUID; public class BukkitSenderFactory extends SenderFactory { - private static BukkitSenderFactory instance = null; - - private BukkitSenderFactory(LuckPermsPlugin plugin) { + public BukkitSenderFactory(LuckPermsPlugin plugin) { super(plugin); } - public static synchronized BukkitSenderFactory get(LuckPermsPlugin plugin) { - if (instance == null) { - instance = new BukkitSenderFactory(plugin); - } - return instance; - } - @Override protected String getName(CommandSender sender) { if (sender instanceof Player) { diff --git a/bukkit/src/main/java/me/lucko/luckperms/bukkit/LPBukkitPlugin.java b/bukkit/src/main/java/me/lucko/luckperms/bukkit/LPBukkitPlugin.java index 0bc2f37b..05d269be 100644 --- a/bukkit/src/main/java/me/lucko/luckperms/bukkit/LPBukkitPlugin.java +++ b/bukkit/src/main/java/me/lucko/luckperms/bukkit/LPBukkitPlugin.java @@ -97,6 +97,7 @@ public class LPBukkitPlugin extends JavaPlugin implements LuckPermsPlugin { private BufferedRequest updateTaskBuffer; private boolean started = false; private DebugHandler debugHandler; + private BukkitSenderFactory senderFactory; private ExecutorService executorService; private boolean schedulerAvailable = false; @@ -108,6 +109,7 @@ public class LPBukkitPlugin extends JavaPlugin implements LuckPermsPlugin { log = LogFactory.wrap(getLogger()); debugHandler = new DebugHandler(); + senderFactory = new BukkitSenderFactory(this); getLog().info("Loading configuration..."); configuration = new BukkitConfig(this); @@ -319,16 +321,15 @@ public class LPBukkitPlugin extends JavaPlugin implements LuckPermsPlugin { } @Override - public List getNotifyListeners() { + public List getSenders() { return getServer().getOnlinePlayers().stream() - .map(p -> BukkitSenderFactory.get(this).wrap(p)) - .filter(Permission.LOG_NOTIFY::isAuthorized) + .map(p -> getSenderFactory().wrap(p)) .collect(Collectors.toList()); } @Override public Sender getConsoleSender() { - return BukkitSenderFactory.get(this).wrap(getServer().getConsoleSender()); + return getSenderFactory().wrap(getServer().getConsoleSender()); } @Override diff --git a/bukkit/src/main/java/me/lucko/luckperms/bukkit/inject/LPPermissible.java b/bukkit/src/main/java/me/lucko/luckperms/bukkit/inject/LPPermissible.java index 23f0d7ee..6b121f93 100644 --- a/bukkit/src/main/java/me/lucko/luckperms/bukkit/inject/LPPermissible.java +++ b/bukkit/src/main/java/me/lucko/luckperms/bukkit/inject/LPPermissible.java @@ -184,7 +184,7 @@ public class LPPermissible extends PermissibleBase { } PermissionAttachment result = addAttachment(plugin); - if (Bukkit.getServer().getScheduler().scheduleSyncDelayedTask(plugin, new RemoveAttachmentRunnable(result), ticks) == -1) { + if (Bukkit.getServer().getScheduler().scheduleSyncDelayedTask(plugin, () -> result.remove(), ticks) == -1) { Bukkit.getServer().getLogger().log(Level.WARNING, "Could not add PermissionAttachment to " + parent + " for plugin " + plugin.getDescription().getFullName() + ": Scheduler returned -1"); result.remove(); return null; @@ -254,16 +254,4 @@ public class LPPermissible extends PermissibleBase { } } } - - private class RemoveAttachmentRunnable implements Runnable { - private PermissionAttachment attachment; - - private RemoveAttachmentRunnable(PermissionAttachment attachment) { - this.attachment = attachment; - } - - public void run() { - attachment.remove(); - } - } } diff --git a/bungee/src/main/java/me/lucko/luckperms/bungee/BungeeCommand.java b/bungee/src/main/java/me/lucko/luckperms/bungee/BungeeCommand.java index 31b64073..564a62a2 100644 --- a/bungee/src/main/java/me/lucko/luckperms/bungee/BungeeCommand.java +++ b/bungee/src/main/java/me/lucko/luckperms/bungee/BungeeCommand.java @@ -35,17 +35,19 @@ import net.md_5.bungee.api.plugin.TabExecutor; import java.util.Arrays; class BungeeCommand extends Command implements TabExecutor { + private final LPBungeePlugin plugin; private final CommandManager manager; - BungeeCommand(CommandManager manager) { + BungeeCommand(LPBungeePlugin plugin, CommandManager manager) { super("luckpermsbungee", null, "bperms", "lpb", "bpermissions", "bp", "bperm"); + this.plugin = plugin; this.manager = manager; } @Override public void execute(CommandSender sender, String[] args) { manager.onCommand( - BungeeSenderFactory.get(manager.getPlugin()).wrap(sender), + plugin.getSenderFactory().wrap(sender), "bperms", Util.stripQuotes(Splitter.on(Patterns.COMMAND_SEPARATOR).omitEmptyStrings().splitToList(Joiner.on(' ').join(args))), Callback.empty() @@ -54,6 +56,6 @@ class BungeeCommand extends Command implements TabExecutor { @Override public Iterable onTabComplete(CommandSender sender, String[] args) { - return manager.onTabComplete(BungeeSenderFactory.get(manager.getPlugin()).wrap(sender), Arrays.asList(args)); + return manager.onTabComplete(plugin.getSenderFactory().wrap(sender), Arrays.asList(args)); } } diff --git a/bungee/src/main/java/me/lucko/luckperms/bungee/BungeeSenderFactory.java b/bungee/src/main/java/me/lucko/luckperms/bungee/BungeeSenderFactory.java index 49037ed1..41da02dd 100644 --- a/bungee/src/main/java/me/lucko/luckperms/bungee/BungeeSenderFactory.java +++ b/bungee/src/main/java/me/lucko/luckperms/bungee/BungeeSenderFactory.java @@ -32,19 +32,10 @@ import net.md_5.bungee.api.connection.ProxiedPlayer; import java.util.UUID; public class BungeeSenderFactory extends SenderFactory { - private static BungeeSenderFactory instance = null; - - private BungeeSenderFactory(LuckPermsPlugin plugin) { + public BungeeSenderFactory(LuckPermsPlugin plugin) { super(plugin); } - public static synchronized BungeeSenderFactory get(LuckPermsPlugin plugin) { - if (instance == null) { - instance = new BungeeSenderFactory(plugin); - } - return instance; - } - @Override protected String getName(CommandSender sender) { if (sender instanceof ProxiedPlayer) { diff --git a/bungee/src/main/java/me/lucko/luckperms/bungee/LPBungeePlugin.java b/bungee/src/main/java/me/lucko/luckperms/bungee/LPBungeePlugin.java index 9bc38631..4bbe2da7 100644 --- a/bungee/src/main/java/me/lucko/luckperms/bungee/LPBungeePlugin.java +++ b/bungee/src/main/java/me/lucko/luckperms/bungee/LPBungeePlugin.java @@ -36,7 +36,6 @@ import me.lucko.luckperms.common.commands.CommandManager; import me.lucko.luckperms.common.commands.ConsecutiveExecutor; import me.lucko.luckperms.common.commands.Sender; import me.lucko.luckperms.common.config.LPConfiguration; -import me.lucko.luckperms.common.constants.Permission; import me.lucko.luckperms.common.contexts.ContextManager; import me.lucko.luckperms.common.contexts.ServerCalculator; import me.lucko.luckperms.common.core.UuidCache; @@ -85,11 +84,13 @@ public class LPBungeePlugin extends Plugin implements LuckPermsPlugin { private CalculatorFactory calculatorFactory; private BufferedRequest updateTaskBuffer; private DebugHandler debugHandler; + private BungeeSenderFactory senderFactory; @Override public void onEnable() { log = LogFactory.wrap(getLogger()); debugHandler = new DebugHandler(); + senderFactory = new BungeeSenderFactory(this); getLog().info("Loading configuration..."); configuration = new BungeeConfig(this); @@ -137,7 +138,7 @@ public class LPBungeePlugin extends Plugin implements LuckPermsPlugin { // register commands getLog().info("Registering commands..."); CommandManager commandManager = new CommandManager(this); - getProxy().getPluginManager().registerCommand(this, new BungeeCommand(commandManager)); + getProxy().getPluginManager().registerCommand(this, new BungeeCommand(this, commandManager)); // disable the default Bungee /perms command so it gets handled by the Bukkit plugin getProxy().getDisabledCommands().add("perms"); @@ -229,16 +230,15 @@ public class LPBungeePlugin extends Plugin implements LuckPermsPlugin { } @Override - public List getNotifyListeners() { + public List getSenders() { return getProxy().getPlayers().stream() - .map(p -> BungeeSenderFactory.get(this).wrap(p)) - .filter(Permission.LOG_NOTIFY::isAuthorized) + .map(p -> getSenderFactory().wrap(p)) .collect(Collectors.toList()); } @Override public Sender getConsoleSender() { - return BungeeSenderFactory.get(this).wrap(getProxy().getConsole()); + return getSenderFactory().wrap(getProxy().getConsole()); } @Override diff --git a/common/src/main/java/me/lucko/luckperms/common/LuckPermsPlugin.java b/common/src/main/java/me/lucko/luckperms/common/LuckPermsPlugin.java index c22086fd..d3acccfc 100644 --- a/common/src/main/java/me/lucko/luckperms/common/LuckPermsPlugin.java +++ b/common/src/main/java/me/lucko/luckperms/common/LuckPermsPlugin.java @@ -49,46 +49,142 @@ import java.util.Set; import java.util.UUID; /** - * Main internal interface for LuckPerms plugins, allowing the luckperms-common module to bind with the plugin instance. + * Main internal interface for LuckPerms plugins, providing the base for abstraction throughout the project. + * * All plugin platforms implement this interface. */ public interface LuckPermsPlugin { - /* - * Access to all of the main internal manager classes + /** + * Gets the user manager instance for the platform + * @return the user manager */ UserManager getUserManager(); + + /** + * Gets the group manager instance for the platform + * @return the group manager + */ GroupManager getGroupManager(); + + /** + * Gets the track manager instance for the platform + * @return the track manager + */ TrackManager getTrackManager(); + + /** + * Gets the plugin's configuration + * @return the plugin config + */ LPConfiguration getConfiguration(); + + /** + * Gets the primary datastore instance. This is likely to be wrapped with extra layers for caching, etc. + * @return the datastore + */ Datastore getDatastore(); + + /** + * Gets the redis messaging instance if present. Could return null if redis is not enabled. + * @return the redis messaging service + */ RedisMessaging getRedisMessaging(); + + /** + * Gets a wrapped logger instance for the platform. + * @return the plugin's logger + */ Logger getLog(); + + /** + * Gets the UUID caching store for the platform + * @return the uuid cache + */ UuidCache getUuidCache(); + + /** + * Returns the class implementing the LuckPermsAPI on this platform. + * @return the api + */ ApiProvider getApiProvider(); + + /** + * Gets the importer instance + * @return the importer + */ Importer getImporter(); + + /** + * Gets the consecutive command executor instance + * @return the consecutive executor + */ ConsecutiveExecutor getConsecutiveExecutor(); + + /** + * Gets the instance providing locale translations for the plugin + * @return the locale manager + */ LocaleManager getLocaleManager(); + + /** + * Gets the context manager. + * This object handles context accumulation for all players on the platform. + * @return the context manager + */ ContextManager getContextManager(); + + /** + * Gets the class responsible for constructing PermissionCalculators on this platform. + * @return the permission calculator factory + */ CalculatorFactory getCalculatorFactory(); + + /** + * Gets the verbose debug handler instance. + * @return the debug handler instance + */ DebugHandler getDebugHandler(); /** + * Execute a runnable asynchronously + * @param r the task to run + */ + void doAsync(Runnable r); + + /** + * Execute a runnable synchronously + * @param r the task to run + */ + void doSync(Runnable r); + + /** + * Execute a runnable asynchronously on a loop + * @param r the task to run + * @param interval the time between runs in ticks + */ + void doAsyncRepeating(Runnable r, long interval); + + /** + * Gets a string of the plugin's version * @return the version of the plugin */ String getVersion(); /** + * Gets the platform type this instance of LuckPerms is running on. * @return the platform type */ PlatformType getType(); /** + * Gets the plugins main directory * @return the main plugin directory */ File getMainDir(); /** + * Gets the plugins main data storage directory * @return the platforms data folder */ File getDataFolder(); @@ -129,11 +225,13 @@ public interface LuckPermsPlugin { boolean isOnline(UUID external); /** + * Gets a list of online Senders on the platform * @return a {@link List} of senders online on the platform */ - List getNotifyListeners(); + List getSenders(); /** + * Gets the console. * @return the console sender of the instance */ Sender getConsoleSender(); @@ -147,7 +245,7 @@ public interface LuckPermsPlugin { /** * Gets a set of players ignoring logging output - * @return a {@link Set} of uuids + * @return a {@link Set} of {@link UUID}s */ Set getIgnoringLogs(); @@ -166,7 +264,7 @@ public interface LuckPermsPlugin { Object getService(Class clazz); /** - * Used as a backup for migration + * Gets the UUID of a player. Used as a backup for migration * @param playerName the players name * @return a uuid if found, or null if not */ @@ -180,27 +278,9 @@ public interface LuckPermsPlugin { boolean isPluginLoaded(String name); /** - * Runs an update task + * Gets the update task buffer of the platform, used for scheduling and running update tasks. + * @return the update task buffer instance */ BufferedRequest getUpdateTaskBuffer(); - /** - * Execute a runnable asynchronously - * @param r the task to run - */ - void doAsync(Runnable r); - - /** - * Execute a runnable synchronously - * @param r the task to run - */ - void doSync(Runnable r); - - /** - * Execute a runnable asynchronously on a loop - * @param r the task to run - * @param interval the time between runs in ticks - */ - void doAsyncRepeating(Runnable r, long interval); - } diff --git a/common/src/main/java/me/lucko/luckperms/common/data/LogEntry.java b/common/src/main/java/me/lucko/luckperms/common/data/LogEntry.java index 105d0a2f..eec49cec 100644 --- a/common/src/main/java/me/lucko/luckperms/common/data/LogEntry.java +++ b/common/src/main/java/me/lucko/luckperms/common/data/LogEntry.java @@ -26,6 +26,7 @@ import me.lucko.luckperms.api.event.events.LogNotifyEvent; import me.lucko.luckperms.common.LuckPermsPlugin; import me.lucko.luckperms.common.commands.Sender; import me.lucko.luckperms.common.constants.Message; +import me.lucko.luckperms.common.constants.Permission; import me.lucko.luckperms.common.core.PermissionHolder; import me.lucko.luckperms.common.groups.Group; import me.lucko.luckperms.common.tracks.Track; @@ -56,15 +57,17 @@ public class LogEntry extends me.lucko.luckperms.api.LogEntry { final String msg = super.getFormatted(); - List senders = plugin.getNotifyListeners(); + List senders = plugin.getSenders(); senders.add(plugin.getConsoleSender()); if (sender == null) { senders.stream() + .filter(Permission.LOG_NOTIFY::isAuthorized) .filter(s -> !plugin.getIgnoringLogs().contains(s.getUuid())) .forEach(s -> Message.LOG.send(s, msg)); } else { senders.stream() + .filter(Permission.LOG_NOTIFY::isAuthorized) .filter(s -> !plugin.getIgnoringLogs().contains(s.getUuid())) .filter(s -> !s.getUuid().equals(sender.getUuid())) .forEach(s -> Message.LOG.send(s, msg)); diff --git a/common/src/main/java/me/lucko/luckperms/common/users/User.java b/common/src/main/java/me/lucko/luckperms/common/users/User.java index 3bf5600e..fd831fc2 100644 --- a/common/src/main/java/me/lucko/luckperms/common/users/User.java +++ b/common/src/main/java/me/lucko/luckperms/common/users/User.java @@ -61,6 +61,9 @@ public class User extends PermissionHolder implements Identifiable the return type + */ public class AbstractFuture implements LPFuture { private final CountDownLatch latch = new CountDownLatch(1); private R value; diff --git a/common/src/main/java/me/lucko/luckperms/common/utils/AbstractListener.java b/common/src/main/java/me/lucko/luckperms/common/utils/AbstractListener.java index d2a46d61..927892cd 100644 --- a/common/src/main/java/me/lucko/luckperms/common/utils/AbstractListener.java +++ b/common/src/main/java/me/lucko/luckperms/common/utils/AbstractListener.java @@ -32,6 +32,9 @@ import me.lucko.luckperms.common.users.User; import java.util.UUID; +/** + * An abstract listener shared by Bukkit & Sponge. + */ @AllArgsConstructor public class AbstractListener { private final LuckPermsPlugin plugin; diff --git a/common/src/main/java/me/lucko/luckperms/common/utils/ArgumentChecker.java b/common/src/main/java/me/lucko/luckperms/common/utils/ArgumentChecker.java index b9fc368e..8ecda1f0 100644 --- a/common/src/main/java/me/lucko/luckperms/common/utils/ArgumentChecker.java +++ b/common/src/main/java/me/lucko/luckperms/common/utils/ArgumentChecker.java @@ -25,6 +25,9 @@ package me.lucko.luckperms.common.utils; import lombok.experimental.UtilityClass; import me.lucko.luckperms.common.constants.Patterns; +/** + * Utility for checking arguments for consistency + */ @UtilityClass public class ArgumentChecker { diff --git a/common/src/main/java/me/lucko/luckperms/common/utils/Buffer.java b/common/src/main/java/me/lucko/luckperms/common/utils/Buffer.java index ffe1703b..743ae4ac 100644 --- a/common/src/main/java/me/lucko/luckperms/common/utils/Buffer.java +++ b/common/src/main/java/me/lucko/luckperms/common/utils/Buffer.java @@ -27,19 +27,24 @@ import lombok.*; import java.util.LinkedList; import java.util.List; import java.util.ListIterator; +import java.util.concurrent.locks.ReentrantLock; /** - * Holds a buffer of objects to be processed after they've been in the buffer for a given time. + * Thread-safe buffer utility. Holds a buffer of objects to be processed after they've been waiting in the buffer + * for a given time. If the same object is pushed to the buffer again in that time, its wait time is reset. + * * @param the type of objects in the buffer * @param the type of result produced by the final process */ public abstract class Buffer implements Runnable { private static final long DEFAULT_FLUSH_TIME = 1000; // 1 second + private final ReentrantLock lock = new ReentrantLock(); private final List> buffer = new LinkedList<>(); public LPFuture enqueue(@NonNull T t) { - synchronized (buffer) { + lock.lock(); + try { ListIterator> it = buffer.listIterator(); BufferedObject o = null; @@ -62,6 +67,8 @@ public abstract class Buffer implements Runnable { buffer.add(o); return o.getFuture(); + } finally { + lock.unlock(); } } @@ -70,7 +77,8 @@ public abstract class Buffer implements Runnable { public void flush(long flushTime) { long time = System.currentTimeMillis(); - synchronized (buffer) { + lock.lock(); + try { ListIterator> it = buffer.listIterator(buffer.size()); while (it.hasPrevious()) { @@ -85,6 +93,8 @@ public abstract class Buffer implements Runnable { it.remove(); } } + } finally { + lock.unlock(); } } diff --git a/common/src/main/java/me/lucko/luckperms/common/utils/BufferedRequest.java b/common/src/main/java/me/lucko/luckperms/common/utils/BufferedRequest.java index 08dfb722..2962102e 100644 --- a/common/src/main/java/me/lucko/luckperms/common/utils/BufferedRequest.java +++ b/common/src/main/java/me/lucko/luckperms/common/utils/BufferedRequest.java @@ -30,14 +30,20 @@ import java.util.concurrent.locks.ReentrantLock; import java.util.function.Consumer; import java.util.function.Supplier; +/** + * Thread-safe request buffer. + * + * Waits for the buffer time to pass before performing the operation. If the task is called again in that time, the + * buffer time is reset. + * + * @param the return type + */ @RequiredArgsConstructor public abstract class BufferedRequest { private final long bufferTimeMillis; private final Consumer executor; private WeakReference> processor = null; - - @Getter private ReentrantLock lock = new ReentrantLock(); public LPFuture request() { @@ -66,7 +72,6 @@ public abstract class BufferedRequest { protected abstract T perform(); - @RequiredArgsConstructor private static class Processor implements Runnable { private final long delayMillis; diff --git a/common/src/main/java/me/lucko/luckperms/common/utils/DateUtil.java b/common/src/main/java/me/lucko/luckperms/common/utils/DateUtil.java index a4f304e7..100f0cf5 100644 --- a/common/src/main/java/me/lucko/luckperms/common/utils/DateUtil.java +++ b/common/src/main/java/me/lucko/luckperms/common/utils/DateUtil.java @@ -1,23 +1,7 @@ /* - * Copyright (c) 2016 Lucko (Luck) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. + * All credit to Essentials / EssentialsX for this class + * https://github.com/drtshock/Essentials/blob/2.x/Essentials/src/com/earth2me/essentials/utils/DateUtil.java + * https://github.com/essentials/Essentials/blob/2.x/Essentials/src/com/earth2me/essentials/utils/DateUtil.java */ package me.lucko.luckperms.common.utils; @@ -30,9 +14,7 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; /** - * All credit to Essentials / EssentialsX for this class - * https://github.com/drtshock/Essentials/blob/2.x/Essentials/src/com/earth2me/essentials/utils/DateUtil.java - * https://github.com/essentials/Essentials/blob/2.x/Essentials/src/com/earth2me/essentials/utils/DateUtil.java + * Translates unix timestamps / durations into a readable format */ @UtilityClass public class DateUtil { @@ -52,13 +34,7 @@ public class DateUtil { */ public static long parseDateDiff(String time, boolean future) throws IllegalDateException { Matcher m = TIME_PATTERN.matcher(time); - int years = 0; - int months = 0; - int weeks = 0; - int days = 0; - int hours = 0; - int minutes = 0; - int seconds = 0; + int years = 0, months = 0, weeks = 0, days = 0, hours = 0, minutes = 0, seconds = 0; boolean found = false; while (m.find()) { if (m.group() == null || m.group().isEmpty()) { @@ -137,8 +113,7 @@ public class DateUtil { int fromYear = fromDate.get(year); int toYear = toDate.get(year); if (Math.abs(fromYear - toYear) > MAX_YEARS) { - toDate.set(year, fromYear + - (future ? MAX_YEARS : -MAX_YEARS)); + toDate.set(year, fromYear + (future ? MAX_YEARS : -MAX_YEARS)); } int diff = 0; diff --git a/common/src/main/java/me/lucko/luckperms/common/utils/DebugHandler.java b/common/src/main/java/me/lucko/luckperms/common/utils/DebugHandler.java index c35ce5d6..12a8f018 100644 --- a/common/src/main/java/me/lucko/luckperms/common/utils/DebugHandler.java +++ b/common/src/main/java/me/lucko/luckperms/common/utils/DebugHandler.java @@ -36,11 +36,11 @@ import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; public class DebugHandler { - private final Map> listeners = new ConcurrentHashMap<>(); + private final Map> listeners = new ConcurrentHashMap<>(); public void printOutput(String checked, String node, Tristate value) { all: - for (Map.Entry> e : listeners.entrySet()) { + for (Map.Entry> e : listeners.entrySet()) { for (String filter : e.getValue()) { if (node.toLowerCase().startsWith(filter.toLowerCase())) { continue; @@ -58,17 +58,17 @@ public class DebugHandler { } public void register(Sender sender, List filters) { - listeners.put(new Reciever(sender.getUuid(), sender), ImmutableList.copyOf(filters)); + listeners.put(new Receiver(sender.getUuid(), sender), ImmutableList.copyOf(filters)); } public void unregister(UUID uuid) { - listeners.remove(new Reciever(uuid, null)); + listeners.remove(new Receiver(uuid, null)); } @Getter @EqualsAndHashCode(of = "uuid") @AllArgsConstructor - private static final class Reciever { + private static final class Receiver { private final UUID uuid; private final Sender sender; } diff --git a/common/src/main/java/me/lucko/luckperms/common/utils/LocalizedNode.java b/common/src/main/java/me/lucko/luckperms/common/utils/LocalizedNode.java index 5e0281b5..cff9c4b6 100644 --- a/common/src/main/java/me/lucko/luckperms/common/utils/LocalizedNode.java +++ b/common/src/main/java/me/lucko/luckperms/common/utils/LocalizedNode.java @@ -27,7 +27,7 @@ import lombok.experimental.Delegate; import me.lucko.luckperms.api.Node; /** - * Holds a Node and where it was inherited from + * Holds a Node and where it was inherited from. All calls are passed onto the contained Node instance. */ @Getter @ToString diff --git a/common/src/main/java/me/lucko/luckperms/common/utils/LogFactory.java b/common/src/main/java/me/lucko/luckperms/common/utils/LogFactory.java index 1a5199b1..241659b7 100644 --- a/common/src/main/java/me/lucko/luckperms/common/utils/LogFactory.java +++ b/common/src/main/java/me/lucko/luckperms/common/utils/LogFactory.java @@ -25,6 +25,9 @@ package me.lucko.luckperms.common.utils; import lombok.experimental.UtilityClass; import me.lucko.luckperms.api.Logger; +/** + * Utility to help create wrapped log instances + */ @UtilityClass public class LogFactory { public static Logger wrap(org.slf4j.Logger l) { diff --git a/common/src/main/java/me/lucko/luckperms/common/utils/Predicates.java b/common/src/main/java/me/lucko/luckperms/common/utils/Predicates.java index e0b4cf80..c60f931c 100644 --- a/common/src/main/java/me/lucko/luckperms/common/utils/Predicates.java +++ b/common/src/main/java/me/lucko/luckperms/common/utils/Predicates.java @@ -29,6 +29,9 @@ import java.util.function.Predicate; import java.util.stream.Collectors; import java.util.stream.IntStream; +/** + * A collection of predicate utilities used mostly in command classes + */ @SuppressWarnings({"WeakerAccess", "unused"}) @UtilityClass public class Predicates { diff --git a/sponge/src/main/java/me/lucko/luckperms/sponge/LPSpongePlugin.java b/sponge/src/main/java/me/lucko/luckperms/sponge/LPSpongePlugin.java index c74f4a62..45a372bf 100644 --- a/sponge/src/main/java/me/lucko/luckperms/sponge/LPSpongePlugin.java +++ b/sponge/src/main/java/me/lucko/luckperms/sponge/LPSpongePlugin.java @@ -123,11 +123,13 @@ public class LPSpongePlugin implements LuckPermsPlugin { private CalculatorFactory calculatorFactory; private BufferedRequest updateTaskBuffer; private DebugHandler debugHandler; + private SpongeSenderFactory senderFactory; @Listener public void onEnable(GamePreInitializationEvent event) { log = LogFactory.wrap(logger); debugHandler = new DebugHandler(); + senderFactory = new SpongeSenderFactory(this); timings = new LPTimings(this); getLog().info("Loading configuration..."); @@ -304,16 +306,15 @@ public class LPSpongePlugin implements LuckPermsPlugin { } @Override - public List getNotifyListeners() { + public List getSenders() { return game.getServer().getOnlinePlayers().stream() - .map(s -> SpongeSenderFactory.get(this).wrap(s)) - .filter(Permission.LOG_NOTIFY::isAuthorized) + .map(s -> getSenderFactory().wrap(s)) .collect(Collectors.toList()); } @Override public Sender getConsoleSender() { - return SpongeSenderFactory.get(this).wrap(game.getServer().getConsole()); + return getSenderFactory().wrap(game.getServer().getConsole()); } @Override diff --git a/sponge/src/main/java/me/lucko/luckperms/sponge/SpongeCommand.java b/sponge/src/main/java/me/lucko/luckperms/sponge/SpongeCommand.java index 4748db49..9d0fe436 100644 --- a/sponge/src/main/java/me/lucko/luckperms/sponge/SpongeCommand.java +++ b/sponge/src/main/java/me/lucko/luckperms/sponge/SpongeCommand.java @@ -54,7 +54,7 @@ class SpongeCommand extends CommandManager implements CommandCallable { public CommandResult process(CommandSource source, String s) throws CommandException { try (Timing ignored = plugin.getTimings().time(LPTiming.ON_COMMAND)) { onCommand( - SpongeSenderFactory.get(getPlugin()).wrap(source), + plugin.getSenderFactory().wrap(source), "perms", Util.stripQuotes(Splitter.on(Patterns.COMMAND_SEPARATOR).omitEmptyStrings().splitToList(s)), Callback.empty() @@ -66,13 +66,13 @@ class SpongeCommand extends CommandManager implements CommandCallable { @Override public List getSuggestions(CommandSource source, String s, @Nullable Location location) throws CommandException { try (Timing ignored = plugin.getTimings().time(LPTiming.COMMAND_TAB_COMPLETE)) { - return onTabComplete(SpongeSenderFactory.get(getPlugin()).wrap(source), Splitter.on(' ').splitToList(s)); + return onTabComplete(plugin.getSenderFactory().wrap(source), Splitter.on(' ').splitToList(s)); } } public List getSuggestions(CommandSource source, String s) throws CommandException { try (Timing ignored = plugin.getTimings().time(LPTiming.COMMAND_TAB_COMPLETE)) { - return onTabComplete(SpongeSenderFactory.get(getPlugin()).wrap(source), Splitter.on(' ').splitToList(s)); + return onTabComplete(plugin.getSenderFactory().wrap(source), Splitter.on(' ').splitToList(s)); } } diff --git a/sponge/src/main/java/me/lucko/luckperms/sponge/SpongeSenderFactory.java b/sponge/src/main/java/me/lucko/luckperms/sponge/SpongeSenderFactory.java index f9012755..fd8d13f1 100644 --- a/sponge/src/main/java/me/lucko/luckperms/sponge/SpongeSenderFactory.java +++ b/sponge/src/main/java/me/lucko/luckperms/sponge/SpongeSenderFactory.java @@ -32,19 +32,10 @@ import org.spongepowered.api.text.serializer.TextSerializers; import java.util.UUID; public class SpongeSenderFactory extends SenderFactory { - private static SpongeSenderFactory instance = null; - - private SpongeSenderFactory(LuckPermsPlugin plugin) { + public SpongeSenderFactory(LuckPermsPlugin plugin) { super(plugin); } - public static synchronized SpongeSenderFactory get(LuckPermsPlugin plugin) { - if (instance == null) { - instance = new SpongeSenderFactory(plugin); - } - return instance; - } - @Override protected String getName(CommandSource source) { if (source instanceof Player) { diff --git a/sponge/src/main/java/me/lucko/luckperms/sponge/service/LuckPermsSubject.java b/sponge/src/main/java/me/lucko/luckperms/sponge/service/LuckPermsSubject.java index 9e4ac44f..388b5d42 100644 --- a/sponge/src/main/java/me/lucko/luckperms/sponge/service/LuckPermsSubject.java +++ b/sponge/src/main/java/me/lucko/luckperms/sponge/service/LuckPermsSubject.java @@ -22,6 +22,7 @@ package me.lucko.luckperms.sponge.service; +import com.google.common.collect.ImmutableSet; import lombok.NonNull; import me.lucko.luckperms.api.context.ContextSet; import org.spongepowered.api.service.context.Context; @@ -97,7 +98,7 @@ public abstract class LuckPermsSubject implements Subject { @Override @Deprecated public Set getActiveContexts() { - return LuckPermsService.convertContexts(getActiveContextSet()); + return ImmutableSet.copyOf(LuckPermsService.convertContexts(getActiveContextSet())); } } diff --git a/sponge/src/main/java/me/lucko/luckperms/sponge/service/LuckPermsSubjectData.java b/sponge/src/main/java/me/lucko/luckperms/sponge/service/LuckPermsSubjectData.java index 6e8727e7..e454d1da 100644 --- a/sponge/src/main/java/me/lucko/luckperms/sponge/service/LuckPermsSubjectData.java +++ b/sponge/src/main/java/me/lucko/luckperms/sponge/service/LuckPermsSubjectData.java @@ -28,6 +28,7 @@ import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; import lombok.AllArgsConstructor; import lombok.Getter; +import lombok.NonNull; import me.lucko.luckperms.api.Node; import me.lucko.luckperms.api.context.ContextSet; import me.lucko.luckperms.common.core.NodeBuilder; @@ -97,12 +98,12 @@ public class LuckPermsSubjectData implements SubjectData { } @Override - public Map getPermissions(Set contexts) { + public Map getPermissions(@NonNull Set contexts) { return getAllPermissions().getOrDefault(contexts, ImmutableMap.of()); } @Override - public boolean setPermission(Set contexts, String permission, Tristate tristate) { + public boolean setPermission(@NonNull Set contexts, @NonNull String permission, @NonNull Tristate tristate) { try (Timing i = service.getPlugin().getTimings().time(LPTiming.LP_SUBJECT_SET_PERMISSION)) { if (tristate == Tristate.UNDEFINED) { // Unset @@ -158,7 +159,7 @@ public class LuckPermsSubjectData implements SubjectData { } @Override - public boolean clearPermissions(Set c) { + public boolean clearPermissions(@NonNull Set c) { try (Timing i = service.getPlugin().getTimings().time(LPTiming.LP_SUBJECT_CLEAR_PERMISSIONS)) { List toRemove = new ArrayList<>(); for (Node n : enduring ? holder.getNodes() : holder.getTransientNodes()) { @@ -232,12 +233,12 @@ public class LuckPermsSubjectData implements SubjectData { } @Override - public List getParents(Set contexts) { + public List getParents(@NonNull Set contexts) { return getAllParents().getOrDefault(contexts, ImmutableList.of()); } @Override - public boolean addParent(Set set, Subject subject) { + public boolean addParent(@NonNull Set set, @NonNull Subject subject) { try (Timing i = service.getPlugin().getTimings().time(LPTiming.LP_SUBJECT_ADD_PARENT)) { if (subject instanceof LuckPermsGroupSubject) { LuckPermsGroupSubject permsSubject = ((LuckPermsGroupSubject) subject); @@ -263,7 +264,7 @@ public class LuckPermsSubjectData implements SubjectData { } @Override - public boolean removeParent(Set set, Subject subject) { + public boolean removeParent(@NonNull Set set, @NonNull Subject subject) { try (Timing i = service.getPlugin().getTimings().time(LPTiming.LP_SUBJECT_REMOVE_PARENT)) { if (subject instanceof LuckPermsGroupSubject) { LuckPermsGroupSubject permsSubject = ((LuckPermsGroupSubject) subject); @@ -315,7 +316,7 @@ public class LuckPermsSubjectData implements SubjectData { } @Override - public boolean clearParents(Set set) { + public boolean clearParents(@NonNull Set set) { try (Timing i = service.getPlugin().getTimings().time(LPTiming.LP_SUBJECT_CLEAR_PARENTS)) { List toRemove = new ArrayList<>(); for (Node n : enduring ? holder.getNodes() : holder.getTransientNodes()) { @@ -421,12 +422,12 @@ public class LuckPermsSubjectData implements SubjectData { } @Override - public Map getOptions(Set set) { + public Map getOptions(@NonNull Set set) { return getAllOptions().getOrDefault(set, ImmutableMap.of()); } @Override - public boolean setOption(Set set, String key, String value) { + public boolean setOption(@NonNull Set set, @NonNull String key, @NonNull String value) { try (Timing i = service.getPlugin().getTimings().time(LPTiming.LP_SUBJECT_SET_OPTION)) { ContextSet context = LuckPermsService.convertContexts(set); @@ -452,7 +453,7 @@ public class LuckPermsSubjectData implements SubjectData { } @Override - public boolean clearOptions(Set set) { + public boolean clearOptions(@NonNull Set set) { try (Timing i = service.getPlugin().getTimings().time(LPTiming.LP_SUBJECT_CLEAR_OPTIONS)) { List toRemove = new ArrayList<>(); for (Node n : enduring ? holder.getNodes() : holder.getTransientNodes()) { diff --git a/sponge/src/main/java/me/lucko/luckperms/sponge/service/collections/GroupCollection.java b/sponge/src/main/java/me/lucko/luckperms/sponge/service/collections/GroupCollection.java index 7fab4b87..c34160a5 100644 --- a/sponge/src/main/java/me/lucko/luckperms/sponge/service/collections/GroupCollection.java +++ b/sponge/src/main/java/me/lucko/luckperms/sponge/service/collections/GroupCollection.java @@ -40,7 +40,6 @@ import org.spongepowered.api.util.Tristate; import java.util.Map; import java.util.Set; -import java.util.stream.Collectors; public class GroupCollection implements SubjectCollection { private final LuckPermsService service; @@ -92,7 +91,7 @@ public class GroupCollection implements SubjectCollection { return manager.getAll().values().stream() .map(u -> LuckPermsGroupSubject.wrapGroup(u, service)) .filter(sub -> sub.getPermissionValue(cs, node) != Tristate.UNDEFINED) - .collect(Collectors.toMap(sub -> sub, sub -> sub.getPermissionValue(cs, node).asBoolean())); + .collect(ImmutableCollectors.toImmutableMap(sub -> sub, sub -> sub.getPermissionValue(cs, node).asBoolean())); } @Override diff --git a/sponge/src/main/java/me/lucko/luckperms/sponge/service/collections/UserCollection.java b/sponge/src/main/java/me/lucko/luckperms/sponge/service/collections/UserCollection.java index 2b159a54..68d88e6c 100644 --- a/sponge/src/main/java/me/lucko/luckperms/sponge/service/collections/UserCollection.java +++ b/sponge/src/main/java/me/lucko/luckperms/sponge/service/collections/UserCollection.java @@ -62,13 +62,6 @@ public class UserCollection implements SubjectCollection { private final SimpleCollection fallback; private final LoadingCache users = CacheBuilder.newBuilder() - /* - .removalListener((RemovalListener) r -> { - if (r.getValue() != null) { - r.getValue().deprovision(); - } - }) - */ .build(new CacheLoader() { @Override public LuckPermsUserSubject load(UUID uuid) throws Exception { diff --git a/sponge/src/main/java/me/lucko/luckperms/sponge/service/persisted/PersistedCollection.java b/sponge/src/main/java/me/lucko/luckperms/sponge/service/persisted/PersistedCollection.java index 6e6d5407..f5dee514 100644 --- a/sponge/src/main/java/me/lucko/luckperms/sponge/service/persisted/PersistedCollection.java +++ b/sponge/src/main/java/me/lucko/luckperms/sponge/service/persisted/PersistedCollection.java @@ -26,6 +26,7 @@ import com.google.common.cache.CacheBuilder; import com.google.common.cache.CacheLoader; import com.google.common.cache.LoadingCache; import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableSet; import lombok.Getter; import lombok.NonNull; import lombok.RequiredArgsConstructor; @@ -36,7 +37,6 @@ import org.spongepowered.api.service.permission.Subject; import org.spongepowered.api.service.permission.SubjectCollection; import org.spongepowered.api.util.Tristate; -import java.util.Collections; import java.util.Map; import java.util.Set; @@ -83,7 +83,7 @@ public class PersistedCollection implements SubjectCollection { @Override public Map getAllWithPermission(@NonNull String id) { - return getAllWithPermission(Collections.emptySet(), id); + return getAllWithPermission(ImmutableSet.of(), id); } @Override diff --git a/sponge/src/main/java/me/lucko/luckperms/sponge/service/persisted/PersistedSubject.java b/sponge/src/main/java/me/lucko/luckperms/sponge/service/persisted/PersistedSubject.java index 85381ad9..8503e814 100644 --- a/sponge/src/main/java/me/lucko/luckperms/sponge/service/persisted/PersistedSubject.java +++ b/sponge/src/main/java/me/lucko/luckperms/sponge/service/persisted/PersistedSubject.java @@ -24,6 +24,7 @@ package me.lucko.luckperms.sponge.service.persisted; import co.aikar.timings.Timing; import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableSet; import lombok.Getter; import lombok.NonNull; import me.lucko.luckperms.common.utils.BufferedRequest; @@ -196,7 +197,7 @@ public class PersistedSubject implements Subject { @Override public Set getActiveContexts() { try (Timing ignored = service.getPlugin().getTimings().time(LPTiming.PERSISTED_SUBJECT_GET_ACTIVE_CONTEXTS)) { - return LuckPermsService.convertContexts(service.getPlugin().getContextManager().getApplicableContext(this)); + return ImmutableSet.copyOf(LuckPermsService.convertContexts(service.getPlugin().getContextManager().getApplicableContext(this))); } } } diff --git a/sponge/src/main/java/me/lucko/luckperms/sponge/service/simple/SimpleCollection.java b/sponge/src/main/java/me/lucko/luckperms/sponge/service/simple/SimpleCollection.java index 9e2e0250..8da03a6a 100644 --- a/sponge/src/main/java/me/lucko/luckperms/sponge/service/simple/SimpleCollection.java +++ b/sponge/src/main/java/me/lucko/luckperms/sponge/service/simple/SimpleCollection.java @@ -25,20 +25,20 @@ package me.lucko.luckperms.sponge.service.simple; import com.google.common.cache.CacheBuilder; import com.google.common.cache.CacheLoader; import com.google.common.cache.LoadingCache; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableSet; import lombok.Getter; import lombok.NonNull; import lombok.RequiredArgsConstructor; +import me.lucko.luckperms.common.utils.ImmutableCollectors; import me.lucko.luckperms.sponge.service.LuckPermsService; import org.spongepowered.api.service.context.Context; import org.spongepowered.api.service.permission.Subject; import org.spongepowered.api.service.permission.SubjectCollection; import org.spongepowered.api.util.Tristate; -import java.util.Collections; -import java.util.HashMap; import java.util.Map; import java.util.Set; -import java.util.stream.Collectors; /** * Super simple SubjectCollection implementation @@ -70,17 +70,17 @@ public class SimpleCollection implements SubjectCollection { @Override public Iterable getAllSubjects() { - return subjects.asMap().values().stream().map(s -> (Subject) s).collect(Collectors.toList()); + return subjects.asMap().values().stream().map(s -> (Subject) s).collect(ImmutableCollectors.toImmutableList()); } @Override public Map getAllWithPermission(@NonNull String id) { - return getAllWithPermission(Collections.emptySet(), id); + return getAllWithPermission(ImmutableSet.of(), id); } @Override public Map getAllWithPermission(@NonNull Set contexts, @NonNull String node) { - Map m = new HashMap<>(); + ImmutableMap.Builder m = ImmutableMap.builder(); for (Subject subject : subjects.asMap().values()) { Tristate ts = subject.getPermissionValue(contexts, node); if (ts != Tristate.UNDEFINED) { @@ -88,7 +88,7 @@ public class SimpleCollection implements SubjectCollection { } } - return m; + return m.build(); } @Override diff --git a/sponge/src/main/java/me/lucko/luckperms/sponge/service/simple/SimpleSubject.java b/sponge/src/main/java/me/lucko/luckperms/sponge/service/simple/SimpleSubject.java index 43ba5952..ef25a4fd 100644 --- a/sponge/src/main/java/me/lucko/luckperms/sponge/service/simple/SimpleSubject.java +++ b/sponge/src/main/java/me/lucko/luckperms/sponge/service/simple/SimpleSubject.java @@ -24,6 +24,7 @@ package me.lucko.luckperms.sponge.service.simple; import co.aikar.timings.Timing; import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableSet; import lombok.Getter; import lombok.NonNull; import me.lucko.luckperms.sponge.service.LuckPermsService; @@ -162,7 +163,7 @@ public class SimpleSubject implements Subject { @Override public Set getActiveContexts() { try (Timing ignored = service.getPlugin().getTimings().time(LPTiming.SIMPLE_SUBJECT_GET_ACTIVE_CONTEXTS)) { - return LuckPermsService.convertContexts(service.getPlugin().getContextManager().getApplicableContext(this)); + return ImmutableSet.copyOf(LuckPermsService.convertContexts(service.getPlugin().getContextManager().getApplicableContext(this))); } } }