From a3ebf86f6b2d8e06b53e978092a8407325c987e7 Mon Sep 17 00:00:00 2001 From: Luck Date: Sun, 28 Aug 2016 14:57:03 +0100 Subject: [PATCH] More progress towards 1.6: implement PermissionService --- .../me/lucko/luckperms/api/LuckPermsApi.java | 1 + .../java/me/lucko/luckperms/api/Node.java | 40 + .../lucko/luckperms/api/PermissionHolder.java | 7 +- .../me/lucko/luckperms/api/data/Callback.java | 2 +- .../LuckPermsPlaceholderExpansion.java | 1 + .../luckperms/api/vault/VaultChatHook.java | 151 ++-- .../java/me/lucko/luckperms/utils/Node.java | 89 +- .../sponge}/LuckPermsService.java | 13 +- .../api/sponge/LuckPermsSubject.java | 837 ++++++++++++++++++ .../sponge}/collections/GroupCollection.java | 10 +- .../sponge}/collections/UserCollection.java | 13 +- .../sponge}/simple/SimpleCollection.java | 4 +- .../sponge}/simple/SimpleSubject.java | 42 +- .../service/wrapping/LuckPermsSubject.java | 464 ---------- 14 files changed, 1091 insertions(+), 583 deletions(-) rename sponge/src/main/java/me/lucko/luckperms/{service => api/sponge}/LuckPermsService.java (93%) create mode 100644 sponge/src/main/java/me/lucko/luckperms/api/sponge/LuckPermsSubject.java rename sponge/src/main/java/me/lucko/luckperms/{service => api/sponge}/collections/GroupCollection.java (92%) rename sponge/src/main/java/me/lucko/luckperms/{service => api/sponge}/collections/UserCollection.java (89%) rename sponge/src/main/java/me/lucko/luckperms/{service => api/sponge}/simple/SimpleCollection.java (96%) rename sponge/src/main/java/me/lucko/luckperms/{service => api/sponge}/simple/SimpleSubject.java (73%) delete mode 100644 sponge/src/main/java/me/lucko/luckperms/service/wrapping/LuckPermsSubject.java diff --git a/api/src/main/java/me/lucko/luckperms/api/LuckPermsApi.java b/api/src/main/java/me/lucko/luckperms/api/LuckPermsApi.java index 4b4cd162..ee8533d4 100644 --- a/api/src/main/java/me/lucko/luckperms/api/LuckPermsApi.java +++ b/api/src/main/java/me/lucko/luckperms/api/LuckPermsApi.java @@ -180,6 +180,7 @@ public interface LuckPermsApi { * @param permission the main permission node to build * @return a {@link Node.Builder} instance * @throws IllegalArgumentException if the permission is invalid + * @since 1.6 */ Node.Builder buildNode(String permission) throws IllegalArgumentException; diff --git a/api/src/main/java/me/lucko/luckperms/api/Node.java b/api/src/main/java/me/lucko/luckperms/api/Node.java index ad9b2a57..8d0a460a 100644 --- a/api/src/main/java/me/lucko/luckperms/api/Node.java +++ b/api/src/main/java/me/lucko/luckperms/api/Node.java @@ -29,6 +29,8 @@ import java.util.Optional; /** * Represents an immutable node object + *

Use {@link LuckPermsApi#buildNode(String)} to get an instance. + * @since 1.6 */ public interface Node extends Map.Entry { @@ -201,6 +203,42 @@ public interface Node extends Map.Entry { */ int getWildcardLevel(); + /** + * @return true if this node is a meta node + */ + boolean isMeta(); + + /** + * Gets the meta value from this node + * @return the meta value + * @throws IllegalStateException if this node is not a meta node + */ + Map.Entry getMeta(); + + /** + * @return true if this node is a prefix node + */ + boolean isPrefix(); + + /** + * Gets the prefix value from this node + * @return the prefix value + * @throws IllegalStateException if this node is a not a prefix node + */ + Map.Entry getPrefix(); + + /** + * @return true if this node is a suffix node + */ + boolean isSuffix(); + + /** + * Gets the suffix value from this node + * @return the suffix value + * @throws IllegalStateException if this node is a not a suffix node + */ + Map.Entry getSuffix(); + /** * Similar to {@link #equals(Object)}, except doesn't take note of the value * @param node the other node @@ -229,6 +267,8 @@ public interface Node extends Map.Entry { Builder setWorld(String world); Builder setServer(String server) throws IllegalArgumentException; Builder withExtraContext(String key, String value); + Builder withExtraContext(Map map); + Builder withExtraContext(Map.Entry entry); Node build(); } diff --git a/api/src/main/java/me/lucko/luckperms/api/PermissionHolder.java b/api/src/main/java/me/lucko/luckperms/api/PermissionHolder.java index 1abb8b01..da0f0bdb 100644 --- a/api/src/main/java/me/lucko/luckperms/api/PermissionHolder.java +++ b/api/src/main/java/me/lucko/luckperms/api/PermissionHolder.java @@ -31,7 +31,7 @@ import java.util.Set; import java.util.SortedSet; /** - * Wrapper interface for internal PermissionHolder (object/group) instances + * Wrapper interface for internal PermissionHolder (user/group) instances */ @SuppressWarnings("unused") public interface PermissionHolder { @@ -260,11 +260,10 @@ public interface PermissionHolder { * Whenever a user logs out of the server, or the server restarts, this permission will disappear. * It is never saved to the datastore, and therefore will not apply on other servers. * - * This is useful if you want to temporarily set a permission for a user while they're online, but don't + *

This is useful if you want to temporarily set a permission for a user while they're online, but don't * want it to persist, and have to worry about removing it when they log out. * - * For unsetting a transient permission, see {@link #unsetTransientPermission(Node)} - * + *

For unsetting a transient permission, see {@link #unsetTransientPermission(Node)} * @param node The node to be set * @throws ObjectAlreadyHasException if the object already has the permission * @throws NullPointerException if the node is null diff --git a/api/src/main/java/me/lucko/luckperms/api/data/Callback.java b/api/src/main/java/me/lucko/luckperms/api/data/Callback.java index 050592be..5a4f5dcd 100644 --- a/api/src/main/java/me/lucko/luckperms/api/data/Callback.java +++ b/api/src/main/java/me/lucko/luckperms/api/data/Callback.java @@ -26,7 +26,7 @@ import java.util.function.Consumer; /** * A callback used to wait for the completion of asynchronous operations. - * All callbacks are ran on the main Bukkit server thread. + * All callbacks are ran on the main server thread. * @param the return type */ public interface Callback { diff --git a/bukkit-placeholders/src/main/java/me/lucko/luckperms/api/placeholders/LuckPermsPlaceholderExpansion.java b/bukkit-placeholders/src/main/java/me/lucko/luckperms/api/placeholders/LuckPermsPlaceholderExpansion.java index 2a52f889..a86e46b0 100644 --- a/bukkit-placeholders/src/main/java/me/lucko/luckperms/api/placeholders/LuckPermsPlaceholderExpansion.java +++ b/bukkit-placeholders/src/main/java/me/lucko/luckperms/api/placeholders/LuckPermsPlaceholderExpansion.java @@ -51,6 +51,7 @@ import java.util.regex.Pattern; * - suffix * - meta_ */ +@SuppressWarnings("deprecation") public class LuckPermsPlaceholderExpansion extends PlaceholderExpansion { private static final String IDENTIFIER = "luckperms"; private static final String PLUGIN_NAME = "LuckPerms"; diff --git a/bukkit/src/main/java/me/lucko/luckperms/api/vault/VaultChatHook.java b/bukkit/src/main/java/me/lucko/luckperms/api/vault/VaultChatHook.java index 45613a75..fbece153 100644 --- a/bukkit/src/main/java/me/lucko/luckperms/api/vault/VaultChatHook.java +++ b/bukkit/src/main/java/me/lucko/luckperms/api/vault/VaultChatHook.java @@ -25,16 +25,14 @@ package me.lucko.luckperms.api.vault; import lombok.NonNull; import lombok.Setter; import me.lucko.luckperms.LPBukkitPlugin; -import me.lucko.luckperms.constants.Patterns; +import me.lucko.luckperms.api.Node; import me.lucko.luckperms.core.PermissionHolder; import me.lucko.luckperms.exceptions.ObjectAlreadyHasException; import me.lucko.luckperms.groups.Group; import me.lucko.luckperms.users.User; import net.milkbowl.vault.chat.Chat; -import java.util.Collections; import java.util.Map; -import java.util.regex.Pattern; import static me.lucko.luckperms.utils.ArgumentChecker.escapeCharacters; import static me.lucko.luckperms.utils.ArgumentChecker.unescapeCharacters; @@ -58,8 +56,6 @@ import static me.lucko.luckperms.utils.ArgumentChecker.unescapeCharacters; * Registered on normal priority so other plugins can override. */ class VaultChatHook extends Chat { - private static final Pattern PREFIX_PATTERN = Pattern.compile("(?i)prefix\\.\\d+\\..*"); - private static final Pattern SUFFIX_PATTERN = Pattern.compile("(?i)suffix\\.\\d+\\..*"); @Setter private LPBukkitPlugin plugin; @@ -103,24 +99,24 @@ class VaultChatHook extends Chat { if (node.equals("")) return defaultValue; node = escapeCharacters(node); - for (Map.Entry e : holder.exportNodes("global", world, null, true, false, Collections.emptyList()).entrySet()) { - if (!e.getValue()) continue; - - String[] parts = Patterns.DOT.split(e.getKey(), 3); - if (parts.length < 3) continue; - - if (!parts[0].equalsIgnoreCase("meta")) { + for (Node n : holder.getPermissions()) { + if (!n.isMeta()) { continue; } - if (!parts[1].equalsIgnoreCase(node)) { + if (!n.shouldApplyOnWorld(world, true, false)) { continue; } - try { - return Integer.parseInt(unescapeCharacters(parts[2])); - } catch (Throwable t) { - return defaultValue; + Map.Entry meta = n.getMeta(); + if (meta.getKey().equalsIgnoreCase(node)) { + + try { + return Integer.parseInt(unescapeCharacters(meta.getValue())); + } catch (Throwable t) { + return defaultValue; + } + } } @@ -132,24 +128,24 @@ class VaultChatHook extends Chat { if (node.equals("")) return defaultValue; node = escapeCharacters(node); - for (Map.Entry e : holder.exportNodes("global", world, null, true, false, Collections.emptyList()).entrySet()) { - if (!e.getValue()) continue; - - String[] parts = Patterns.DOT.split(e.getKey(), 3); - if (parts.length < 3) continue; - - if (!parts[0].equalsIgnoreCase("meta")) { + for (Node n : holder.getPermissions()) { + if (!n.isMeta()) { continue; } - if (!parts[1].equalsIgnoreCase(node)) { + if (!n.shouldApplyOnWorld(world, true, false)) { continue; } - try { - return Double.parseDouble(unescapeCharacters(parts[2])); - } catch (Throwable t) { - return defaultValue; + Map.Entry meta = n.getMeta(); + if (meta.getKey().equalsIgnoreCase(node)) { + + try { + return Double.parseDouble(unescapeCharacters(meta.getValue())); + } catch (Throwable t) { + return defaultValue; + } + } } @@ -161,24 +157,24 @@ class VaultChatHook extends Chat { if (node.equals("")) return defaultValue; node = escapeCharacters(node); - for (Map.Entry e : holder.exportNodes("global", world, null, true, false, Collections.emptyList()).entrySet()) { - if (!e.getValue()) continue; - - String[] parts = Patterns.DOT.split(e.getKey(), 3); - if (parts.length < 3) continue; - - if (!parts[0].equalsIgnoreCase("meta")) { + for (Node n : holder.getPermissions()) { + if (!n.isMeta()) { continue; } - if (!parts[1].equalsIgnoreCase(node)) { + if (!n.shouldApplyOnWorld(world, true, false)) { continue; } - try { - return Boolean.parseBoolean(unescapeCharacters(parts[2])); - } catch (Throwable t) { - return defaultValue; + Map.Entry meta = n.getMeta(); + if (meta.getKey().equalsIgnoreCase(node)) { + + try { + return Boolean.parseBoolean(unescapeCharacters(meta.getValue())); + } catch (Throwable t) { + return defaultValue; + } + } } @@ -190,41 +186,68 @@ class VaultChatHook extends Chat { if (node.equals("")) return defaultValue; node = escapeCharacters(node); - for (Map.Entry e : holder.exportNodes("global", world, null, true, false, Collections.emptyList()).entrySet()) { - if (!e.getValue()) continue; - - String[] parts = Patterns.DOT.split(e.getKey(), 3); - if (parts.length < 3) continue; - - if (!parts[0].equalsIgnoreCase("meta")) { + for (Node n : holder.getPermissions()) { + if (!n.getValue()) { continue; } - if (!parts[1].equalsIgnoreCase(node)) { + if (!n.isMeta()) { continue; } - return unescapeCharacters(parts[2]); + if (!n.shouldApplyOnWorld(world, true, false)) { + continue; + } + + Map.Entry meta = n.getMeta(); + if (meta.getKey().equalsIgnoreCase(node)) { + + try { + return unescapeCharacters(meta.getValue()); + } catch (Throwable t) { + return defaultValue; + } + + } } return defaultValue; } - private static String getChatMeta(Pattern pattern, PermissionHolder holder, String world) { + private static String getChatMeta(boolean prefix, PermissionHolder holder, String world) { if (holder == null) return ""; - int priority = 0; + int priority = -1000; String meta = null; - for (Map.Entry e : holder.getLocalPermissions("global", world, null).entrySet()) { - if (!e.getValue()) continue; - if (pattern.matcher(e.getKey()).matches()) { - String[] parts = Patterns.DOT.split(e.getKey(), 3); - int p = Integer.parseInt(parts[1]); + for (Node n : holder.getAllNodes(null)) { + if (!n.getValue()) { + continue; + } - if (meta == null || p > priority) { - meta = parts[2]; - priority = p; + if (!n.shouldApplyOnWorld(world, true, false)) { + continue; + } + + if (prefix) { + if (!n.isPrefix()) { + continue; + } + + Map.Entry prefixValue = n.getPrefix(); + if (prefixValue.getKey() > priority) { + meta = prefixValue.getValue(); + priority = prefixValue.getKey(); + } + } else { + if (!n.isSuffix()) { + continue; + } + + Map.Entry suffixValue = n.getSuffix(); + if (suffixValue.getKey() > priority) { + meta = suffixValue.getValue(); + priority = suffixValue.getKey(); } } } @@ -234,7 +257,7 @@ class VaultChatHook extends Chat { public String getPlayerPrefix(String world, @NonNull String player) { final User user = plugin.getUserManager().get(player); - return getChatMeta(PREFIX_PATTERN, user, world); + return getChatMeta(true, user, world); } public void setPlayerPrefix(String world, @NonNull String player, @NonNull String prefix) { @@ -252,7 +275,7 @@ class VaultChatHook extends Chat { public String getPlayerSuffix(String world, @NonNull String player) { final User user = plugin.getUserManager().get(player); - return getChatMeta(SUFFIX_PATTERN, user, world); + return getChatMeta(false, user, world); } public void setPlayerSuffix(String world, @NonNull String player, @NonNull String suffix) { @@ -270,7 +293,7 @@ class VaultChatHook extends Chat { public String getGroupPrefix(String world, @NonNull String group) { final Group g = plugin.getGroupManager().get(group); - return getChatMeta(PREFIX_PATTERN, g, world); + return getChatMeta(false, g, world); } public void setGroupPrefix(String world, @NonNull String group, @NonNull String prefix) { @@ -288,7 +311,7 @@ class VaultChatHook extends Chat { public String getGroupSuffix(String world, @NonNull String group) { final Group g = plugin.getGroupManager().get(group); - return getChatMeta(SUFFIX_PATTERN, g, world); + return getChatMeta(false, g, world); } public void setGroupSuffix(String world, @NonNull String group, @NonNull String suffix) { diff --git a/common/src/main/java/me/lucko/luckperms/utils/Node.java b/common/src/main/java/me/lucko/luckperms/utils/Node.java index 5f1316ba..a04a619d 100644 --- a/common/src/main/java/me/lucko/luckperms/utils/Node.java +++ b/common/src/main/java/me/lucko/luckperms/utils/Node.java @@ -38,6 +38,9 @@ import java.util.stream.Collectors; @ToString @EqualsAndHashCode public class Node implements me.lucko.luckperms.api.Node { + private static final Pattern PREFIX_PATTERN = Pattern.compile("(?i)prefix\\.\\d+\\..*"); + private static final Pattern SUFFIX_PATTERN = Pattern.compile("(?i)suffix\\.\\d+\\..*"); + public static me.lucko.luckperms.api.Node fromSerialisedNode(String s, Boolean b) { return builderFromSerialisedNode(s, b).build(); } @@ -234,6 +237,18 @@ public class Node implements me.lucko.luckperms.api.Node { } for (Map.Entry c : context.entrySet()) { + if (c.getKey().equals("server")) { + if (shouldApplyOnServer(c.getValue(), false, false)) { + return false; + } + } + + if (c.getKey().equals("world")) { + if (shouldApplyOnWorld(c.getValue(), false, false)) { + return false; + } + } + if (!getExtraContexts().containsKey(c.getKey())) { return false; } @@ -405,6 +420,55 @@ public class Node implements me.lucko.luckperms.api.Node { return (int) getPermission().chars().filter(num -> num == Character.getNumericValue('.')).count(); } + @Override + public boolean isMeta() { + return getPermission().matches("meta\\..*\\..*"); + } + + @Override + public Map.Entry getMeta() { + if (!isMeta()) { + throw new IllegalStateException(); + } + + String[] metaPart = getPermission().substring("meta.".length()).split("\\.", 2); + return new AbstractMap.SimpleEntry<>(metaPart[0], metaPart[1]); + } + + @Override + public boolean isPrefix() { + return PREFIX_PATTERN.matcher(getPermission()).matches(); + } + + @Override + public Map.Entry getPrefix() { + if (!isPrefix()) { + throw new IllegalStateException(); + } + + String[] prefixPart = Patterns.DOT.split(getPermission().substring("prefix.".length()), 2); + Integer i = Integer.parseInt(prefixPart[0]); + + return new AbstractMap.SimpleEntry<>(i, prefixPart[1]); + } + + @Override + public boolean isSuffix() { + return SUFFIX_PATTERN.matcher(getPermission()).matches(); + } + + @Override + public Map.Entry getSuffix() { + if (!isPrefix()) { + throw new IllegalStateException(); + } + + String[] suffixPart = Patterns.DOT.split(getPermission().substring("suffix.".length()), 2); + Integer i = Integer.parseInt(suffixPart[0]); + + return new AbstractMap.SimpleEntry<>(i, suffixPart[1]); + } + @Override public boolean equalsIgnoringValue(me.lucko.luckperms.api.Node other) { if (!other.getPermission().equalsIgnoreCase(this.getPermission())) { @@ -581,7 +645,30 @@ public class Node implements me.lucko.luckperms.api.Node { @Override public me.lucko.luckperms.api.Node.Builder withExtraContext(@NonNull String key, @NonNull String value) { - this.extraContexts.put(key, value); + switch (key) { + case "server": + setServer(value); + break; + case "world": + setWorld(value); + break; + default: + this.extraContexts.put(key, value); + break; + } + + return this; + } + + @Override + public me.lucko.luckperms.api.Node.Builder withExtraContext(Map map) { + map.entrySet().forEach(this::withExtraContext); + return this; + } + + @Override + public me.lucko.luckperms.api.Node.Builder withExtraContext(Map.Entry entry) { + withExtraContext(entry.getKey(), entry.getValue()); return this; } diff --git a/sponge/src/main/java/me/lucko/luckperms/service/LuckPermsService.java b/sponge/src/main/java/me/lucko/luckperms/api/sponge/LuckPermsService.java similarity index 93% rename from sponge/src/main/java/me/lucko/luckperms/service/LuckPermsService.java rename to sponge/src/main/java/me/lucko/luckperms/api/sponge/LuckPermsService.java index 4c57b9e7..b29cb80b 100644 --- a/sponge/src/main/java/me/lucko/luckperms/service/LuckPermsService.java +++ b/sponge/src/main/java/me/lucko/luckperms/api/sponge/LuckPermsService.java @@ -20,14 +20,14 @@ * SOFTWARE. */ -package me.lucko.luckperms.service; +package me.lucko.luckperms.api.sponge; import com.google.common.collect.ImmutableSet; import lombok.*; import me.lucko.luckperms.LPSpongePlugin; -import me.lucko.luckperms.service.collections.GroupCollection; -import me.lucko.luckperms.service.collections.UserCollection; -import me.lucko.luckperms.service.simple.SimpleCollection; +import me.lucko.luckperms.api.sponge.collections.GroupCollection; +import me.lucko.luckperms.api.sponge.collections.UserCollection; +import me.lucko.luckperms.api.sponge.simple.SimpleCollection; import org.spongepowered.api.plugin.PluginContainer; import org.spongepowered.api.service.context.ContextCalculator; import org.spongepowered.api.service.permission.*; @@ -41,6 +41,7 @@ import java.util.stream.Collectors; public class LuckPermsService implements PermissionService { public static final String SERVER_CONTEXT = "server"; + @Getter private final LPSpongePlugin plugin; @Getter @@ -103,7 +104,7 @@ public class LuckPermsService implements PermissionService { } @Override - public Optional getDescription(String s) { + public Optional getDescription(@NonNull String s) { for (PermissionDescription d : descriptionSet) { if (d.getId().equals(s)) { return Optional.of(d); @@ -119,7 +120,7 @@ public class LuckPermsService implements PermissionService { } @Override - public void registerContextCalculator(ContextCalculator contextCalculator) { + public void registerContextCalculator(@NonNull ContextCalculator contextCalculator) { contextCalculators.add(contextCalculator); } diff --git a/sponge/src/main/java/me/lucko/luckperms/api/sponge/LuckPermsSubject.java b/sponge/src/main/java/me/lucko/luckperms/api/sponge/LuckPermsSubject.java new file mode 100644 index 00000000..cc802df8 --- /dev/null +++ b/sponge/src/main/java/me/lucko/luckperms/api/sponge/LuckPermsSubject.java @@ -0,0 +1,837 @@ +/* + * Copyright (c) 2016 Lucko (Luck) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package me.lucko.luckperms.api.sponge; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NonNull; +import me.lucko.luckperms.api.Node; +import me.lucko.luckperms.api.data.Callback; +import me.lucko.luckperms.core.PermissionHolder; +import me.lucko.luckperms.exceptions.ObjectAlreadyHasException; +import me.lucko.luckperms.exceptions.ObjectLacksException; +import me.lucko.luckperms.groups.Group; +import me.lucko.luckperms.users.User; +import org.spongepowered.api.Sponge; +import org.spongepowered.api.command.CommandSource; +import org.spongepowered.api.entity.living.player.Player; +import org.spongepowered.api.service.context.Context; +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.*; +import java.util.stream.Collectors; + +import static me.lucko.luckperms.utils.ArgumentChecker.escapeCharacters; +import static me.lucko.luckperms.utils.ArgumentChecker.unescapeCharacters; + +@AllArgsConstructor +public class LuckPermsSubject implements Subject { + private final EnduringData enduringData; + private final TransientData transientData; + private final LuckPermsService service; + + public LuckPermsSubject(PermissionHolder holder, LuckPermsService service) { + this.enduringData = new EnduringData(this, service, holder); + this.transientData = new TransientData(service, holder); + this.service = service; + } + + private void objectSave(PermissionHolder t) { + if (t instanceof User) { + ((User) t).refreshPermissions(); + service.getPlugin().getDatastore().saveUser(((User) t), Callback.empty()); + } + if (t instanceof Group) { + service.getPlugin().getDatastore().saveGroup(((Group) t), c -> service.getPlugin().runUpdateTask()); + } + } + + @Override + public String getIdentifier() { + return enduringData.getHolder().getObjectName(); + } + + @Override + public Optional getCommandSource() { + if (enduringData.getHolder() instanceof User) { + final UUID uuid = ((User) enduringData.getHolder()).getUuid(); + + Optional p = Sponge.getServer().getPlayer(uuid); + if (p.isPresent()) { + return Optional.of(p.get()); + } + } + + return Optional.empty(); + } + + @Override + public SubjectCollection getContainingCollection() { + if (enduringData.getHolder() instanceof Group) { + return service.getGroupSubjects(); + } else { + return service.getUserSubjects(); + } + } + + @Override + public SubjectData getSubjectData() { + return enduringData; + } + + @Override + public SubjectData getTransientSubjectData() { + return transientData; + } + + @Override + public boolean hasPermission(@NonNull Set contexts, @NonNull String node) { + return getPermissionValue(contexts, node).asBoolean(); + } + + @Override + public boolean hasPermission(String permission) { + return getPermissionValue(getActiveContexts(), permission).asBoolean(); + } + + @Override + public Tristate getPermissionValue(@NonNull Set contexts, @NonNull String node) { + Map context = new HashMap<>(); + for (Context c : contexts) { + context.put(c.getKey(), c.getValue()); + } + + me.lucko.luckperms.api.Tristate t = enduringData.getHolder().hasPermission(new me.lucko.luckperms.utils.Node.Builder(node).withExtraContext(context).build()); + if (t == me.lucko.luckperms.api.Tristate.UNDEFINED) { + return Tristate.UNDEFINED; + } + if (t == me.lucko.luckperms.api.Tristate.TRUE) { + return Tristate.TRUE; + } + if (t == me.lucko.luckperms.api.Tristate.FALSE) { + return Tristate.FALSE; + } + + return null; + } + + @Override + public boolean isChildOf(@NonNull Subject parent) { + return isChildOf(getActiveContexts(), parent); + } + + @Override + public boolean isChildOf(@NonNull Set contexts, @NonNull Subject parent) { + return parent instanceof PermissionHolder && getPermissionValue(contexts, "group." + parent.getIdentifier()).asBoolean(); + } + + @Override + public List getParents() { + return getParents(getActiveContexts()); + } + + @Override + public List getParents(@NonNull Set contexts) { + List parents = new ArrayList<>(); + parents.addAll(enduringData.getParents(contexts)); + parents.addAll(transientData.getParents(contexts)); + return ImmutableList.copyOf(parents); + } + + @Override + public Optional getOption(Set set, String s) { + Map enduringOptions = enduringData.getOptions(set); + if (enduringOptions.containsKey(s)) { + return Optional.of(enduringOptions.get(s)); + } + + Map transientOptions = enduringData.getOptions(set); + if (transientOptions.containsKey(s)) { + return Optional.of(transientOptions.get(s)); + } + + return Optional.empty(); + } + + @Override + public Optional getOption(String key) { + return getOption(getActiveContexts(), key); + } + + @Override + public Set getActiveContexts() { + return SubjectData.GLOBAL_CONTEXT; + } + + @AllArgsConstructor + public static class EnduringData implements SubjectData { + private final LuckPermsSubject superClass; + private final LuckPermsService service; + + @Getter + private final PermissionHolder holder; + + @Override + public Map, Map> getAllPermissions() { + Map, Map> perms = new HashMap<>(); + + for (Node n : holder.getNodes()) { + Set contexts = n.getExtraContexts().entrySet().stream() + .map(entry -> new Context(entry.getKey(), entry.getValue())) + .collect(Collectors.toSet()); + + if (n.isServerSpecific()) { + contexts.add(new Context(LuckPermsService.SERVER_CONTEXT, n.getServer().get())); + } + + if (n.isWorldSpecific()) { + contexts.add(new Context(Context.WORLD_KEY, n.getWorld().get())); + } + + if (!perms.containsKey(contexts)) { + perms.put(contexts, new HashMap<>()); + } + + perms.get(contexts).put(n.getPermission(), n.getValue()); + } + + return ImmutableMap.copyOf(perms); + } + + @Override + public Map getPermissions(Set set) { + return ImmutableMap.copyOf(getAllPermissions().getOrDefault(set, Collections.emptyMap())); + } + + @Override + public boolean setPermission(Set set, String s, Tristate tristate) { + if (tristate == Tristate.UNDEFINED) { + // Unset + Node.Builder builder = new me.lucko.luckperms.utils.Node.Builder(s); + + for (Context ct : set) { + builder.withExtraContext(ct.getKey(), ct.getValue()); + } + + try { + holder.unsetPermission(builder.build()); + } catch (ObjectLacksException ignored) {} + superClass.objectSave(holder); + return true; + } + + Node.Builder builder = new me.lucko.luckperms.utils.Node.Builder(s) + .setValue(tristate.asBoolean()); + + for (Context ct : set) { + builder.withExtraContext(ct.getKey(), ct.getValue()); + } + + try { + holder.setPermission(builder.build()); + } catch (ObjectAlreadyHasException ignored) {} + superClass.objectSave(holder); + return true; + } + + @Override + public boolean clearPermissions() { + // TODO re-give default nodes? + + holder.getNodes().clear(); + superClass.objectSave(holder); + return true; + } + + @Override + public boolean clearPermissions(Set set) { + // TODO re-give default nodes? + + Map context = new HashMap<>(); + for (Context c : set) { + context.put(c.getKey(), c.getValue()); + } + + boolean work = false; + Iterator iterator = holder.getNodes().iterator(); + + while (iterator.hasNext()) { + Node entry = iterator.next(); + if (entry.shouldApplyWithContext(context)) { + iterator.remove(); + work = true; + } + } + + superClass.objectSave(holder); + return work; + } + + @Override + public Map, List> getAllParents() { + Map, List> parents = new HashMap<>(); + + for (Node n : holder.getAllNodes(null)) { + if (!n.isGroupNode()) { + continue; + } + + Set contexts = n.getExtraContexts().entrySet().stream() + .map(entry -> new Context(entry.getKey(), entry.getValue())) + .collect(Collectors.toSet()); + + if (n.isServerSpecific()) { + contexts.add(new Context(LuckPermsService.SERVER_CONTEXT, n.getServer().get())); + } + + if (n.isWorldSpecific()) { + contexts.add(new Context(Context.WORLD_KEY, n.getWorld().get())); + } + + if (!parents.containsKey(contexts)) { + parents.put(contexts, new ArrayList<>()); + } + + parents.get(contexts).add(service.getGroupSubjects().get(n.getGroupName())); + } + + return ImmutableMap.copyOf(parents); + } + + @Override + public List getParents(Set contexts) { + return ImmutableList.copyOf(getAllParents().getOrDefault(contexts, Collections.emptyList())); + } + + @Override + public boolean addParent(Set set, Subject subject) { + if (subject instanceof LuckPermsSubject) { + LuckPermsSubject permsSubject = ((LuckPermsSubject) subject); + + Map contexts = set.stream() + .map(context -> new AbstractMap.SimpleEntry<>(context.getKey(), context.getValue())) + .collect(Collectors.toMap(AbstractMap.SimpleEntry::getKey, AbstractMap.SimpleEntry::getValue)); + + try { + holder.setPermission(new me.lucko.luckperms.utils.Node.Builder("group." + permsSubject.getIdentifier()) + .withExtraContext(contexts) + .build()); + } catch (ObjectAlreadyHasException ignored) {} + superClass.objectSave(holder); + } else { + return false; + } + return false; + } + + @Override + public boolean removeParent(Set set, Subject subject) { + if (subject instanceof LuckPermsSubject) { + LuckPermsSubject permsSubject = ((LuckPermsSubject) subject); + + Map contexts = set.stream() + .map(context -> new AbstractMap.SimpleEntry<>(context.getKey(), context.getValue())) + .collect(Collectors.toMap(AbstractMap.SimpleEntry::getKey, AbstractMap.SimpleEntry::getValue)); + + try { + holder.unsetPermission(new me.lucko.luckperms.utils.Node.Builder("group." + permsSubject.getIdentifier()) + .withExtraContext(contexts) + .build()); + } catch (ObjectLacksException ignored) {} + superClass.objectSave(holder); + } else { + return false; + } + return false; + } + + @Override + public boolean clearParents() { + // TODO re-give default nodes? + + boolean work = false; + Iterator iterator = holder.getNodes().iterator(); + + while (iterator.hasNext()) { + Node entry = iterator.next(); + + if (entry.isGroupNode()) { + iterator.remove(); + work = true; + } + } + + superClass.objectSave(holder); + return work; + } + + @Override + public boolean clearParents(Set set) { + // TODO re-give default nodes? + + Map context = new HashMap<>(); + for (Context c : set) { + context.put(c.getKey(), c.getValue()); + } + + boolean work = false; + Iterator iterator = holder.getNodes().iterator(); + + while (iterator.hasNext()) { + Node entry = iterator.next(); + + if (!entry.isGroupNode()) { + continue; + } + + if (entry.shouldApplyWithContext(context)) { + iterator.remove(); + work = true; + } + } + + superClass.objectSave(holder); + return work; + } + + @Override + public Map, Map> getAllOptions() { + Map, Map> options = new HashMap<>(); + + for (Node n : holder.getAllNodes(null)) { + if (!n.isMeta()) { + continue; + } + + Set contexts = n.getExtraContexts().entrySet().stream() + .map(entry -> new Context(entry.getKey(), entry.getValue())) + .collect(Collectors.toSet()); + + if (n.isServerSpecific()) { + contexts.add(new Context(LuckPermsService.SERVER_CONTEXT, n.getServer().get())); + } + + if (n.isWorldSpecific()) { + contexts.add(new Context(Context.WORLD_KEY, n.getWorld().get())); + } + + if (!options.containsKey(contexts)) { + options.put(contexts, new HashMap<>()); + } + + options.get(contexts).put(unescapeCharacters(n.getMeta().getKey()), unescapeCharacters(n.getMeta().getValue())); + } + + return ImmutableMap.copyOf(options); + } + + @Override + public Map getOptions(Set set) { + return ImmutableMap.copyOf(getAllOptions().getOrDefault(set, Collections.emptyMap())); + } + + @Override + public boolean setOption(Set set, String key, String value) { + Map context = new HashMap<>(); + for (Context c : set) { + context.put(c.getKey(), c.getValue()); + } + + key = escapeCharacters(key); + value = escapeCharacters(value); + + try { + holder.setPermission(new me.lucko.luckperms.utils.Node.Builder("meta." + key + "." + value) + .withExtraContext(context) + .build() + ); + } catch (ObjectAlreadyHasException ignored) {} + superClass.objectSave(holder); + return true; + } + + @Override + public boolean clearOptions(Set set) { + Map context = new HashMap<>(); + for (Context c : set) { + context.put(c.getKey(), c.getValue()); + } + + boolean work = false; + Iterator iterator = holder.getNodes().iterator(); + + while (iterator.hasNext()) { + Node entry = iterator.next(); + + if (!entry.isMeta()) { + continue; + } + + if (entry.shouldApplyWithContext(context)) { + iterator.remove(); + work = true; + } + } + + superClass.objectSave(holder); + return work; + } + + @Override + public boolean clearOptions() { + boolean work = false; + Iterator iterator = holder.getNodes().iterator(); + + while (iterator.hasNext()) { + Node entry = iterator.next(); + + if (entry.isMeta()) { + iterator.remove(); + work = true; + } + } + + superClass.objectSave(holder); + return work; + } + } + + @AllArgsConstructor + public static class TransientData implements SubjectData { + private final LuckPermsService service; + + @Getter + private final PermissionHolder holder; + + @Override + public Map, Map> getAllPermissions() { + Map, Map> perms = new HashMap<>(); + + for (Node n : holder.getTransientNodes()) { + Set contexts = n.getExtraContexts().entrySet().stream() + .map(entry -> new Context(entry.getKey(), entry.getValue())) + .collect(Collectors.toSet()); + + if (n.isServerSpecific()) { + contexts.add(new Context(LuckPermsService.SERVER_CONTEXT, n.getServer().get())); + } + + if (n.isWorldSpecific()) { + contexts.add(new Context(Context.WORLD_KEY, n.getWorld().get())); + } + + if (!perms.containsKey(contexts)) { + perms.put(contexts, new HashMap<>()); + } + + perms.get(contexts).put(n.getPermission(), n.getValue()); + } + + return ImmutableMap.copyOf(perms); + } + + @Override + public Map getPermissions(Set set) { + return ImmutableMap.copyOf(getAllPermissions().getOrDefault(set, Collections.emptyMap())); + } + + @Override + public boolean setPermission(Set set, String s, Tristate tristate) { + if (tristate == Tristate.UNDEFINED) { + // Unset + + Node.Builder builder = new me.lucko.luckperms.utils.Node.Builder(s); + + for (Context ct : set) { + builder.withExtraContext(ct.getKey(), ct.getValue()); + } + + try { + holder.unsetTransientPermission(builder.build()); + } catch (ObjectLacksException ignored) {} + return true; + } + + Node.Builder builder = new me.lucko.luckperms.utils.Node.Builder(s) + .setValue(tristate.asBoolean()); + + for (Context ct : set) { + builder.withExtraContext(ct.getKey(), ct.getValue()); + } + + try { + holder.setTransientPermission(builder.build()); + } catch (ObjectAlreadyHasException ignored) {} + return true; + } + + @Override + public boolean clearPermissions() { + holder.getTransientNodes().clear(); + return true; + } + + @Override + public boolean clearPermissions(Set set) { + Map context = new HashMap<>(); + for (Context c : set) { + context.put(c.getKey(), c.getValue()); + } + + boolean work = false; + Iterator iterator = holder.getTransientNodes().iterator(); + + while (iterator.hasNext()) { + Node entry = iterator.next(); + if (entry.shouldApplyWithContext(context)) { + iterator.remove(); + work = true; + } + } + + return work; + } + + @Override + public Map, List> getAllParents() { + Map, List> parents = new HashMap<>(); + + for (Node n : holder.getTransientNodes()) { + if (!n.isGroupNode()) { + continue; + } + + Set contexts = n.getExtraContexts().entrySet().stream() + .map(entry -> new Context(entry.getKey(), entry.getValue())) + .collect(Collectors.toSet()); + + if (n.isServerSpecific()) { + contexts.add(new Context(LuckPermsService.SERVER_CONTEXT, n.getServer().get())); + } + + if (n.isWorldSpecific()) { + contexts.add(new Context(Context.WORLD_KEY, n.getWorld().get())); + } + + if (!parents.containsKey(contexts)) { + parents.put(contexts, new ArrayList<>()); + } + + parents.get(contexts).add(service.getGroupSubjects().get(n.getGroupName())); + } + + return ImmutableMap.copyOf(parents); + } + + @Override + public List getParents(Set contexts) { + return ImmutableList.copyOf(getAllParents().getOrDefault(contexts, Collections.emptyList())); + } + + @Override + public boolean addParent(Set set, Subject subject) { + if (subject instanceof LuckPermsSubject) { + LuckPermsSubject permsSubject = ((LuckPermsSubject) subject); + + Map contexts = set.stream() + .map(context -> new AbstractMap.SimpleEntry<>(context.getKey(), context.getValue())) + .collect(Collectors.toMap(AbstractMap.SimpleEntry::getKey, AbstractMap.SimpleEntry::getValue)); + + try { + holder.setTransientPermission(new me.lucko.luckperms.utils.Node.Builder("group." + permsSubject.getIdentifier()) + .withExtraContext(contexts) + .build()); + } catch (ObjectAlreadyHasException ignored) {} + } else { + return false; + } + return false; + } + + @Override + public boolean removeParent(Set set, Subject subject) { + if (subject instanceof LuckPermsSubject) { + LuckPermsSubject permsSubject = ((LuckPermsSubject) subject); + + Map contexts = set.stream() + .map(context -> new AbstractMap.SimpleEntry<>(context.getKey(), context.getValue())) + .collect(Collectors.toMap(AbstractMap.SimpleEntry::getKey, AbstractMap.SimpleEntry::getValue)); + + try { + holder.unsetTransientPermission(new me.lucko.luckperms.utils.Node.Builder("group." + permsSubject.getIdentifier()) + .withExtraContext(contexts) + .build()); + } catch (ObjectLacksException ignored) {} + } else { + return false; + } + return false; + } + + @Override + public boolean clearParents() { + boolean work = false; + Iterator iterator = holder.getTransientNodes().iterator(); + + while (iterator.hasNext()) { + Node entry = iterator.next(); + + if (entry.isGroupNode()) { + iterator.remove(); + work = true; + } + } + + return work; + } + + @Override + public boolean clearParents(Set set) { + Map context = new HashMap<>(); + for (Context c : set) { + context.put(c.getKey(), c.getValue()); + } + + boolean work = false; + Iterator iterator = holder.getTransientNodes().iterator(); + + while (iterator.hasNext()) { + Node entry = iterator.next(); + + if (!entry.isGroupNode()) { + continue; + } + + if (entry.shouldApplyWithContext(context)) { + iterator.remove(); + work = true; + } + } + + return work; + } + + @Override + public Map, Map> getAllOptions() { + Map, Map> options = new HashMap<>(); + + for (Node n : holder.getTransientNodes()) { + if (!n.isMeta()) { + continue; + } + + Set contexts = n.getExtraContexts().entrySet().stream() + .map(entry -> new Context(entry.getKey(), entry.getValue())) + .collect(Collectors.toSet()); + + if (n.isServerSpecific()) { + contexts.add(new Context(LuckPermsService.SERVER_CONTEXT, n.getServer().get())); + } + + if (n.isWorldSpecific()) { + contexts.add(new Context(Context.WORLD_KEY, n.getWorld().get())); + } + + if (!options.containsKey(contexts)) { + options.put(contexts, new HashMap<>()); + } + + options.get(contexts).put(unescapeCharacters(n.getMeta().getKey()), unescapeCharacters(n.getMeta().getValue())); + } + + return ImmutableMap.copyOf(options); + } + + @Override + public Map getOptions(Set set) { + return ImmutableMap.copyOf(getAllOptions().getOrDefault(set, Collections.emptyMap())); + } + + @Override + public boolean setOption(Set set, String key, String value) { + Map context = new HashMap<>(); + for (Context c : set) { + context.put(c.getKey(), c.getValue()); + } + + key = escapeCharacters(key); + value = escapeCharacters(value); + + try { + holder.setTransientPermission(new me.lucko.luckperms.utils.Node.Builder("meta." + key + "." + value) + .withExtraContext(context) + .build() + ); + } catch (ObjectAlreadyHasException ignored) {} + return true; + } + + @Override + public boolean clearOptions(Set set) { + Map context = new HashMap<>(); + for (Context c : set) { + context.put(c.getKey(), c.getValue()); + } + + boolean work = false; + Iterator iterator = holder.getTransientNodes().iterator(); + + while (iterator.hasNext()) { + Node entry = iterator.next(); + + if (!entry.isMeta()) { + continue; + } + + if (entry.shouldApplyWithContext(context)) { + iterator.remove(); + work = true; + } + } + + return work; + } + + @Override + public boolean clearOptions() { + boolean work = false; + Iterator iterator = holder.getTransientNodes().iterator(); + + while (iterator.hasNext()) { + Node entry = iterator.next(); + + if (entry.isMeta()) { + iterator.remove(); + work = true; + } + } + + return work; + } + } +} diff --git a/sponge/src/main/java/me/lucko/luckperms/service/collections/GroupCollection.java b/sponge/src/main/java/me/lucko/luckperms/api/sponge/collections/GroupCollection.java similarity index 92% rename from sponge/src/main/java/me/lucko/luckperms/service/collections/GroupCollection.java rename to sponge/src/main/java/me/lucko/luckperms/api/sponge/collections/GroupCollection.java index bb6a37d5..4b22b605 100644 --- a/sponge/src/main/java/me/lucko/luckperms/service/collections/GroupCollection.java +++ b/sponge/src/main/java/me/lucko/luckperms/api/sponge/collections/GroupCollection.java @@ -20,14 +20,14 @@ * SOFTWARE. */ -package me.lucko.luckperms.service.collections; +package me.lucko.luckperms.api.sponge.collections; import lombok.AllArgsConstructor; import lombok.NonNull; import me.lucko.luckperms.groups.GroupManager; -import me.lucko.luckperms.service.LuckPermsService; -import me.lucko.luckperms.service.simple.SimpleSubject; -import me.lucko.luckperms.service.wrapping.LuckPermsSubject; +import me.lucko.luckperms.api.sponge.LuckPermsService; +import me.lucko.luckperms.api.sponge.simple.SimpleSubject; +import me.lucko.luckperms.api.sponge.LuckPermsSubject; import org.spongepowered.api.service.context.Context; import org.spongepowered.api.service.permission.PermissionService; import org.spongepowered.api.service.permission.Subject; @@ -86,6 +86,6 @@ public class GroupCollection implements SubjectCollection { @Override public Subject getDefaults() { - return null; + return new SimpleSubject("default", service, this); } } diff --git a/sponge/src/main/java/me/lucko/luckperms/service/collections/UserCollection.java b/sponge/src/main/java/me/lucko/luckperms/api/sponge/collections/UserCollection.java similarity index 89% rename from sponge/src/main/java/me/lucko/luckperms/service/collections/UserCollection.java rename to sponge/src/main/java/me/lucko/luckperms/api/sponge/collections/UserCollection.java index 4109d27c..6bd48c4c 100644 --- a/sponge/src/main/java/me/lucko/luckperms/service/collections/UserCollection.java +++ b/sponge/src/main/java/me/lucko/luckperms/api/sponge/collections/UserCollection.java @@ -20,13 +20,13 @@ * SOFTWARE. */ -package me.lucko.luckperms.service.collections; +package me.lucko.luckperms.api.sponge.collections; import lombok.AllArgsConstructor; import lombok.NonNull; -import me.lucko.luckperms.service.LuckPermsService; -import me.lucko.luckperms.service.simple.SimpleSubject; -import me.lucko.luckperms.service.wrapping.LuckPermsSubject; +import me.lucko.luckperms.api.sponge.LuckPermsService; +import me.lucko.luckperms.api.sponge.simple.SimpleSubject; +import me.lucko.luckperms.api.sponge.LuckPermsSubject; import me.lucko.luckperms.users.User; import me.lucko.luckperms.users.UserManager; import org.spongepowered.api.service.context.Context; @@ -66,7 +66,8 @@ public class UserCollection implements SubjectCollection { } } - // Wtf am I meant to do here? What if no user is loaded? Load it? Create it? + // What am I meant to do here? What if no user is loaded? Load it? Create it? + // If I do load/create it, this method should always be called async??.... errr. return new SimpleSubject(id, service, this); } @@ -104,6 +105,6 @@ public class UserCollection implements SubjectCollection { @Override public Subject getDefaults() { - return null; + return new SimpleSubject("default", service, this); } } diff --git a/sponge/src/main/java/me/lucko/luckperms/service/simple/SimpleCollection.java b/sponge/src/main/java/me/lucko/luckperms/api/sponge/simple/SimpleCollection.java similarity index 96% rename from sponge/src/main/java/me/lucko/luckperms/service/simple/SimpleCollection.java rename to sponge/src/main/java/me/lucko/luckperms/api/sponge/simple/SimpleCollection.java index 715bc0a7..2b07019b 100644 --- a/sponge/src/main/java/me/lucko/luckperms/service/simple/SimpleCollection.java +++ b/sponge/src/main/java/me/lucko/luckperms/api/sponge/simple/SimpleCollection.java @@ -20,7 +20,7 @@ * SOFTWARE. */ -package me.lucko.luckperms.service.simple; +package me.lucko.luckperms.api.sponge.simple; import lombok.Getter; import lombok.NonNull; @@ -85,6 +85,6 @@ public class SimpleCollection implements SubjectCollection { @Override public Subject getDefaults() { - return null; // TODO + return new SimpleSubject("default", service, this); } } diff --git a/sponge/src/main/java/me/lucko/luckperms/service/simple/SimpleSubject.java b/sponge/src/main/java/me/lucko/luckperms/api/sponge/simple/SimpleSubject.java similarity index 73% rename from sponge/src/main/java/me/lucko/luckperms/service/simple/SimpleSubject.java rename to sponge/src/main/java/me/lucko/luckperms/api/sponge/simple/SimpleSubject.java index 40038416..ddb3b7e9 100644 --- a/sponge/src/main/java/me/lucko/luckperms/service/simple/SimpleSubject.java +++ b/sponge/src/main/java/me/lucko/luckperms/api/sponge/simple/SimpleSubject.java @@ -20,7 +20,7 @@ * SOFTWARE. */ -package me.lucko.luckperms.service.simple; +package me.lucko.luckperms.api.sponge.simple; import lombok.Getter; import lombok.NonNull; @@ -29,8 +29,9 @@ import org.spongepowered.api.service.context.Context; import org.spongepowered.api.service.permission.*; import org.spongepowered.api.util.Tristate; -import java.util.*; -import java.util.concurrent.ConcurrentHashMap; +import java.util.List; +import java.util.Optional; +import java.util.Set; /** * Super simple Subject implementation. @@ -43,9 +44,6 @@ public class SimpleSubject implements Subject { private final SubjectCollection containingCollection; private final SubjectData subjectData; - private final Map, Map> perms = new ConcurrentHashMap<>(); - private final Map, Set> parents = new ConcurrentHashMap<>(); - public SimpleSubject(String identifier, PermissionService service, SubjectCollection containingCollection) { this.identifier = identifier; this.service = service; @@ -65,33 +63,21 @@ public class SimpleSubject implements Subject { @Override public boolean hasPermission(@NonNull Set contexts, @NonNull String node) { - return getPermissionValue(contexts, node).asBoolean(); + return subjectData.getPermissions(contexts).getOrDefault(node, false); } @Override public boolean hasPermission(@NonNull String permission) { - return getPermissionValue(getActiveContexts(), permission).asBoolean(); + return hasPermission(getActiveContexts(), permission); } @Override public Tristate getPermissionValue(@NonNull Set contexts, @NonNull String node) { - if (!perms.containsKey(contexts)) { + if (!subjectData.getPermissions(contexts).containsKey(node)) { return Tristate.UNDEFINED; } - Map context = perms.get(contexts); - if (context.containsKey(node)) { - return context.get(node); - } - - for (Subject parent : getParents(contexts)) { - Tristate ts = parent.getPermissionValue(contexts, node); - if (ts != Tristate.UNDEFINED) { - return ts; - } - } - - return Tristate.UNDEFINED; + return Tristate.fromBoolean(subjectData.getPermissions(contexts).get(node)); } @Override @@ -101,7 +87,7 @@ public class SimpleSubject implements Subject { @Override public boolean isChildOf(@NonNull Set contexts, @NonNull Subject subject) { - return parents.containsKey(contexts) && parents.get(contexts).contains(subject); + return subjectData.getParents(contexts).contains(subject); } @Override @@ -111,21 +97,17 @@ public class SimpleSubject implements Subject { @Override public List getParents(@NonNull Set contexts) { - if (!parents.containsKey(contexts)) { - return Collections.emptyList(); - } - - return new ArrayList<>(parents.get(contexts)); + return subjectData.getParents(contexts); } @Override public Optional getOption(Set set, String s) { - return null; // TODO + return Optional.ofNullable(subjectData.getOptions(set).get(s)); } @Override public Optional getOption(String key) { - return null; // TODO + return Optional.ofNullable(subjectData.getOptions(getActiveContexts()).get(key)); } @Override diff --git a/sponge/src/main/java/me/lucko/luckperms/service/wrapping/LuckPermsSubject.java b/sponge/src/main/java/me/lucko/luckperms/service/wrapping/LuckPermsSubject.java deleted file mode 100644 index ab07ec48..00000000 --- a/sponge/src/main/java/me/lucko/luckperms/service/wrapping/LuckPermsSubject.java +++ /dev/null @@ -1,464 +0,0 @@ -/* - * Copyright (c) 2016 Lucko (Luck) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -package me.lucko.luckperms.service.wrapping; - -import com.google.common.collect.Sets; -import lombok.AllArgsConstructor; -import lombok.Getter; -import lombok.NonNull; -import me.lucko.luckperms.constants.Patterns; -import me.lucko.luckperms.core.PermissionHolder; -import me.lucko.luckperms.groups.Group; -import me.lucko.luckperms.service.LuckPermsService; -import me.lucko.luckperms.users.User; -import org.spongepowered.api.Sponge; -import org.spongepowered.api.command.CommandSource; -import org.spongepowered.api.entity.living.player.Player; -import org.spongepowered.api.service.context.Context; -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.*; -import java.util.stream.Collectors; - -/** - * TODO - * this class is aids rn - */ -@AllArgsConstructor -public class LuckPermsSubject implements Subject { - private final EnduringData enduringData; - private final LuckPermsService service; - - public LuckPermsSubject(PermissionHolder holder, LuckPermsService service) { - this.enduringData = new EnduringData(service, holder); - this.service = service; - } - - @Override - public String getIdentifier() { - return enduringData.getHolder().getObjectName(); - } - - @Override - public Optional getCommandSource() { - if (enduringData.getHolder() instanceof User) { - final UUID uuid = ((User) enduringData.getHolder()).getUuid(); - - Optional p = Sponge.getServer().getPlayer(uuid); - if (p.isPresent()) { - return Optional.of(p.get()); - } - } - - return Optional.empty(); - } - - @Override - public SubjectCollection getContainingCollection() { - if (enduringData.getHolder() instanceof Group) { - return service.getGroupSubjects(); - } else { - return service.getUserSubjects(); - } - } - - @Override - public SubjectData getSubjectData() { - return null; // TODO - } - - @Override - public SubjectData getTransientSubjectData() { - return null; // TODO - } - - @Override - public boolean hasPermission(@NonNull Set contexts, @NonNull String node) { - return getPermissionValue(contexts, node).asBoolean(); - } - - @Override - public boolean hasPermission(String permission) { - return getPermissionValue(getActiveContexts(), permission).asBoolean(); - } - - @Override - public Tristate getPermissionValue(@NonNull Set contexts, @NonNull String node) { - return null; - /* - final Map nodes = applyContexts(contexts); - - if (nodes.containsKey(node)) { - return Tristate.fromBoolean(nodes.get(node)); - } else { - return Tristate.UNDEFINED; - } - */ - } - - @Override - public boolean isChildOf(@NonNull Subject parent) { - return isChildOf(getActiveContexts(), parent); - } - - @Override - public boolean isChildOf(@NonNull Set contexts, @NonNull Subject parent) { - return parent instanceof PermissionHolder && getPermissionValue(contexts, "group." + parent.getIdentifier()).asBoolean(); - } - - @Override - public List getParents() { - return getParents(getActiveContexts()); - } - - @Override - public List getParents(@NonNull Set contexts) { - return null; - } - - @Override - public Optional getOption(Set set, String s) { - return null; - } - - @Override - public Optional getOption(String key) { - return null; - } - - @Override - public Set getActiveContexts() { - return SubjectData.GLOBAL_CONTEXT; - } - - @AllArgsConstructor - public static class EnduringData implements SubjectData { - private final LuckPermsService service; - - @Getter - private final PermissionHolder holder; - - @Override - public Map, Map> getAllPermissions() { - return null; - // TODO - - /* - Map nodes = holder.convertTemporaryPerms(); - Map, Map> permissions = new HashMap<>(); - - for (Map.Entry e : nodes.entrySet()) { - String node = e.getKey(); - if (node.contains("/")) { - // server and/or world specific - String[] parts = Patterns.SERVER_DELIMITER.split(node, 2); - // 0 = server+world 1 = node - - node = parts[1]; - String server = null; - String world = null; - - if (parts[0].contains("-")) { - String[] serverParts = Patterns.WORLD_DELIMITER.split(parts[0], 2); - world = serverParts[0]; - server = serverParts[1]; - - } else { - server = parts[0]; - } - - if (world == null) { - if (Patterns.NODE_CONTEXTS.matcher(node).matches()) { - // Has special context - Set c = Sets.newHashSet(new Context(LuckPermsService.SERVER_CONTEXT, server)); - - String[] contextParts = e.getKey().substring(1).split("\\)", 2); - // 0 = context, 1 = node - - node = contextParts[1]; - - // Parse the context values from this node - for (String s : contextParts[0].split("\\,")) { - if (!s.contains("=")) { - // Not valid - continue; - } - - // contextKey=value - String[] con = s.split("\\=", 2); - c.add(new Context(con[0], con[1])); - } - - if (!permissions.containsKey(c)) { - permissions.put(c, new HashMap<>()); - } - permissions.get(c).put(node, e.getValue()); - - } else { - // No special context - Set c = Sets.newHashSet(new Context(LuckPermsService.SERVER_CONTEXT, server)); - if (!permissions.containsKey(c)) { - permissions.put(c, new HashMap<>()); - } - permissions.get(c).put(node, e.getValue()); - } - } else { - if (Patterns.NODE_CONTEXTS.matcher(node).matches()) { - // Has special context - Set c = Sets.newHashSet(new Context(Context.WORLD_KEY, world), new Context(LuckPermsService.SERVER_CONTEXT, server)); - - String[] contextParts = e.getKey().substring(1).split("\\)", 2); - // 0 = context, 1 = node - - node = contextParts[1]; - - // Parse the context values from this node - for (String s : contextParts[0].split("\\,")) { - if (!s.contains("=")) { - // Not valid - continue; - } - - // contextKey=value - String[] con = s.split("\\=", 2); - c.add(new Context(con[0], con[1])); - } - - if (!permissions.containsKey(c)) { - permissions.put(c, new HashMap<>()); - } - permissions.get(c).put(node, e.getValue()); - - } else { - // No special context - Set c = Sets.newHashSet(new Context(Context.WORLD_KEY, world), new Context(LuckPermsService.SERVER_CONTEXT, server)); - if (!permissions.containsKey(c)) { - permissions.put(c, new HashMap<>()); - } - permissions.get(c).put(node, e.getValue()); - } - } - - } else { - // Plain node - if (Patterns.NODE_CONTEXTS.matcher(e.getKey()).matches()) { - // Has special context - Set c = Sets.newHashSet(); - - String[] contextParts = e.getKey().substring(1).split("\\)", 2); - // 0 = context, 1 = node - - node = contextParts[1]; - - // Parse the context values from this node - for (String s : contextParts[0].split("\\,")) { - if (!s.contains("=")) { - // Not valid - continue; - } - - // contextKey=value - String[] con = s.split("\\=", 2); - c.add(new Context(con[0], con[1])); - } - - if (!permissions.containsKey(c)) { - permissions.put(c, new HashMap<>()); - } - permissions.get(c).put(node, e.getValue()); - - } else { - if (!permissions.containsKey(new HashSet())) { - permissions.put(new HashSet<>(), new HashMap<>()); - } - permissions.get(new HashSet()).put(node, e.getValue()); - } - } - } - - return permissions; - */ - } - - @Override - public Map getPermissions(Set set) { - return getAllPermissions().getOrDefault(set, Collections.emptyMap()); - } - - @Override - public boolean setPermission(Set set, String s, Tristate tristate) { - return false; - } - - @Override - public boolean clearPermissions() { - return false; - } - - @Override - public boolean clearPermissions(Set set) { - return false; - } - - @Override - public Map, List> getAllParents() { - return null; - } - - @Override - public List getParents(Set contexts) { - final Set parents = new HashSet<>(); - final Map nodes = applyContexts(contexts); - - for (Map.Entry e : nodes.entrySet()) { - if (!e.getValue()) { - continue; - } - - if (Patterns.GROUP_MATCH.matcher(e.getKey()).matches()) { - final String groupName = e.getKey().substring("group.".length()); - parents.add(groupName); - } - } - - return parents.stream().map(s -> service.getGroupSubjects().get(s)).collect(Collectors.toList()); - } - - @Override - public boolean addParent(Set set, Subject subject) { - return false; - } - - @Override - public boolean removeParent(Set set, Subject subject) { - return false; - } - - @Override - public boolean clearParents() { - return false; - } - - @Override - public boolean clearParents(Set set) { - return false; - } - - @Override - public Map, Map> getAllOptions() { - return null; - } - - @Override - public Map getOptions(Set set) { - return null; - } - - @Override - public boolean setOption(Set set, String s, String s1) { - return false; - } - - @Override - public boolean clearOptions(Set set) { - return false; - } - - @Override - public boolean clearOptions() { - return false; - } - - private Map applyContexts(@NonNull Set set) { - final Map map = new HashMap<>(); - - String world = null; - String server = null; - - Map contexts = new HashMap<>(); - - for (Context context : set) { - if (context.getType().equals(Context.WORLD_KEY)) { - world = context.getName(); - continue; - } - - if (context.getType().equals(LuckPermsService.SERVER_CONTEXT)) { - server = context.getName(); - continue; - } - - contexts.put(context.getType(), context.getName()); - } - - Map local = holder.getLocalPermissions(server, world, null, service.getPossiblePermissions()); - perms: - for (Map.Entry e : local.entrySet()) { - if (!contexts.isEmpty()) { - if (!Patterns.NODE_CONTEXTS.matcher(e.getKey()).matches()) { - continue; - } - - String[] parts = e.getKey().substring(1).split("\\)", 2); - // 0 = context, 1 = node - - // Parse the context values from this node - Map contextValues = new HashMap<>(); - for (String s : parts[0].split("\\,")) { - if (!s.contains("=")) { - // Not valid - continue; - } - - // contextKey=value - String[] con = s.split("\\=", 2); - contextValues.put(con[0], con[1]); - } - - // Check that all of the requested contexts are met - for (Map.Entry req : contexts.entrySet()) { - if (!contextValues.containsKey(e.getKey())) { - continue; - } - - if (!contextValues.get(req.getKey()).equalsIgnoreCase(req.getValue())) { - // Not valid within the current contexts - continue perms; - } - } - - // Passed all da tests. - map.put(parts[1], e.getValue()); - } else { - map.put(e.getKey(), e.getValue()); - } - - } - - return map; - } - } -}