More progress towards 1.6: add transient permissions

This commit is contained in:
Luck 2016-08-27 22:01:17 +01:00
parent 2ea9b36c77
commit 2a305b1c55
No known key found for this signature in database
GPG Key ID: EFA9B3EC5FD90F8B
17 changed files with 560 additions and 244 deletions

View File

@ -44,11 +44,23 @@ public interface Node extends Map.Entry<String, Boolean> {
@Override
Boolean getValue();
/**
* @return the value of this node as a Tristate
*/
Tristate getTristate();
/**
* @return true if the node is negated
*/
boolean isNegated();
/**
* If this node is set to override explicitly.
* This value does not persist across saves, and is therefore only useful for transient nodes
* @return true if this node is set to override explicitly
*/
boolean isOverride();
/**
* Gets the server this node applies on, if the node is server specific
* @return an {@link Optional} containing the server, if one is defined
@ -189,6 +201,13 @@ public interface Node extends Map.Entry<String, Boolean> {
*/
int getWildcardLevel();
/**
* Similar to {@link #equals(Object)}, except doesn't take note of the value
* @param node the other node
* @return true if the two nodes are almost equal
*/
boolean equalsIgnoringValue(Node node);
/**
* Similar to {@link #equals(Object)}, except doesn't take note of the expiry time or value
* @param node the other node
@ -199,6 +218,13 @@ public interface Node extends Map.Entry<String, Boolean> {
interface Builder {
Builder setNegated(boolean negated);
Builder setValue(boolean value);
/**
* Warning: this value does not persist, and disappears when the holder is re-loaded.
* It is therefore only useful for transient nodes.
*/
Builder setOverride(boolean override);
Builder setExpiry(long expireAt);
Builder setWorld(String world);
Builder setServer(String server) throws IllegalArgumentException;

View File

@ -28,6 +28,7 @@ import me.lucko.luckperms.exceptions.ObjectLacksException;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.SortedSet;
/**
* Wrapper interface for internal PermissionHolder (object/group) instances
@ -43,10 +44,25 @@ public interface PermissionHolder {
/**
* Gets an immutable Set of the objects permission nodes
* @return an immutable set of permissions
* @return an immutable set of permissions in priority order
* @since 1.6
*/
Set<Node> getPermissionNodes();
SortedSet<Node> getPermissions();
/**
* Similar to {@link #getPermissions()}, except excluding transient permissions
* @return a set of nodes
* @since 1.6
*/
Set<Node> getEnduringPermissions();
/**
* Similar to {@link #getPermissions()}, except excluding non-transient permissions
* @return a set of nodes
* @since 1.6
*/
Set<Node> getTransientPermissions();
/**
* Gets an immutable set of the nodes that this object has and inherits
@ -58,7 +74,7 @@ public interface PermissionHolder {
/**
* Gets an immutable Map of the objects permission nodes
* @return an immutable map of permissions
* @deprecated in favour of {@link #getPermissionNodes()}
* @deprecated in favour of {@link #getPermissions()}
*/
@Deprecated
Map<String, Boolean> getNodes();
@ -66,11 +82,20 @@ public interface PermissionHolder {
/**
* Checks to see if the object has a certain permission
* @param node the node to check for
* @return true if the object has the permission
* @return a Tristate for the holders permission status for the node
* @throws NullPointerException if the node is null
* @since 1.6
*/
boolean hasPermission(Node node);
Tristate hasPermission(Node node);
/**
* Checks to see if the object has a certain permission
* @param node the node to check for
* @return a Tristate for the holders permission status for the node
* @throws NullPointerException if the node is null
* @since 1.6
*/
Tristate hasTransientPermission(Node node);
/**
* Checks to see if the object has a certain permission
@ -79,9 +104,7 @@ public interface PermissionHolder {
* @return true if the object has the permission
* @throws NullPointerException if the node is null
* @throws IllegalArgumentException if the node is invalid
* @deprecated in favour of {@link #hasPermission(Node)}
*/
@Deprecated
boolean hasPermission(String node, boolean b);
/**
@ -92,9 +115,7 @@ public interface PermissionHolder {
* @return true if the object has the permission
* @throws NullPointerException if the node or server is null
* @throws IllegalArgumentException if the node or server is invalid
* @deprecated in favour of {@link #hasPermission(Node)}
*/
@Deprecated
boolean hasPermission(String node, boolean b, String server);
/**
@ -106,9 +127,7 @@ public interface PermissionHolder {
* @return true if the object has the permission
* @throws NullPointerException if the node, server or world is null
* @throws IllegalArgumentException if the node, server or world is invalid
* @deprecated in favour of {@link #hasPermission(Node)}
*/
@Deprecated
boolean hasPermission(String node, boolean b, String server, String world);
/**
@ -119,9 +138,7 @@ public interface PermissionHolder {
* @return true if the object has the permission
* @throws NullPointerException if the node is null
* @throws IllegalArgumentException if the node is invalid
* @deprecated in favour of {@link #hasPermission(Node)}
*/
@Deprecated
boolean hasPermission(String node, boolean b, boolean temporary);
/**
@ -133,9 +150,7 @@ public interface PermissionHolder {
* @return true if the object has the permission
* @throws NullPointerException if the node or server is null
* @throws IllegalArgumentException if the node or server is invalid
* @deprecated in favour of {@link #hasPermission(Node)}
*/
@Deprecated
boolean hasPermission(String node, boolean b, String server, boolean temporary);
/**
@ -148,19 +163,17 @@ public interface PermissionHolder {
* @return true if the object has the permission
* @throws NullPointerException if the node, server or world is null
* @throws IllegalArgumentException if the node, server or world is invalid
* @deprecated in favour of {@link #hasPermission(Node)}
*/
@Deprecated
boolean hasPermission(String node, boolean b, String server, String world, boolean temporary);
/**
* Cheks to see if the object inherits a certain permission
* @param node the node to check for
* @return true if the object inherits the permission
* @return a Tristate for the holders inheritance status for the node
* @throws NullPointerException if the node is null
* @since 1.6
*/
boolean inheritsPermission(Node node);
Tristate inheritsPermission(Node node);
/**
* Checks to see if the object inherits a certain permission
@ -169,9 +182,7 @@ public interface PermissionHolder {
* @return true if the object inherits the permission
* @throws NullPointerException if the node is null
* @throws IllegalArgumentException if the node is invalid
* @deprecated in favour of {@link #inheritsPermission(Node)}
*/
@Deprecated
boolean inheritsPermission(String node, boolean b);
/**
@ -182,9 +193,7 @@ public interface PermissionHolder {
* @return true if the object inherits the permission
* @throws NullPointerException if the node or server is null
* @throws IllegalArgumentException if the node or server is invalid
* @deprecated in favour of {@link #inheritsPermission(Node)}
*/
@Deprecated
boolean inheritsPermission(String node, boolean b, String server);
/**
@ -196,9 +205,7 @@ public interface PermissionHolder {
* @return true if the object inherits the permission
* @throws NullPointerException if the node, server or world is null
* @throws IllegalArgumentException if the node server or world is invalid
* @deprecated in favour of {@link #inheritsPermission(Node)}
*/
@Deprecated
boolean inheritsPermission(String node, boolean b, String server, String world);
/**
@ -209,9 +216,7 @@ public interface PermissionHolder {
* @return true if the object inherits the permission
* @throws NullPointerException if the node is null
* @throws IllegalArgumentException if the node is invalid
* @deprecated in favour of {@link #inheritsPermission(Node)}
*/
@Deprecated
boolean inheritsPermission(String node, boolean b, boolean temporary);
/**
@ -223,9 +228,7 @@ public interface PermissionHolder {
* @return true if the object inherits the permission
* @throws NullPointerException if the node or server is null
* @throws IllegalArgumentException if the node or server is invalid
* @deprecated in favour of {@link #inheritsPermission(Node)}
*/
@Deprecated
boolean inheritsPermission(String node, boolean b, String server, boolean temporary);
/**
@ -238,9 +241,7 @@ public interface PermissionHolder {
* @return true if the object inherits the permission
* @throws NullPointerException if the node, server or world is null
* @throws IllegalArgumentException if the node, server or world if invalid
* @deprecated in favour of {@link #inheritsPermission(Node)}
*/
@Deprecated
boolean inheritsPermission(String node, boolean b, String server, String world, boolean temporary);
/**
@ -252,6 +253,25 @@ public interface PermissionHolder {
*/
void setPermission(Node node) throws ObjectAlreadyHasException;
/**
* Sets a transient permission for the object
*
* <p> A transient node is a permission that does not persist.
* Whenever a user logs out of the server, or the server restarts, this permission will disappear.
* It is never saved to the datastore, and therefore will not apply on other servers.
*
* This is useful if you want to temporarily set a permission for a user while they're online, but don't
* want it to persist, and have to worry about removing it when they log out.
*
* For unsetting a transient permission, see {@link #unsetTransientPermission(Node)}
*
* @param node The node to be set
* @throws ObjectAlreadyHasException if the object already has the permission
* @throws NullPointerException if the node is null
* @since 1.6
*/
void setTransientPermission(Node node) throws ObjectAlreadyHasException;
/**
* Sets a permission for the object
* @param node The node to be set
@ -342,6 +362,15 @@ public interface PermissionHolder {
*/
void unsetPermission(Node node) throws ObjectLacksException;
/**
* Unsets a transient permission for the object
* @param node The node to be unset
* @throws ObjectLacksException if the node wasn't already set
* @throws NullPointerException if the node is null
* @since 1.6
*/
void unsetTransientPermission(Node node) throws ObjectLacksException;
/**
* Unsets a permission for the object
* @param node The node to be unset

View File

@ -0,0 +1,47 @@
/*
* Copyright (c) 2016 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.api;
/**
* Represents a permission value
*/
public enum Tristate {
TRUE(true),
FALSE(false),
UNDEFINED(false);
private final boolean booleanValue;
Tristate(boolean booleanValue) {
this.booleanValue = booleanValue;
}
public boolean asBoolean() {
return booleanValue;
}
public static Tristate fromBoolean(boolean b) {
return b ? TRUE : FALSE;
}
}

View File

@ -103,7 +103,7 @@ class VaultChatHook extends Chat {
if (node.equals("")) return defaultValue;
node = escapeCharacters(node);
for (Map.Entry<String, Boolean> e : holder.getPermissions("global", world, null, true, Collections.emptyList(), false).entrySet()) {
for (Map.Entry<String, Boolean> e : holder.exportNodes("global", world, null, true, false, Collections.emptyList()).entrySet()) {
if (!e.getValue()) continue;
String[] parts = Patterns.DOT.split(e.getKey(), 3);
@ -132,7 +132,7 @@ class VaultChatHook extends Chat {
if (node.equals("")) return defaultValue;
node = escapeCharacters(node);
for (Map.Entry<String, Boolean> e : holder.getPermissions("global", world, null, true, Collections.emptyList(), false).entrySet()) {
for (Map.Entry<String, Boolean> e : holder.exportNodes("global", world, null, true, false, Collections.emptyList()).entrySet()) {
if (!e.getValue()) continue;
String[] parts = Patterns.DOT.split(e.getKey(), 3);
@ -161,7 +161,7 @@ class VaultChatHook extends Chat {
if (node.equals("")) return defaultValue;
node = escapeCharacters(node);
for (Map.Entry<String, Boolean> e : holder.getPermissions("global", world, null, true, Collections.emptyList(), false).entrySet()) {
for (Map.Entry<String, Boolean> e : holder.exportNodes("global", world, null, true, false, Collections.emptyList()).entrySet()) {
if (!e.getValue()) continue;
String[] parts = Patterns.DOT.split(e.getKey(), 3);
@ -190,7 +190,7 @@ class VaultChatHook extends Chat {
if (node.equals("")) return defaultValue;
node = escapeCharacters(node);
for (Map.Entry<String, Boolean> e : holder.getPermissions("global", world, null, true, Collections.emptyList(), false).entrySet()) {
for (Map.Entry<String, Boolean> e : holder.exportNodes("global", world, null, true, false, Collections.emptyList()).entrySet()) {
if (!e.getValue()) continue;
String[] parts = Patterns.DOT.split(e.getKey(), 3);

View File

@ -26,18 +26,19 @@ import lombok.AllArgsConstructor;
import lombok.NonNull;
import me.lucko.luckperms.api.Node;
import me.lucko.luckperms.api.PermissionHolder;
import me.lucko.luckperms.api.Tristate;
import me.lucko.luckperms.exceptions.ObjectAlreadyHasException;
import me.lucko.luckperms.exceptions.ObjectLacksException;
import java.util.*;
import static me.lucko.luckperms.api.implementation.internal.Utils.*;
import static me.lucko.luckperms.core.PermissionHolder.convertToLegacy;
import static me.lucko.luckperms.core.PermissionHolder.exportToLegacy;
/**
* Provides a link between {@link PermissionHolder} and {@link me.lucko.luckperms.core.PermissionHolder}
*/
@SuppressWarnings("unused")
@SuppressWarnings({"unused", "deprecation"})
@AllArgsConstructor
public class PermissionHolderLink implements PermissionHolder {
@ -50,10 +51,20 @@ public class PermissionHolderLink implements PermissionHolder {
}
@Override
public Set<Node> getPermissionNodes() {
public SortedSet<Node> getPermissions() {
return Collections.unmodifiableSortedSet(master.getPermissions());
}
@Override
public Set<Node> getEnduringPermissions() {
return Collections.unmodifiableSet(master.getNodes());
}
@Override
public Set<Node> getTransientPermissions() {
return Collections.unmodifiableSet(master.getTransientNodes());
}
@Override
public Set<Node> getAllNodes() {
return Collections.unmodifiableSet(master.getAllNodes(null));
@ -61,12 +72,17 @@ public class PermissionHolderLink implements PermissionHolder {
@Override
public Map<String, Boolean> getNodes() {
return convertToLegacy(master.getNodes());
return exportToLegacy(master.getNodes());
}
@Override
public boolean hasPermission(@NonNull Node node) {
return master.hasPermission(node);
public Tristate hasPermission(@NonNull Node node) {
return master.hasPermission(node, false);
}
@Override
public Tristate hasTransientPermission(@NonNull Node node) {
return master.hasPermission(node, true);
}
@Override
@ -100,7 +116,7 @@ public class PermissionHolderLink implements PermissionHolder {
}
@Override
public boolean inheritsPermission(@NonNull Node node) {
public Tristate inheritsPermission(@NonNull Node node) {
return master.inheritsPermission(node);
}
@ -139,6 +155,11 @@ public class PermissionHolderLink implements PermissionHolder {
master.setPermission(node);
}
@Override
public void setTransientPermission(@NonNull Node node) throws ObjectAlreadyHasException {
master.setTransientPermission(node);
}
@Override
public void setPermission(@NonNull String node, @NonNull boolean value) throws ObjectAlreadyHasException {
master.setPermission(checkNode(node), value);
@ -174,6 +195,11 @@ public class PermissionHolderLink implements PermissionHolder {
master.unsetPermission(node);
}
@Override
public void unsetTransientPermission(@NonNull Node node) throws ObjectLacksException {
master.unsetTransientPermission(node);
}
@Override
public void unsetPermission(@NonNull String node, @NonNull boolean temporary) throws ObjectLacksException {
master.unsetPermission(checkNode(node), temporary);
@ -226,7 +252,7 @@ public class PermissionHolderLink implements PermissionHolder {
@Override
public Map<String, Boolean> getPermissions(String server, String world, Map<String, String> extraContext, boolean includeGlobal, List<String> possibleNodes, boolean applyGroups) {
return master.getPermissions(server, world, extraContext, includeGlobal, possibleNodes, applyGroups);
return master.exportNodes(server, world, extraContext, includeGlobal, applyGroups, possibleNodes);
}
@Override
@ -247,7 +273,7 @@ public class PermissionHolderLink implements PermissionHolder {
@Override
public Map<String, Boolean> getPermanentNodes() {
return convertToLegacy(master.getPermanentNodes());
return exportToLegacy(master.getPermanentNodes());
}
@Override

View File

@ -30,7 +30,7 @@ import me.lucko.luckperms.groups.Group;
import java.util.List;
import static me.lucko.luckperms.core.PermissionHolder.convertToLegacy;
import static me.lucko.luckperms.core.PermissionHolder.exportToLegacy;
public class GroupListNodes extends SubCommand<Group> {
public GroupListNodes() {
@ -40,7 +40,7 @@ public class GroupListNodes extends SubCommand<Group> {
@Override
public CommandResult execute(LuckPermsPlugin plugin, Sender sender, Group group, List<String> args, String label) {
Message.LISTNODES.send(sender, group.getName(), Util.permNodesToString(convertToLegacy(group.getPermanentNodes())));
Message.LISTNODES.send(sender, group.getName(), Util.permNodesToString(exportToLegacy(group.getPermanentNodes())));
Message.LISTNODES_TEMP.send(sender, group.getName(), Util.tempNodesToString(group.getTemporaryNodesLegacy()));
return CommandResult.SUCCESS;
}

View File

@ -26,7 +26,6 @@ import me.lucko.luckperms.LuckPermsPlugin;
import me.lucko.luckperms.commands.*;
import me.lucko.luckperms.constants.Message;
import me.lucko.luckperms.constants.Permission;
import me.lucko.luckperms.core.PermissionHolder;
import me.lucko.luckperms.users.User;
import java.util.List;
@ -41,7 +40,7 @@ public class UserListNodes extends SubCommand<User> {
@Override
public CommandResult execute(LuckPermsPlugin plugin, Sender sender, User user, List<String> args, String label) {
Message.LISTNODES.send(sender, user.getName(), Util.permNodesToString(convertToLegacy(user.getPermanentNodes())));
Message.LISTNODES.send(sender, user.getName(), Util.permNodesToString(exportToLegacy(user.getPermanentNodes())));
Message.LISTNODES_TEMP.send(sender, user.getName(), Util.tempNodesToString(user.getTemporaryNodesLegacy()));
return CommandResult.SUCCESS;
}

View File

@ -27,6 +27,7 @@ import lombok.Getter;
import lombok.RequiredArgsConstructor;
import me.lucko.luckperms.LuckPermsPlugin;
import me.lucko.luckperms.api.Node;
import me.lucko.luckperms.api.Tristate;
import me.lucko.luckperms.api.event.events.GroupRemoveEvent;
import me.lucko.luckperms.api.event.events.PermissionNodeExpireEvent;
import me.lucko.luckperms.api.event.events.PermissionNodeSetEvent;
@ -38,6 +39,7 @@ import me.lucko.luckperms.groups.Group;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentSkipListSet;
import java.util.stream.Collectors;
/**
@ -66,14 +68,195 @@ public abstract class PermissionHolder {
@Getter
private Set<Node> nodes = ConcurrentHashMap.newKeySet();
/**
* The user/group's transient permissions
*/
@Getter
private Set<Node> transientNodes = ConcurrentHashMap.newKeySet();
/**
* Returns a Set of nodes in priority order
* @return the holders transient and permanent nodes
*/
public SortedSet<Node> getPermissions() {
// Returns no duplicate nodes. as in, nodes with the same value.
TreeSet<Node> permissions = new TreeSet<>(PRIORITY_COMPARATOR);
permissions.addAll(nodes);
permissions.addAll(transientNodes);
Iterator<Node> iterator = permissions.descendingIterator(); // TODO check this
while (iterator.hasNext()) {
Node entry = iterator.next();
permissions.stream()
.filter(entry::equalsIgnoringValue) // The node appears again at a higher priority
.forEachOrdered(other -> iterator.remove()); // Remove it.
}
return permissions;
}
/**
* Removes temporary permissions that have expired
* @return true if permissions had expired and were removed
*/
public boolean auditTemporaryPermissions() {
boolean work = false;
Iterator<Node> iterator = nodes.iterator();
while (iterator.hasNext()) {
Node element = iterator.next();
if (element.hasExpired()) {
iterator.remove();
work = true;
plugin.getApiProvider().fireEventAsync(new PermissionNodeExpireEvent(new PermissionHolderLink(this), element));
}
}
Iterator<Node> iterator2 = transientNodes.iterator();
while (iterator2.hasNext()) {
Node element = iterator2.next();
if (element.hasExpired()) {
iterator2.remove();
work = true;
plugin.getApiProvider().fireEventAsync(new PermissionNodeExpireEvent(new PermissionHolderLink(this), element));
}
}
return work;
}
/**
* Gets all of the nodes that this holder has and inherits
* @param excludedGroups a list of groups to exclude
* @return a set of nodes
*/
public SortedSet<Node> getAllNodes(List<String> excludedGroups) {
SortedSet<Node> all = new ConcurrentSkipListSet<>(PRIORITY_COMPARATOR);
all.addAll(getPermissions());
if (excludedGroups == null) {
excludedGroups = new ArrayList<>();
}
excludedGroups.add(getObjectName().toLowerCase());
Set<String> parents = getPermissions().stream()
.filter(Node::isGroupNode)
.map(Node::getGroupName)
.collect(Collectors.toSet());
for (String parent : parents) {
Group group = plugin.getGroupManager().get(parent);
if (group == null) {
continue;
}
if (excludedGroups.contains(group.getObjectName())) {
continue;
}
inherited:
for (Node inherited : group.getAllNodes(excludedGroups)) {
for (Node existing : all) {
if (existing.almostEquals(inherited)) {
continue inherited;
}
}
all.add(inherited);
}
}
return all;
}
/**
* Gets all of the nodes that this holder has (and inherits), given the context
* @param server the server
* @param world the world
* @param extraContext any extra context to filter by
* @param includeGlobal whether to include global nodes
* @param applyGroups if inherited group permissions should be included
* @return a map of permissions
*/
public Set<Node> getAllNodesFiltered(String server, String world, Map<String, String> extraContext, boolean includeGlobal, boolean applyGroups) {
Set<Node> perms = ConcurrentHashMap.newKeySet();
SortedSet<Node> allNodes;
if (applyGroups) {
allNodes = sort(getAllNodes(null), true);
} else {
allNodes = sort(getPermissions(), true);
}
for (Node node : allNodes) {
if (!node.shouldApplyOnServer(server, includeGlobal, plugin.getConfiguration().getApplyRegex())) {
continue;
}
if (!node.shouldApplyOnWorld(world, includeGlobal, plugin.getConfiguration().getApplyRegex())) {
continue;
}
if (!node.shouldApplyWithContext(extraContext)) {
continue;
}
perms.add(node);
}
return perms;
}
/**
* Converts the output of {@link #getAllNodesFiltered(String, String, Map, boolean, boolean)}, and expands wildcards/regex/shorthand perms
* @param server the server
* @param world the world
* @param extraContext any extra context to filter by
* @param includeGlobal whether to include global nodes
* @param applyGroups if inherited group permissions should be included
* @param possibleNodes a list of possible nodes for wildcards and regex permissions
* @return a map of permissions
*/
public Map<String, Boolean> exportNodes(String server, String world, Map<String, String> extraContext, boolean includeGlobal, boolean applyGroups, List<String> possibleNodes) {
Map<String, Boolean> perms = new HashMap<>();
for (Node node : getAllNodesFiltered(server, world, extraContext, includeGlobal, applyGroups)) {
perms.put(node.getPermission(), node.getValue());
if (plugin.getConfiguration().getApplyShorthand()) {
node.resolveShorthand().stream()
.filter(s -> !perms.containsKey(s))
.forEach(s -> perms.put(s, node.getValue()));
}
if (plugin.getConfiguration().getApplyWildcards()) {
node.resolveWildcard(possibleNodes).stream()
.filter(s -> !perms.containsKey(s))
.forEach(s -> perms.put(s, node.getValue()));
}
}
return Collections.unmodifiableMap(perms);
}
public void setNodes(Set<Node> nodes) {
this.nodes.clear();
this.nodes.addAll(nodes);
auditTemporaryPermissions();
}
@Deprecated
public static Map<String, Boolean> convertToLegacy(Set<Node> nodes) {
public void setTransiestNodes(Set<Node> nodes) {
this.transientNodes.clear();
this.transientNodes.addAll(nodes);
auditTemporaryPermissions();
}
public static Map<String, Boolean> exportToLegacy(Set<Node> nodes) {
Map<String, Boolean> m = new HashMap<>();
for (Node node : nodes) {
m.put(node.toSerializedNode(), node.getValue());
@ -81,6 +264,7 @@ public abstract class PermissionHolder {
return Collections.unmodifiableMap(m);
}
// Convenience method
private static Node.Builder buildNode(String permission) {
return new me.lucko.luckperms.utils.Node.Builder(permission);
}
@ -96,84 +280,94 @@ public abstract class PermissionHolder {
auditTemporaryPermissions();
}
private static boolean hasPermission(Set<Node> toQuery, Node node) {
private static Tristate hasPermission(Set<Node> toQuery, Node node) {
for (Node n : toQuery) {
if (n.almostEquals(node)) {
return true;
if (n.equalsIgnoringValue(node)) {
n.getTristate();
}
}
return false;
return Tristate.UNDEFINED;
}
/**
* Check if the holder has a permission node
* @param node the node to check
* @return true if the holder has the node
* @param t whether to check transient nodes
* @return a tristate
*/
public boolean hasPermission(Node node) {
return hasPermission(this.nodes, node);
public Tristate hasPermission(Node node, boolean t) {
return hasPermission(t ? transientNodes : nodes, node);
}
public Tristate hasPermission(Node node) {
return hasPermission(node, false);
}
public boolean hasPermission(String node, boolean b) {
return hasPermission(buildNode(node).setValue(b).build());
return hasPermission(buildNode(node).setValue(b).build()).asBoolean() == b;
}
public boolean hasPermission(String node, boolean b, String server) {
return hasPermission(buildNode(node).setValue(b).setServer(server).build());
return hasPermission(buildNode(node).setValue(b).setServer(server).build()).asBoolean() == b;
}
public boolean hasPermission(String node, boolean b, String server, String world) {
return hasPermission(buildNode(node).setValue(b).setServer(server).setWorld(world).build());
return hasPermission(buildNode(node).setValue(b).setServer(server).setWorld(world).build()).asBoolean() == b;
}
public boolean hasPermission(String node, boolean b, boolean temporary) {
return hasPermission(buildNode(node).setValue(b).setExpiry(temporary ? 10L : 0L).build());
return hasPermission(buildNode(node).setValue(b).setExpiry(temporary ? 10L : 0L).build()).asBoolean() == b;
}
public boolean hasPermission(String node, boolean b, String server, boolean temporary) {
return hasPermission(buildNode(node).setValue(b).setServer(server).setExpiry(temporary ? 10L : 0L).build());
return hasPermission(buildNode(node).setValue(b).setServer(server).setExpiry(temporary ? 10L : 0L).build()).asBoolean() == b;
}
public boolean hasPermission(String node, boolean b, String server, String world, boolean temporary) {
return hasPermission(buildNode(node).setValue(b).setServer(server).setWorld(world).setExpiry(temporary ? 10L : 0L).build());
return hasPermission(buildNode(node).setValue(b).setServer(server).setWorld(world).setExpiry(temporary ? 10L : 0L).build()).asBoolean() == b;
}
/**
* Check if the holder inherits a node
* @param node the node to check
* @return true if the holder inherits the node
* @return a tristate
*/
public boolean inheritsPermission(Node node) {
public Tristate inheritsPermission(Node node) {
return hasPermission(getAllNodes(null), node);
}
public boolean inheritsPermission(String node, boolean b) {
return inheritsPermission(buildNode(node).setValue(b).build());
return inheritsPermission(buildNode(node).setValue(b).build()).asBoolean() == b;
}
public boolean inheritsPermission(String node, boolean b, String server) {
return inheritsPermission(buildNode(node).setValue(b).setServer(server).build());
return inheritsPermission(buildNode(node).setValue(b).setServer(server).build()).asBoolean() == b;
}
public boolean inheritsPermission(String node, boolean b, String server, String world) {
return inheritsPermission(buildNode(node).setValue(b).setServer(server).setWorld(world).build());
return inheritsPermission(buildNode(node).setValue(b).setServer(server).setWorld(world).build()).asBoolean() == b;
}
public boolean inheritsPermission(String node, boolean b, boolean temporary) {
return inheritsPermission(buildNode(node).setValue(b).setExpiry(temporary ? 10L : 0L).build());
return inheritsPermission(buildNode(node).setValue(b).setExpiry(temporary ? 10L : 0L).build()).asBoolean() == b;
}
public boolean inheritsPermission(String node, boolean b, String server, boolean temporary) {
return inheritsPermission(buildNode(node).setValue(b).setServer(server).setExpiry(temporary ? 10L : 0L).build());
return inheritsPermission(buildNode(node).setValue(b).setServer(server).setExpiry(temporary ? 10L : 0L).build()).asBoolean() == b;
}
public boolean inheritsPermission(String node, boolean b, String server, String world, boolean temporary) {
return inheritsPermission(buildNode(node).setValue(b).setServer(server).setWorld(world).setExpiry(temporary ? 10L : 0L).build());
return inheritsPermission(buildNode(node).setValue(b).setServer(server).setWorld(world).setExpiry(temporary ? 10L : 0L).build()).asBoolean() == b;
}
/**
* Sets a permission node
* @param node the node to set
* @throws ObjectAlreadyHasException if the holder has this permission already
*/
public void setPermission(Node node) throws ObjectAlreadyHasException {
if (hasPermission(node)) {
if (hasPermission(node, false) == Tristate.TRUE) {
throw new ObjectAlreadyHasException();
}
@ -181,6 +375,20 @@ public abstract class PermissionHolder {
plugin.getApiProvider().fireEventAsync(new PermissionNodeSetEvent(new PermissionHolderLink(this), node));
}
/**
* Sets a transient permission node
* @param node the node to set
* @throws ObjectAlreadyHasException if the holder has this permission already
*/
public void setTransientPermission(Node node) throws ObjectAlreadyHasException {
if (hasPermission(node, true) == Tristate.TRUE) {
throw new ObjectAlreadyHasException();
}
transientNodes.add(node);
plugin.getApiProvider().fireEventAsync(new PermissionNodeSetEvent(new PermissionHolderLink(this), node));
}
public void setPermission(String node, boolean value) throws ObjectAlreadyHasException {
setPermission(buildNode(node).setValue(value).build());
}
@ -211,7 +419,7 @@ public abstract class PermissionHolder {
* @throws ObjectLacksException if the holder doesn't have this node already
*/
public void unsetPermission(Node node) throws ObjectLacksException {
if (!hasPermission(node)) {
if (hasPermission(node, false) == Tristate.FALSE) {
throw new ObjectLacksException();
}
@ -225,6 +433,26 @@ public abstract class PermissionHolder {
}
}
/**
* Unsets a transient permission node
* @param node the node to unset
* @throws ObjectLacksException if the holder doesn't have this node already
*/
public void unsetTransientPermission(Node node) throws ObjectLacksException {
if (hasPermission(node, true) == Tristate.FALSE) {
throw new ObjectLacksException();
}
transientNodes.remove(node);
if (node.isGroupNode()) {
plugin.getApiProvider().fireEventAsync(new GroupRemoveEvent(new PermissionHolderLink(this),
node.getGroupName(), node.getServer().orElse(null), node.getWorld().orElse(null), node.isTemporary()));
} else {
plugin.getApiProvider().fireEventAsync(new PermissionNodeUnsetEvent(new PermissionHolderLink(this), node));
}
}
public void unsetPermission(String node, boolean temporary) throws ObjectLacksException {
unsetPermission(buildNode(node).setExpiry(temporary ? 10L : 0L).build());
}
@ -253,7 +481,7 @@ public abstract class PermissionHolder {
* @return The temporary nodes held by the holder
*/
public Set<Node> getTemporaryNodes() {
return nodes.stream().filter(Node::isTemporary).collect(Collectors.toSet());
return getPermissions().stream().filter(Node::isTemporary).collect(Collectors.toSet());
}
@Deprecated
@ -271,84 +499,18 @@ public abstract class PermissionHolder {
* @return The permanent nodes held by the holder
*/
public Set<Node> getPermanentNodes() {
return nodes.stream().filter(Node::isPermanent).collect(Collectors.toSet());
}
/**
* Removes temporary permissions that have expired
* @return true if permissions had expired and were removed
*/
public boolean auditTemporaryPermissions() {
boolean work = false;
Iterator<Node> iterator = nodes.iterator();
while (iterator.hasNext()) {
Node element = iterator.next();
if (element.hasExpired()) {
iterator.remove();
work = true;
plugin.getApiProvider().fireEventAsync(new PermissionNodeExpireEvent(new PermissionHolderLink(this), element));
}
}
return work;
}
/**
* Gets all of the nodes that this holder has and inherits
* @param excludedGroups a list of groups to exclude
* @return a set of nodes
*/
public Set<Node> getAllNodes(List<String> excludedGroups) {
Set<Node> all = ConcurrentHashMap.newKeySet();
all.addAll(nodes);
if (excludedGroups == null) {
excludedGroups = new ArrayList<>();
}
excludedGroups.add(getObjectName().toLowerCase());
Set<String> parents = nodes.stream()
.filter(Node::isGroupNode)
.map(Node::getGroupName)
.collect(Collectors.toSet());
for (String parent : parents) {
Group group = plugin.getGroupManager().get(parent);
if (group == null) {
continue;
}
if (excludedGroups.contains(group.getObjectName())) {
continue;
}
inherited:
for (Node inherited : group.getAllNodes(excludedGroups)) {
for (Node existing : all) {
if (existing.almostEquals(inherited)) {
continue inherited;
}
}
all.add(inherited);
}
}
return all;
return getPermissions().stream().filter(Node::isPermanent).collect(Collectors.toSet());
}
/*
* Don't use these methods, only here for compat reasons
*/
public Map<String, Boolean> getLocalPermissions(String server, String world, List<String> excludedGroups, List<String> possibleNodes) {
return getPermissions(server, world, null, plugin.getConfiguration().getIncludeGlobalPerms(), possibleNodes, true);
return exportNodes(server, world, null, plugin.getConfiguration().getIncludeGlobalPerms(), true, possibleNodes);
}
public Map<String, Boolean> getLocalPermissions(String server, String world, List<String> excludedGroups) {
return getPermissions(server, world, null, plugin.getConfiguration().getIncludeGlobalPerms(), null, true);
return exportNodes(server, world, null, plugin.getConfiguration().getIncludeGlobalPerms(), true, null);
}
public Map<String, Boolean> getLocalPermissions(String server, List<String> excludedGroups, List<String> possibleNodes) {
@ -359,57 +521,6 @@ public abstract class PermissionHolder {
return getLocalPermissions(server, null, excludedGroups, null);
}
/**
* Convert the holders nodes into a Map of permissions to be applied on the platform
* @param server the server
* @param world the world
* @param extraContext any extra context to filter by
* @param includeGlobal whether to include global nodes
* @param possibleNodes a list of possible permissions for resolving wildcards
* @param applyGroups if inherited group permissions should be included
* @return a map of permissions
*/
public Map<String, Boolean> getPermissions(String server, String world, Map<String, String> extraContext, boolean includeGlobal, List<String> possibleNodes, boolean applyGroups) {
Map<String, Boolean> perms = new HashMap<>();
SortedSet<Node> allNodes;
if (applyGroups) {
allNodes = sort(getAllNodes(null), true);
} else {
allNodes = sort(nodes, true);
}
for (Node node : allNodes) {
if (!node.shouldApplyOnServer(server, includeGlobal, plugin.getConfiguration().getApplyRegex())) {
continue;
}
if (!node.shouldApplyOnWorld(world, includeGlobal, plugin.getConfiguration().getApplyRegex())) {
continue;
}
if (!node.shouldApplyWithContext(extraContext)) {
continue;
}
perms.put(node.getPermission(), node.getValue());
if (plugin.getConfiguration().getApplyShorthand()) {
node.resolveShorthand().stream()
.filter(s -> !perms.containsKey(s))
.forEach(s -> perms.put(s, node.getValue()));
}
if (plugin.getConfiguration().getApplyWildcards()) {
node.resolveWildcard(possibleNodes).stream()
.filter(s -> !perms.containsKey(s))
.forEach(s -> perms.put(s, node.getValue()));
}
}
return perms;
}
public static SortedSet<Node> sort(Set<Node> toSort, boolean reversed) {
TreeSet<Node> set = new TreeSet<>(reversed ? PRIORITY_COMPARATOR.reversed() : PRIORITY_COMPARATOR);
set.addAll(toSort);
@ -421,41 +532,35 @@ public abstract class PermissionHolder {
@Override
public int compare(Node o1, Node o2) {
if (takesPriority(o1, o2)) {
return 1;
if (o1.isOverride() != o2.isOverride()) {
return o1.isOverride() ? 1 : -1;
}
if (takesPriority(o2, o1)) {
return -1;
if (o1.isServerSpecific() != o2.isServerSpecific()) {
return o1.isServerSpecific() ? 1 : -1;
}
if (o1.isWorldSpecific() != o2.isWorldSpecific()) {
return o1.isWorldSpecific() ? 1 : -1;
}
if (o1.isTemporary() != o2.isTemporary()) {
return o1.isTemporary() ? 1 : -1;
}
if (o1.isWildcard() != o2.isWildcard()) {
return o1.isWildcard() ? 1 : -1;
}
if (o1.isTemporary()) {
return o1.getSecondsTilExpiry() < o2.getSecondsTilExpiry() ? 1 : -1;
}
if (o1.isWildcard()) {
return o1.getWildcardLevel() > o2.getWildcardLevel() ? 1 : -1;
}
return 1;
}
public boolean takesPriority(Node target, Node over) {
if (target.isTemporary() && !over.isTemporary()) {
return true;
}
if (target.isWorldSpecific() && !over.isWorldSpecific()) {
return true;
}
if (target.isServerSpecific() && !over.isServerSpecific()) {
return true;
}
if (!target.isWildcard() && over.isWildcard()) {
return true;
}
if (target.isWildcard() && over.isWildcard()) {
if (target.getWildcardLevel() > over.getWildcardLevel()) {
return true;
}
}
return false;
}
}
}

View File

@ -321,7 +321,7 @@ public class Group extends PermissionHolder implements Identifiable<String> {
*/
private List<String> getGroups(String server, String world, boolean includeGlobal) {
// Call super #getPermissions method, and just sort through those
Map<String, Boolean> perms = getPermissions(server, world, null, includeGlobal, null, true);
Map<String, Boolean> perms = exportNodes(server, world, null, includeGlobal, true, null);
return perms.keySet().stream()
.filter(s -> Patterns.GROUP_MATCH.matcher(s).matches())
.map(s -> Patterns.DOT.split(s, 2)[1])

View File

@ -28,7 +28,6 @@ import lombok.Cleanup;
import me.lucko.luckperms.LuckPermsPlugin;
import me.lucko.luckperms.api.LogEntry;
import me.lucko.luckperms.constants.Constants;
import me.lucko.luckperms.core.PermissionHolder;
import me.lucko.luckperms.data.Log;
import me.lucko.luckperms.groups.Group;
import me.lucko.luckperms.storage.Datastore;
@ -188,7 +187,7 @@ public class FlatfileDatastore extends Datastore {
writer.name("primaryGroup").value(user.getPrimaryGroup());
writer.name("perms");
writer.beginObject();
for (Map.Entry<String, Boolean> e : convertToLegacy(user.getNodes()).entrySet()) {
for (Map.Entry<String, Boolean> e : exportToLegacy(user.getNodes()).entrySet()) {
writer.name(e.getKey()).value(e.getValue().booleanValue());
}
writer.endObject();
@ -229,7 +228,7 @@ public class FlatfileDatastore extends Datastore {
writer.name("primaryGroup").value(user.getPrimaryGroup());
writer.name("perms");
writer.beginObject();
for (Map.Entry<String, Boolean> e : convertToLegacy(user.getNodes()).entrySet()) {
for (Map.Entry<String, Boolean> e : exportToLegacy(user.getNodes()).entrySet()) {
writer.name(e.getKey()).value(e.getValue().booleanValue());
}
writer.endObject();
@ -295,7 +294,7 @@ public class FlatfileDatastore extends Datastore {
writer.name("primaryGroup").value(user.getPrimaryGroup());
writer.name("perms");
writer.beginObject();
for (Map.Entry<String, Boolean> e : convertToLegacy(user.getNodes()).entrySet()) {
for (Map.Entry<String, Boolean> e : exportToLegacy(user.getNodes()).entrySet()) {
writer.name(e.getKey()).value(e.getValue().booleanValue());
}
writer.endObject();
@ -323,7 +322,7 @@ public class FlatfileDatastore extends Datastore {
writer.name("name").value(group.getName());
writer.name("perms");
writer.beginObject();
for (Map.Entry<String, Boolean> e : convertToLegacy(group.getNodes()).entrySet()) {
for (Map.Entry<String, Boolean> e : exportToLegacy(group.getNodes()).entrySet()) {
writer.name(e.getKey()).value(e.getValue().booleanValue());
}
writer.endObject();
@ -415,7 +414,7 @@ public class FlatfileDatastore extends Datastore {
writer.name("name").value(group.getName());
writer.name("perms");
writer.beginObject();
for (Map.Entry<String, Boolean> e : convertToLegacy(group.getNodes()).entrySet()) {
for (Map.Entry<String, Boolean> e : exportToLegacy(group.getNodes()).entrySet()) {
writer.name(e.getKey()).value(e.getValue().booleanValue());
}
writer.endObject();

View File

@ -31,7 +31,6 @@ import com.mongodb.client.MongoDatabase;
import com.mongodb.client.model.InsertOneOptions;
import me.lucko.luckperms.LuckPermsPlugin;
import me.lucko.luckperms.api.LogEntry;
import me.lucko.luckperms.core.PermissionHolder;
import me.lucko.luckperms.data.Log;
import me.lucko.luckperms.groups.Group;
import me.lucko.luckperms.groups.GroupManager;
@ -46,7 +45,7 @@ import java.util.*;
import java.util.concurrent.Callable;
import java.util.stream.Collectors;
import static me.lucko.luckperms.core.PermissionHolder.convertToLegacy;
import static me.lucko.luckperms.core.PermissionHolder.exportToLegacy;
@SuppressWarnings("unchecked")
public class MongoDBDatastore extends Datastore {
@ -430,7 +429,7 @@ public class MongoDBDatastore extends Datastore {
.append("primaryGroup", user.getPrimaryGroup());
Document perms = new Document();
for (Map.Entry<String, Boolean> e : convert(convertToLegacy(user.getNodes())).entrySet()) {
for (Map.Entry<String, Boolean> e : convert(exportToLegacy(user.getNodes())).entrySet()) {
perms.append(e.getKey(), e.getValue());
}
@ -442,7 +441,7 @@ public class MongoDBDatastore extends Datastore {
Document main = new Document("_id", group.getName());
Document perms = new Document();
for (Map.Entry<String, Boolean> e : convert(convertToLegacy(group.getNodes())).entrySet()) {
for (Map.Entry<String, Boolean> e : convert(exportToLegacy(group.getNodes())).entrySet()) {
perms.append(e.getKey(), e.getValue());
}

View File

@ -330,7 +330,7 @@ public abstract class User extends PermissionHolder implements Identifiable<UUID
*/
private List<String> getGroups(String server, String world, boolean includeGlobal) {
// Call super #getPermissions method, and just sort through those
Map<String, Boolean> perms = getPermissions(server, world, null, includeGlobal, null, true);
Map<String, Boolean> perms = exportNodes(server, world, null, includeGlobal, true, null);
return perms.keySet().stream()
.filter(s -> Patterns.GROUP_MATCH.matcher(s).matches())
.map(s -> Patterns.DOT.split(s, 2)[1])

View File

@ -24,6 +24,7 @@ package me.lucko.luckperms.utils;
import com.google.common.collect.ImmutableMap;
import lombok.*;
import me.lucko.luckperms.api.Tristate;
import me.lucko.luckperms.constants.Patterns;
import java.util.*;
@ -85,6 +86,9 @@ public class Node implements me.lucko.luckperms.api.Node {
@Getter
private Boolean value;
@Getter
private boolean override;
private String server = null;
private String world = null;
@ -101,7 +105,7 @@ public class Node implements me.lucko.luckperms.api.Node {
* @param world the world this node applies on
* @param extraContexts any additional contexts applying to this node
*/
public Node(String permission, boolean value, long expireAt, String server, String world, Map<String, String> extraContexts) {
public Node(String permission, boolean value, boolean override, long expireAt, String server, String world, Map<String, String> extraContexts) {
if (permission == null || permission.equals("")) {
throw new IllegalArgumentException("Empty permission");
}
@ -120,6 +124,7 @@ public class Node implements me.lucko.luckperms.api.Node {
this.permission = permission;
this.value = value;
this.override = override;
this.expireAt = expireAt;
this.server = server;
this.world = world;
@ -129,6 +134,11 @@ public class Node implements me.lucko.luckperms.api.Node {
}
}
@Override
public Tristate getTristate() {
return Tristate.fromBoolean(value);
}
public boolean isNegated() {
return !value;
}
@ -395,6 +405,53 @@ public class Node implements me.lucko.luckperms.api.Node {
return (int) getPermission().chars().filter(num -> num == Character.getNumericValue('.')).count();
}
@Override
public boolean equalsIgnoringValue(me.lucko.luckperms.api.Node other) {
if (!other.getPermission().equalsIgnoreCase(this.getPermission())) {
return false;
}
if (other.isTemporary() != this.isTemporary()) {
return false;
}
if (this.isTemporary()) {
if (other.getExpiryUnixTime() != this.getExpiryUnixTime()) {
return false;
}
}
if (other.getServer().isPresent() != this.getServer().isPresent()) {
if (other.getServer().isPresent()) {
if (!other.getServer().get().equalsIgnoreCase(this.getServer().get())) {
return false;
}
}
} else {
return false;
}
if (other.getWorld().isPresent() != this.getWorld().isPresent()) {
if (other.getWorld().isPresent()) {
if (!other.getWorld().get().equalsIgnoreCase(this.getWorld().get())) {
return false;
}
}
} else {
return false;
}
if (!other.getExtraContexts().equals(this.getExtraContexts())) {
return false;
}
if (other.isTemporary() != this.isTemporary()) {
return false;
}
return true;
}
@Override
public boolean almostEquals(me.lucko.luckperms.api.Node other) {
if (!other.getPermission().equalsIgnoreCase(this.getPermission())) {
@ -446,6 +503,7 @@ public class Node implements me.lucko.luckperms.api.Node {
public static class Builder implements me.lucko.luckperms.api.Node.Builder {
private final String permission;
private Boolean value = true;
private boolean override = false;
private String server = null;
private String world = null;
private long expireAt = 0L;
@ -488,6 +546,12 @@ public class Node implements me.lucko.luckperms.api.Node {
return this;
}
@Override
public me.lucko.luckperms.api.Node.Builder setOverride(boolean override) {
this.override = override;
return this;
}
@Override
public me.lucko.luckperms.api.Node.Builder setExpiry(long expireAt) {
this.expireAt = expireAt;
@ -523,7 +587,7 @@ public class Node implements me.lucko.luckperms.api.Node {
@Override
public me.lucko.luckperms.api.Node build() {
return new Node(permission, value, expireAt, server, world, extraContexts);
return new Node(permission, value, override, expireAt, server, world, extraContexts);
}
}

View File

@ -30,7 +30,10 @@ import org.spongepowered.api.command.CommandException;
import org.spongepowered.api.command.CommandResult;
import org.spongepowered.api.command.CommandSource;
import org.spongepowered.api.text.Text;
import org.spongepowered.api.world.Location;
import org.spongepowered.api.world.World;
import javax.annotation.Nullable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@ -49,6 +52,15 @@ class SpongeCommand extends CommandManager implements CommandCallable {
}
@Override
public List<String> getSuggestions(CommandSource source, String s, @Nullable Location<World> location) throws CommandException {
List<String> args = new ArrayList<>(Arrays.asList(Patterns.SPACE.split(s)));
if (s.endsWith(" ")) {
args.add("");
}
return onTabComplete(SpongeSenderFactory.get().wrap(source), args);
}
public List<String> getSuggestions(CommandSource source, String s) throws CommandException {
List<String> args = new ArrayList<>(Arrays.asList(Patterns.SPACE.split(s)));
if (s.endsWith(" ")) {
@ -64,12 +76,12 @@ class SpongeCommand extends CommandManager implements CommandCallable {
}
@Override
public Optional<? extends Text> getShortDescription(CommandSource source) {
public Optional<Text> getShortDescription(CommandSource source) {
return Optional.of(Text.of("LuckPerms main command."));
}
@Override
public Optional<? extends Text> getHelp(CommandSource source) {
public Optional<Text> getHelp(CommandSource source) {
return Optional.of(Text.of("Type /perms for help."));
}

View File

@ -25,10 +25,7 @@ package me.lucko.luckperms;
import me.lucko.luckperms.constants.Message;
import me.lucko.luckperms.users.User;
import me.lucko.luckperms.utils.AbstractListener;
import org.spongepowered.api.entity.Entity;
import org.spongepowered.api.entity.living.player.Player;
import org.spongepowered.api.event.Listener;
import org.spongepowered.api.event.entity.DisplaceEntityEvent;
import org.spongepowered.api.event.network.ClientConnectionEvent;
import org.spongepowered.api.profile.GameProfile;
import org.spongepowered.api.text.serializer.TextSerializers;
@ -75,8 +72,10 @@ public class SpongeListener extends AbstractListener {
refreshPlayer(e.getTargetEntity().getUniqueId());
}
// TODO Use reflection/any other method to refresh on world change
/*
@Listener
public void onPlayerTeleport(DisplaceEntityEvent.Teleport e) {
public void onPlayerTeleport(DisplaceEntityEvent e) {
final Entity entity = e.getTargetEntity();
if (!(entity instanceof Player)){
return;
@ -84,6 +83,7 @@ public class SpongeListener extends AbstractListener {
refreshPlayer(entity.getUniqueId());
}
*/
@Listener
public void onClientLeave(ClientConnectionEvent.Disconnect e) {

View File

@ -83,4 +83,9 @@ public class GroupCollection implements SubjectCollection {
.map(sub -> new AbstractMap.SimpleEntry<Subject, Boolean>(sub, sub.getPermissionValue(contexts, node).asBoolean()))
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
}
@Override
public Subject getDefaults() {
return null;
}
}

View File

@ -101,4 +101,9 @@ public class UserCollection implements SubjectCollection {
.map(sub -> new AbstractMap.SimpleEntry<Subject, Boolean>(sub, sub.getPermissionValue(contexts, node).asBoolean()))
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
}
@Override
public Subject getDefaults() {
return null;
}
}