Refactor paginated command output, add flags for ordering 'permission info' entries, fix crashes caused by long messages (#591)

This commit is contained in:
Luck 2017-12-16 21:05:43 +00:00
parent 2e7a08c006
commit 904bb90385
No known key found for this signature in database
GPG Key ID: EFA9B3EC5FD90F8B
29 changed files with 447 additions and 403 deletions

View File

@ -302,7 +302,7 @@ public class VaultChatHook extends Chat {
world = perms.correctWorld(world); world = perms.correctWorld(world);
Contexts contexts; Contexts contexts;
if (holder instanceof User) { if (holder.getType().isUser()) {
contexts = perms.createContextForWorldLookup(perms.getPlugin().getPlayer((User) holder), world); contexts = perms.createContextForWorldLookup(perms.getPlugin().getPlayer((User) holder), world);
} else { } else {
contexts = perms.createContextForWorldLookup(world); contexts = perms.createContextForWorldLookup(world);
@ -322,7 +322,7 @@ public class VaultChatHook extends Chat {
world = perms.correctWorld(world); world = perms.correctWorld(world);
Contexts contexts; Contexts contexts;
if (holder instanceof User) { if (holder.getType().isUser()) {
contexts = perms.createContextForWorldLookup(perms.getPlugin().getPlayer((User) holder), world); contexts = perms.createContextForWorldLookup(perms.getPlugin().getPlayer((User) holder), world);
} else { } else {
contexts = perms.createContextForWorldLookup(world); contexts = perms.createContextForWorldLookup(world);

View File

@ -444,11 +444,11 @@ public class VaultPermissionHook extends Permission {
} }
void holderSave(PermissionHolder holder) { void holderSave(PermissionHolder holder) {
if (holder instanceof User) { if (holder.getType().isUser()) {
User u = (User) holder; User u = (User) holder;
plugin.getStorage().saveUser(u).thenRunAsync(() -> u.getRefreshBuffer().request(), plugin.getScheduler().async()); plugin.getStorage().saveUser(u).thenRunAsync(() -> u.getRefreshBuffer().request(), plugin.getScheduler().async());
} }
if (holder instanceof Group) { if (holder.getType().isGroup()) {
Group g = (Group) holder; Group g = (Group) holder;
plugin.getStorage().saveGroup(g).thenRunAsync(() -> plugin.getUpdateTaskBuffer().request(), plugin.getScheduler().async()); plugin.getStorage().saveGroup(g).thenRunAsync(() -> plugin.getUpdateTaskBuffer().request(), plugin.getScheduler().async());
} }

View File

@ -283,11 +283,11 @@ public class ExtendedLogEntry implements LogEntry {
} }
public ExtendedLogEntryBuilder acted(PermissionHolder acted) { public ExtendedLogEntryBuilder acted(PermissionHolder acted) {
if (acted instanceof User) { if (acted.getType().isUser()) {
actedName(((User) acted).getName().orElse("null")); actedName(((User) acted).getName().orElse("null"));
acted(((User) acted).getUuid()); acted(((User) acted).getUuid());
type(Type.USER); type(Type.USER);
} else if (acted instanceof Group) { } else if (acted.getType().isGroup()) {
actedName(((Group) acted).getName()); actedName(((Group) acted).getName());
type(Type.GROUP); type(Type.GROUP);
} }

View File

@ -66,7 +66,7 @@ public class ApiPermissionHolder implements PermissionHolder {
@Override @Override
public String getFriendlyName() { public String getFriendlyName() {
if (handle instanceof Group) { if (handle.getType().isGroup()) {
Group group = (Group) this.handle; Group group = (Group) this.handle;
return group.getDisplayName().orElse(group.getName()); return group.getDisplayName().orElse(group.getName());
} }
@ -181,7 +181,7 @@ public class ApiPermissionHolder implements PermissionHolder {
@Override @Override
public void clearMatching(Predicate<Node> test) { public void clearMatching(Predicate<Node> test) {
handle.removeIf(test); handle.removeIf(test);
if (handle instanceof User) { if (handle.getType().isUser()) {
handle.getPlugin().getUserManager().giveDefaultIfNeeded((User) handle, false); handle.getPlugin().getUserManager().giveDefaultIfNeeded((User) handle, false);
} }
} }

View File

@ -35,6 +35,7 @@ import me.lucko.luckperms.common.model.Track;
import me.lucko.luckperms.common.model.User; import me.lucko.luckperms.common.model.User;
import me.lucko.luckperms.common.node.NodeFactory; import me.lucko.luckperms.common.node.NodeFactory;
import me.lucko.luckperms.common.plugin.LuckPermsPlugin; import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
import me.lucko.luckperms.common.references.HolderType;
import me.lucko.luckperms.common.storage.Storage; import me.lucko.luckperms.common.storage.Storage;
import me.lucko.luckperms.common.utils.Cycle; import me.lucko.luckperms.common.utils.Cycle;
@ -124,7 +125,7 @@ public class Exporter implements Runnable {
write(writer, "# Export group: " + group.getName()); write(writer, "# Export group: " + group.getName());
for (Node node : group.getEnduringNodes().values()) { for (Node node : group.getEnduringNodes().values()) {
write(writer, "/lp " + NodeFactory.nodeAsCommand(node, group.getName(), true, true)); write(writer, "/lp " + NodeFactory.nodeAsCommand(node, group.getName(), HolderType.GROUP, true));
} }
write(writer, ""); write(writer, "");
log.logAllProgress("Exported {} groups so far.", groupCount.incrementAndGet()); log.logAllProgress("Exported {} groups so far.", groupCount.incrementAndGet());
@ -230,7 +231,7 @@ public class Exporter implements Runnable {
continue; continue;
} }
output.add("/lp " + NodeFactory.nodeAsCommand(node, user.getUuid().toString(), false, true)); output.add("/lp " + NodeFactory.nodeAsCommand(node, user.getUuid().toString(), HolderType.USER, true));
} }
if (!user.getPrimaryGroup().getStoredValue().orElse("default").equalsIgnoreCase("default")) { if (!user.getPrimaryGroup().getStoredValue().orElse("default").equalsIgnoreCase("default")) {

View File

@ -118,13 +118,13 @@ public abstract class SharedSubCommand {
} }
public static void save(PermissionHolder holder, Sender sender, LuckPermsPlugin plugin) { public static void save(PermissionHolder holder, Sender sender, LuckPermsPlugin plugin) {
if (holder instanceof User) { if (holder.getType().isUser()) {
User user = ((User) holder); User user = ((User) holder);
SubCommand.save(user, sender, plugin); SubCommand.save(user, sender, plugin);
return; return;
} }
if (holder instanceof Group) { if (holder.getType().isGroup()) {
Group group = ((Group) holder); Group group = ((Group) holder);
SubCommand.save(group, sender, plugin); SubCommand.save(group, sender, plugin);
return; return;

View File

@ -43,7 +43,6 @@ import me.lucko.luckperms.common.locale.LocaleManager;
import me.lucko.luckperms.common.locale.Message; import me.lucko.luckperms.common.locale.Message;
import me.lucko.luckperms.common.model.Group; import me.lucko.luckperms.common.model.Group;
import me.lucko.luckperms.common.model.PermissionHolder; import me.lucko.luckperms.common.model.PermissionHolder;
import me.lucko.luckperms.common.model.User;
import me.lucko.luckperms.common.node.NodeFactory; import me.lucko.luckperms.common.node.NodeFactory;
import me.lucko.luckperms.common.plugin.LuckPermsPlugin; import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
import me.lucko.luckperms.common.utils.Predicates; import me.lucko.luckperms.common.utils.Predicates;
@ -168,12 +167,12 @@ public class MetaInfo extends SharedSubCommand {
"¥7Click to remove this " + type.name().toLowerCase() + " from " + holder.getFriendlyName() "¥7Click to remove this " + type.name().toLowerCase() + " from " + holder.getFriendlyName()
), '¥')); ), '¥'));
boolean group = !(holder instanceof User); String command = "/" + label + " " + NodeFactory.nodeAsCommand(node, holder.getType().isGroup() ? holder.getObjectName() : holder.getFriendlyName(), holder.getType(), false);
String command = "/" + label + " " + NodeFactory.nodeAsCommand(node, group ? holder.getObjectName() : holder.getFriendlyName(), group, false); ClickEvent clickEvent = new ClickEvent(ClickEvent.Action.SUGGEST_COMMAND, command);
return component -> { return component -> {
component.hoverEvent(hoverEvent); component.hoverEvent(hoverEvent);
component.clickEvent(new ClickEvent(ClickEvent.Action.SUGGEST_COMMAND, command)); component.clickEvent(clickEvent);
}; };
} }
@ -192,12 +191,12 @@ public class MetaInfo extends SharedSubCommand {
"¥7Click to remove this meta pair from " + holder.getFriendlyName() "¥7Click to remove this meta pair from " + holder.getFriendlyName()
), '¥')); ), '¥'));
boolean group = !(holder instanceof User); String command = "/" + label + " " + NodeFactory.nodeAsCommand(node, holder.getType().isGroup() ? holder.getObjectName() : holder.getFriendlyName(), holder.getType(), false);
String command = "/" + label + " " + NodeFactory.nodeAsCommand(node, group ? holder.getObjectName() : holder.getFriendlyName(), group, false); ClickEvent clickEvent = new ClickEvent(ClickEvent.Action.SUGGEST_COMMAND, command);
return component -> { return component -> {
component.hoverEvent(hoverEvent); component.hoverEvent(hoverEvent);
component.clickEvent(new ClickEvent(ClickEvent.Action.SUGGEST_COMMAND, command)); component.clickEvent(clickEvent);
}; };
} }
} }

View File

