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 4f71bcfff..d3ea31c35 100644 --- a/bukkit/src/main/java/me/lucko/luckperms/bukkit/LPBukkitPlugin.java +++ b/bukkit/src/main/java/me/lucko/luckperms/bukkit/LPBukkitPlugin.java @@ -102,6 +102,8 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.CountDownLatch; import java.util.stream.Stream; +import javax.annotation.Nullable; + /** * LuckPerms implementation for the Bukkit API. */ @@ -505,6 +507,7 @@ public class LPBukkitPlugin extends JavaPlugin implements LuckPermsPlugin { } } + @Nullable @Override public Contexts getContextForUser(User user) { Player player = getPlayer(user); diff --git a/bukkit/src/main/java/me/lucko/luckperms/bukkit/calculators/BukkitCalculatorFactory.java b/bukkit/src/main/java/me/lucko/luckperms/bukkit/calculators/BukkitCalculatorFactory.java index 98c6ddb45..4f1704d7a 100644 --- a/bukkit/src/main/java/me/lucko/luckperms/bukkit/calculators/BukkitCalculatorFactory.java +++ b/bukkit/src/main/java/me/lucko/luckperms/bukkit/calculators/BukkitCalculatorFactory.java @@ -41,8 +41,6 @@ import me.lucko.luckperms.common.processors.RegexProcessor; import me.lucko.luckperms.common.processors.WildcardProcessor; import me.lucko.luckperms.common.references.HolderType; -import java.util.List; - public class BukkitCalculatorFactory extends AbstractCalculatorFactory { private final LPBukkitPlugin plugin; @@ -74,16 +72,4 @@ public class BukkitCalculatorFactory extends AbstractCalculatorFactory { return registerCalculator(new PermissionCalculator(this.plugin, metadata, processors.build())); } - - @Override - public List getActiveProcessors() { - ImmutableList.Builder ret = ImmutableList.builder(); - ret.add("Map"); - if (this.plugin.getConfiguration().get(ConfigKeys.APPLY_BUKKIT_CHILD_PERMISSIONS)) ret.add("Child"); - if (this.plugin.getConfiguration().get(ConfigKeys.APPLY_BUKKIT_ATTACHMENT_PERMISSIONS)) ret.add("Attachment"); - if (this.plugin.getConfiguration().get(ConfigKeys.APPLYING_REGEX)) ret.add("Regex"); - if (this.plugin.getConfiguration().get(ConfigKeys.APPLYING_WILDCARDS)) ret.add("Wildcard"); - if (this.plugin.getConfiguration().get(ConfigKeys.APPLY_BUKKIT_DEFAULT_PERMISSIONS)) ret.add("Defaults"); - return ret.build(); - } } 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 a6b886a9b..36a72939c 100644 --- a/bungee/src/main/java/me/lucko/luckperms/bungee/LPBungeePlugin.java +++ b/bungee/src/main/java/me/lucko/luckperms/bungee/LPBungeePlugin.java @@ -90,6 +90,8 @@ import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; import java.util.stream.Stream; +import javax.annotation.Nullable; + /** * LuckPerms implementation for the BungeeCord API. */ @@ -335,6 +337,7 @@ public class LPBungeePlugin extends Plugin implements LuckPermsPlugin { return Optional.empty(); } + @Nullable @Override public Contexts getContextForUser(User user) { ProxiedPlayer player = getPlayer(user); diff --git a/bungee/src/main/java/me/lucko/luckperms/bungee/calculators/BungeeCalculatorFactory.java b/bungee/src/main/java/me/lucko/luckperms/bungee/calculators/BungeeCalculatorFactory.java index e95ef2fa5..11628bbd7 100644 --- a/bungee/src/main/java/me/lucko/luckperms/bungee/calculators/BungeeCalculatorFactory.java +++ b/bungee/src/main/java/me/lucko/luckperms/bungee/calculators/BungeeCalculatorFactory.java @@ -38,8 +38,6 @@ import me.lucko.luckperms.common.processors.PermissionProcessor; import me.lucko.luckperms.common.processors.RegexProcessor; import me.lucko.luckperms.common.processors.WildcardProcessor; -import java.util.List; - public class BungeeCalculatorFactory extends AbstractCalculatorFactory { private final LPBungeePlugin plugin; @@ -63,13 +61,4 @@ public class BungeeCalculatorFactory extends AbstractCalculatorFactory { return registerCalculator(new PermissionCalculator(this.plugin, metadata, processors.build())); } - - @Override - public List getActiveProcessors() { - ImmutableList.Builder ret = ImmutableList.builder(); - ret.add("Map"); - if (this.plugin.getConfiguration().get(ConfigKeys.APPLYING_REGEX)) ret.add("Regex"); - if (this.plugin.getConfiguration().get(ConfigKeys.APPLYING_WILDCARDS)) ret.add("Wildcards"); - return ret.build(); - } } diff --git a/common/src/main/java/me/lucko/luckperms/common/caching/HolderCachedData.java b/common/src/main/java/me/lucko/luckperms/common/caching/HolderCachedData.java index fdead0417..b3bedf993 100644 --- a/common/src/main/java/me/lucko/luckperms/common/caching/HolderCachedData.java +++ b/common/src/main/java/me/lucko/luckperms/common/caching/HolderCachedData.java @@ -37,10 +37,8 @@ import me.lucko.luckperms.common.caching.type.MetaAccumulator; import me.lucko.luckperms.common.caching.type.MetaCache; import me.lucko.luckperms.common.caching.type.PermissionCache; import me.lucko.luckperms.common.calculators.PermissionCalculatorMetadata; -import me.lucko.luckperms.common.config.ConfigKeys; import me.lucko.luckperms.common.metastacking.SimpleMetaStack; import me.lucko.luckperms.common.model.PermissionHolder; -import me.lucko.luckperms.common.plugin.LuckPermsPlugin; import java.util.HashSet; import java.util.Objects; @@ -149,7 +147,7 @@ public abstract class HolderCachedData implements Ca @Override public MetaCache getMetaData(@Nonnull Contexts contexts) { Objects.requireNonNull(contexts, "contexts"); - return getMetaData(makeFromMetaContextsConfig(contexts, this.holder.getPlugin())); + return getMetaData(this.holder.getPlugin().getContextManager().formMetaContexts(contexts)); } @Nonnull @@ -170,7 +168,7 @@ public abstract class HolderCachedData implements Ca @Override public MetaCache calculateMeta(@Nonnull Contexts contexts) { Objects.requireNonNull(contexts, "contexts"); - return calculateMeta(makeFromMetaContextsConfig(contexts, this.holder.getPlugin())); + return calculateMeta(this.holder.getPlugin().getContextManager().formMetaContexts(contexts)); } @Override @@ -188,7 +186,7 @@ public abstract class HolderCachedData implements Ca @Override public void recalculateMeta(@Nonnull Contexts contexts) { Objects.requireNonNull(contexts, "contexts"); - recalculateMeta(makeFromMetaContextsConfig(contexts, this.holder.getPlugin())); + recalculateMeta(this.holder.getPlugin().getContextManager().formMetaContexts(contexts)); } @Nonnull @@ -225,7 +223,7 @@ public abstract class HolderCachedData implements Ca @Override public CompletableFuture reloadMeta(@Nonnull Contexts contexts) { Objects.requireNonNull(contexts, "contexts"); - return reloadMeta(makeFromMetaContextsConfig(contexts, this.holder.getPlugin())); + return reloadMeta(this.holder.getPlugin().getContextManager().formMetaContexts(contexts)); } @Override @@ -279,7 +277,7 @@ public abstract class HolderCachedData implements Ca @Override public void invalidateMeta(@Nonnull Contexts contexts) { Objects.requireNonNull(contexts, "contexts"); - this.meta.invalidate(makeFromMetaContextsConfig(contexts, this.holder.getPlugin())); + this.meta.invalidate(this.holder.getPlugin().getContextManager().formMetaContexts(contexts)); } @Override @@ -321,14 +319,6 @@ public abstract class HolderCachedData implements Ca } } - private static MetaContexts makeFromMetaContextsConfig(Contexts contexts, LuckPermsPlugin plugin) { - return new MetaContexts( - contexts, - plugin.getConfiguration().get(ConfigKeys.PREFIX_FORMATTING_OPTIONS), - plugin.getConfiguration().get(ConfigKeys.SUFFIX_FORMATTING_OPTIONS) - ); - } - private static MetaAccumulator newAccumulator(MetaContexts contexts) { return new MetaAccumulator( new SimpleMetaStack(contexts.getPrefixStackDefinition(), ChatMetaType.PREFIX), diff --git a/common/src/main/java/me/lucko/luckperms/common/caching/type/PermissionCache.java b/common/src/main/java/me/lucko/luckperms/common/caching/type/PermissionCache.java index 49eaa21a6..d028428b0 100644 --- a/common/src/main/java/me/lucko/luckperms/common/caching/type/PermissionCache.java +++ b/common/src/main/java/me/lucko/luckperms/common/caching/type/PermissionCache.java @@ -93,6 +93,10 @@ public class PermissionCache implements PermissionData { } } + public PermissionCalculator getCalculator() { + return this.calculator; + } + @Nonnull @Override public Map getImmutableBacking() { diff --git a/common/src/main/java/me/lucko/luckperms/common/calculators/CalculatorFactory.java b/common/src/main/java/me/lucko/luckperms/common/calculators/CalculatorFactory.java index 2bb863585..948ac2928 100644 --- a/common/src/main/java/me/lucko/luckperms/common/calculators/CalculatorFactory.java +++ b/common/src/main/java/me/lucko/luckperms/common/calculators/CalculatorFactory.java @@ -27,8 +27,6 @@ package me.lucko.luckperms.common.calculators; import me.lucko.luckperms.api.Contexts; -import java.util.List; - /** * Creates a calculator instance given a set of contexts */ @@ -43,13 +41,6 @@ public interface CalculatorFactory { */ PermissionCalculator build(Contexts contexts, PermissionCalculatorMetadata metadata); - /** - * Gets the processors which are currently being added to built calculators - * - * @return a list of processors - */ - List getActiveProcessors(); - /** * Invalidates all calculators build by this factory */ diff --git a/common/src/main/java/me/lucko/luckperms/common/calculators/PermissionCalculator.java b/common/src/main/java/me/lucko/luckperms/common/calculators/PermissionCalculator.java index 75a0aa334..83657cd56 100644 --- a/common/src/main/java/me/lucko/luckperms/common/calculators/PermissionCalculator.java +++ b/common/src/main/java/me/lucko/luckperms/common/calculators/PermissionCalculator.java @@ -28,6 +28,7 @@ package me.lucko.luckperms.common.calculators; import com.github.benmanes.caffeine.cache.CacheLoader; import com.github.benmanes.caffeine.cache.Caffeine; import com.github.benmanes.caffeine.cache.LoadingCache; +import com.google.common.collect.ImmutableList; import me.lucko.luckperms.api.Tristate; import me.lucko.luckperms.common.plugin.LuckPermsPlugin; @@ -45,17 +46,21 @@ import javax.annotation.Nonnull; public class PermissionCalculator implements CacheLoader { private final LuckPermsPlugin plugin; private final PermissionCalculatorMetadata metadata; - private final List processors; + private final ImmutableList processors; // caches lookup calls. private final LoadingCache lookupCache = Caffeine.newBuilder().build(this); - public PermissionCalculator(LuckPermsPlugin plugin, PermissionCalculatorMetadata metadata, List processors) { + public PermissionCalculator(LuckPermsPlugin plugin, PermissionCalculatorMetadata metadata, ImmutableList processors) { this.plugin = plugin; this.metadata = metadata; this.processors = processors; } + public List getProcessors() { + return this.processors; + } + public void invalidateCache() { this.lookupCache.invalidateAll(); } diff --git a/common/src/main/java/me/lucko/luckperms/common/commands/CommandManager.java b/common/src/main/java/me/lucko/luckperms/common/commands/CommandManager.java index e45487f02..fa41b8e7b 100644 --- a/common/src/main/java/me/lucko/luckperms/common/commands/CommandManager.java +++ b/common/src/main/java/me/lucko/luckperms/common/commands/CommandManager.java @@ -37,6 +37,7 @@ import me.lucko.luckperms.common.commands.impl.migration.MigrationMainCommand; import me.lucko.luckperms.common.commands.impl.misc.ApplyEditsCommand; import me.lucko.luckperms.common.commands.impl.misc.BulkUpdateCommand; import me.lucko.luckperms.common.commands.impl.misc.CheckCommand; +import me.lucko.luckperms.common.commands.impl.misc.DebugCommand; import me.lucko.luckperms.common.commands.impl.misc.ExportCommand; import me.lucko.luckperms.common.commands.impl.misc.ImportCommand; import me.lucko.luckperms.common.commands.impl.misc.InfoCommand; @@ -108,6 +109,7 @@ public class CommandManager { .add(new LogMainCommand(locale)) .add(new SyncCommand(locale)) .add(new InfoCommand(locale)) + .add(new DebugCommand(locale)) .add(new VerboseCommand(locale)) .add(new TreeCommand(locale)) .add(new SearchCommand(locale)) diff --git a/common/src/main/java/me/lucko/luckperms/common/commands/CommandPermission.java b/common/src/main/java/me/lucko/luckperms/common/commands/CommandPermission.java index 171c77ae6..92f3aeaf9 100644 --- a/common/src/main/java/me/lucko/luckperms/common/commands/CommandPermission.java +++ b/common/src/main/java/me/lucko/luckperms/common/commands/CommandPermission.java @@ -41,6 +41,7 @@ public enum CommandPermission { SYNC("sync", NONE), INFO("info", NONE), + DEBUG("debug", NONE), VERBOSE("verbose", NONE), TREE("tree", NONE), SEARCH("search", NONE), diff --git a/common/src/main/java/me/lucko/luckperms/common/commands/impl/misc/DebugCommand.java b/common/src/main/java/me/lucko/luckperms/common/commands/impl/misc/DebugCommand.java new file mode 100644 index 000000000..f11e24cda --- /dev/null +++ b/common/src/main/java/me/lucko/luckperms/common/commands/impl/misc/DebugCommand.java @@ -0,0 +1,373 @@ +/* + * This file is part of LuckPerms, licensed under the MIT License. + * + * Copyright (c) lucko (Luck) + * Copyright (c) contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package me.lucko.luckperms.common.commands.impl.misc; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; + +import me.lucko.luckperms.api.Contexts; +import me.lucko.luckperms.api.caching.MetaContexts; +import me.lucko.luckperms.api.context.ContextCalculator; +import me.lucko.luckperms.api.context.StaticContextCalculator; +import me.lucko.luckperms.api.metastacking.MetaStackDefinition; +import me.lucko.luckperms.api.metastacking.MetaStackElement; +import me.lucko.luckperms.common.caching.type.MetaCache; +import me.lucko.luckperms.common.caching.type.PermissionCache; +import me.lucko.luckperms.common.commands.CommandPermission; +import me.lucko.luckperms.common.commands.CommandResult; +import me.lucko.luckperms.common.commands.abstraction.SingleCommand; +import me.lucko.luckperms.common.commands.sender.Sender; +import me.lucko.luckperms.common.contexts.ContextSetJsonSerializer; +import me.lucko.luckperms.common.contexts.ProxiedContextCalculator; +import me.lucko.luckperms.common.locale.CommandSpec; +import me.lucko.luckperms.common.locale.LocaleManager; +import me.lucko.luckperms.common.locale.Message; +import me.lucko.luckperms.common.model.User; +import me.lucko.luckperms.common.plugin.LuckPermsPlugin; +import me.lucko.luckperms.common.processors.PermissionProcessor; +import me.lucko.luckperms.common.utils.PasteUtils; +import me.lucko.luckperms.common.utils.Predicates; +import me.lucko.luckperms.common.utils.TextUtils; + +import net.kyori.text.Component; +import net.kyori.text.TextComponent; +import net.kyori.text.event.ClickEvent; +import net.kyori.text.event.HoverEvent; +import net.kyori.text.format.TextColor; + +import java.util.Collection; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.UUID; +import java.util.function.Supplier; +import java.util.stream.Collectors; + +public class DebugCommand extends SingleCommand { + private static final Gson GSON = new GsonBuilder().setPrettyPrinting().disableHtmlEscaping().create(); + + public DebugCommand(LocaleManager locale) { + super(CommandSpec.DEBUG.spec(locale), "Debug", CommandPermission.DEBUG, Predicates.alwaysFalse()); + } + + @Override + public CommandResult execute(LuckPermsPlugin plugin, Sender sender, List args, String label) { + Message.DEBUG_START.send(sender); + + Map pages = new LinkedHashMap<>(); + + pages.put("__DEBUG__.md", TextUtils.joinNewline("# Debug Output", "The debugging data can be found in the files below.")); + + pages.put("platform.json", GSON.toJson(getPlatformData(plugin).toJson())); + pages.put("storage.json", GSON.toJson(getStorageData(plugin).toJson())); + pages.put("context.json", GSON.toJson(getContextData(plugin).toJson())); + pages.put("players.json", GSON.toJson(getPlayersData(plugin).toJson())); + + String url = PasteUtils.paste("LuckPerms Debug Output", pages.entrySet()); + Message.DEBUG_URL.send(sender); + + Component message = TextComponent.builder(url).color(TextColor.AQUA) + .clickEvent(new ClickEvent(ClickEvent.Action.OPEN_URL, String.valueOf(url))) + .hoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, TextComponent.of("Click to open the debugging data.").color(TextColor.GRAY))) + .build(); + + sender.sendMessage(message); + return CommandResult.SUCCESS; + } + + private static JObject getPlatformData(LuckPermsPlugin plugin) { + return new JObject() + .add("type", plugin.getServerType().name()) + .add("version", new JObject() + .add("api", String.valueOf(plugin.getApiProvider().getPlatformInfo().getApiVersion())) + .add("plugin", plugin.getVersion()) + ) + .add("server", new JObject() + .add("brand", plugin.getServerBrand()) + .add("version", plugin.getServerVersion()) + ); + } + + private static JObject getStorageData(LuckPermsPlugin plugin) { + return new JObject() + .add("storage", new JObject() + .add("name", plugin.getStorage().getName()) + .add("type", plugin.getStorage().getDao().getClass().getName()) + .add("meta", () -> { + JObject metaObject = new JObject(); + Map meta = plugin.getStorage().getMeta(); + for (Map.Entry entry : meta.entrySet()) { + metaObject.add(entry.getKey(), entry.getValue()); + } + return metaObject; + })) + .add("messaging", () -> { + JObject messaging = new JObject(); + plugin.getMessagingService().ifPresent(ms -> { + messaging.add("name", ms.getName()); + messaging.add("implementation", new JObject() + .add("messenger", ms.getMessenger().getClass().getName()) + .add("provider", ms.getMessengerProvider().getClass().getName()) + ); + }); + return messaging; + }); + } + + private static JObject getContextData(LuckPermsPlugin plugin) { + return new JObject() + .add("staticContext", ContextSetJsonSerializer.serializeContextSet(plugin.getContextManager().getStaticContext())) + .add("calculators", () -> { + JArray calculators = new JArray(); + for (ContextCalculator calculator : plugin.getContextManager().getCalculators()) { + String name = calculator.getClass().getName(); + if (calculator instanceof ProxiedContextCalculator) { + name = ((ProxiedContextCalculator) calculator).getDelegate().getClass().getName(); + } + calculators.add(name); + } + return calculators; + }) + .add("staticCalculators", () -> { + JArray staticCalculators = new JArray(); + for (StaticContextCalculator calculator : plugin.getContextManager().getStaticCalculators()) { + staticCalculators.add(calculator.getClass().getName()); + } + return staticCalculators; + }); + } + + private static JObject getPlayersData(LuckPermsPlugin plugin) { + JObject ret = new JObject(); + + Set onlinePlayers = plugin.getOnlinePlayers().collect(Collectors.toSet()); + ret.add("count", onlinePlayers.size()); + + JArray playerArray = new JArray(); + for (UUID uuid : onlinePlayers) { + User user = plugin.getUserManager().getIfLoaded(uuid); + if (user == null) { + playerArray.add(new JObject() + .add("uniqueId", uuid.toString()) + .add("loaded", false) + ); + continue; + } + + playerArray.add(new JObject() + .add("uniqueId", uuid.toString()) + .add("loaded", true) + .add("username", user.getName().orElse("null")) + .add("primaryGroup", new JObject() + .add("type", user.getPrimaryGroup().getClass().getName()) + .add("value", user.getPrimaryGroup().getValue()) + .add("storedValue", user.getPrimaryGroup().getStoredValue().orElse("null")) + ) + .add("activeContext", () -> { + JObject obj = new JObject(); + Contexts contexts = plugin.getContextForUser(user); + if (contexts != null) { + MetaContexts metaContexts = plugin.getContextManager().formMetaContexts(contexts); + obj.add("data", new JObject() + .add("permissions", serializePermissionsData(user.getCachedData().getPermissionData(contexts))) + .add("meta", serializeMetaData(user.getCachedData().getMetaData(metaContexts))) + ) + .add("contextSet", ContextSetJsonSerializer.serializeContextSet(contexts.getContexts())) + .add("settings", serializeContextsSettings(contexts)) + .add("metaSettings", serializeMetaContextsSettings(metaContexts)); + } + return obj; + }) + ); + } + ret.add("players", playerArray); + return ret; + } + + private static JObject serializeContextsSettings(Contexts contexts) { + return new JObject() + .add("op", contexts.isOp()) + .add("includeGlobal", contexts.isIncludeGlobal()) + .add("includeGlobalWorld", contexts.isIncludeGlobalWorld()) + .add("applyGroups", contexts.isApplyGroups()) + .add("applyGlobalGroups", contexts.isApplyGlobalGroups()) + .add("applyGlobalWorldGroups", contexts.isApplyGlobalWorldGroups()); + } + + private static JObject serializeMetaContextsSettings(MetaContexts metaContexts) { + return new JObject() + .add("prefixStack", serializeMetaStackData(metaContexts.getPrefixStackDefinition())) + .add("suffixStack", serializeMetaStackData(metaContexts.getSuffixStackDefinition())); + } + + private static JObject serializePermissionsData(PermissionCache permissionData) { + return new JObject() + .add("processors", () -> { + JArray processors = new JArray(); + for (PermissionProcessor processor : permissionData.getCalculator().getProcessors()) { + processors.add(processor.getClass().getName()); + } + return processors; + }); + } + + private static JObject serializeMetaData(MetaCache metaData) { + return new JObject() + .add("prefix", metaData.getPrefix()) + .add("suffix", metaData.getSuffix()) + .add("prefixes", () -> { + JArray prefixes = new JArray(); + for (Map.Entry entry : metaData.getPrefixes().entrySet()) { + prefixes.add(new JObject() + .add("weight", entry.getKey()) + .add("value", entry.getValue()) + ); + } + return prefixes; + }) + .add("suffixes", () -> { + JArray suffixes = new JArray(); + for (Map.Entry entry : metaData.getSuffixes().entrySet()) { + suffixes.add(new JObject() + .add("weight", entry.getKey()) + .add("value", entry.getValue()) + ); + } + return suffixes; + }) + .add("meta", () -> { + JObject metaMap = new JObject(); + for (Map.Entry entry : metaData.getMeta().entrySet()) { + metaMap.add(entry.getKey(), entry.getValue()); + } + return metaMap; + }) + .add("metaMap", () -> { + JObject metaMultimap = new JObject(); + for (Map.Entry> entry : metaData.getMetaMultimap().asMap().entrySet()) { + JArray values = new JArray(); + for (String v : entry.getValue()) { + values.add(v); + } + metaMultimap.add(entry.getKey(), values); + } + return metaMultimap; + }); + } + + private static JObject serializeMetaStackData(MetaStackDefinition definition) { + return new JObject() + .add("type", definition.getClass().getName()) + .add("startSpacer", definition.getStartSpacer()) + .add("middleSpacer", definition.getMiddleSpacer()) + .add("endSpacer", definition.getEndSpacer()) + .add("elements", () -> { + JArray elements = new JArray(); + for (MetaStackElement element : definition.getElements()) { + elements.add(new JObject() + .add("type", element.getClass().getName()) + .add("info", element.toString()) + ); + } + return elements; + }); + } + + // stupidly simply fluent gson wrappers + + private interface JElement { + JsonElement toJson(); + } + + private static final class JObject implements JElement { + private final JsonObject o = new JsonObject(); + + @Override + public JsonElement toJson() { + return this.o; + } + + public JObject add(String key, String value) { + this.o.addProperty(key, value); + return this; + } + + public JObject add(String key, Number value) { + this.o.addProperty(key, value); + return this; + } + + public JObject add(String key, Boolean value) { + this.o.addProperty(key, value); + return this; + } + + public JObject add(String key, JsonElement value) { + this.o.add(key, value); + return this; + } + + public JObject add(String key, JElement value) { + return add(key, value.toJson()); + } + + public JObject add(String key, Supplier value) { + return add(key, value.get().toJson()); + } + } + + private static final class JArray implements JElement { + private final JsonArray o = new JsonArray(); + + @Override + public JsonElement toJson() { + return this.o; + } + + public JArray add(String value) { + this.o.add(value); + return this; + } + + public JArray add(JsonElement value) { + this.o.add(value); + return this; + } + + public JArray add(JElement value) { + return add(value.toJson()); + } + + public JArray add(Supplier value) { + return add(value.get().toJson()); + } + } + +} diff --git a/common/src/main/java/me/lucko/luckperms/common/contexts/AbstractContextManager.java b/common/src/main/java/me/lucko/luckperms/common/contexts/AbstractContextManager.java index bb3dfd378..d5d4867e4 100644 --- a/common/src/main/java/me/lucko/luckperms/common/contexts/AbstractContextManager.java +++ b/common/src/main/java/me/lucko/luckperms/common/contexts/AbstractContextManager.java @@ -28,8 +28,10 @@ package me.lucko.luckperms.common.contexts; import com.github.benmanes.caffeine.cache.CacheLoader; import com.github.benmanes.caffeine.cache.Caffeine; import com.github.benmanes.caffeine.cache.LoadingCache; +import com.google.common.collect.ImmutableList; import me.lucko.luckperms.api.Contexts; +import me.lucko.luckperms.api.caching.MetaContexts; import me.lucko.luckperms.api.context.ContextCalculator; import me.lucko.luckperms.api.context.ImmutableContextSet; import me.lucko.luckperms.api.context.MutableContextSet; @@ -80,6 +82,16 @@ public abstract class AbstractContextManager implements ContextManager { this.subjectClass = subjectClass; } + @Override + public List> getCalculators() { + return ImmutableList.copyOf(this.calculators); + } + + @Override + public List getStaticCalculators() { + return ImmutableList.copyOf(this.staticCalculators); + } + @Override public Class getSubjectClass() { return this.subjectClass; @@ -146,6 +158,15 @@ public abstract class AbstractContextManager implements ContextManager { ); } + @Override + public MetaContexts formMetaContexts(Contexts contexts) { + return new MetaContexts( + contexts, + this.plugin.getConfiguration().get(ConfigKeys.PREFIX_FORMATTING_OPTIONS), + this.plugin.getConfiguration().get(ConfigKeys.SUFFIX_FORMATTING_OPTIONS) + ); + } + @Override public void registerCalculator(ContextCalculator calculator) { // calculators registered first should have priority (and be checked last.) @@ -167,11 +188,6 @@ public abstract class AbstractContextManager implements ContextManager { this.lookupCache.invalidate(subject); } - @Override - public int getCalculatorsSize() { - return this.calculators.size(); - } - private final class Loader implements CacheLoader { @Override public Contexts load(@Nonnull T subject) { diff --git a/common/src/main/java/me/lucko/luckperms/common/contexts/ContextManager.java b/common/src/main/java/me/lucko/luckperms/common/contexts/ContextManager.java index 614817b8c..a58a8e83d 100644 --- a/common/src/main/java/me/lucko/luckperms/common/contexts/ContextManager.java +++ b/common/src/main/java/me/lucko/luckperms/common/contexts/ContextManager.java @@ -26,10 +26,12 @@ package me.lucko.luckperms.common.contexts; import me.lucko.luckperms.api.Contexts; +import me.lucko.luckperms.api.caching.MetaContexts; import me.lucko.luckperms.api.context.ContextCalculator; import me.lucko.luckperms.api.context.ImmutableContextSet; import me.lucko.luckperms.api.context.StaticContextCalculator; +import java.util.List; import java.util.Optional; /** @@ -103,6 +105,14 @@ public interface ContextManager { */ Contexts formContexts(ImmutableContextSet contextSet); + /** + * Forms a "default" {@link MetaContexts} instance from {@link Contexts}. + * + * @param contexts the contexts + * @return a contexts instance + */ + MetaContexts formMetaContexts(Contexts contexts); + /** * Registers a context calculator with the manager. * @@ -125,10 +135,17 @@ public interface ContextManager { void invalidateCache(T subject); /** - * Gets the number of calculators registered with the manager. + * Gets the calculators registered on the platform * - * @return the number of calculators registered + * @return the registered calculators */ - int getCalculatorsSize(); + List> getCalculators(); + + /** + * Gets the static calculators registered on the platform + * + * @return the registered static calculators + */ + List getStaticCalculators(); } diff --git a/common/src/main/java/me/lucko/luckperms/common/locale/CommandSpec.java b/common/src/main/java/me/lucko/luckperms/common/locale/CommandSpec.java index 63fdef76e..eeaa97645 100644 --- a/common/src/main/java/me/lucko/luckperms/common/locale/CommandSpec.java +++ b/common/src/main/java/me/lucko/luckperms/common/locale/CommandSpec.java @@ -49,6 +49,7 @@ public enum CommandSpec { SYNC("Sync changes with the storage", "/%s sync"), INFO("Print general plugin info", "/%s info"), + DEBUG("Produce debugging output", "/%s debug"), VERBOSE("Manage verbose permission checking", "/%s verbose [filter]", Arg.list( Arg.create("on|record|off|paste", true, "whether to enable/disable logging, or to paste the logged output"), diff --git a/common/src/main/java/me/lucko/luckperms/common/locale/Message.java b/common/src/main/java/me/lucko/luckperms/common/locale/Message.java index ac3872d6f..1dabb5e50 100644 --- a/common/src/main/java/me/lucko/luckperms/common/locale/Message.java +++ b/common/src/main/java/me/lucko/luckperms/common/locale/Message.java @@ -190,6 +190,9 @@ public enum Message { false ), + DEBUG_START("&bGenerating debugging output...", true), + DEBUG_URL("&aDebug data URL:", true), + CREATE_ERROR("&cThere was an error whilst creating &4{}&c.", true), DELETE_ERROR("&cThere was an error whilst deleting &4{}&c.", true), diff --git a/common/src/main/java/me/lucko/luckperms/common/messaging/InternalMessagingService.java b/common/src/main/java/me/lucko/luckperms/common/messaging/InternalMessagingService.java index fb27acb57..991e73e73 100644 --- a/common/src/main/java/me/lucko/luckperms/common/messaging/InternalMessagingService.java +++ b/common/src/main/java/me/lucko/luckperms/common/messaging/InternalMessagingService.java @@ -26,6 +26,8 @@ package me.lucko.luckperms.common.messaging; import me.lucko.luckperms.api.LogEntry; +import me.lucko.luckperms.api.messenger.Messenger; +import me.lucko.luckperms.api.messenger.MessengerProvider; import me.lucko.luckperms.common.buffers.BufferedRequest; import me.lucko.luckperms.common.model.User; @@ -38,6 +40,10 @@ public interface InternalMessagingService { */ String getName(); + Messenger getMessenger(); + + MessengerProvider getMessengerProvider(); + /** * Closes the messaging service */ diff --git a/common/src/main/java/me/lucko/luckperms/common/messaging/LuckPermsMessagingService.java b/common/src/main/java/me/lucko/luckperms/common/messaging/LuckPermsMessagingService.java index 666f764b2..b610daaa5 100644 --- a/common/src/main/java/me/lucko/luckperms/common/messaging/LuckPermsMessagingService.java +++ b/common/src/main/java/me/lucko/luckperms/common/messaging/LuckPermsMessagingService.java @@ -74,6 +74,16 @@ public class LuckPermsMessagingService implements InternalMessagingService, Inco return this.messengerProvider.getName(); } + @Override + public Messenger getMessenger() { + return this.messenger; + } + + @Override + public MessengerProvider getMessengerProvider() { + return this.messengerProvider; + } + @Override public void close() { this.messenger.close(); diff --git a/common/src/main/java/me/lucko/luckperms/common/plugin/LuckPermsPlugin.java b/common/src/main/java/me/lucko/luckperms/common/plugin/LuckPermsPlugin.java index 71d52865a..821291bbb 100644 --- a/common/src/main/java/me/lucko/luckperms/common/plugin/LuckPermsPlugin.java +++ b/common/src/main/java/me/lucko/luckperms/common/plugin/LuckPermsPlugin.java @@ -62,6 +62,8 @@ import java.util.Set; import java.util.UUID; import java.util.stream.Stream; +import javax.annotation.Nullable; + /** * Main internal interface for LuckPerms plugins, providing the base for * abstraction throughout the project. @@ -322,6 +324,7 @@ public interface LuckPermsPlugin { * @param user the user instance * @return a contexts object, or null if one couldn't be generated */ + @Nullable Contexts getContextForUser(User user); /** diff --git a/common/src/main/java/me/lucko/luckperms/common/storage/AbstractStorage.java b/common/src/main/java/me/lucko/luckperms/common/storage/AbstractStorage.java index 679ef4359..365eec552 100644 --- a/common/src/main/java/me/lucko/luckperms/common/storage/AbstractStorage.java +++ b/common/src/main/java/me/lucko/luckperms/common/storage/AbstractStorage.java @@ -72,6 +72,11 @@ public class AbstractStorage implements Storage { this.delegate = new ApiStorage(plugin, this); } + @Override + public AbstractDao getDao() { + return this.dao; + } + private CompletableFuture makeFuture(Callable supplier) { return CompletableFuture.supplyAsync(() -> { try { diff --git a/common/src/main/java/me/lucko/luckperms/common/storage/Storage.java b/common/src/main/java/me/lucko/luckperms/common/storage/Storage.java index 6f6e2037e..3527eaf22 100644 --- a/common/src/main/java/me/lucko/luckperms/common/storage/Storage.java +++ b/common/src/main/java/me/lucko/luckperms/common/storage/Storage.java @@ -35,6 +35,7 @@ import me.lucko.luckperms.common.bulkupdate.BulkUpdate; import me.lucko.luckperms.common.model.Group; import me.lucko.luckperms.common.model.Track; import me.lucko.luckperms.common.model.User; +import me.lucko.luckperms.common.storage.dao.AbstractDao; import java.util.List; import java.util.Map; @@ -50,6 +51,8 @@ public interface Storage { ApiStorage getDelegate(); + AbstractDao getDao(); + String getName(); Storage noBuffer(); diff --git a/common/src/main/java/me/lucko/luckperms/common/storage/wrappings/BufferedOutputStorage.java b/common/src/main/java/me/lucko/luckperms/common/storage/wrappings/BufferedOutputStorage.java index ed3b7f77d..f5c6c1757 100644 --- a/common/src/main/java/me/lucko/luckperms/common/storage/wrappings/BufferedOutputStorage.java +++ b/common/src/main/java/me/lucko/luckperms/common/storage/wrappings/BufferedOutputStorage.java @@ -37,6 +37,7 @@ import me.lucko.luckperms.common.model.Group; import me.lucko.luckperms.common.model.Track; import me.lucko.luckperms.common.model.User; import me.lucko.luckperms.common.storage.Storage; +import me.lucko.luckperms.common.storage.dao.AbstractDao; import java.util.List; import java.util.Map; @@ -106,6 +107,11 @@ public class BufferedOutputStorage implements Storage, Runnable { // delegate + @Override + public AbstractDao getDao() { + return this.delegate.getDao(); + } + @Override public CompletableFuture> getUniqueUsers() { return this.delegate.getUniqueUsers(); diff --git a/common/src/main/java/me/lucko/luckperms/common/storage/wrappings/PhasedStorage.java b/common/src/main/java/me/lucko/luckperms/common/storage/wrappings/PhasedStorage.java index 09141bbdf..198977be2 100644 --- a/common/src/main/java/me/lucko/luckperms/common/storage/wrappings/PhasedStorage.java +++ b/common/src/main/java/me/lucko/luckperms/common/storage/wrappings/PhasedStorage.java @@ -36,6 +36,7 @@ import me.lucko.luckperms.common.model.Group; import me.lucko.luckperms.common.model.Track; import me.lucko.luckperms.common.model.User; import me.lucko.luckperms.common.storage.Storage; +import me.lucko.luckperms.common.storage.dao.AbstractDao; import java.util.List; import java.util.Map; @@ -62,6 +63,11 @@ public class PhasedStorage implements Storage { this.delegate = delegate; } + @Override + public AbstractDao getDao() { + return this.delegate.getDao(); + } + @Override public ApiStorage getDelegate() { return this.delegate.getDelegate(); diff --git a/common/src/main/java/me/lucko/luckperms/common/utils/PasteUtils.java b/common/src/main/java/me/lucko/luckperms/common/utils/PasteUtils.java index c0fc17f39..ea1a424b8 100644 --- a/common/src/main/java/me/lucko/luckperms/common/utils/PasteUtils.java +++ b/common/src/main/java/me/lucko/luckperms/common/utils/PasteUtils.java @@ -37,7 +37,6 @@ import java.io.StringWriter; import java.net.HttpURLConnection; import java.net.URL; import java.nio.charset.StandardCharsets; -import java.util.List; import java.util.Map; /** @@ -54,7 +53,7 @@ public class PasteUtils { * @param files the files to include in the gist (file name --> content) * @return the url, or null */ - public static String paste(String desc, List> files) { + public static String paste(String desc, Iterable> files) { HttpURLConnection connection = null; try { connection = (HttpURLConnection) new URL(GIST_API).openConnection(); 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 bb437fc87..02ebb3979 100644 --- a/sponge/src/main/java/me/lucko/luckperms/sponge/LPSpongePlugin.java +++ b/sponge/src/main/java/me/lucko/luckperms/sponge/LPSpongePlugin.java @@ -121,6 +121,8 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ExecutionException; import java.util.stream.Stream; +import javax.annotation.Nullable; + /** * LuckPerms implementation for the Sponge API. */ @@ -422,6 +424,7 @@ public class LPSpongePlugin implements LuckPermsSpongePlugin { } } + @Nullable @Override public Contexts getContextForUser(User user) { Player player = getPlayer(user); diff --git a/sponge/src/main/java/me/lucko/luckperms/sponge/calculators/SpongeCalculatorFactory.java b/sponge/src/main/java/me/lucko/luckperms/sponge/calculators/SpongeCalculatorFactory.java index 0da4860b4..039b77bc6 100644 --- a/sponge/src/main/java/me/lucko/luckperms/sponge/calculators/SpongeCalculatorFactory.java +++ b/sponge/src/main/java/me/lucko/luckperms/sponge/calculators/SpongeCalculatorFactory.java @@ -42,8 +42,6 @@ import me.lucko.luckperms.sponge.processors.GroupDefaultsProcessor; import me.lucko.luckperms.sponge.processors.SpongeWildcardProcessor; import me.lucko.luckperms.sponge.processors.UserDefaultsProcessor; -import java.util.List; - public class SpongeCalculatorFactory extends AbstractCalculatorFactory { private final LPSpongePlugin plugin; @@ -79,15 +77,4 @@ public class SpongeCalculatorFactory extends AbstractCalculatorFactory { return registerCalculator(new PermissionCalculator(this.plugin, metadata, processors.build())); } - - @Override - public List getActiveProcessors() { - ImmutableList.Builder ret = ImmutableList.builder(); - ret.add("Map"); - if (this.plugin.getConfiguration().get(ConfigKeys.APPLY_SPONGE_IMPLICIT_WILDCARDS)) ret.add("SpongeWildcard"); - if (this.plugin.getConfiguration().get(ConfigKeys.APPLYING_REGEX)) ret.add("Regex"); - if (this.plugin.getConfiguration().get(ConfigKeys.APPLYING_WILDCARDS)) ret.add("Wildcard"); - if (this.plugin.getConfiguration().get(ConfigKeys.APPLY_SPONGE_DEFAULT_SUBJECTS)) ret.add("Defaults"); - return ret.build(); - } } diff --git a/sponge/src/main/java/me/lucko/luckperms/sponge/service/calculated/CalculatedSubjectData.java b/sponge/src/main/java/me/lucko/luckperms/sponge/service/calculated/CalculatedSubjectData.java index 2ecd829c2..ca99acb59 100644 --- a/sponge/src/main/java/me/lucko/luckperms/sponge/service/calculated/CalculatedSubjectData.java +++ b/sponge/src/main/java/me/lucko/luckperms/sponge/service/calculated/CalculatedSubjectData.java @@ -25,7 +25,6 @@ package me.lucko.luckperms.sponge.service.calculated; -import com.github.benmanes.caffeine.cache.CacheLoader; import com.github.benmanes.caffeine.cache.Caffeine; import com.github.benmanes.caffeine.cache.LoadingCache; import com.google.common.collect.ImmutableList; @@ -57,8 +56,6 @@ import java.util.concurrent.CompletableFuture; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.TimeUnit; -import javax.annotation.Nonnull; - /** * In-memory implementation of {@link LPSubjectData}. */ @@ -75,18 +72,15 @@ public class CalculatedSubjectData implements LPSubjectData { private final LoadingCache permissionCache = Caffeine.newBuilder() .expireAfterAccess(10, TimeUnit.MINUTES) - .build(new CacheLoader() { - @Override - public CalculatorHolder load(@Nonnull ImmutableContextSet contexts) { - ImmutableList.Builder processors = ImmutableList.builder(); - processors.add(new MapProcessor()); - processors.add(new SpongeWildcardProcessor()); + .build(contexts -> { + ImmutableList.Builder processors = ImmutableList.builder(); + processors.add(new MapProcessor()); + processors.add(new SpongeWildcardProcessor()); - CalculatorHolder holder = new CalculatorHolder(new PermissionCalculator(CalculatedSubjectData.this.service.getPlugin(), PermissionCalculatorMetadata.of(HolderType.GROUP, CalculatedSubjectData.this.calculatorDisplayName, contexts), processors.build())); - holder.setPermissions(flattenMap(getRelevantEntries(contexts, CalculatedSubjectData.this.permissions))); + CalculatorHolder holder = new CalculatorHolder(new PermissionCalculator(CalculatedSubjectData.this.service.getPlugin(), PermissionCalculatorMetadata.of(HolderType.GROUP, CalculatedSubjectData.this.calculatorDisplayName, contexts), processors.build())); + holder.setPermissions(flattenMap(getRelevantEntries(contexts, CalculatedSubjectData.this.permissions))); - return holder; - } + return holder; }); public CalculatedSubjectData(LPSubject parentSubject, LPPermissionService service, String calculatorDisplayName) {