diff --git a/common/src/main/java/me/lucko/luckperms/common/api/delegates/MetaStackFactoryDelegate.java b/common/src/main/java/me/lucko/luckperms/common/api/delegates/MetaStackFactoryDelegate.java index 2f6bda6c..85c8109b 100644 --- a/common/src/main/java/me/lucko/luckperms/common/api/delegates/MetaStackFactoryDelegate.java +++ b/common/src/main/java/me/lucko/luckperms/common/api/delegates/MetaStackFactoryDelegate.java @@ -33,8 +33,8 @@ import com.google.common.collect.ImmutableList; import me.lucko.luckperms.api.metastacking.MetaStackDefinition; import me.lucko.luckperms.api.metastacking.MetaStackElement; import me.lucko.luckperms.api.metastacking.MetaStackFactory; -import me.lucko.luckperms.common.metastacking.definition.SimpleMetaStackDefinition; -import me.lucko.luckperms.common.metastacking.definition.StandardStackElements; +import me.lucko.luckperms.common.metastacking.SimpleMetaStackDefinition; +import me.lucko.luckperms.common.metastacking.StandardStackElements; import me.lucko.luckperms.common.plugin.LuckPermsPlugin; import java.util.List; diff --git a/common/src/main/java/me/lucko/luckperms/common/caching/MetaAccumulator.java b/common/src/main/java/me/lucko/luckperms/common/caching/MetaAccumulator.java index a814ccbf..6933b28e 100644 --- a/common/src/main/java/me/lucko/luckperms/common/caching/MetaAccumulator.java +++ b/common/src/main/java/me/lucko/luckperms/common/caching/MetaAccumulator.java @@ -36,8 +36,8 @@ import com.google.common.collect.ListMultimap; import me.lucko.luckperms.api.ChatMetaType; import me.lucko.luckperms.api.LocalizedNode; import me.lucko.luckperms.common.config.ConfigKeys; -import me.lucko.luckperms.common.metastacking.GenericMetaStack; import me.lucko.luckperms.common.metastacking.MetaStack; +import me.lucko.luckperms.common.metastacking.SimpleMetaStack; import me.lucko.luckperms.common.plugin.LuckPermsPlugin; import java.util.Comparator; @@ -46,15 +46,16 @@ import java.util.SortedMap; import java.util.TreeMap; /** - * Holds temporary mutable meta whilst this object is passed up the inheritance tree to accumulate meta from parents + * Holds temporary mutable meta whilst this object is passed up the + * inheritance tree to accumulate meta from parents */ @Getter @ToString public class MetaAccumulator { public static MetaAccumulator makeFromConfig(LuckPermsPlugin plugin) { return new MetaAccumulator( - new GenericMetaStack(plugin.getConfiguration().get(ConfigKeys.PREFIX_FORMATTING_OPTIONS), ChatMetaType.PREFIX), - new GenericMetaStack(plugin.getConfiguration().get(ConfigKeys.SUFFIX_FORMATTING_OPTIONS), ChatMetaType.SUFFIX) + new SimpleMetaStack(plugin.getConfiguration().get(ConfigKeys.PREFIX_FORMATTING_OPTIONS), ChatMetaType.PREFIX), + new SimpleMetaStack(plugin.getConfiguration().get(ConfigKeys.SUFFIX_FORMATTING_OPTIONS), ChatMetaType.SUFFIX) ); } @@ -104,7 +105,8 @@ public class MetaAccumulator { this.weight = Math.max(this.weight, weight); } - // We can assume that if this method is being called, this holder is effectively finalized. (it's not going to accumulate more nodes) + // We can assume that if this method is being called, this holder is effectively finalized. + // (it's not going to accumulate more nodes) // Therefore, it should be ok to set the weight meta key, if not already present. public ListMultimap getMeta() { if (!this.meta.containsKey("weight") && this.weight != 0) { diff --git a/common/src/main/java/me/lucko/luckperms/common/caching/UserCache.java b/common/src/main/java/me/lucko/luckperms/common/caching/UserCache.java index 53d64099..b60b0437 100644 --- a/common/src/main/java/me/lucko/luckperms/common/caching/UserCache.java +++ b/common/src/main/java/me/lucko/luckperms/common/caching/UserCache.java @@ -41,7 +41,7 @@ import me.lucko.luckperms.api.caching.PermissionData; import me.lucko.luckperms.api.caching.UserData; import me.lucko.luckperms.common.config.ConfigKeys; import me.lucko.luckperms.common.contexts.ExtractedContexts; -import me.lucko.luckperms.common.metastacking.GenericMetaStack; +import me.lucko.luckperms.common.metastacking.SimpleMetaStack; import me.lucko.luckperms.common.model.User; import me.lucko.luckperms.common.plugin.LuckPermsPlugin; @@ -219,8 +219,8 @@ public class UserCache implements UserData { private static MetaAccumulator newAccumulator(MetaContexts contexts) { return new MetaAccumulator( - new GenericMetaStack(contexts.getPrefixStackDefinition(), ChatMetaType.PREFIX), - new GenericMetaStack(contexts.getSuffixStackDefinition(), ChatMetaType.SUFFIX) + new SimpleMetaStack(contexts.getPrefixStackDefinition(), ChatMetaType.PREFIX), + new SimpleMetaStack(contexts.getSuffixStackDefinition(), ChatMetaType.SUFFIX) ); } diff --git a/common/src/main/java/me/lucko/luckperms/common/config/ConfigKeys.java b/common/src/main/java/me/lucko/luckperms/common/config/ConfigKeys.java index 01955274..31c8a7a1 100644 --- a/common/src/main/java/me/lucko/luckperms/common/config/ConfigKeys.java +++ b/common/src/main/java/me/lucko/luckperms/common/config/ConfigKeys.java @@ -40,8 +40,8 @@ import me.lucko.luckperms.common.config.keys.MapKey; import me.lucko.luckperms.common.config.keys.StaticKey; import me.lucko.luckperms.common.config.keys.StringKey; import me.lucko.luckperms.common.defaults.Rule; -import me.lucko.luckperms.common.metastacking.definition.SimpleMetaStackDefinition; -import me.lucko.luckperms.common.metastacking.definition.StandardStackElements; +import me.lucko.luckperms.common.metastacking.SimpleMetaStackDefinition; +import me.lucko.luckperms.common.metastacking.StandardStackElements; import me.lucko.luckperms.common.model.TemporaryModifier; import me.lucko.luckperms.common.model.User; import me.lucko.luckperms.common.primarygroup.AllParentsByWeightHolder; diff --git a/common/src/main/java/me/lucko/luckperms/common/metastacking/MetaStack.java b/common/src/main/java/me/lucko/luckperms/common/metastacking/MetaStack.java index e76369d7..e61937d0 100644 --- a/common/src/main/java/me/lucko/luckperms/common/metastacking/MetaStack.java +++ b/common/src/main/java/me/lucko/luckperms/common/metastacking/MetaStack.java @@ -29,14 +29,42 @@ import me.lucko.luckperms.api.ChatMetaType; import me.lucko.luckperms.api.LocalizedNode; import me.lucko.luckperms.api.metastacking.MetaStackDefinition; +/** + * A live stack of {@link MetaStackEntry} instances, formed from a + * {@link MetaStackDefinition}. + * + * This class is used to construct a formatted string, by accumulating + * nodes to each element. + */ public interface MetaStack { + /** + * Gets the definition this stack is based upon + * + * @return the definition of the stack + */ MetaStackDefinition getDefinition(); + /** + * Gets the target of this stack + * + * @return the stack target + */ ChatMetaType getTargetType(); + /** + * Returns a formatted string, as defined by the {@link MetaStackDefinition}, + * using the accumulated elements in the stack. + * + * @return the string output + */ String toFormattedString(); + /** + * Tries to accumulate the given node to all elements in the stack. + * + * @param node the node to accumulate + */ void accumulateToAll(LocalizedNode node); } diff --git a/common/src/main/java/me/lucko/luckperms/common/metastacking/MetaStackEntry.java b/common/src/main/java/me/lucko/luckperms/common/metastacking/MetaStackEntry.java index 642c8326..092b4f7e 100644 --- a/common/src/main/java/me/lucko/luckperms/common/metastacking/MetaStackEntry.java +++ b/common/src/main/java/me/lucko/luckperms/common/metastacking/MetaStackEntry.java @@ -31,14 +31,39 @@ import me.lucko.luckperms.api.metastacking.MetaStackElement; import java.util.Map; import java.util.Optional; +/** + * Represents a specific entry in a {@link MetaStack}. + * An entry is basically a live/mutable version of a {@link MetaStackElement}. + */ public interface MetaStackEntry { + /** + * Gets the stack this entry belongs to. + * + * @return the parent stack + */ MetaStack getParentStack(); + /** + * Gets the element this entry was formed form + * + * @return the forming element + */ MetaStackElement getElement(); - Optional> getEntry(); + /** + * Gets the value currently held by this entry. + * + * @return the entry + */ + Optional> getCurrentValue(); + /** + * Accumulates a node to this entry + * + * @param node the node to accumulate + * @return if the node was accepted + */ boolean accumulateNode(LocalizedNode node); } diff --git a/common/src/main/java/me/lucko/luckperms/common/metastacking/GenericMetaStack.java b/common/src/main/java/me/lucko/luckperms/common/metastacking/SimpleMetaStack.java similarity index 91% rename from common/src/main/java/me/lucko/luckperms/common/metastacking/GenericMetaStack.java rename to common/src/main/java/me/lucko/luckperms/common/metastacking/SimpleMetaStack.java index cc8cf304..baae07f0 100644 --- a/common/src/main/java/me/lucko/luckperms/common/metastacking/GenericMetaStack.java +++ b/common/src/main/java/me/lucko/luckperms/common/metastacking/SimpleMetaStack.java @@ -37,7 +37,7 @@ import java.util.ArrayList; import java.util.List; @Getter -public class GenericMetaStack implements MetaStack { +public final class SimpleMetaStack implements MetaStack { private final MetaStackDefinition definition; private final ChatMetaType targetType; @@ -45,7 +45,7 @@ public class GenericMetaStack implements MetaStack { @Getter(AccessLevel.NONE) private final List entries; - public GenericMetaStack(MetaStackDefinition definition, ChatMetaType targetType) { + public SimpleMetaStack(MetaStackDefinition definition, ChatMetaType targetType) { this.definition = definition; this.targetType = targetType; this.entries = definition.getElements().stream() @@ -56,7 +56,7 @@ public class GenericMetaStack implements MetaStack { @Override public String toFormattedString() { List ret = new ArrayList<>(entries); - ret.removeIf(m -> !m.getEntry().isPresent()); + ret.removeIf(m -> !m.getCurrentValue().isPresent()); if (ret.isEmpty()) { return null; @@ -70,7 +70,7 @@ public class GenericMetaStack implements MetaStack { } MetaStackEntry e = ret.get(i); - sb.append(e.getEntry().get().getValue()); + sb.append(e.getCurrentValue().get().getValue()); } sb.append(definition.getEndSpacer()); diff --git a/common/src/main/java/me/lucko/luckperms/common/metastacking/definition/SimpleMetaStackDefinition.java b/common/src/main/java/me/lucko/luckperms/common/metastacking/SimpleMetaStackDefinition.java similarity index 97% rename from common/src/main/java/me/lucko/luckperms/common/metastacking/definition/SimpleMetaStackDefinition.java rename to common/src/main/java/me/lucko/luckperms/common/metastacking/SimpleMetaStackDefinition.java index 87490a1d..44272b35 100644 --- a/common/src/main/java/me/lucko/luckperms/common/metastacking/definition/SimpleMetaStackDefinition.java +++ b/common/src/main/java/me/lucko/luckperms/common/metastacking/SimpleMetaStackDefinition.java @@ -23,7 +23,7 @@ * SOFTWARE. */ -package me.lucko.luckperms.common.metastacking.definition; +package me.lucko.luckperms.common.metastacking; import lombok.EqualsAndHashCode; import lombok.Getter; diff --git a/common/src/main/java/me/lucko/luckperms/common/metastacking/SimpleMetaStackEntry.java b/common/src/main/java/me/lucko/luckperms/common/metastacking/SimpleMetaStackEntry.java index b081f184..2988fa39 100644 --- a/common/src/main/java/me/lucko/luckperms/common/metastacking/SimpleMetaStackEntry.java +++ b/common/src/main/java/me/lucko/luckperms/common/metastacking/SimpleMetaStackEntry.java @@ -26,8 +26,10 @@ package me.lucko.luckperms.common.metastacking; import lombok.AccessLevel; +import lombok.EqualsAndHashCode; import lombok.Getter; import lombok.RequiredArgsConstructor; +import lombok.ToString; import me.lucko.luckperms.api.ChatMetaType; import me.lucko.luckperms.api.LocalizedNode; @@ -37,8 +39,10 @@ import java.util.Map; import java.util.Optional; @Getter +@ToString +@EqualsAndHashCode(of = {"element", "type", "current"}) @RequiredArgsConstructor -class SimpleMetaStackEntry implements MetaStackEntry { +final class SimpleMetaStackEntry implements MetaStackEntry { private final MetaStack parentStack; private final MetaStackElement element; @@ -48,7 +52,7 @@ class SimpleMetaStackEntry implements MetaStackEntry { private Map.Entry current = null; @Override - public Optional> getEntry() { + public Optional> getCurrentValue() { return Optional.ofNullable(current); } diff --git a/common/src/main/java/me/lucko/luckperms/common/metastacking/definition/StandardStackElements.java b/common/src/main/java/me/lucko/luckperms/common/metastacking/StandardStackElements.java similarity index 98% rename from common/src/main/java/me/lucko/luckperms/common/metastacking/definition/StandardStackElements.java rename to common/src/main/java/me/lucko/luckperms/common/metastacking/StandardStackElements.java index 4db7a0e4..5b846f2d 100644 --- a/common/src/main/java/me/lucko/luckperms/common/metastacking/definition/StandardStackElements.java +++ b/common/src/main/java/me/lucko/luckperms/common/metastacking/StandardStackElements.java @@ -23,7 +23,7 @@ * SOFTWARE. */ -package me.lucko.luckperms.common.metastacking.definition; +package me.lucko.luckperms.common.metastacking; import lombok.EqualsAndHashCode; import lombok.RequiredArgsConstructor; @@ -42,6 +42,9 @@ import java.util.Map; import java.util.Optional; import java.util.UUID; +/** + * Contains the standard {@link MetaStackElement}s provided by LuckPerms. + */ @UtilityClass public class StandardStackElements { 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 f62df2ed..7d8bc625 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 @@ -515,7 +515,7 @@ public abstract class PermissionHolder { * @param context context to decide if groups should be applied * @return a set of nodes */ - protected List resolveInheritances(List accumulator, Set excludedGroups, ExtractedContexts context) { + public List resolveInheritances(List accumulator, Set excludedGroups, ExtractedContexts context) { if (accumulator == null) { accumulator = new ArrayList<>(); } @@ -595,7 +595,7 @@ public abstract class PermissionHolder { * @param excludedGroups a list of groups to exclude * @return a set of nodes */ - protected List resolveInheritances(List accumulator, Set excludedGroups) { + public List resolveInheritances(List accumulator, Set excludedGroups) { if (accumulator == null) { accumulator = new ArrayList<>(); } diff --git a/common/src/main/java/me/lucko/luckperms/common/primarygroup/AllParentsByWeightHolder.java b/common/src/main/java/me/lucko/luckperms/common/primarygroup/AllParentsByWeightHolder.java index 5096e1a9..c5dbc0f1 100644 --- a/common/src/main/java/me/lucko/luckperms/common/primarygroup/AllParentsByWeightHolder.java +++ b/common/src/main/java/me/lucko/luckperms/common/primarygroup/AllParentsByWeightHolder.java @@ -28,15 +28,16 @@ package me.lucko.luckperms.common.primarygroup; import lombok.NonNull; import me.lucko.luckperms.api.Contexts; -import me.lucko.luckperms.api.Node; import me.lucko.luckperms.common.config.ConfigKeys; import me.lucko.luckperms.common.contexts.ExtractedContexts; import me.lucko.luckperms.common.model.Group; import me.lucko.luckperms.common.model.User; -import java.util.Collections; -import java.util.Comparator; -import java.util.Optional; +import java.util.AbstractList; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; public class AllParentsByWeightHolder extends StoredHolder { @@ -67,18 +68,51 @@ public class AllParentsByWeightHolder extends StoredHolder { ); } - cachedValue = user.resolveInheritancesAlmostEqual(ExtractedContexts.generate(contexts)).stream() - .filter(Node::isGroupNode) - .filter(Node::getValue) - .map(n -> Optional.ofNullable(user.getPlugin().getGroupManager().getIfLoaded(n.getGroupName()))) - .filter(Optional::isPresent) - .map(Optional::get) - .sorted(Collections.reverseOrder(Comparator.comparingInt(o -> o.getWeight().orElse(0)))) - .findFirst() - .map(Group::getName) - .orElse(null); + // hack to get a list of groups the holder is inheriting from + Set groupNames = new HashSet<>(); + user.resolveInheritances(new NoopList<>(), groupNames, ExtractedContexts.generate(contexts)); + List groups = new ArrayList<>(); + for (String groupName : groupNames) { + Group group = user.getPlugin().getGroupManager().getIfLoaded(groupName); + if (group != null) { + groups.add(group); + } + } + + Group bestGroup = null; + + if (!groups.isEmpty()) { + int best = 0; + for (Group g : groups) { + int weight = g.getWeight().orElse(0); + if (bestGroup == null || g.getWeight().orElse(0) > best) { + bestGroup = g; + best = weight; + } + } + } + + cachedValue = bestGroup == null ? null : bestGroup.getName(); useCached = true; return cachedValue; } + + private static final class NoopList extends AbstractList implements List { + + @Override + public boolean add(E e) { + return true; + } + + @Override + public E get(int index) { + return null; + } + + @Override + public int size() { + return 0; + } + } } diff --git a/common/src/main/java/me/lucko/luckperms/common/primarygroup/ParentsByWeightHolder.java b/common/src/main/java/me/lucko/luckperms/common/primarygroup/ParentsByWeightHolder.java index 21919293..7215786f 100644 --- a/common/src/main/java/me/lucko/luckperms/common/primarygroup/ParentsByWeightHolder.java +++ b/common/src/main/java/me/lucko/luckperms/common/primarygroup/ParentsByWeightHolder.java @@ -33,9 +33,8 @@ import me.lucko.luckperms.api.context.ContextSet; import me.lucko.luckperms.common.model.Group; import me.lucko.luckperms.common.model.User; -import java.util.Collections; -import java.util.Comparator; -import java.util.Optional; +import java.util.ArrayList; +import java.util.List; public class ParentsByWeightHolder extends StoredHolder { @@ -55,17 +54,33 @@ public class ParentsByWeightHolder extends StoredHolder { Contexts contexts = user.getPlugin().getContextForUser(user); ContextSet contextSet = contexts != null ? contexts.getContexts() : user.getPlugin().getContextManager().getStaticContexts(); - cachedValue = user.filterNodes(contextSet).stream() - .filter(Node::isGroupNode) - .filter(Node::getValue) - .map(n -> Optional.ofNullable(user.getPlugin().getGroupManager().getIfLoaded(n.getGroupName()))) - .filter(Optional::isPresent) - .map(Optional::get) - .sorted(Collections.reverseOrder(Comparator.comparingInt(o -> o.getWeight().orElse(0)))) - .findFirst() - .map(Group::getName) - .orElse(null); + List groups = new ArrayList<>(); + for (Node node : user.filterNodes(contextSet)) { + if (!node.getValue() || !node.isGroupNode()) { + continue; + } + + Group group = user.getPlugin().getGroupManager().getIfLoaded(node.getGroupName()); + if (group != null) { + groups.add(group); + } + } + + Group bestGroup = null; + + if (!groups.isEmpty()) { + int best = 0; + for (Group g : groups) { + int weight = g.getWeight().orElse(0); + if (bestGroup == null || g.getWeight().orElse(0) > best) { + bestGroup = g; + best = weight; + } + } + } + + cachedValue = bestGroup == null ? null : bestGroup.getName(); useCached = true; return cachedValue; } diff --git a/common/src/main/java/me/lucko/luckperms/common/primarygroup/PrimaryGroupHolder.java b/common/src/main/java/me/lucko/luckperms/common/primarygroup/PrimaryGroupHolder.java index 6349bc60..cfdac61c 100644 --- a/common/src/main/java/me/lucko/luckperms/common/primarygroup/PrimaryGroupHolder.java +++ b/common/src/main/java/me/lucko/luckperms/common/primarygroup/PrimaryGroupHolder.java @@ -25,12 +25,30 @@ package me.lucko.luckperms.common.primarygroup; +/** + * Calculates and caches a User's "primary group" + */ public interface PrimaryGroupHolder { + /** + * Gets the name of the primary group, or null. + * + * @return the name of the primary group, or null. + */ String getValue(); + /** + * Gets the primary group which is stored against the user's data. + * + * @return the stored value + */ String getStoredValue(); + /** + * Sets the primary group which is stored against the user's data. + * + * @param storedValue the new stored value + */ void setStoredValue(String storedValue); }