@ -71,7 +71,7 @@ public class HolderEditor<T extends PermissionHolder> extends SubCommand<T> {
JsonObject payload = new JsonObject(); JsonObject payload = new JsonObject();
payload.addProperty("who", WebEditorUtils.getHolderIdentifier(holder)); payload.addProperty("who", WebEditorUtils.getHolderIdentifier(holder));
payload.addProperty("whoFriendly", holder.getFriendlyName()); payload.addProperty("whoFriendly", holder.getFriendlyName());
if (holder instanceof User) { if (holder.getType().isUser()) {
payload.addProperty("whoUuid", ((User) holder).getUuid().toString()); payload.addProperty("whoUuid", ((User) holder).getUuid().toString());
} }
payload.addProperty("cmdAlias", label); payload.addProperty("cmdAlias", label);

View File

@ -25,6 +25,8 @@
package me.lucko.luckperms.common.commands.impl.generic.other; package me.lucko.luckperms.common.commands.impl.generic.other;
import com.google.common.collect.Maps;
import me.lucko.luckperms.api.Node; import me.lucko.luckperms.api.Node;
import me.lucko.luckperms.common.commands.ArgumentPermissions; import me.lucko.luckperms.common.commands.ArgumentPermissions;
import me.lucko.luckperms.common.commands.CommandException; import me.lucko.luckperms.common.commands.CommandException;
@ -37,10 +39,13 @@ import me.lucko.luckperms.common.locale.CommandSpec;
import me.lucko.luckperms.common.locale.LocaleManager; import me.lucko.luckperms.common.locale.LocaleManager;
import me.lucko.luckperms.common.locale.Message; import me.lucko.luckperms.common.locale.Message;
import me.lucko.luckperms.common.model.PermissionHolder; import me.lucko.luckperms.common.model.PermissionHolder;
import me.lucko.luckperms.common.model.Track;
import me.lucko.luckperms.common.plugin.LuckPermsPlugin; import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
import me.lucko.luckperms.common.utils.Predicates; import me.lucko.luckperms.common.utils.Predicates;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@ -63,32 +68,32 @@ public class HolderShowTracks<T extends PermissionHolder> extends SubCommand<T>
Set<Node> nodes = holder.getEnduringNodes().values().stream() Set<Node> nodes = holder.getEnduringNodes().values().stream()
.filter(Node::isGroupNode) .filter(Node::isGroupNode)
.filter(Node::getValuePrimitive)
.filter(Node::isPermanent) .filter(Node::isPermanent)
.collect(Collectors.toSet()); .collect(Collectors.toSet());
StringBuilder sb = new StringBuilder(); List<Map.Entry<Track, String>> lines = new ArrayList<>();
for (Node node : nodes) { for (Node node : nodes) {
String name = node.getGroupName(); String name = node.getGroupName();
List<Track> tracks = plugin.getTrackManager().getAll().values().stream()
plugin.getTrackManager().getAll().values().stream()
.filter(t -> t.containsGroup(name)) .filter(t -> t.containsGroup(name))
.forEach(t -> sb.append("&a") .collect(Collectors.toList());
.append(t.getName())
.append(": ") for (Track t : tracks) {
.append(CommandUtils.listToArrowSep(t.getGroups(), name)) lines.add(Maps.immutableEntry(t, CommandUtils.listToArrowSep(t.getGroups(), name) + CommandUtils.getAppendableNodeContextString(node)));
.append(CommandUtils.getAppendableNodeContextString(node)) }
.append("\n")
);
} }
if (sb.length() == 0) { if (lines.isEmpty()) {
Message.LIST_TRACKS_EMPTY.send(sender, holder.getFriendlyName()); Message.LIST_TRACKS_EMPTY.send(sender, holder.getFriendlyName());
return CommandResult.SUCCESS; return CommandResult.SUCCESS;
} else {
sb.deleteCharAt(sb.length() - 1);
Message.LIST_TRACKS.send(sender, holder.getFriendlyName(), sb.toString());
return CommandResult.SUCCESS;
} }
Message.LIST_TRACKS.send(sender, holder.getFriendlyName());
for (Map.Entry<Track, String> line : lines) {
Message.LIST_TRACKS_ENTRY.send(sender, line.getKey().getName(), line.getValue());
}
return CommandResult.SUCCESS;
} }
} }

View File

@ -103,7 +103,7 @@ public class ParentClearTrack extends SharedSubCommand {
holder.removeIf(node -> node.isGroupNode() && node.getFullContexts().equals(context) && track.containsGroup(node.getGroupName())); holder.removeIf(node -> node.isGroupNode() && node.getFullContexts().equals(context) && track.containsGroup(node.getGroupName()));
} }
if (holder instanceof User) { if (holder.getType().isUser()) {
plugin.getUserManager().giveDefaultIfNeeded(((User) holder), false); plugin.getUserManager().giveDefaultIfNeeded(((User) holder), false);
} }

View File

@ -32,35 +32,38 @@ import me.lucko.luckperms.common.commands.CommandException;
import me.lucko.luckperms.common.commands.CommandResult; import me.lucko.luckperms.common.commands.CommandResult;
import me.lucko.luckperms.common.commands.abstraction.SharedSubCommand; import me.lucko.luckperms.common.commands.abstraction.SharedSubCommand;
import me.lucko.luckperms.common.commands.sender.Sender; import me.lucko.luckperms.common.commands.sender.Sender;
import me.lucko.luckperms.common.commands.utils.ArgumentUtils;
import me.lucko.luckperms.common.commands.utils.CommandUtils; import me.lucko.luckperms.common.commands.utils.CommandUtils;
import me.lucko.luckperms.common.commands.utils.SortMode;
import me.lucko.luckperms.common.commands.utils.SortType;
import me.lucko.luckperms.common.constants.CommandPermission; import me.lucko.luckperms.common.constants.CommandPermission;
import me.lucko.luckperms.common.constants.Constants; import me.lucko.luckperms.common.constants.Constants;
import me.lucko.luckperms.common.locale.CommandSpec; import me.lucko.luckperms.common.locale.CommandSpec;
import me.lucko.luckperms.common.locale.LocaleManager; import me.lucko.luckperms.common.locale.LocaleManager;
import me.lucko.luckperms.common.locale.Message; import me.lucko.luckperms.common.locale.Message;
import me.lucko.luckperms.common.model.PermissionHolder; import me.lucko.luckperms.common.model.PermissionHolder;
import me.lucko.luckperms.common.model.User;
import me.lucko.luckperms.common.node.NodeFactory; import me.lucko.luckperms.common.node.NodeFactory;
import me.lucko.luckperms.common.node.NodeWithContextComparator;
import me.lucko.luckperms.common.plugin.LuckPermsPlugin; import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
import me.lucko.luckperms.common.utils.CollationKeyCache;
import me.lucko.luckperms.common.utils.DateUtil; import me.lucko.luckperms.common.utils.DateUtil;
import me.lucko.luckperms.common.utils.Predicates; import me.lucko.luckperms.common.utils.Predicates;
import me.lucko.luckperms.common.utils.TextUtils; import me.lucko.luckperms.common.utils.TextUtils;
import net.kyori.text.BuildableComponent; import net.kyori.text.BuildableComponent;
import net.kyori.text.Component;
import net.kyori.text.TextComponent; import net.kyori.text.TextComponent;
import net.kyori.text.event.ClickEvent; import net.kyori.text.event.ClickEvent;
import net.kyori.text.event.HoverEvent; import net.kyori.text.event.HoverEvent;
import net.kyori.text.format.TextColor;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List; import java.util.List;
import java.util.SortedSet;
import java.util.function.Consumer; import java.util.function.Consumer;
public class ParentInfo extends SharedSubCommand { public class ParentInfo extends SharedSubCommand {
public ParentInfo(LocaleManager locale) { public ParentInfo(LocaleManager locale) {
super(CommandSpec.PARENT_INFO.spec(locale), "info", CommandPermission.USER_PARENT_INFO, CommandPermission.GROUP_PARENT_INFO, Predicates.alwaysFalse()); super(CommandSpec.PARENT_INFO.spec(locale), "info", CommandPermission.USER_PARENT_INFO, CommandPermission.GROUP_PARENT_INFO, Predicates.notInRange(0, 2));
} }
@Override @Override
@ -70,58 +73,67 @@ public class ParentInfo extends SharedSubCommand {
return CommandResult.NO_PERMISSION; return CommandResult.NO_PERMISSION;
} }
Component ent = permGroupsToMessage(holder.getOwnNodesSorted(), holder, label); int page = ArgumentUtils.handleIntOrElse(0, args, 1);
Message.LISTPARENTS.send(sender, holder.getFriendlyName()); SortMode sortMode = SortMode.determine(args);
sender.sendMessage(ent);
Component tempEnt = tempGroupsToMessage(holder.getOwnNodesSorted(), holder, label); // get the holders nodes
Message.LISTPARENTS_TEMP.send(sender, holder.getFriendlyName()); List<LocalizedNode> nodes = new ArrayList<>(holder.getOwnNodesSorted());
sender.sendMessage(tempEnt);
// remove irrelevant types (these are displayed in the other info commands)
nodes.removeIf(node -> !node.isGroupNode() || !node.getValuePrimitive());
// handle empty
if (nodes.isEmpty()) {
Message.PARENT_INFO_NO_DATA.send(sender, holder.getFriendlyName());
return CommandResult.SUCCESS;
}
// sort the list alphabetically instead
if (sortMode.getType() == SortType.ALPHABETICALLY) {
nodes.sort(ALPHABETICAL_NODE_COMPARATOR);
}
// reverse the order if necessary
if (!sortMode.isAscending()) {
Collections.reverse(nodes);
}
int pageIndex = page - 1;
List<List<LocalizedNode>> pages = CommandUtils.divideList(nodes, 19);
if (pageIndex < 0 || pageIndex >= pages.size()) {
page = 1;
pageIndex = 0;
}
List<LocalizedNode> content = pages.get(pageIndex);
// send header
Message.PARENT_INFO.send(sender, holder.getFriendlyName(), page, pages.size(), nodes.size());
// send content
for (LocalizedNode node : content) {
String s = "&3> &a" + node.getGroupName() + CommandUtils.getAppendableNodeContextString(node);
if (node.isTemporary()) {
s += "\n&2 expires in " + DateUtil.formatDateDiff(node.getExpiryUnixTime());
}
TextComponent message = TextUtils.fromLegacy(s, Constants.FORMAT_CHAR).toBuilder().applyDeep(makeFancy(holder, label, node)).build();
sender.sendMessage(message);
}
return CommandResult.SUCCESS; return CommandResult.SUCCESS;
} }
private static Component permGroupsToMessage(SortedSet<LocalizedNode> nodes, PermissionHolder holder, String label) { private static final Comparator<LocalizedNode> ALPHABETICAL_NODE_COMPARATOR = (o1, o2) -> {
List<Node> page = new ArrayList<>(); int i = CollationKeyCache.compareStrings(o1.getGroupName(), o2.getGroupName());
for (Node node : nodes) { if (i != 0) {
if (!node.isGroupNode()) continue; return i;
if (!node.getValuePrimitive()) continue;
if (node.isTemporary()) continue;
page.add(node);
} }
if (page.isEmpty()) { // fallback to priority
return TextComponent.builder("None").color(TextColor.DARK_AQUA).build(); return NodeWithContextComparator.reverse().compare(o1, o2);
} };
TextComponent.Builder message = TextComponent.builder("");
for (Node node : page) {
String s = "&3> &a" + node.getGroupName() + CommandUtils.getAppendableNodeContextString(node) + "\n";
message.append(TextUtils.fromLegacy(s, Constants.FORMAT_CHAR).toBuilder().applyDeep(makeFancy(holder, label, node)).build());
}
return message.build();
}
private static Component tempGroupsToMessage(SortedSet<LocalizedNode> nodes, PermissionHolder holder, String label) {
List<Node> page = new ArrayList<>();
for (Node node : nodes) {
if (!node.isGroupNode()) continue;
if (!node.getValuePrimitive()) continue;
if (node.isPermanent()) continue;
page.add(node);
}
if (page.isEmpty()) {
return TextComponent.builder("None").color(TextColor.DARK_AQUA).build();
}
TextComponent.Builder message = TextComponent.builder("");
for (Node node : page) {
String s = "&3> &a" + node.getGroupName() + CommandUtils.getAppendableNodeContextString(node) + "\n&2- expires in " + DateUtil.formatDateDiff(node.getExpiryUnixTime()) + "\n";
message.append(TextUtils.fromLegacy(s, Constants.FORMAT_CHAR).toBuilder().applyDeep(makeFancy(holder, label, node)).build());
}
return message.build();
}
private static Consumer<BuildableComponent.Builder<? ,?>> makeFancy(PermissionHolder holder, String label, Node node) { private static Consumer<BuildableComponent.Builder<? ,?>> makeFancy(PermissionHolder holder, String label, Node node) {
HoverEvent hoverEvent = new HoverEvent(HoverEvent.Action.SHOW_TEXT, TextUtils.fromLegacy(TextUtils.joinNewline( HoverEvent hoverEvent = new HoverEvent(HoverEvent.Action.SHOW_TEXT, TextUtils.fromLegacy(TextUtils.joinNewline(
@ -130,12 +142,12 @@ public class ParentInfo extends SharedSubCommand {
"&7Click to remove this parent from " + holder.getFriendlyName() "&7Click to remove this parent from " + holder.getFriendlyName()
), Constants.FORMAT_CHAR)); ), Constants.FORMAT_CHAR));
boolean group = !(holder instanceof User); String command = "/" + label + " " + NodeFactory.nodeAsCommand(node, holder.getType().isGroup() ? holder.getObjectName() : holder.getFriendlyName(), holder.getType(), false);
String command = "/" + label + " " + NodeFactory.nodeAsCommand(node, group ? holder.getObjectName() : holder.getFriendlyName(), group, false); ClickEvent clickEvent = new ClickEvent(ClickEvent.Action.SUGGEST_COMMAND, command);
return component -> { return component -> {
component.hoverEvent(hoverEvent); component.hoverEvent(hoverEvent);
component.clickEvent(new ClickEvent(ClickEvent.Action.SUGGEST_COMMAND, command)); component.clickEvent(clickEvent);
}; };
} }
} }

