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;
- }
- }
-}