mirror of
https://github.com/LuckPerms/LuckPerms.git
synced 2024-12-28 03:57:36 +01:00
Cleanup permission calculation
This commit is contained in:
parent
7b655d12df
commit
d113a92ce5
@ -44,10 +44,8 @@ public class AttachmentProcessor implements PermissionProcessor {
|
||||
return Tristate.UNDEFINED;
|
||||
}
|
||||
|
||||
if (m.containsKey(permission)) {
|
||||
return Tristate.fromBoolean(m.get(permission).getValue());
|
||||
}
|
||||
return Tristate.UNDEFINED;
|
||||
PermissionAttachmentInfo pai = m.get(permission);
|
||||
return pai == null ? Tristate.UNDEFINED : Tristate.fromBoolean(pai.getValue());
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -28,6 +28,7 @@ import me.lucko.luckperms.bukkit.inject.LPPermissible;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
public class AutoOPListener implements ContextListener<Player> {
|
||||
|
||||
@ -39,7 +40,7 @@ public class AutoOPListener implements ContextListener<Player> {
|
||||
}
|
||||
|
||||
Map<String, Boolean> backing = permissible.getUser().getUserData().getPermissionData(permissible.calculateContexts()).getImmutableBacking();
|
||||
boolean op = backing.containsKey("luckperms.autoop") && backing.get("luckperms.autoop");
|
||||
boolean op = Optional.ofNullable(backing.get("luckperms.autoop")).orElse(false);
|
||||
subject.setOp(op);
|
||||
}
|
||||
|
||||
|
@ -41,10 +41,6 @@ public class DefaultsProcessor implements PermissionProcessor {
|
||||
}
|
||||
|
||||
Permission defPerm = Bukkit.getServer().getPluginManager().getPermission(permission);
|
||||
if (defPerm != null) {
|
||||
return Tristate.fromBoolean(defPerm.getDefault().getValue(isOp));
|
||||
} else {
|
||||
return Tristate.UNDEFINED;
|
||||
}
|
||||
return defPerm == null ? Tristate.UNDEFINED : Tristate.fromBoolean(defPerm.getDefault().getValue(isOp));
|
||||
}
|
||||
}
|
||||
|
@ -97,11 +97,9 @@ public class DefaultsProvider {
|
||||
|
||||
public Tristate hasDefault(String permission, boolean isOp) {
|
||||
Map<String, Boolean> map = isOp ? op : nonOp;
|
||||
if (!map.containsKey(permission)) {
|
||||
return Tristate.UNDEFINED;
|
||||
}
|
||||
|
||||
return Tristate.fromBoolean(map.get(permission));
|
||||
Boolean b = map.get(permission);
|
||||
return b == null ? Tristate.UNDEFINED : Tristate.fromBoolean(b);
|
||||
}
|
||||
|
||||
@AllArgsConstructor
|
||||
|
@ -23,27 +23,25 @@
|
||||
package me.lucko.luckperms.common.caching;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import lombok.Getter;
|
||||
import com.google.common.collect.ImmutableSortedMap;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import me.lucko.luckperms.api.Contexts;
|
||||
import me.lucko.luckperms.api.LocalizedNode;
|
||||
import me.lucko.luckperms.api.Node;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.SortedSet;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* Holds a user's cached meta for a given context
|
||||
*/
|
||||
@RequiredArgsConstructor
|
||||
public class MetaData {
|
||||
private final Contexts contexts;
|
||||
|
||||
@Getter
|
||||
private String prefix = null;
|
||||
private final SortedMap<Integer, String> prefixes = new TreeMap<>(Comparator.reverseOrder());
|
||||
private final SortedMap<Integer, String> suffixes = new TreeMap<>(Comparator.reverseOrder());
|
||||
|
||||
@Getter
|
||||
private String suffix = null;
|
||||
private Map<String, String> meta = new ConcurrentHashMap<>();
|
||||
private final Map<String, String> meta = new HashMap<>();
|
||||
|
||||
public void loadMeta(SortedSet<LocalizedNode> nodes) {
|
||||
invalidateCache();
|
||||
@ -52,9 +50,6 @@ public class MetaData {
|
||||
String server = contexts.remove("server");
|
||||
String world = contexts.remove("world");
|
||||
|
||||
int prefixPriority = Integer.MIN_VALUE;
|
||||
int suffixPriority = Integer.MIN_VALUE;
|
||||
|
||||
for (LocalizedNode ln : nodes) {
|
||||
Node n = ln.getNode();
|
||||
|
||||
@ -80,37 +75,84 @@ public class MetaData {
|
||||
|
||||
if (n.isPrefix()) {
|
||||
Map.Entry<Integer, String> value = n.getPrefix();
|
||||
if (value.getKey() > prefixPriority) {
|
||||
this.prefix = value.getValue();
|
||||
prefixPriority = value.getKey();
|
||||
synchronized (this.prefixes) {
|
||||
if (!this.prefixes.containsKey(value.getKey())) {
|
||||
this.prefixes.put(value.getKey(), value.getValue());
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (n.isSuffix()) {
|
||||
Map.Entry<Integer, String> value = n.getSuffix();
|
||||
if (value.getKey() > suffixPriority) {
|
||||
this.suffix = value.getValue();
|
||||
suffixPriority = value.getKey();
|
||||
synchronized (this.suffixes) {
|
||||
if (!this.suffixes.containsKey(value.getKey())) {
|
||||
this.suffixes.put(value.getKey(), value.getValue());
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (n.isMeta()) {
|
||||
Map.Entry<String, String> meta = n.getMeta();
|
||||
synchronized (this.meta) {
|
||||
if (!this.meta.containsKey(meta.getKey())) {
|
||||
this.meta.put(meta.getKey(), meta.getValue());
|
||||
}
|
||||
}
|
||||
this.meta.put(meta.getKey(), meta.getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void invalidateCache() {
|
||||
meta.clear();
|
||||
prefix = null;
|
||||
suffix = null;
|
||||
synchronized (meta) {
|
||||
meta.clear();
|
||||
}
|
||||
synchronized (prefixes) {
|
||||
prefixes.clear();
|
||||
}
|
||||
synchronized (suffixes) {
|
||||
suffixes.clear();
|
||||
}
|
||||
}
|
||||
|
||||
public Map<String, String> getMeta() {
|
||||
return ImmutableMap.copyOf(meta);
|
||||
synchronized (meta) {
|
||||
return ImmutableMap.copyOf(meta);
|
||||
}
|
||||
}
|
||||
|
||||
public SortedMap<Integer, String> getPrefixes() {
|
||||
synchronized (prefixes) {
|
||||
return ImmutableSortedMap.copyOfSorted(prefixes);
|
||||
}
|
||||
}
|
||||
|
||||
public SortedMap<Integer, String> getSuffixes() {
|
||||
synchronized (suffixes) {
|
||||
return ImmutableSortedMap.copyOfSorted(suffixes);
|
||||
}
|
||||
}
|
||||
|
||||
public String getPrefix() {
|
||||
synchronized (prefixes) {
|
||||
if (prefixes.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return prefixes.get(prefixes.firstKey());
|
||||
}
|
||||
}
|
||||
|
||||
public String getSuffix() {
|
||||
synchronized (suffixes) {
|
||||
if (suffixes.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return suffixes.get(suffixes.firstKey());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -33,14 +33,24 @@ import me.lucko.luckperms.common.users.User;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
/**
|
||||
* Holds a user's cached permissions for a given context
|
||||
*/
|
||||
public class PermissionData {
|
||||
private final Contexts contexts;
|
||||
|
||||
/**
|
||||
* The raw set of permission strings.
|
||||
*/
|
||||
private final Map<String, Boolean> permissions;
|
||||
|
||||
/**
|
||||
* The calculator instance responsible for resolving the raw permission strings in the permission map.
|
||||
* This calculator will attempt to resolve all regex/wildcard permissions, as well as account for
|
||||
* defaults & attachment permissions (if applicable.)
|
||||
*/
|
||||
private final PermissionCalculator calculator;
|
||||
|
||||
public PermissionData(Contexts contexts, User user, CalculatorFactory calculatorFactory) {
|
||||
this.contexts = contexts;
|
||||
permissions = new ConcurrentHashMap<>();
|
||||
calculator = calculatorFactory.build(contexts, user, permissions);
|
||||
}
|
||||
@ -56,20 +66,7 @@ public class PermissionData {
|
||||
}
|
||||
|
||||
public void comparePermissions(Map<String, Boolean> toApply) {
|
||||
boolean different = false;
|
||||
if (toApply.size() != permissions.size()) {
|
||||
different = true;
|
||||
} else {
|
||||
for (Map.Entry<String, Boolean> e : permissions.entrySet()) {
|
||||
if (toApply.containsKey(e.getKey()) && toApply.get(e.getKey()) == e.getValue()) {
|
||||
continue;
|
||||
}
|
||||
different = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (different) {
|
||||
if (!permissions.equals(toApply)) {
|
||||
setPermissions(toApply);
|
||||
}
|
||||
}
|
||||
@ -79,11 +76,6 @@ public class PermissionData {
|
||||
}
|
||||
|
||||
public Tristate getPermissionValue(@NonNull String permission) {
|
||||
Tristate t = calculator.getPermissionValue(permission);
|
||||
if (t != Tristate.UNDEFINED) {
|
||||
return Tristate.fromBoolean(t.asBoolean());
|
||||
} else {
|
||||
return Tristate.UNDEFINED;
|
||||
}
|
||||
return calculator.getPermissionValue(permission);
|
||||
}
|
||||
}
|
||||
|
@ -31,28 +31,72 @@ import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
/**
|
||||
* Holds an easily accessible cache of a user's data in a number of contexts
|
||||
*/
|
||||
@RequiredArgsConstructor
|
||||
public class UserData {
|
||||
|
||||
/**
|
||||
* The user whom this data instance is representing
|
||||
*/
|
||||
private final User user;
|
||||
|
||||
/**
|
||||
* A provider of {@link me.lucko.luckperms.common.calculators.PermissionCalculator}s for the instance
|
||||
*/
|
||||
private final CalculatorFactory calculatorFactory;
|
||||
|
||||
private final Map<Contexts, PermissionData> permission = new ConcurrentHashMap<>();
|
||||
private final Map<Contexts, MetaData> meta = new ConcurrentHashMap<>();
|
||||
|
||||
/**
|
||||
* 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) {
|
||||
return permission.computeIfAbsent(contexts, this::calculatePermissions);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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) {
|
||||
return meta.computeIfAbsent(contexts, this::calculateMeta);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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);
|
||||
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);
|
||||
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) {
|
||||
permission.compute(contexts, (c, data) -> {
|
||||
if (data == null) {
|
||||
@ -64,16 +108,11 @@ public class UserData {
|
||||
});
|
||||
}
|
||||
|
||||
public void recalculatePermissions() {
|
||||
permission.keySet().forEach(this::recalculatePermissions);
|
||||
}
|
||||
|
||||
public MetaData calculateMeta(Contexts contexts) {
|
||||
MetaData data = new MetaData(contexts);
|
||||
data.loadMeta(user.getAllNodes(null, contexts));
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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) {
|
||||
meta.compute(contexts, (c, data) -> {
|
||||
if (data == null) {
|
||||
@ -85,14 +124,33 @@ public class UserData {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls {@link #recalculatePermissions(Contexts)} for all current loaded contexts
|
||||
*/
|
||||
public void recalculatePermissions() {
|
||||
permission.keySet().forEach(this::recalculatePermissions);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls {@link #recalculateMeta(Contexts)} for all current loaded contexts
|
||||
*/
|
||||
public void recalculateMeta() {
|
||||
meta.keySet().forEach(this::recalculateMeta);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls {@link #preCalculate(Contexts)} for the given contexts
|
||||
* @param contexts a set of contexts
|
||||
*/
|
||||
public void preCalculate(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) {
|
||||
getPermissionData(contexts);
|
||||
getMetaData(contexts);
|
||||
|
@ -36,10 +36,7 @@ public class MapProcessor implements PermissionProcessor {
|
||||
|
||||
@Override
|
||||
public Tristate hasPermission(String permission) {
|
||||
if (map.containsKey(permission)) {
|
||||
return Tristate.fromBoolean(map.get(permission));
|
||||
}
|
||||
|
||||
return Tristate.UNDEFINED;
|
||||
Boolean b = map.get(permission);
|
||||
return b == null ? Tristate.UNDEFINED : Tristate.fromBoolean(b);
|
||||
}
|
||||
}
|
||||
|
@ -38,43 +38,31 @@ public class WildcardProcessor implements PermissionProcessor {
|
||||
public Tristate hasPermission(String permission) {
|
||||
String node = permission;
|
||||
|
||||
while (node.contains(".")) {
|
||||
while (true) {
|
||||
int endIndex = node.lastIndexOf('.');
|
||||
if (endIndex == -1) {
|
||||
break;
|
||||
}
|
||||
|
||||
node = node.substring(0, endIndex);
|
||||
if (!isEmpty(node)) {
|
||||
if (map.containsKey(node + ".*")) {
|
||||
return Tristate.fromBoolean(map.get(node + ".*"));
|
||||
if (!node.isEmpty()) {
|
||||
Boolean b = map.get(node + ".*");
|
||||
if (b != null) {
|
||||
return Tristate.fromBoolean(b);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (map.containsKey("'*'")) {
|
||||
return Tristate.fromBoolean(map.get("'*'"));
|
||||
Boolean b = map.get("'*'");
|
||||
if (b != null) {
|
||||
return Tristate.fromBoolean(b);
|
||||
}
|
||||
|
||||
if (map.containsKey("*")) {
|
||||
return Tristate.fromBoolean(map.get("*"));
|
||||
b = map.get("*");
|
||||
if (b != null) {
|
||||
return Tristate.fromBoolean(b);
|
||||
}
|
||||
|
||||
return Tristate.UNDEFINED;
|
||||
}
|
||||
|
||||
private static boolean isEmpty(String s) {
|
||||
if (s.equals("")) {
|
||||
return true;
|
||||
}
|
||||
|
||||
char[] chars = s.toCharArray();
|
||||
for (char c : chars) {
|
||||
if (c != '.') {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -41,12 +41,12 @@ public class DefaultsProcessor implements PermissionProcessor {
|
||||
public me.lucko.luckperms.api.Tristate hasPermission(String permission) {
|
||||
Tristate t = service.getUserSubjects().getDefaults().getPermissionValue(contexts, permission);
|
||||
if (t != Tristate.UNDEFINED) {
|
||||
return convertTristate(Tristate.fromBoolean(t.asBoolean()));
|
||||
return convertTristate(t);
|
||||
}
|
||||
|
||||
Tristate t2 = service.getDefaults().getPermissionValue(contexts, permission);
|
||||
if (t2 != Tristate.UNDEFINED) {
|
||||
return convertTristate(Tristate.fromBoolean(t.asBoolean()));
|
||||
return convertTristate(t);
|
||||
}
|
||||
|
||||
return me.lucko.luckperms.api.Tristate.UNDEFINED;
|
||||
|
@ -24,6 +24,7 @@ package me.lucko.luckperms.sponge.calculators;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import me.lucko.luckperms.api.Tristate;
|
||||
import me.lucko.luckperms.common.calculators.PermissionProcessor;
|
||||
|
||||
import java.util.Map;
|
||||
@ -35,46 +36,24 @@ public class SpongeWildcardProcessor implements PermissionProcessor {
|
||||
private final Map<String, Boolean> map;
|
||||
|
||||
@Override
|
||||
public me.lucko.luckperms.api.Tristate hasPermission(String permission) {
|
||||
public Tristate hasPermission(String permission) {
|
||||
String node = permission;
|
||||
|
||||
while (node.contains(".")) {
|
||||
while (true) {
|
||||
int endIndex = node.lastIndexOf('.');
|
||||
if (endIndex == -1) {
|
||||
break;
|
||||
}
|
||||
|
||||
node = node.substring(0, endIndex);
|
||||
if (!isEmpty(node)) {
|
||||
if (map.containsKey(node)) {
|
||||
return me.lucko.luckperms.api.Tristate.fromBoolean(map.get(node));
|
||||
if (!node.isEmpty()) {
|
||||
Boolean b = map.get(node);
|
||||
if (b != null) {
|
||||
return Tristate.fromBoolean(b);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (map.containsKey("'*'")) {
|
||||
return me.lucko.luckperms.api.Tristate.fromBoolean(map.get("'*'"));
|
||||
}
|
||||
|
||||
if (map.containsKey("*")) {
|
||||
return me.lucko.luckperms.api.Tristate.fromBoolean(map.get("*"));
|
||||
}
|
||||
|
||||
return me.lucko.luckperms.api.Tristate.UNDEFINED;
|
||||
}
|
||||
|
||||
private static boolean isEmpty(String s) {
|
||||
if (s.equals("")) {
|
||||
return true;
|
||||
}
|
||||
|
||||
char[] chars = s.toCharArray();
|
||||
for (char c : chars) {
|
||||
if (c != '.') {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
return Tristate.UNDEFINED;
|
||||
}
|
||||
}
|
||||
|
@ -24,12 +24,12 @@ package me.lucko.luckperms.sponge.contexts;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import me.lucko.luckperms.api.context.ContextCalculator;
|
||||
import me.lucko.luckperms.sponge.service.LuckPermsService;
|
||||
import org.spongepowered.api.service.context.Context;
|
||||
import org.spongepowered.api.service.permission.Subject;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@AllArgsConstructor
|
||||
public class SpongeCalculatorLink extends ContextCalculator<Subject> {
|
||||
@ -37,10 +37,11 @@ public class SpongeCalculatorLink extends ContextCalculator<Subject> {
|
||||
|
||||
@Override
|
||||
public Map<String, String> giveApplicableContext(Subject subject, Map<String, String> accumulator) {
|
||||
Set<Context> contexts = accumulator.entrySet().stream().map(e -> new Context(e.getKey(), e.getValue())).collect(Collectors.toSet());
|
||||
Set<Context> contexts = LuckPermsService.convertContexts(accumulator);
|
||||
calculator.accumulateContexts(subject, contexts);
|
||||
|
||||
contexts.forEach(c -> accumulator.put(c.getKey(), c.getValue()));
|
||||
accumulator.clear();
|
||||
accumulator.putAll(LuckPermsService.convertContexts(contexts));
|
||||
return accumulator;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user