View File

@ -75,7 +75,7 @@ public class ParentRemove extends SharedSubCommand {
return CommandResult.NO_PERMISSION; return CommandResult.NO_PERMISSION;
} }
if (holder instanceof User) { if (holder.getType().isUser()) {
User user = (User) holder; User user = (User) holder;
boolean shouldPrevent = plugin.getConfiguration().get(ConfigKeys.PREVENT_PRIMARY_GROUP_REMOVAL) && boolean shouldPrevent = plugin.getConfiguration().get(ConfigKeys.PREVENT_PRIMARY_GROUP_REMOVAL) &&
@ -97,7 +97,7 @@ public class ParentRemove extends SharedSubCommand {
.action("parent", "remove", groupName, context) .action("parent", "remove", groupName, context)
.build().submit(plugin, sender); .build().submit(plugin, sender);
if (holder instanceof User) { if (holder.getType().isUser()) {
plugin.getUserManager().giveDefaultIfNeeded(((User) holder), false); plugin.getUserManager().giveDefaultIfNeeded(((User) holder), false);
} }

View File

@ -86,7 +86,7 @@ public class ParentSet extends SharedSubCommand {
holder.clearParents(context, false); holder.clearParents(context, false);
holder.setInheritGroup(group, context); holder.setInheritGroup(group, context);
if (holder instanceof User) { if (holder.getType().isUser()) {
((User) holder).getPrimaryGroup().setStoredValue(group.getName()); ((User) holder).getPrimaryGroup().setStoredValue(group.getName());
} }

View File

@ -25,8 +25,6 @@
package me.lucko.luckperms.common.commands.impl.generic.permission; package me.lucko.luckperms.common.commands.impl.generic.permission;
import com.google.common.collect.Maps;
import me.lucko.luckperms.api.LocalizedNode; import me.lucko.luckperms.api.LocalizedNode;
import me.lucko.luckperms.api.Node; import me.lucko.luckperms.api.Node;
import me.lucko.luckperms.common.commands.ArgumentPermissions; import me.lucko.luckperms.common.commands.ArgumentPermissions;
@ -36,30 +34,31 @@ import me.lucko.luckperms.common.commands.abstraction.SharedSubCommand;
import me.lucko.luckperms.common.commands.sender.Sender; import me.lucko.luckperms.common.commands.sender.Sender;
import me.lucko.luckperms.common.commands.utils.ArgumentUtils; import me.lucko.luckperms.common.commands.utils.ArgumentUtils;
import me.lucko.luckperms.common.commands.utils.CommandUtils; import me.lucko.luckperms.common.commands.utils.CommandUtils;
import me.lucko.luckperms.common.commands.utils.SortMode;
import me.lucko.luckperms.common.commands.utils.SortType;
import me.lucko.luckperms.common.constants.CommandPermission; import me.lucko.luckperms.common.constants.CommandPermission;
import me.lucko.luckperms.common.constants.Constants; import me.lucko.luckperms.common.constants.Constants;
import me.lucko.luckperms.common.locale.CommandSpec; import me.lucko.luckperms.common.locale.CommandSpec;
import me.lucko.luckperms.common.locale.LocaleManager; import me.lucko.luckperms.common.locale.LocaleManager;
import me.lucko.luckperms.common.locale.Message; import me.lucko.luckperms.common.locale.Message;
import me.lucko.luckperms.common.model.PermissionHolder; import me.lucko.luckperms.common.model.PermissionHolder;
import me.lucko.luckperms.common.model.User;
import me.lucko.luckperms.common.node.NodeFactory; import me.lucko.luckperms.common.node.NodeFactory;
import me.lucko.luckperms.common.node.NodeWithContextComparator;
import me.lucko.luckperms.common.plugin.LuckPermsPlugin; import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
import me.lucko.luckperms.common.utils.CollationKeyCache;
import me.lucko.luckperms.common.utils.DateUtil; import me.lucko.luckperms.common.utils.DateUtil;
import me.lucko.luckperms.common.utils.Predicates; import me.lucko.luckperms.common.utils.Predicates;
import me.lucko.luckperms.common.utils.TextUtils; import me.lucko.luckperms.common.utils.TextUtils;
import net.kyori.text.BuildableComponent; import net.kyori.text.BuildableComponent;
import net.kyori.text.Component;
import net.kyori.text.TextComponent; import net.kyori.text.TextComponent;
import net.kyori.text.event.ClickEvent; import net.kyori.text.event.ClickEvent;
import net.kyori.text.event.HoverEvent; import net.kyori.text.event.HoverEvent;
import net.kyori.text.format.TextColor;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.SortedSet;
import java.util.function.Consumer; import java.util.function.Consumer;
public class PermissionInfo extends SharedSubCommand { public class PermissionInfo extends SharedSubCommand {
@ -74,111 +73,72 @@ public class PermissionInfo extends SharedSubCommand {
return CommandResult.NO_PERMISSION; return CommandResult.NO_PERMISSION;
} }
String filter = null;
if (args.size() == 1) {
// it might be a filter, if it's a number, then it relates to a page.
try {
Integer.parseInt(args.get(0));
} catch (NumberFormatException e) {
// it's not a number, so assume it's the filter.
filter = args.get(0);
}
} else if (args.size() == 2) {
filter = args.get(1);
}
int page = ArgumentUtils.handleIntOrElse(0, args, 1); int page = ArgumentUtils.handleIntOrElse(0, args, 1);
SortMode sortMode = SortMode.determine(args);
Map.Entry<Component, String> ent = nodesToMessage(false, filter, holder.getOwnNodesSorted(), holder, label, page, sender.isConsole()); // get the holders nodes
if (ent.getValue() != null) { List<LocalizedNode> nodes = new ArrayList<>(holder.getOwnNodesSorted());
Message.LISTNODES_WITH_PAGE.send(sender, holder.getFriendlyName(), ent.getValue());
sender.sendMessage(ent.getKey()); // remove irrelevant types (these are displayed in the other info commands)
} else { nodes.removeIf(node ->
Message.LISTNODES.send(sender, holder.getFriendlyName()); // remove if the node is a group node, and if the value isn't false and if the group actually exists
sender.sendMessage(ent.getKey()); (node.isGroupNode() && node.getValuePrimitive() && plugin.getGroupManager().isLoaded(node.getGroupName())) ||
// remove if the node is a meta node
node.isPrefix() || node.isSuffix() || node.isMeta()
);
// handle empty
if (nodes.isEmpty()) {
Message.PERMISSION_INFO_NO_DATA.send(sender, holder.getFriendlyName());
return CommandResult.SUCCESS;
} }
Map.Entry<Component, String> tempEnt = nodesToMessage(true, filter, holder.getOwnNodesSorted(), holder, label, page, sender.isConsole()); // sort the list alphabetically instead
if (tempEnt.getValue() != null) { if (sortMode.getType() == SortType.ALPHABETICALLY) {
Message.LISTNODES_TEMP_WITH_PAGE.send(sender, holder.getFriendlyName(), tempEnt.getValue()); nodes.sort(ALPHABETICAL_NODE_COMPARATOR);
sender.sendMessage(tempEnt.getKey()); }
} else {
Message.LISTNODES_TEMP.send(sender, holder.getFriendlyName()); // reverse the order if necessary
sender.sendMessage(tempEnt.getKey()); if (!sortMode.isAscending()) {
Collections.reverse(nodes);
}
int pageIndex = page - 1;
List<List<LocalizedNode>> pages = CommandUtils.divideList(nodes, 19);
if (pageIndex < 0 || pageIndex >= pages.size()) {
page = 1;
pageIndex = 0;
}
List<LocalizedNode> content = pages.get(pageIndex);
// send header
Message.PERMISSION_INFO.send(sender, holder.getFriendlyName(), page, pages.size(), nodes.size());
// send content
for (LocalizedNode node : content) {
String s = "&3> " + (node.getValuePrimitive() ? "&a" : "&c") + node.getPermission() + (sender.isConsole() ? " &7(" + node.getValuePrimitive() + "&7)" : "") + CommandUtils.getAppendableNodeContextString(node);
if (node.isTemporary()) {
s += "\n&2- expires in " + DateUtil.formatDateDiff(node.getExpiryUnixTime());
}
TextComponent message = TextUtils.fromLegacy(s, Constants.FORMAT_CHAR).toBuilder().applyDeep(makeFancy(holder, label, node)).build();
sender.sendMessage(message);
} }
return CommandResult.SUCCESS; return CommandResult.SUCCESS;
} }
private static Map.Entry<Component, String> nodesToMessage(boolean temp, String filter, SortedSet<LocalizedNode> nodes, PermissionHolder holder, String label, int pageNumber, boolean console) { private static final Comparator<LocalizedNode> ALPHABETICAL_NODE_COMPARATOR = (o1, o2) -> {
// parse the filter int i = CollationKeyCache.compareStrings(o1.getPermission(), o2.getPermission());
String nodeFilter = null; if (i != 0) {
Map.Entry<String, String> contextFilter = null; return i;
if (filter != null) {
int index = filter.indexOf('=');
context:
if (index != -1) {
String key = filter.substring(0, index);
if (key.equals("")) break context;
String value = filter.substring(index + 1);
if (value.equals("")) break context;
contextFilter = Maps.immutableEntry(key, value);
}
if (contextFilter == null) {
nodeFilter = filter;
}
} }
List<Node> l = new ArrayList<>(); // fallback to priority
for (Node node : nodes) { return NodeWithContextComparator.reverse().compare(o1, o2);
if ((node.isGroupNode() && node.getValuePrimitive()) || node.isPrefix() || node.isSuffix() || node.isMeta()) continue; };
// check against filters
if (nodeFilter != null && !node.getPermission().startsWith(nodeFilter)) continue;
if (contextFilter != null && !node.getFullContexts().hasIgnoreCase(contextFilter.getKey(), contextFilter.getValue())) continue;
if (temp != node.isTemporary()) continue;
l.add(node);
}
if (l.isEmpty()) {
return Maps.immutableEntry(TextComponent.builder("None").color(TextColor.DARK_AQUA).build(), null);
}
int index = pageNumber - 1;
List<List<Node>> pages = CommandUtils.divideList(l, 15);
if (index < 0 || index >= pages.size()) {
pageNumber = 1;
index = 0;
}
List<Node> page = pages.get(index);
TextComponent.Builder message = TextComponent.builder("");
String title = "&7(showing page &f" + pageNumber + "&7 of &f" + pages.size() + "&7 - &f" + l.size() + "&7 entries";
if (filter != null) {
title += " - filtered by &f\"" + filter + "\"&7)";
} else {
title += ")";
}
for (Node node : page) {
String s = "&3> " + (node.getValuePrimitive() ? "&a" : "&c") + node.getPermission() + (console ? " &7(" + node.getValuePrimitive() + "&7)" : "") + CommandUtils.getAppendableNodeContextString(node) + "\n";
if (temp) {
s += "&2- expires in " + DateUtil.formatDateDiff(node.getExpiryUnixTime()) + "\n";
}
message.append(TextUtils.fromLegacy(s, Constants.FORMAT_CHAR).toBuilder().applyDeep(makeFancy(holder, label, node)).build());
}
return Maps.immutableEntry(message.build(), title);
}
private static Consumer<BuildableComponent.Builder<?, ?>> makeFancy(PermissionHolder holder, String label, Node node) { private static Consumer<BuildableComponent.Builder<?, ?>> makeFancy(PermissionHolder holder, String label, Node node) {
HoverEvent hoverEvent = new HoverEvent(HoverEvent.Action.SHOW_TEXT, TextUtils.fromLegacy(TextUtils.joinNewline( HoverEvent hoverEvent = new HoverEvent(HoverEvent.Action.SHOW_TEXT, TextUtils.fromLegacy(TextUtils.joinNewline(
@ -187,12 +147,12 @@ public class PermissionInfo extends SharedSubCommand {
"¥7Click to remove this node from " + holder.getFriendlyName() "¥7Click to remove this node from " + holder.getFriendlyName()
), '¥')); ), '¥'));
boolean group = !(holder instanceof User); String command = "/" + label + " " + NodeFactory.nodeAsCommand(node, holder.getType().isGroup() ? holder.getObjectName() : holder.getFriendlyName(), holder.getType(), false);
String command = "/" + label + " " + NodeFactory.nodeAsCommand(node, group ? holder.getObjectName() : holder.getFriendlyName(), group, false); ClickEvent clickEvent = new ClickEvent(ClickEvent.Action.SUGGEST_COMMAND, command);
return component -> { return component -> {
component.hoverEvent(hoverEvent); component.hoverEvent(hoverEvent);
component.clickEvent(new ClickEvent(ClickEvent.Action.SUGGEST_COMMAND, command)); component.clickEvent(clickEvent);
}; };
} }
} }

View File

@ -25,6 +25,8 @@
package me.lucko.luckperms.common.commands.impl.group; package me.lucko.luckperms.common.commands.impl.group;
import com.github.benmanes.caffeine.cache.Caffeine;
import com.github.benmanes.caffeine.cache.LoadingCache;
import com.google.common.collect.Maps; import com.google.common.collect.Maps;
import me.lucko.luckperms.api.HeldPermission; import me.lucko.luckperms.api.HeldPermission;
@ -44,20 +46,17 @@ import me.lucko.luckperms.common.locale.Message;
import me.lucko.luckperms.common.model.Group; import me.lucko.luckperms.common.model.Group;
import me.lucko.luckperms.common.node.NodeFactory; import me.lucko.luckperms.common.node.NodeFactory;
import me.lucko.luckperms.common.plugin.LuckPermsPlugin; import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
import me.lucko.luckperms.common.references.HolderType;
import me.lucko.luckperms.common.utils.DateUtil; import me.lucko.luckperms.common.utils.DateUtil;
import me.lucko.luckperms.common.utils.Predicates; import me.lucko.luckperms.common.utils.Predicates;
import me.lucko.luckperms.common.utils.TextUtils; import me.lucko.luckperms.common.utils.TextUtils;
import net.kyori.text.BuildableComponent; import net.kyori.text.BuildableComponent;
import net.kyori.text.Component;
import net.kyori.text.TextComponent; import net.kyori.text.TextComponent;
import net.kyori.text.event.ClickEvent; import net.kyori.text.event.ClickEvent;
import net.kyori.text.event.HoverEvent; import net.kyori.text.event.HoverEvent;
import net.kyori.text.format.TextColor;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.UUID; import java.util.UUID;
@ -90,96 +89,60 @@ public class GroupListMembers extends SubCommand<Group> {
Message.SEARCH_RESULT.send(sender, users + groups, users, groups); Message.SEARCH_RESULT.send(sender, users + groups, users, groups);
Map<UUID, String> uuidLookups = new HashMap<>(); if (!matchedUsers.isEmpty()) {
Function<UUID, String> lookupFunc = uuid -> uuidLookups.computeIfAbsent(uuid, u -> { LoadingCache<UUID, String> uuidLookups = Caffeine.newBuilder()
String s = plugin.getStorage().getName(u).join(); .build(u -> {
if (s == null || s.isEmpty() || s.equals("null")) { String s = plugin.getStorage().getName(u).join();
s = u.toString(); if (s == null || s.isEmpty() || s.equals("null")) {
} s = u.toString();
return s; }
}); return s;
});
Map.Entry<Component, String> msgUsers = searchUserResultToMessage(matchedUsers, lookupFunc, label, page); sendResult(sender, matchedUsers, uuidLookups::get, Message.SEARCH_SHOWING_USERS, HolderType.USER, label, page);
Map.Entry<Component, String> msgGroups = searchGroupResultToMessage(matchedGroups, label, page);
if (msgUsers.getValue() != null) {
Message.SEARCH_SHOWING_USERS_WITH_PAGE.send(sender, msgUsers.getValue());
sender.sendMessage(msgUsers.getKey());
} else {
Message.SEARCH_SHOWING_USERS.send(sender);
sender.sendMessage(msgUsers.getKey());
} }
if (msgGroups.getValue() != null) { if (!matchedGroups.isEmpty()) {
Message.SEARCH_SHOWING_GROUPS_WITH_PAGE.send(sender, msgGroups.getValue()); sendResult(sender, matchedGroups, Function.identity(), Message.SEARCH_SHOWING_GROUPS, HolderType.GROUP, label, page);
sender.sendMessage(msgGroups.getKey());
} else {
Message.SEARCH_SHOWING_GROUPS.send(sender);
sender.sendMessage(msgGroups.getKey());
} }
return CommandResult.SUCCESS; return CommandResult.SUCCESS;
} }
private static Map.Entry<Component, String> searchUserResultToMessage(List<HeldPermission<UUID>> results, Function<UUID, String> uuidLookup, String label, int pageNumber) { private static <T> void sendResult(Sender sender, List<HeldPermission<T>> results, Function<T, String> lookupFunction, Message headerMessage, HolderType holderType, String label, int page) {
if (results.isEmpty()) { results = new ArrayList<>(results);
return Maps.immutableEntry(TextComponent.builder("None").color(TextColor.DARK_AQUA).build(), null);
// we need a deterministic sort order
// even though we're comparing uuids here in some cases - it doesn't matter
// the import thing is that the order is the same each time the command is executed
results.sort((o1, o2) -> {
Comparable h1 = (Comparable) o1.getHolder();
Comparable h2 = (Comparable) o2.getHolder();
//noinspection unchecked
return h1.compareTo(h2);
});
int pageIndex = page - 1;
List<List<HeldPermission<T>>> pages = CommandUtils.divideList(results, 15);
if (pageIndex < 0 || pageIndex >= pages.size()) {
page = 1;
pageIndex = 0;
} }
List<HeldPermission<UUID>> sorted = new ArrayList<>(results); List<HeldPermission<T>> content = pages.get(pageIndex);
sorted.sort(Comparator.comparing(HeldPermission::getHolder));
int index = pageNumber - 1; List<Map.Entry<String, HeldPermission<T>>> mappedContent = content.stream()
List<List<HeldPermission<UUID>>> pages = CommandUtils.divideList(sorted, 15); .map(hp -> Maps.immutableEntry(lookupFunction.apply(hp.getHolder()), hp))
if (index < 0 || index >= pages.size()) {
pageNumber = 1;
index = 0;
}
List<HeldPermission<UUID>> page = pages.get(index);
List<Map.Entry<String, HeldPermission<UUID>>> uuidMappedPage = page.stream()
.map(hp -> Maps.immutableEntry(uuidLookup.apply(hp.getHolder()), hp))
.collect(Collectors.toList()); .collect(Collectors.toList());
TextComponent.Builder message = TextComponent.builder(""); // send header
String title = "&7(page &f" + pageNumber + "&7 of &f" + pages.size() + "&7 - &f" + sorted.size() + "&7 entries)"; headerMessage.send(sender, page, pages.size(), results.size());
for (Map.Entry<String, HeldPermission<UUID>> ent : uuidMappedPage) { for (Map.Entry<String, HeldPermission<T>> ent : mappedContent) {
String s = "&3> &b" + ent.getKey() + " " + getNodeExpiryString(ent.getValue().asNode()) + CommandUtils.getAppendableNodeContextString(ent.getValue().asNode()) + "\n"; String s = "&3> &b" + ent.getKey() + " " + getNodeExpiryString(ent.getValue().asNode()) + CommandUtils.getAppendableNodeContextString(ent.getValue().asNode());
message.append(TextUtils.fromLegacy(s, Constants.FORMAT_CHAR).toBuilder().applyDeep(makeFancy(ent.getKey(), false, label, ent.getValue())).build()); TextComponent message = TextUtils.fromLegacy(s, Constants.FORMAT_CHAR).toBuilder().applyDeep(makeFancy(ent.getKey(), holderType, label, ent.getValue())).build();
sender.sendMessage(message);
} }
return Maps.immutableEntry(message.build(), title);
}
private static Map.Entry<Component, String> searchGroupResultToMessage(List<HeldPermission<String>> results, String label, int pageNumber) {
if (results.isEmpty()) {
return Maps.immutableEntry(TextComponent.builder("None").color(TextColor.DARK_AQUA).build(), null);
}
List<HeldPermission<String>> sorted = new ArrayList<>(results);
sorted.sort(Comparator.comparing(HeldPermission::getHolder));
int index = pageNumber - 1;
List<List<HeldPermission<String>>> pages = CommandUtils.divideList(sorted, 15);
if (index < 0 || index >= pages.size()) {
pageNumber = 1;
index = 0;
}
List<HeldPermission<String>> page = pages.get(index);
TextComponent.Builder message = TextComponent.builder("");
String title = "&7(page &f" + pageNumber + "&7 of &f" + pages.size() + "&7 - &f" + sorted.size() + "&7 entries)";
for (HeldPermission<String> ent : page) {
String s = "&3> &b" + ent.getHolder() + " " + getNodeExpiryString(ent.asNode()) + CommandUtils.getAppendableNodeContextString(ent.asNode()) + "\n";
message.append(TextUtils.fromLegacy(s, Constants.FORMAT_CHAR).toBuilder().applyDeep(makeFancy(ent.getHolder(), true, label, ent)).build());
}
return Maps.immutableEntry(message.build(), title);
} }
private static String getNodeExpiryString(Node node) { private static String getNodeExpiryString(Node node) {
@ -190,18 +153,19 @@ public class GroupListMembers extends SubCommand<Group> {
return " &8(&7expires in " + DateUtil.formatDateDiff(node.getExpiryUnixTime()) + "&8)"; return " &8(&7expires in " + DateUtil.formatDateDiff(node.getExpiryUnixTime()) + "&8)";
} }
private static Consumer<BuildableComponent.Builder<? ,?>> makeFancy(String holderName, boolean group, String label, HeldPermission<?> perm) { private static Consumer<BuildableComponent.Builder<? ,?>> makeFancy(String holderName, HolderType holderType, String label, HeldPermission<?> perm) {
HoverEvent hoverEvent = new HoverEvent(HoverEvent.Action.SHOW_TEXT, TextUtils.fromLegacy(TextUtils.joinNewline( HoverEvent hoverEvent = new HoverEvent(HoverEvent.Action.SHOW_TEXT, TextUtils.fromLegacy(TextUtils.joinNewline(
"&3> " + (perm.asNode().getValuePrimitive() ? "&a" : "&c") + perm.asNode().getGroupName(), "&3> &b" + perm.asNode().getGroupName(),
" ", " ",
"&7Click to remove this parent from " + holderName "&7Click to remove this parent from " + holderName
), Constants.FORMAT_CHAR)); ), Constants.FORMAT_CHAR));
String command = "/" + label + " " + NodeFactory.nodeAsCommand(perm.asNode(), holderName, group, false); String command = "/" + label + " " + NodeFactory.nodeAsCommand(perm.asNode(), holderName, holderType, false);
ClickEvent clickEvent = new ClickEvent(ClickEvent.Action.SUGGEST_COMMAND, command);
return component -> { return component -> {
component.hoverEvent(hoverEvent); component.hoverEvent(hoverEvent);
component.clickEvent(new ClickEvent(ClickEvent.Action.SUGGEST_COMMAND, command)); component.clickEvent(clickEvent);
}; };
} }
} }

