mirror of
https://github.com/LuckPerms/LuckPerms.git
synced 2024-11-24 03:25:19 +01:00
This commit is contained in:
parent
da9977a30f
commit
31d435dc2b
@ -105,8 +105,6 @@ 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.
|
||||
*/
|
||||
@ -190,7 +188,7 @@ public class LPBukkitPlugin extends JavaPlugin implements LuckPermsPlugin {
|
||||
private void enable() {
|
||||
this.startTime = System.currentTimeMillis();
|
||||
sendStartupBanner(getConsoleSender());
|
||||
this.verboseHandler = new VerboseHandler(this.scheduler.asyncBukkit(), getVersion());
|
||||
this.verboseHandler = new VerboseHandler(this.scheduler.asyncBukkit());
|
||||
this.permissionVault = new PermissionVault(this.scheduler.asyncBukkit());
|
||||
this.logDispatcher = new LogDispatcher(this);
|
||||
|
||||
@ -539,14 +537,13 @@ public class LPBukkitPlugin extends JavaPlugin implements LuckPermsPlugin {
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Contexts getContextForUser(User user) {
|
||||
public Optional<Contexts> getContextForUser(User user) {
|
||||
Player player = getPlayer(user);
|
||||
if (player == null) {
|
||||
return null;
|
||||
return Optional.empty();
|
||||
}
|
||||
return this.contextManager.getApplicableContexts(player);
|
||||
return Optional.of(this.contextManager.getApplicableContexts(player));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -90,8 +90,6 @@ import java.util.UUID;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* LuckPerms implementation for the BungeeCord API.
|
||||
*/
|
||||
@ -141,7 +139,7 @@ public class LPBungeePlugin extends Plugin implements LuckPermsPlugin {
|
||||
public void onEnable() {
|
||||
this.startTime = System.currentTimeMillis();
|
||||
sendStartupBanner(getConsoleSender());
|
||||
this.verboseHandler = new VerboseHandler(this.scheduler.async(), getVersion());
|
||||
this.verboseHandler = new VerboseHandler(this.scheduler.async());
|
||||
this.permissionVault = new PermissionVault(this.scheduler.async());
|
||||
this.logDispatcher = new LogDispatcher(this);
|
||||
|
||||
@ -339,14 +337,13 @@ public class LPBungeePlugin extends Plugin implements LuckPermsPlugin {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Contexts getContextForUser(User user) {
|
||||
public Optional<Contexts> getContextForUser(User user) {
|
||||
ProxiedPlayer player = getPlayer(user);
|
||||
if (player == null) {
|
||||
return null;
|
||||
return Optional.empty();
|
||||
}
|
||||
return this.contextManager.getApplicableContexts(player);
|
||||
return Optional.of(this.contextManager.getApplicableContexts(player));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -74,14 +74,14 @@ public class ApiContextManager implements me.lucko.luckperms.api.context.Context
|
||||
@Override
|
||||
public Optional<ImmutableContextSet> lookupApplicableContext(@Nonnull User user) {
|
||||
Objects.requireNonNull(user, "user");
|
||||
return Optional.ofNullable(this.plugin.getContextForUser(ApiUser.cast(user))).map(c -> c.getContexts().makeImmutable());
|
||||
return this.plugin.getContextForUser(ApiUser.cast(user)).map(c -> c.getContexts().makeImmutable());
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public Optional<Contexts> lookupApplicableContexts(@Nonnull User user) {
|
||||
Objects.requireNonNull(user, "user");
|
||||
return Optional.ofNullable(this.plugin.getContextForUser(ApiUser.cast(user)));
|
||||
return this.plugin.getContextForUser(ApiUser.cast(user));
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
|
@ -25,7 +25,6 @@
|
||||
|
||||
package me.lucko.luckperms.common.commands.impl.generic.other;
|
||||
|
||||
import com.google.gson.GsonBuilder;
|
||||
import com.google.gson.JsonObject;
|
||||
|
||||
import me.lucko.luckperms.common.commands.ArgumentPermissions;
|
||||
@ -40,6 +39,7 @@ import me.lucko.luckperms.common.locale.Message;
|
||||
import me.lucko.luckperms.common.model.PermissionHolder;
|
||||
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
|
||||
import me.lucko.luckperms.common.utils.Predicates;
|
||||
import me.lucko.luckperms.common.utils.web.StandardPastebin;
|
||||
import me.lucko.luckperms.common.webeditor.WebEditor;
|
||||
|
||||
import net.kyori.text.Component;
|
||||
@ -69,14 +69,14 @@ public class HolderEditor<T extends PermissionHolder> extends SubCommand<T> {
|
||||
JsonObject payload = WebEditor.formPayload(Collections.singletonList(holder), sender, label, plugin);
|
||||
|
||||
// upload the payload data to gist
|
||||
String gistId = WebEditor.postToGist(new GsonBuilder().setPrettyPrinting().disableHtmlEscaping().create().toJson(payload));
|
||||
if (gistId == null) {
|
||||
String pasteId = StandardPastebin.BYTEBIN.postJson(payload).id();
|
||||
if (pasteId == null) {
|
||||
Message.EDITOR_UPLOAD_FAILURE.send(sender);
|
||||
return CommandResult.STATE_ERROR;
|
||||
}
|
||||
|
||||
// form a url for the editor
|
||||
String url = plugin.getConfiguration().get(ConfigKeys.WEB_EDITOR_URL_PATTERN) + "?" + gistId;
|
||||
String url = plugin.getConfiguration().get(ConfigKeys.WEB_EDITOR_URL_PATTERN) + "?" + pasteId;
|
||||
|
||||
Message.EDITOR_URL.send(sender);
|
||||
|
||||
|
@ -68,7 +68,7 @@ public class CheckCommand extends SingleCommand {
|
||||
return CommandResult.STATE_ERROR;
|
||||
}
|
||||
|
||||
Tristate tristate = user.getCachedData().getPermissionData(plugin.getContextForUser(user)).getPermissionValue(permission, CheckOrigin.INTERNAL);
|
||||
Tristate tristate = user.getCachedData().getPermissionData(plugin.getContextForUser(user).orElse(plugin.getContextManager().getStaticContexts())).getPermissionValue(permission, CheckOrigin.INTERNAL);
|
||||
Message.CHECK_RESULT.send(sender, user.getFriendlyName(), permission, CommandUtils.formatTristate(tristate));
|
||||
return CommandResult.SUCCESS;
|
||||
}
|
||||
|
@ -27,9 +27,6 @@ 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;
|
||||
@ -51,9 +48,11 @@ 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.Gist;
|
||||
import me.lucko.luckperms.common.utils.Predicates;
|
||||
import me.lucko.luckperms.common.utils.TextUtils;
|
||||
import me.lucko.luckperms.common.utils.gson.JArray;
|
||||
import me.lucko.luckperms.common.utils.gson.JObject;
|
||||
import me.lucko.luckperms.common.utils.web.Pastebin;
|
||||
import me.lucko.luckperms.common.utils.web.StandardPastebin;
|
||||
|
||||
import net.kyori.text.Component;
|
||||
import net.kyori.text.TextComponent;
|
||||
@ -66,7 +65,7 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class DebugCommand extends SingleCommand {
|
||||
@ -80,19 +79,26 @@ public class DebugCommand extends SingleCommand {
|
||||
public CommandResult execute(LuckPermsPlugin plugin, Sender sender, List<String> args, String label) {
|
||||
Message.DEBUG_START.send(sender);
|
||||
|
||||
Gist gist = Gist.builder()
|
||||
.description("LuckPerms Debug Output")
|
||||
.file("__DEBUG__.md", TextUtils.joinNewline("# Debug Output", "The debugging data can be found in the files below."))
|
||||
.file("platform.json", GSON.toJson(getPlatformData(plugin).toJson()))
|
||||
.file("storage.json", GSON.toJson(getStorageData(plugin).toJson()))
|
||||
.file("context.json", GSON.toJson(getContextData(plugin).toJson()))
|
||||
.file("players.json", GSON.toJson(getPlayersData(plugin).toJson()))
|
||||
.upload();
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("LuckPerms Debug Output\n\n\n");
|
||||
|
||||
BiConsumer<String, JObject> builder = (name, content) -> {
|
||||
sb.append("-- ").append(name).append(" --\n");
|
||||
sb.append(GSON.toJson(content.toJson()));
|
||||
sb.append("\n\n");
|
||||
};
|
||||
|
||||
builder.accept("platform.json", getPlatformData(plugin));
|
||||
builder.accept("storage.json", getStorageData(plugin));
|
||||
builder.accept("context.json", getContextData(plugin));
|
||||
builder.accept("players.json", getPlayersData(plugin));
|
||||
|
||||
Pastebin.Paste paste = StandardPastebin.HASTEBIN.postPlain(sb.toString());
|
||||
|
||||
Message.DEBUG_URL.send(sender);
|
||||
|
||||
Component message = TextComponent.builder(gist.getUrl()).color(TextColor.AQUA)
|
||||
.clickEvent(new ClickEvent(ClickEvent.Action.OPEN_URL, String.valueOf(gist.getUrl())))
|
||||
Component message = TextComponent.builder(paste.url()).color(TextColor.AQUA)
|
||||
.clickEvent(new ClickEvent(ClickEvent.Action.OPEN_URL, String.valueOf(paste.url())))
|
||||
.hoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, TextComponent.of("Click to open the debugging data.").color(TextColor.GRAY)))
|
||||
.build();
|
||||
|
||||
@ -190,7 +196,7 @@ public class DebugCommand extends SingleCommand {
|
||||
)
|
||||
.add("activeContext", () -> {
|
||||
JObject obj = new JObject();
|
||||
Contexts contexts = plugin.getContextForUser(user);
|
||||
Contexts contexts = plugin.getContextForUser(user).orElse(null);
|
||||
if (contexts != null) {
|
||||
MetaContexts metaContexts = plugin.getContextManager().formMetaContexts(contexts);
|
||||
obj.add("data", new JObject()
|
||||
@ -298,74 +304,4 @@ public class DebugCommand extends SingleCommand {
|
||||
});
|
||||
}
|
||||
|
||||
// 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<? extends JElement> 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<? extends JElement> value) {
|
||||
return add(value.get().toJson());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -25,7 +25,6 @@
|
||||
|
||||
package me.lucko.luckperms.common.commands.impl.misc;
|
||||
|
||||
import com.google.gson.GsonBuilder;
|
||||
import com.google.gson.JsonObject;
|
||||
|
||||
import me.lucko.luckperms.common.commands.ArgumentPermissions;
|
||||
@ -41,6 +40,7 @@ import me.lucko.luckperms.common.locale.Message;
|
||||
import me.lucko.luckperms.common.model.PermissionHolder;
|
||||
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
|
||||
import me.lucko.luckperms.common.utils.Predicates;
|
||||
import me.lucko.luckperms.common.utils.web.StandardPastebin;
|
||||
import me.lucko.luckperms.common.webeditor.WebEditor;
|
||||
|
||||
import net.kyori.text.Component;
|
||||
@ -95,14 +95,14 @@ public class EditorCommand extends SingleCommand {
|
||||
JsonObject payload = WebEditor.formPayload(holders, sender, label, plugin);
|
||||
|
||||
// upload the payload data to gist
|
||||
String gistId = WebEditor.postToGist(new GsonBuilder().setPrettyPrinting().disableHtmlEscaping().create().toJson(payload));
|
||||
if (gistId == null) {
|
||||
String pasteId = StandardPastebin.BYTEBIN.postJson(payload).id();
|
||||
if (pasteId == null) {
|
||||
Message.EDITOR_UPLOAD_FAILURE.send(sender);
|
||||
return CommandResult.STATE_ERROR;
|
||||
}
|
||||
|
||||
// form a url for the editor
|
||||
String url = plugin.getConfiguration().get(ConfigKeys.WEB_EDITOR_URL_PATTERN) + "?" + gistId;
|
||||
String url = plugin.getConfiguration().get(ConfigKeys.WEB_EDITOR_URL_PATTERN) + "?" + pasteId;
|
||||
|
||||
Message.EDITOR_URL.send(sender);
|
||||
|
||||
|
@ -30,14 +30,13 @@ 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.commands.utils.ArgumentUtils;
|
||||
import me.lucko.luckperms.common.config.ConfigKeys;
|
||||
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.treeview.TreeView;
|
||||
import me.lucko.luckperms.common.treeview.TreeViewBuilder;
|
||||
import me.lucko.luckperms.common.utils.Predicates;
|
||||
import me.lucko.luckperms.common.utils.Uuids;
|
||||
|
||||
@ -58,21 +57,17 @@ public class TreeCommand extends SingleCommand {
|
||||
@Override
|
||||
public CommandResult execute(LuckPermsPlugin plugin, Sender sender, List<String> args, String label) {
|
||||
String selection = ".";
|
||||
int maxLevel = 5;
|
||||
String player = null;
|
||||
|
||||
if (!args.isEmpty()) {
|
||||
selection = args.get(0);
|
||||
}
|
||||
if (args.size() > 1) {
|
||||
maxLevel = ArgumentUtils.handleIntOrElse(1, args, 5);
|
||||
}
|
||||
if (args.size() > 2) {
|
||||
player = args.get(2);
|
||||
player = args.get(1);
|
||||
}
|
||||
|
||||
User user;
|
||||
if (player != null) {
|
||||
User user;
|
||||
UUID u = Uuids.parseNullable(player);
|
||||
if (u != null) {
|
||||
user = plugin.getUserManager().getIfLoaded(u);
|
||||
@ -84,38 +79,20 @@ public class TreeCommand extends SingleCommand {
|
||||
Message.USER_NOT_ONLINE.send(sender, player);
|
||||
return CommandResult.STATE_ERROR;
|
||||
}
|
||||
|
||||
PermissionCache permissionData = user.getCachedData().getPermissionData(plugin.getContextForUser(user));
|
||||
TreeView view = TreeViewBuilder.newBuilder().rootPosition(selection).maxLevels(maxLevel).build(plugin.getPermissionVault());
|
||||
|
||||
if (!view.hasData()) {
|
||||
Message.TREE_EMPTY.send(sender);
|
||||
return CommandResult.FAILURE;
|
||||
}
|
||||
|
||||
Message.TREE_UPLOAD_START.send(sender);
|
||||
String url = view.uploadPasteData(plugin.getVersion(), user.getFriendlyName(), permissionData);
|
||||
|
||||
Message.TREE_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 tree view.").color(TextColor.GRAY)))
|
||||
.build();
|
||||
|
||||
sender.sendMessage(message);
|
||||
return CommandResult.SUCCESS;
|
||||
} else {
|
||||
user = null;
|
||||
}
|
||||
|
||||
TreeView view = TreeViewBuilder.newBuilder().rootPosition(selection).maxLevels(maxLevel).build(plugin.getPermissionVault());
|
||||
|
||||
TreeView view = new TreeView(plugin.getPermissionVault(), selection);
|
||||
if (!view.hasData()) {
|
||||
Message.TREE_EMPTY.send(sender);
|
||||
return CommandResult.FAILURE;
|
||||
}
|
||||
|
||||
Message.TREE_UPLOAD_START.send(sender);
|
||||
String url = view.uploadPasteData(plugin.getVersion());
|
||||
PermissionCache permissionData = user == null ? null : user.getCachedData().getPermissionData(plugin.getContextForUser(user).orElse(plugin.getContextManager().getStaticContexts()));
|
||||
String id = view.uploadPasteData(sender, user, permissionData);
|
||||
String url = plugin.getConfiguration().get(ConfigKeys.TREE_VIEWER_URL_PATTERN) + "?" + id;
|
||||
|
||||
Message.TREE_URL.send(sender);
|
||||
|
||||
|
@ -31,6 +31,7 @@ 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.config.ConfigKeys;
|
||||
import me.lucko.luckperms.common.locale.CommandSpec;
|
||||
import me.lucko.luckperms.common.locale.LocaleManager;
|
||||
import me.lucko.luckperms.common.locale.Message;
|
||||
@ -64,8 +65,6 @@ public class VerboseCommand extends SingleCommand {
|
||||
return CommandResult.INVALID_ARGS;
|
||||
}
|
||||
|
||||
boolean noTraces = args.remove("--notrace") || args.remove("--notraces") || args.remove("--slim") || args.remove("-s");
|
||||
boolean attachRaw = args.remove("--raw");
|
||||
String mode = args.get(0).toLowerCase();
|
||||
|
||||
if (mode.equals("on") || mode.equals("true") || mode.equals("record")) {
|
||||
@ -114,7 +113,8 @@ public class VerboseCommand extends SingleCommand {
|
||||
Message.VERBOSE_OFF.send(sender);
|
||||
} else {
|
||||
Message.VERBOSE_UPLOAD_START.send(sender);
|
||||
String url = listener.uploadPasteData(!noTraces, attachRaw);
|
||||
String id = listener.uploadPasteData();
|
||||
String url = plugin.getConfiguration().get(ConfigKeys.VERBOSE_VIEWER_URL_PATTERN) + "?" + id;
|
||||
|
||||
Message.VERBOSE_RESULTS_URL.send(sender);
|
||||
|
||||
|
@ -100,7 +100,7 @@ public class UserInfo extends SubCommand<User> {
|
||||
String prefix = "&bNone";
|
||||
String suffix = "&bNone";
|
||||
String meta = "&bNone";
|
||||
Contexts contexts = plugin.getContextForUser(user);
|
||||
Contexts contexts = plugin.getContextForUser(user).orElse(null);
|
||||
if (contexts != null) {
|
||||
ContextSet contextSet = contexts.getContexts();
|
||||
if (!contextSet.isEmpty()) {
|
||||
|
@ -37,7 +37,7 @@ import me.lucko.luckperms.common.config.keys.IntegerKey;
|
||||
import me.lucko.luckperms.common.config.keys.LowercaseStringKey;
|
||||
import me.lucko.luckperms.common.config.keys.MapKey;
|
||||
import me.lucko.luckperms.common.config.keys.StringKey;
|
||||
import me.lucko.luckperms.common.inheritance.graph.TraversalAlgorithm;
|
||||
import me.lucko.luckperms.common.graph.TraversalAlgorithm;
|
||||
import me.lucko.luckperms.common.metastacking.SimpleMetaStackDefinition;
|
||||
import me.lucko.luckperms.common.metastacking.StandardStackElements;
|
||||
import me.lucko.luckperms.common.model.TemporaryModifier;
|
||||
@ -476,7 +476,17 @@ public class ConfigKeys {
|
||||
/**
|
||||
* The URL of the web editor
|
||||
*/
|
||||
public static final ConfigKey<String> WEB_EDITOR_URL_PATTERN = StringKey.of("web-editor-url", "https://lpedit.lucko.me/");
|
||||
public static final ConfigKey<String> WEB_EDITOR_URL_PATTERN = StringKey.of("web-editor-url", "https://luckperms.github.io/editor/");
|
||||
|
||||
/**
|
||||
* The URL of the verbose viewer
|
||||
*/
|
||||
public static final ConfigKey<String> VERBOSE_VIEWER_URL_PATTERN = StringKey.of("verbose-viewer-url", "https://luckperms.github.io/verbose/");
|
||||
|
||||
/**
|
||||
* The URL of the tree viewer
|
||||
*/
|
||||
public static final ConfigKey<String> TREE_VIEWER_URL_PATTERN = StringKey.of("tree-viewer-url", "https://luckperms.github.io/treeview/");
|
||||
|
||||
private static Map<String, ConfigKey<?>> KEYS = null;
|
||||
|
||||
|
@ -23,7 +23,7 @@
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package me.lucko.luckperms.common.inheritance.graph;
|
||||
package me.lucko.luckperms.common.graph;
|
||||
|
||||
/**
|
||||
* A minimal functional interface for graph-structured data.
|
@ -39,7 +39,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package me.lucko.luckperms.common.inheritance.graph;
|
||||
package me.lucko.luckperms.common.graph;
|
||||
|
||||
import com.google.common.collect.AbstractIterator;
|
||||
|
@ -23,7 +23,7 @@
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package me.lucko.luckperms.common.inheritance.graph;
|
||||
package me.lucko.luckperms.common.graph;
|
||||
|
||||
public enum TraversalAlgorithm {
|
||||
|
@ -27,9 +27,9 @@ package me.lucko.luckperms.common.inheritance;
|
||||
|
||||
import me.lucko.luckperms.api.Contexts;
|
||||
import me.lucko.luckperms.api.Node;
|
||||
import me.lucko.luckperms.common.inheritance.graph.Graph;
|
||||
import me.lucko.luckperms.common.inheritance.graph.GraphTraversers;
|
||||
import me.lucko.luckperms.common.inheritance.graph.TraversalAlgorithm;
|
||||
import me.lucko.luckperms.common.graph.Graph;
|
||||
import me.lucko.luckperms.common.graph.GraphTraversers;
|
||||
import me.lucko.luckperms.common.graph.TraversalAlgorithm;
|
||||
import me.lucko.luckperms.common.model.Group;
|
||||
import me.lucko.luckperms.common.model.PermissionHolder;
|
||||
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
|
||||
|
@ -58,14 +58,12 @@ public enum CommandSpec {
|
||||
VERBOSE("Manage verbose permission checking", "/%s verbose <true|false> [filter]",
|
||||
Arg.list(
|
||||
Arg.create("on|record|off|paste", true, "whether to enable/disable logging, or to paste the logged output"),
|
||||
Arg.create("filter", false, "the filter to match entries against"),
|
||||
Arg.create("--slim", false, "add \"--slim\" to exclude trace data from the pasted output")
|
||||
Arg.create("filter", false, "the filter to match entries against")
|
||||
)
|
||||
),
|
||||
TREE("Generate a tree view of permissions", "/%s tree [selection] [max level] [player]",
|
||||
TREE("Generate a tree view of permissions", "/%s tree [scope] [player]",
|
||||
Arg.list(
|
||||
Arg.create("selection", false, "the root of the tree. specify \".\" to include all permissions"),
|
||||
Arg.create("max level", false, "how many branch levels should be returned"),
|
||||
Arg.create("scope", false, "the root of the tree. specify \".\" to include all permissions"),
|
||||
Arg.create("player", false, "the name of an online player to check against")
|
||||
)
|
||||
),
|
||||
|
@ -63,8 +63,6 @@ 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.
|
||||
@ -332,8 +330,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);
|
||||
Optional<Contexts> getContextForUser(User user);
|
||||
|
||||
/**
|
||||
* Gets the number of users online on the platform
|
||||
|
@ -43,7 +43,7 @@ public class AllParentsByWeightHolder extends CachedPrimaryGroupHolder {
|
||||
|
||||
@Override
|
||||
protected String calculateValue() {
|
||||
Contexts contexts = this.user.getPlugin().getContextForUser(this.user);
|
||||
Contexts contexts = this.user.getPlugin().getContextForUser(this.user).orElse(null);
|
||||
if (contexts == null) {
|
||||
contexts = this.user.getPlugin().getContextManager().getStaticContexts();
|
||||
}
|
||||
|
@ -40,7 +40,7 @@ public class ParentsByWeightHolder extends CachedPrimaryGroupHolder {
|
||||
|
||||
@Override
|
||||
protected String calculateValue() {
|
||||
Contexts contexts = this.user.getPlugin().getContextForUser(this.user);
|
||||
Contexts contexts = this.user.getPlugin().getContextForUser(this.user).orElse(null);
|
||||
if (contexts == null) {
|
||||
contexts = this.user.getPlugin().getContextManager().getStaticContexts();
|
||||
}
|
||||
|
@ -27,6 +27,7 @@ package me.lucko.luckperms.common.treeview;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.Maps;
|
||||
import com.google.gson.JsonObject;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
@ -101,6 +102,19 @@ public class ImmutableTreeNode implements Comparable<ImmutableTreeNode> {
|
||||
return results;
|
||||
}
|
||||
|
||||
public JsonObject toJson(String prefix) {
|
||||
if (this.children == null) {
|
||||
return new JsonObject();
|
||||
}
|
||||
|
||||
JsonObject object = new JsonObject();
|
||||
for (Map.Entry<String, ImmutableTreeNode> entry : this.children.entrySet()) {
|
||||
String name = prefix + entry.getKey();
|
||||
object.add(name, entry.getValue().toJson(name + "."));
|
||||
}
|
||||
return object;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(@Nonnull ImmutableTreeNode o) {
|
||||
return (this.children != null) == o.getChildren().isPresent() ? 0 : (this.children != null ? 1 : -1);
|
||||
|
@ -26,22 +26,19 @@
|
||||
package me.lucko.luckperms.common.treeview;
|
||||
|
||||
import com.google.common.base.Splitter;
|
||||
import com.google.common.base.Strings;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.Maps;
|
||||
import com.google.gson.JsonObject;
|
||||
|
||||
import me.lucko.luckperms.api.Tristate;
|
||||
import me.lucko.luckperms.common.caching.type.PermissionCache;
|
||||
import me.lucko.luckperms.common.utils.Gist;
|
||||
import me.lucko.luckperms.common.verbose.CheckOrigin;
|
||||
import me.lucko.luckperms.common.commands.sender.Sender;
|
||||
import me.lucko.luckperms.common.model.User;
|
||||
import me.lucko.luckperms.common.utils.gson.JObject;
|
||||
import me.lucko.luckperms.common.utils.web.StandardPastebin;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* A readable view of a branch of {@link TreeNode}s.
|
||||
@ -52,15 +49,16 @@ public class TreeView {
|
||||
// the root of the tree
|
||||
private final String rootPosition;
|
||||
|
||||
// how many levels / branches to display
|
||||
private final int maxLevel;
|
||||
|
||||
// the actual tree object
|
||||
private final ImmutableTreeNode view;
|
||||
|
||||
public TreeView(PermissionVault source, String rootPosition, int maxLevel) {
|
||||
public TreeView(PermissionVault source, String rootPosition) {
|
||||
if (rootPosition.equals("") || rootPosition.equals("*")) {
|
||||
rootPosition = ".";
|
||||
} else if (!rootPosition.equals(".") && rootPosition.endsWith(".")) {
|
||||
rootPosition = rootPosition.substring(0, rootPosition.length() - 1);
|
||||
}
|
||||
this.rootPosition = rootPosition;
|
||||
this.maxLevel = maxLevel;
|
||||
|
||||
Optional<TreeNode> root = findRoot(rootPosition, source);
|
||||
this.view = root.map(TreeNode::makeImmutableCopy).orElse(null);
|
||||
@ -115,152 +113,61 @@ public class TreeView {
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the view to a readable list
|
||||
* Uploads the data contained in this TreeView and returns the id.
|
||||
*
|
||||
* <p>The list contains KV pairs, where the key is the tree padding/structure,
|
||||
* and the value is the actual permission.</p>
|
||||
*
|
||||
* @return a list of the nodes in this view
|
||||
* @param sender the sender
|
||||
* @param user the reference user, or null
|
||||
* @param checker the permission data instance to check against, or null
|
||||
* @return the id, or null
|
||||
*/
|
||||
private List<Map.Entry<String, String>> asTreeList() {
|
||||
public String uploadPasteData(Sender sender, User user, PermissionCache checker) {
|
||||
// only paste if there is actually data here
|
||||
if (!hasData()) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
|
||||
// work out the prefix to apply
|
||||
// since the view is relative, we need to prepend this to all permissions
|
||||
String prefix = this.rootPosition.equals(".") ? "" : (this.rootPosition + ".");
|
||||
JsonObject jsonTree = this.view.toJson(prefix);
|
||||
|
||||
JObject metadata = new JObject()
|
||||
.add("time", DATE_FORMAT.format(new Date(System.currentTimeMillis())))
|
||||
.add("root", this.rootPosition)
|
||||
.add("uploader", new JObject()
|
||||
.add("name", sender.getNameWithLocation())
|
||||
.add("uuid", sender.getUuid().toString())
|
||||
);
|
||||
|
||||
List<Map.Entry<String, String>> ret = new ArrayList<>();
|
||||
JObject checks;
|
||||
if (user != null && checker != null) {
|
||||
metadata.add("referenceUser", new JObject()
|
||||
.add("name", user.getFriendlyName())
|
||||
.add("uuid", user.getUuid().toString())
|
||||
);
|
||||
|
||||
// iterate the node endings in the view
|
||||
for (Map.Entry<Integer, String> s : this.view.getNodeEndings()) {
|
||||
// don't include the node if it exceeds the max level
|
||||
if (s.getKey() >= this.maxLevel) {
|
||||
continue;
|
||||
checks = new JObject();
|
||||
for (Map.Entry<Integer, String> node : this.view.getNodeEndings()) {
|
||||
String permission = prefix + node.getValue();
|
||||
checks.add(permission, checker.getPermissionValue(permission).name().toLowerCase());
|
||||
}
|
||||
|
||||
// generate the tree padding characters from the node level
|
||||
String treeStructure = Strings.repeat("│ ", s.getKey()) + "├── ";
|
||||
// generate the permission, using the prefix and the node
|
||||
String permission = prefix + s.getValue();
|
||||
|
||||
ret.add(Maps.immutableEntry(treeStructure, permission));
|
||||
} else {
|
||||
checks = null;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
JsonObject payload = new JObject()
|
||||
.add("metadata", metadata)
|
||||
.add("data", new JObject()
|
||||
.add("tree", jsonTree)
|
||||
.consume(obj -> {
|
||||
if (checks != null) {
|
||||
obj.add("checkResults", checks);
|
||||
}
|
||||
})
|
||||
)
|
||||
.toJson();
|
||||
|
||||
/**
|
||||
* Uploads the data contained in this TreeView to a paste, and returns the URL.
|
||||
*
|
||||
* @param version the plugin version string
|
||||
* @return the url, or null
|
||||
*/
|
||||
public String uploadPasteData(String version) {
|
||||
// only paste if there is actually data here
|
||||
if (!hasData()) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
|
||||
// get the data contained in the view in a list form
|
||||
// for each entry, the key is the padding tree characters
|
||||
// and the value is the actual permission string
|
||||
List<Map.Entry<String, String>> ret = asTreeList();
|
||||
|
||||
// build the header of the paste
|
||||
ImmutableList.Builder<String> builder = getPasteHeader(version, "none", ret.size());
|
||||
|
||||
// add the tree data
|
||||
builder.add("```");
|
||||
for (Map.Entry<String, String> e : ret) {
|
||||
builder.add(e.getKey() + e.getValue());
|
||||
}
|
||||
builder.add("```");
|
||||
|
||||
// clear the initial data map
|
||||
ret.clear();
|
||||
|
||||
// upload the return the data
|
||||
Gist gist = Gist.builder()
|
||||
.description("LuckPerms Permission Tree")
|
||||
.file("luckperms-tree.md", builder.build().stream().collect(Collectors.joining("\n")))
|
||||
.upload();
|
||||
|
||||
return gist.getUrl();
|
||||
}
|
||||
|
||||
/**
|
||||
* Uploads the data contained in this TreeView to a paste, and returns the URL.
|
||||
*
|
||||
* <p>Unlike {@link #uploadPasteData(String)}, this method will check each permission
|
||||
* against a corresponding user, and colorize the output depending on the check results.</p>
|
||||
*
|
||||
* @param version the plugin version string
|
||||
* @param username the username of the reference user
|
||||
* @param checker the permission data instance to check against
|
||||
* @return the url, or null
|
||||
*/
|
||||
public String uploadPasteData(String version, String username, PermissionCache checker) {
|
||||
// only paste if there is actually data here
|
||||
if (!hasData()) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
|
||||
// get the data contained in the view in a list form
|
||||
// for each entry, the key is the padding tree characters
|
||||
// and the value is the actual permission string
|
||||
List<Map.Entry<String, String>> ret = asTreeList();
|
||||
|
||||
// build the header of the paste
|
||||
ImmutableList.Builder<String> builder = getPasteHeader(version, username, ret.size());
|
||||
|
||||
// add the tree data
|
||||
builder.add("```diff");
|
||||
for (Map.Entry<String, String> e : ret) {
|
||||
|
||||
// lookup a permission value for the node
|
||||
Tristate tristate = checker.getPermissionValue(e.getValue(), CheckOrigin.INTERNAL);
|
||||
|
||||
// append the data to the paste
|
||||
builder.add(getTristateDiffPrefix(tristate) + e.getKey() + e.getValue());
|
||||
}
|
||||
builder.add("```");
|
||||
|
||||
// clear the initial data map
|
||||
ret.clear();
|
||||
|
||||
// upload the return the data
|
||||
Gist gist = Gist.builder()
|
||||
.description("LuckPerms Permission Tree")
|
||||
.file("luckperms-tree.md", builder.build().stream().collect(Collectors.joining("\n")))
|
||||
.upload();
|
||||
|
||||
return gist.getUrl();
|
||||
}
|
||||
|
||||
private static String getTristateDiffPrefix(Tristate t) {
|
||||
switch (t) {
|
||||
case TRUE:
|
||||
return "+ ";
|
||||
case FALSE:
|
||||
return "- ";
|
||||
default:
|
||||
return "# ";
|
||||
}
|
||||
}
|
||||
|
||||
private ImmutableList.Builder<String> getPasteHeader(String version, String referenceUser, int size) {
|
||||
String date = DATE_FORMAT.format(new Date(System.currentTimeMillis()));
|
||||
String selection = this.rootPosition.equals(".") ? "any" : "`" + this.rootPosition + "`";
|
||||
|
||||
return ImmutableList.<String>builder()
|
||||
.add("## Permission Tree")
|
||||
.add("#### This file was automatically generated by [LuckPerms](https://github.com/lucko/LuckPerms) v" + version)
|
||||
.add("")
|
||||
.add("### Metadata")
|
||||
.add("| Selection | Max Recursion | Reference User | Size | Produced at |")
|
||||
.add("|-----------|---------------|----------------|------|-------------|")
|
||||
.add("| " + selection + " | " + this.maxLevel + " | " + referenceUser + " | **" + size + "** | " + date + " |")
|
||||
.add("")
|
||||
.add("### Output");
|
||||
return StandardPastebin.BYTEBIN.postJson(payload).id();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,189 +0,0 @@
|
||||
/*
|
||||
* This file is part of LuckPerms, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) lucko (Luck) <luck@lucko.me>
|
||||
* 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.utils;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.stream.JsonWriter;
|
||||
|
||||
import okhttp3.FormBody;
|
||||
import okhttp3.MediaType;
|
||||
import okhttp3.Request;
|
||||
import okhttp3.RequestBody;
|
||||
import okhttp3.Response;
|
||||
import okhttp3.ResponseBody;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Represents a posted GitHub Gist
|
||||
*/
|
||||
public class Gist {
|
||||
private static final Gson GSON = new Gson();
|
||||
|
||||
private static final MediaType JSON_TYPE = MediaType.parse("application/json; charset=utf-8");
|
||||
|
||||
private static final String GIST_API_URL = "https://api.github.com/gists";
|
||||
private static final String GIT_IO_URL = "https://git.io";
|
||||
|
||||
public static Builder builder() {
|
||||
return new Builder();
|
||||
}
|
||||
|
||||
private final String url;
|
||||
private final String id;
|
||||
|
||||
private Gist(String url, String id) {
|
||||
this.url = url;
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getUrl() {
|
||||
return this.url;
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return this.id;
|
||||
}
|
||||
|
||||
private static final class GistFile {
|
||||
private final String name;
|
||||
private final String content;
|
||||
|
||||
private GistFile(String name, String content) {
|
||||
this.name = name;
|
||||
this.content = content;
|
||||
}
|
||||
}
|
||||
|
||||
public static final class Builder {
|
||||
private final List<GistFile> files = new ArrayList<>();
|
||||
private boolean shorten = true;
|
||||
private String description = "LuckPerms Gist";
|
||||
|
||||
private Builder() {
|
||||
|
||||
}
|
||||
|
||||
public Builder file(String name, String content) {
|
||||
this.files.add(new GistFile(name, content));
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder shorten(boolean shorten) {
|
||||
this.shorten = shorten;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder description(String description) {
|
||||
this.description = description;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Gist upload() {
|
||||
return Gist.upload(ImmutableList.copyOf(this.files), this.shorten, this.description);
|
||||
}
|
||||
}
|
||||
|
||||
private static Gist upload(List<GistFile> files, boolean shorten, String description) {
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
try (JsonWriter jw = new JsonWriter(new OutputStreamWriter(out, StandardCharsets.UTF_8))) {
|
||||
jw.beginObject();
|
||||
jw.name("description").value(description);
|
||||
jw.name("public").value(false);
|
||||
jw.name("files").beginObject();
|
||||
for (GistFile file : files) {
|
||||
jw.name(file.name).beginObject().name("content").value(file.content).endObject();
|
||||
}
|
||||
jw.endObject().endObject();
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
RequestBody body = RequestBody.create(JSON_TYPE, out.toByteArray());
|
||||
Request request = new Request.Builder()
|
||||
.url(GIST_API_URL)
|
||||
.post(body)
|
||||
.build();
|
||||
|
||||
try (Response response = HttpClient.makeCall(request)) {
|
||||
try (ResponseBody responseBody = response.body()) {
|
||||
if (responseBody == null) {
|
||||
throw new RuntimeException("No response");
|
||||
}
|
||||
|
||||
String id;
|
||||
String pasteUrl;
|
||||
try (InputStream inputStream = responseBody.byteStream()) {
|
||||
try (BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8))) {
|
||||
JsonObject object = GSON.fromJson(reader, JsonObject.class);
|
||||
id = object.get("id").getAsString();
|
||||
pasteUrl = object.get("html_url").getAsString();
|
||||
}
|
||||
}
|
||||
|
||||
if (shorten) {
|
||||
pasteUrl = shortenUrl(pasteUrl);
|
||||
}
|
||||
|
||||
return new Gist(pasteUrl, id);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private static String shortenUrl(String pasteUrl) {
|
||||
RequestBody requestBody = new FormBody.Builder()
|
||||
.add("url", pasteUrl)
|
||||
.build();
|
||||
|
||||
Request request = new Request.Builder()
|
||||
.url(GIT_IO_URL)
|
||||
.post(requestBody)
|
||||
.build();
|
||||
|
||||
try (Response response = HttpClient.makeCall(request)) {
|
||||
String location = response.header("Location");
|
||||
if (location == null) {
|
||||
throw new RuntimeException("No location header");
|
||||
}
|
||||
return location;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return pasteUrl;
|
||||
}
|
||||
}
|
@ -0,0 +1,110 @@
|
||||
/*
|
||||
* This file is part of LuckPerms, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) lucko (Luck) <luck@lucko.me>
|
||||
* 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.utils;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
public final class StackTracePrinter {
|
||||
public static Consumer<StackTraceElement> elementToString(Consumer<String> consumer) {
|
||||
return e -> consumer.accept(e.getClassName() + "." + e.getMethodName() + (e.getLineNumber() >= 0 ? ":" + e.getLineNumber() : ""));
|
||||
}
|
||||
|
||||
public static Builder builder() {
|
||||
return new Builder();
|
||||
}
|
||||
|
||||
private final int truncateLength;
|
||||
private final Predicate<StackTraceElement> shouldPrintPredicate;
|
||||
|
||||
private StackTracePrinter(int truncateLength, Predicate<StackTraceElement> shouldPrintPredicate) {
|
||||
this.truncateLength = truncateLength;
|
||||
this.shouldPrintPredicate = shouldPrintPredicate;
|
||||
}
|
||||
|
||||
public int process(StackTraceElement[] stackTrace, Consumer<StackTraceElement> consumer) {
|
||||
// how many lines have been printed
|
||||
int count = 0;
|
||||
// if we're printing elements yet
|
||||
boolean printing = false;
|
||||
|
||||
for (StackTraceElement e : stackTrace) {
|
||||
// start printing when the predicate passes
|
||||
if (!printing && this.shouldPrintPredicate.test(e)) {
|
||||
printing = true;
|
||||
}
|
||||
|
||||
if (!printing) continue;
|
||||
if (count >= this.truncateLength) break;
|
||||
|
||||
consumer.accept(e);
|
||||
count++;
|
||||
}
|
||||
if (stackTrace.length > this.truncateLength) {
|
||||
return stackTrace.length - this.truncateLength;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public Builder toBuilder() {
|
||||
Builder builder = new Builder();
|
||||
builder.truncateLength = this.truncateLength;
|
||||
builder.shouldPrintPredicate = this.shouldPrintPredicate;
|
||||
return builder;
|
||||
}
|
||||
|
||||
public static final class Builder {
|
||||
private int truncateLength = Integer.MAX_VALUE;
|
||||
private Predicate<StackTraceElement> shouldPrintPredicate = Predicates.alwaysTrue();
|
||||
|
||||
private Builder() {
|
||||
|
||||
}
|
||||
|
||||
public Builder truncateLength(int truncateLength) {
|
||||
this.truncateLength = truncateLength;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder ignoreElementsMatching(Predicate<? super StackTraceElement> predicate) {
|
||||
this.shouldPrintPredicate = this.shouldPrintPredicate.and(predicate.negate());
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder ignoreClass(String className) {
|
||||
return ignoreElementsMatching(e -> e.getClassName().equals(className));
|
||||
}
|
||||
|
||||
public Builder ignoreClassStartingWith(String className) {
|
||||
return ignoreElementsMatching(e -> e.getClassName().startsWith(className));
|
||||
}
|
||||
|
||||
public StackTracePrinter build() {
|
||||
return new StackTracePrinter(this.truncateLength, this.shouldPrintPredicate);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -23,45 +23,42 @@
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package me.lucko.luckperms.common.treeview;
|
||||
package me.lucko.luckperms.common.utils.gson;
|
||||
|
||||
/**
|
||||
* Builds a {@link TreeView}.
|
||||
*/
|
||||
public class TreeViewBuilder {
|
||||
public static TreeViewBuilder newBuilder() {
|
||||
return new TreeViewBuilder();
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonElement;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public class JArray implements JElement {
|
||||
private final JsonArray array = new JsonArray();
|
||||
|
||||
@Override
|
||||
public JsonArray toJson() {
|
||||
return this.array;
|
||||
}
|
||||
|
||||
private String rootPosition;
|
||||
private int maxLevels;
|
||||
|
||||
private TreeViewBuilder() {
|
||||
this.rootPosition = ".";
|
||||
this.maxLevels = 5;
|
||||
}
|
||||
|
||||
public TreeViewBuilder rootPosition(String rootPosition) {
|
||||
this.rootPosition = rootPosition;
|
||||
public JArray add(String value) {
|
||||
this.array.add(value);
|
||||
return this;
|
||||
}
|
||||
|
||||
public TreeViewBuilder maxLevels(int maxLevels) {
|
||||
this.maxLevels = maxLevels;
|
||||
public JArray add(JsonElement value) {
|
||||
this.array.add(value);
|
||||
return this;
|
||||
}
|
||||
|
||||
public TreeView build(PermissionVault source) {
|
||||
if (this.maxLevels < 1) {
|
||||
this.maxLevels = 1;
|
||||
}
|
||||
if (this.rootPosition.equals("") || this.rootPosition.equals("*")) {
|
||||
this.rootPosition = ".";
|
||||
} else if (!this.rootPosition.equals(".") && this.rootPosition.endsWith(".")) {
|
||||
this.rootPosition = this.rootPosition.substring(0, this.rootPosition.length() - 1);
|
||||
}
|
||||
|
||||
return new TreeView(source, this.rootPosition, this.maxLevels);
|
||||
public JArray add(JElement value) {
|
||||
return add(value.toJson());
|
||||
}
|
||||
|
||||
}
|
||||
public JArray add(Supplier<? extends JElement> value) {
|
||||
return add(value.get().toJson());
|
||||
}
|
||||
|
||||
public JArray consume(Consumer<? super JArray> consumer) {
|
||||
consumer.accept(this);
|
||||
return this;
|
||||
}
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
/*
|
||||
* This file is part of LuckPerms, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) lucko (Luck) <luck@lucko.me>
|
||||
* 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.utils.gson;
|
||||
|
||||
import com.google.gson.JsonElement;
|
||||
|
||||
/**
|
||||
* Stupidly simple fluent gson wrappers
|
||||
*/
|
||||
public interface JElement {
|
||||
|
||||
JsonElement toJson();
|
||||
|
||||
}
|
@ -0,0 +1,74 @@
|
||||
/*
|
||||
* This file is part of LuckPerms, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) lucko (Luck) <luck@lucko.me>
|
||||
* 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.utils.gson;
|
||||
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public class JObject implements JElement {
|
||||
private final JsonObject object = new JsonObject();
|
||||
|
||||
@Override
|
||||
public JsonObject toJson() {
|
||||
return this.object;
|
||||
}
|
||||
|
||||
public JObject add(String key, String value) {
|
||||
this.object.addProperty(key, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
public JObject add(String key, Number value) {
|
||||
this.object.addProperty(key, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
public JObject add(String key, Boolean value) {
|
||||
this.object.addProperty(key, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
public JObject add(String key, JsonElement value) {
|
||||
this.object.add(key, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
public JObject add(String key, JElement value) {
|
||||
return add(key, value.toJson());
|
||||
}
|
||||
|
||||
public JObject add(String key, Supplier<? extends JElement> value) {
|
||||
return add(key, value.get().toJson());
|
||||
}
|
||||
|
||||
public JObject consume(Consumer<? super JObject> consumer) {
|
||||
consumer.accept(this);
|
||||
return this;
|
||||
}
|
||||
}
|
@ -23,7 +23,7 @@
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package me.lucko.luckperms.common.utils;
|
||||
package me.lucko.luckperms.common.utils.web;
|
||||
|
||||
import okhttp3.Interceptor;
|
||||
import okhttp3.OkHttpClient;
|
@ -0,0 +1,43 @@
|
||||
/*
|
||||
* This file is part of LuckPerms, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) lucko (Luck) <luck@lucko.me>
|
||||
* 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.utils.web;
|
||||
|
||||
import com.google.gson.JsonElement;
|
||||
|
||||
public interface Pastebin {
|
||||
|
||||
Paste postJson(JsonElement element);
|
||||
|
||||
Paste postPlain(String content);
|
||||
|
||||
String getRawUrl(String id);
|
||||
|
||||
interface Paste {
|
||||
String url();
|
||||
String id();
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,161 @@
|
||||
/*
|
||||
* This file is part of LuckPerms, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) lucko (Luck) <luck@lucko.me>
|
||||
* 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.utils.web;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
|
||||
import okhttp3.MediaType;
|
||||
import okhttp3.Request;
|
||||
import okhttp3.RequestBody;
|
||||
import okhttp3.Response;
|
||||
import okhttp3.ResponseBody;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
public enum StandardPastebin implements Pastebin {
|
||||
|
||||
BYTEBIN {
|
||||
public static final String URL = "https://bytebin.lucko.me/";
|
||||
private static final String POST_URL = URL + "post";
|
||||
|
||||
@Override
|
||||
public String getPostUrl() {
|
||||
return POST_URL;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String parseIdFromResult(BufferedReader reader) {
|
||||
JsonObject object = GSON.fromJson(reader, JsonObject.class);
|
||||
return object.get("key").getAsString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRawUrl(String id) {
|
||||
return URL + id;
|
||||
}
|
||||
},
|
||||
|
||||
HASTEBIN {
|
||||
private static final String URL = "https://hastebin.com/";
|
||||
private static final String RAW_URL = URL + "raw/";
|
||||
private static final String POST_URL = URL + "documents";
|
||||
|
||||
@Override
|
||||
public String getPostUrl() {
|
||||
return POST_URL;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String parseIdFromResult(BufferedReader reader) {
|
||||
JsonObject object = GSON.fromJson(reader, JsonObject.class);
|
||||
return object.get("key").getAsString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRawUrl(String id) {
|
||||
return RAW_URL + id;
|
||||
}
|
||||
};
|
||||
|
||||
private static final Gson GSON = new GsonBuilder().setPrettyPrinting().disableHtmlEscaping().create();
|
||||
private static final MediaType JSON_TYPE = MediaType.parse("application/json; charset=utf-8");
|
||||
private static final MediaType PLAIN_TYPE = MediaType.parse("text/plain; charset=utf-8");
|
||||
|
||||
protected abstract String getPostUrl();
|
||||
protected abstract String parseIdFromResult(BufferedReader reader);
|
||||
|
||||
@Override
|
||||
public Pastebin.Paste postJson(JsonElement content) {
|
||||
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
|
||||
try (BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(bytes))) {
|
||||
GSON.toJson(content, writer);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
return post(RequestBody.create(JSON_TYPE, bytes.toByteArray()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Pastebin.Paste postPlain(String content) {
|
||||
return post(RequestBody.create(PLAIN_TYPE, content));
|
||||
}
|
||||
|
||||
private Pastebin.Paste post(RequestBody body) {
|
||||
Request request = new Request.Builder()
|
||||
.url(getPostUrl())
|
||||
.post(body)
|
||||
.build();
|
||||
|
||||
try (Response response = HttpClient.makeCall(request)) {
|
||||
try (ResponseBody responseBody = response.body()) {
|
||||
if (responseBody == null) {
|
||||
throw new RuntimeException("No response");
|
||||
}
|
||||
|
||||
try (InputStream inputStream = responseBody.byteStream()) {
|
||||
try (BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8))) {
|
||||
String id = parseIdFromResult(reader);
|
||||
String url = getRawUrl(id);
|
||||
return new Paste(url, id);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private static final class Paste implements Pastebin.Paste {
|
||||
private final String url;
|
||||
private final String id;
|
||||
|
||||
private Paste(String url, String id) {
|
||||
this.url = url;
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String url() {
|
||||
return this.url;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String id() {
|
||||
return this.id;
|
||||
}
|
||||
}
|
||||
}
|
@ -25,8 +25,15 @@
|
||||
|
||||
package me.lucko.luckperms.common.verbose;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
|
||||
import me.lucko.luckperms.api.Tristate;
|
||||
import me.lucko.luckperms.api.context.ImmutableContextSet;
|
||||
import me.lucko.luckperms.common.utils.StackTracePrinter;
|
||||
import me.lucko.luckperms.common.utils.gson.JArray;
|
||||
import me.lucko.luckperms.common.utils.gson.JObject;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Holds the data from a permission check
|
||||
@ -95,4 +102,33 @@ public class CheckData {
|
||||
public Tristate getResult() {
|
||||
return this.result;
|
||||
}
|
||||
|
||||
private JObject formBaseJson() {
|
||||
return new JObject()
|
||||
.add("who", new JObject()
|
||||
.add("identifier", this.checkTarget)
|
||||
)
|
||||
.add("permission", this.permission)
|
||||
.add("result", this.result.name().toLowerCase())
|
||||
.add("origin", this.checkOrigin.name().toLowerCase())
|
||||
.add("context", new JArray()
|
||||
.consume(arr -> {
|
||||
for (Map.Entry<String, String> contextPair : this.checkContext.toSet()) {
|
||||
arr.add(new JObject().add("key", contextPair.getKey()).add("value", contextPair.getValue()));
|
||||
}
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
public JsonObject toJson() {
|
||||
return formBaseJson().toJson();
|
||||
}
|
||||
|
||||
public JsonObject toJson(StackTracePrinter tracePrinter) {
|
||||
return formBaseJson()
|
||||
.add("trace", new JArray()
|
||||
.consume(arr -> tracePrinter.process(this.checkTrace, StackTracePrinter.elementToString(arr::add)))
|
||||
)
|
||||
.toJson();
|
||||
}
|
||||
}
|
||||
|
@ -40,7 +40,6 @@ import java.util.concurrent.Executor;
|
||||
* Accepts {@link CheckData} and passes it onto registered {@link VerboseListener}s.
|
||||
*/
|
||||
public class VerboseHandler implements Runnable {
|
||||
private final String pluginVersion;
|
||||
|
||||
// the listeners currently registered
|
||||
private final Map<UUID, VerboseListener> listeners;
|
||||
@ -54,8 +53,7 @@ public class VerboseHandler implements Runnable {
|
||||
// if the handler should shutdown
|
||||
private boolean shutdown = false;
|
||||
|
||||
public VerboseHandler(Executor executor, String pluginVersion) {
|
||||
this.pluginVersion = "v" + pluginVersion;
|
||||
public VerboseHandler(Executor executor) {
|
||||
this.listeners = new ConcurrentHashMap<>();
|
||||
this.queue = new ConcurrentLinkedQueue<>();
|
||||
|
||||
@ -95,7 +93,7 @@ public class VerboseHandler implements Runnable {
|
||||
* @param notify if the sender should be notified in chat on each check
|
||||
*/
|
||||
public void registerListener(Sender sender, VerboseFilter filter, boolean notify) {
|
||||
this.listeners.put(sender.getUuid(), new VerboseListener(this.pluginVersion, sender, filter, notify));
|
||||
this.listeners.put(sender.getUuid(), new VerboseListener(sender, filter, notify));
|
||||
this.listening = true;
|
||||
}
|
||||
|
||||
|
@ -25,7 +25,7 @@
|
||||
|
||||
package me.lucko.luckperms.common.verbose;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.gson.JsonObject;
|
||||
|
||||
import me.lucko.luckperms.api.Tristate;
|
||||
import me.lucko.luckperms.common.commands.CommandManager;
|
||||
@ -33,8 +33,11 @@ import me.lucko.luckperms.common.commands.sender.Sender;
|
||||
import me.lucko.luckperms.common.commands.utils.CommandUtils;
|
||||
import me.lucko.luckperms.common.locale.Message;
|
||||
import me.lucko.luckperms.common.utils.DateUtil;
|
||||
import me.lucko.luckperms.common.utils.Gist;
|
||||
import me.lucko.luckperms.common.utils.StackTracePrinter;
|
||||
import me.lucko.luckperms.common.utils.TextUtils;
|
||||
import me.lucko.luckperms.common.utils.gson.JArray;
|
||||
import me.lucko.luckperms.common.utils.gson.JObject;
|
||||
import me.lucko.luckperms.common.utils.web.StandardPastebin;
|
||||
|
||||
import net.kyori.text.TextComponent;
|
||||
import net.kyori.text.event.HoverEvent;
|
||||
@ -45,7 +48,6 @@ import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* Accepts and processes {@link CheckData}, passed from the {@link VerboseHandler}.
|
||||
@ -55,17 +57,36 @@ public class VerboseListener {
|
||||
|
||||
// how much data should we store before stopping.
|
||||
private static final int DATA_TRUNCATION = 10000;
|
||||
// how many traces should we add
|
||||
private static final int TRACE_DATA_TRUNCATION = 250;
|
||||
// how many lines should we include in each stack trace send as a chat message
|
||||
private static final int STACK_TRUNCATION_CHAT = 15;
|
||||
// how many lines should we include in each stack trace in the web output
|
||||
private static final int STACK_TRUNCATION_WEB = 30;
|
||||
|
||||
private static final StackTracePrinter FILTERING_PRINTER = StackTracePrinter.builder()
|
||||
.ignoreClassStartingWith("me.lucko.luckperms.")
|
||||
.ignoreClassStartingWith("com.github.benmanes.caffeine")
|
||||
.ignoreClass("java.util.concurrent.CompletableFuture")
|
||||
.ignoreClass("java.util.concurrent.ConcurrentHashMap")
|
||||
.build();
|
||||
|
||||
private static final StackTracePrinter CHAT_FILTERED_PRINTER = FILTERING_PRINTER.toBuilder()
|
||||
.truncateLength(STACK_TRUNCATION_CHAT)
|
||||
.build();
|
||||
|
||||
private static final StackTracePrinter CHAT_UNFILTERED_PRINTER = StackTracePrinter.builder()
|
||||
.truncateLength(STACK_TRUNCATION_CHAT)
|
||||
.build();
|
||||
|
||||
private static final StackTracePrinter WEB_FILTERED_PRINTER = FILTERING_PRINTER.toBuilder()
|
||||
.truncateLength(STACK_TRUNCATION_WEB)
|
||||
.build();
|
||||
|
||||
private static final StackTracePrinter WEB_UNFILTERED_PRINTER = StackTracePrinter.builder()
|
||||
.truncateLength(STACK_TRUNCATION_WEB)
|
||||
.build();
|
||||
|
||||
// the time when the listener was first registered
|
||||
private final long startTime = System.currentTimeMillis();
|
||||
// the version of the plugin. (used when we paste data to gist)
|
||||
private final String pluginVersion;
|
||||
// the sender to notify each time the listener processes a check which passes the filter
|
||||
private final Sender notifiedSender;
|
||||
// the filter
|
||||
@ -80,8 +101,7 @@ public class VerboseListener {
|
||||
// the checks which passed the filter, up to a max size of #DATA_TRUNCATION
|
||||
private final List<CheckData> results = new ArrayList<>(DATA_TRUNCATION / 10);
|
||||
|
||||
public VerboseListener(String pluginVersion, Sender notifiedSender, VerboseFilter filter, boolean notify) {
|
||||
this.pluginVersion = pluginVersion;
|
||||
public VerboseListener(Sender notifiedSender, VerboseFilter filter, boolean notify) {
|
||||
this.notifiedSender = notifiedSender;
|
||||
this.filter = filter;
|
||||
this.notify = notify;
|
||||
@ -132,7 +152,13 @@ public class VerboseListener {
|
||||
hover.add("&bContext: &r" + CommandUtils.contextSetToString(data.getCheckContext()));
|
||||
hover.add("&bTrace: &r");
|
||||
|
||||
int overflow = readStack(data, STACK_TRUNCATION_CHAT, e -> hover.add("&7" + e.getClassName() + "." + e.getMethodName() + (e.getLineNumber() >= 0 ? ":" + e.getLineNumber() : "")));
|
||||
Consumer<StackTraceElement> printer = StackTracePrinter.elementToString(str -> hover.add("&7" + str));
|
||||
int overflow;
|
||||
if (data.getCheckOrigin() == CheckOrigin.API || data.getCheckOrigin() == CheckOrigin.INTERNAL) {
|
||||
overflow = CHAT_UNFILTERED_PRINTER.process(data.getCheckTrace(), printer);
|
||||
} else {
|
||||
overflow = CHAT_FILTERED_PRINTER.process(data.getCheckTrace(), printer);
|
||||
}
|
||||
if (overflow != 0) {
|
||||
hover.add("&f... and " + overflow + " more");
|
||||
}
|
||||
@ -146,11 +172,9 @@ public class VerboseListener {
|
||||
/**
|
||||
* Uploads the captured data in this listener to a paste and returns the url
|
||||
*
|
||||
* @param showTraces if stack traces should be included in the output
|
||||
* @param attachRaw if the rawdata should be attached to the gist
|
||||
* @return the url
|
||||
*/
|
||||
public String uploadPasteData(boolean showTraces, boolean attachRaw) {
|
||||
public String uploadPasteData() {
|
||||
|
||||
// retrieve variables
|
||||
long now = System.currentTimeMillis();
|
||||
@ -163,148 +187,42 @@ public class VerboseListener {
|
||||
if (this.filter.isBlank()){
|
||||
filter = "any";
|
||||
} else {
|
||||
filter = "`" + this.filter.toString() + "`";
|
||||
filter = this.filter.toString();
|
||||
}
|
||||
|
||||
// start building the message output
|
||||
ImmutableList.Builder<String> prettyOutput = ImmutableList.<String>builder()
|
||||
.add("## Verbose Checking Output")
|
||||
.add("#### This file was automatically generated by [LuckPerms](https://github.com/lucko/LuckPerms) " + this.pluginVersion)
|
||||
.add("")
|
||||
.add("### Metadata")
|
||||
.add("| Key | Value |")
|
||||
.add("|-----|-------|")
|
||||
.add("| Start Time | " + startDate + " |")
|
||||
.add("| End Time | " + endDate + " |")
|
||||
.add("| Duration | " + duration +" |")
|
||||
.add("| Count | **" + this.matchedCounter.get() + "** / " + this.counter.get() + " |")
|
||||
.add("| User | " + this.notifiedSender.getNameWithLocation() + " |")
|
||||
.add("| Filter | " + filter + " |")
|
||||
.add("| Include traces | " + showTraces + " |")
|
||||
.add("");
|
||||
boolean truncated = this.matchedCounter.get() > this.results.size();
|
||||
|
||||
// warn if data was truncated
|
||||
if (this.matchedCounter.get() > this.results.size()) {
|
||||
prettyOutput.add("**WARN:** Result set exceeded max size of " + DATA_TRUNCATION + ". The output below was truncated to " + DATA_TRUNCATION + " entries.");
|
||||
prettyOutput.add("");
|
||||
}
|
||||
|
||||
// explain why some traces may be missing
|
||||
if (showTraces && this.results.size() > TRACE_DATA_TRUNCATION) {
|
||||
prettyOutput.add("**WARN:** Result set exceeded size of " + TRACE_DATA_TRUNCATION + ". The traced output below was truncated to " + TRACE_DATA_TRUNCATION + " entries. ");
|
||||
prettyOutput.add("Either refine the query using a more specific filter, or disable tracing by adding '--slim' to the end of the paste command.");
|
||||
prettyOutput.add("");
|
||||
}
|
||||
|
||||
// print the format of the output
|
||||
prettyOutput.add("### Output")
|
||||
.add("Format: `<checked>` `<permission>` `<value>`")
|
||||
.add("")
|
||||
.add("___")
|
||||
.add("");
|
||||
|
||||
// build the csv output - will only be appended to if this is enabled.
|
||||
ImmutableList.Builder<String> csvOutput = ImmutableList.<String>builder()
|
||||
.add("User,Permission,Result");
|
||||
|
||||
// how many instances have been printed so far
|
||||
AtomicInteger printedCount = new AtomicInteger(0);
|
||||
JObject metadata = new JObject()
|
||||
.add("startTime", startDate)
|
||||
.add("endTime", endDate)
|
||||
.add("duration", duration)
|
||||
.add("count", new JObject()
|
||||
.add("matched", this.matchedCounter.get())
|
||||
.add("total", this.counter.get())
|
||||
)
|
||||
.add("uploader", new JObject()
|
||||
.add("name", this.notifiedSender.getNameWithLocation())
|
||||
.add("uuid", this.notifiedSender.getUuid().toString())
|
||||
)
|
||||
.add("filter", filter)
|
||||
.add("truncated", truncated);
|
||||
|
||||
JArray data = new JArray();
|
||||
for (CheckData c : this.results) {
|
||||
if (!showTraces) {
|
||||
|
||||
// if traces aren't being shown, just append using raw markdown
|
||||
prettyOutput.add("`" + c.getCheckTarget() + "` - " + c.getPermission() + " - " + getTristateSymbol(c.getResult()) + " ");
|
||||
|
||||
} else if (printedCount.incrementAndGet() > TRACE_DATA_TRUNCATION) {
|
||||
|
||||
// if we've gone over the trace truncation, just append the raw info.
|
||||
// we still have to use html, as the rest of this section is still using it.
|
||||
prettyOutput.add("<br><code>" + c.getCheckTarget() + "</code> - " + c.getPermission() + " - " + getTristateSymbol(c.getResult()));
|
||||
|
||||
if (c.getCheckOrigin() == CheckOrigin.API || c.getCheckOrigin() == CheckOrigin.INTERNAL) {
|
||||
data.add(c.toJson(WEB_UNFILTERED_PRINTER));
|
||||
} else {
|
||||
|
||||
// append the full output.
|
||||
prettyOutput.add("<details><summary><code>" + c.getCheckTarget() + "</code> - " + c.getPermission() + " - " + getTristateSymbol(c.getResult()) + "</summary><p>");
|
||||
|
||||
// append the spoiler text
|
||||
prettyOutput.add("<br><b>Origin:</b> <code>" + c.getCheckOrigin().name() + "</code>");
|
||||
prettyOutput.add("<br><b>Context:</b> <code>" + CommandUtils.stripColor(CommandUtils.contextSetToString(c.getCheckContext())) + "</code>");
|
||||
prettyOutput.add("<br><b>Trace:</b><pre>");
|
||||
|
||||
int overflow = readStack(c, STACK_TRUNCATION_WEB, e -> prettyOutput.add(e.getClassName() + "." + e.getMethodName() + (e.getLineNumber() >= 0 ? ":" + e.getLineNumber() : "")));
|
||||
if (overflow != 0) {
|
||||
prettyOutput.add("... and " + overflow + " more");
|
||||
}
|
||||
|
||||
prettyOutput.add("</pre></p></details>");
|
||||
}
|
||||
|
||||
// if we're including a raw csv output, append that too
|
||||
if (attachRaw) {
|
||||
csvOutput.add(escapeCommas(c.getCheckTarget()) + "," + escapeCommas(c.getPermission()) + "," + c.getResult().name().toLowerCase());
|
||||
data.add(c.toJson(WEB_FILTERED_PRINTER));
|
||||
}
|
||||
}
|
||||
this.results.clear();
|
||||
|
||||
Gist.Builder gist = Gist.builder()
|
||||
.description("LuckPerms Verbose Checking Output")
|
||||
.file("luckperms-verbose.md", prettyOutput.build().stream().collect(Collectors.joining("\n")));
|
||||
JsonObject payload = new JObject()
|
||||
.add("metadata", metadata)
|
||||
.add("data", data)
|
||||
.toJson();
|
||||
|
||||
if (attachRaw) {
|
||||
gist.file("raw-data.csv", csvOutput.build().stream().collect(Collectors.joining("\n")));
|
||||
}
|
||||
|
||||
return gist.upload().getUrl();
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a stack trace from a {@link CheckData} instance.
|
||||
*
|
||||
* @param data the data to read from
|
||||
* @param truncateLength the length when we should stop reading the stack
|
||||
* @param consumer the element consumer
|
||||
* @return how many elements were left unread, or 0 if everything was read
|
||||
*/
|
||||
private static int readStack(CheckData data, int truncateLength, Consumer<StackTraceElement> consumer) {
|
||||
StackTraceElement[] stack = data.getCheckTrace();
|
||||
|
||||
// how many lines have been printed
|
||||
int count = 0;
|
||||
// if we're printing elements yet
|
||||
boolean printing = false;
|
||||
|
||||
for (StackTraceElement e : stack) {
|
||||
// start printing when we escape LP internals code
|
||||
boolean shouldStartPrinting = !printing && (
|
||||
(data.getCheckOrigin() == CheckOrigin.API || data.getCheckOrigin() == CheckOrigin.INTERNAL) || (
|
||||
!e.getClassName().startsWith("me.lucko.luckperms.") &&
|
||||
// all used within the checking impl somewhere
|
||||
!e.getClassName().equals("java.util.concurrent.CompletableFuture") &&
|
||||
!e.getClassName().startsWith("com.github.benmanes.caffeine") &&
|
||||
!e.getClassName().equals("java.util.concurrent.ConcurrentHashMap")
|
||||
)
|
||||
);
|
||||
|
||||
if (shouldStartPrinting) {
|
||||
printing = true;
|
||||
}
|
||||
|
||||
if (!printing) continue;
|
||||
if (count >= truncateLength) break;
|
||||
|
||||
consumer.accept(e);
|
||||
count++;
|
||||
}
|
||||
|
||||
if (stack.length > truncateLength) {
|
||||
return stack.length - truncateLength;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
private static String escapeCommas(String s) {
|
||||
return s.contains(",") ? "\"" + s + "\"" : s;
|
||||
return StandardPastebin.BYTEBIN.postJson(payload).id();
|
||||
}
|
||||
|
||||
private static String getTristateColor(Tristate tristate) {
|
||||
@ -318,17 +236,6 @@ public class VerboseListener {
|
||||
}
|
||||
}
|
||||
|
||||
private static String getTristateSymbol(Tristate tristate) {
|
||||
switch (tristate) {
|
||||
case TRUE:
|
||||
return "✔️";
|
||||
case FALSE:
|
||||
return "❌";
|
||||
default:
|
||||
return "❔";
|
||||
}
|
||||
}
|
||||
|
||||
public Sender getNotifiedSender() {
|
||||
return this.notifiedSender;
|
||||
}
|
||||
|
@ -30,7 +30,6 @@ import com.google.gson.Gson;
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonPrimitive;
|
||||
|
||||
import me.lucko.luckperms.api.context.ImmutableContextSet;
|
||||
import me.lucko.luckperms.common.commands.sender.Sender;
|
||||
@ -41,9 +40,11 @@ import me.lucko.luckperms.common.model.PermissionHolder;
|
||||
import me.lucko.luckperms.common.model.User;
|
||||
import me.lucko.luckperms.common.node.NodeModel;
|
||||
import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
|
||||
import me.lucko.luckperms.common.utils.Gist;
|
||||
import me.lucko.luckperms.common.utils.HttpClient;
|
||||
import me.lucko.luckperms.common.utils.Uuids;
|
||||
import me.lucko.luckperms.common.utils.gson.JArray;
|
||||
import me.lucko.luckperms.common.utils.gson.JObject;
|
||||
import me.lucko.luckperms.common.utils.web.HttpClient;
|
||||
import me.lucko.luckperms.common.utils.web.StandardPastebin;
|
||||
|
||||
import okhttp3.Request;
|
||||
import okhttp3.Response;
|
||||
@ -66,54 +67,49 @@ import java.util.stream.Stream;
|
||||
public final class WebEditor {
|
||||
private static final Gson GSON = new Gson();
|
||||
|
||||
private static final String FILE_NAME = "luckperms-data.json";
|
||||
private static final String GIST_API_URL = "https://api.github.com/gists";
|
||||
|
||||
private static final String USER_ID_PATTERN = "user/";
|
||||
private static final String GROUP_ID_PATTERN = "group/";
|
||||
|
||||
private static void writeData(PermissionHolder holder, JsonObject payload) {
|
||||
payload.addProperty("who", getHolderIdentifier(holder));
|
||||
payload.addProperty("whoFriendly", holder.getFriendlyName());
|
||||
if (holder.getType().isUser()) {
|
||||
payload.addProperty("whoUuid", ((User) holder).getUuid().toString());
|
||||
}
|
||||
|
||||
// attach the holders permissions
|
||||
payload.add("nodes", serializePermissions(holder.getEnduringNodes().values().stream().map(NodeModel::fromNode)));
|
||||
private static JObject writeData(PermissionHolder holder) {
|
||||
return new JObject()
|
||||
.add("who", new JObject()
|
||||
.add("id", getHolderIdentifier(holder))
|
||||
.add("friendly", holder.getFriendlyName())
|
||||
.consume(obj -> {
|
||||
if (holder.getType().isUser()) {
|
||||
obj.add("uuid", ((User) holder).getUuid().toString());
|
||||
}
|
||||
}))
|
||||
.add("nodes", serializePermissions(holder.getEnduringNodes().values().stream().map(NodeModel::fromNode)));
|
||||
}
|
||||
|
||||
public static JsonObject formPayload(List<PermissionHolder> holders, Sender sender, String cmdLabel, LuckPermsPlugin plugin) {
|
||||
Preconditions.checkArgument(!holders.isEmpty(), "holders is empty");
|
||||
|
||||
// form the payload data
|
||||
JsonObject payload = new JsonObject();
|
||||
|
||||
payload.addProperty("cmdAlias", cmdLabel);
|
||||
payload.addProperty("uploadedBy", sender.getNameWithLocation());
|
||||
payload.addProperty("uploadedByUuid", sender.getUuid().toString());
|
||||
payload.addProperty("time", System.currentTimeMillis());
|
||||
|
||||
if (holders.size() == 1) {
|
||||
writeData(holders.get(0), payload);
|
||||
} else {
|
||||
JsonArray tabs = new JsonArray();
|
||||
for (PermissionHolder holder : holders) {
|
||||
JsonObject o = new JsonObject();
|
||||
writeData(holder, o);
|
||||
tabs.add(o);
|
||||
}
|
||||
payload.add("tabs", tabs);
|
||||
}
|
||||
|
||||
// attach an array of all permissions known to the server, to use for tab completion in the editor
|
||||
JsonArray knownPermsArray = new JsonArray();
|
||||
for (String perm : plugin.getPermissionVault().rootAsList()) {
|
||||
knownPermsArray.add(new JsonPrimitive(perm));
|
||||
}
|
||||
payload.add("knownPermissions", knownPermsArray);
|
||||
|
||||
return payload;
|
||||
return new JObject()
|
||||
.add("metadata", new JObject()
|
||||
.add("cmdAlias", cmdLabel)
|
||||
.add("uploader", new JObject()
|
||||
.add("name", sender.getNameWithLocation())
|
||||
.add("uuid", sender.getUuid().toString())
|
||||
)
|
||||
.add("time", System.currentTimeMillis())
|
||||
)
|
||||
.add("sessions", new JArray()
|
||||
.consume(arr -> {
|
||||
for (PermissionHolder holder : holders) {
|
||||
arr.add(writeData(holder));
|
||||
}
|
||||
})
|
||||
)
|
||||
.add("knownPermissions", new JArray()
|
||||
.consume(arr -> {
|
||||
for (String perm : plugin.getPermissionVault().rootAsList()) {
|
||||
arr.add(perm);
|
||||
}
|
||||
})
|
||||
).toJson();
|
||||
}
|
||||
|
||||
private static String getHolderIdentifier(PermissionHolder holder) {
|
||||
@ -152,19 +148,9 @@ public final class WebEditor {
|
||||
}
|
||||
}
|
||||
|
||||
public static String postToGist(String content) {
|
||||
Gist gist = Gist.builder()
|
||||
.description("LuckPerms Web Editor Data")
|
||||
.shorten(false)
|
||||
.file(FILE_NAME, content)
|
||||
.upload();
|
||||
|
||||
return gist.getId();
|
||||
}
|
||||
|
||||
public static JsonObject getDataFromGist(String id) {
|
||||
Request request = new Request.Builder()
|
||||
.url(GIST_API_URL + "/" + id)
|
||||
.url(StandardPastebin.BYTEBIN.getRawUrl(id))
|
||||
.build();
|
||||
|
||||
try (Response response = HttpClient.makeCall(request)) {
|
||||
@ -175,29 +161,7 @@ public final class WebEditor {
|
||||
|
||||
try (InputStream inputStream = responseBody.byteStream()) {
|
||||
try (BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8))) {
|
||||
JsonObject object = new Gson().fromJson(reader, JsonObject.class);
|
||||
JsonObject files = object.get("files").getAsJsonObject();
|
||||
JsonObject permsFile = files.get(FILE_NAME).getAsJsonObject();
|
||||
|
||||
// uh..
|
||||
if (permsFile.get("truncated").getAsBoolean()) {
|
||||
try (Response rawResponse = HttpClient.makeCall(new Request.Builder().url(permsFile.get("raw_url").getAsString()).build())) {
|
||||
try (ResponseBody rawResponseBody = rawResponse.body()) {
|
||||
if (rawResponseBody == null) {
|
||||
throw new RuntimeException("No response");
|
||||
}
|
||||
|
||||
try (InputStream rawInputStream = rawResponseBody.byteStream()) {
|
||||
try (BufferedReader rawReader = new BufferedReader(new InputStreamReader(rawInputStream, StandardCharsets.UTF_8))) {
|
||||
return GSON.fromJson(rawReader, JsonObject.class);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
String content = permsFile.get("content").getAsString();
|
||||
return GSON.fromJson(content, JsonObject.class);
|
||||
}
|
||||
return GSON.fromJson(reader, JsonObject.class);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -103,8 +103,6 @@ import java.util.UUID;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* LuckPerms implementation for the Nukkit API.
|
||||
*/
|
||||
@ -157,7 +155,7 @@ public class LPNukkitPlugin extends PluginBase implements LuckPermsPlugin {
|
||||
public void onEnable() {
|
||||
this.startTime = System.currentTimeMillis();
|
||||
sendStartupBanner(getConsoleSender());
|
||||
this.verboseHandler = new VerboseHandler(this.scheduler.asyncNukkit(), getVersion());
|
||||
this.verboseHandler = new VerboseHandler(this.scheduler.asyncNukkit());
|
||||
this.permissionVault = new PermissionVault(this.scheduler.asyncNukkit());
|
||||
this.logDispatcher = new LogDispatcher(this);
|
||||
|
||||
@ -469,14 +467,13 @@ public class LPNukkitPlugin extends PluginBase implements LuckPermsPlugin {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Contexts getContextForUser(User user) {
|
||||
public Optional<Contexts> getContextForUser(User user) {
|
||||
Player player = getPlayer(user);
|
||||
if (player == null) {
|
||||
return null;
|
||||
return Optional.empty();
|
||||
}
|
||||
return this.contextManager.getApplicableContexts(player);
|
||||
return Optional.of(this.contextManager.getApplicableContexts(player));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -123,8 +123,6 @@ 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.
|
||||
*/
|
||||
@ -203,7 +201,7 @@ public class LPSpongePlugin implements LuckPermsSpongePlugin {
|
||||
this.dependencyManager.loadDependencies(DependencyRegistry.GLOBAL_DEPENDENCIES);
|
||||
|
||||
sendStartupBanner(getConsoleSender());
|
||||
this.verboseHandler = new VerboseHandler(this.scheduler.async(), getVersion());
|
||||
this.verboseHandler = new VerboseHandler(this.scheduler.async());
|
||||
this.permissionVault = new PermissionVault(this.scheduler.async());
|
||||
this.logDispatcher = new LogDispatcher(this);
|
||||
|
||||
@ -429,14 +427,13 @@ public class LPSpongePlugin implements LuckPermsSpongePlugin {
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Contexts getContextForUser(User user) {
|
||||
public Optional<Contexts> getContextForUser(User user) {
|
||||
Player player = getPlayer(user);
|
||||
if (player == null) {
|
||||
return null;
|
||||
return Optional.empty();
|
||||
}
|
||||
return this.contextManager.getApplicableContexts(player);
|
||||
return Optional.of(this.contextManager.getApplicableContexts(player));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
Loading…
Reference in New Issue
Block a user