diff --git a/bukkit/src/main/java/me/lucko/luckperms/bukkit/BukkitConfig.java b/bukkit/src/main/java/me/lucko/luckperms/bukkit/BukkitConfig.java index 7fc560d10..0154c0ccc 100644 --- a/bukkit/src/main/java/me/lucko/luckperms/bukkit/BukkitConfig.java +++ b/bukkit/src/main/java/me/lucko/luckperms/bukkit/BukkitConfig.java @@ -22,6 +22,7 @@ package me.lucko.luckperms.bukkit; +import lombok.Getter; import lombok.RequiredArgsConstructor; import me.lucko.luckperms.common.config.AbstractConfiguration; @@ -38,7 +39,10 @@ import java.util.stream.Collectors; @RequiredArgsConstructor public class BukkitConfig extends AbstractConfiguration { + + @Getter private final LPBukkitPlugin plugin; + private YamlConfiguration configuration; @Override diff --git a/bukkit/src/main/resources/config.yml b/bukkit/src/main/resources/config.yml index acd710218..b109e3de1 100644 --- a/bukkit/src/main/resources/config.yml +++ b/bukkit/src/main/resources/config.yml @@ -75,6 +75,38 @@ group-weight: +# +------------------------------------------------------------------------+ # +# | Meta Formatting & Stacking | # +# +------------------------------------------------------------------------+ # + +# Allows you to setup prefix/suffix stacking options. +# +# Available formats: +# - highest +# - lowest +# - highest_own +# - lowest_own +# - highest_on_track_ +# - lowest_on_track_ +# +# Each element is added in the order listed. +meta-formatting: + prefix: + format: + - "highest" + start-spacer: "" + middle-spacer: " " + end-spacer: "" + suffix: + format: + - "highest" + start-spacer: "" + middle-spacer: " " + end-spacer: "" + + + + # +------------------------------------------------------------------------+ # # | OP (Server Operator) Settings | # # +------------------------------------------------------------------------+ # diff --git a/bungee/src/main/java/me/lucko/luckperms/bungee/BungeeConfig.java b/bungee/src/main/java/me/lucko/luckperms/bungee/BungeeConfig.java index ebb1b2ca5..2e6b2fa87 100644 --- a/bungee/src/main/java/me/lucko/luckperms/bungee/BungeeConfig.java +++ b/bungee/src/main/java/me/lucko/luckperms/bungee/BungeeConfig.java @@ -22,6 +22,7 @@ package me.lucko.luckperms.bungee; +import lombok.Getter; import lombok.RequiredArgsConstructor; import me.lucko.luckperms.common.config.AbstractConfiguration; @@ -42,7 +43,10 @@ import java.util.stream.Collectors; @RequiredArgsConstructor public class BungeeConfig extends AbstractConfiguration { + + @Getter private final LPBungeePlugin plugin; + private Configuration configuration; @SuppressWarnings("ResultOfMethodCallIgnored") diff --git a/bungee/src/main/resources/config.yml b/bungee/src/main/resources/config.yml index 673b21573..dc9b5b2de 100644 --- a/bungee/src/main/resources/config.yml +++ b/bungee/src/main/resources/config.yml @@ -85,6 +85,38 @@ group-weight: +# +------------------------------------------------------------------------+ # +# | Meta Formatting & Stacking | # +# +------------------------------------------------------------------------+ # + +# Allows you to setup prefix/suffix stacking options. +# +# Available formats: +# - highest +# - lowest +# - highest_own +# - lowest_own +# - highest_on_track_ +# - lowest_on_track_ +# +# Each element is added in the order listed. +meta-formatting: + prefix: + format: + - "highest" + start-spacer: "" + middle-spacer: " " + end-spacer: "" + suffix: + format: + - "highest" + start-spacer: "" + middle-spacer: " " + end-spacer: "" + + + + # +------------------------------------------------------------------------+ # # | Storage | # # +------------------------------------------------------------------------+ # diff --git a/common/src/main/java/me/lucko/luckperms/common/caching/MetaCache.java b/common/src/main/java/me/lucko/luckperms/common/caching/MetaCache.java index eda4c37d5..15ab240bc 100644 --- a/common/src/main/java/me/lucko/luckperms/common/caching/MetaCache.java +++ b/common/src/main/java/me/lucko/luckperms/common/caching/MetaCache.java @@ -29,6 +29,8 @@ import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSortedMap; import me.lucko.luckperms.api.caching.MetaData; +import me.lucko.luckperms.common.caching.stacking.MetaStack; +import me.lucko.luckperms.common.caching.stacking.NoopMetaStack; import java.util.Map; import java.util.SortedMap; @@ -51,12 +53,20 @@ public class MetaCache implements MetaData { @Getter private SortedMap suffixes = ImmutableSortedMap.of(); + @Getter + private MetaStack prefixStack = NoopMetaStack.INSTANCE; + + @Getter + private MetaStack suffixStack = NoopMetaStack.INSTANCE; + public void loadMeta(MetaHolder meta) { lock.writeLock().lock(); try { this.meta = ImmutableMap.copyOf(meta.getMeta()); this.prefixes = ImmutableSortedMap.copyOfSorted(meta.getPrefixes()); this.suffixes = ImmutableSortedMap.copyOfSorted(meta.getSuffixes()); + this.prefixStack = meta.getPrefixStack(); + this.suffixStack = meta.getSuffixStack(); } finally { lock.writeLock().unlock(); } @@ -66,11 +76,7 @@ public class MetaCache implements MetaData { public String getPrefix() { lock.readLock().lock(); try { - if (prefixes.isEmpty()) { - return null; - } - - return prefixes.get(prefixes.firstKey()); + return prefixStack.toFormattedString(); } finally { lock.readLock().unlock(); } @@ -80,11 +86,7 @@ public class MetaCache implements MetaData { public String getSuffix() { lock.readLock().lock(); try { - if (suffixes.isEmpty()) { - return null; - } - - return suffixes.get(suffixes.firstKey()); + return suffixStack.toFormattedString(); } finally { lock.readLock().unlock(); } diff --git a/common/src/main/java/me/lucko/luckperms/common/caching/MetaHolder.java b/common/src/main/java/me/lucko/luckperms/common/caching/MetaHolder.java index 1c4e0fd01..578db2e86 100644 --- a/common/src/main/java/me/lucko/luckperms/common/caching/MetaHolder.java +++ b/common/src/main/java/me/lucko/luckperms/common/caching/MetaHolder.java @@ -25,7 +25,9 @@ package me.lucko.luckperms.common.caching; import lombok.Getter; import lombok.ToString; -import me.lucko.luckperms.api.Node; +import me.lucko.luckperms.api.LocalizedNode; +import me.lucko.luckperms.common.caching.stacking.MetaStack; +import me.lucko.luckperms.common.caching.stacking.NoopMetaStack; import java.util.Comparator; import java.util.HashMap; @@ -40,11 +42,26 @@ import java.util.TreeMap; @ToString public class MetaHolder { - private final Map meta = new HashMap<>(); - private final SortedMap prefixes = new TreeMap<>(Comparator.reverseOrder()); - private final SortedMap suffixes = new TreeMap<>(Comparator.reverseOrder()); + private final Map meta; + private final SortedMap prefixes; + private final SortedMap suffixes; - public void accumulateNode(Node n) { + private final MetaStack prefixStack; + private final MetaStack suffixStack; + + public MetaHolder(MetaStack prefixStack, MetaStack suffixStack) { + this.meta = new HashMap<>(); + this.prefixes = new TreeMap<>(Comparator.reverseOrder()); + this.suffixes = new TreeMap<>(Comparator.reverseOrder()); + this.prefixStack = prefixStack; + this.suffixStack = suffixStack; + } + + public MetaHolder() { + this(NoopMetaStack.INSTANCE, NoopMetaStack.INSTANCE); + } + + public void accumulateNode(LocalizedNode n) { if (n.isMeta()) { Map.Entry entry = n.getMeta(); if (!meta.containsKey(entry.getKey())) { @@ -57,6 +74,8 @@ public class MetaHolder { if (!prefixes.containsKey(value.getKey())) { prefixes.put(value.getKey(), value.getValue()); } + + prefixStack.accumulateToAll(n); } if (n.isSuffix()) { @@ -64,6 +83,8 @@ public class MetaHolder { if (!suffixes.containsKey(value.getKey())) { suffixes.put(value.getKey(), value.getValue()); } + + suffixStack.accumulateToAll(n); } } diff --git a/common/src/main/java/me/lucko/luckperms/common/caching/stacking/GenericMetaStack.java b/common/src/main/java/me/lucko/luckperms/common/caching/stacking/GenericMetaStack.java new file mode 100644 index 000000000..4b8c00abd --- /dev/null +++ b/common/src/main/java/me/lucko/luckperms/common/caching/stacking/GenericMetaStack.java @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2016 Lucko (Luck) + * + * 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.caching.stacking; + +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +import java.util.ArrayList; +import java.util.List; + +@Getter +@RequiredArgsConstructor +public class GenericMetaStack implements MetaStack { + + private final List elements; + private final String startSpacer; + private final String middleSpacer; + private final String endSpacer; + + @Override + public String toFormattedString() { + List ret = new ArrayList<>(elements); + ret.removeIf(m -> !m.getEntry().isPresent()); + + if (ret.isEmpty()) { + return null; + } + + StringBuilder sb = new StringBuilder(); + sb.append(startSpacer); + for (int i = 0; i < ret.size(); i++) { + if (i != 0) { + sb.append(middleSpacer); + } + + MetaStackElement e = ret.get(i); + sb.append(e.getEntry().get().getValue()); + } + sb.append(endSpacer); + + return sb.toString(); + } +} diff --git a/common/src/main/java/me/lucko/luckperms/common/caching/stacking/MetaStack.java b/common/src/main/java/me/lucko/luckperms/common/caching/stacking/MetaStack.java new file mode 100644 index 000000000..864a62c89 --- /dev/null +++ b/common/src/main/java/me/lucko/luckperms/common/caching/stacking/MetaStack.java @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2016 Lucko (Luck) + * + * 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.caching.stacking; + +import me.lucko.luckperms.api.LocalizedNode; + +import java.util.List; + +public interface MetaStack { + + List getElements(); + String toFormattedString(); + + default void accumulateToAll(LocalizedNode node) { + getElements().forEach(m -> m.accumulateNode(node)); + } + +} diff --git a/common/src/main/java/me/lucko/luckperms/common/caching/stacking/MetaStackElement.java b/common/src/main/java/me/lucko/luckperms/common/caching/stacking/MetaStackElement.java new file mode 100644 index 000000000..99860a20b --- /dev/null +++ b/common/src/main/java/me/lucko/luckperms/common/caching/stacking/MetaStackElement.java @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2016 Lucko (Luck) + * + * 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.caching.stacking; + +import me.lucko.luckperms.api.LocalizedNode; +import me.lucko.luckperms.common.LuckPermsPlugin; +import me.lucko.luckperms.common.core.model.Track; + +import java.util.Map; +import java.util.Optional; +import java.util.UUID; + +public interface MetaStackElement { + + Optional> getEntry(); + + boolean accumulateNode(LocalizedNode node); + + /** + * Returns true if the types do not match + * @param expectingPrefix if the method is expecting a prefix + * @param node the node to check + * @return true if the accumulation should return + */ + static boolean checkMetaType(boolean expectingPrefix, LocalizedNode node) { + if (expectingPrefix) { + if (!node.isPrefix()) { + return true; + } + } else { + if (!node.isSuffix()) { + return true; + } + } + return false; + } + + /** + * Returns true if the node is not held by a user + * @param node the node to check + * @return true if the accumulation should return + */ + static boolean checkOwnElement(LocalizedNode node) { + if (node.getLocation() == null || node.getLocation().equals("")) { + return true; + } + + try { + UUID.fromString(node.getLocation()); + return false; + } catch (IllegalArgumentException e) { + return true; + } + } + + /** + * Returns true if the node is not held by a group on the track + * @param node the node to check + * @param track the track + * @return true if the accumulation should return + */ + static boolean checkTrackElement(LuckPermsPlugin plugin, LocalizedNode node, String track) { + if (node.getLocation() == null || node.getLocation().equals("")) { + return true; + } + + Track t = plugin.getTrackManager().getIfLoaded(track); + return t == null || !t.containsGroup(node.getLocation()); + } + +} diff --git a/common/src/main/java/me/lucko/luckperms/common/caching/stacking/NoopMetaStack.java b/common/src/main/java/me/lucko/luckperms/common/caching/stacking/NoopMetaStack.java new file mode 100644 index 000000000..f93b4eabc --- /dev/null +++ b/common/src/main/java/me/lucko/luckperms/common/caching/stacking/NoopMetaStack.java @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2016 Lucko (Luck) + * + * 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.caching.stacking; + +import java.util.Collections; +import java.util.List; + +public class NoopMetaStack implements MetaStack { + public static final NoopMetaStack INSTANCE = new NoopMetaStack(); + + @Override + public List getElements() { + return Collections.emptyList(); + } + + @Override + public String toFormattedString() { + return null; + } +} diff --git a/common/src/main/java/me/lucko/luckperms/common/caching/stacking/StackElementFactory.java b/common/src/main/java/me/lucko/luckperms/common/caching/stacking/StackElementFactory.java new file mode 100644 index 000000000..12cabfe97 --- /dev/null +++ b/common/src/main/java/me/lucko/luckperms/common/caching/stacking/StackElementFactory.java @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2016 Lucko (Luck) + * + * 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.caching.stacking; + +import lombok.experimental.UtilityClass; + +import me.lucko.luckperms.common.LuckPermsPlugin; +import me.lucko.luckperms.common.caching.stacking.elements.HighestPriorityElement; +import me.lucko.luckperms.common.caching.stacking.elements.HighestPriorityOwnElement; +import me.lucko.luckperms.common.caching.stacking.elements.HighestPriorityTrackElement; +import me.lucko.luckperms.common.caching.stacking.elements.LowestPriorityElement; +import me.lucko.luckperms.common.caching.stacking.elements.LowestPriorityOwnElement; +import me.lucko.luckperms.common.caching.stacking.elements.LowestPriorityTrackElement; +import me.lucko.luckperms.common.utils.ImmutableCollectors; + +import java.util.List; +import java.util.Optional; + +@UtilityClass +public class StackElementFactory { + + public static Optional fromString(LuckPermsPlugin plugin, String s, boolean prefix) { + s = s.toLowerCase(); + + if (s.equals("highest")) { + return Optional.of(new HighestPriorityElement(prefix)); + } + + if (s.equals("lowest")) { + return Optional.of(new LowestPriorityElement(prefix)); + } + + if (s.equals("highest_own")) { + return Optional.of(new HighestPriorityOwnElement(prefix)); + } + + if (s.equals("lowest_own")) { + return Optional.of(new LowestPriorityOwnElement(prefix)); + } + + if (s.startsWith("highest_on_track_") && s.length() > "highest_on_track_".length()) { + String track = s.substring("highest_on_track_".length()); + return Optional.of(new HighestPriorityTrackElement(prefix, plugin, track)); + } + + if (s.startsWith("lowest_on_track_") && s.length() > "lowest_on_track_".length()) { + String track = s.substring("lowest_on_track_".length()); + return Optional.of(new LowestPriorityTrackElement(prefix, plugin, track)); + } + + new IllegalArgumentException("Cannot parse MetaStackElement: " + s).printStackTrace(); + return Optional.empty(); + } + + public static List fromList(LuckPermsPlugin plugin, List strings, boolean prefix) { + return strings.stream().map(s -> fromString(plugin, s, prefix)).filter(Optional::isPresent).map(Optional::get).collect(ImmutableCollectors.toImmutableList()); + } + +} diff --git a/common/src/main/java/me/lucko/luckperms/common/caching/stacking/elements/HighestPriorityElement.java b/common/src/main/java/me/lucko/luckperms/common/caching/stacking/elements/HighestPriorityElement.java new file mode 100644 index 000000000..e01a743cf --- /dev/null +++ b/common/src/main/java/me/lucko/luckperms/common/caching/stacking/elements/HighestPriorityElement.java @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2016 Lucko (Luck) + * + * 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.caching.stacking.elements; + +import lombok.RequiredArgsConstructor; + +import me.lucko.luckperms.api.LocalizedNode; +import me.lucko.luckperms.common.caching.stacking.MetaStackElement; + +import java.util.Map; +import java.util.Optional; + +@RequiredArgsConstructor +public class HighestPriorityElement implements MetaStackElement { + + /** + * Returns true if the current node has the greater priority + * @param current the current entry + * @param newEntry the new entry + * @return true if the accumulation should return + */ + public static boolean compareEntries(Map.Entry current, Map.Entry newEntry) { + return current != null && current.getKey() >= newEntry.getKey(); + } + + private final boolean prefix; + private Map.Entry entry = null; + + @Override + public Optional> getEntry() { + return Optional.ofNullable(entry); + } + + @Override + public boolean accumulateNode(LocalizedNode node) { + if (MetaStackElement.checkMetaType(prefix, node)) { + return false; + } + + Map.Entry entry = prefix ? node.getPrefix() : node.getSuffix(); + if (compareEntries(this.entry, entry)) { + return false; + } + + this.entry = entry; + return true; + } +} diff --git a/common/src/main/java/me/lucko/luckperms/common/caching/stacking/elements/HighestPriorityOwnElement.java b/common/src/main/java/me/lucko/luckperms/common/caching/stacking/elements/HighestPriorityOwnElement.java new file mode 100644 index 000000000..cb2a39b01 --- /dev/null +++ b/common/src/main/java/me/lucko/luckperms/common/caching/stacking/elements/HighestPriorityOwnElement.java @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2016 Lucko (Luck) + * + * 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.caching.stacking.elements; + +import lombok.RequiredArgsConstructor; + +import me.lucko.luckperms.api.LocalizedNode; +import me.lucko.luckperms.common.caching.stacking.MetaStackElement; + +import java.util.Map; +import java.util.Optional; + +@RequiredArgsConstructor +public class HighestPriorityOwnElement implements MetaStackElement { + private final boolean prefix; + private Map.Entry entry = null; + + @Override + public Optional> getEntry() { + return Optional.ofNullable(entry); + } + + @Override + public boolean accumulateNode(LocalizedNode node) { + if (MetaStackElement.checkMetaType(prefix, node)) { + return false; + } + + if (MetaStackElement.checkOwnElement(node)) { + return false; + } + + Map.Entry entry = prefix ? node.getPrefix() : node.getSuffix(); + if (HighestPriorityElement.compareEntries(this.entry, entry)) { + return false; + } + + this.entry = entry; + return true; + } + +} diff --git a/common/src/main/java/me/lucko/luckperms/common/caching/stacking/elements/HighestPriorityTrackElement.java b/common/src/main/java/me/lucko/luckperms/common/caching/stacking/elements/HighestPriorityTrackElement.java new file mode 100644 index 000000000..05a090e09 --- /dev/null +++ b/common/src/main/java/me/lucko/luckperms/common/caching/stacking/elements/HighestPriorityTrackElement.java @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2016 Lucko (Luck) + * + * 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.caching.stacking.elements; + +import lombok.RequiredArgsConstructor; + +import me.lucko.luckperms.api.LocalizedNode; +import me.lucko.luckperms.common.LuckPermsPlugin; +import me.lucko.luckperms.common.caching.stacking.MetaStackElement; + +import java.util.Map; +import java.util.Optional; + +@RequiredArgsConstructor +public class HighestPriorityTrackElement implements MetaStackElement { + private final boolean prefix; + private final LuckPermsPlugin plugin; + private final String trackName; + + private Map.Entry entry = null; + + @Override + public Optional> getEntry() { + return Optional.ofNullable(entry); + } + + @Override + public boolean accumulateNode(LocalizedNode node) { + if (MetaStackElement.checkMetaType(prefix, node)) { + return false; + } + + Map.Entry entry = prefix ? node.getPrefix() : node.getSuffix(); + if (HighestPriorityElement.compareEntries(this.entry, entry)) { + return false; + } + + if (MetaStackElement.checkTrackElement(plugin, node, trackName)) { + return false; + } + + this.entry = entry; + return true; + } +} diff --git a/common/src/main/java/me/lucko/luckperms/common/caching/stacking/elements/LowestPriorityElement.java b/common/src/main/java/me/lucko/luckperms/common/caching/stacking/elements/LowestPriorityElement.java new file mode 100644 index 000000000..9ef82b1a4 --- /dev/null +++ b/common/src/main/java/me/lucko/luckperms/common/caching/stacking/elements/LowestPriorityElement.java @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2016 Lucko (Luck) + * + * 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.caching.stacking.elements; + +import lombok.RequiredArgsConstructor; + +import me.lucko.luckperms.api.LocalizedNode; +import me.lucko.luckperms.common.caching.stacking.MetaStackElement; + +import java.util.Map; +import java.util.Optional; + +@RequiredArgsConstructor +public class LowestPriorityElement implements MetaStackElement { + + /** + * Returns true if the current node has the lesser priority + * @param current the current entry + * @param newEntry the new entry + * @return true if the accumulation should return + */ + public static boolean compareEntries(Map.Entry current, Map.Entry newEntry) { + return current != null && current.getKey() <= newEntry.getKey(); + } + + private final boolean prefix; + private Map.Entry entry = null; + + @Override + public Optional> getEntry() { + return Optional.ofNullable(entry); + } + + @Override + public boolean accumulateNode(LocalizedNode node) { + if (MetaStackElement.checkMetaType(prefix, node)) { + return false; + } + + Map.Entry entry = prefix ? node.getPrefix() : node.getSuffix(); + if (compareEntries(this.entry, entry)) { + return false; + } + + this.entry = entry; + return true; + } +} diff --git a/common/src/main/java/me/lucko/luckperms/common/caching/stacking/elements/LowestPriorityOwnElement.java b/common/src/main/java/me/lucko/luckperms/common/caching/stacking/elements/LowestPriorityOwnElement.java new file mode 100644 index 000000000..5eb085c51 --- /dev/null +++ b/common/src/main/java/me/lucko/luckperms/common/caching/stacking/elements/LowestPriorityOwnElement.java @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2016 Lucko (Luck) + * + * 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.caching.stacking.elements; + +import lombok.RequiredArgsConstructor; + +import me.lucko.luckperms.api.LocalizedNode; +import me.lucko.luckperms.common.caching.stacking.MetaStackElement; + +import java.util.Map; +import java.util.Optional; + +@RequiredArgsConstructor +public class LowestPriorityOwnElement implements MetaStackElement { + private final boolean prefix; + private Map.Entry entry = null; + + @Override + public Optional> getEntry() { + return Optional.ofNullable(entry); + } + + @Override + public boolean accumulateNode(LocalizedNode node) { + if (MetaStackElement.checkMetaType(prefix, node)) { + return false; + } + + if (MetaStackElement.checkOwnElement(node)) { + return false; + } + + Map.Entry entry = prefix ? node.getPrefix() : node.getSuffix(); + if (LowestPriorityElement.compareEntries(this.entry, entry)) { + return false; + } + + this.entry = entry; + return true; + } +} diff --git a/common/src/main/java/me/lucko/luckperms/common/caching/stacking/elements/LowestPriorityTrackElement.java b/common/src/main/java/me/lucko/luckperms/common/caching/stacking/elements/LowestPriorityTrackElement.java new file mode 100644 index 000000000..d29194e2a --- /dev/null +++ b/common/src/main/java/me/lucko/luckperms/common/caching/stacking/elements/LowestPriorityTrackElement.java @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2016 Lucko (Luck) + * + * 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.caching.stacking.elements; + +import lombok.RequiredArgsConstructor; + +import me.lucko.luckperms.api.LocalizedNode; +import me.lucko.luckperms.common.LuckPermsPlugin; +import me.lucko.luckperms.common.caching.stacking.MetaStackElement; + +import java.util.Map; +import java.util.Optional; + +@RequiredArgsConstructor +public class LowestPriorityTrackElement implements MetaStackElement { + private final boolean prefix; + private final LuckPermsPlugin plugin; + private final String trackName; + + private Map.Entry entry = null; + + @Override + public Optional> getEntry() { + return Optional.ofNullable(entry); + } + + @Override + public boolean accumulateNode(LocalizedNode node) { + if (MetaStackElement.checkMetaType(prefix, node)) { + return false; + } + + Map.Entry entry = prefix ? node.getPrefix() : node.getSuffix(); + if (LowestPriorityElement.compareEntries(this.entry, entry)) { + return false; + } + + if (MetaStackElement.checkTrackElement(plugin, node, trackName)) { + return false; + } + + this.entry = entry; + return true; + } +} 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 ffd757942..0f245238b 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 @@ -27,6 +27,8 @@ import lombok.experimental.UtilityClass; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; +import me.lucko.luckperms.common.caching.stacking.GenericMetaStack; +import me.lucko.luckperms.common.caching.stacking.StackElementFactory; import me.lucko.luckperms.common.config.keys.AbstractKey; import me.lucko.luckperms.common.config.keys.BooleanKey; import me.lucko.luckperms.common.config.keys.EnduringKey; @@ -38,6 +40,7 @@ import me.lucko.luckperms.common.defaults.Rule; import me.lucko.luckperms.common.storage.DatastoreConfiguration; import me.lucko.luckperms.common.utils.ImmutableCollectors; +import java.util.Collections; import java.util.List; import java.util.Map; @@ -68,6 +71,22 @@ public class ConfigKeys { }) ); }); + public static final ConfigKey PREFIX_FORMATTING_OPTIONS = AbstractKey.of(l -> { + List format = l.getList("meta-formatting.prefix.format", Collections.singletonList("highest")); + String startSpacer = l.getString("meta-formatting.prefix.start-spacer", ""); + String middleSpacer = l.getString("meta-formatting.prefix.middle-spacer", " "); + String endSpacer = l.getString("meta-formatting.prefix.end-spacer", ""); + + return new GenericMetaStack(StackElementFactory.fromList(l.getPlugin(), format, true), startSpacer, middleSpacer, endSpacer); + }); + public static final ConfigKey SUFFIX_FORMATTING_OPTIONS = AbstractKey.of(l -> { + List format = l.getList("meta-formatting.suffix.format", Collections.singletonList("highest")); + String startSpacer = l.getString("meta-formatting.suffix.start-spacer", ""); + String middleSpacer = l.getString("meta-formatting.suffix.middle-spacer", " "); + String endSpacer = l.getString("meta-formatting.suffix.end-spacer", ""); + + return new GenericMetaStack(StackElementFactory.fromList(l.getPlugin(), format, false), startSpacer, middleSpacer, endSpacer); + }); public static final ConfigKey LOG_NOTIFY = BooleanKey.of("log-notify", true); public static final ConfigKey AUTO_OP = EnduringKey.wrap(BooleanKey.of("auto-op", false)); public static final ConfigKey OPS_ENABLED = EnduringKey.wrap(AbstractKey.of(c -> !AUTO_OP.get(c) && c.getBoolean("enable-ops", true))); diff --git a/common/src/main/java/me/lucko/luckperms/common/config/LPConfiguration.java b/common/src/main/java/me/lucko/luckperms/common/config/LPConfiguration.java index 31d10804f..addd97ab5 100644 --- a/common/src/main/java/me/lucko/luckperms/common/config/LPConfiguration.java +++ b/common/src/main/java/me/lucko/luckperms/common/config/LPConfiguration.java @@ -22,11 +22,15 @@ package me.lucko.luckperms.common.config; +import me.lucko.luckperms.common.LuckPermsPlugin; + import java.util.List; import java.util.Map; public interface LPConfiguration { + LuckPermsPlugin getPlugin(); + void init(); void reload(); diff --git a/common/src/main/java/me/lucko/luckperms/common/core/model/PermissionHolder.java b/common/src/main/java/me/lucko/luckperms/common/core/model/PermissionHolder.java index 9cdc6e41d..597316be7 100644 --- a/common/src/main/java/me/lucko/luckperms/common/core/model/PermissionHolder.java +++ b/common/src/main/java/me/lucko/luckperms/common/core/model/PermissionHolder.java @@ -467,7 +467,10 @@ public abstract class PermissionHolder { public MetaHolder accumulateMeta(MetaHolder holder, List excludedGroups, ExtractedContexts contexts) { if (holder == null) { - holder = new MetaHolder(); + holder = new MetaHolder( + plugin.getConfiguration().get(ConfigKeys.PREFIX_FORMATTING_OPTIONS), + plugin.getConfiguration().get(ConfigKeys.SUFFIX_FORMATTING_OPTIONS) + ); } if (excludedGroups == null) { @@ -490,7 +493,7 @@ public abstract class PermissionHolder { if (!n.shouldApplyOnWorld(world, context.isIncludeGlobalWorld(), false)) continue; if (!n.shouldApplyWithContext(contexts.getContextSet(), false)) continue; - holder.accumulateNode(n); + holder.accumulateNode(ln); } Set parents = all.stream() diff --git a/sponge/src/main/java/me/lucko/luckperms/sponge/SpongeConfig.java b/sponge/src/main/java/me/lucko/luckperms/sponge/SpongeConfig.java index be7d397f8..a88864d61 100644 --- a/sponge/src/main/java/me/lucko/luckperms/sponge/SpongeConfig.java +++ b/sponge/src/main/java/me/lucko/luckperms/sponge/SpongeConfig.java @@ -22,6 +22,7 @@ package me.lucko.luckperms.sponge; +import lombok.Getter; import lombok.RequiredArgsConstructor; import com.google.common.base.Splitter; @@ -45,7 +46,10 @@ import java.util.stream.Collectors; @RequiredArgsConstructor public class SpongeConfig extends AbstractConfiguration { + + @Getter private final LPSpongePlugin plugin; + private ConfigurationNode root; @SuppressWarnings("ResultOfMethodCallIgnored") diff --git a/sponge/src/main/resources/luckperms.conf b/sponge/src/main/resources/luckperms.conf index 870a16910..121aeac94 100644 --- a/sponge/src/main/resources/luckperms.conf +++ b/sponge/src/main/resources/luckperms.conf @@ -84,6 +84,43 @@ group-weight { +# +------------------------------------------------------------------------+ # +# | Meta Formatting & Stacking | # +# +------------------------------------------------------------------------+ # + +# Allows you to setup prefix/suffix stacking options. +# +# Available formats: +# - highest +# - lowest +# - highest_own +# - lowest_own +# - highest_on_track_ +# - lowest_on_track_ +# +# Each element is added in the order listed. +meta-formatting { + prefix { + format = [ + "highest" + ] + start-spacer="" + middle-spacer=" " + end-spacer="" + } + suffix { + format = [ + "highest" + ] + start-spacer="" + middle-spacer=" " + end-spacer="" + } +} + + + + # +------------------------------------------------------------------------+ # # | Storage | # # +------------------------------------------------------------------------+ #