View File

@ -25,6 +25,8 @@
package me.lucko.luckperms.common.commands.impl.misc; package me.lucko.luckperms.common.commands.impl.misc;
import com.github.benmanes.caffeine.cache.Caffeine;
import com.github.benmanes.caffeine.cache.LoadingCache;
import com.google.common.collect.Maps; import com.google.common.collect.Maps;
import me.lucko.luckperms.api.HeldPermission; import me.lucko.luckperms.api.HeldPermission;
@ -43,20 +45,17 @@ import me.lucko.luckperms.common.locale.LocaleManager;
import me.lucko.luckperms.common.locale.Message; import me.lucko.luckperms.common.locale.Message;
import me.lucko.luckperms.common.node.NodeFactory; import me.lucko.luckperms.common.node.NodeFactory;
import me.lucko.luckperms.common.plugin.LuckPermsPlugin; import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
import me.lucko.luckperms.common.references.HolderType;
import me.lucko.luckperms.common.utils.DateUtil; import me.lucko.luckperms.common.utils.DateUtil;
import me.lucko.luckperms.common.utils.Predicates; import me.lucko.luckperms.common.utils.Predicates;
import me.lucko.luckperms.common.utils.TextUtils; import me.lucko.luckperms.common.utils.TextUtils;
import net.kyori.text.BuildableComponent; import net.kyori.text.BuildableComponent;
import net.kyori.text.Component;
import net.kyori.text.TextComponent; import net.kyori.text.TextComponent;
import net.kyori.text.event.ClickEvent; import net.kyori.text.event.ClickEvent;
import net.kyori.text.event.HoverEvent; import net.kyori.text.event.HoverEvent;
import net.kyori.text.format.TextColor;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.UUID; import java.util.UUID;
@ -84,32 +83,20 @@ public class SearchCommand extends SingleCommand {
Message.SEARCH_RESULT.send(sender, users + groups, users, groups); Message.SEARCH_RESULT.send(sender, users + groups, users, groups);
Map<UUID, String> uuidLookups = new HashMap<>(); if (!matchedUsers.isEmpty()) {
Function<UUID, String> lookupFunc = uuid -> uuidLookups.computeIfAbsent(uuid, u -> { LoadingCache<UUID, String> uuidLookups = Caffeine.newBuilder()
String s = plugin.getStorage().getName(u).join(); .build(u -> {
if (s == null || s.isEmpty() || s.equals("null")) { String s = plugin.getStorage().getName(u).join();
s = u.toString(); if (s == null || s.isEmpty() || s.equals("null")) {
} s = u.toString();
return s; }
}); return s;
});
Map.Entry<Component, String> msgUsers = searchUserResultToMessage(matchedUsers, lookupFunc, label, page); sendResult(sender, matchedUsers, uuidLookups::get, Message.SEARCH_SHOWING_USERS, HolderType.USER, label, page);
Map.Entry<Component, String> msgGroups = searchGroupResultToMessage(matchedGroups, label, page);
if (msgUsers.getValue() != null) {
Message.SEARCH_SHOWING_USERS_WITH_PAGE.send(sender, msgUsers.getValue());
sender.sendMessage(msgUsers.getKey());
} else {
Message.SEARCH_SHOWING_USERS.send(sender);
sender.sendMessage(msgUsers.getKey());
} }
if (msgGroups.getValue() != null) { if (!matchedGroups.isEmpty()) {
Message.SEARCH_SHOWING_GROUPS_WITH_PAGE.send(sender, msgGroups.getValue()); sendResult(sender, matchedGroups, Function.identity(), Message.SEARCH_SHOWING_GROUPS, HolderType.GROUP, label, page);
sender.sendMessage(msgGroups.getKey());
} else {
Message.SEARCH_SHOWING_GROUPS.send(sender);
sender.sendMessage(msgGroups.getKey());
} }
return CommandResult.SUCCESS; return CommandResult.SUCCESS;
@ -120,65 +107,41 @@ public class SearchCommand extends SingleCommand {
return SubCommand.getPermissionTabComplete(args, plugin.getPermissionVault()); return SubCommand.getPermissionTabComplete(args, plugin.getPermissionVault());
} }
private static Map.Entry<Component, String> searchUserResultToMessage(List<HeldPermission<UUID>> results, Function<UUID, String> uuidLookup, String label, int pageNumber) { private static <T> void sendResult(Sender sender, List<HeldPermission<T>> results, Function<T, String> lookupFunction, Message headerMessage, HolderType holderType, String label, int page) {
if (results.isEmpty()) { results = new ArrayList<>(results);
return Maps.immutableEntry(TextComponent.builder("None").color(TextColor.DARK_AQUA).build(), null);
// we need a deterministic sort order
// even though we're comparing uuids here in some cases - it doesn't matter
// the import thing is that the order is the same each time the command is executed
results.sort((o1, o2) -> {
Comparable h1 = (Comparable) o1.getHolder();
Comparable h2 = (Comparable) o2.getHolder();
//noinspection unchecked
return h1.compareTo(h2);
});
int pageIndex = page - 1;
List<List<HeldPermission<T>>> pages = CommandUtils.divideList(results, 15);
if (pageIndex < 0 || pageIndex >= pages.size()) {
page = 1;
pageIndex = 0;
} }
List<HeldPermission<UUID>> sorted = new ArrayList<>(results); List<HeldPermission<T>> content = pages.get(pageIndex);
sorted.sort(Comparator.comparing(HeldPermission::getHolder));
int index = pageNumber - 1; List<Map.Entry<String, HeldPermission<T>>> mappedContent = content.stream()
List<List<HeldPermission<UUID>>> pages = CommandUtils.divideList(sorted, 15); .map(hp -> Maps.immutableEntry(lookupFunction.apply(hp.getHolder()), hp))
if (index < 0 || index >= pages.size()) {
pageNumber = 1;
index = 0;
}
List<HeldPermission<UUID>> page = pages.get(index);
List<Map.Entry<String, HeldPermission<UUID>>> uuidMappedPage = page.stream()
.map(hp -> Maps.immutableEntry(uuidLookup.apply(hp.getHolder()), hp))
.collect(Collectors.toList()); .collect(Collectors.toList());
TextComponent.Builder message = TextComponent.builder(""); // send header
String title = "&7(page &f" + pageNumber + "&7 of &f" + pages.size() + "&7 - &f" + sorted.size() + "&7 entries)"; headerMessage.send(sender, page, pages.size(), results.size());
for (Map.Entry<String, HeldPermission<UUID>> ent : uuidMappedPage) { for (Map.Entry<String, HeldPermission<T>> ent : mappedContent) {
String s = "&3> &b" + ent.getKey() + " &7- " + (ent.getValue().getValue() ? "&a" : "&c") + ent.getValue().getValue() + getNodeExpiryString(ent.getValue().asNode()) + CommandUtils.getAppendableNodeContextString(ent.getValue().asNode()) + "\n"; String s = "&3> &b" + ent.getKey() + " &7- " + (ent.getValue().getValue() ? "&a" : "&c") + ent.getValue().getValue() + getNodeExpiryString(ent.getValue().asNode()) + CommandUtils.getAppendableNodeContextString(ent.getValue().asNode());
message.append(TextUtils.fromLegacy(s, Constants.FORMAT_CHAR).toBuilder().applyDeep(makeFancy(ent.getKey(), false, label, ent.getValue())).build()); TextComponent message = TextUtils.fromLegacy(s, Constants.FORMAT_CHAR).toBuilder().applyDeep(makeFancy(ent.getKey(), holderType, label, ent.getValue())).build();
sender.sendMessage(message);
} }
return Maps.immutableEntry(message.build(), title);
}
private static Map.Entry<Component, String> searchGroupResultToMessage(List<HeldPermission<String>> results, String label, int pageNumber) {
if (results.isEmpty()) {
return Maps.immutableEntry(TextComponent.builder("None").color(TextColor.DARK_AQUA).build(), null);
}
List<HeldPermission<String>> sorted = new ArrayList<>(results);
sorted.sort(Comparator.comparing(HeldPermission::getHolder));
int index = pageNumber - 1;
List<List<HeldPermission<String>>> pages = CommandUtils.divideList(sorted, 15);
if (index < 0 || index >= pages.size()) {
pageNumber = 1;
index = 0;
}
List<HeldPermission<String>> page = pages.get(index);
TextComponent.Builder message = TextComponent.builder("");
String title = "&7(page &f" + pageNumber + "&7 of &f" + pages.size() + "&7 - &f" + sorted.size() + "&7 entries)";
for (HeldPermission<String> ent : page) {
String s = "&3> &b" + ent.getHolder() + " &7- " + (ent.getValue() ? "&a" : "&c") + ent.getValue() + getNodeExpiryString(ent.asNode()) + CommandUtils.getAppendableNodeContextString(ent.asNode()) + "\n";
message.append(TextUtils.fromLegacy(s, Constants.FORMAT_CHAR).toBuilder().applyDeep(makeFancy(ent.getHolder(), true, label, ent)).build());
}
return Maps.immutableEntry(message.build(), title);
} }
private static String getNodeExpiryString(Node node) { private static String getNodeExpiryString(Node node) {
@ -189,18 +152,19 @@ public class SearchCommand extends SingleCommand {
return " &8(&7expires in " + DateUtil.formatDateDiff(node.getExpiryUnixTime()) + "&8)"; return " &8(&7expires in " + DateUtil.formatDateDiff(node.getExpiryUnixTime()) + "&8)";
} }
private static Consumer<BuildableComponent.Builder<?, ?>> makeFancy(String holderName, boolean group, String label, HeldPermission<?> perm) { private static Consumer<BuildableComponent.Builder<?, ?>> makeFancy(String holderName, HolderType holderType, String label, HeldPermission<?> perm) {
HoverEvent hoverEvent = new HoverEvent(HoverEvent.Action.SHOW_TEXT, TextUtils.fromLegacy(TextUtils.joinNewline( HoverEvent hoverEvent = new HoverEvent(HoverEvent.Action.SHOW_TEXT, TextUtils.fromLegacy(TextUtils.joinNewline(
"&3> " + (perm.asNode().getValuePrimitive() ? "&a" : "&c") + perm.asNode().getPermission(), "&3> " + (perm.asNode().getValuePrimitive() ? "&a" : "&c") + perm.asNode().getPermission(),
" ", " ",
"&7Click to remove this node from " + holderName "&7Click to remove this node from " + holderName
), Constants.FORMAT_CHAR)); ), Constants.FORMAT_CHAR));
String command = "/" + label + " " + NodeFactory.nodeAsCommand(perm.asNode(), holderName, group, false); String command = "/" + label + " " + NodeFactory.nodeAsCommand(perm.asNode(), holderName, holderType, false);
ClickEvent clickEvent = new ClickEvent(ClickEvent.Action.SUGGEST_COMMAND, command);
return component -> { return component -> {
component.hoverEvent(hoverEvent); component.hoverEvent(hoverEvent);
component.clickEvent(new ClickEvent(ClickEvent.Action.SUGGEST_COMMAND, command)); component.clickEvent(clickEvent);
}; };
} }
} }

