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.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;

View File

@ -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<String, String> getMeta() {
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.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)
);
}

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.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;

View File

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

View File

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

View File

@ -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<MetaStackEntry> 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<MetaStackEntry> 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());

View File

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

View File

@ -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<Integer, String> current = null;
@Override
public Optional<Map.Entry<Integer, String>> getEntry() {
public Optional<Map.Entry<Integer, String>> getCurrentValue() {
return Optional.ofNullable(current);
}

View File

@ -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 {

View File

@ -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<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) {
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<LocalizedNode> resolveInheritances(List<LocalizedNode> accumulator, Set<String> excludedGroups) {
public List<LocalizedNode> resolveInheritances(List<LocalizedNode> accumulator, Set<String> excludedGroups) {
if (accumulator == null) {
accumulator = new ArrayList<>();
}

View File

@ -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<String> groupNames = new HashSet<>();
user.resolveInheritances(new NoopList<>(), groupNames, ExtractedContexts.generate(contexts));
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;
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.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<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;
return cachedValue;
}

View File

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