diff --git a/api/src/main/java/net/luckperms/api/model/PermissionHolder.java b/api/src/main/java/net/luckperms/api/model/PermissionHolder.java
index 47fea0e7e..36cb8bd45 100644
--- a/api/src/main/java/net/luckperms/api/model/PermissionHolder.java
+++ b/api/src/main/java/net/luckperms/api/model/PermissionHolder.java
@@ -31,13 +31,17 @@ import net.luckperms.api.model.data.NodeMap;
import net.luckperms.api.model.group.Group;
import net.luckperms.api.model.user.User;
import net.luckperms.api.node.Node;
+import net.luckperms.api.node.NodeType;
import net.luckperms.api.query.QueryOptions;
import org.checkerframework.checker.nullness.qual.NonNull;
+import java.util.ArrayList;
import java.util.Collection;
+import java.util.List;
import java.util.SortedSet;
import java.util.UUID;
+import java.util.stream.Collectors;
/**
* Generic superinterface for an object which holds permissions.
@@ -121,7 +125,7 @@ public interface PermissionHolder {
* @param dataType the data type
* @return the data
*/
- NodeMap getData(@NonNull DataType dataType);
+ @NonNull NodeMap getData(@NonNull DataType dataType);
/**
* Gets the holders {@link DataType#NORMAL} data.
@@ -149,35 +153,60 @@ public interface PermissionHolder {
@NonNull NodeMap transientData();
/**
- * Gets a flattened/squashed view of the holders permissions.
+ * Gets a flattened view of the holders own {@link Node}s.
*
- *
This list is constructed using the values
- * of both the transient and enduring backing multimaps.
+ * This list is constructed using the values of both the {@link #data() normal}
+ * and {@link #transientData() transient} backing node maps.
*
- * This means that it may contain duplicate entries.
- *
- * Use {@link #getDistinctNodes()} for a view without duplicates.
+ * It may contain duplicate entries if the same node is added to both the normal
+ * and transient node maps. You can use {@link #getDistinctNodes()} for a view without
+ * duplicates.
*
* This method does not resolve inheritance rules.
*
- * @return a list of the holders own nodes.
+ * @return a collection of the holders own nodes.
*/
- @NonNull Collection getNodes();
+ default @NonNull Collection getNodes() {
+ /* This default method is overridden in the implementation, and is just here
+ to demonstrate what this method does in the API sources. */
+ List nodes = new ArrayList<>();
+ nodes.addAll(data().toCollection());
+ nodes.addAll(transientData().toCollection());
+ return nodes;
+ }
/**
- * Gets a sorted set of all held nodes.
+ * Gets a flattened view of the holders own {@link Node}s of the given {@code type}.
+ *
+ * @param type the type of node to filter by
+ * @param the node type
+ * @return a filtered collection of the holders own nodes
+ * @see #getNodes()
+ * @since 5.1
+ */
+ default @NonNull Collection getNodes(@NonNull NodeType type) {
+ /* This default method is overridden in the implementation, and is just here
+ to demonstrate what this method does in the API sources. */
+ return getNodes().stream()
+ .filter(type::matches)
+ .map(type::cast)
+ .collect(Collectors.toList());
+ }
+
+ /**
+ * Gets a flattened and sorted view of the holders own distinct {@link Node}s.
*
* Effectively a sorted version of {@link #getNodes()}, without duplicates. Use the
* aforementioned method if you don't require either of these attributes.
*
* This method does not resolve inheritance rules.
*
- * @return an immutable set of permissions in priority order
+ * @return a sorted set of the holders own distinct nodes
*/
@NonNull SortedSet getDistinctNodes();
/**
- * Recursively resolves this holders permissions.
+ * Gets a resolved view of the holders own and inherited {@link Node}s.
*
* The returned list will contain every inherited
* node the holder has, in the order that they were inherited in.
@@ -189,22 +218,62 @@ public interface PermissionHolder {
* with the entries from the end of the inheritance tree appearing last.
*
* @param queryOptions the query options
- * @return a list of nodes
+ * @return a list of the holders inherited nodes
*/
@NonNull Collection resolveInheritedNodes(@NonNull QueryOptions queryOptions);
/**
- * Gets a mutable sorted set of the nodes that this object has and inherits, filtered by context
+ * Gets a resolved view of the holders own and inherited {@link Node}s of a given {@code type}.
*
- * Nodes are sorted into priority order. The order of inheritance is only important during
- * the process of flattening inherited entries.
+ * @param type the type of node to filter by
+ * @param queryOptions the query options
+ * @param the node type
+ * @return a filtered list of the holders inherited nodes
+ * @see #resolveInheritedNodes(QueryOptions)
+ * @since 5.1
+ */
+ default @NonNull Collection resolveInheritedNodes(@NonNull NodeType type, @NonNull QueryOptions queryOptions) {
+ /* This default method is overridden in the implementation, and is just here
+ to demonstrate what this method does in the API sources. */
+ return resolveInheritedNodes(queryOptions).stream()
+ .filter(type::matches)
+ .map(type::cast)
+ .collect(Collectors.toList());
+ }
+
+ /**
+ * Gets a resolved and sorted view of the holders own and inherited distinct {@link Node}s.
+ *
+ * Effectively a sorted version of {@link #resolveInheritedNodes(QueryOptions)},
+ * without duplicates. Use the aforementioned method if you don't require either of these
+ * attributes.
+ *
+ * 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 queryOptions the query options
- * @return an immutable sorted set of permissions
- * @throws NullPointerException if the context is null
+ * @return a sorted set of the holders distinct inherited nodes
*/
@NonNull SortedSet resolveDistinctInheritedNodes(@NonNull QueryOptions queryOptions);
+ /**
+ * Gets a collection of the {@link Group}s this holder inherits nodes from, both directly
+ * and indirectly (through directly inherited groups).
+ *
+ * It effectively resolves the whole "inheritance tree".
+ *
+ * The collection will be ordered according to the platforms inheritance rules. The groups
+ * which are inherited from first will appear earlier in the list.
+ *
+ * The list will not contain the holder.
+ *
+ * @param queryOptions the query options
+ * @return a collection of the groups the holder inherits from
+ * @since 5.1
+ */
+ @NonNull Collection getInheritedGroups(@NonNull QueryOptions queryOptions);
+
/**
* Removes any temporary permissions that have expired.
*
diff --git a/common/src/main/java/me/lucko/luckperms/common/api/implementation/ApiPermissionHolder.java b/common/src/main/java/me/lucko/luckperms/common/api/implementation/ApiPermissionHolder.java
index b4282d094..781381486 100644
--- a/common/src/main/java/me/lucko/luckperms/common/api/implementation/ApiPermissionHolder.java
+++ b/common/src/main/java/me/lucko/luckperms/common/api/implementation/ApiPermissionHolder.java
@@ -27,6 +27,7 @@ package me.lucko.luckperms.common.api.implementation;
import me.lucko.luckperms.common.model.PermissionHolder;
import me.lucko.luckperms.common.query.QueryOptionsImpl;
+import me.lucko.luckperms.common.util.ImmutableCollectors;
import net.luckperms.api.cacheddata.CachedDataManager;
import net.luckperms.api.context.ContextSet;
@@ -35,8 +36,10 @@ import net.luckperms.api.model.data.DataMutateResult;
import net.luckperms.api.model.data.DataType;
import net.luckperms.api.model.data.NodeMap;
import net.luckperms.api.model.data.TemporaryNodeMergeStrategy;
+import net.luckperms.api.model.group.Group;
import net.luckperms.api.node.Node;
import net.luckperms.api.node.NodeEqualityPredicate;
+import net.luckperms.api.node.NodeType;
import net.luckperms.api.query.QueryOptions;
import net.luckperms.api.util.Tristate;
@@ -88,7 +91,7 @@ public class ApiPermissionHolder implements net.luckperms.api.model.PermissionHo
}
@Override
- public NodeMap getData(@NonNull DataType dataType) {
+ public @NonNull NodeMap getData(@NonNull DataType dataType) {
switch (dataType) {
case NORMAL:
return this.normalData;
@@ -114,6 +117,12 @@ public class ApiPermissionHolder implements net.luckperms.api.model.PermissionHo
return this.handle.getOwnNodes(QueryOptionsImpl.DEFAULT_NON_CONTEXTUAL);
}
+ @Override
+ public @NonNull Collection getNodes(@NonNull NodeType type) {
+ Objects.requireNonNull(type, "type");
+ return this.handle.getOwnNodes(type, QueryOptionsImpl.DEFAULT_NON_CONTEXTUAL);
+ }
+
@Override
public @NonNull SortedSet getDistinctNodes() {
return this.handle.getOwnNodesSorted(QueryOptionsImpl.DEFAULT_NON_CONTEXTUAL);
@@ -121,14 +130,31 @@ public class ApiPermissionHolder implements net.luckperms.api.model.PermissionHo
@Override
public @NonNull List resolveInheritedNodes(@NonNull QueryOptions queryOptions) {
+ Objects.requireNonNull(queryOptions, "queryOptions");
return this.handle.resolveInheritedNodes(queryOptions);
}
+ @Override
+ public @NonNull Collection resolveInheritedNodes(@NonNull NodeType type, @NonNull QueryOptions queryOptions) {
+ Objects.requireNonNull(type, "type");
+ Objects.requireNonNull(queryOptions, "queryOptions");
+ return this.handle.resolveInheritedNodes(type, queryOptions);
+ }
+
@Override
public @NonNull SortedSet resolveDistinctInheritedNodes(@NonNull QueryOptions queryOptions) {
+ Objects.requireNonNull(queryOptions, "queryOptions");
return this.handle.resolveInheritedNodesSorted(queryOptions);
}
+ @Override
+ public @NonNull Collection getInheritedGroups(@NonNull QueryOptions queryOptions) {
+ Objects.requireNonNull(queryOptions, "queryOptions");
+ return this.handle.resolveInheritanceTree(queryOptions).stream()
+ .map(me.lucko.luckperms.common.model.Group::getApiProxy)
+ .collect(ImmutableCollectors.toList());
+ }
+
@Override
public void auditTemporaryNodes() {
this.handle.auditTemporaryNodes();
@@ -153,11 +179,14 @@ public class ApiPermissionHolder implements net.luckperms.api.model.PermissionHo
@Override
public @NonNull Tristate contains(@NonNull Node node, @NonNull NodeEqualityPredicate equalityPredicate) {
+ Objects.requireNonNull(node, "node");
+ Objects.requireNonNull(equalityPredicate, "equalityPredicate");
return ApiPermissionHolder.this.handle.hasNode(this.dataType, node, equalityPredicate);
}
@Override
public @NonNull DataMutateResult add(@NonNull Node node) {
+ Objects.requireNonNull(node, "node");
DataMutateResult result = ApiPermissionHolder.this.handle.setNode(this.dataType, node, true);
if (result.wasSuccessful()) {
onNodeChange();
@@ -167,6 +196,8 @@ public class ApiPermissionHolder implements net.luckperms.api.model.PermissionHo
@Override
public DataMutateResult.@NonNull WithMergedNode add(@NonNull Node node, @NonNull TemporaryNodeMergeStrategy temporaryNodeMergeStrategy) {
+ Objects.requireNonNull(node, "node");
+ Objects.requireNonNull(temporaryNodeMergeStrategy, "temporaryNodeMergeStrategy");
DataMutateResult.WithMergedNode result = ApiPermissionHolder.this.handle.setNode(this.dataType, node, temporaryNodeMergeStrategy);
if (result.getResult().wasSuccessful()) {
onNodeChange();
@@ -176,6 +207,7 @@ public class ApiPermissionHolder implements net.luckperms.api.model.PermissionHo
@Override
public @NonNull DataMutateResult remove(@NonNull Node node) {
+ Objects.requireNonNull(node, "node");
DataMutateResult result = ApiPermissionHolder.this.handle.unsetNode(this.dataType, node);
if (result.wasSuccessful()) {
onNodeChange();
@@ -192,6 +224,7 @@ public class ApiPermissionHolder implements net.luckperms.api.model.PermissionHo
@Override
public void clear(@NonNull Predicate super Node> test) {
+ Objects.requireNonNull(test, "test");
if (ApiPermissionHolder.this.handle.removeIf(this.dataType, null, test, true)) {
onNodeChange();
}
@@ -200,6 +233,7 @@ public class ApiPermissionHolder implements net.luckperms.api.model.PermissionHo
@Override
public void clear(@NonNull ContextSet contextSet) {
+ Objects.requireNonNull(contextSet, "contextSet");
if (ApiPermissionHolder.this.handle.clearNodes(this.dataType, contextSet, true)) {
onNodeChange();
}
@@ -207,6 +241,8 @@ public class ApiPermissionHolder implements net.luckperms.api.model.PermissionHo
@Override
public void clear(@NonNull ContextSet contextSet, @NonNull Predicate super Node> test) {
+ Objects.requireNonNull(contextSet, "contextSet");
+ Objects.requireNonNull(test, "test");
if (ApiPermissionHolder.this.handle.removeIf(this.dataType, contextSet, test, true)) {
onNodeChange();
}
diff --git a/common/src/main/java/me/lucko/luckperms/common/model/NodeMap.java b/common/src/main/java/me/lucko/luckperms/common/model/NodeMap.java
index d1102d55f..affdabb6c 100644
--- a/common/src/main/java/me/lucko/luckperms/common/model/NodeMap.java
+++ b/common/src/main/java/me/lucko/luckperms/common/model/NodeMap.java
@@ -41,6 +41,7 @@ import net.luckperms.api.context.DefaultContextKeys;
import net.luckperms.api.context.ImmutableContextSet;
import net.luckperms.api.node.Node;
import net.luckperms.api.node.NodeEqualityPredicate;
+import net.luckperms.api.node.NodeType;
import net.luckperms.api.node.metadata.types.InheritanceOriginMetadata;
import net.luckperms.api.node.types.InheritanceNode;
import net.luckperms.api.query.Flag;
@@ -63,6 +64,7 @@ import java.util.SortedSet;
import java.util.TreeSet;
import java.util.concurrent.ConcurrentSkipListMap;
import java.util.concurrent.ConcurrentSkipListSet;
+import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Stream;
@@ -152,19 +154,69 @@ public final class NodeMap {
!flagExcludeTest(Flag.APPLY_INHERITANCE_NODES_WITHOUT_WORLD_CONTEXT, DefaultContextKeys.WORLD_KEY, filter, contextSet);
}
+ public void forEach(QueryOptions filter, Consumer super Node> consumer) {
+ for (Map.Entry> e : this.map.entrySet()) {
+ if (!filter.satisfies(e.getKey())) {
+ continue;
+ }
+
+ if (normalNodesExcludeTest(filter, e.getKey())) {
+ if (inheritanceNodesIncludeTest(filter, e.getKey())) {
+ // only copy inheritance nodes.
+ SortedSet inheritanceNodes = this.inheritanceMap.get(e.getKey());
+ if (inheritanceNodes != null) {
+ inheritanceNodes.forEach(consumer);
+ }
+ }
+ } else {
+ e.getValue().forEach(consumer);
+ }
+ }
+ }
+
public void copyTo(Collection super Node> collection, QueryOptions filter) {
for (Map.Entry> e : this.map.entrySet()) {
- if (filter.satisfies(e.getKey())) {
- if (normalNodesExcludeTest(filter, e.getKey())) {
- if (inheritanceNodesIncludeTest(filter, e.getKey())) {
- // only copy inheritance nodes.
+ if (!filter.satisfies(e.getKey())) {
+ continue;
+ }
+
+ if (normalNodesExcludeTest(filter, e.getKey())) {
+ if (inheritanceNodesIncludeTest(filter, e.getKey())) {
+ // only copy inheritance nodes.
+ SortedSet inheritanceNodes = this.inheritanceMap.get(e.getKey());
+ if (inheritanceNodes != null) {
+ collection.addAll(inheritanceNodes);
+ }
+ }
+ } else {
+ collection.addAll(e.getValue());
+ }
+ }
+ }
+
+ public void copyTo(Collection super T> collection, NodeType type, QueryOptions filter) {
+ for (Map.Entry> e : this.map.entrySet()) {
+ if (!filter.satisfies(e.getKey())) {
+ continue;
+ }
+
+ if (normalNodesExcludeTest(filter, e.getKey())) {
+ if (inheritanceNodesIncludeTest(filter, e.getKey())) {
+ // only copy inheritance nodes.
+ if (type == NodeType.INHERITANCE) {
SortedSet inheritanceNodes = this.inheritanceMap.get(e.getKey());
if (inheritanceNodes != null) {
- collection.addAll(inheritanceNodes);
+ for (InheritanceNode node : inheritanceNodes) {
+ collection.add(type.cast(node));
+ }
}
}
- } else {
- collection.addAll(e.getValue());
+ }
+ } else {
+ for (Node node : e.getValue()) {
+ if (type.matches(node)) {
+ collection.add(type.cast(node));
+ }
}
}
}
@@ -172,10 +224,12 @@ public final class NodeMap {
public void copyInheritanceNodesTo(Collection super InheritanceNode> collection, QueryOptions filter) {
for (Map.Entry> e : this.inheritanceMap.entrySet()) {
- if (filter.satisfies(e.getKey())) {
- if (inheritanceNodesIncludeTest(filter, e.getKey())) {
- collection.addAll(e.getValue());
- }
+ if (!filter.satisfies(e.getKey())) {
+ continue;
+ }
+
+ if (inheritanceNodesIncludeTest(filter, e.getKey())) {
+ collection.addAll(e.getValue());
}
}
}
diff --git a/common/src/main/java/me/lucko/luckperms/common/model/PermissionHolder.java b/common/src/main/java/me/lucko/luckperms/common/model/PermissionHolder.java
index f21a66df5..545e29975 100644
--- a/common/src/main/java/me/lucko/luckperms/common/model/PermissionHolder.java
+++ b/common/src/main/java/me/lucko/luckperms/common/model/PermissionHolder.java
@@ -27,6 +27,7 @@ package me.lucko.luckperms.common.model;
import com.google.common.collect.ImmutableCollection;
import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Iterables;
import com.google.common.collect.Multimap;
import me.lucko.luckperms.common.cacheddata.HolderCachedDataManager;
@@ -59,6 +60,7 @@ import java.time.Duration;
import java.time.Instant;
import java.util.ArrayList;
import java.util.Collection;
+import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
@@ -249,73 +251,124 @@ public abstract class PermissionHolder {
invalidateCache();
}
- public List getOwnNodes(QueryOptions queryOptions) {
- List nodes = new ArrayList<>();
-
+ private List queryOrder(QueryOptions queryOptions) {
Comparator comparator = queryOptions.option(DataQueryOrderFunction.KEY)
.map(func -> func.getOrderComparator(getIdentifier()))
.orElse(DataQueryOrder.TRANSIENT_FIRST);
- for (DataType dataType : DataQueryOrder.order(comparator)) {
+ return DataQueryOrder.order(comparator);
+ }
+
+ public List getOwnNodes(QueryOptions queryOptions) {
+ List nodes = new ArrayList<>();
+ for (DataType dataType : queryOrder(queryOptions)) {
getData(dataType).copyTo(nodes, queryOptions);
}
-
return nodes;
}
public SortedSet getOwnNodesSorted(QueryOptions queryOptions) {
SortedSet nodes = new TreeSet<>(NodeWithContextComparator.reverse());
-
- Comparator comparator = queryOptions.option(DataQueryOrderFunction.KEY)
- .map(func -> func.getOrderComparator(getIdentifier()))
- .orElse(DataQueryOrder.TRANSIENT_FIRST);
-
- for (DataType dataType : DataQueryOrder.order(comparator)) {
+ for (DataType dataType : queryOrder(queryOptions)) {
getData(dataType).copyTo(nodes, queryOptions);
}
-
return nodes;
}
public List getOwnInheritanceNodes(QueryOptions queryOptions) {
List nodes = new ArrayList<>();
-
- Comparator comparator = queryOptions.option(DataQueryOrderFunction.KEY)
- .map(func -> func.getOrderComparator(getIdentifier()))
- .orElse(DataQueryOrder.TRANSIENT_FIRST);
-
- for (DataType dataType : DataQueryOrder.order(comparator)) {
+ for (DataType dataType : queryOrder(queryOptions)) {
getData(dataType).copyInheritanceNodesTo(nodes, queryOptions);
}
-
return nodes;
}
- private void accumulateInheritedNodesTo(Collection accumulator, QueryOptions queryOptions) {
- if (queryOptions.flag(Flag.RESOLVE_INHERITANCE)) {
- InheritanceGraph graph = this.plugin.getInheritanceGraphFactory().getGraph(queryOptions);
- Iterable traversal = graph.traverse(this);
- for (PermissionHolder holder : traversal) {
- List extends Node> nodes = holder.getOwnNodes(queryOptions);
- accumulator.addAll(nodes);
- }
- } else {
- accumulator.addAll(getOwnNodes(queryOptions));
+ public List getOwnNodes(NodeType type, QueryOptions queryOptions) {
+ List nodes = new ArrayList<>();
+ for (DataType dataType : queryOrder(queryOptions)) {
+ getData(dataType).copyTo(nodes, type, queryOptions);
}
+ return nodes;
}
public List resolveInheritedNodes(QueryOptions queryOptions) {
+ if (!queryOptions.flag(Flag.RESOLVE_INHERITANCE)) {
+ return getOwnNodes(queryOptions);
+ }
+
List nodes = new ArrayList<>();
- accumulateInheritedNodesTo(nodes, queryOptions);
+ InheritanceGraph graph = this.plugin.getInheritanceGraphFactory().getGraph(queryOptions);
+ for (PermissionHolder holder : graph.traverse(this)) {
+ for (DataType dataType : holder.queryOrder(queryOptions)) {
+ holder.getData(dataType).copyTo(nodes, queryOptions);
+ }
+ }
return nodes;
+
}
public SortedSet resolveInheritedNodesSorted(QueryOptions queryOptions) {
+ if (!queryOptions.flag(Flag.RESOLVE_INHERITANCE)) {
+ return getOwnNodesSorted(queryOptions);
+ }
+
SortedSet nodes = new TreeSet<>(NodeWithContextComparator.reverse());
- accumulateInheritedNodesTo(nodes, queryOptions);
+ InheritanceGraph graph = this.plugin.getInheritanceGraphFactory().getGraph(queryOptions);
+ for (PermissionHolder holder : graph.traverse(this)) {
+ for (DataType dataType : holder.queryOrder(queryOptions)) {
+ holder.getData(dataType).copyTo(nodes, queryOptions);
+ }
+ }
return nodes;
}
+ public List resolveInheritedNodes(NodeType type, QueryOptions queryOptions) {
+ if (!queryOptions.flag(Flag.RESOLVE_INHERITANCE)) {
+ return getOwnNodes(type, queryOptions);
+ }
+
+ List nodes = new ArrayList<>();
+ InheritanceGraph graph = this.plugin.getInheritanceGraphFactory().getGraph(queryOptions);
+ for (PermissionHolder holder : graph.traverse(this)) {
+ for (DataType dataType : holder.queryOrder(queryOptions)) {
+ holder.getData(dataType).copyTo(nodes, type, queryOptions);
+ }
+ }
+ return nodes;
+ }
+
+ @SuppressWarnings({"unchecked", "rawtypes"})
+ public List resolveInheritanceTree(QueryOptions queryOptions) {
+ if (!queryOptions.flag(Flag.RESOLVE_INHERITANCE)) {
+ return Collections.emptyList();
+ }
+
+ InheritanceGraph graph = this.plugin.getInheritanceGraphFactory().getGraph(queryOptions);
+
+ // perform a full traversal of the inheritance tree
+ List traversal = new ArrayList<>();
+ Iterables.addAll(traversal, graph.traverse(this));
+
+ // remove 'this' (the start node) - will usually be at traversal[0],
+ // but not always due to the possibility of post-traversal sorts!
+ if (traversal.get(0) == this) {
+ traversal.remove(0);
+ } else {
+ traversal.remove(this);
+ }
+
+ // ensure our traversal now only consists of groups
+ for (PermissionHolder permissionHolder : traversal) {
+ if (!(permissionHolder instanceof Group)) {
+ throw new IllegalStateException("Non-group object in inheritance tree: " + permissionHolder);
+ }
+ }
+
+ // cast List to List
+ // this feels a bit dirty but it works & avoids needless copying!
+ return (List) traversal;
+ }
+
public Map exportPermissions(QueryOptions queryOptions, boolean convertToLowercase, boolean resolveShorthand) {
List entries = resolveInheritedNodes(queryOptions);
return processExportedPermissions(entries, convertToLowercase, resolveShorthand);
@@ -353,22 +406,24 @@ public abstract class PermissionHolder {
public MetaAccumulator accumulateMeta(MetaAccumulator accumulator, QueryOptions queryOptions) {
InheritanceGraph graph = this.plugin.getInheritanceGraphFactory().getGraph(queryOptions);
- Iterable traversal = graph.traverse(this);
- for (PermissionHolder holder : traversal) {
- List extends Node> nodes = holder.getOwnNodes(queryOptions);
- for (Node node : nodes) {
- if (!node.getValue()) continue;
- if (!NodeType.META_OR_CHAT_META.matches(node)) continue;
-
- accumulator.accumulateNode(node);
+ for (PermissionHolder holder : graph.traverse(this)) {
+ // accumulate nodes
+ for (DataType dataType : holder.queryOrder(queryOptions)) {
+ holder.getData(dataType).forEach(queryOptions, node -> {
+ if (node.getValue() && NodeType.META_OR_CHAT_META.matches(node)) {
+ accumulator.accumulateNode(node);
+ }
+ });
}
+ // accumulate weight
OptionalInt w = holder.getWeight();
if (w.isPresent()) {
accumulator.accumulateWeight(w.getAsInt());
}
}
+ // accumulate primary group
if (this instanceof User) {
String primaryGroup = ((User) this).getPrimaryGroup().calculateValue(queryOptions);
accumulator.setPrimaryGroup(primaryGroup);