View File

@ -0,0 +1,62 @@
/*
* Copyright (c) 2017 Lucko (Luck) <luck@lucko.me>
*
* 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.utils;
import lombok.AllArgsConstructor;
import lombok.Getter;
import java.util.List;
@Getter
@AllArgsConstructor
public class SortMode {
public static SortMode determine(List<String> args) {
SortType type = SortType.PRIORITY;
boolean ascending = true;
for (String arg : args) {
if (arg.equals("!") || arg.equalsIgnoreCase("reverse") || arg.equalsIgnoreCase("reversed")) {
ascending = false;
} else if (arg.equalsIgnoreCase("priority")) {
type = SortType.PRIORITY;
ascending = true;
} else if (arg.equalsIgnoreCase("!priority")) {
type = SortType.PRIORITY;
ascending = false;
} else if (arg.equalsIgnoreCase("alphabetically") || arg.equalsIgnoreCase("abc")) {
type = SortType.ALPHABETICALLY;
ascending = true;
} else if (arg.equalsIgnoreCase("!alphabetically") || arg.equalsIgnoreCase("!abc")) {
type = SortType.ALPHABETICALLY;
ascending = false;
} else {
continue;
}
break;
}
return new SortMode(type, ascending);
}
private final SortType type;
private final boolean ascending;
}

View File

@ -0,0 +1,34 @@
/*
* Copyright (c) 2017 Lucko (Luck) <luck@lucko.me>
*
* 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.utils;
public enum SortType {
PRIORITY,
ALPHABETICALLY;
@Override
public String toString() {
return name().toLowerCase();
}
}

View File

@ -191,7 +191,7 @@ public enum CommandSpec {
PERMISSION_INFO("Lists the permission nodes the object has", PERMISSION_INFO("Lists the permission nodes the object has",
Arg.list( Arg.list(
Arg.create("page", false, "the page to view"), Arg.create("page", false, "the page to view"),
Arg.create("filter", false, "the string to filter by") Arg.create("sort mode", false, "how to sort the entries")
) )
), ),
PERMISSION_SET("Sets a permission for the object", PERMISSION_SET("Sets a permission for the object",
@ -234,7 +234,12 @@ public enum CommandSpec {
) )
), ),
PARENT_INFO("Lists the groups that this object inherits from"), PARENT_INFO("Lists the groups that this object inherits from",
Arg.list(
Arg.create("page", false, "the page to view"),
Arg.create("sort mode", false, "how to sort the entries")
)
),
PARENT_SET("Removes all other groups the object inherits already and adds them to the one given", PARENT_SET("Removes all other groups the object inherits already and adds them to the one given",
Arg.list( Arg.list(
Arg.create("group", true, "the group to set to"), Arg.create("group", true, "the group to set to"),

View File

@ -113,10 +113,9 @@ public enum Message {
SEARCH_SEARCHING("&aSearching for users and groups with &b{}&a...", true), SEARCH_SEARCHING("&aSearching for users and groups with &b{}&a...", true),
SEARCH_SEARCHING_MEMBERS("&aSearching for users and groups who inherit from &b{}&a...", true), SEARCH_SEARCHING_MEMBERS("&aSearching for users and groups who inherit from &b{}&a...", true),
SEARCH_RESULT("&aFound &b{}&a entries from &b{}&a users and &b{}&a groups.", true), SEARCH_RESULT("&aFound &b{}&a entries from &b{}&a users and &b{}&a groups.", true),
SEARCH_SHOWING_USERS("&bShowing user entries:", true),
SEARCH_SHOWING_GROUPS("&bShowing group entries:", true), SEARCH_SHOWING_USERS("&bShowing user entries: &7(showing page &f{}&7 of &f{}&7 - &f{}&7 entries)", true),
SEARCH_SHOWING_USERS_WITH_PAGE("&bShowing user entries: {}", true), SEARCH_SHOWING_GROUPS("&bShowing group entries: &7(showing page &f{}&7 of &f{}&7 - &f{}&7 entries)", true),
SEARCH_SHOWING_GROUPS_WITH_PAGE("&bShowing group entries: {}", true),
APPLY_EDITS_INVALID_CODE("&cInvalid code. &7({})", true), APPLY_EDITS_INVALID_CODE("&cInvalid code. &7({})", true),
APPLY_EDITS_UNABLE_TO_READ("&cUnable to read data using the given code. &7({})", true), APPLY_EDITS_UNABLE_TO_READ("&cUnable to read data using the given code. &7({})", true),
@ -198,14 +197,14 @@ public enum Message {
TRACKS_LIST("&aTracks: {}", true), TRACKS_LIST("&aTracks: {}", true),
LISTNODES("&b{}'s Permissions:", true), PERMISSION_INFO("&b{}'s Permissions: &7(showing page &f{}&7 of &f{}&7 - &f{}&7 entries)", true),
LISTNODES_WITH_PAGE("&b{}'s Permissions: {}", true), PERMISSION_INFO_NO_DATA("&b{}&a does not have any permissions set.", true),
LISTNODES_TEMP("&b{}'s Temporary Permissions:", true),
LISTNODES_TEMP_WITH_PAGE("&b{}'s Temporary Permissions: {}", true),
LISTPARENTS("&b{}'s Parent Groups:", true), PARENT_INFO("&b{}'s Parents: &7(showing page &f{}&7 of &f{}&7 - &f{}&7 entries)", true),
LISTPARENTS_TEMP("&b{}'s Temporary Parent Groups:", true), PARENT_INFO_NO_DATA("&b{}&a does not have any parents defined.", true),
LIST_TRACKS("&b{}'s Tracks:" + "\n" + "{}", true),
LIST_TRACKS("&b{}'s Tracks:", true),
LIST_TRACKS_ENTRY("&a{}: {}", false),
LIST_TRACKS_EMPTY("&b{}&a is not on any tracks.", true), LIST_TRACKS_EMPTY("&b{}&a is not on any tracks.", true),
CONTEXT_PAIR_INLINE("&3{}=&b{}", false), CONTEXT_PAIR_INLINE("&3{}=&b{}", false),

View File

@ -37,6 +37,7 @@ import me.lucko.luckperms.common.caching.GroupCachedData;
import me.lucko.luckperms.common.config.ConfigKeys; import me.lucko.luckperms.common.config.ConfigKeys;
import me.lucko.luckperms.common.plugin.LuckPermsPlugin; import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
import me.lucko.luckperms.common.references.GroupReference; import me.lucko.luckperms.common.references.GroupReference;
import me.lucko.luckperms.common.references.HolderType;
import me.lucko.luckperms.common.references.Identifiable; import me.lucko.luckperms.common.references.Identifiable;
import java.util.Optional; import java.util.Optional;
@ -111,6 +112,11 @@ public class Group extends PermissionHolder implements Identifiable<String> {
return GroupReference.of(getId()); return GroupReference.of(getId());
} }
@Override
public HolderType getType() {
return HolderType.GROUP;
}
private CompletableFuture<Void> reloadCachedData() { private CompletableFuture<Void> reloadCachedData() {
return CompletableFuture.allOf(cachedData.reloadPermissions(), cachedData.reloadMeta()).thenAccept(n -> { return CompletableFuture.allOf(cachedData.reloadPermissions(), cachedData.reloadMeta()).thenAccept(n -> {
getPlugin().getApiProvider().getEventFactory().handleGroupDataRecalculate(this, cachedData); getPlugin().getApiProvider().getEventFactory().handleGroupDataRecalculate(this, cachedData);

View File

@ -64,6 +64,7 @@ import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
import me.lucko.luckperms.common.primarygroup.GroupInheritanceComparator; import me.lucko.luckperms.common.primarygroup.GroupInheritanceComparator;
import me.lucko.luckperms.common.references.GroupReference; import me.lucko.luckperms.common.references.GroupReference;
import me.lucko.luckperms.common.references.HolderReference; import me.lucko.luckperms.common.references.HolderReference;
import me.lucko.luckperms.common.references.HolderType;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
@ -240,7 +241,7 @@ public abstract class PermissionHolder {
protected void declareState() { protected void declareState() {
/* only declare state of groups. the state manager isn't really being used now the caches in this class /* only declare state of groups. the state manager isn't really being used now the caches in this class
are gone, but it's useful for command output. */ are gone, but it's useful for command output. */
if (this instanceof Group) { if (this.getType().isGroup()) {
plugin.getCachedStateManager().putAll(toReference(), getGroupReferences()); plugin.getCachedStateManager().putAll(toReference(), getGroupReferences());
} }
} }
@ -268,6 +269,13 @@ public abstract class PermissionHolder {
*/ */
public abstract HolderReference<?, ?> toReference(); public abstract HolderReference<?, ?> toReference();
/**
* Returns the type of this PermissionHolder.
*
* @return this holders type
*/
public abstract HolderType getType();
/** /**
* Gets the API delegate for this instance * Gets the API delegate for this instance
* *
@ -543,7 +551,7 @@ public abstract class PermissionHolder {
excludedGroups = new HashSet<>(); excludedGroups = new HashSet<>();
} }
if (this instanceof Group) { if (this.getType().isGroup()) {
excludedGroups.add(getObjectName().toLowerCase()); excludedGroups.add(getObjectName().toLowerCase());
} }
@ -619,7 +627,7 @@ public abstract class PermissionHolder {
excludedGroups = new HashSet<>(); excludedGroups = new HashSet<>();
} }
if (this instanceof Group) { if (this.getType().isGroup()) {
excludedGroups.add(getObjectName().toLowerCase()); excludedGroups.add(getObjectName().toLowerCase());
} }
@ -768,7 +776,7 @@ public abstract class PermissionHolder {
excludedGroups = new HashSet<>(); excludedGroups = new HashSet<>();
} }
if (this instanceof Group) { if (this.getType().isGroup()) {
excludedGroups.add(getObjectName().toLowerCase()); excludedGroups.add(getObjectName().toLowerCase());
} }
@ -830,7 +838,7 @@ public abstract class PermissionHolder {
excludedGroups = new HashSet<>(); excludedGroups = new HashSet<>();
} }
if (this instanceof Group) { if (this.getType().isGroup()) {
excludedGroups.add(getObjectName().toLowerCase()); excludedGroups.add(getObjectName().toLowerCase());
} }
@ -956,7 +964,7 @@ public abstract class PermissionHolder {
* @return a tristate * @return a tristate
*/ */
public Tristate hasPermission(Node node, boolean checkTransient) { public Tristate hasPermission(Node node, boolean checkTransient) {
if (this instanceof Group && node.isGroupNode() && node.getGroupName().equalsIgnoreCase(getObjectName())) { if (this.getType().isGroup() && node.isGroupNode() && node.getGroupName().equalsIgnoreCase(getObjectName())) {
return Tristate.TRUE; return Tristate.TRUE;
} }
@ -1327,7 +1335,7 @@ public abstract class PermissionHolder {
nodesLock.unlock(); nodesLock.unlock();
} }
if (this instanceof User && giveDefault) { if (this.getType().isUser() && giveDefault) {
plugin.getUserManager().giveDefaultIfNeeded((User) this, false); plugin.getUserManager().giveDefaultIfNeeded((User) this, false);
} }
@ -1355,7 +1363,7 @@ public abstract class PermissionHolder {
nodesLock.unlock(); nodesLock.unlock();
} }
if (this instanceof User && giveDefault) { if (this.getType().isUser() && giveDefault) {
plugin.getUserManager().giveDefaultIfNeeded((User) this, false); plugin.getUserManager().giveDefaultIfNeeded((User) this, false);
} }
invalidateCache(); invalidateCache();
@ -1501,7 +1509,7 @@ public abstract class PermissionHolder {
} }
private OptionalInt calculateWeight() { private OptionalInt calculateWeight() {
if (this instanceof User) return OptionalInt.empty(); if (this.getType().isUser()) return OptionalInt.empty();
boolean seen = false; boolean seen = false;
int best = 0; int best = 0;

View File

@ -36,6 +36,7 @@ import me.lucko.luckperms.common.caching.UserCachedData;
import me.lucko.luckperms.common.config.ConfigKeys; import me.lucko.luckperms.common.config.ConfigKeys;
import me.lucko.luckperms.common.plugin.LuckPermsPlugin; import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
import me.lucko.luckperms.common.primarygroup.PrimaryGroupHolder; import me.lucko.luckperms.common.primarygroup.PrimaryGroupHolder;
import me.lucko.luckperms.common.references.HolderType;
import me.lucko.luckperms.common.references.Identifiable; import me.lucko.luckperms.common.references.Identifiable;
import me.lucko.luckperms.common.references.UserIdentifier; import me.lucko.luckperms.common.references.UserIdentifier;
import me.lucko.luckperms.common.references.UserReference; import me.lucko.luckperms.common.references.UserReference;
@ -168,6 +169,11 @@ public class User extends PermissionHolder implements Identifiable<UserIdentifie
return UserReference.of(getId()); return UserReference.of(getId());
} }
@Override
public HolderType getType() {
return HolderType.USER;
}
/** /**
* Sets up the UserData cache * Sets up the UserData cache
* Blocking call. * Blocking call.

View File

@ -34,6 +34,7 @@ import me.lucko.luckperms.api.ChatMetaType;
import me.lucko.luckperms.api.Node; import me.lucko.luckperms.api.Node;
import me.lucko.luckperms.api.context.ContextSet; import me.lucko.luckperms.api.context.ContextSet;
import me.lucko.luckperms.common.model.Group; import me.lucko.luckperms.common.model.Group;
import me.lucko.luckperms.common.references.HolderType;
import me.lucko.luckperms.common.utils.PatternCache; import me.lucko.luckperms.common.utils.PatternCache;
import java.util.Iterator; import java.util.Iterator;
@ -79,9 +80,9 @@ public class NodeFactory {
return new NodeBuilder("suffix." + priority + "." + LegacyNodeFactory.escapeCharacters(suffix)); return new NodeBuilder("suffix." + priority + "." + LegacyNodeFactory.escapeCharacters(suffix));
} }
public static String nodeAsCommand(Node node, String id, boolean group, boolean set) { public static String nodeAsCommand(Node node, String id, HolderType type, boolean set) {
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
sb.append(group ? "group " : "user ").append(id).append(" "); sb.append(type.toString()).append(" ").append(id).append(" ");
if (node.isGroupNode()) { if (node.isGroupNode()) {
sb.append(node.isTemporary() ? (set ? "parent addtemp " : "parent removetemp ") : (set ? "parent add " : "parent remove ")); sb.append(node.isTemporary() ? (set ? "parent addtemp " : "parent removetemp ") : (set ? "parent add " : "parent remove "));
@ -95,16 +96,16 @@ public class NodeFactory {
} }
if (node.getValuePrimitive() && (node.isPrefix() || node.isSuffix())) { if (node.getValuePrimitive() && (node.isPrefix() || node.isSuffix())) {
ChatMetaType type = node.isPrefix() ? ChatMetaType.PREFIX : ChatMetaType.SUFFIX; ChatMetaType nodeType = node.isPrefix() ? ChatMetaType.PREFIX : ChatMetaType.SUFFIX;
String typeName = type.name().toLowerCase(); String typeName = type.name().toLowerCase();
sb.append(node.isTemporary() ? (set ? "meta addtemp" + typeName + " " : "meta removetemp" + typeName + " ") : (set ? "meta add" + typeName + " " : "meta remove" + typeName + " ")); sb.append(node.isTemporary() ? (set ? "meta addtemp" + typeName + " " : "meta removetemp" + typeName + " ") : (set ? "meta add" + typeName + " " : "meta remove" + typeName + " "));
sb.append(type.getEntry(node).getKey()).append(" "); sb.append(nodeType.getEntry(node).getKey()).append(" ");
if (type.getEntry(node).getValue().contains(" ")) { if (nodeType.getEntry(node).getValue().contains(" ")) {
sb.append("\"").append(type.getEntry(node).getValue()).append("\""); sb.append("\"").append(nodeType.getEntry(node).getValue()).append("\"");
} else { } else {
sb.append(type.getEntry(node).getValue()); sb.append(nodeType.getEntry(node).getValue());
} }
if (set && node.isTemporary()) { if (set && node.isTemporary()) {
sb.append(" ").append(node.getExpiryUnixTime()); sb.append(" ").append(node.getExpiryUnixTime());

View File

@ -42,7 +42,7 @@ public class GroupInheritanceComparator implements Comparator<Group> {
private static final Comparator<Group> NULL_ORIGIN = new GroupInheritanceComparator(null); private static final Comparator<Group> NULL_ORIGIN = new GroupInheritanceComparator(null);
public static Comparator<Group> getFor(PermissionHolder origin) { public static Comparator<Group> getFor(PermissionHolder origin) {
if (origin instanceof User) { if (origin.getType().isUser()) {
return new GroupInheritanceComparator(((User) origin)); return new GroupInheritanceComparator(((User) origin));
} }
return NULL_ORIGIN; return NULL_ORIGIN;

View File

@ -25,9 +25,27 @@
package me.lucko.luckperms.common.references; package me.lucko.luckperms.common.references;
import lombok.AllArgsConstructor;
import lombok.Getter;
import me.lucko.luckperms.common.model.PermissionHolder;
@Getter
@AllArgsConstructor
public enum HolderType { public enum HolderType {
USER, USER(true, false),
GROUP GROUP(false, true);
private final boolean user;
private final boolean group;
public boolean matches(PermissionHolder holder) {
return holder.getType() == this;
}
@Override
public String toString() {
return name().toLowerCase();
}
} }

View File

@ -70,7 +70,7 @@ public class WebEditorUtils {
private static final String GROUP_ID_PATTERN = "group/"; private static final String GROUP_ID_PATTERN = "group/";
public static String getHolderIdentifier(PermissionHolder holder) { public static String getHolderIdentifier(PermissionHolder holder) {
if (holder instanceof User) { if (holder.getType().isUser()) {
User user = ((User) holder); User user = ((User) holder);
return USER_ID_PATTERN + user.getUuid().toString(); return USER_ID_PATTERN + user.getUuid().toString();
} else { } else {

View File

@ -48,7 +48,7 @@ import java.util.Set;
public class SpongeMigrationUtils { public class SpongeMigrationUtils {
public static void migrateSubject(Subject from, PermissionHolder to, int priority) { public static void migrateSubject(Subject from, PermissionHolder to, int priority) {
if (to instanceof Group) { if (to.getType().isGroup()) {
MigrationUtils.setGroupWeight((Group) to, priority); MigrationUtils.setGroupWeight((Group) to, priority);
} }

View File

@ -133,7 +133,7 @@ public class LuckPermsSubjectData implements LPSubjectData {
return CompletableFuture.completedFuture(false); return CompletableFuture.completedFuture(false);
} }
if (holder instanceof User) { if (holder.getType().isUser()) {
service.getPlugin().getUserManager().giveDefaultIfNeeded(((User) holder), false); service.getPlugin().getUserManager().giveDefaultIfNeeded(((User) holder), false);
} }
@ -158,7 +158,7 @@ public class LuckPermsSubjectData implements LPSubjectData {
return CompletableFuture.completedFuture(false); return CompletableFuture.completedFuture(false);
} }
if (holder instanceof User) { if (holder.getType().isUser()) {
service.getPlugin().getUserManager().giveDefaultIfNeeded(((User) holder), false); service.getPlugin().getUserManager().giveDefaultIfNeeded(((User) holder), false);
} }
@ -251,7 +251,7 @@ public class LuckPermsSubjectData implements LPSubjectData {
toRemove.forEach(makeUnsetConsumer(false)); toRemove.forEach(makeUnsetConsumer(false));
ret = !toRemove.isEmpty(); ret = !toRemove.isEmpty();
if (ret && holder instanceof User) { if (ret && holder.getType().isUser()) {
service.getPlugin().getUserManager().giveDefaultIfNeeded(((User) holder), false); service.getPlugin().getUserManager().giveDefaultIfNeeded(((User) holder), false);
} }
} }
@ -277,7 +277,7 @@ public class LuckPermsSubjectData implements LPSubjectData {
toRemove.forEach(makeUnsetConsumer(false)); toRemove.forEach(makeUnsetConsumer(false));
ret = !toRemove.isEmpty(); ret = !toRemove.isEmpty();
if (ret && holder instanceof User) { if (ret && holder.getType().isUser()) {
service.getPlugin().getUserManager().giveDefaultIfNeeded(((User) holder), false); service.getPlugin().getUserManager().giveDefaultIfNeeded(((User) holder), false);
} }
} }
@ -441,14 +441,14 @@ public class LuckPermsSubjectData implements LPSubjectData {
private CompletableFuture<Void> objectSave(PermissionHolder t) { private CompletableFuture<Void> objectSave(PermissionHolder t) {
if (!enduring) { if (!enduring) {
// don't bother saving to primary storage. just refresh // don't bother saving to primary storage. just refresh
if (t instanceof User) { if (t.getType().isUser()) {
User user = ((User) t); User user = ((User) t);
return user.getRefreshBuffer().request(); return user.getRefreshBuffer().request();
} else { } else {
return service.getPlugin().getUpdateTaskBuffer().request(); return service.getPlugin().getUpdateTaskBuffer().request();
} }
} else { } else {
if (t instanceof User) { if (t.getType().isUser()) {
User user = ((User) t); User user = ((User) t);
return service.getPlugin().getStorage().saveUser(user).thenComposeAsync(success -> { return service.getPlugin().getStorage().saveUser(user).thenComposeAsync(success -> {
if (!success) { if (!success) {