mirror of
https://github.com/LuckPerms/LuckPerms.git
synced 2025-02-04 14:41:39 +01:00
Refactor contexts, expose cached data in the API & release 2.13
This commit is contained in:
parent
33c78e4a17
commit
383276f47a
@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<artifactId>luckperms</artifactId>
|
||||
<groupId>me.lucko.luckperms</groupId>
|
||||
<version>2.12-SNAPSHOT</version>
|
||||
<version>2.13-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
@ -22,9 +22,8 @@
|
||||
|
||||
package me.lucko.luckperms.api;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import me.lucko.luckperms.api.context.ContextSet;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
@ -41,23 +40,19 @@ public class Contexts {
|
||||
* @return a context that will not apply any filters
|
||||
*/
|
||||
public static Contexts allowAll() {
|
||||
return new Contexts(Collections.emptyMap(), true, true, true, true, true, true);
|
||||
return new Contexts(ContextSet.empty(), true, true, true, true, true, true);
|
||||
}
|
||||
|
||||
public static Contexts of(Map<String, String> context, boolean includeGlobal, boolean includeGlobalWorld, boolean applyGroups, boolean applyGlobalGroups, boolean applyGlobalWorldGroups) {
|
||||
return new Contexts(context, includeGlobal, includeGlobalWorld, applyGroups, applyGlobalGroups, applyGlobalWorldGroups);
|
||||
}
|
||||
|
||||
public static Contexts of(Map<String, String> context, boolean includeGlobal, boolean includeGlobalWorld, boolean applyGroups, boolean applyGlobalGroups, boolean applyGlobalWorldGroups, boolean op) {
|
||||
public static Contexts of(ContextSet context, boolean includeGlobal, boolean includeGlobalWorld, boolean applyGroups, boolean applyGlobalGroups, boolean applyGlobalWorldGroups, boolean op) {
|
||||
return new Contexts(context, includeGlobal, includeGlobalWorld, applyGroups, applyGlobalGroups, applyGlobalWorldGroups, op);
|
||||
}
|
||||
|
||||
public Contexts(Map<String, String> context, boolean includeGlobal, boolean includeGlobalWorld, boolean applyGroups, boolean applyGlobalGroups, boolean applyGlobalWorldGroups, boolean op) {
|
||||
public Contexts(ContextSet context, boolean includeGlobal, boolean includeGlobalWorld, boolean applyGroups, boolean applyGlobalGroups, boolean applyGlobalWorldGroups, boolean op) {
|
||||
if (context == null) {
|
||||
throw new NullPointerException("context");
|
||||
}
|
||||
|
||||
this.context = ImmutableMap.copyOf(context);
|
||||
this.context = context.makeImmutable();
|
||||
this.includeGlobal = includeGlobal;
|
||||
this.includeGlobalWorld = includeGlobalWorld;
|
||||
this.applyGroups = applyGroups;
|
||||
@ -66,16 +61,34 @@ public class Contexts {
|
||||
this.op = op;
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
@Deprecated
|
||||
public static Contexts of(Map<String, String> context, boolean includeGlobal, boolean includeGlobalWorld, boolean applyGroups, boolean applyGlobalGroups, boolean applyGlobalWorldGroups) {
|
||||
return new Contexts(context, includeGlobal, includeGlobalWorld, applyGroups, applyGlobalGroups, applyGlobalWorldGroups);
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
@Deprecated
|
||||
public static Contexts of(Map<String, String> context, boolean includeGlobal, boolean includeGlobalWorld, boolean applyGroups, boolean applyGlobalGroups, boolean applyGlobalWorldGroups, boolean op) {
|
||||
return new Contexts(context, includeGlobal, includeGlobalWorld, applyGroups, applyGlobalGroups, applyGlobalWorldGroups, op);
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public Contexts(Map<String, String> context, boolean includeGlobal, boolean includeGlobalWorld, boolean applyGroups, boolean applyGlobalGroups, boolean applyGlobalWorldGroups, boolean op) {
|
||||
this(context == null ? null : ContextSet.fromMap(context), includeGlobal, includeGlobalWorld, applyGroups, applyGlobalGroups, applyGlobalWorldGroups, op);
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
@Deprecated
|
||||
public Contexts(Map<String, String> context, boolean includeGlobal, boolean includeGlobalWorld, boolean applyGroups, boolean applyGlobalGroups, boolean applyGlobalWorldGroups) {
|
||||
this(context, includeGlobal, includeGlobalWorld, applyGroups, applyGlobalGroups, applyGlobalWorldGroups, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* The contexts that apply for this lookup
|
||||
*
|
||||
* The keys for servers and worlds are defined as static values.
|
||||
*/
|
||||
private final Map<String, String> context;
|
||||
private final ContextSet context;
|
||||
|
||||
/**
|
||||
* The mode to parse defaults on Bukkit
|
||||
@ -110,12 +123,23 @@ public class Contexts {
|
||||
|
||||
/**
|
||||
* Gets the contexts that apply for this lookup
|
||||
* @return an immutable map of context key value pairs
|
||||
* @return an immutable set of context key value pairs
|
||||
* @since 2.13
|
||||
*/
|
||||
public Map<String, String> getContext() {
|
||||
public ContextSet getContexts() {
|
||||
return this.context;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the contexts that apply for this lookup
|
||||
* @return an immutable map of context key value pairs
|
||||
* @deprecated in favour of {@link #getContexts()}
|
||||
*/
|
||||
@Deprecated
|
||||
public Map<String, String> getContext() {
|
||||
return this.context.toMap();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets if OP defaults should be included
|
||||
* @return true if op defaults should be included
|
||||
@ -166,7 +190,7 @@ public class Contexts {
|
||||
|
||||
public String toString() {
|
||||
return "Contexts(" +
|
||||
"context=" + this.getContext() + ", " +
|
||||
"context=" + this.getContexts() + ", " +
|
||||
"op=" + this.isOp() + ", " +
|
||||
"includeGlobal=" + this.isIncludeGlobal() + ", " +
|
||||
"includeGlobalWorld=" + this.isIncludeGlobalWorld() + ", " +
|
||||
@ -190,8 +214,8 @@ public class Contexts {
|
||||
if (o == this) return true;
|
||||
if (!(o instanceof Contexts)) return false;
|
||||
final Contexts other = (Contexts) o;
|
||||
final Object this$context = this.getContext();
|
||||
final Object other$context = other.getContext();
|
||||
final Object this$context = this.getContexts();
|
||||
final Object other$context = other.getContexts();
|
||||
if (this$context == null ? other$context != null : !this$context.equals(other$context)) return false;
|
||||
if (this.isOp() != other.isOp()) return false;
|
||||
if (this.isIncludeGlobal() != other.isIncludeGlobal()) return false;
|
||||
@ -210,7 +234,7 @@ public class Contexts {
|
||||
public int hashCode() {
|
||||
final int PRIME = 59;
|
||||
int result = 1;
|
||||
final Object $context = this.getContext();
|
||||
final Object $context = this.getContexts();
|
||||
result = result * PRIME + ($context == null ? 43 : $context.hashCode());
|
||||
result = result * PRIME + (this.isOp() ? 79 : 97);
|
||||
result = result * PRIME + (this.isIncludeGlobal() ? 79 : 97);
|
||||
|
@ -258,7 +258,7 @@ public class MetaUtils {
|
||||
|
||||
int priority = Integer.MIN_VALUE;
|
||||
String meta = null;
|
||||
for (Node n : holder.getAllNodes()) {
|
||||
for (Node n : holder.getAllNodes(Contexts.allowAll())) {
|
||||
if (!n.getValue()) {
|
||||
continue;
|
||||
}
|
||||
|
@ -22,10 +22,9 @@
|
||||
|
||||
package me.lucko.luckperms.api;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import me.lucko.luckperms.api.context.ContextSet;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* Represents an immutable node object
|
||||
@ -109,15 +108,40 @@ public interface Node extends Map.Entry<String, Boolean> {
|
||||
* @param context the context key value pairs
|
||||
* @param worldAndServer if world and server contexts should be checked
|
||||
* @return true if the node should apply
|
||||
* @since 2.13
|
||||
*/
|
||||
boolean shouldApplyWithContext(Map<String, String> context, boolean worldAndServer);
|
||||
boolean shouldApplyWithContext(ContextSet context, boolean worldAndServer);
|
||||
|
||||
/**
|
||||
* If this node should apply in the given context
|
||||
* @param context the context key value pairs
|
||||
* @return true if the node should apply
|
||||
* @since 2.13
|
||||
*/
|
||||
boolean shouldApplyWithContext(Map<String, String> context);
|
||||
boolean shouldApplyWithContext(ContextSet context);
|
||||
|
||||
/**
|
||||
* If this node should apply in the given context
|
||||
* @param context the context key value pairs
|
||||
* @param worldAndServer if world and server contexts should be checked
|
||||
* @return true if the node should apply
|
||||
* @deprecated in favour of {@link #shouldApplyWithContext(ContextSet, boolean)}
|
||||
*/
|
||||
@Deprecated
|
||||
default boolean shouldApplyWithContext(Map<String, String> context, boolean worldAndServer) {
|
||||
return shouldApplyWithContext(ContextSet.fromMap(context), worldAndServer);
|
||||
}
|
||||
|
||||
/**
|
||||
* If this node should apply in the given context
|
||||
* @param context the context key value pairs
|
||||
* @return true if the node should apply
|
||||
* @deprecated in favour of {@link #shouldApplyWithContext(ContextSet)}
|
||||
*/
|
||||
@Deprecated
|
||||
default boolean shouldApplyWithContext(Map<String, String> context) {
|
||||
return shouldApplyWithContext(ContextSet.fromMap(context));
|
||||
}
|
||||
|
||||
/**
|
||||
* Similar to {@link #shouldApplyOnServer(String, boolean, boolean)}, except this method accepts a List
|
||||
@ -186,8 +210,18 @@ public interface Node extends Map.Entry<String, Boolean> {
|
||||
|
||||
/**
|
||||
* @return the extra contexts required for this node to apply
|
||||
* @deprecated in favour of {@link #getContexts()}
|
||||
*/
|
||||
Map<String, String> getExtraContexts();
|
||||
@Deprecated
|
||||
default Map<String, String> getExtraContexts() {
|
||||
return getContexts().toMap();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the extra contexts required for this node to apply
|
||||
* @since 2.13
|
||||
*/
|
||||
ContextSet getContexts();
|
||||
|
||||
/**
|
||||
* Converts this node into a serialized form
|
||||
@ -302,7 +336,9 @@ public interface Node extends Map.Entry<String, Boolean> {
|
||||
Builder setServer(String server) throws IllegalArgumentException;
|
||||
Builder withExtraContext(String key, String value);
|
||||
Builder withExtraContext(Map<String, String> map);
|
||||
Builder withExtraContext(Set<Map.Entry<String, String>> context);
|
||||
Builder withExtraContext(Map.Entry<String, String> entry);
|
||||
Builder withExtraContext(ContextSet set);
|
||||
Node build();
|
||||
}
|
||||
|
||||
|
@ -22,10 +22,12 @@
|
||||
|
||||
package me.lucko.luckperms.api;
|
||||
|
||||
import me.lucko.luckperms.api.caching.UserData;
|
||||
import me.lucko.luckperms.exceptions.ObjectAlreadyHasException;
|
||||
import me.lucko.luckperms.exceptions.ObjectLacksException;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
@ -64,6 +66,13 @@ public interface User extends PermissionHolder {
|
||||
*/
|
||||
void refreshPermissions();
|
||||
|
||||
/**
|
||||
* Gets the user's {@link UserData} cache, if they have one setup.
|
||||
* @return an optional, possibly containing the user's cached lookup data.
|
||||
* @since 2.13
|
||||
*/
|
||||
Optional<UserData> getUserDataCache();
|
||||
|
||||
/**
|
||||
* Check to see if the user is a member of a group
|
||||
* @param group The group to check membership of
|
||||
|
@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Copyright (c) 2016 Lucko (Luck) <luck@lucko.me>
|
||||
*
|
||||
* 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.api.caching;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.SortedMap;
|
||||
|
||||
/**
|
||||
* Holds cached Meta lookup data for a specific set of contexts
|
||||
* @since 2.13
|
||||
*/
|
||||
public interface MetaData {
|
||||
|
||||
/**
|
||||
* Gets an immutable copy of the meta this user has
|
||||
* @return an immutable map of meta
|
||||
*/
|
||||
Map<String, String> getMeta();
|
||||
|
||||
/**
|
||||
* Gets an immutable sorted map of all of the prefixes the user has, whereby the first value is the highest priority prefix.
|
||||
* @return a sorted map of prefixes
|
||||
*/
|
||||
SortedMap<Integer, String> getPrefixes();
|
||||
|
||||
/**
|
||||
* Gets an immutable sorted map of all of the suffixes the user has, whereby the first value is the highest priority suffix.
|
||||
* @return a sorted map of suffixes
|
||||
*/
|
||||
SortedMap<Integer, String> getSuffixes();
|
||||
|
||||
/**
|
||||
* Gets the user's highest priority prefix, or null if the user has no prefixes
|
||||
* @return a prefix string, or null
|
||||
*/
|
||||
String getPrefix();
|
||||
|
||||
/**
|
||||
* Gets the user's highest priority suffix, or null if the user has no suffixes
|
||||
* @return a suffix string, or null
|
||||
*/
|
||||
String getSuffix();
|
||||
|
||||
}
|
@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright (c) 2016 Lucko (Luck) <luck@lucko.me>
|
||||
*
|
||||
* 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.api.caching;
|
||||
|
||||
import me.lucko.luckperms.api.Tristate;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Holds cached Permission lookup data for a specific set of contexts
|
||||
* @since 2.13
|
||||
*/
|
||||
public interface PermissionData {
|
||||
|
||||
/**
|
||||
* Gets a permission value for the given permission node
|
||||
* @param permission the permission node
|
||||
* @return a tristate result
|
||||
* @throws NullPointerException if permission is null
|
||||
*/
|
||||
Tristate getPermissionValue(String permission);
|
||||
|
||||
/**
|
||||
* Invalidates the underlying permission calculator cache.
|
||||
* Can be called to allow for an update in defaults.
|
||||
*/
|
||||
void invalidateCache();
|
||||
|
||||
/**
|
||||
* Gets an immutable copy of the permission map backing the permission calculator
|
||||
* @return an immutable set of permissions
|
||||
*/
|
||||
Map<String, Boolean> getImmutableBacking();
|
||||
|
||||
}
|
119
api/src/main/java/me/lucko/luckperms/api/caching/UserData.java
Normal file
119
api/src/main/java/me/lucko/luckperms/api/caching/UserData.java
Normal file
@ -0,0 +1,119 @@
|
||||
/*
|
||||
* Copyright (c) 2016 Lucko (Luck) <luck@lucko.me>
|
||||
*
|
||||
* 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.api.caching;
|
||||
|
||||
import me.lucko.luckperms.api.Contexts;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Holds cached permission and meta lookup data for a {@link me.lucko.luckperms.api.User}.
|
||||
* Data is only likely to be available for online users. All calls will account for inheritance, as well as any
|
||||
* default data provided by the platform. This calls are heavily cached and are therefore fast.
|
||||
*
|
||||
* @since 2.13
|
||||
*/
|
||||
public interface UserData {
|
||||
|
||||
/**
|
||||
* Gets PermissionData from the cache, given a specified context.
|
||||
* If the data is not cached, it is calculated. Therefore, this call could be costly.
|
||||
* @param contexts the contexts to get the permission data in
|
||||
* @return a permission data instance
|
||||
* @throws NullPointerException if contexts is null
|
||||
*/
|
||||
PermissionData getPermissionData(Contexts contexts);
|
||||
|
||||
/**
|
||||
* Gets MetaData from the cache, given a specified context.
|
||||
* If the data is not cached, it is calculated. Therefore, this call could be costly.
|
||||
* @param contexts the contexts to get the permission data in
|
||||
* @return a meta data instance
|
||||
* @throws NullPointerException if contexts is null
|
||||
*/
|
||||
MetaData getMetaData(Contexts contexts);
|
||||
|
||||
/**
|
||||
* Calculates permission data, bypassing the cache.
|
||||
* @param contexts the contexts to get permission data in
|
||||
* @return a permission data instance
|
||||
* @throws NullPointerException if contexts is null
|
||||
*/
|
||||
PermissionData calculatePermissions(Contexts contexts);
|
||||
|
||||
/**
|
||||
* Calculates meta data, bypassing the cache.
|
||||
* @param contexts the contexts to get meta data in
|
||||
* @return a meta data instance
|
||||
* @throws NullPointerException if contexts is null
|
||||
*/
|
||||
MetaData calculateMeta(Contexts contexts);
|
||||
|
||||
/**
|
||||
* Calculates permission data and stores it in the cache. If there is already data cached for the given contexts,
|
||||
* and if the resultant output is different, the cached value is updated.
|
||||
* @param contexts the contexts to recalculate in.
|
||||
* @throws NullPointerException if contexts is null
|
||||
*/
|
||||
void recalculatePermissions(Contexts contexts);
|
||||
|
||||
/**
|
||||
* Calculates meta data and stores it in the cache. If there is already data cached for the given contexts,
|
||||
* and if the resultant output is different, the cached value is updated.
|
||||
* @param contexts the contexts to recalculate in.
|
||||
* @throws NullPointerException if contexts is null
|
||||
*/
|
||||
void recalculateMeta(Contexts contexts);
|
||||
|
||||
/**
|
||||
* Calls {@link #recalculatePermissions(Contexts)} for all current loaded contexts
|
||||
*/
|
||||
void recalculatePermissions();
|
||||
|
||||
/**
|
||||
* Calls {@link #recalculateMeta(Contexts)} for all current loaded contexts
|
||||
*/
|
||||
void recalculateMeta();
|
||||
|
||||
/**
|
||||
* Calls {@link #preCalculate(Contexts)} for the given contexts
|
||||
* @param contexts a set of contexts
|
||||
* @throws NullPointerException if contexts is null
|
||||
*/
|
||||
void preCalculate(Set<Contexts> contexts);
|
||||
|
||||
/**
|
||||
* Ensures that PermissionData and MetaData is cached for a context. If the cache does not contain any data for the
|
||||
* context, it will be calculated and saved.
|
||||
* @param contexts the contexts to pre-calculate for
|
||||
* @throws NullPointerException if contexts is null
|
||||
*/
|
||||
void preCalculate(Contexts contexts);
|
||||
|
||||
/**
|
||||
* Invalidates all of the underlying Permission calculators.
|
||||
* Can be called to allow for an update in defaults.
|
||||
*/
|
||||
void invalidatePermissionCalculators();
|
||||
|
||||
}
|
306
api/src/main/java/me/lucko/luckperms/api/context/ContextSet.java
Normal file
306
api/src/main/java/me/lucko/luckperms/api/context/ContextSet.java
Normal file
@ -0,0 +1,306 @@
|
||||
/*
|
||||
* Copyright (c) 2016 Lucko (Luck) <luck@lucko.me>
|
||||
*
|
||||
* 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.api.context;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* Holds contexts.
|
||||
* All contained contexts are immutable, and unlike {@link MutableContextSet}, contexts cannot be added or removed.
|
||||
*
|
||||
* @since 2.13
|
||||
*/
|
||||
public class ContextSet {
|
||||
|
||||
/**
|
||||
* Make a singleton ContextSet from a context pair
|
||||
* @param key the key
|
||||
* @param value the value
|
||||
* @return a new ContextSet containing one KV pair
|
||||
* @throws NullPointerException if key or value is null
|
||||
*/
|
||||
public static ContextSet singleton(String key, String value) {
|
||||
if (key == null) {
|
||||
throw new NullPointerException("key");
|
||||
}
|
||||
if (value == null) {
|
||||
throw new NullPointerException("value");
|
||||
}
|
||||
|
||||
MutableContextSet set = new MutableContextSet();
|
||||
set.add(key, value);
|
||||
return set.immutableCopy();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a ContextSet from an existing map
|
||||
* @param map the map to copy from
|
||||
* @return a new ContextSet representing the pairs from the map
|
||||
* @throws NullPointerException if the map is null
|
||||
*/
|
||||
public static ContextSet fromMap(Map<String, String> map) {
|
||||
if (map == null) {
|
||||
throw new NullPointerException("map");
|
||||
}
|
||||
|
||||
MutableContextSet set = new MutableContextSet();
|
||||
set.addAll(map);
|
||||
return set.immutableCopy();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a ContextSet from an existing iterable of Map Entries
|
||||
* @param iterable the iterable to copy from
|
||||
* @return a new ContextSet representing the pairs in the iterable
|
||||
* @throws NullPointerException if the iterable is null
|
||||
*/
|
||||
public static ContextSet fromEntries(Iterable<Map.Entry<String, String>> iterable) {
|
||||
if (iterable == null) {
|
||||
throw new NullPointerException("iterable");
|
||||
}
|
||||
|
||||
MutableContextSet set = new MutableContextSet();
|
||||
set.addAll(iterable);
|
||||
return set.immutableCopy();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new ContextSet from an existing set.
|
||||
* Only really useful for converting between mutable and immutable types.
|
||||
* @param contextSet the context set to copy from
|
||||
* @return a new ContextSet with the same content and the one provided
|
||||
* @throws NullPointerException if contextSet is null
|
||||
*/
|
||||
public static ContextSet fromSet(ContextSet contextSet) {
|
||||
if (contextSet == null) {
|
||||
throw new NullPointerException("contextSet");
|
||||
}
|
||||
|
||||
MutableContextSet set = new MutableContextSet();
|
||||
set.addAll(contextSet.toSet());
|
||||
return set.immutableCopy();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new empty ContextSet.
|
||||
* @return a new ContextSet
|
||||
*/
|
||||
public static ContextSet empty() {
|
||||
return new ContextSet();
|
||||
}
|
||||
|
||||
final Set<Map.Entry<String, String>> contexts;
|
||||
|
||||
public ContextSet() {
|
||||
this.contexts = new HashSet<>();
|
||||
}
|
||||
|
||||
protected ContextSet(Set<Map.Entry<String, String>> contexts) {
|
||||
this.contexts = contexts;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check to see if this set is in an immutable form
|
||||
* @return true if the set is immutable
|
||||
*/
|
||||
public boolean isImmutable() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* If the set is mutable, this method will return an immutable copy. Otherwise just returns itself.
|
||||
* @return an immutable ContextSet
|
||||
*/
|
||||
public ContextSet makeImmutable() {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts this ContextSet to an immutable {@link Set} of {@link Map.Entry}s.
|
||||
* @return an immutable set
|
||||
*/
|
||||
public Set<Map.Entry<String, String>> toSet() {
|
||||
synchronized (contexts) {
|
||||
return ImmutableSet.copyOf(contexts);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts this ContextSet to an immutable {@link Map}
|
||||
*
|
||||
* <b>NOTE: Use of this method may result in data being lost. ContextSets can contain lots of different values for
|
||||
* one key.</b>
|
||||
*
|
||||
* @return an immutable map
|
||||
*/
|
||||
public Map<String, String> toMap() {
|
||||
synchronized (contexts) {
|
||||
return ImmutableMap.copyOf(contexts.stream().collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the set contains at least one value for the given key.
|
||||
* @param key the key to check for
|
||||
* @return true if the set contains a value for the key
|
||||
* @throws NullPointerException if the key is null
|
||||
*/
|
||||
public boolean containsKey(String key) {
|
||||
if (key == null) {
|
||||
throw new NullPointerException("key");
|
||||
}
|
||||
|
||||
synchronized (contexts) {
|
||||
for (Map.Entry<String, String> e : contexts) {
|
||||
if (e.getKey().equalsIgnoreCase(key)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a set of all of the values mapped to the given key
|
||||
* @param key the key to find values for
|
||||
* @return a set of values
|
||||
* @throws NullPointerException if the key is null
|
||||
*/
|
||||
public Set<String> getValues(String key) {
|
||||
if (key == null) {
|
||||
throw new NullPointerException("key");
|
||||
}
|
||||
|
||||
synchronized (contexts) {
|
||||
return ImmutableSet.copyOf(contexts.stream()
|
||||
.filter(e -> e.getKey().equalsIgnoreCase(key))
|
||||
.map(Map.Entry::getValue)
|
||||
.collect(Collectors.toSet())
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if thr set contains a given key mapped to a given value
|
||||
* @param key the key to look for
|
||||
* @param value the value to look for (case sensitive)
|
||||
* @return true if the set contains the KV pair
|
||||
* @throws NullPointerException if the key or value is null
|
||||
*/
|
||||
public boolean has(String key, String value) {
|
||||
if (key == null) {
|
||||
throw new NullPointerException("key");
|
||||
}
|
||||
if (value == null) {
|
||||
throw new NullPointerException("value");
|
||||
}
|
||||
|
||||
synchronized (contexts) {
|
||||
for (Map.Entry<String, String> e : contexts) {
|
||||
if (!e.getKey().equalsIgnoreCase(key)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!e.getValue().equals(value)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Same as {@link #has(String, String)}, except ignores the case of the value.
|
||||
* @param key the key to look for
|
||||
* @param value the value to look for
|
||||
* @return true if the set contains the KV pair
|
||||
* @throws NullPointerException if the key or value is null
|
||||
*/
|
||||
public boolean hasIgnoreCase(String key, String value) {
|
||||
if (key == null) {
|
||||
throw new NullPointerException("key");
|
||||
}
|
||||
if (value == null) {
|
||||
throw new NullPointerException("value");
|
||||
}
|
||||
|
||||
synchronized (contexts) {
|
||||
for (Map.Entry<String, String> e : contexts) {
|
||||
if (!e.getKey().equalsIgnoreCase(key)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!e.getValue().equalsIgnoreCase(value)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the set is empty
|
||||
* @return true if the set is empty
|
||||
*/
|
||||
public boolean isEmpty() {
|
||||
synchronized (contexts) {
|
||||
return contexts.isEmpty();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the number of key-value context pairs in the set
|
||||
* @return the size of the set
|
||||
*/
|
||||
public int size() {
|
||||
synchronized (contexts) {
|
||||
return contexts.size();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (o == this) return true;
|
||||
if (!(o instanceof ContextSet)) return false;
|
||||
final ContextSet other = (ContextSet) o;
|
||||
|
||||
final Object thisContexts = this.contexts;
|
||||
final Object otherContexts = other.contexts;
|
||||
return thisContexts == null ? otherContexts == null : thisContexts.equals(otherContexts);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return 59 + (this.contexts == null ? 43 : this.contexts.hashCode());
|
||||
}
|
||||
}
|
@ -22,6 +22,7 @@
|
||||
|
||||
package me.lucko.luckperms.api.context;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
@ -34,11 +35,40 @@ public interface IContextCalculator<T> {
|
||||
|
||||
/**
|
||||
* Gives the subject all of the applicable contexts they meet
|
||||
* @param subject the subject to add contexts tp
|
||||
* @param subject the subject to add contexts to
|
||||
* @param accumulator a map of contexts to add to
|
||||
* @return the map
|
||||
* @deprecated in favour of {@link #giveApplicableContext(Object, MutableContextSet)}. Older implementations of this interface
|
||||
* will still work, as the replacement method is given as a default, and falls back to using this method.
|
||||
*/
|
||||
Map<String, String> giveApplicableContext(T subject, Map<String, String> accumulator);
|
||||
@Deprecated
|
||||
default Map<String, String> giveApplicableContext(T subject, Map<String, String> accumulator) {
|
||||
MutableContextSet acc = new MutableContextSet();
|
||||
giveApplicableContext(subject, acc);
|
||||
|
||||
accumulator.putAll(acc.toMap());
|
||||
return accumulator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gives the subject all of the applicable contexts they meet
|
||||
*
|
||||
* <p><b>You MUST implement this method. The default is only provided for backwards compatibility with
|
||||
* {@link #giveApplicableContext(Object, Map)}.</b>
|
||||
*
|
||||
* @param subject the subject to add contexts to
|
||||
* @param accumulator a map of contexts to add to
|
||||
* @return the map
|
||||
* @since 2.13
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
default MutableContextSet giveApplicableContext(T subject, MutableContextSet accumulator) {
|
||||
Map<String, String> acc = new HashMap<>();
|
||||
giveApplicableContext(subject, acc);
|
||||
|
||||
accumulator.addAll(acc.entrySet());
|
||||
return accumulator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks to see if a context is applicable to a subject
|
||||
|
@ -0,0 +1,272 @@
|
||||
/*
|
||||
* Copyright (c) 2016 Lucko (Luck) <luck@lucko.me>
|
||||
*
|
||||
* 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.api.context;
|
||||
|
||||
import com.google.common.collect.Maps;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Holds contexts
|
||||
* All contained contexts are immutable, but contexts can be added or removed from the set.
|
||||
*
|
||||
* @since 2.13
|
||||
*/
|
||||
public class MutableContextSet extends ContextSet {
|
||||
|
||||
/**
|
||||
* Make a singleton MutableContextSet from a context pair
|
||||
* @param key the key
|
||||
* @param value the value
|
||||
* @return a new MutableContextSet containing one KV pair
|
||||
* @throws NullPointerException if key or value is null
|
||||
*/
|
||||
public static MutableContextSet singleton(String key, String value) {
|
||||
MutableContextSet set = new MutableContextSet();
|
||||
set.add(key, value);
|
||||
return set;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a MutableContextSet from an existing map
|
||||
* @param map the map to copy from
|
||||
* @return a new MutableContextSet representing the pairs from the map
|
||||
* @throws NullPointerException if the map is null
|
||||
*/
|
||||
public static MutableContextSet fromMap(Map<String, String> map) {
|
||||
MutableContextSet set = new MutableContextSet();
|
||||
set.addAll(map);
|
||||
return set;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a MutableContextSet from an existing iterable of Map Entries
|
||||
* @param iterable the iterable to copy from
|
||||
* @return a new MutableContextSet representing the pairs in the iterable
|
||||
* @throws NullPointerException if the iterable is null
|
||||
*/
|
||||
public static MutableContextSet fromEntries(Iterable<Map.Entry<String, String>> iterable) {
|
||||
MutableContextSet set = new MutableContextSet();
|
||||
set.addAll(iterable);
|
||||
return set;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new MutableContextSet from an existing set.
|
||||
* Only really useful for converting between mutable and immutable types.
|
||||
* @param contextSet the context set to copy from
|
||||
* @return a new MutableContextSet with the same content and the one provided
|
||||
* @throws NullPointerException if contextSet is null
|
||||
*/
|
||||
public static MutableContextSet fromSet(ContextSet contextSet) {
|
||||
MutableContextSet set = new MutableContextSet();
|
||||
set.addAll(contextSet.toSet());
|
||||
return set;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new empty MutableContextSet.
|
||||
* @return a new MutableContextSet
|
||||
*/
|
||||
public static MutableContextSet empty() {
|
||||
return new MutableContextSet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isImmutable() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ContextSet makeImmutable() {
|
||||
return immutableCopy();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an immutable copy of this set.
|
||||
* @return an immutable copy of this set
|
||||
*/
|
||||
public ContextSet immutableCopy() {
|
||||
synchronized (contexts) {
|
||||
return new ContextSet(new HashSet<>(contexts));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a new key value pair to the set
|
||||
* @param key the key to add
|
||||
* @param value the value to add
|
||||
* @throws NullPointerException if the key or value is null
|
||||
*/
|
||||
public void add(String key, String value) {
|
||||
if (key == null) {
|
||||
throw new NullPointerException("key");
|
||||
}
|
||||
if (value == null) {
|
||||
throw new NullPointerException("value");
|
||||
}
|
||||
|
||||
synchronized (contexts) {
|
||||
contexts.add(Maps.immutableEntry(key, value));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a new key value pair to the set
|
||||
* @param entry the entry to add
|
||||
* @throws NullPointerException if the entry is null
|
||||
*/
|
||||
public void add(Map.Entry<String, String> entry) {
|
||||
if (entry == null) {
|
||||
throw new NullPointerException("context");
|
||||
}
|
||||
|
||||
synchronized (contexts) {
|
||||
contexts.add(Maps.immutableEntry(entry.getKey(), entry.getValue()));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an iterable containing contexts to the set
|
||||
* @param iterable an iterable of key value context pairs
|
||||
* @throws NullPointerException if iterable is null
|
||||
*/
|
||||
public void addAll(Iterable<Map.Entry<String, String>> iterable) {
|
||||
if (iterable == null) {
|
||||
throw new NullPointerException("contexts");
|
||||
}
|
||||
|
||||
synchronized (this.contexts) {
|
||||
for (Map.Entry<String, String> e : iterable) {
|
||||
this.contexts.add(Maps.immutableEntry(e.getKey(), e.getValue()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the entry set of a map to the set
|
||||
* @param map the map to add from
|
||||
* @throws NullPointerException if the map is null
|
||||
*/
|
||||
public void addAll(Map<String, String> map) {
|
||||
if (map == null) {
|
||||
throw new NullPointerException("contexts");
|
||||
}
|
||||
addAll(map.entrySet());
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds of of the values in another ContextSet to this set
|
||||
* @param contextSet the set to add from
|
||||
* @throws NullPointerException if the contextSet is null
|
||||
*/
|
||||
public void addAll(ContextSet contextSet) {
|
||||
if (contextSet == null) {
|
||||
throw new NullPointerException("contextSet");
|
||||
}
|
||||
|
||||
synchronized (this.contexts) {
|
||||
this.contexts.addAll(contextSet.toSet());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a key value pair from this set
|
||||
* @param key the key to remove
|
||||
* @param value the value to remove (case sensitive)
|
||||
* @throws NullPointerException if the key or value is null
|
||||
*/
|
||||
public void remove(String key, String value) {
|
||||
if (key == null) {
|
||||
throw new NullPointerException("key");
|
||||
}
|
||||
if (value == null) {
|
||||
throw new NullPointerException("value");
|
||||
}
|
||||
|
||||
synchronized (contexts) {
|
||||
contexts.removeIf(e -> e.getKey().equalsIgnoreCase(key) && e.getValue().equals(value));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Same as {@link #remove(String, String)}, except ignores the case of the value
|
||||
* @param key the key to remove
|
||||
* @param value the value to remove
|
||||
* @throws NullPointerException if the key or value is null
|
||||
*/
|
||||
public void removeIgnoreCase(String key, String value) {
|
||||
if (key == null) {
|
||||
throw new NullPointerException("key");
|
||||
}
|
||||
if (value == null) {
|
||||
throw new NullPointerException("value");
|
||||
}
|
||||
|
||||
synchronized (contexts) {
|
||||
contexts.removeIf(e -> e.getKey().equalsIgnoreCase(key) && e.getValue().equalsIgnoreCase(value));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all pairs with the given key
|
||||
* @param key the key to remove
|
||||
* @throws NullPointerException if the key is null
|
||||
*/
|
||||
public void removeAll(String key) {
|
||||
if (key == null) {
|
||||
throw new NullPointerException("key");
|
||||
}
|
||||
|
||||
synchronized (contexts) {
|
||||
contexts.removeIf(e -> e.getKey().equalsIgnoreCase(key));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears the set
|
||||
*/
|
||||
public void clear() {
|
||||
synchronized (contexts) {
|
||||
contexts.clear();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (o == this) return true;
|
||||
if (!(o instanceof ContextSet)) return false;
|
||||
final ContextSet other = (ContextSet) o;
|
||||
|
||||
final Object thisContexts = this.contexts;
|
||||
final Object otherContexts = other.contexts;
|
||||
return thisContexts == null ? otherContexts == null : thisContexts.equals(otherContexts);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return 59 + (this.contexts == null ? 43 : this.contexts.hashCode());
|
||||
}
|
||||
|
||||
}
|
@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<artifactId>luckperms</artifactId>
|
||||
<groupId>me.lucko.luckperms</groupId>
|
||||
<version>2.12-SNAPSHOT</version>
|
||||
<version>2.13-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<artifactId>luckperms</artifactId>
|
||||
<groupId>me.lucko.luckperms</groupId>
|
||||
<version>2.12-SNAPSHOT</version>
|
||||
<version>2.13-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<artifactId>luckperms</artifactId>
|
||||
<groupId>me.lucko.luckperms</groupId>
|
||||
<version>2.12-SNAPSHOT</version>
|
||||
<version>2.13-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
@ -28,6 +28,8 @@ import me.lucko.luckperms.api.Contexts;
|
||||
import me.lucko.luckperms.api.Logger;
|
||||
import me.lucko.luckperms.api.LuckPermsApi;
|
||||
import me.lucko.luckperms.api.PlatformType;
|
||||
import me.lucko.luckperms.api.context.ContextSet;
|
||||
import me.lucko.luckperms.api.context.MutableContextSet;
|
||||
import me.lucko.luckperms.bukkit.calculators.AutoOPListener;
|
||||
import me.lucko.luckperms.bukkit.calculators.DefaultsProvider;
|
||||
import me.lucko.luckperms.bukkit.vault.VaultHook;
|
||||
@ -274,32 +276,32 @@ public class LPBukkitPlugin extends JavaPlugin implements LuckPermsPlugin {
|
||||
|
||||
@Override
|
||||
public Set<Contexts> getPreProcessContexts(boolean op) {
|
||||
Set<Map<String, String>> c = new HashSet<>();
|
||||
c.add(Collections.emptyMap());
|
||||
c.add(Collections.singletonMap("server", getConfiguration().getServer()));
|
||||
Set<ContextSet> c = new HashSet<>();
|
||||
c.add(ContextSet.empty());
|
||||
c.add(ContextSet.singleton("server", getConfiguration().getServer()));
|
||||
|
||||
// Pre process all worlds
|
||||
c.addAll(getServer().getWorlds().stream()
|
||||
.map(World::getName)
|
||||
.map(s -> {
|
||||
Map<String, String> map = new HashMap<>();
|
||||
map.put("server", getConfiguration().getServer());
|
||||
map.put("world", s);
|
||||
return map;
|
||||
MutableContextSet set = new MutableContextSet();
|
||||
set.add("server", getConfiguration().getServer());
|
||||
set.add("world", s);
|
||||
return set.makeImmutable();
|
||||
})
|
||||
.collect(Collectors.toList())
|
||||
);
|
||||
|
||||
// Pre process the separate Vault server, if any
|
||||
if (!getConfiguration().getServer().equals(getConfiguration().getVaultServer())) {
|
||||
c.add(Collections.singletonMap("server", getConfiguration().getVaultServer()));
|
||||
c.add(ContextSet.singleton("server", getConfiguration().getVaultServer()));
|
||||
c.addAll(getServer().getWorlds().stream()
|
||||
.map(World::getName)
|
||||
.map(s -> {
|
||||
Map<String, String> map = new HashMap<>();
|
||||
map.put("server", getConfiguration().getVaultServer());
|
||||
map.put("world", s);
|
||||
return map;
|
||||
MutableContextSet set = new MutableContextSet();
|
||||
set.add("server", getConfiguration().getVaultServer());
|
||||
set.add("world", s);
|
||||
return set.makeImmutable();
|
||||
})
|
||||
.collect(Collectors.toList())
|
||||
);
|
||||
@ -309,8 +311,8 @@ public class LPBukkitPlugin extends JavaPlugin implements LuckPermsPlugin {
|
||||
|
||||
// Convert to full Contexts
|
||||
contexts.addAll(c.stream()
|
||||
.map(map -> new Contexts(
|
||||
map,
|
||||
.map(set -> new Contexts(
|
||||
set,
|
||||
getConfiguration().isIncludingGlobalPerms(),
|
||||
getConfiguration().isIncludingGlobalWorldPerms(),
|
||||
true,
|
||||
|
@ -26,6 +26,7 @@ import com.google.common.collect.Maps;
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import me.lucko.luckperms.api.context.ContextCalculator;
|
||||
import me.lucko.luckperms.api.context.MutableContextSet;
|
||||
import me.lucko.luckperms.common.LuckPermsPlugin;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
@ -48,11 +49,11 @@ public class WorldCalculator extends ContextCalculator<Player> implements Listen
|
||||
private final Map<UUID, String> worldCache = new ConcurrentHashMap<>();
|
||||
|
||||
@Override
|
||||
public Map<String, String> giveApplicableContext(Player subject, Map<String, String> accumulator) {
|
||||
public MutableContextSet giveApplicableContext(Player subject, MutableContextSet accumulator) {
|
||||
String world = getWorld(subject);
|
||||
|
||||
if (world != null) {
|
||||
accumulator.put(WORLD_KEY, world);
|
||||
accumulator.add(Maps.immutableEntry(WORLD_KEY, world));
|
||||
}
|
||||
|
||||
return accumulator;
|
||||
|
@ -26,6 +26,7 @@ import lombok.Getter;
|
||||
import lombok.NonNull;
|
||||
import me.lucko.luckperms.api.Contexts;
|
||||
import me.lucko.luckperms.api.Tristate;
|
||||
import me.lucko.luckperms.api.context.MutableContextSet;
|
||||
import me.lucko.luckperms.bukkit.LPBukkitPlugin;
|
||||
import me.lucko.luckperms.common.users.User;
|
||||
import org.bukkit.Bukkit;
|
||||
@ -66,7 +67,7 @@ public class LPPermissible extends PermissibleBase {
|
||||
|
||||
public Contexts calculateContexts() {
|
||||
return new Contexts(
|
||||
plugin.getContextManager().giveApplicableContext(parent, new HashMap<>()),
|
||||
plugin.getContextManager().giveApplicableContext(parent, new MutableContextSet()),
|
||||
plugin.getConfiguration().isIncludingGlobalPerms(),
|
||||
plugin.getConfiguration().isIncludingGlobalWorldPerms(),
|
||||
true,
|
||||
|
@ -25,7 +25,8 @@ package me.lucko.luckperms.bukkit.vault;
|
||||
import lombok.NonNull;
|
||||
import me.lucko.luckperms.api.Contexts;
|
||||
import me.lucko.luckperms.api.Node;
|
||||
import me.lucko.luckperms.common.caching.MetaData;
|
||||
import me.lucko.luckperms.api.caching.MetaData;
|
||||
import me.lucko.luckperms.api.context.ContextSet;
|
||||
import me.lucko.luckperms.common.core.PermissionHolder;
|
||||
import me.lucko.luckperms.common.groups.Group;
|
||||
import me.lucko.luckperms.common.users.User;
|
||||
@ -214,7 +215,7 @@ public class VaultChatHook extends Chat {
|
||||
context.put("world", world);
|
||||
}
|
||||
|
||||
for (Node n : group.getAllNodes(null, new Contexts(context, perms.isIncludeGlobal(), true, true, true, true))) {
|
||||
for (Node n : group.getAllNodes(null, new Contexts(ContextSet.fromMap(context), perms.isIncludeGlobal(), true, true, true, true, false))) {
|
||||
if (!n.getValue()) {
|
||||
continue;
|
||||
}
|
||||
|
@ -27,6 +27,7 @@ import lombok.NonNull;
|
||||
import lombok.Setter;
|
||||
import me.lucko.luckperms.api.Contexts;
|
||||
import me.lucko.luckperms.api.Node;
|
||||
import me.lucko.luckperms.api.context.ContextSet;
|
||||
import me.lucko.luckperms.bukkit.LPBukkitPlugin;
|
||||
import me.lucko.luckperms.common.core.PermissionHolder;
|
||||
import me.lucko.luckperms.common.groups.Group;
|
||||
@ -146,7 +147,7 @@ public class VaultPermissionHook extends Permission {
|
||||
context.put("world", world);
|
||||
}
|
||||
context.put("server", server);
|
||||
return new Contexts(context, isIncludeGlobal(), true, true, true, true);
|
||||
return new Contexts(ContextSet.fromMap(context), isIncludeGlobal(), true, true, true, true, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<artifactId>luckperms</artifactId>
|
||||
<groupId>me.lucko.luckperms</groupId>
|
||||
<version>2.12-SNAPSHOT</version>
|
||||
<version>2.13-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
@ -24,6 +24,7 @@ package me.lucko.luckperms.bungee;
|
||||
|
||||
import com.google.common.collect.Maps;
|
||||
import me.lucko.luckperms.api.context.ContextCalculator;
|
||||
import me.lucko.luckperms.api.context.MutableContextSet;
|
||||
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
||||
import net.md_5.bungee.api.event.ServerSwitchEvent;
|
||||
import net.md_5.bungee.api.plugin.Listener;
|
||||
@ -35,11 +36,11 @@ public class BackendServerCalculator extends ContextCalculator<ProxiedPlayer> im
|
||||
private static final String WORLD_KEY = "world";
|
||||
|
||||
@Override
|
||||
public Map<String, String> giveApplicableContext(ProxiedPlayer subject, Map<String, String> accumulator) {
|
||||
public MutableContextSet giveApplicableContext(ProxiedPlayer subject, MutableContextSet accumulator) {
|
||||
String server = getServer(subject);
|
||||
|
||||
if (server != null) {
|
||||
accumulator.put(WORLD_KEY, server);
|
||||
accumulator.add(Maps.immutableEntry(WORLD_KEY, server));
|
||||
}
|
||||
|
||||
return accumulator;
|
||||
|
@ -23,6 +23,7 @@
|
||||
package me.lucko.luckperms.bungee;
|
||||
|
||||
import me.lucko.luckperms.api.Contexts;
|
||||
import me.lucko.luckperms.api.context.MutableContextSet;
|
||||
import me.lucko.luckperms.api.event.events.UserFirstLoginEvent;
|
||||
import me.lucko.luckperms.common.constants.Message;
|
||||
import me.lucko.luckperms.common.core.UuidCache;
|
||||
@ -38,7 +39,6 @@ import net.md_5.bungee.api.event.PostLoginEvent;
|
||||
import net.md_5.bungee.api.plugin.Listener;
|
||||
import net.md_5.bungee.event.EventHandler;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
@ -72,12 +72,13 @@ public class BungeeListener extends AbstractListener implements Listener {
|
||||
}
|
||||
|
||||
Contexts contexts = new Contexts(
|
||||
plugin.getContextManager().giveApplicableContext(player, new HashMap<>()),
|
||||
plugin.getContextManager().giveApplicableContext(player, MutableContextSet.empty()),
|
||||
plugin.getConfiguration().isIncludingGlobalPerms(),
|
||||
plugin.getConfiguration().isIncludingGlobalWorldPerms(),
|
||||
true,
|
||||
plugin.getConfiguration().isApplyingGlobalGroups(),
|
||||
plugin.getConfiguration().isApplyingGlobalWorldGroups()
|
||||
plugin.getConfiguration().isApplyingGlobalWorldGroups(),
|
||||
false
|
||||
);
|
||||
|
||||
e.setHasPermission(user.getUserData().getPermissionData(contexts).getPermissionValue(e.getPermission()).asBoolean());
|
||||
|
@ -27,6 +27,8 @@ import me.lucko.luckperms.ApiHandler;
|
||||
import me.lucko.luckperms.api.Contexts;
|
||||
import me.lucko.luckperms.api.Logger;
|
||||
import me.lucko.luckperms.api.PlatformType;
|
||||
import me.lucko.luckperms.api.context.ContextSet;
|
||||
import me.lucko.luckperms.api.context.MutableContextSet;
|
||||
import me.lucko.luckperms.common.LuckPermsPlugin;
|
||||
import me.lucko.luckperms.common.api.ApiProvider;
|
||||
import me.lucko.luckperms.common.calculators.CalculatorFactory;
|
||||
@ -212,28 +214,29 @@ public class LPBungeePlugin extends Plugin implements LuckPermsPlugin {
|
||||
|
||||
@Override
|
||||
public Set<Contexts> getPreProcessContexts(boolean op) {
|
||||
Set<Map<String, String>> c = new HashSet<>();
|
||||
c.add(Collections.emptyMap());
|
||||
c.add(Collections.singletonMap("server", getConfiguration().getServer()));
|
||||
Set<ContextSet> c = new HashSet<>();
|
||||
c.add(ContextSet.empty());
|
||||
c.add(ContextSet.singleton("server", getConfiguration().getServer()));
|
||||
c.addAll(getProxy().getServers().values().stream()
|
||||
.map(ServerInfo::getName)
|
||||
.map(s -> {
|
||||
Map<String, String> map = new HashMap<>();
|
||||
map.put("server", getConfiguration().getServer());
|
||||
map.put("world", s);
|
||||
return map;
|
||||
MutableContextSet set = new MutableContextSet();
|
||||
set.add("server", getConfiguration().getServer());
|
||||
set.add("world", s);
|
||||
return set.makeImmutable();
|
||||
})
|
||||
.collect(Collectors.toList())
|
||||
);
|
||||
|
||||
return c.stream()
|
||||
.map(map -> new Contexts(
|
||||
map,
|
||||
.map(set -> new Contexts(
|
||||
set,
|
||||
getConfiguration().isIncludingGlobalPerms(),
|
||||
getConfiguration().isIncludingGlobalWorldPerms(),
|
||||
true,
|
||||
getConfiguration().isApplyingGlobalGroups(),
|
||||
getConfiguration().isApplyingGlobalWorldGroups()
|
||||
getConfiguration().isApplyingGlobalWorldGroups(),
|
||||
false
|
||||
))
|
||||
.collect(Collectors.toSet());
|
||||
}
|
||||
|
@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<artifactId>luckperms</artifactId>
|
||||
<groupId>me.lucko.luckperms</groupId>
|
||||
<version>2.12-SNAPSHOT</version>
|
||||
<version>2.13-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
@ -69,7 +69,7 @@ public class ApiProvider implements LuckPermsApi {
|
||||
|
||||
@Override
|
||||
public double getApiVersion() {
|
||||
return 2.12;
|
||||
return 2.13;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -25,6 +25,7 @@ package me.lucko.luckperms.common.api.internal;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.NonNull;
|
||||
import me.lucko.luckperms.api.*;
|
||||
import me.lucko.luckperms.api.context.ContextSet;
|
||||
import me.lucko.luckperms.exceptions.ObjectAlreadyHasException;
|
||||
import me.lucko.luckperms.exceptions.ObjectLacksException;
|
||||
|
||||
@ -247,7 +248,7 @@ public class PermissionHolderLink implements PermissionHolder {
|
||||
if (world != null && !world.equals("")) {
|
||||
context.put("world", world);
|
||||
}
|
||||
return master.exportNodes(new Contexts(context, true, true, true, true, true), false);
|
||||
return master.exportNodes(new Contexts(ContextSet.fromMap(context), true, true, true, true, true, false), false);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -259,7 +260,7 @@ public class PermissionHolderLink implements PermissionHolder {
|
||||
if (world != null && !world.equals("")) {
|
||||
context.put("world", world);
|
||||
}
|
||||
return master.exportNodes(new Contexts(context, true, true, true, true, true), false);
|
||||
return master.exportNodes(new Contexts(ContextSet.fromMap(context), true, true, true, true, true, false), false);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -283,7 +284,7 @@ public class PermissionHolderLink implements PermissionHolder {
|
||||
if (world != null && !world.equals("")) {
|
||||
extraContext.put("world", world);
|
||||
}
|
||||
return master.exportNodes(new Contexts(extraContext, includeGlobal, includeGlobal, applyGroups, true, true), false);
|
||||
return master.exportNodes(new Contexts(ContextSet.fromMap(extraContext), includeGlobal, includeGlobal, applyGroups, true, true, false), false);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -27,10 +27,12 @@ import lombok.Getter;
|
||||
import lombok.NonNull;
|
||||
import me.lucko.luckperms.api.Group;
|
||||
import me.lucko.luckperms.api.User;
|
||||
import me.lucko.luckperms.api.caching.UserData;
|
||||
import me.lucko.luckperms.exceptions.ObjectAlreadyHasException;
|
||||
import me.lucko.luckperms.exceptions.ObjectLacksException;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
|
||||
import static me.lucko.luckperms.common.api.internal.Utils.*;
|
||||
@ -82,6 +84,11 @@ public class UserLink extends PermissionHolderLink implements User {
|
||||
master.getRefreshBuffer().requestDirectly();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<UserData> getUserDataCache() {
|
||||
return Optional.ofNullable(master.getUserData());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInGroup(@NonNull Group group) {
|
||||
checkGroup(group);
|
||||
|
@ -28,6 +28,8 @@ import lombok.RequiredArgsConstructor;
|
||||
import me.lucko.luckperms.api.Contexts;
|
||||
import me.lucko.luckperms.api.LocalizedNode;
|
||||
import me.lucko.luckperms.api.Node;
|
||||
import me.lucko.luckperms.api.caching.MetaData;
|
||||
import me.lucko.luckperms.api.context.MutableContextSet;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
@ -35,7 +37,7 @@ import java.util.*;
|
||||
* Holds a user's cached meta for a given context
|
||||
*/
|
||||
@RequiredArgsConstructor
|
||||
public class MetaData {
|
||||
public class MetaCache implements MetaData {
|
||||
private final Contexts contexts;
|
||||
|
||||
private final SortedMap<Integer, String> prefixes = new TreeMap<>(Comparator.reverseOrder());
|
||||
@ -46,9 +48,11 @@ public class MetaData {
|
||||
public void loadMeta(SortedSet<LocalizedNode> nodes) {
|
||||
invalidateCache();
|
||||
|
||||
Map<String, String> contexts = new HashMap<>(this.contexts.getContext());
|
||||
String server = contexts.remove("server");
|
||||
String world = contexts.remove("world");
|
||||
MutableContextSet contexts = MutableContextSet.fromSet(this.contexts.getContexts());
|
||||
String server = contexts.getValues("server").stream().findAny().orElse(null);
|
||||
String world = contexts.getValues("world").stream().findAny().orElse(null);
|
||||
contexts.removeAll("server");
|
||||
contexts.removeAll("world");
|
||||
|
||||
for (LocalizedNode ln : nodes) {
|
||||
Node n = ln.getNode();
|
||||
@ -105,7 +109,7 @@ public class MetaData {
|
||||
}
|
||||
}
|
||||
|
||||
public void invalidateCache() {
|
||||
private void invalidateCache() {
|
||||
synchronized (meta) {
|
||||
meta.clear();
|
||||
}
|
||||
@ -117,24 +121,28 @@ public class MetaData {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, String> getMeta() {
|
||||
synchronized (meta) {
|
||||
return ImmutableMap.copyOf(meta);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public SortedMap<Integer, String> getPrefixes() {
|
||||
synchronized (prefixes) {
|
||||
return ImmutableSortedMap.copyOfSorted(prefixes);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public SortedMap<Integer, String> getSuffixes() {
|
||||
synchronized (suffixes) {
|
||||
return ImmutableSortedMap.copyOfSorted(suffixes);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPrefix() {
|
||||
synchronized (prefixes) {
|
||||
if (prefixes.isEmpty()) {
|
||||
@ -145,6 +153,7 @@ public class MetaData {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSuffix() {
|
||||
synchronized (suffixes) {
|
||||
if (suffixes.isEmpty()) {
|
@ -26,6 +26,7 @@ import com.google.common.collect.ImmutableMap;
|
||||
import lombok.NonNull;
|
||||
import me.lucko.luckperms.api.Contexts;
|
||||
import me.lucko.luckperms.api.Tristate;
|
||||
import me.lucko.luckperms.api.caching.PermissionData;
|
||||
import me.lucko.luckperms.common.calculators.CalculatorFactory;
|
||||
import me.lucko.luckperms.common.calculators.PermissionCalculator;
|
||||
import me.lucko.luckperms.common.users.User;
|
||||
@ -36,7 +37,7 @@ import java.util.concurrent.ConcurrentHashMap;
|
||||
/**
|
||||
* Holds a user's cached permissions for a given context
|
||||
*/
|
||||
public class PermissionData {
|
||||
public class PermissionCache implements PermissionData {
|
||||
|
||||
/**
|
||||
* The raw set of permission strings.
|
||||
@ -50,11 +51,12 @@ public class PermissionData {
|
||||
*/
|
||||
private final PermissionCalculator calculator;
|
||||
|
||||
public PermissionData(Contexts contexts, User user, CalculatorFactory calculatorFactory) {
|
||||
public PermissionCache(Contexts contexts, User user, CalculatorFactory calculatorFactory) {
|
||||
permissions = new ConcurrentHashMap<>();
|
||||
calculator = calculatorFactory.build(contexts, user, permissions);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invalidateCache() {
|
||||
calculator.invalidateCache();
|
||||
}
|
||||
@ -71,10 +73,12 @@ public class PermissionData {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Boolean> getImmutableBacking() {
|
||||
return ImmutableMap.copyOf(permissions);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Tristate getPermissionValue(@NonNull String permission) {
|
||||
return calculator.getPermissionValue(permission);
|
||||
}
|
@ -28,8 +28,12 @@ import com.google.common.cache.LoadingCache;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.util.concurrent.Futures;
|
||||
import com.google.common.util.concurrent.ListenableFuture;
|
||||
import lombok.NonNull;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import me.lucko.luckperms.api.Contexts;
|
||||
import me.lucko.luckperms.api.caching.MetaData;
|
||||
import me.lucko.luckperms.api.caching.PermissionData;
|
||||
import me.lucko.luckperms.api.caching.UserData;
|
||||
import me.lucko.luckperms.common.calculators.CalculatorFactory;
|
||||
import me.lucko.luckperms.common.users.User;
|
||||
|
||||
@ -39,7 +43,7 @@ import java.util.Set;
|
||||
* Holds an easily accessible cache of a user's data in a number of contexts
|
||||
*/
|
||||
@RequiredArgsConstructor
|
||||
public class UserData {
|
||||
public class UserCache implements UserData {
|
||||
|
||||
/**
|
||||
* The user whom this data instance is representing
|
||||
@ -51,124 +55,87 @@ public class UserData {
|
||||
*/
|
||||
private final CalculatorFactory calculatorFactory;
|
||||
|
||||
private final LoadingCache<Contexts, PermissionData> permission = CacheBuilder.newBuilder()
|
||||
.build(new CacheLoader<Contexts, PermissionData>() {
|
||||
private final LoadingCache<Contexts, PermissionCache> permission = CacheBuilder.newBuilder()
|
||||
.build(new CacheLoader<Contexts, PermissionCache>() {
|
||||
@Override
|
||||
public PermissionData load(Contexts contexts) {
|
||||
public PermissionCache load(Contexts contexts) {
|
||||
return calculatePermissions(contexts);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ListenableFuture<PermissionData> reload(Contexts contexts, PermissionData oldData) {
|
||||
public ListenableFuture<PermissionCache> reload(Contexts contexts, PermissionCache oldData) {
|
||||
oldData.comparePermissions(user.exportNodes(contexts, true));
|
||||
return Futures.immediateFuture(oldData);
|
||||
}
|
||||
});
|
||||
|
||||
private final LoadingCache<Contexts, MetaData> meta = CacheBuilder.newBuilder()
|
||||
.build(new CacheLoader<Contexts, MetaData>() {
|
||||
private final LoadingCache<Contexts, MetaCache> meta = CacheBuilder.newBuilder()
|
||||
.build(new CacheLoader<Contexts, MetaCache>() {
|
||||
@Override
|
||||
public MetaData load(Contexts contexts) {
|
||||
public MetaCache load(Contexts contexts) {
|
||||
return calculateMeta(contexts);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ListenableFuture<MetaData> reload(Contexts contexts, MetaData oldData) {
|
||||
public ListenableFuture<MetaCache> reload(Contexts contexts, MetaCache oldData) {
|
||||
oldData.loadMeta(user.getAllNodes(null, contexts));
|
||||
return Futures.immediateFuture(oldData);
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Gets PermissionData from the cache, given a specified context.
|
||||
* If the data is not cached, it is calculated. Therefore, this call could be costly.
|
||||
* @param contexts the contexts to get the permission data in
|
||||
* @return a permission data instance
|
||||
*/
|
||||
public PermissionData getPermissionData(Contexts contexts) {
|
||||
@Override
|
||||
public PermissionData getPermissionData(@NonNull Contexts contexts) {
|
||||
return permission.getUnchecked(contexts);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets MetaData from the cache, given a specified context.
|
||||
* If the data is not cached, it is calculated. Therefore, this call could be costly.
|
||||
* @param contexts the contexts to get the permission data in
|
||||
* @return a meta data instance
|
||||
*/
|
||||
public MetaData getMetaData(Contexts contexts) {
|
||||
@Override
|
||||
public MetaData getMetaData(@NonNull Contexts contexts) {
|
||||
return meta.getUnchecked(contexts);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates permission data, bypassing the cache.
|
||||
* @param contexts the contexts to get permission data in
|
||||
* @return a permission data instance
|
||||
*/
|
||||
public PermissionData calculatePermissions(Contexts contexts) {
|
||||
PermissionData data = new PermissionData(contexts, user, calculatorFactory);
|
||||
@Override
|
||||
public PermissionCache calculatePermissions(@NonNull Contexts contexts) {
|
||||
PermissionCache data = new PermissionCache(contexts, user, calculatorFactory);
|
||||
data.setPermissions(user.exportNodes(contexts, true));
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates meta data, bypassing the cache.
|
||||
* @param contexts the contexts to get meta data in
|
||||
* @return a meta data instance
|
||||
*/
|
||||
public MetaData calculateMeta(Contexts contexts) {
|
||||
MetaData data = new MetaData(contexts);
|
||||
@Override
|
||||
public MetaCache calculateMeta(@NonNull Contexts contexts) {
|
||||
MetaCache data = new MetaCache(contexts);
|
||||
data.loadMeta(user.getAllNodes(null, contexts));
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates permission data and stores it in the cache. If there is already data cached for the given contexts,
|
||||
* and if the resultant output is different, the cached value is updated.
|
||||
* @param contexts the contexts to recalculate in.
|
||||
*/
|
||||
public void recalculatePermissions(Contexts contexts) {
|
||||
@Override
|
||||
public void recalculatePermissions(@NonNull Contexts contexts) {
|
||||
permission.refresh(contexts);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates meta data and stores it in the cache. If there is already data cached for the given contexts,
|
||||
* and if the resultant output is different, the cached value is updated.
|
||||
* @param contexts the contexts to recalculate in.
|
||||
*/
|
||||
public void recalculateMeta(Contexts contexts) {
|
||||
@Override
|
||||
public void recalculateMeta(@NonNull Contexts contexts) {
|
||||
meta.refresh(contexts);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls {@link #recalculatePermissions(Contexts)} for all current loaded contexts
|
||||
*/
|
||||
@Override
|
||||
public void recalculatePermissions() {
|
||||
Set<Contexts> keys = ImmutableSet.copyOf(permission.asMap().keySet());
|
||||
keys.forEach(permission::refresh);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls {@link #recalculateMeta(Contexts)} for all current loaded contexts
|
||||
*/
|
||||
@Override
|
||||
public void recalculateMeta() {
|
||||
Set<Contexts> keys = ImmutableSet.copyOf(meta.asMap().keySet());
|
||||
keys.forEach(meta::refresh);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls {@link #preCalculate(Contexts)} for the given contexts
|
||||
* @param contexts a set of contexts
|
||||
*/
|
||||
public void preCalculate(Set<Contexts> contexts) {
|
||||
@Override
|
||||
public void preCalculate(@NonNull Set<Contexts> contexts) {
|
||||
contexts.forEach(this::preCalculate);
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures that PermissionData and MetaData is cached for a context. If the cache does not contain any data for the
|
||||
* context, it will be calculated and saved.
|
||||
* @param contexts the contexts to pre-calculate for
|
||||
*/
|
||||
public void preCalculate(Contexts contexts) {
|
||||
@Override
|
||||
public void preCalculate(@NonNull Contexts contexts) {
|
||||
permission.getUnchecked(contexts);
|
||||
meta.getUnchecked(contexts);
|
||||
}
|
||||
@ -178,6 +145,7 @@ public class UserData {
|
||||
meta.invalidateAll();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invalidatePermissionCalculators() {
|
||||
permission.asMap().values().forEach(PermissionData::invalidateCache);
|
||||
}
|
@ -24,6 +24,7 @@ package me.lucko.luckperms.common.contexts;
|
||||
|
||||
import me.lucko.luckperms.api.context.ContextListener;
|
||||
import me.lucko.luckperms.api.context.IContextCalculator;
|
||||
import me.lucko.luckperms.api.context.MutableContextSet;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@ -47,7 +48,7 @@ public class ContextManager<T> {
|
||||
listeners.add(listener);
|
||||
}
|
||||
|
||||
public Map<String, String> giveApplicableContext(T subject, Map<String, String> accumulator) {
|
||||
public MutableContextSet giveApplicableContext(T subject, MutableContextSet accumulator) {
|
||||
for (IContextCalculator<T> calculator : calculators) {
|
||||
calculator.giveApplicableContext(subject, accumulator);
|
||||
}
|
||||
|
@ -22,8 +22,10 @@
|
||||
|
||||
package me.lucko.luckperms.common.contexts;
|
||||
|
||||
import com.google.common.collect.Maps;
|
||||
import lombok.AllArgsConstructor;
|
||||
import me.lucko.luckperms.api.context.ContextCalculator;
|
||||
import me.lucko.luckperms.api.context.MutableContextSet;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
@ -32,8 +34,8 @@ public class ServerCalculator<T> extends ContextCalculator<T> {
|
||||
private final String server;
|
||||
|
||||
@Override
|
||||
public Map<String, String> giveApplicableContext(T subject, Map<String, String> accumulator) {
|
||||
accumulator.put("server", server);
|
||||
public MutableContextSet giveApplicableContext(T subject, MutableContextSet accumulator) {
|
||||
accumulator.add(Maps.immutableEntry("server", server));
|
||||
return accumulator;
|
||||
}
|
||||
|
||||
|
@ -23,9 +23,10 @@
|
||||
package me.lucko.luckperms.common.core;
|
||||
|
||||
import com.google.common.base.Splitter;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import lombok.*;
|
||||
import me.lucko.luckperms.api.Tristate;
|
||||
import me.lucko.luckperms.api.context.ContextSet;
|
||||
import me.lucko.luckperms.api.context.MutableContextSet;
|
||||
import me.lucko.luckperms.common.constants.Patterns;
|
||||
import me.lucko.luckperms.common.utils.ArgumentChecker;
|
||||
|
||||
@ -60,7 +61,8 @@ public class Node implements me.lucko.luckperms.api.Node {
|
||||
|
||||
private long expireAt = 0L;
|
||||
|
||||
private final Map<String, String> extraContexts;
|
||||
@Getter
|
||||
private final ContextSet contexts;
|
||||
|
||||
// Cache the state
|
||||
private Tristate isPrefix = Tristate.UNDEFINED;
|
||||
@ -74,9 +76,9 @@ public class Node implements me.lucko.luckperms.api.Node {
|
||||
* @param expireAt the time when the node will expire
|
||||
* @param server the server this node applies on
|
||||
* @param world the world this node applies on
|
||||
* @param extraContexts any additional contexts applying to this node
|
||||
* @param contexts any additional contexts applying to this node
|
||||
*/
|
||||
public Node(String permission, boolean value, boolean override, long expireAt, String server, String world, Map<String, String> extraContexts) {
|
||||
public Node(String permission, boolean value, boolean override, long expireAt, String server, String world, ContextSet contexts) {
|
||||
if (permission == null || permission.equals("")) {
|
||||
throw new IllegalArgumentException("Empty permission");
|
||||
}
|
||||
@ -99,12 +101,7 @@ public class Node implements me.lucko.luckperms.api.Node {
|
||||
this.expireAt = expireAt;
|
||||
this.server = server;
|
||||
this.world = world;
|
||||
|
||||
ImmutableMap.Builder<String, String> contexts = ImmutableMap.builder();
|
||||
if (extraContexts != null) {
|
||||
contexts.putAll(extraContexts);
|
||||
}
|
||||
this.extraContexts = contexts.build();
|
||||
this.contexts = contexts == null ? ContextSet.empty() : contexts.makeImmutable();
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -176,11 +173,6 @@ public class Node implements me.lucko.luckperms.api.Node {
|
||||
return isTemporary() && expireAt < (System.currentTimeMillis() / 1000L);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, String> getExtraContexts() {
|
||||
return ImmutableMap.copyOf(extraContexts);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isGroupNode() {
|
||||
return getPermission().toLowerCase().startsWith("group.");
|
||||
@ -316,31 +308,28 @@ public class Node implements me.lucko.luckperms.api.Node {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldApplyWithContext(Map<String, String> context, boolean worldAndServer) {
|
||||
if (extraContexts.isEmpty() && !isServerSpecific() && !isWorldSpecific()) {
|
||||
public boolean shouldApplyWithContext(ContextSet context, boolean worldAndServer) {
|
||||
if (contexts.isEmpty() && !isServerSpecific() && !isWorldSpecific()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (worldAndServer) {
|
||||
if (isWorldSpecific()) {
|
||||
if (context == null) return false;
|
||||
if (!context.containsKey("world")) return false;
|
||||
if (!context.get("world").equalsIgnoreCase(world)) return false;
|
||||
if (!context.hasIgnoreCase("world", world)) return false;
|
||||
}
|
||||
|
||||
if (isServerSpecific()) {
|
||||
if (context == null) return false;
|
||||
if (!context.containsKey("server")) return false;
|
||||
if (!context.get("server").equalsIgnoreCase(server)) return false;
|
||||
if (!context.hasIgnoreCase("server", server)) return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!extraContexts.isEmpty()) {
|
||||
if (!contexts.isEmpty()) {
|
||||
if (context == null) return false;
|
||||
|
||||
for (Map.Entry<String, String> c : extraContexts.entrySet()) {
|
||||
if (!context.containsKey(c.getKey())) return false;
|
||||
if (!context.get(c.getKey()).equalsIgnoreCase(c.getValue())) return false;
|
||||
for (Map.Entry<String, String> c : contexts.toSet()) {
|
||||
if (!context.hasIgnoreCase(c.getKey(), c.getValue())) return false;
|
||||
}
|
||||
}
|
||||
|
||||
@ -348,7 +337,7 @@ public class Node implements me.lucko.luckperms.api.Node {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldApplyWithContext(Map<String, String> context) {
|
||||
public boolean shouldApplyWithContext(ContextSet context) {
|
||||
return shouldApplyWithContext(context, true);
|
||||
}
|
||||
|
||||
@ -478,9 +467,9 @@ public class Node implements me.lucko.luckperms.api.Node {
|
||||
}
|
||||
}
|
||||
|
||||
if (!extraContexts.isEmpty()) {
|
||||
if (!contexts.isEmpty()) {
|
||||
builder.append("(");
|
||||
for (Map.Entry<String, String> entry : extraContexts.entrySet()) {
|
||||
for (Map.Entry<String, String> entry : contexts.toSet()) {
|
||||
builder.append(entry.getKey()).append("=").append(entry.getValue()).append(",");
|
||||
}
|
||||
|
||||
@ -533,7 +522,7 @@ public class Node implements me.lucko.luckperms.api.Node {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!other.getExtraContexts().equals(this.getExtraContexts())) {
|
||||
if (!other.getContexts().equals(this.getContexts())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -570,7 +559,7 @@ public class Node implements me.lucko.luckperms.api.Node {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!other.getExtraContexts().equals(this.getExtraContexts())) {
|
||||
if (!other.getContexts().equals(this.getContexts())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -603,7 +592,7 @@ public class Node implements me.lucko.luckperms.api.Node {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!other.getExtraContexts().equals(this.getExtraContexts())) {
|
||||
if (!other.getContexts().equals(this.getContexts())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -681,8 +670,7 @@ public class Node implements me.lucko.luckperms.api.Node {
|
||||
private String server = null;
|
||||
private String world = null;
|
||||
private long expireAt = 0L;
|
||||
|
||||
private final Map<String, String> extraContexts = new HashMap<>();
|
||||
private final MutableContextSet extraContexts = new MutableContextSet();
|
||||
|
||||
Builder(String permission, boolean shouldConvertContexts) {
|
||||
if (!shouldConvertContexts) {
|
||||
@ -696,7 +684,7 @@ public class Node implements me.lucko.luckperms.api.Node {
|
||||
|
||||
this.permission = contextParts.get(1);
|
||||
try {
|
||||
extraContexts.putAll(Splitter.on(',').withKeyValueSeparator('=').split(contextParts.get(0)));
|
||||
extraContexts.addAll(Splitter.on(',').withKeyValueSeparator('=').split(contextParts.get(0)));
|
||||
} catch (IllegalArgumentException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
@ -711,6 +699,7 @@ public class Node implements me.lucko.luckperms.api.Node {
|
||||
this.server = other.getServer().orElse(null);
|
||||
this.world = other.getWorld().orElse(null);
|
||||
this.expireAt = other.isPermanent() ? 0L : other.getExpiryUnixTime();
|
||||
this.extraContexts.addAll(other.getContexts());
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -760,7 +749,7 @@ public class Node implements me.lucko.luckperms.api.Node {
|
||||
|
||||
@Override
|
||||
public me.lucko.luckperms.api.Node.Builder withExtraContext(@NonNull String key, @NonNull String value) {
|
||||
switch (key) {
|
||||
switch (key.toLowerCase()) {
|
||||
case "server":
|
||||
setServer(value);
|
||||
break;
|
||||
@ -768,25 +757,37 @@ public class Node implements me.lucko.luckperms.api.Node {
|
||||
setWorld(value);
|
||||
break;
|
||||
default:
|
||||
this.extraContexts.put(key, value);
|
||||
this.extraContexts.add(key, value);
|
||||
break;
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public me.lucko.luckperms.api.Node.Builder withExtraContext(Map<String, String> map) {
|
||||
map.entrySet().forEach(this::withExtraContext);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public me.lucko.luckperms.api.Node.Builder withExtraContext(Map.Entry<String, String> entry) {
|
||||
withExtraContext(entry.getKey(), entry.getValue());
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public me.lucko.luckperms.api.Node.Builder withExtraContext(Map<String, String> map) {
|
||||
withExtraContext(ContextSet.fromMap(map));
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public me.lucko.luckperms.api.Node.Builder withExtraContext(Set<Map.Entry<String, String>> context) {
|
||||
withExtraContext(ContextSet.fromEntries(context));
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public me.lucko.luckperms.api.Node.Builder withExtraContext(ContextSet set) {
|
||||
set.toSet().forEach(this::withExtraContext);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public me.lucko.luckperms.api.Node build() {
|
||||
return new Node(permission, value, override, expireAt, server, world, extraContexts);
|
||||
|
@ -32,6 +32,7 @@ import me.lucko.luckperms.api.Contexts;
|
||||
import me.lucko.luckperms.api.LocalizedNode;
|
||||
import me.lucko.luckperms.api.Node;
|
||||
import me.lucko.luckperms.api.Tristate;
|
||||
import me.lucko.luckperms.api.context.MutableContextSet;
|
||||
import me.lucko.luckperms.api.event.events.*;
|
||||
import me.lucko.luckperms.common.LuckPermsPlugin;
|
||||
import me.lucko.luckperms.common.api.internal.GroupLink;
|
||||
@ -368,11 +369,11 @@ public abstract class PermissionHolder {
|
||||
.filter(Node::isGroupNode)
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
Map<String, String> contexts = new HashMap<>(context.getContext());
|
||||
String server = contexts.get("server");
|
||||
String world = contexts.get("world");
|
||||
contexts.remove("server");
|
||||
contexts.remove("world");
|
||||
MutableContextSet contexts = MutableContextSet.fromSet(context.getContexts());
|
||||
String server = contexts.getValues("server").stream().findAny().orElse(null);
|
||||
String world = contexts.getValues("world").stream().findAny().orElse(null);
|
||||
contexts.removeAll("server");
|
||||
contexts.removeAll("world");
|
||||
|
||||
parents.removeIf(node ->
|
||||
!node.shouldApplyOnServer(server, context.isApplyGlobalGroups(), plugin.getConfiguration().isApplyingRegex()) ||
|
||||
@ -419,11 +420,11 @@ public abstract class PermissionHolder {
|
||||
allNodes = new TreeSet<>((SortedSet<LocalizedNode>) getPermissions(true));
|
||||
}
|
||||
|
||||
Map<String, String> contexts = new HashMap<>(context.getContext());
|
||||
String server = contexts.get("server");
|
||||
String world = contexts.get("world");
|
||||
contexts.remove("server");
|
||||
contexts.remove("world");
|
||||
MutableContextSet contexts = MutableContextSet.fromSet(context.getContexts());
|
||||
String server = contexts.getValues("server").stream().findAny().orElse(null);
|
||||
String world = contexts.getValues("world").stream().findAny().orElse(null);
|
||||
contexts.removeAll("server");
|
||||
contexts.removeAll("world");
|
||||
|
||||
allNodes.removeIf(node ->
|
||||
!node.shouldApplyOnServer(server, context.isIncludeGlobal(), plugin.getConfiguration().isApplyingRegex()) ||
|
||||
|
@ -26,10 +26,11 @@ import lombok.EqualsAndHashCode;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.ToString;
|
||||
import me.lucko.luckperms.api.caching.UserData;
|
||||
import me.lucko.luckperms.api.event.events.UserPermissionRefreshEvent;
|
||||
import me.lucko.luckperms.common.LuckPermsPlugin;
|
||||
import me.lucko.luckperms.common.api.internal.UserLink;
|
||||
import me.lucko.luckperms.common.caching.UserData;
|
||||
import me.lucko.luckperms.common.caching.UserCache;
|
||||
import me.lucko.luckperms.common.core.PermissionHolder;
|
||||
import me.lucko.luckperms.common.utils.BufferedRequest;
|
||||
import me.lucko.luckperms.common.utils.Identifiable;
|
||||
@ -61,7 +62,7 @@ public class User extends PermissionHolder implements Identifiable<UserIdentifie
|
||||
private String primaryGroup = null;
|
||||
|
||||
@Getter
|
||||
private UserData userData = null;
|
||||
private UserCache userData = null;
|
||||
|
||||
@Getter
|
||||
private BufferedRequest<Void> refreshBuffer = new BufferedRequest<Void>(1000L, r -> getPlugin().doAsync(r)) {
|
||||
@ -103,7 +104,7 @@ public class User extends PermissionHolder implements Identifiable<UserIdentifie
|
||||
return;
|
||||
}
|
||||
|
||||
userData = new UserData(this, getPlugin().getCalculatorFactory());
|
||||
userData = new UserCache(this, getPlugin().getCalculatorFactory());
|
||||
userData.preCalculate(getPlugin().getPreProcessContexts(op));
|
||||
}
|
||||
|
||||
|
@ -23,13 +23,8 @@
|
||||
package me.lucko.luckperms.common.utils;
|
||||
|
||||
import lombok.*;
|
||||
import lombok.experimental.Delegate;
|
||||
import me.lucko.luckperms.api.Node;
|
||||
import me.lucko.luckperms.api.Tristate;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* Holds a Node and where it was inherited from
|
||||
@ -38,11 +33,12 @@ import java.util.Optional;
|
||||
@ToString
|
||||
@AllArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
public class LocalizedNode implements me.lucko.luckperms.api.LocalizedNode {
|
||||
public static LocalizedNode of(@NonNull me.lucko.luckperms.api.Node node, @NonNull String location) {
|
||||
public static LocalizedNode of(@NonNull Node node, @NonNull String location) {
|
||||
return new LocalizedNode(node, location);
|
||||
}
|
||||
|
||||
private final me.lucko.luckperms.api.Node node;
|
||||
@Delegate
|
||||
private final Node node;
|
||||
private final String location;
|
||||
|
||||
@Override
|
||||
@ -54,204 +50,4 @@ public class LocalizedNode implements me.lucko.luckperms.api.LocalizedNode {
|
||||
public boolean equals(Object obj) {
|
||||
return node.equals(obj);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPermission() {
|
||||
return node.getPermission();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getKey() {
|
||||
return node.getKey();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean getValue() {
|
||||
return node.getValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean setValue(Boolean value) {
|
||||
return node.setValue(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Tristate getTristate() {
|
||||
return node.getTristate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isNegated() {
|
||||
return node.isNegated();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isOverride() {
|
||||
return node.isOverride();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<String> getServer() {
|
||||
return node.getServer();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<String> getWorld() {
|
||||
return node.getWorld();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isServerSpecific() {
|
||||
return node.isServerSpecific();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isWorldSpecific() {
|
||||
return node.isWorldSpecific();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldApplyOnServer(String server, boolean includeGlobal, boolean applyRegex) {
|
||||
return node.shouldApplyOnServer(server, includeGlobal, applyRegex);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldApplyOnWorld(String world, boolean includeGlobal, boolean applyRegex) {
|
||||
return node.shouldApplyOnWorld(world, includeGlobal, applyRegex);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldApplyWithContext(Map<String, String> context, boolean worldAndServer) {
|
||||
return node.shouldApplyWithContext(context, worldAndServer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldApplyWithContext(Map<String, String> context) {
|
||||
return node.shouldApplyWithContext(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldApplyOnAnyServers(List<String> servers, boolean includeGlobal) {
|
||||
return node.shouldApplyOnAnyServers(servers, includeGlobal);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldApplyOnAnyWorlds(List<String> worlds, boolean includeGlobal) {
|
||||
return node.shouldApplyOnAnyWorlds(worlds, includeGlobal);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> resolveWildcard(List<String> possibleNodes) {
|
||||
return node.resolveWildcard(possibleNodes);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> resolveShorthand() {
|
||||
return node.resolveShorthand();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isTemporary() {
|
||||
return node.isTemporary();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPermanent() {
|
||||
return node.isPermanent();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getExpiryUnixTime() {
|
||||
return node.getExpiryUnixTime();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Date getExpiry() {
|
||||
return node.getExpiry();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getSecondsTilExpiry() {
|
||||
return node.getSecondsTilExpiry();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasExpired() {
|
||||
return node.hasExpired();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, String> getExtraContexts() {
|
||||
return node.getExtraContexts();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toSerializedNode() {
|
||||
return node.toSerializedNode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isGroupNode() {
|
||||
return node.isGroupNode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getGroupName() {
|
||||
return node.getGroupName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isWildcard() {
|
||||
return node.isWildcard();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getWildcardLevel() {
|
||||
return node.getWildcardLevel();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isMeta() {
|
||||
return node.isMeta();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map.Entry<String, String> getMeta() {
|
||||
return node.getMeta();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPrefix() {
|
||||
return node.isPrefix();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map.Entry<Integer, String> getPrefix() {
|
||||
return node.getPrefix();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSuffix() {
|
||||
return node.isSuffix();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map.Entry<Integer, String> getSuffix() {
|
||||
return node.getSuffix();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equalsIgnoringValue(Node other) {
|
||||
return node.equalsIgnoringValue(other);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean almostEquals(Node other) {
|
||||
return node.almostEquals(other);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equalsIgnoringValueOrTemp(Node other) {
|
||||
return node.equalsIgnoringValueOrTemp(other);
|
||||
}
|
||||
}
|
||||
|
4
pom.xml
4
pom.xml
@ -6,7 +6,7 @@
|
||||
|
||||
<groupId>me.lucko.luckperms</groupId>
|
||||
<artifactId>luckperms</artifactId>
|
||||
<version>2.12-SNAPSHOT</version>
|
||||
<version>2.13-SNAPSHOT</version>
|
||||
<modules>
|
||||
<module>common</module>
|
||||
<module>api</module>
|
||||
@ -38,7 +38,7 @@
|
||||
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<release.version>2.12</release.version>
|
||||
<release.version>2.13</release.version>
|
||||
</properties>
|
||||
|
||||
<distributionManagement>
|
||||
|
@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<artifactId>luckperms</artifactId>
|
||||
<groupId>me.lucko.luckperms</groupId>
|
||||
<version>2.12-SNAPSHOT</version>
|
||||
<version>2.13-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
@ -49,7 +49,7 @@ public class SpongeCalculatorFactory implements CalculatorFactory {
|
||||
if (plugin.getConfiguration().isApplyingRegex()) {
|
||||
processors.add(new RegexProcessor(map));
|
||||
}
|
||||
processors.add(new DefaultsProcessor(plugin.getService(), LuckPermsService.convertContexts(contexts.getContext())));
|
||||
processors.add(new DefaultsProcessor(plugin.getService(), LuckPermsService.convertContexts(contexts.getContexts())));
|
||||
|
||||
return new PermissionCalculator(plugin, user.getName(), plugin.getConfiguration().isDebugPermissionChecks(), processors);
|
||||
}
|
||||
|
@ -22,7 +22,8 @@
|
||||
|
||||
package me.lucko.luckperms.sponge;
|
||||
|
||||
import me.lucko.luckperms.common.caching.UserData;
|
||||
import me.lucko.luckperms.api.caching.UserData;
|
||||
import me.lucko.luckperms.api.context.MutableContextSet;
|
||||
import me.lucko.luckperms.common.constants.Message;
|
||||
import me.lucko.luckperms.common.users.User;
|
||||
import me.lucko.luckperms.common.utils.AbstractListener;
|
||||
@ -34,9 +35,7 @@ import org.spongepowered.api.profile.GameProfile;
|
||||
import org.spongepowered.api.text.serializer.TextSerializers;
|
||||
import org.spongepowered.api.world.World;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@ -77,7 +76,7 @@ public class SpongeListener extends AbstractListener {
|
||||
// Attempt to pre-process some permissions for the user to save time later. Might not work, but it's better than nothing.
|
||||
Optional<Player> p = e.getCause().first(Player.class);
|
||||
if (p.isPresent()) {
|
||||
Map<String, String> context = plugin.getContextManager().giveApplicableContext(p.get(), new HashMap<>());
|
||||
MutableContextSet context = plugin.getContextManager().giveApplicableContext(p.get(), MutableContextSet.empty());
|
||||
|
||||
List<String> worlds = plugin.getGame().getServer().getWorlds().stream()
|
||||
.map(World::getName)
|
||||
@ -88,8 +87,9 @@ public class SpongeListener extends AbstractListener {
|
||||
data.preCalculate(plugin.getService().calculateContexts(LuckPermsService.convertContexts(context)));
|
||||
|
||||
for (String world : worlds) {
|
||||
Map<String, String> modified = new HashMap<>(context);
|
||||
modified.put("world", world);
|
||||
MutableContextSet modified = MutableContextSet.fromSet(context);
|
||||
modified.removeAll("world");
|
||||
modified.add("world", world);
|
||||
data.preCalculate(plugin.getService().calculateContexts(LuckPermsService.convertContexts(modified)));
|
||||
}
|
||||
});
|
||||
|
@ -24,6 +24,7 @@ package me.lucko.luckperms.sponge.contexts;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import me.lucko.luckperms.api.context.ContextCalculator;
|
||||
import me.lucko.luckperms.api.context.MutableContextSet;
|
||||
import me.lucko.luckperms.sponge.service.LuckPermsService;
|
||||
import org.spongepowered.api.service.context.Context;
|
||||
import org.spongepowered.api.service.permission.Subject;
|
||||
@ -36,12 +37,12 @@ public class SpongeCalculatorLink extends ContextCalculator<Subject> {
|
||||
private final org.spongepowered.api.service.context.ContextCalculator<Subject> calculator;
|
||||
|
||||
@Override
|
||||
public Map<String, String> giveApplicableContext(Subject subject, Map<String, String> accumulator) {
|
||||
public MutableContextSet giveApplicableContext(Subject subject, MutableContextSet accumulator) {
|
||||
Set<Context> contexts = LuckPermsService.convertContexts(accumulator);
|
||||
calculator.accumulateContexts(subject, contexts);
|
||||
|
||||
accumulator.clear();
|
||||
accumulator.putAll(LuckPermsService.convertContexts(contexts));
|
||||
accumulator.addAll(LuckPermsService.convertContexts(contexts));
|
||||
return accumulator;
|
||||
}
|
||||
|
||||
|
@ -24,6 +24,7 @@ package me.lucko.luckperms.sponge.contexts;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import me.lucko.luckperms.api.context.ContextCalculator;
|
||||
import me.lucko.luckperms.api.context.MutableContextSet;
|
||||
import me.lucko.luckperms.common.commands.Util;
|
||||
import me.lucko.luckperms.sponge.LPSpongePlugin;
|
||||
import org.spongepowered.api.entity.living.player.Player;
|
||||
@ -39,7 +40,7 @@ public class WorldCalculator extends ContextCalculator<Subject> {
|
||||
private final LPSpongePlugin plugin;
|
||||
|
||||
@Override
|
||||
public Map<String, String> giveApplicableContext(Subject subject, Map<String, String> accumulator) {
|
||||
public MutableContextSet giveApplicableContext(Subject subject, MutableContextSet accumulator) {
|
||||
UUID uuid = Util.parseUuid(subject.getIdentifier());
|
||||
if (uuid == null) {
|
||||
return accumulator;
|
||||
@ -50,7 +51,7 @@ public class WorldCalculator extends ContextCalculator<Subject> {
|
||||
return accumulator;
|
||||
}
|
||||
|
||||
accumulator.put(Context.WORLD_KEY, p.get().getWorld().getName());
|
||||
accumulator.add(Context.WORLD_KEY, p.get().getWorld().getName());
|
||||
return accumulator;
|
||||
}
|
||||
|
||||
|
@ -28,13 +28,13 @@ import lombok.Getter;
|
||||
import lombok.NonNull;
|
||||
import me.lucko.luckperms.api.LocalizedNode;
|
||||
import me.lucko.luckperms.api.Node;
|
||||
import me.lucko.luckperms.api.context.MutableContextSet;
|
||||
import me.lucko.luckperms.common.groups.Group;
|
||||
import org.spongepowered.api.command.CommandSource;
|
||||
import org.spongepowered.api.service.context.Context;
|
||||
import org.spongepowered.api.service.permission.NodeTree;
|
||||
import org.spongepowered.api.service.permission.Subject;
|
||||
import org.spongepowered.api.service.permission.SubjectCollection;
|
||||
import org.spongepowered.api.service.permission.SubjectData;
|
||||
import org.spongepowered.api.util.Tristate;
|
||||
|
||||
import java.util.List;
|
||||
@ -156,7 +156,7 @@ public class LuckPermsGroupSubject implements Subject {
|
||||
|
||||
@Override
|
||||
public Set<Context> getActiveContexts() {
|
||||
return SubjectData.GLOBAL_CONTEXT;
|
||||
return LuckPermsService.convertContexts(service.getPlugin().getContextManager().giveApplicableContext(this, MutableContextSet.empty()));
|
||||
}
|
||||
|
||||
private Optional<String> getChatMeta(Set<Context> contexts, boolean prefix) {
|
||||
|
@ -22,10 +22,15 @@
|
||||
|
||||
package me.lucko.luckperms.sponge.service;
|
||||
|
||||
import com.google.common.cache.CacheBuilder;
|
||||
import com.google.common.cache.CacheLoader;
|
||||
import com.google.common.cache.LoadingCache;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.Maps;
|
||||
import lombok.*;
|
||||
import me.lucko.luckperms.api.Contexts;
|
||||
import me.lucko.luckperms.api.context.ContextSet;
|
||||
import me.lucko.luckperms.sponge.LPSpongePlugin;
|
||||
import me.lucko.luckperms.sponge.contexts.SpongeCalculatorLink;
|
||||
import me.lucko.luckperms.sponge.service.collections.GroupCollection;
|
||||
@ -48,28 +53,25 @@ import java.util.stream.Collectors;
|
||||
/**
|
||||
* The LuckPerms implementation of the Sponge Permission Service
|
||||
*/
|
||||
@Getter
|
||||
public class LuckPermsService implements PermissionService {
|
||||
public static final String SERVER_CONTEXT = "server";
|
||||
|
||||
@Getter
|
||||
private final LPSpongePlugin plugin;
|
||||
|
||||
@Getter
|
||||
private final SubjectStorage storage;
|
||||
|
||||
@Getter
|
||||
private final UserCollection userSubjects;
|
||||
|
||||
@Getter
|
||||
private final GroupCollection groupSubjects;
|
||||
|
||||
@Getter
|
||||
private final PersistedCollection defaultSubjects;
|
||||
|
||||
@Getter
|
||||
private final Set<PermissionDescription> descriptionSet;
|
||||
|
||||
private final Map<String, SubjectCollection> subjects;
|
||||
@Getter(value = AccessLevel.NONE)
|
||||
private final LoadingCache<String, SubjectCollection> collections = CacheBuilder.newBuilder()
|
||||
.build(new CacheLoader<String, SubjectCollection>() {
|
||||
@Override
|
||||
public SubjectCollection load(String s) {
|
||||
return new SimpleCollection(LuckPermsService.this, s);
|
||||
}
|
||||
});
|
||||
|
||||
public LuckPermsService(LPSpongePlugin plugin) {
|
||||
this.plugin = plugin;
|
||||
@ -81,10 +83,9 @@ public class LuckPermsService implements PermissionService {
|
||||
defaultSubjects = new PersistedCollection(this, "defaults");
|
||||
defaultSubjects.loadAll();
|
||||
|
||||
subjects = new ConcurrentHashMap<>();
|
||||
subjects.put(PermissionService.SUBJECTS_USER, userSubjects);
|
||||
subjects.put(PermissionService.SUBJECTS_GROUP, groupSubjects);
|
||||
subjects.put("defaults", defaultSubjects);
|
||||
collections.put(PermissionService.SUBJECTS_USER, userSubjects);
|
||||
collections.put(PermissionService.SUBJECTS_GROUP, groupSubjects);
|
||||
collections.put("defaults", defaultSubjects);
|
||||
|
||||
descriptionSet = ConcurrentHashMap.newKeySet();
|
||||
}
|
||||
@ -100,16 +101,12 @@ public class LuckPermsService implements PermissionService {
|
||||
|
||||
@Override
|
||||
public SubjectCollection getSubjects(String s) {
|
||||
if (!subjects.containsKey(s)) {
|
||||
subjects.put(s, new SimpleCollection(this, s));
|
||||
}
|
||||
|
||||
return subjects.get(s);
|
||||
return collections.getUnchecked(s.toLowerCase());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, SubjectCollection> getKnownSubjects() {
|
||||
return ImmutableMap.copyOf(subjects);
|
||||
return ImmutableMap.copyOf(collections.asMap());
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -150,16 +147,17 @@ public class LuckPermsService implements PermissionService {
|
||||
plugin.getConfiguration().isIncludingGlobalWorldPerms(),
|
||||
true,
|
||||
plugin.getConfiguration().isApplyingGlobalGroups(),
|
||||
plugin.getConfiguration().isApplyingGlobalWorldGroups()
|
||||
plugin.getConfiguration().isApplyingGlobalWorldGroups(),
|
||||
false
|
||||
);
|
||||
}
|
||||
|
||||
public static Map<String, String> convertContexts(Set<Context> contexts) {
|
||||
return contexts.stream().collect(Collectors.toMap(Context::getKey, Context::getValue));
|
||||
public static ContextSet convertContexts(Set<Context> contexts) {
|
||||
return ContextSet.fromEntries(contexts.stream().map(c -> Maps.immutableEntry(c.getKey(), c.getValue())).collect(Collectors.toSet()));
|
||||
}
|
||||
|
||||
public static Set<Context> convertContexts(Map<String, String> contexts) {
|
||||
return contexts.entrySet().stream().map(e -> new Context(e.getKey(), e.getValue())).collect(Collectors.toSet());
|
||||
public static Set<Context> convertContexts(ContextSet contexts) {
|
||||
return contexts.toSet().stream().map(e -> new Context(e.getKey(), e.getValue())).collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
public static Tristate convertTristate(me.lucko.luckperms.api.Tristate tristate) {
|
||||
|
@ -28,6 +28,7 @@ import com.google.common.collect.ImmutableSet;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import me.lucko.luckperms.api.Node;
|
||||
import me.lucko.luckperms.api.context.ContextSet;
|
||||
import me.lucko.luckperms.common.core.PermissionHolder;
|
||||
import me.lucko.luckperms.common.groups.Group;
|
||||
import me.lucko.luckperms.common.users.User;
|
||||
@ -65,7 +66,7 @@ public class LuckPermsSubjectData implements SubjectData {
|
||||
Map<Set<Context>, Map<String, Boolean>> perms = new HashMap<>();
|
||||
|
||||
for (Node n : enduring ? holder.getNodes() : holder.getTransientNodes()) {
|
||||
Set<Context> contexts = LuckPermsService.convertContexts(n.getExtraContexts());
|
||||
Set<Context> contexts = LuckPermsService.convertContexts(n.getContexts());
|
||||
|
||||
if (n.isServerSpecific()) {
|
||||
contexts.add(new Context(LuckPermsService.SERVER_CONTEXT, n.getServer().get()));
|
||||
@ -185,7 +186,7 @@ public class LuckPermsSubjectData implements SubjectData {
|
||||
continue;
|
||||
}
|
||||
|
||||
Set<Context> contexts = LuckPermsService.convertContexts(n.getExtraContexts());
|
||||
Set<Context> contexts = LuckPermsService.convertContexts(n.getContexts());
|
||||
|
||||
if (n.isServerSpecific()) {
|
||||
contexts.add(new Context(LuckPermsService.SERVER_CONTEXT, n.getServer().get()));
|
||||
@ -225,7 +226,7 @@ public class LuckPermsSubjectData implements SubjectData {
|
||||
public boolean addParent(Set<Context> set, Subject subject) {
|
||||
if (subject instanceof LuckPermsGroupSubject) {
|
||||
LuckPermsGroupSubject permsSubject = ((LuckPermsGroupSubject) subject);
|
||||
Map<String, String> contexts = LuckPermsService.convertContexts(set);
|
||||
ContextSet contexts = LuckPermsService.convertContexts(set);
|
||||
|
||||
try {
|
||||
if (enduring) {
|
||||
@ -249,7 +250,7 @@ public class LuckPermsSubjectData implements SubjectData {
|
||||
public boolean removeParent(Set<Context> set, Subject subject) {
|
||||
if (subject instanceof LuckPermsGroupSubject) {
|
||||
LuckPermsGroupSubject permsSubject = ((LuckPermsGroupSubject) subject);
|
||||
Map<String, String> contexts = LuckPermsService.convertContexts(set);
|
||||
ContextSet contexts = LuckPermsService.convertContexts(set);
|
||||
|
||||
try {
|
||||
if (enduring) {
|
||||
@ -295,7 +296,7 @@ public class LuckPermsSubjectData implements SubjectData {
|
||||
|
||||
@Override
|
||||
public boolean clearParents(Set<Context> set) {
|
||||
Map<String, String> context = LuckPermsService.convertContexts(set);
|
||||
ContextSet context = LuckPermsService.convertContexts(set);
|
||||
|
||||
List<Node> toRemove = (enduring ? holder.getNodes() : holder.getTransientNodes()).stream()
|
||||
.filter(Node::isGroupNode)
|
||||
@ -336,7 +337,7 @@ public class LuckPermsSubjectData implements SubjectData {
|
||||
continue;
|
||||
}
|
||||
|
||||
Set<Context> contexts = LuckPermsService.convertContexts(n.getExtraContexts());
|
||||
Set<Context> contexts = LuckPermsService.convertContexts(n.getContexts());
|
||||
|
||||
if (n.isServerSpecific()) {
|
||||
contexts.add(new Context(LuckPermsService.SERVER_CONTEXT, n.getServer().get()));
|
||||
@ -384,7 +385,7 @@ public class LuckPermsSubjectData implements SubjectData {
|
||||
@Override
|
||||
public Map<String, String> getOptions(Set<Context> set) {
|
||||
ImmutableMap.Builder<String, String> options = ImmutableMap.builder();
|
||||
Map<String, String> contexts = LuckPermsService.convertContexts(set);
|
||||
ContextSet contexts = LuckPermsService.convertContexts(set);
|
||||
|
||||
int prefixPriority = Integer.MIN_VALUE;
|
||||
int suffixPriority = Integer.MIN_VALUE;
|
||||
@ -431,7 +432,7 @@ public class LuckPermsSubjectData implements SubjectData {
|
||||
|
||||
@Override
|
||||
public boolean setOption(Set<Context> set, String key, String value) {
|
||||
Map<String, String> context = LuckPermsService.convertContexts(set);
|
||||
ContextSet context = LuckPermsService.convertContexts(set);
|
||||
|
||||
key = escapeCharacters(key);
|
||||
value = escapeCharacters(value);
|
||||
@ -455,7 +456,7 @@ public class LuckPermsSubjectData implements SubjectData {
|
||||
|
||||
@Override
|
||||
public boolean clearOptions(Set<Context> set) {
|
||||
Map<String, String> context = LuckPermsService.convertContexts(set);
|
||||
ContextSet context = LuckPermsService.convertContexts(set);
|
||||
|
||||
List<Node> toRemove = (enduring ? holder.getNodes() : holder.getTransientNodes()).stream()
|
||||
.filter(n -> n.isMeta() || n.isPrefix() || n.isSuffix())
|
||||
|
@ -26,7 +26,8 @@ import com.google.common.collect.ImmutableList;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.Getter;
|
||||
import lombok.NonNull;
|
||||
import me.lucko.luckperms.common.caching.MetaData;
|
||||
import me.lucko.luckperms.api.caching.MetaData;
|
||||
import me.lucko.luckperms.api.context.MutableContextSet;
|
||||
import me.lucko.luckperms.common.users.User;
|
||||
import org.spongepowered.api.Sponge;
|
||||
import org.spongepowered.api.command.CommandSource;
|
||||
@ -36,8 +37,10 @@ import org.spongepowered.api.service.permission.Subject;
|
||||
import org.spongepowered.api.service.permission.SubjectCollection;
|
||||
import org.spongepowered.api.util.Tristate;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
@EqualsAndHashCode(of = "user")
|
||||
public class LuckPermsUserSubject implements Subject {
|
||||
@ -171,8 +174,6 @@ public class LuckPermsUserSubject implements Subject {
|
||||
|
||||
@Override
|
||||
public Set<Context> getActiveContexts() {
|
||||
return service.getPlugin().getContextManager().giveApplicableContext(this, new HashMap<>()).entrySet().stream()
|
||||
.map(e -> new Context(e.getKey(), e.getValue()))
|
||||
.collect(Collectors.toSet());
|
||||
return LuckPermsService.convertContexts(service.getPlugin().getContextManager().giveApplicableContext(this, MutableContextSet.empty()));
|
||||
}
|
||||
}
|
||||
|
@ -22,6 +22,9 @@
|
||||
|
||||
package me.lucko.luckperms.sponge.service.persisted;
|
||||
|
||||
import com.google.common.cache.CacheBuilder;
|
||||
import com.google.common.cache.CacheLoader;
|
||||
import com.google.common.cache.LoadingCache;
|
||||
import lombok.Getter;
|
||||
import lombok.NonNull;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
@ -35,7 +38,6 @@ import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
@ -48,34 +50,35 @@ public class PersistedCollection implements SubjectCollection {
|
||||
@Getter
|
||||
private final String identifier;
|
||||
|
||||
private final Map<String, PersistedSubject> subjects = new ConcurrentHashMap<>();
|
||||
private final LoadingCache<String, PersistedSubject> subjects = CacheBuilder.newBuilder()
|
||||
.build(new CacheLoader<String, PersistedSubject>() {
|
||||
@Override
|
||||
public PersistedSubject load(String s) {
|
||||
return new PersistedSubject(s, service, PersistedCollection.this);
|
||||
}
|
||||
});
|
||||
|
||||
public void loadAll() {
|
||||
Map<String, SubjectDataHolder> holders = service.getStorage().loadAllFromFile(identifier);
|
||||
for (Map.Entry<String, SubjectDataHolder> e : holders.entrySet()) {
|
||||
PersistedSubject subject = new PersistedSubject(e.getKey(), service, this);
|
||||
PersistedSubject subject = get(e.getKey());
|
||||
subject.loadData(e.getValue());
|
||||
subjects.put(e.getKey(), subject);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized Subject get(@NonNull String id) {
|
||||
if (!subjects.containsKey(id)) {
|
||||
subjects.put(id, new PersistedSubject(id, service, this));
|
||||
}
|
||||
|
||||
return subjects.get(id);
|
||||
public PersistedSubject get(@NonNull String id) {
|
||||
return subjects.getUnchecked(id.toLowerCase());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasRegistered(@NonNull String id) {
|
||||
return subjects.containsKey(id);
|
||||
return subjects.asMap().containsKey(id.toLowerCase());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterable<Subject> getAllSubjects() {
|
||||
return subjects.values().stream().map(s -> (Subject) s).collect(Collectors.toList());
|
||||
return subjects.asMap().values().stream().map(s -> (Subject) s).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -86,7 +89,7 @@ public class PersistedCollection implements SubjectCollection {
|
||||
@Override
|
||||
public Map<Subject, Boolean> getAllWithPermission(@NonNull Set<Context> contexts, @NonNull String node) {
|
||||
Map<Subject, Boolean> m = new HashMap<>();
|
||||
for (Subject subject : subjects.values()) {
|
||||
for (Subject subject : subjects.asMap().values()) {
|
||||
Tristate ts = subject.getPermissionValue(contexts, node);
|
||||
if (ts != Tristate.UNDEFINED) {
|
||||
m.put(subject, ts.asBoolean());
|
||||
|
@ -25,13 +25,14 @@ package me.lucko.luckperms.sponge.service.persisted;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import lombok.Getter;
|
||||
import lombok.NonNull;
|
||||
import me.lucko.luckperms.api.context.MutableContextSet;
|
||||
import me.lucko.luckperms.common.utils.BufferedRequest;
|
||||
import me.lucko.luckperms.sponge.service.LuckPermsService;
|
||||
import org.spongepowered.api.command.CommandSource;
|
||||
import org.spongepowered.api.service.context.Context;
|
||||
import org.spongepowered.api.service.permission.MemorySubjectData;
|
||||
import org.spongepowered.api.service.permission.Subject;
|
||||
import org.spongepowered.api.service.permission.SubjectCollection;
|
||||
import org.spongepowered.api.service.permission.SubjectData;
|
||||
import org.spongepowered.api.util.Tristate;
|
||||
|
||||
import java.io.IOException;
|
||||
@ -51,6 +52,19 @@ public class PersistedSubject implements Subject {
|
||||
private final SubjectCollection containingCollection;
|
||||
private final PersistedSubjectData subjectData;
|
||||
private final MemorySubjectData transientSubjectData;
|
||||
private final BufferedRequest<Void> saveBuffer = new BufferedRequest<Void>(1000L, r -> PersistedSubject.this.service.getPlugin().doAsync(r)) {
|
||||
@Override
|
||||
protected Void perform() {
|
||||
service.getPlugin().doAsync(() -> {
|
||||
try {
|
||||
service.getStorage().saveToFile(PersistedSubject.this);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
});
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
public PersistedSubject(String identifier, LuckPermsService service, SubjectCollection containingCollection) {
|
||||
this.identifier = identifier;
|
||||
@ -67,13 +81,7 @@ public class PersistedSubject implements Subject {
|
||||
}
|
||||
|
||||
public void save() {
|
||||
service.getPlugin().doAsync(() -> {
|
||||
try {
|
||||
service.getStorage().saveToFile(this);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
});
|
||||
saveBuffer.request();
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -178,6 +186,6 @@ public class PersistedSubject implements Subject {
|
||||
|
||||
@Override
|
||||
public Set<Context> getActiveContexts() {
|
||||
return SubjectData.GLOBAL_CONTEXT;
|
||||
return LuckPermsService.convertContexts(service.getPlugin().getContextManager().giveApplicableContext(this, MutableContextSet.empty()));
|
||||
}
|
||||
}
|
||||
|
@ -22,6 +22,8 @@
|
||||
|
||||
package me.lucko.luckperms.sponge.service.persisted;
|
||||
|
||||
import lombok.ToString;
|
||||
import me.lucko.luckperms.api.context.ContextSet;
|
||||
import org.spongepowered.api.service.context.Context;
|
||||
import org.spongepowered.api.service.permission.MemorySubjectData;
|
||||
import org.spongepowered.api.service.permission.PermissionService;
|
||||
@ -35,6 +37,7 @@ import static me.lucko.luckperms.sponge.service.LuckPermsService.convertContexts
|
||||
/**
|
||||
* Holds SubjectData in a "gson friendly" format for serialization
|
||||
*/
|
||||
@ToString
|
||||
public class SubjectDataHolder {
|
||||
private final Map<Map<String, String>, Map<String, Boolean>> permissions;
|
||||
private final Map<Map<String, String>, Map<String, String>> options;
|
||||
@ -43,17 +46,17 @@ public class SubjectDataHolder {
|
||||
public SubjectDataHolder(Map<Set<Context>, Map<String, String>> options, Map<Set<Context>, Map<String, Boolean>> permissions, Map<Set<Context>, List<Map.Entry<String, String>>> parents) {
|
||||
this.options = new HashMap<>();
|
||||
for (Map.Entry<Set<Context>, Map<String, String>> e : options.entrySet()) {
|
||||
this.options.put(convertContexts(e.getKey()), new HashMap<>(e.getValue()));
|
||||
this.options.put(convertContexts(e.getKey()).toMap(), new HashMap<>(e.getValue()));
|
||||
}
|
||||
|
||||
this.permissions = new HashMap<>();
|
||||
for (Map.Entry<Set<Context>, Map<String, Boolean>> e : permissions.entrySet()) {
|
||||
this.permissions.put(convertContexts(e.getKey()), new HashMap<>(e.getValue()));
|
||||
this.permissions.put(convertContexts(e.getKey()).toMap(), new HashMap<>(e.getValue()));
|
||||
}
|
||||
|
||||
this.parents = new HashMap<>();
|
||||
for (Map.Entry<Set<Context>, List<Map.Entry<String, String>>> e : parents.entrySet()) {
|
||||
this.parents.put(convertContexts(e.getKey()), e.getValue().stream().map(p -> new AbstractMap.SimpleEntry<>(p.getKey(), p.getValue())).collect(Collectors.toList()));
|
||||
this.parents.put(convertContexts(e.getKey()).toMap(), e.getValue().stream().map(p -> new AbstractMap.SimpleEntry<>(p.getKey(), p.getValue())).collect(Collectors.toList()));
|
||||
}
|
||||
}
|
||||
|
||||
@ -77,20 +80,23 @@ public class SubjectDataHolder {
|
||||
|
||||
public void copyTo(MemorySubjectData subjectData, PermissionService service) {
|
||||
for (Map.Entry<Map<String, String>, Map<String, Boolean>> e : permissions.entrySet()) {
|
||||
Set<Context> contexts = convertContexts(ContextSet.fromMap(e.getKey()));
|
||||
for (Map.Entry<String, Boolean> perm : e.getValue().entrySet()) {
|
||||
subjectData.setPermission(convertContexts(e.getKey()), perm.getKey(), Tristate.fromBoolean(perm.getValue()));
|
||||
subjectData.setPermission(contexts, perm.getKey(), Tristate.fromBoolean(perm.getValue()));
|
||||
}
|
||||
}
|
||||
|
||||
for (Map.Entry<Map<String, String>, Map<String, String>> e : options.entrySet()) {
|
||||
Set<Context> contexts = convertContexts(ContextSet.fromMap(e.getKey()));
|
||||
for (Map.Entry<String, String> option : e.getValue().entrySet()) {
|
||||
subjectData.setOption(convertContexts(e.getKey()), option.getKey(), option.getValue());
|
||||
subjectData.setOption(contexts, option.getKey(), option.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
for (Map.Entry<Map<String, String>, List<Map.Entry<String, String>>> e : parents.entrySet()) {
|
||||
Set<Context> contexts = convertContexts(ContextSet.fromMap(e.getKey()));
|
||||
for (Map.Entry<String, String> parent : e.getValue()) {
|
||||
subjectData.addParent(convertContexts(e.getKey()), service.getSubjects(parent.getKey()).get(parent.getValue()));
|
||||
subjectData.addParent(contexts, service.getSubjects(parent.getKey()).get(parent.getValue()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -58,7 +58,7 @@ public class SubjectStorage {
|
||||
collection.mkdirs();
|
||||
}
|
||||
|
||||
File subjectFile = new File(collection, subject.getIdentifier().toLowerCase() + ".json");
|
||||
File subjectFile = new File(collection, subject.getIdentifier() + ".json");
|
||||
saveToFile(subject, subjectFile);
|
||||
}
|
||||
|
||||
@ -110,8 +110,8 @@ public class SubjectStorage {
|
||||
return null;
|
||||
}
|
||||
|
||||
File subject = new File(collection, subjectName.toLowerCase() + ".json");
|
||||
return new AbstractMap.SimpleEntry<>(subjectName.toLowerCase(), loadFromFile(subject).getValue());
|
||||
File subject = new File(collection, subjectName + ".json");
|
||||
return new AbstractMap.SimpleEntry<>(subjectName, loadFromFile(subject).getValue());
|
||||
}
|
||||
|
||||
public Map.Entry<String, SubjectDataHolder> loadFromFile(File file) throws IOException {
|
||||
@ -120,7 +120,7 @@ public class SubjectStorage {
|
||||
}
|
||||
|
||||
String s = Files.toString(file, Charset.defaultCharset());
|
||||
return new AbstractMap.SimpleEntry<>(file.getName().substring(file.getName().length() - 5).toLowerCase(), loadFromString(s));
|
||||
return new AbstractMap.SimpleEntry<>(file.getName().substring(0, file.getName().length() - 5), loadFromString(s));
|
||||
}
|
||||
|
||||
public SubjectDataHolder loadFromString(String s) {
|
||||
|
@ -22,6 +22,9 @@
|
||||
|
||||
package me.lucko.luckperms.sponge.service.simple;
|
||||
|
||||
import com.google.common.cache.CacheBuilder;
|
||||
import com.google.common.cache.CacheLoader;
|
||||
import com.google.common.cache.LoadingCache;
|
||||
import lombok.Getter;
|
||||
import lombok.NonNull;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
@ -35,7 +38,7 @@ import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* Super simple SubjectCollection implementation
|
||||
@ -47,25 +50,27 @@ public class SimpleCollection implements SubjectCollection {
|
||||
@Getter
|
||||
private final String identifier;
|
||||
|
||||
private final Map<String, Subject> subjects = new ConcurrentHashMap<>();
|
||||
private final LoadingCache<String, SimpleSubject> subjects = CacheBuilder.newBuilder()
|
||||
.build(new CacheLoader<String, SimpleSubject>() {
|
||||
@Override
|
||||
public SimpleSubject load(String s) {
|
||||
return new SimpleSubject(s, service, SimpleCollection.this);
|
||||
}
|
||||
});
|
||||
|
||||
@Override
|
||||
public synchronized Subject get(@NonNull String id) {
|
||||
if (!subjects.containsKey(id)) {
|
||||
subjects.put(id, new SimpleSubject(id, service, this));
|
||||
}
|
||||
|
||||
return subjects.get(id);
|
||||
public Subject get(@NonNull String id) {
|
||||
return subjects.getUnchecked(id.toLowerCase());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasRegistered(@NonNull String id) {
|
||||
return subjects.containsKey(id);
|
||||
return subjects.asMap().containsKey(id.toLowerCase());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterable<Subject> getAllSubjects() {
|
||||
return subjects.values();
|
||||
return subjects.asMap().values().stream().map(s -> (Subject) s).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -76,7 +81,7 @@ public class SimpleCollection implements SubjectCollection {
|
||||
@Override
|
||||
public Map<Subject, Boolean> getAllWithPermission(@NonNull Set<Context> contexts, @NonNull String node) {
|
||||
Map<Subject, Boolean> m = new HashMap<>();
|
||||
for (Subject subject : subjects.values()) {
|
||||
for (Subject subject : subjects.asMap().values()) {
|
||||
Tristate ts = subject.getPermissionValue(contexts, node);
|
||||
if (ts != Tristate.UNDEFINED) {
|
||||
m.put(subject, ts.asBoolean());
|
||||
|
@ -25,9 +25,14 @@ package me.lucko.luckperms.sponge.service.simple;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import lombok.Getter;
|
||||
import lombok.NonNull;
|
||||
import me.lucko.luckperms.api.context.MutableContextSet;
|
||||
import me.lucko.luckperms.sponge.service.LuckPermsService;
|
||||
import org.spongepowered.api.command.CommandSource;
|
||||
import org.spongepowered.api.service.context.Context;
|
||||
import org.spongepowered.api.service.permission.*;
|
||||
import org.spongepowered.api.service.permission.MemorySubjectData;
|
||||
import org.spongepowered.api.service.permission.Subject;
|
||||
import org.spongepowered.api.service.permission.SubjectCollection;
|
||||
import org.spongepowered.api.service.permission.SubjectData;
|
||||
import org.spongepowered.api.util.Tristate;
|
||||
|
||||
import java.util.ArrayList;
|
||||
@ -42,11 +47,11 @@ import java.util.Set;
|
||||
public class SimpleSubject implements Subject {
|
||||
private final String identifier;
|
||||
|
||||
private final PermissionService service;
|
||||
private final LuckPermsService service;
|
||||
private final SubjectCollection containingCollection;
|
||||
private final MemorySubjectData subjectData;
|
||||
|
||||
public SimpleSubject(String identifier, PermissionService service, SubjectCollection containingCollection) {
|
||||
public SimpleSubject(String identifier, LuckPermsService service, SubjectCollection containingCollection) {
|
||||
this.identifier = identifier;
|
||||
this.service = service;
|
||||
this.containingCollection = containingCollection;
|
||||
@ -147,6 +152,6 @@ public class SimpleSubject implements Subject {
|
||||
|
||||
@Override
|
||||
public Set<Context> getActiveContexts() {
|
||||
return SubjectData.GLOBAL_CONTEXT;
|
||||
return LuckPermsService.convertContexts(service.getPlugin().getContextManager().giveApplicableContext(this, MutableContextSet.empty()));
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user