Refactor metastacks & primary group calculation

This commit is contained in:
Luck 2017-08-21 15:39:35 +02:00
parent 41b0e10709
commit f45c0caa45
No known key found for this signature in database
GPG Key ID: EFA9B3EC5FD90F8B
14 changed files with 179 additions and 50 deletions

View File

@ -33,8 +33,8 @@ import com.google.common.collect.ImmutableList;
import me.lucko.luckperms.api.metastacking.MetaStackDefinition; import me.lucko.luckperms.api.metastacking.MetaStackDefinition;
import me.lucko.luckperms.api.metastacking.MetaStackElement; import me.lucko.luckperms.api.metastacking.MetaStackElement;
import me.lucko.luckperms.api.metastacking.MetaStackFactory; import me.lucko.luckperms.api.metastacking.MetaStackFactory;
import me.lucko.luckperms.common.metastacking.definition.SimpleMetaStackDefinition; import me.lucko.luckperms.common.metastacking.SimpleMetaStackDefinition;
import me.lucko.luckperms.common.metastacking.definition.StandardStackElements; import me.lucko.luckperms.common.metastacking.StandardStackElements;
import me.lucko.luckperms.common.plugin.LuckPermsPlugin; import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
import java.util.List; import java.util.List;

View File

@ -36,8 +36,8 @@ import com.google.common.collect.ListMultimap;
import me.lucko.luckperms.api.ChatMetaType; import me.lucko.luckperms.api.ChatMetaType;
import me.lucko.luckperms.api.LocalizedNode; import me.lucko.luckperms.api.LocalizedNode;
import me.lucko.luckperms.common.config.ConfigKeys; 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.MetaStack;
import me.lucko.luckperms.common.metastacking.SimpleMetaStack;
import me.lucko.luckperms.common.plugin.LuckPermsPlugin; import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
import java.util.Comparator; import java.util.Comparator;
@ -46,15 +46,16 @@ import java.util.SortedMap;
import java.util.TreeMap; 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 @Getter
@ToString @ToString
public class MetaAccumulator { public class MetaAccumulator {
public static MetaAccumulator makeFromConfig(LuckPermsPlugin plugin) { public static MetaAccumulator makeFromConfig(LuckPermsPlugin plugin) {
return new MetaAccumulator( return new MetaAccumulator(
new GenericMetaStack(plugin.getConfiguration().get(ConfigKeys.PREFIX_FORMATTING_OPTIONS), ChatMetaType.PREFIX), new SimpleMetaStack(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.SUFFIX_FORMATTING_OPTIONS), ChatMetaType.SUFFIX)
); );
} }
@ -104,7 +105,8 @@ public class MetaAccumulator {
this.weight = Math.max(this.weight, weight); 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. // Therefore, it should be ok to set the weight meta key, if not already present.
public ListMultimap<String, String> getMeta() { public ListMultimap<String, String> getMeta() {
if (!this.meta.containsKey("weight") && this.weight != 0) { if (!this.meta.containsKey("weight") && this.weight != 0) {

View File

@ -41,7 +41,7 @@ import me.lucko.luckperms.api.caching.PermissionData;
import me.lucko.luckperms.api.caching.UserData; import me.lucko.luckperms.api.caching.UserData;
import me.lucko.luckperms.common.config.ConfigKeys; import me.lucko.luckperms.common.config.ConfigKeys;
import me.lucko.luckperms.common.contexts.ExtractedContexts; 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.model.User;
import me.lucko.luckperms.common.plugin.LuckPermsPlugin; import me.lucko.luckperms.common.plugin.LuckPermsPlugin;
@ -219,8 +219,8 @@ public class UserCache implements UserData {
private static MetaAccumulator newAccumulator(MetaContexts contexts) { private static MetaAccumulator newAccumulator(MetaContexts contexts) {
return new MetaAccumulator( return new MetaAccumulator(
new GenericMetaStack(contexts.getPrefixStackDefinition(), ChatMetaType.PREFIX), new SimpleMetaStack(contexts.getPrefixStackDefinition(), ChatMetaType.PREFIX),
new GenericMetaStack(contexts.getSuffixStackDefinition(), ChatMetaType.SUFFIX) new SimpleMetaStack(contexts.getSuffixStackDefinition(), ChatMetaType.SUFFIX)
); );
} }

View File

@ -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.StaticKey;
import me.lucko.luckperms.common.config.keys.StringKey; import me.lucko.luckperms.common.config.keys.StringKey;
import me.lucko.luckperms.common.defaults.Rule; import me.lucko.luckperms.common.defaults.Rule;
import me.lucko.luckperms.common.metastacking.definition.SimpleMetaStackDefinition; import me.lucko.luckperms.common.metastacking.SimpleMetaStackDefinition;
import me.lucko.luckperms.common.metastacking.definition.StandardStackElements; import me.lucko.luckperms.common.metastacking.StandardStackElements;
import me.lucko.luckperms.common.model.TemporaryModifier; import me.lucko.luckperms.common.model.TemporaryModifier;
import me.lucko.luckperms.common.model.User; import me.lucko.luckperms.common.model.User;
import me.lucko.luckperms.common.primarygroup.AllParentsByWeightHolder; import me.lucko.luckperms.common.primarygroup.AllParentsByWeightHolder;

View File

@ -29,14 +29,42 @@ import me.lucko.luckperms.api.ChatMetaType;
import me.lucko.luckperms.api.LocalizedNode; import me.lucko.luckperms.api.LocalizedNode;
import me.lucko.luckperms.api.metastacking.MetaStackDefinition; 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 { public interface MetaStack {
/**
* Gets the definition this stack is based upon
*
* @return the definition of the stack
*/
MetaStackDefinition getDefinition(); MetaStackDefinition getDefinition();
/**
* Gets the target of this stack
*
* @return the stack target
*/
ChatMetaType getTargetType(); 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(); String toFormattedString();
/**
* Tries to accumulate the given node to all elements in the stack.
*
* @param node the node to accumulate
*/
void accumulateToAll(LocalizedNode node); void accumulateToAll(LocalizedNode node);
} }

View File

@ -31,14 +31,39 @@ import me.lucko.luckperms.api.metastacking.MetaStackElement;
import java.util.Map; import java.util.Map;
import java.util.Optional; 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 { public interface MetaStackEntry {
/**
* Gets the stack this entry belongs to.
*
* @return the parent stack
*/
MetaStack getParentStack(); MetaStack getParentStack();
/**
* Gets the element this entry was formed form
*
* @return the forming element
*/
MetaStackElement getElement(); MetaStackElement getElement();
Optional<Map.Entry<Integer, String>> getEntry(); /**
* Gets the value currently held by this entry.
*
* @return the entry
*/
Optional<Map.Entry<Integer, String>> getCurrentValue();
/**
* Accumulates a node to this entry
*
* @param node the node to accumulate
* @return if the node was accepted
*/
boolean accumulateNode(LocalizedNode node); boolean accumulateNode(LocalizedNode node);
} }

View File

@ -37,7 +37,7 @@ import java.util.ArrayList;
import java.util.List; import java.util.List;
@Getter @Getter
public class GenericMetaStack implements MetaStack { public final class SimpleMetaStack implements MetaStack {
private final MetaStackDefinition definition; private final MetaStackDefinition definition;
private final ChatMetaType targetType; private final ChatMetaType targetType;
@ -45,7 +45,7 @@ public class GenericMetaStack implements MetaStack {
@Getter(AccessLevel.NONE) @Getter(AccessLevel.NONE)
private final List<MetaStackEntry> entries; private final List<MetaStackEntry> entries;
public GenericMetaStack(MetaStackDefinition definition, ChatMetaType targetType) { public SimpleMetaStack(MetaStackDefinition definition, ChatMetaType targetType) {
this.definition = definition; this.definition = definition;
this.targetType = targetType; this.targetType = targetType;
this.entries = definition.getElements().stream() this.entries = definition.getElements().stream()
@ -56,7 +56,7 @@ public class GenericMetaStack implements MetaStack {
@Override @Override
public String toFormattedString() { public String toFormattedString() {
List<MetaStackEntry> ret = new ArrayList<>(entries); List<MetaStackEntry> ret = new ArrayList<>(entries);
ret.removeIf(m -> !m.getEntry().isPresent()); ret.removeIf(m -> !m.getCurrentValue().isPresent());
if (ret.isEmpty()) { if (ret.isEmpty()) {
return null; return null;
@ -70,7 +70,7 @@ public class GenericMetaStack implements MetaStack {
} }
MetaStackEntry e = ret.get(i); MetaStackEntry e = ret.get(i);
sb.append(e.getEntry().get().getValue()); sb.append(e.getCurrentValue().get().getValue());
} }
sb.append(definition.getEndSpacer()); sb.append(definition.getEndSpacer());

View File

@ -23,7 +23,7 @@
* SOFTWARE. * SOFTWARE.
*/ */
package me.lucko.luckperms.common.metastacking.definition; package me.lucko.luckperms.common.metastacking;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import lombok.Getter; import lombok.Getter;

View File

@ -26,8 +26,10 @@
package me.lucko.luckperms.common.metastacking; package me.lucko.luckperms.common.metastacking;
import lombok.AccessLevel; import lombok.AccessLevel;
import lombok.EqualsAndHashCode;
import lombok.Getter; import lombok.Getter;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.ToString;
import me.lucko.luckperms.api.ChatMetaType; import me.lucko.luckperms.api.ChatMetaType;
import me.lucko.luckperms.api.LocalizedNode; import me.lucko.luckperms.api.LocalizedNode;
@ -37,8 +39,10 @@ import java.util.Map;
import java.util.Optional; import java.util.Optional;
@Getter @Getter
@ToString
@EqualsAndHashCode(of = {"element", "type", "current"})
@RequiredArgsConstructor @RequiredArgsConstructor
class SimpleMetaStackEntry implements MetaStackEntry { final class SimpleMetaStackEntry implements MetaStackEntry {
private final MetaStack parentStack; private final MetaStack parentStack;
private final MetaStackElement element; private final MetaStackElement element;
@ -48,7 +52,7 @@ class SimpleMetaStackEntry implements MetaStackEntry {
private Map.Entry<Integer, String> current = null; private Map.Entry<Integer, String> current = null;
@Override @Override
public Optional<Map.Entry<Integer, String>> getEntry() { public Optional<Map.Entry<Integer, String>> getCurrentValue() {
return Optional.ofNullable(current); return Optional.ofNullable(current);
} }

View File

@ -23,7 +23,7 @@
* SOFTWARE. * SOFTWARE.
*/ */
package me.lucko.luckperms.common.metastacking.definition; package me.lucko.luckperms.common.metastacking;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
@ -42,6 +42,9 @@ import java.util.Map;
import java.util.Optional; import java.util.Optional;
import java.util.UUID; import java.util.UUID;
/**
* Contains the standard {@link MetaStackElement}s provided by LuckPerms.
*/
@UtilityClass @UtilityClass
public class StandardStackElements { public class StandardStackElements {

View File

@ -515,7 +515,7 @@ public abstract class PermissionHolder {
* @param context context to decide if groups should be applied * @param context context to decide if groups should be applied
* @return a set of nodes * @return a set of nodes
*/ */
protected List<LocalizedNode> resolveInheritances(List<LocalizedNode> accumulator, Set<String> excludedGroups, ExtractedContexts context) { public List<LocalizedNode> resolveInheritances(List<LocalizedNode> accumulator, Set<String> excludedGroups, ExtractedContexts context) {
if (accumulator == null) { if (accumulator == null) {
accumulator = new ArrayList<>(); accumulator = new ArrayList<>();
} }
@ -595,7 +595,7 @@ public abstract class PermissionHolder {
* @param excludedGroups a list of groups to exclude * @param excludedGroups a list of groups to exclude
* @return a set of nodes * @return a set of nodes
*/ */
protected List<LocalizedNode> resolveInheritances(List<LocalizedNode> accumulator, Set<String> excludedGroups) { public List<LocalizedNode> resolveInheritances(List<LocalizedNode> accumulator, Set<String> excludedGroups) {
if (accumulator == null) { if (accumulator == null) {
accumulator = new ArrayList<>(); accumulator = new ArrayList<>();
} }

View File

@ -28,15 +28,16 @@ package me.lucko.luckperms.common.primarygroup;
import lombok.NonNull; import lombok.NonNull;
import me.lucko.luckperms.api.Contexts; import me.lucko.luckperms.api.Contexts;
import me.lucko.luckperms.api.Node;
import me.lucko.luckperms.common.config.ConfigKeys; import me.lucko.luckperms.common.config.ConfigKeys;
import me.lucko.luckperms.common.contexts.ExtractedContexts; import me.lucko.luckperms.common.contexts.ExtractedContexts;
import me.lucko.luckperms.common.model.Group; import me.lucko.luckperms.common.model.Group;
import me.lucko.luckperms.common.model.User; import me.lucko.luckperms.common.model.User;
import java.util.Collections; import java.util.AbstractList;
import java.util.Comparator; import java.util.ArrayList;
import java.util.Optional; import java.util.HashSet;
import java.util.List;
import java.util.Set;
public class AllParentsByWeightHolder extends StoredHolder { public class AllParentsByWeightHolder extends StoredHolder {
@ -67,18 +68,51 @@ public class AllParentsByWeightHolder extends StoredHolder {
); );
} }
cachedValue = user.resolveInheritancesAlmostEqual(ExtractedContexts.generate(contexts)).stream() // hack to get a list of groups the holder is inheriting from
.filter(Node::isGroupNode) Set<String> groupNames = new HashSet<>();
.filter(Node::getValue) user.resolveInheritances(new NoopList<>(), groupNames, ExtractedContexts.generate(contexts));
.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<Group> 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; useCached = true;
return cachedValue; return cachedValue;
} }
private static final class NoopList<E> extends AbstractList<E> implements List<E> {
@Override
public boolean add(E e) {
return true;
}
@Override
public E get(int index) {
return null;
}
@Override
public int size() {
return 0;
}
}
} }

View File

@ -33,9 +33,8 @@ import me.lucko.luckperms.api.context.ContextSet;
import me.lucko.luckperms.common.model.Group; import me.lucko.luckperms.common.model.Group;
import me.lucko.luckperms.common.model.User; import me.lucko.luckperms.common.model.User;
import java.util.Collections; import java.util.ArrayList;
import java.util.Comparator; import java.util.List;
import java.util.Optional;
public class ParentsByWeightHolder extends StoredHolder { public class ParentsByWeightHolder extends StoredHolder {
@ -55,17 +54,33 @@ public class ParentsByWeightHolder extends StoredHolder {
Contexts contexts = user.getPlugin().getContextForUser(user); Contexts contexts = user.getPlugin().getContextForUser(user);
ContextSet contextSet = contexts != null ? contexts.getContexts() : user.getPlugin().getContextManager().getStaticContexts(); 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<Group> 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; useCached = true;
return cachedValue; return cachedValue;
} }

View File

@ -25,12 +25,30 @@
package me.lucko.luckperms.common.primarygroup; package me.lucko.luckperms.common.primarygroup;
/**
* Calculates and caches a User's "primary group"
*/
public interface PrimaryGroupHolder { public interface PrimaryGroupHolder {
/**
* Gets the name of the primary group, or null.
*
* @return the name of the primary group, or null.
*/
String getValue(); String getValue();
/**
* Gets the primary group which is stored against the user's data.
*
* @return the stored value
*/
String getStoredValue(); String getStoredValue();
/**
* Sets the primary group which is stored against the user's data.
*
* @param storedValue the new stored value
*/
void setStoredValue(String storedValue); void setStoredValue(String storedValue);
} }