diff --git a/api/src/main/java/me/lucko/luckperms/api/Group.java b/api/src/main/java/me/lucko/luckperms/api/Group.java index 9e5cdd1e..ccbab7bf 100644 --- a/api/src/main/java/me/lucko/luckperms/api/Group.java +++ b/api/src/main/java/me/lucko/luckperms/api/Group.java @@ -26,10 +26,12 @@ package me.lucko.luckperms.api; import me.lucko.luckperms.api.caching.GroupData; +import me.lucko.luckperms.api.context.ContextSet; import java.util.OptionalInt; import javax.annotation.Nonnull; +import javax.annotation.Nullable; /** * An inheritable holder of permission data. @@ -44,6 +46,33 @@ public interface Group extends PermissionHolder { @Nonnull String getName(); + /** + * Gets the groups "display name", if it has one that differs from it's actual name. + * + *

The lookup is made using the current servers active context.

+ * + *

Will return null if the groups display name is equal to it's + * {@link #getName() actual name}.

+ * + * @return the display name + * @since 4.3 + */ + @Nullable + String getDisplayName(); + + /** + * Gets the groups "display name", if it has one that differs from it's actual name. + * + *

Will return null if the groups display name is equal to it's + * {@link #getName() actual name}.

+ * + * @param contextSet the contexts to lookup in + * @return the display name + * @since 4.3 + */ + @Nullable + String getDisplayName(@Nonnull ContextSet contextSet); + /** * Gets the weight of this group, if present. * diff --git a/api/src/main/java/me/lucko/luckperms/api/LocalizedNode.java b/api/src/main/java/me/lucko/luckperms/api/LocalizedNode.java index 15f15570..e103058e 100644 --- a/api/src/main/java/me/lucko/luckperms/api/LocalizedNode.java +++ b/api/src/main/java/me/lucko/luckperms/api/LocalizedNode.java @@ -25,13 +25,12 @@ package me.lucko.luckperms.api; -import java.util.function.Predicate; - import javax.annotation.Nonnull; import javax.annotation.concurrent.Immutable; /** - * A node with a traceable origin + * An extension of {@link Node}, providing information about + * where the node originated from. * * @since 2.11 */ @@ -39,19 +38,9 @@ import javax.annotation.concurrent.Immutable; public interface LocalizedNode extends Node { /** - * Returns a predicate which unwraps the localised node parameter before delegating - * the handling to the provided predicate. + * Gets the delegate node. * - * @param delegate the delegate predicate. - * @return the composed predicate - * @since 4.3 - */ - static Predicate composedPredicate(Predicate delegate) { - return localizedNode -> delegate.test(localizedNode.getNode()); - } - - /** - * Gets the delegate node + *

Result is never another {@link LocalizedNode} instance.

* * @return the node this instance is representing */ @@ -59,10 +48,15 @@ public interface LocalizedNode extends Node { Node getNode(); /** - * Gets the location where the {@link Node} is inherited from + * Gets the location where the {@link Node} is inherited from. * - * @return where the node was inherited from. Will not return null. - * @see PermissionHolder#getObjectName() + *

The resultant string is the {@link PermissionHolder#getObjectName() object name} of the + * permission holder the node was inherited from.

+ * + *

If the node was not inherited, the {@link PermissionHolder#getObjectName() object name} + * of the permission holder itself (the one that defined the node) will be returned.

+ * + * @return where the node was inherited from. */ @Nonnull String getLocation(); diff --git a/api/src/main/java/me/lucko/luckperms/api/NodeEqualityPredicate.java b/api/src/main/java/me/lucko/luckperms/api/NodeEqualityPredicate.java index 0312bf12..4c7250d2 100644 --- a/api/src/main/java/me/lucko/luckperms/api/NodeEqualityPredicate.java +++ b/api/src/main/java/me/lucko/luckperms/api/NodeEqualityPredicate.java @@ -33,8 +33,7 @@ import javax.annotation.Nonnull; *

Generally, individual instances of this interface should fulfil the same * requirements as the {@link Object#equals(Object)} contract.

* - *

Some standard implementations are provided by - * {@link StandardNodeEquality}.

+ *

Some standard implementations are provided by {@link StandardNodeEquality}.

* * @since 4.1 */ diff --git a/api/src/main/java/me/lucko/luckperms/api/PermissionHolder.java b/api/src/main/java/me/lucko/luckperms/api/PermissionHolder.java index a5181db5..9e82d4c3 100644 --- a/api/src/main/java/me/lucko/luckperms/api/PermissionHolder.java +++ b/api/src/main/java/me/lucko/luckperms/api/PermissionHolder.java @@ -31,29 +31,40 @@ import com.google.common.collect.Multimap; import me.lucko.luckperms.api.caching.CachedData; import me.lucko.luckperms.api.context.ContextSet; import me.lucko.luckperms.api.context.ImmutableContextSet; +import me.lucko.luckperms.api.manager.GroupManager; +import me.lucko.luckperms.api.manager.UserManager; +import me.lucko.luckperms.api.nodetype.types.MetaType; +import me.lucko.luckperms.api.nodetype.types.PrefixType; +import me.lucko.luckperms.api.nodetype.types.SuffixType; import java.util.List; import java.util.Map; import java.util.Set; import java.util.SortedSet; +import java.util.UUID; import java.util.concurrent.CompletableFuture; import java.util.function.Predicate; import javax.annotation.Nonnull; /** - * An object which holds permissions. - * - *

Any changes made to permission holding objects will be lost unless the - * instance is saved back to the {@link Storage}.

+ * Generic superinterface for an object which holds permissions. */ public interface PermissionHolder { /** - * Gets the objects name. + * Gets the objects generic name. * - *

{@link User#getUuid()}, {@link User#getName()} or {@link Group#getName()} should normally be used instead of - * this method.

+ *

The result of this method is guaranteed to be a unique identifier for distinct instances + * of the same type of object.

+ * + *

For {@link User}s, this method returns a {@link UUID#toString() string} representation of + * the users {@link User#getUuid() unique id}.

+ * + *

For {@link Group}s, this method returns the {@link Group#getName() group name}.

+ * + *

The {@link User#getUuid()}, {@link User#getName()} and {@link Group#getName()} methods + * define a "tighter" specification for obtaining object identifiers.

* * @return the identifier for this object. Either a uuid string or name. */ @@ -63,8 +74,14 @@ public interface PermissionHolder { /** * Gets a friendly name for this holder, to be displayed in command output, etc. * - *

This will always return a value, eventually falling back to {@link #getObjectName()} if no - * other "friendlier" identifiers are present.

+ *

This will always return a value, eventually falling back to + * {@link #getObjectName()} if no other "friendlier" identifiers are present.

+ * + *

For {@link User}s, this method will attempt to return the {@link User#getName() username}, + * before falling back to {@link #getObjectName()}.

+ * + *

For {@link Group}s, this method will attempt to return the groups display name, before + * falling back to {@link #getObjectName()}.

* * @return a friendly identifier for this holder * @since 3.2 @@ -128,6 +145,8 @@ public interface PermissionHolder { * *

Use {@link #getPermissions()} for a view without duplicates.

* + *

This method does not resolve inheritance rules.

+ * * @return a list of the holders own nodes. * @since 3.3 */ @@ -137,6 +156,13 @@ public interface PermissionHolder { /** * Gets a sorted set of all held permissions. * + *

Effectively a sorted version of {@link #getOwnNodes()}, without duplicates. Use the + * aforementioned method if you don't require either of these attributes.

+ * + *

This method does not resolve inheritance rules.

+ * + *

Although this method is named getPermissions, it will actually return all types of node.

+ * * @return an immutable set of permissions in priority order * @since 2.6 */ @@ -144,9 +170,16 @@ public interface PermissionHolder { SortedSet getPermissions(); /** - * Similar to {@link #getPermissions()}, except without transient permissions. + * Similar to {@link #getPermissions()}, except only including permissions from the enduring + * node map. (See {@link #getNodes()}) * - *

Unlike transient permissions, enduring permissions will be saved to storage, and exist after the session.

+ *

Unlike transient permissions, enduring permissions will be saved to storage, and exist + * after the session.

+ * + *

This method does not resolve inheritance rules.

+ * + *

Although this method is named getEnduringPermissions, it will actually return all types + * of node.

* * @return a set of nodes * @since 2.6 @@ -155,10 +188,16 @@ public interface PermissionHolder { Set getEnduringPermissions(); /** - * Similar to {@link #getPermissions()}, except without enduring permissions. + * Similar to {@link #getPermissions()}, except only including permissions from the enduring + * node map. (See {@link #getTransientNodes()}) * *

Transient permissions only exist for the duration of the session.

* + *

This method does not resolve inheritance rules.

+ * + *

Although this method is named getTransientPermissions, it will actually return all types + * of node.

+ * * @return a set of nodes * @since 2.6 */ @@ -166,7 +205,14 @@ public interface PermissionHolder { Set getTransientPermissions(); /** - * Processes the nodes and returns the non-temporary ones. + * A filtered view of this holders nodes, only including permanent entries. + * + *

Data is sourced from {@link #getOwnNodes()}, filtered, and then collected to a set.

+ * + *

This method does not resolve inheritance rules.

+ * + *

Although this method is named getPermanentPermissionNodes, it will actually return all types + * of node.

* * @return a set of permanent nodes * @since 2.6 @@ -175,7 +221,14 @@ public interface PermissionHolder { Set getPermanentPermissionNodes(); /** - * Processes the nodes and returns the temporary ones. + * A filtered view of this holders nodes, only including temporary entries. + * + *

Data is sourced from {@link #getOwnNodes()}, filtered, and then collected to a set.

+ * + *

This method does not resolve inheritance rules.

+ * + *

Although this method is named getTemporaryPermissionNodes, it will actually return all types + * of node.

* * @return a set of temporary nodes * @since 2.6 @@ -191,12 +244,16 @@ public interface PermissionHolder { * *

This means the list will contain duplicates.

* + *

Inheritance is performed according to the platforms rules, and the order will vary + * depending on the accumulation order. By default, the holders own nodes are first in the list, + * with the entries from the end of the inheritance tree appearing last.

+ * * @param contexts the contexts for the lookup * @return a list of nodes * @since 3.3 */ @Nonnull - List resolveInheritances(Contexts contexts); + List resolveInheritances(@Nonnull Contexts contexts); /** * Recursively resolves this holders permissions. @@ -209,6 +266,10 @@ public interface PermissionHolder { *

Unlike {@link #resolveInheritances(Contexts)}, this method does not * filter by context, at all.

* + *

Inheritance is performed according to the platforms rules, and the order will vary + * depending on the accumulation order. By default, the holders own nodes are first in the list, + * with the entries from the end of the inheritance tree appearing last.

+ * * @return a list of nodes * @since 3.3 */ @@ -218,13 +279,14 @@ public interface PermissionHolder { /** * Gets a mutable sorted set of the nodes that this object has and inherits, filtered by context * - *

Unlike {@link #getAllNodesFiltered(Contexts)}, this method will not filter individual nodes. The context is only - * used to determine which groups should apply.

+ *

Unlike {@link #getAllNodesFiltered(Contexts)}, this method will not filter individual + * nodes by context. The context is only used to determine which groups should apply.

* - *

Nodes are sorted into priority order.

+ *

Nodes are sorted into priority order. The order of inheritance is only important during + * the process of flattening inherited entries.

* * @param contexts the context for the lookup - * @return a mutable sorted set of permissions + * @return an immutable sorted set of permissions * @throws NullPointerException if the context is null * @since 2.11 */ @@ -236,9 +298,10 @@ public interface PermissionHolder { * *

Unlike {@link #getAllNodes(Contexts)}, this method does not filter by context, at all.

* - *

Nodes are sorted into priority order.

+ *

Nodes are sorted into priority order. The order of inheritance is only important during + * the process of flattening inherited entries.

* - * @return a mutable sorted set of permissions + * @return an immutable sorted set of permissions * @throws NullPointerException if the context is null * @since 3.3 */ @@ -248,8 +311,8 @@ public interface PermissionHolder { /** * Gets a mutable set of the nodes that this object has and inherits, filtered by context. * - *

Unlike {@link #getAllNodes(Contexts)}, this method WILL filter individual nodes, and only return ones that fully - * meet the context provided.

+ *

Unlike {@link #getAllNodes(Contexts)}, this method WILL filter individual nodes, + * and only return ones that fully meet the context provided.

* * @param contexts the context for the lookup * @return a mutable set of permissions @@ -260,22 +323,28 @@ public interface PermissionHolder { Set getAllNodesFiltered(@Nonnull Contexts contexts); /** - * Converts the output of {@link #getAllNodesFiltered(Contexts)}, and expands shorthand permissions. + * Converts the output of {@link #getAllNodesFiltered(Contexts)} into string and boolean form, + * and expands shorthand permissions. * * @param contexts the context for the lookup - * @param lowerCase if the keys should be made lowercase whilst being exported + * @param convertToLowercase if the keys should be made lowercase whilst being exported * @return a mutable map of permissions */ @Nonnull - Map exportNodes(@Nonnull Contexts contexts, boolean lowerCase); + Map exportNodes(@Nonnull Contexts contexts, boolean convertToLowercase); /** - * Removes temporary permissions that have expired + * Removes any temporary permissions that have expired. + * + *

This method is called periodically by the platform, so it is only necessary to run + * if you want to guarentee that the current data is totally up-to-date.

*/ void auditTemporaryPermissions(); /** - * Checks to see if the object has a certain permission + * Checks to see if the object has a certain permission. + * + *

Although this method is named hasPermission, it can be used for all node types.

* * @param node the node to check for * @param equalityPredicate how to determine if a node matches @@ -287,7 +356,9 @@ public interface PermissionHolder { Tristate hasPermission(@Nonnull Node node, @Nonnull NodeEqualityPredicate equalityPredicate); /** - * Checks to see if the object has a certain permission + * Checks to see if the object has a certain permission. + * + *

Although this method is named hasTransientPermission, it can be used for all node types.

* * @param node the node to check for * @param equalityPredicate how to determine if a node matches @@ -299,7 +370,9 @@ public interface PermissionHolder { Tristate hasTransientPermission(@Nonnull Node node, @Nonnull NodeEqualityPredicate equalityPredicate); /** - * Checks to see if the object inherits a certain permission + * Checks to see if the object inherits a certain permission. + * + *

Although this method is named inheritsPermission, it can be used for all node types.

* * @param node the node to check for * @param equalityPredicate how to determine if a node matches @@ -311,7 +384,9 @@ public interface PermissionHolder { Tristate inheritsPermission(@Nonnull Node node, @Nonnull NodeEqualityPredicate equalityPredicate); /** - * Checks to see if the object has a certain permission + * Checks to see if the object has a certain permission. + * + *

Although this method is named hasPermission, it can be used for all node types.

* * @param node the node to check for * @return a Tristate for the holders permission status for the node @@ -322,7 +397,9 @@ public interface PermissionHolder { Tristate hasPermission(@Nonnull Node node); /** - * Checks to see if the object has a certain permission + * Checks to see if the object has a certain permission. + * + *

Although this method is named hasTransientPermission, it can be used for all node types.

* * @param node the node to check for * @return a Tristate for the holders permission status for the node @@ -333,7 +410,9 @@ public interface PermissionHolder { Tristate hasTransientPermission(@Nonnull Node node); /** - * Checks to see if the object inherits a certain permission + * Checks to see if the object inherits a certain permission. + * + *

Although this method is named inheritsPermission, it can be used for all node types.

* * @param node the node to check for * @return a Tristate for the holders inheritance status for the node @@ -344,7 +423,11 @@ public interface PermissionHolder { Tristate inheritsPermission(@Nonnull Node node); /** - * Check to see if this holder inherits another group directly + * Check to see if this holder inherits another group in the global context. + * + *

"Global context" simply means an empty context set.

+ * + *

This method only checks for direct inheritance - one hop up the inheritance tree.

* * @param group The group to check membership of * @return true if the group inherits the other group @@ -355,7 +438,9 @@ public interface PermissionHolder { boolean inheritsGroup(@Nonnull Group group); /** - * Check to see if this holder inherits another group directly + * Check to see if this holder inherits another group. + * + *

This method only checks for direct inheritance - one hop up the inheritance tree.

* * @param group The group to check membership of * @param contextSet the context set to filter by @@ -367,7 +452,20 @@ public interface PermissionHolder { boolean inheritsGroup(@Nonnull Group group, @Nonnull ContextSet contextSet); /** - * Sets a permission for the object + * Sets a permission node for the permission holder. + * + *

Although this method is named setPermission, it can be used for all node types.

+ * + *

The effect of this mutate operation will not persist in storage unless changes are + * explicitly saved. If changes are not saved, the effect will only be observed until the next + * time the holders permission data is (re)loaded. Changes to {@link User}s should be saved + * using {@link UserManager#saveUser(User)}, and changes to {@link Group}s should be saved + * using {@link GroupManager#saveGroup(Group)}.

+ * + *

Before making changes to a user or group, it may be a good idea to load a fresh copy of + * the backing data from the storage if you haven't done so already, to avoid overwriting changes + * made already. This can be done via {@link UserManager#loadUser(UUID)} or + * {@link GroupManager#loadGroup(String)} respectively.

* * @param node The node to be set * @return the result of the operation @@ -378,16 +476,20 @@ public interface PermissionHolder { DataMutateResult setPermission(@Nonnull Node node); /** - * Sets a transient permission for the object + * Sets a transient permission for the permission holder. * *

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.

+ * 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.

+ *

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)}

+ *

For unsetting a transient permission, see {@link #unsetTransientPermission(Node)}.

+ * + *

Although this method is named setTransientPermission, it can be used for all node types.

* * @param node The node to be set * @return the result of the operation @@ -398,7 +500,20 @@ public interface PermissionHolder { DataMutateResult setTransientPermission(@Nonnull Node node); /** - * Unsets a permission for the object + * Unsets a permission for the permission holder. + * + *

Although this method is named unsetPermission, it can be used for all node types.

+ * + *

The effect of this mutate operation will not persist in storage unless changes are + * explicitly saved. If changes are not saved, the effect will only be observed until the next + * time the holders permission data is (re)loaded. Changes to {@link User}s should be saved + * using {@link UserManager#saveUser(User)}, and changes to {@link Group}s should be saved + * using {@link GroupManager#saveGroup(Group)}.

+ * + *

Before making changes to a user or group, it may be a good idea to load a fresh copy of + * the backing data from the storage if you haven't done so already, to avoid overwriting changes + * made already. This can be done via {@link UserManager#loadUser(UUID)} or + * {@link GroupManager#loadGroup(String)} respectively.

* * @param node The node to be unset * @return the result of the operation @@ -409,7 +524,9 @@ public interface PermissionHolder { DataMutateResult unsetPermission(@Nonnull Node node); /** - * Unsets a transient permission for the object + * Unsets a transient permission for the permission holder. + * + *

Although this method is named unsetTransientPermission, it can be used for all node types.

* * @param node The node to be unset * @return the result of the operation @@ -420,7 +537,20 @@ public interface PermissionHolder { DataMutateResult unsetTransientPermission(@Nonnull Node node); /** - * Clears any nodes from the holder which pass the predicate + * Clears any nodes from the holder which pass the predicate. + * + *

This method only targets enduring data.

+ * + *

The effect of this mutate operation will not persist in storage unless changes are + * explicitly saved. If changes are not saved, the effect will only be observed until the next + * time the holders permission data is (re)loaded. Changes to {@link User}s should be saved + * using {@link UserManager#saveUser(User)}, and changes to {@link Group}s should be saved + * using {@link GroupManager#saveGroup(Group)}.

+ * + *

Before making changes to a user or group, it may be a good idea to load a fresh copy of + * the backing data from the storage if you haven't done so already, to avoid overwriting changes + * made already. This can be done via {@link UserManager#loadUser(UUID)} or + * {@link GroupManager#loadGroup(String)} respectively.

* * @param test the predicate to test for nodes which should be removed * @since 3.2 @@ -428,7 +558,18 @@ public interface PermissionHolder { void clearMatching(@Nonnull Predicate test); /** - * Clears any transient nodes from the holder which pass the predicate + * Clears any transient nodes from the holder which pass the predicate. + * + *

The effect of this mutate operation will not persist in storage unless changes are + * explicitly saved. If changes are not saved, the effect will only be observed until the next + * time the holders permission data is (re)loaded. Changes to {@link User}s should be saved + * using {@link UserManager#saveUser(User)}, and changes to {@link Group}s should be saved + * using {@link GroupManager#saveGroup(Group)}.

+ * + *

Before making changes to a user or group, it may be a good idea to load a fresh copy of + * the backing data from the storage if you haven't done so already, to avoid overwriting changes + * made already. This can be done via {@link UserManager#loadUser(UUID)} or + * {@link GroupManager#loadGroup(String)} respectively.

* * @param test the predicate to test for nodes which should be removed * @since 3.2 @@ -436,14 +577,36 @@ public interface PermissionHolder { void clearMatchingTransient(@Nonnull Predicate test); /** - * Clears all nodes held by the object + * Clears all nodes held by the permission holder. + * + *

The effect of this mutate operation will not persist in storage unless changes are + * explicitly saved. If changes are not saved, the effect will only be observed until the next + * time the holders permission data is (re)loaded. Changes to {@link User}s should be saved + * using {@link UserManager#saveUser(User)}, and changes to {@link Group}s should be saved + * using {@link GroupManager#saveGroup(Group)}.

+ * + *

Before making changes to a user or group, it may be a good idea to load a fresh copy of + * the backing data from the storage if you haven't done so already, to avoid overwriting changes + * made already. This can be done via {@link UserManager#loadUser(UUID)} or + * {@link GroupManager#loadGroup(String)} respectively.

* * @since 2.17 */ void clearNodes(); /** - * Clears all nodes held by the object in a specific context + * Clears all nodes held by the permission holder in a specific context. + * + *

The effect of this mutate operation will not persist in storage unless changes are + * explicitly saved. If changes are not saved, the effect will only be observed until the next + * time the holders permission data is (re)loaded. Changes to {@link User}s should be saved + * using {@link UserManager#saveUser(User)}, and changes to {@link Group}s should be saved + * using {@link GroupManager#saveGroup(Group)}.

+ * + *

Before making changes to a user or group, it may be a good idea to load a fresh copy of + * the backing data from the storage if you haven't done so already, to avoid overwriting changes + * made already. This can be done via {@link UserManager#loadUser(UUID)} or + * {@link GroupManager#loadGroup(String)} respectively.

* * @param contextSet the contexts to filter by * @since 3.2 @@ -451,14 +614,36 @@ public interface PermissionHolder { void clearNodes(@Nonnull ContextSet contextSet); /** - * Clears all parent groups + * Clears all parent groups. + * + *

The effect of this mutate operation will not persist in storage unless changes are + * explicitly saved. If changes are not saved, the effect will only be observed until the next + * time the holders permission data is (re)loaded. Changes to {@link User}s should be saved + * using {@link UserManager#saveUser(User)}, and changes to {@link Group}s should be saved + * using {@link GroupManager#saveGroup(Group)}.

+ * + *

Before making changes to a user or group, it may be a good idea to load a fresh copy of + * the backing data from the storage if you haven't done so already, to avoid overwriting changes + * made already. This can be done via {@link UserManager#loadUser(UUID)} or + * {@link GroupManager#loadGroup(String)} respectively.

* * @since 2.17 */ void clearParents(); /** - * Clears all parent groups in a specific context + * Clears all parent groups in a specific context. + * + *

The effect of this mutate operation will not persist in storage unless changes are + * explicitly saved. If changes are not saved, the effect will only be observed until the next + * time the holders permission data is (re)loaded. Changes to {@link User}s should be saved + * using {@link UserManager#saveUser(User)}, and changes to {@link Group}s should be saved + * using {@link GroupManager#saveGroup(Group)}.

+ * + *

Before making changes to a user or group, it may be a good idea to load a fresh copy of + * the backing data from the storage if you haven't done so already, to avoid overwriting changes + * made already. This can be done via {@link UserManager#loadUser(UUID)} or + * {@link GroupManager#loadGroup(String)} respectively.

* * @param contextSet the contexts to filter by * @since 3.2 @@ -466,14 +651,42 @@ public interface PermissionHolder { void clearParents(@Nonnull ContextSet contextSet); /** - * Clears all meta held by the object + * Clears all meta held by the permission holder. + * + *

Meta nodes in this case, are any nodes which have a {@link MetaType}, {@link PrefixType} + * or {@link SuffixType} type.

+ * + *

The effect of this mutate operation will not persist in storage unless changes are + * explicitly saved. If changes are not saved, the effect will only be observed until the next + * time the holders permission data is (re)loaded. Changes to {@link User}s should be saved + * using {@link UserManager#saveUser(User)}, and changes to {@link Group}s should be saved + * using {@link GroupManager#saveGroup(Group)}.

+ * + *

Before making changes to a user or group, it may be a good idea to load a fresh copy of + * the backing data from the storage if you haven't done so already, to avoid overwriting changes + * made already. This can be done via {@link UserManager#loadUser(UUID)} or + * {@link GroupManager#loadGroup(String)} respectively.

* * @since 2.17 */ void clearMeta(); /** - * Clears all meta held by the object in a specific context + * Clears all meta held by the permission holder in a specific context. + * + *

Meta nodes in this case, are any nodes which have a {@link MetaType}, {@link PrefixType} + * or {@link SuffixType} type.

+ * + *

The effect of this mutate operation will not persist in storage unless changes are + * explicitly saved. If changes are not saved, the effect will only be observed until the next + * time the holders permission data is (re)loaded. Changes to {@link User}s should be saved + * using {@link UserManager#saveUser(User)}, and changes to {@link Group}s should be saved + * using {@link GroupManager#saveGroup(Group)}.

+ * + *

Before making changes to a user or group, it may be a good idea to load a fresh copy of + * the backing data from the storage if you haven't done so already, to avoid overwriting changes + * made already. This can be done via {@link UserManager#loadUser(UUID)} or + * {@link GroupManager#loadGroup(String)} respectively.

* * @param contextSet the contexts to filter by * @since 3.2 @@ -481,12 +694,12 @@ public interface PermissionHolder { void clearMeta(@Nonnull ContextSet contextSet); /** - * Clears all transient permissions the holder has. + * Clears all transient nodes the permission holder has. */ void clearTransientNodes(); /** - * Sets a permission for the object + * Sets a permission for the permission holder. * * @param node The node to be set * @return the result of the operation @@ -501,7 +714,7 @@ public interface PermissionHolder { } /** - * Sets a transient permission for the object + * Sets a transient permission for the permission holder. * * @param node The node to be set * @return the result of the operation @@ -516,7 +729,7 @@ public interface PermissionHolder { } /** - * Unsets a permission for the object + * Unsets a permission for the permission holder. * * @param node The node to be unset * @throws NullPointerException if the node is null @@ -531,7 +744,7 @@ public interface PermissionHolder { } /** - * Unsets a transient permission for the object + * Unsets a transient permission for the permission holder. * * @param node The node to be unset * @throws NullPointerException if the node is null diff --git a/api/src/main/java/me/lucko/luckperms/api/PlayerSaveResult.java b/api/src/main/java/me/lucko/luckperms/api/PlayerSaveResult.java index e070820a..37067a59 100644 --- a/api/src/main/java/me/lucko/luckperms/api/PlayerSaveResult.java +++ b/api/src/main/java/me/lucko/luckperms/api/PlayerSaveResult.java @@ -25,6 +25,8 @@ package me.lucko.luckperms.api; +import me.lucko.luckperms.api.manager.UserManager; + import java.util.Set; import java.util.UUID; @@ -34,6 +36,9 @@ import javax.annotation.Nullable; /** * Encapsulates the result of an operation to save uuid data about a player. * + *

The corresponding method can be found at + * {@link UserManager#savePlayerData(UUID, String)}.

+ * * @since 4.2 */ public interface PlayerSaveResult { diff --git a/api/src/main/java/me/lucko/luckperms/api/User.java b/api/src/main/java/me/lucko/luckperms/api/User.java index 0420a7e7..a3cd3ee8 100644 --- a/api/src/main/java/me/lucko/luckperms/api/User.java +++ b/api/src/main/java/me/lucko/luckperms/api/User.java @@ -48,7 +48,7 @@ public interface User extends PermissionHolder { /** * Gets the users username * - *

Returns null if no username is associated with this user.

+ *

Returns null if no username is known for the user.

* * @return the users username */ @@ -58,8 +58,9 @@ public interface User extends PermissionHolder { /** * Gets the users current primary group. * - *

The result of this method depends on which method is configured for primary group calculation. It may not - * be the same as any value set through {@link #setPrimaryGroup(String)}.

+ *

The result of this method depends on which method is configured for primary group + * calculation. It may not be the same as any value set through + * {@link #setPrimaryGroup(String)}.

* * @return the users primary group */ @@ -67,7 +68,10 @@ public interface User extends PermissionHolder { String getPrimaryGroup(); /** - * Sets a users primary group. This will only take effect if platform is using stored primary groups. + * Sets a users primary group. + * + *

This modifies the "stored value" for the users primary group, which may or may not + * actually take effect, depending on how the platform is calculating primary groups.

* * @param group the new primary group * @return if the change was applied successfully @@ -90,10 +94,9 @@ public interface User extends PermissionHolder { /** * Refresh and re-assign the users permissions. * - *

This request is not buffered, and the refresh call will be ran directly. This should be called on an - * asynchronous thread.

- * - * @deprecated in favour of {@link #refreshCachedData()}. + * @deprecated Calling this method is no longer necessary. Permissions data is now refreshed on + * demand, as changes are made. Consider use of {@link #refreshCachedData()} + * instead. This method is now implemented as a no-op. */ @Deprecated void refreshPermissions(); @@ -101,11 +104,8 @@ public interface User extends PermissionHolder { /** * Pre-calculates some values in the user's data cache. * - *

Is it not necessary to call this method before - * using {@link #getCachedData()}.

- * * @since 2.17 - * @deprecated because use of this method is no longer necessary. + * @deprecated Use of this method is no longer necessary. It is implemented as a no-op. */ @Deprecated void setupDataCache(); diff --git a/api/src/main/java/me/lucko/luckperms/api/caching/CachedData.java b/api/src/main/java/me/lucko/luckperms/api/caching/CachedData.java index 04a8d970..f4036640 100644 --- a/api/src/main/java/me/lucko/luckperms/api/caching/CachedData.java +++ b/api/src/main/java/me/lucko/luckperms/api/caching/CachedData.java @@ -28,6 +28,7 @@ package me.lucko.luckperms.api.caching; import me.lucko.luckperms.api.Contexts; import me.lucko.luckperms.api.PermissionHolder; +import java.util.Objects; import java.util.Set; import java.util.concurrent.CompletableFuture; @@ -372,7 +373,14 @@ public interface CachedData { * @param contexts the contexts to pre-calculate for * @throws NullPointerException if contexts is null */ - void preCalculate(@Nonnull Contexts contexts); + default void preCalculate(@Nonnull Contexts contexts) { + Objects.requireNonNull(contexts, "contexts"); + + // pre-calculate just by requesting the data from this cache. + // if the data isn't already loaded, it will be calculated. + getPermissionData(contexts); + getMetaData(contexts); + } /** * Invalidates any cached {@link PermissionData} instances mapped to the given diff --git a/api/src/main/java/me/lucko/luckperms/api/messenger/IncomingMessageConsumer.java b/api/src/main/java/me/lucko/luckperms/api/messenger/IncomingMessageConsumer.java index 5de6f04d..c568c1f6 100644 --- a/api/src/main/java/me/lucko/luckperms/api/messenger/IncomingMessageConsumer.java +++ b/api/src/main/java/me/lucko/luckperms/api/messenger/IncomingMessageConsumer.java @@ -32,7 +32,7 @@ import javax.annotation.Nonnull; /** * Encapsulates the LuckPerms system which accepts incoming {@link Message}s - * from implementations of {@link MessengerProvider}. + * from implementations of {@link Messenger}. * * @since 4.1 */ diff --git a/api/src/main/java/me/lucko/luckperms/api/messenger/Messenger.java b/api/src/main/java/me/lucko/luckperms/api/messenger/Messenger.java index 3324203a..54bb8fe2 100644 --- a/api/src/main/java/me/lucko/luckperms/api/messenger/Messenger.java +++ b/api/src/main/java/me/lucko/luckperms/api/messenger/Messenger.java @@ -45,12 +45,18 @@ public interface Messenger extends AutoCloseable { * of the interfaces extending {@link Message} in the * 'api.messenger.message.type' package.

* + *

3rd party implementations are encouraged to implement this method with consideration + * that new types may be added in the future.

+ * *

This call is always made async.

* * @param outgoingMessage the outgoing message */ void sendOutgoingMessage(@Nonnull OutgoingMessage outgoingMessage); + /** + * Performs the necessary action to gracefully shutdown the messenger. + */ @Override default void close() { diff --git a/bukkit/src/main/java/me/lucko/luckperms/bukkit/model/permissible/LPPermissionAttachment.java b/bukkit/src/main/java/me/lucko/luckperms/bukkit/model/permissible/LPPermissionAttachment.java index 9ecd7181..4beabacf 100644 --- a/bukkit/src/main/java/me/lucko/luckperms/bukkit/model/permissible/LPPermissionAttachment.java +++ b/bukkit/src/main/java/me/lucko/luckperms/bukkit/model/permissible/LPPermissionAttachment.java @@ -27,13 +27,13 @@ package me.lucko.luckperms.bukkit.model.permissible; import com.google.common.base.Preconditions; -import me.lucko.luckperms.api.LocalizedNode; import me.lucko.luckperms.api.Node; import me.lucko.luckperms.bukkit.model.dummy.DummyPlugin; import me.lucko.luckperms.common.config.ConfigKeys; import me.lucko.luckperms.common.model.User; import me.lucko.luckperms.common.node.factory.NodeFactory; import me.lucko.luckperms.common.node.model.ImmutableTransientNode; +import me.lucko.luckperms.common.node.utils.NodeTools; import org.bukkit.permissions.PermissionAttachment; import org.bukkit.permissions.PermissionRemovedExecutor; @@ -199,13 +199,13 @@ public class LPPermissionAttachment extends PermissionAttachment { // remove transient permissions from the holder which were added by this attachment & equal the permission User user = this.permissible.getUser(); - user.removeIfTransient(LocalizedNode.composedPredicate(n -> n instanceof ImmutableTransientNode && ((ImmutableTransientNode) n).getOwner() == this && n.getPermission().equals(name))); + user.removeIfTransient(NodeTools.localizedNodeComposedPredicate(n -> n instanceof ImmutableTransientNode && ((ImmutableTransientNode) n).getOwner() == this && n.getPermission().equals(name))); } private void clearInternal() { // remove all transient permissions added by this attachment User user = this.permissible.getUser(); - user.removeIfTransient(LocalizedNode.composedPredicate(n -> n instanceof ImmutableTransientNode && ((ImmutableTransientNode) n).getOwner() == this)); + user.removeIfTransient(NodeTools.localizedNodeComposedPredicate(n -> n instanceof ImmutableTransientNode && ((ImmutableTransientNode) n).getOwner() == this)); } @Override diff --git a/common/src/main/java/me/lucko/luckperms/common/api/delegates/model/ApiGroup.java b/common/src/main/java/me/lucko/luckperms/common/api/delegates/model/ApiGroup.java index e2c4101e..d468d350 100644 --- a/common/src/main/java/me/lucko/luckperms/common/api/delegates/model/ApiGroup.java +++ b/common/src/main/java/me/lucko/luckperms/common/api/delegates/model/ApiGroup.java @@ -28,12 +28,14 @@ package me.lucko.luckperms.common.api.delegates.model; import com.google.common.base.Preconditions; import me.lucko.luckperms.api.caching.GroupData; +import me.lucko.luckperms.api.context.ContextSet; import me.lucko.luckperms.common.model.Group; import java.util.Objects; import java.util.OptionalInt; import javax.annotation.Nonnull; +import javax.annotation.Nullable; public final class ApiGroup extends ApiPermissionHolder implements me.lucko.luckperms.api.Group { public static Group cast(me.lucko.luckperms.api.Group group) { @@ -60,6 +62,18 @@ public final class ApiGroup extends ApiPermissionHolder implements me.lucko.luck return this.handle.getName(); } + @Nullable + @Override + public String getDisplayName() { + return this.handle.getDisplayName().orElse(null); + } + + @Nullable + @Override + public String getDisplayName(@Nonnull ContextSet contextSet) { + return this.handle.getDisplayName(contextSet).orElse(null); + } + @Nonnull @Override public OptionalInt getWeight() { diff --git a/common/src/main/java/me/lucko/luckperms/common/api/delegates/model/ApiPermissionHolder.java b/common/src/main/java/me/lucko/luckperms/common/api/delegates/model/ApiPermissionHolder.java index d2267ed9..711ff279 100644 --- a/common/src/main/java/me/lucko/luckperms/common/api/delegates/model/ApiPermissionHolder.java +++ b/common/src/main/java/me/lucko/luckperms/common/api/delegates/model/ApiPermissionHolder.java @@ -342,7 +342,7 @@ public class ApiPermissionHolder implements me.lucko.luckperms.api.PermissionHol @Nonnull @Override - public List resolveInheritances(Contexts contexts) { + public List resolveInheritances(@Nonnull Contexts contexts) { Objects.requireNonNull(contexts, "contexts"); return ImmutableList.copyOf(this.handle.resolveInheritances(contexts)); } diff --git a/common/src/main/java/me/lucko/luckperms/common/caching/AbstractCachedData.java b/common/src/main/java/me/lucko/luckperms/common/caching/AbstractCachedData.java index 1f523aa6..1038bd0a 100644 --- a/common/src/main/java/me/lucko/luckperms/common/caching/AbstractCachedData.java +++ b/common/src/main/java/me/lucko/luckperms/common/caching/AbstractCachedData.java @@ -186,7 +186,7 @@ public abstract class AbstractCachedData implements CachedData { @Nonnull @Override - public PermissionCache getPermissionData(@Nonnull Contexts contexts) { + public final PermissionCache getPermissionData(@Nonnull Contexts contexts) { Objects.requireNonNull(contexts, "contexts"); //noinspection ConstantConditions @@ -195,7 +195,7 @@ public abstract class AbstractCachedData implements CachedData { @Nonnull @Override - public MetaCache getMetaData(@Nonnull MetaContexts contexts) { + public final MetaCache getMetaData(@Nonnull MetaContexts contexts) { Objects.requireNonNull(contexts, "contexts"); //noinspection ConstantConditions @@ -204,53 +204,53 @@ public abstract class AbstractCachedData implements CachedData { @Nonnull @Override - public MetaCache getMetaData(@Nonnull Contexts contexts) { + public final MetaCache getMetaData(@Nonnull Contexts contexts) { Objects.requireNonNull(contexts, "contexts"); return getMetaData(getDefaultMetaContexts(contexts)); } @Nonnull @Override - public PermissionCache calculatePermissions(@Nonnull Contexts contexts) { + public final PermissionCache calculatePermissions(@Nonnull Contexts contexts) { Objects.requireNonNull(contexts, "contexts"); return calculatePermissions(contexts, null); } @Nonnull @Override - public MetaCache calculateMeta(@Nonnull MetaContexts contexts) { + public final MetaCache calculateMeta(@Nonnull MetaContexts contexts) { Objects.requireNonNull(contexts, "contexts"); return calculateMeta(contexts, null); } @Nonnull @Override - public MetaCache calculateMeta(@Nonnull Contexts contexts) { + public final MetaCache calculateMeta(@Nonnull Contexts contexts) { Objects.requireNonNull(contexts, "contexts"); return calculateMeta(getDefaultMetaContexts(contexts)); } @Override - public void recalculatePermissions(@Nonnull Contexts contexts) { + public final void recalculatePermissions(@Nonnull Contexts contexts) { Objects.requireNonNull(contexts, "contexts"); this.permission.synchronous().refresh(contexts); } @Override - public void recalculateMeta(@Nonnull MetaContexts contexts) { + public final void recalculateMeta(@Nonnull MetaContexts contexts) { Objects.requireNonNull(contexts, "contexts"); this.meta.synchronous().refresh(contexts); } @Override - public void recalculateMeta(@Nonnull Contexts contexts) { + public final void recalculateMeta(@Nonnull Contexts contexts) { Objects.requireNonNull(contexts, "contexts"); recalculateMeta(getDefaultMetaContexts(contexts)); } @Nonnull @Override - public CompletableFuture reloadPermissions(@Nonnull Contexts contexts) { + public final CompletableFuture reloadPermissions(@Nonnull Contexts contexts) { Objects.requireNonNull(contexts, "contexts"); // get the previous value - to use when recalculating @@ -271,7 +271,7 @@ public abstract class AbstractCachedData implements CachedData { @Nonnull @Override - public CompletableFuture reloadMeta(@Nonnull MetaContexts contexts) { + public final CompletableFuture reloadMeta(@Nonnull MetaContexts contexts) { Objects.requireNonNull(contexts, "contexts"); // get the previous value - to use when recalculating @@ -292,86 +292,76 @@ public abstract class AbstractCachedData implements CachedData { @Nonnull @Override - public CompletableFuture reloadMeta(@Nonnull Contexts contexts) { + public final CompletableFuture reloadMeta(@Nonnull Contexts contexts) { Objects.requireNonNull(contexts, "contexts"); return reloadMeta(getDefaultMetaContexts(contexts)); } @Override - public void recalculatePermissions() { + public final void recalculatePermissions() { Set keys = this.permission.synchronous().asMap().keySet(); keys.forEach(this::recalculatePermissions); } @Override - public void recalculateMeta() { + public final void recalculateMeta() { Set keys = this.meta.synchronous().asMap().keySet(); keys.forEach(this::recalculateMeta); } @Nonnull @Override - public CompletableFuture reloadPermissions() { + public final CompletableFuture reloadPermissions() { Set keys = this.permission.synchronous().asMap().keySet(); return CompletableFuture.allOf(keys.stream().map(this::reloadPermissions).toArray(CompletableFuture[]::new)); } @Nonnull @Override - public CompletableFuture reloadMeta() { + public final CompletableFuture reloadMeta() { Set keys = this.meta.synchronous().asMap().keySet(); return CompletableFuture.allOf(keys.stream().map(this::reloadMeta).toArray(CompletableFuture[]::new)); } @Override - public void preCalculate(@Nonnull Contexts contexts) { - Objects.requireNonNull(contexts, "contexts"); - - // pre-calculate just by requesting the data from this cache. - // if the data isn't already loaded, it will be calculated. - getPermissionData(contexts); - getMetaData(contexts); - } - - @Override - public void invalidatePermissions(@Nonnull Contexts contexts) { + public final void invalidatePermissions(@Nonnull Contexts contexts) { Objects.requireNonNull(contexts, "contexts"); this.permission.synchronous().invalidate(contexts); } @Override - public void invalidateMeta(@Nonnull MetaContexts contexts) { + public final void invalidateMeta(@Nonnull MetaContexts contexts) { Objects.requireNonNull(contexts, "contexts"); this.meta.synchronous().invalidate(contexts); } @Override - public void invalidateMeta(@Nonnull Contexts contexts) { + public final void invalidateMeta(@Nonnull Contexts contexts) { Objects.requireNonNull(contexts, "contexts"); this.meta.synchronous().invalidate(getDefaultMetaContexts(contexts)); } @Override - public void invalidatePermissions() { + public final void invalidatePermissions() { this.permission.synchronous().invalidateAll(); } @Override - public void invalidateMeta() { + public final void invalidateMeta() { this.meta.synchronous().invalidateAll(); } @Override - public void invalidatePermissionCalculators() { + public final void invalidatePermissionCalculators() { this.permission.synchronous().asMap().values().forEach(PermissionCache::invalidateCache); } - public void invalidate() { + public final void invalidate() { invalidatePermissions(); invalidateMeta(); } - public void doCacheCleanup() { + public final void doCacheCleanup() { this.permission.synchronous().cleanUp(); this.meta.synchronous().cleanUp(); } diff --git a/common/src/main/java/me/lucko/luckperms/common/node/utils/NodeTools.java b/common/src/main/java/me/lucko/luckperms/common/node/utils/NodeTools.java index 466dea20..d892a480 100644 --- a/common/src/main/java/me/lucko/luckperms/common/node/utils/NodeTools.java +++ b/common/src/main/java/me/lucko/luckperms/common/node/utils/NodeTools.java @@ -25,6 +25,7 @@ package me.lucko.luckperms.common.node.utils; +import me.lucko.luckperms.api.LocalizedNode; import me.lucko.luckperms.api.Node; import me.lucko.luckperms.api.NodeEqualityPredicate; @@ -33,6 +34,7 @@ import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Set; +import java.util.function.Predicate; public final class NodeTools { @@ -64,5 +66,17 @@ public final class NodeTools { } } + /** + * Returns a predicate which unwraps the localised node parameter before delegating + * the handling to the provided predicate. + * + * @param delegate the delegate predicate. + * @return the composed predicate + * @since 4.3 + */ + public static Predicate localizedNodeComposedPredicate(Predicate delegate) { + return localizedNode -> delegate.test(localizedNode.getNode()); + } + private NodeTools() {} } diff --git a/nukkit/src/main/java/me/lucko/luckperms/nukkit/model/permissible/LPPermissionAttachment.java b/nukkit/src/main/java/me/lucko/luckperms/nukkit/model/permissible/LPPermissionAttachment.java index 09ac5366..e26d8e25 100644 --- a/nukkit/src/main/java/me/lucko/luckperms/nukkit/model/permissible/LPPermissionAttachment.java +++ b/nukkit/src/main/java/me/lucko/luckperms/nukkit/model/permissible/LPPermissionAttachment.java @@ -27,12 +27,12 @@ package me.lucko.luckperms.nukkit.model.permissible; import com.google.common.base.Preconditions; -import me.lucko.luckperms.api.LocalizedNode; import me.lucko.luckperms.api.Node; import me.lucko.luckperms.common.config.ConfigKeys; import me.lucko.luckperms.common.model.User; import me.lucko.luckperms.common.node.factory.NodeFactory; import me.lucko.luckperms.common.node.model.ImmutableTransientNode; +import me.lucko.luckperms.common.node.utils.NodeTools; import me.lucko.luckperms.nukkit.model.dummy.DummyPlugin; import cn.nukkit.permission.Permission; @@ -200,13 +200,13 @@ public class LPPermissionAttachment extends PermissionAttachment { // remove transient permissions from the holder which were added by this attachment & equal the permission User user = this.permissible.getUser(); - user.removeIfTransient(LocalizedNode.composedPredicate(n -> n instanceof ImmutableTransientNode && ((ImmutableTransientNode) n).getOwner() == this && n.getPermission().equals(name))); + user.removeIfTransient(NodeTools.localizedNodeComposedPredicate(n -> n instanceof ImmutableTransientNode && ((ImmutableTransientNode) n).getOwner() == this && n.getPermission().equals(name))); } private void clearInternal() { // remove all transient permissions added by this attachment User user = this.permissible.getUser(); - user.removeIfTransient(LocalizedNode.composedPredicate(n -> n instanceof ImmutableTransientNode && ((ImmutableTransientNode) n).getOwner() == this)); + user.removeIfTransient(NodeTools.localizedNodeComposedPredicate(n -> n instanceof ImmutableTransientNode && ((ImmutableTransientNode) n).getOwner() == this)); } @Override