Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3006e58209 |
No files matched your search
+7
-31
@@ -26,14 +26,13 @@
|
||||
package me.lucko.luckperms.common.cacheddata.type;
|
||||
|
||||
import me.lucko.luckperms.common.cacheddata.result.StringResult;
|
||||
import me.lucko.luckperms.common.metastacking.ElementAccumulator;
|
||||
|
||||
import net.luckperms.api.metastacking.MetaStackDefinition;
|
||||
import net.luckperms.api.metastacking.MetaStackElement;
|
||||
import net.luckperms.api.node.ChatMetaType;
|
||||
import net.luckperms.api.node.types.ChatMetaNode;
|
||||
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedList;
|
||||
@@ -43,7 +42,7 @@ import java.util.stream.Collectors;
|
||||
|
||||
public class MetaStackAccumulator<N extends ChatMetaNode<N, ?>> {
|
||||
private final MetaStackDefinition definition;
|
||||
private final List<Entry<N>> entries;
|
||||
private final List<ElementAccumulator<N>> entries;
|
||||
|
||||
public MetaStackAccumulator(MetaStackDefinition definition, ChatMetaType targetType) {
|
||||
this.definition = definition;
|
||||
@@ -51,27 +50,27 @@ public class MetaStackAccumulator<N extends ChatMetaNode<N, ?>> {
|
||||
List<MetaStackElement> elements = definition.getElements();
|
||||
this.entries = new ArrayList<>(elements.size());
|
||||
for (MetaStackElement element : elements) {
|
||||
this.entries.add(new Entry<>(element, targetType));
|
||||
this.entries.add(ElementAccumulator.create(element, targetType));
|
||||
}
|
||||
}
|
||||
|
||||
public void offer(N node) {
|
||||
for (Entry<N> entry : this.entries) {
|
||||
for (ElementAccumulator<N> entry : this.entries) {
|
||||
entry.offer(node);
|
||||
}
|
||||
}
|
||||
|
||||
public List<N> getElements() {
|
||||
return this.entries.stream()
|
||||
.map(Entry::getNode)
|
||||
.map(ElementAccumulator::result)
|
||||
.filter(Objects::nonNull)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public String toFormattedString() {
|
||||
List<String> elements = new LinkedList<>();
|
||||
for (Entry<N> entry : this.entries) {
|
||||
N node = entry.getNode();
|
||||
for (ElementAccumulator<N> entry : this.entries) {
|
||||
N node = entry.result();
|
||||
if (node != null) {
|
||||
elements.add(node.getMetaValue());
|
||||
}
|
||||
@@ -134,27 +133,4 @@ public class MetaStackAccumulator<N extends ChatMetaNode<N, ?>> {
|
||||
}
|
||||
}
|
||||
|
||||
private static final class Entry<N extends ChatMetaNode<?, ?>> {
|
||||
private final MetaStackElement element;
|
||||
private final ChatMetaType type;
|
||||
|
||||
private @Nullable N current = null;
|
||||
|
||||
Entry(MetaStackElement element, ChatMetaType type) {
|
||||
this.element = element;
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public N getNode() {
|
||||
return this.current;
|
||||
}
|
||||
|
||||
public boolean offer(N node) {
|
||||
if (this.element.shouldAccumulate(this.type, node, this.current)) {
|
||||
this.current = node;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
+56
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* This file is part of LuckPerms, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) lucko (Luck) <luck@lucko.me>
|
||||
* Copyright (c) contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package me.lucko.luckperms.common.metastacking;
|
||||
|
||||
import net.luckperms.api.metastacking.MetaStackElement;
|
||||
import net.luckperms.api.node.ChatMetaType;
|
||||
import net.luckperms.api.node.types.ChatMetaNode;
|
||||
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
|
||||
/**
|
||||
* Special extension of {@link MetaStackElement} that provides its own {@link ElementAccumulator}
|
||||
* instead of using the {@link #shouldAccumulate(ChatMetaType, ChatMetaNode, ChatMetaNode)} method.
|
||||
*/
|
||||
public interface DynamicMetaStackElement extends MetaStackElement {
|
||||
|
||||
@Deprecated
|
||||
@Override
|
||||
default boolean shouldAccumulate(@NonNull ChatMetaType type, @NonNull ChatMetaNode<?, ?> node, @Nullable ChatMetaNode<?, ?> current) {
|
||||
throw new UnsupportedOperationException("DynamicMetaStackElements do not support this method.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link ElementAccumulator} for this element.
|
||||
*
|
||||
* @param type the type
|
||||
* @param <N> the node type
|
||||
* @return a new element accumulator
|
||||
*/
|
||||
<N extends ChatMetaNode<?, ?>> ElementAccumulator<N> newAccumulator(ChatMetaType type);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
/*
|
||||
* This file is part of LuckPerms, licensed under the MIT License.
|
||||
*
|
||||
* Copyright (c) lucko (Luck) <luck@lucko.me>
|
||||
* Copyright (c) contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
package me.lucko.luckperms.common.metastacking;
|
||||
|
||||
import net.luckperms.api.metastacking.MetaStackElement;
|
||||
import net.luckperms.api.node.ChatMetaType;
|
||||
import net.luckperms.api.node.types.ChatMetaNode;
|
||||
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
|
||||
/**
|
||||
* Accumulates {@link ChatMetaNode}s for a {@link MetaStackElement}
|
||||
* to provide the stack resolution.
|
||||
*
|
||||
* @param <N> the node type
|
||||
*/
|
||||
public interface ElementAccumulator<N extends ChatMetaNode<?, ?>> {
|
||||
|
||||
/**
|
||||
* Creates a {@link ElementAccumulator} for the given {@link MetaStackElement}.
|
||||
*
|
||||
* @param element the element
|
||||
* @param type the type
|
||||
* @param <N> the node type
|
||||
* @return the new accumulator
|
||||
*/
|
||||
static <N extends ChatMetaNode<?, ?>> ElementAccumulator<N> create(MetaStackElement element, ChatMetaType type) {
|
||||
// if the element is dynamic, use its provided impl
|
||||
if (element instanceof DynamicMetaStackElement) {
|
||||
return ((DynamicMetaStackElement) element).newAccumulator(type);
|
||||
}
|
||||
|
||||
// otherwise, just use the standard accumulator
|
||||
return new Standard<>(element, type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Offers a node to the accumulator.
|
||||
*
|
||||
* @param node the node
|
||||
*/
|
||||
void offer(@NonNull N node);
|
||||
|
||||
/**
|
||||
* Exports the final result from the accumulator.
|
||||
*
|
||||
* @return the result node
|
||||
*/
|
||||
@Nullable N result();
|
||||
|
||||
final class Standard<N extends ChatMetaNode<?, ?>> implements ElementAccumulator<N> {
|
||||
private final MetaStackElement element;
|
||||
private final ChatMetaType type;
|
||||
|
||||
private @Nullable N current = null;
|
||||
|
||||
Standard(MetaStackElement element, ChatMetaType type) {
|
||||
this.element = element;
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void offer(@NonNull N node) {
|
||||
if (this.element.shouldAccumulate(this.type, node, this.current)) {
|
||||
this.current = node;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable N result() {
|
||||
return this.current;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+91
-9
@@ -38,9 +38,13 @@ import net.luckperms.api.node.types.ChatMetaNode;
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Objects;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* Contains the standard {@link MetaStackElement}s provided by LuckPerms.
|
||||
@@ -48,6 +52,9 @@ import java.util.Objects;
|
||||
public final class StandardStackElements {
|
||||
private StandardStackElements() {}
|
||||
|
||||
private static final Pattern HIGHEST_N_PATTERN = Pattern.compile("highest\\[([1-9]\\d*)]");
|
||||
private static final Pattern LOWEST_N_PATTERN = Pattern.compile("lowest\\[([1-9]\\d*)]");
|
||||
|
||||
public static MetaStackElement parseFromString(LuckPermsPlugin plugin, String s) {
|
||||
s = s.toLowerCase(Locale.ROOT);
|
||||
|
||||
@@ -61,25 +68,35 @@ public final class StandardStackElements {
|
||||
|
||||
// dynamic
|
||||
String p;
|
||||
if ((p = parseParam(s, "highest_on_track_")) != null) return highestFromGroupOnTrack(plugin, p);
|
||||
if ((p = parseParam(s, "lowest_on_track_")) != null) return lowestFromGroupOnTrack(plugin, p);
|
||||
if ((p = parseParam(s, "highest_not_on_track_")) != null) return highestNotFromGroupOnTrack(plugin, p);
|
||||
if ((p = parseParam(s, "lowest_not_on_track_")) != null) return lowestNotFromGroupOnTrack(plugin, p);
|
||||
if ((p = parseParam(s, "highest_from_group_")) != null) return highestFromGroup(p);
|
||||
if ((p = parseParam(s, "lowest_from_group_")) != null) return lowestFromGroup(p);
|
||||
if ((p = parseParam(s, "highest_not_from_group_")) != null) return highestNotFromGroup(p);
|
||||
if ((p = parseParam(s, "lowest_not_from_group_")) != null) return lowestNotFromGroup(p);
|
||||
if ((p = parseSuffixParam(s, "highest_on_track_")) != null) return highestFromGroupOnTrack(plugin, p);
|
||||
if ((p = parseSuffixParam(s, "lowest_on_track_")) != null) return lowestFromGroupOnTrack(plugin, p);
|
||||
if ((p = parseSuffixParam(s, "highest_not_on_track_")) != null) return highestNotFromGroupOnTrack(plugin, p);
|
||||
if ((p = parseSuffixParam(s, "lowest_not_on_track_")) != null) return lowestNotFromGroupOnTrack(plugin, p);
|
||||
if ((p = parseSuffixParam(s, "highest_from_group_")) != null) return highestFromGroup(p);
|
||||
if ((p = parseSuffixParam(s, "lowest_from_group_")) != null) return lowestFromGroup(p);
|
||||
if ((p = parseSuffixParam(s, "highest_not_from_group_")) != null) return highestNotFromGroup(p);
|
||||
if ((p = parseSuffixParam(s, "lowest_not_from_group_")) != null) return lowestNotFromGroup(p);
|
||||
if ((p = parseRegexParam(s, HIGHEST_N_PATTERN)) != null) return highestN(p);
|
||||
if ((p = parseRegexParam(s, LOWEST_N_PATTERN)) != null) return lowestN(p);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static String parseParam(String s, String prefix) {
|
||||
private static String parseSuffixParam(String s, String prefix) {
|
||||
if (s.startsWith(prefix) && s.length() > prefix.length()) {
|
||||
return s.substring(prefix.length());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static String parseRegexParam(String s, Pattern pattern) {
|
||||
Matcher matcher = pattern.matcher(s);
|
||||
if (!matcher.matches()) {
|
||||
return null;
|
||||
}
|
||||
return matcher.group(1);
|
||||
}
|
||||
|
||||
public static List<MetaStackElement> parseList(LuckPermsPlugin plugin, List<String> strings) {
|
||||
return strings.stream()
|
||||
.map(s -> {
|
||||
@@ -157,6 +174,15 @@ public final class StandardStackElements {
|
||||
.build();
|
||||
}
|
||||
|
||||
public static MetaStackElement highestN(String nString) {
|
||||
int n = Integer.parseInt(nString);
|
||||
return FluentMetaStackElement.builder("HighestN")
|
||||
.param("n", Integer.toString(n))
|
||||
.with(TYPE_CHECK)
|
||||
.with(CompareTakeNCheck.highest(n))
|
||||
.build();
|
||||
}
|
||||
|
||||
public static final MetaStackElement LOWEST = FluentMetaStackElement.builder("LowestPriority")
|
||||
.with(TYPE_CHECK)
|
||||
.with(LOWEST_CHECK)
|
||||
@@ -210,6 +236,62 @@ public final class StandardStackElements {
|
||||
.build();
|
||||
}
|
||||
|
||||
public static MetaStackElement lowestN(String nString) {
|
||||
int n = Integer.parseInt(nString);
|
||||
return FluentMetaStackElement.builder("LowestN")
|
||||
.param("n", Integer.toString(n))
|
||||
.with(TYPE_CHECK)
|
||||
.with(CompareTakeNCheck.lowest(n))
|
||||
.build();
|
||||
}
|
||||
|
||||
private static final class CompareTakeNCheck implements DynamicMetaStackElement {
|
||||
private static final Comparator<? super ChatMetaNode<?, ?>> LOWEST = Comparator.comparingInt(ChatMetaNode::getPriority);
|
||||
private static final Comparator<? super ChatMetaNode<?, ?>> HIGHEST = LOWEST.reversed();
|
||||
|
||||
static CompareTakeNCheck lowest(int n) {
|
||||
return new CompareTakeNCheck(n, LOWEST);
|
||||
}
|
||||
|
||||
static CompareTakeNCheck highest(int n) {
|
||||
return new CompareTakeNCheck(n, HIGHEST);
|
||||
}
|
||||
|
||||
private final int n;
|
||||
private final Comparator<? super ChatMetaNode<?, ?>> comparator;
|
||||
|
||||
CompareTakeNCheck(int n, Comparator<? super ChatMetaNode<?, ?>> comparator) {
|
||||
this.n = n - 1; // n is 1-indexed, convert it to zero-indexed
|
||||
this.comparator = comparator;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <N extends ChatMetaNode<?, ?>> ElementAccumulator<N> newAccumulator(ChatMetaType type) {
|
||||
return new Accumulator<>();
|
||||
}
|
||||
|
||||
private final class Accumulator<N extends ChatMetaNode<?, ?>> implements ElementAccumulator<N> {
|
||||
private final List<N> nodes = new ArrayList<>();
|
||||
|
||||
@Override
|
||||
public void offer(@NonNull N node) {
|
||||
this.nodes.add(node);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable N result() {
|
||||
// sort by priority
|
||||
this.nodes.sort(CompareTakeNCheck.this.comparator);
|
||||
|
||||
// return nodes[n]
|
||||
if (this.nodes.size() <= CompareTakeNCheck.this.n) {
|
||||
return null;
|
||||
}
|
||||
return this.nodes.get(CompareTakeNCheck.this.n);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static final class FromGroupOnTrackCheck implements MetaStackElement {
|
||||
private final LuckPermsPlugin plugin;
|
||||
private final String trackName;
|
||||
|
||||
Reference in new issue
Block a user