diff --git a/api/pom.xml b/api/pom.xml
index c2b8c3cef..373c71a5e 100644
--- a/api/pom.xml
+++ b/api/pom.xml
@@ -5,7 +5,7 @@
luckpermsme.lucko.luckperms
- 2.6-SNAPSHOT
+ 2.7-SNAPSHOT4.0.0
diff --git a/api/src/main/java/me/lucko/luckperms/api/Datastore.java b/api/src/main/java/me/lucko/luckperms/api/Datastore.java
index 4d0758f88..92ff2cff4 100644
--- a/api/src/main/java/me/lucko/luckperms/api/Datastore.java
+++ b/api/src/main/java/me/lucko/luckperms/api/Datastore.java
@@ -28,7 +28,7 @@ import java.util.Set;
import java.util.UUID;
/**
- * Wrapper interface for the internal Datastore instance
+ * Interface for the internal Datastore instance
*/
@SuppressWarnings("unused")
public interface Datastore {
@@ -55,7 +55,7 @@ public interface Datastore {
Async async();
/**
- * Gets the {@link Future} interface
+ * Gets the {@link Future} interface.
*
* All operations through this interface are called in a new, separate asynchronous thread, similar to {@link Async}.
* The only difference is that instead of providing a callback, a {@link java.util.concurrent.Future} is returned.
@@ -112,7 +112,7 @@ public interface Datastore {
* @param username the users username. (if you want to specify null here, just input "null" as a string.)
* @return if the operation was performed successfully
* @throws NullPointerException if uuid or username is null
- * @since 1.6
+ * @since 2.6
*/
boolean loadUser(UUID uuid, String username);
@@ -128,14 +128,14 @@ public interface Datastore {
/**
* Removes users from the datastore who are "default". This is called every time the plugin loads.
* @return true if the operation completed successfully
- * @since 1.6
+ * @since 2.6
*/
boolean cleanupUsers();
/**
* Gets a set all user's UUIDs who are "unique", and aren't just a member of the "default" group.
* @return a set of uuids, or null if the operation failed.
- * @since 1.6
+ * @since 2.6
*/
Set getUniqueUsers();
diff --git a/api/src/main/java/me/lucko/luckperms/api/Group.java b/api/src/main/java/me/lucko/luckperms/api/Group.java
index 99edf626c..9b65199a0 100644
--- a/api/src/main/java/me/lucko/luckperms/api/Group.java
+++ b/api/src/main/java/me/lucko/luckperms/api/Group.java
@@ -28,7 +28,7 @@ import me.lucko.luckperms.exceptions.ObjectLacksException;
import java.util.List;
/**
- * Wrapper interface for internal Group instances
+ * Interface for internal Group instances
*/
@SuppressWarnings("unused")
public interface Group extends PermissionHolder {
diff --git a/api/src/main/java/me/lucko/luckperms/api/LPConfiguration.java b/api/src/main/java/me/lucko/luckperms/api/LPConfiguration.java
index ebde682bd..db3c5c424 100644
--- a/api/src/main/java/me/lucko/luckperms/api/LPConfiguration.java
+++ b/api/src/main/java/me/lucko/luckperms/api/LPConfiguration.java
@@ -25,6 +25,8 @@ package me.lucko.luckperms.api;
import me.lucko.luckperms.api.data.DatastoreConfiguration;
import me.lucko.luckperms.api.data.MySQLConfiguration;
+import java.util.Map;
+
/**
* A wrapper interface for the internal LuckPerms configuration, providing read only access.
*/
@@ -43,14 +45,14 @@ public interface LPConfiguration {
/**
* @return the default group, in a node representation
- * @deprecated as of 1.6, the default group is always "default"
+ * @deprecated as of 2.6, the default group is always "default"
*/
@Deprecated
String getDefaultGroupNode();
/**
* @return the name of the default group
- * @deprecated as of 1.6, the default group is always "default"
+ * @deprecated as of 2.6, the default group is always "default"
*/
@Deprecated
String getDefaultGroupName();
@@ -80,6 +82,24 @@ public interface LPConfiguration {
*/
boolean getApplyShorthand();
+ /**
+ * @return if LuckPerms will send notifications to users when permissions are modified
+ * @since 2.7
+ */
+ boolean getLogNotify();
+
+ /**
+ * @return the name of the server used within Vault operations
+ * @since 2.7
+ */
+ String getVaultServer();
+
+ /**
+ * @return true if global permissions should be considered when retrieving meta or player groups
+ * @since 2.7
+ */
+ boolean getVaultIncludeGlobal();
+
/**
* @return the database values set in the configuration
* @deprecated use {@link #getDatastoreConfig()}
@@ -98,4 +118,17 @@ public interface LPConfiguration {
*/
String getStorageMethod();
+ /**
+ * @return true if split storage is enabled
+ * @since 2.7
+ */
+ boolean getSplitStorage();
+
+ /**
+ * @return a map of split storage options, where the key is the storage section, and the value is the storage method.
+ * For example: key = user, value = json
+ * @since 2.7
+ */
+ Map getSplitStorageOptions();
+
}
diff --git a/api/src/main/java/me/lucko/luckperms/api/Logger.java b/api/src/main/java/me/lucko/luckperms/api/Logger.java
index 5687c38c7..bf74eb9b2 100644
--- a/api/src/main/java/me/lucko/luckperms/api/Logger.java
+++ b/api/src/main/java/me/lucko/luckperms/api/Logger.java
@@ -23,7 +23,7 @@
package me.lucko.luckperms.api;
/**
- * A wrapper class for platform logger instances.
+ * A wrapper interface for platform logger instances.
*
*
Bukkit/Bungee both use java.util.logging, and Sponge uses org.slf4j. This class wraps those classes so the commons
* module can access a logger.
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 664a93eba..43d335598 100644
--- a/api/src/main/java/me/lucko/luckperms/api/LuckPermsApi.java
+++ b/api/src/main/java/me/lucko/luckperms/api/LuckPermsApi.java
@@ -41,7 +41,7 @@ public interface LuckPermsApi {
/**
* @return the version of the API running on the platform
- * @since 1.6
+ * @since 2.6
*/
double getApiVersion();
@@ -50,6 +50,11 @@ public interface LuckPermsApi {
*/
String getVersion();
+ /**
+ * @return the platform LuckPerms is running on
+ */
+ PlatformType getPlatformType();
+
/**
* Registers a listener to be sent LuckPerms events
* @param listener the listener instance
@@ -138,7 +143,7 @@ public interface LuckPermsApi {
* Unload a user from the internal storage, if they're not currently online.
* @param user the user to unload
* @throws NullPointerException if the user is null
- * @since 1.6
+ * @since 2.6
*/
void cleanupUser(User user);
@@ -208,7 +213,7 @@ public interface LuckPermsApi {
* @return a {@link Node.Builder} instance
* @throws IllegalArgumentException if the permission is invalid
* @throws NullPointerException if the permission is null
- * @since 1.6
+ * @since 2.6
*/
Node.Builder buildNode(String permission) throws IllegalArgumentException;
diff --git a/api/src/main/java/me/lucko/luckperms/api/MetaUtils.java b/api/src/main/java/me/lucko/luckperms/api/MetaUtils.java
new file mode 100644
index 000000000..8cb1880b8
--- /dev/null
+++ b/api/src/main/java/me/lucko/luckperms/api/MetaUtils.java
@@ -0,0 +1,314 @@
+/*
+ * 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;
+
+import me.lucko.luckperms.LuckPerms;
+import me.lucko.luckperms.exceptions.ObjectAlreadyHasException;
+import me.lucko.luckperms.exceptions.ObjectLacksException;
+
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * A collection of utilities to help retrieve meta values for {@link PermissionHolder}s
+ * @since 2.7
+ */
+public class MetaUtils {
+
+ /**
+ * Escapes special characters used within LuckPerms, so the string can be saved without issues
+ * @param s the string to escape
+ * @return an escaped string
+ * @throws NullPointerException if the string is null
+ */
+ public static String escapeCharacters(String s) {
+ if (s == null) {
+ throw new NullPointerException();
+ }
+
+ s = s.replace(".", "{SEP}");
+ s = s.replace("/", "{FSEP}");
+ s = s.replace("$", "{DSEP}");
+
+ return s;
+ }
+
+ /**
+ * Unescapes special characters used within LuckPerms, the inverse of {@link #escapeCharacters(String)}
+ * @param s the string to unescape
+ * @return an unescaped string
+ * @throws NullPointerException if the string is null
+ */
+ public static String unescapeCharacters(String s) {
+ if (s == null) {
+ throw new NullPointerException();
+ }
+
+ s = s.replace("{SEP}", ".");
+ s = s.replace("{FSEP}", "/");
+ s = s.replace("{DSEP}", "$");
+
+ return s;
+ }
+
+ /**
+ * Sets a meta value on a holder
+ * @param holder the holder to apply the meta node to
+ * @param server the server to apply the meta on, can be null
+ * @param world the world to apply the meta on, can be null
+ * @param node the meta node
+ * @param value the meta value
+ * @throws NullPointerException if the holder, node or value is null
+ * @throws IllegalArgumentException if the node or value is empty
+ */
+ public static void setMeta(PermissionHolder holder, String server, String world, String node, String value) {
+ if (holder == null) {
+ throw new NullPointerException("holder");
+ }
+
+ if (node == null) {
+ throw new NullPointerException("node");
+ }
+
+ if (value == null) {
+ throw new NullPointerException("value");
+ }
+
+ if (node.equals("")) {
+ throw new IllegalArgumentException("node is empty");
+ }
+
+ if (value.equals("")) {
+ throw new IllegalArgumentException("value is empty");
+ }
+
+ if (server == null || server.equals("")) {
+ server = "global";
+ }
+
+ node = escapeCharacters(node);
+ value = escapeCharacters(value);
+
+ Set toRemove = new HashSet<>();
+ for (Node n : holder.getEnduringPermissions()) {
+ if (n.isMeta() && n.getMeta().getKey().equals(node)) {
+ toRemove.add(n);
+ }
+ }
+
+ for (Node n : toRemove) {
+ try {
+ holder.unsetPermission(n);
+ } catch (ObjectLacksException ignored) {}
+ }
+
+ Node.Builder metaNode = LuckPerms.getApi().buildNode("meta." + node + "." + value).setValue(true);
+ if (!server.equalsIgnoreCase("global")) {
+ metaNode.setServer(server);
+ }
+ if (world != null && !world.equals("")) {
+ metaNode.setServer(server).setWorld(world);
+ }
+
+ try {
+ holder.setPermission(metaNode.build());
+ } catch (ObjectAlreadyHasException ignored) {}
+ }
+
+ /**
+ * Gets a meta value for the holder
+ * @param holder the holder to get the meta from
+ * @param server the server to retrieve the meta on, can be null
+ * @param world the world to retrieve the meta on, can be null
+ * @param node the node to get
+ * @param defaultValue the default value to return if the node is not set
+ * @param includeGlobal if global nodes should be considered when retrieving the meta
+ * @return a meta string, or the default value if the user does not have the meta node
+ * @throws NullPointerException if the holder or node is null
+ * @throws IllegalArgumentException if the node is empty
+ */
+ public static String getMeta(PermissionHolder holder, String server, String world, String node, String defaultValue, boolean includeGlobal) {
+ if (holder == null) {
+ throw new NullPointerException("holder");
+ }
+
+ if (server == null || server.equals("")) {
+ server = "global";
+ }
+
+ if (node == null) {
+ throw new NullPointerException("node");
+ }
+
+ if (node.equals("")) {
+ throw new IllegalArgumentException("node is empty");
+ }
+
+ node = escapeCharacters(node);
+
+ for (Node n : holder.getPermissions()) {
+ if (!n.getValue()) {
+ continue;
+ }
+
+ if (!n.isMeta()) {
+ continue;
+ }
+
+ if (!server.equalsIgnoreCase("global")) {
+ if (!n.shouldApplyOnServer(server, includeGlobal, false)) {
+ continue;
+ }
+ }
+
+ if (!n.shouldApplyOnWorld(world, includeGlobal, false)) {
+ continue;
+ }
+
+ Map.Entry meta = n.getMeta();
+ if (meta.getKey().equalsIgnoreCase(node)) {
+ return unescapeCharacters(meta.getValue());
+ }
+ }
+
+ return defaultValue;
+ }
+
+ private static void setChatMeta(boolean prefix, PermissionHolder holder, String value, int priority, String server, String world) {
+ if (holder == null) {
+ throw new NullPointerException("holder");
+ }
+
+ if (value == null || value.equals("")) {
+ throw new IllegalArgumentException("value is null/empty");
+ }
+
+ Node.Builder node = LuckPerms.getApi().buildNode(prefix ? "prefix" : "suffix" + "." + priority + "." + escapeCharacters(value));
+ node.setValue(true);
+ if (!server.equalsIgnoreCase("global")) {
+ node.setServer(server);
+ }
+ if (world != null && !world.equals("")) {
+ node.setServer(server).setWorld(world);
+ }
+
+ try {
+ holder.setPermission(node.build());
+ } catch (ObjectAlreadyHasException ignored) {}
+ }
+
+ /**
+ * Adds a prefix to a holder on a specific server and world
+ * @param holder the holder to set the prefix for
+ * @param prefix the prefix value
+ * @param priority the priority to set the prefix at
+ * @param server the server to set the prefix on, can be null
+ * @param world the world to set the prefix on, can be null
+ * @throws NullPointerException if the holder is null
+ * @throws IllegalArgumentException if the prefix is null or empty
+ */
+ public static void setPrefix(PermissionHolder holder, String prefix, int priority, String server, String world) {
+ setChatMeta(true, holder, prefix, priority, server, world);
+ }
+
+ /**
+ * Adds a suffix to a holder on a specific server and world
+ * @param holder the holder to set the suffix for
+ * @param suffix the suffix value
+ * @param priority the priority to set the suffix at
+ * @param server the server to set the suffix on, can be null
+ * @param world the world to set the suffix on, can be null
+ * @throws NullPointerException if the holder is null
+ * @throws IllegalArgumentException if the suffix is null or empty
+ */
+ public static void setSuffix(PermissionHolder holder, String suffix, int priority, String server, String world) {
+ setChatMeta(false, holder, suffix, priority, server, world);
+ }
+
+ private static String getChatMeta(boolean prefix, PermissionHolder holder, String server, String world, boolean includeGlobal) {
+ if (holder == null) {
+ throw new NullPointerException("holder");
+ }
+ if (server == null) {
+ server = "global";
+ }
+
+ int priority = Integer.MIN_VALUE;
+ String meta = null;
+ for (Node n : holder.getAllNodes()) {
+ if (!n.getValue()) {
+ continue;
+ }
+
+ if (!server.equalsIgnoreCase("global")) {
+ if (!n.shouldApplyOnServer(server, includeGlobal, false)) {
+ continue;
+ }
+ }
+
+ if (!n.shouldApplyOnWorld(world, includeGlobal, false)) {
+ continue;
+ }
+
+ if (prefix ? !n.isPrefix() : !n.isSuffix()) {
+ continue;
+ }
+
+ Map.Entry value = prefix ? n.getPrefix() : n.getSuffix();
+ if (value.getKey() > priority) {
+ meta = value.getValue();
+ priority = value.getKey();
+ }
+ }
+
+ return meta == null ? "" : unescapeCharacters(meta);
+ }
+
+ /**
+ * Returns a holders highest priority prefix, if they have one
+ * @param holder the holder
+ * @param server the server to retrieve the prefix on
+ * @param world the world to retrieve the prefix on
+ * @param includeGlobal if global nodes should be considered when retrieving the prefix
+ * @return a prefix string, if the holder has one, or an empty string if not.
+ * @throws NullPointerException if the holder is null
+ */
+ public static String getPrefix(PermissionHolder holder, String server, String world, boolean includeGlobal) {
+ return getChatMeta(true, holder, server, world, includeGlobal);
+ }
+
+ /**
+ * Returns a holders highest priority suffix, if they have one
+ * @param holder the holder
+ * @param server the server to retrieve the suffix on
+ * @param world the world to retrieve the suffix on
+ * @param includeGlobal if global nodes should be considered when retrieving the suffix
+ * @return a suffix string, if the holder has one, or an empty string if not.
+ * @throws NullPointerException if the holder is null
+ */
+ public static String getSuffix(PermissionHolder holder, String server, String world, boolean includeGlobal) {
+ return getChatMeta(false, holder, server, world, includeGlobal);
+ }
+
+}
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 faa299274..2e07a3221 100644
--- a/api/src/main/java/me/lucko/luckperms/api/Node.java
+++ b/api/src/main/java/me/lucko/luckperms/api/Node.java
@@ -30,7 +30,7 @@ import java.util.Optional;
/**
* Represents an immutable node object
*
Use {@link LuckPermsApi#buildNode(String)} to get an instance.
- * @since 1.6
+ * @since 2.6
*/
@SuppressWarnings("unused")
public interface Node extends Map.Entry {
@@ -260,6 +260,9 @@ public interface Node extends Map.Entry {
*/
boolean almostEquals(Node node);
+ /**
+ * Builds a Node instance
+ */
interface Builder {
Builder setNegated(boolean negated);
Builder setValue(boolean value);
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 da0f0bdb6..2ad8e19c9 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 (user/group) instances
+ * Interface for internal PermissionHolder (user/group) instances
*/
@SuppressWarnings("unused")
public interface PermissionHolder {
@@ -45,21 +45,21 @@ public interface PermissionHolder {
/**
* Gets an immutable Set of the objects permission nodes
* @return an immutable set of permissions in priority order
- * @since 1.6
+ * @since 2.6
*/
SortedSet getPermissions();
/**
* Similar to {@link #getPermissions()}, except excluding transient permissions
* @return a set of nodes
- * @since 1.6
+ * @since 2.6
*/
Set getEnduringPermissions();
/**
* Similar to {@link #getPermissions()}, except excluding non-transient permissions
* @return a set of nodes
- * @since 1.6
+ * @since 2.6
*/
Set getTransientPermissions();
@@ -67,7 +67,7 @@ public interface PermissionHolder {
/**
* Gets an immutable set of the nodes that this object has and inherits
* @return an immutable set of permissions
- * @since 1.6
+ * @since 2.6
*/
Set getAllNodes();
@@ -84,7 +84,7 @@ public interface PermissionHolder {
* @param node the node to check for
* @return a Tristate for the holders permission status for the node
* @throws NullPointerException if the node is null
- * @since 1.6
+ * @since 2.6
*/
Tristate hasPermission(Node node);
@@ -93,7 +93,7 @@ public interface PermissionHolder {
* @param node the node to check for
* @return a Tristate for the holders permission status for the node
* @throws NullPointerException if the node is null
- * @since 1.6
+ * @since 2.6
*/
Tristate hasTransientPermission(Node node);
@@ -171,7 +171,7 @@ public interface PermissionHolder {
* @param node the node to check for
* @return a Tristate for the holders inheritance status for the node
* @throws NullPointerException if the node is null
- * @since 1.6
+ * @since 2.6
*/
Tristate inheritsPermission(Node node);
@@ -249,7 +249,7 @@ public interface PermissionHolder {
* @param node The node to be set
* @throws ObjectAlreadyHasException if the object already has the permission
* @throws NullPointerException if the node is null
- * @since 1.6
+ * @since 2.6
*/
void setPermission(Node node) throws ObjectAlreadyHasException;
@@ -267,7 +267,7 @@ public interface PermissionHolder {
* @param node The node to be set
* @throws ObjectAlreadyHasException if the object already has the permission
* @throws NullPointerException if the node is null
- * @since 1.6
+ * @since 2.6
*/
void setTransientPermission(Node node) throws ObjectAlreadyHasException;
@@ -357,7 +357,7 @@ public interface PermissionHolder {
* @param node The node to be unset
* @throws ObjectLacksException if the node wasn't already set
* @throws NullPointerException if the node is null
- * @since 1.6
+ * @since 2.6
*/
void unsetPermission(Node node) throws ObjectLacksException;
@@ -366,7 +366,7 @@ public interface PermissionHolder {
* @param node The node to be unset
* @throws ObjectLacksException if the node wasn't already set
* @throws NullPointerException if the node is null
- * @since 1.6
+ * @since 2.6
*/
void unsetTransientPermission(Node node) throws ObjectLacksException;
@@ -498,7 +498,7 @@ public interface PermissionHolder {
* @param possibleNodes a list of possible permissions for resolving wildcards
* @param applyGroups if inherited group permissions should be included
* @return a map of permissions
- * @since 1.6
+ * @since 2.6
*/
Map getPermissions(String server, String world, Map extraContext, boolean includeGlobal, List possibleNodes, boolean applyGroups);
@@ -513,7 +513,7 @@ public interface PermissionHolder {
/**
* Processes the nodes and returns the temporary ones.
* @return a set of temporary nodes
- * @since 1.6
+ * @since 2.6
*/
Set getTemporaryPermissionNodes();
@@ -528,7 +528,7 @@ public interface PermissionHolder {
/**
* Processes the nodes and returns the non-temporary ones.
* @return a set of permanent nodes
- * @since 1.6
+ * @since 2.6
*/
Set getPermanentPermissionNodes();
diff --git a/api/src/main/java/me/lucko/luckperms/api/PlatformType.java b/api/src/main/java/me/lucko/luckperms/api/PlatformType.java
new file mode 100644
index 000000000..15694edcb
--- /dev/null
+++ b/api/src/main/java/me/lucko/luckperms/api/PlatformType.java
@@ -0,0 +1,44 @@
+/*
+ * 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;
+
+/**
+ * Represents the platform type that LuckPerms is running on
+ * @since 2.7
+ */
+public enum PlatformType {
+
+ BUKKIT("Bukkit"),
+ BUNGEE("Bungee"),
+ SPONGE("Sponge");
+
+ private final String friendlyName;
+
+ PlatformType(String friendlyName) {
+ this.friendlyName = friendlyName;
+ }
+
+ public String getFriendlyName() {
+ return friendlyName;
+ }
+}
diff --git a/api/src/main/java/me/lucko/luckperms/api/Track.java b/api/src/main/java/me/lucko/luckperms/api/Track.java
index 6457e0593..e10f2f880 100644
--- a/api/src/main/java/me/lucko/luckperms/api/Track.java
+++ b/api/src/main/java/me/lucko/luckperms/api/Track.java
@@ -28,7 +28,7 @@ import me.lucko.luckperms.exceptions.ObjectLacksException;
import java.util.List;
/**
- * Wrapper interface for internal Track instances
+ * Interface for internal Track instances
*/
@SuppressWarnings("unused")
public interface Track {
diff --git a/api/src/main/java/me/lucko/luckperms/api/User.java b/api/src/main/java/me/lucko/luckperms/api/User.java
index 349740821..4755b2d8f 100644
--- a/api/src/main/java/me/lucko/luckperms/api/User.java
+++ b/api/src/main/java/me/lucko/luckperms/api/User.java
@@ -29,7 +29,7 @@ import java.util.List;
import java.util.UUID;
/**
- * Wrapper interface for internal User instances
+ * Interface for internal User instances
*/
@SuppressWarnings("unused")
public interface User extends PermissionHolder {
diff --git a/api/src/main/java/me/lucko/luckperms/api/UuidCache.java b/api/src/main/java/me/lucko/luckperms/api/UuidCache.java
index 30b26b295..9b6756cf1 100644
--- a/api/src/main/java/me/lucko/luckperms/api/UuidCache.java
+++ b/api/src/main/java/me/lucko/luckperms/api/UuidCache.java
@@ -25,7 +25,9 @@ package me.lucko.luckperms.api;
import java.util.UUID;
/**
- * This UuidCache is a means of allowing users to have the same internal UUID across a network of offline mode servers
+ * A UUID cache for online users, between external Mojang UUIDs, and internal LuckPerms UUIDs.
+ *
+ *
This UuidCache is a means of allowing users to have the same internal UUID across a network of offline mode servers
* or mixed offline mode and online mode servers. Platforms running in offline mode generate a random UUID for a user when
* they first join the server, but this UUID will then not be consistent across the network. LuckPerms will instead check
* the datastore cache, to get a UUID for a user that is consistent across an entire network.
diff --git a/api/src/main/java/me/lucko/luckperms/api/event/AbstractPermissionEvent.java b/api/src/main/java/me/lucko/luckperms/api/event/AbstractPermissionEvent.java
index f0240386e..09ae4976a 100644
--- a/api/src/main/java/me/lucko/luckperms/api/event/AbstractPermissionEvent.java
+++ b/api/src/main/java/me/lucko/luckperms/api/event/AbstractPermissionEvent.java
@@ -26,7 +26,7 @@ import me.lucko.luckperms.api.Node;
import me.lucko.luckperms.api.PermissionHolder;
/**
- * @since 1.6
+ * @since 2.6
*/
public class AbstractPermissionEvent extends TargetedEvent {
diff --git a/api/src/main/java/me/lucko/luckperms/api/event/events/PermissionNodeExpireEvent.java b/api/src/main/java/me/lucko/luckperms/api/event/events/PermissionNodeExpireEvent.java
index 82456d123..5f64eaf9c 100644
--- a/api/src/main/java/me/lucko/luckperms/api/event/events/PermissionNodeExpireEvent.java
+++ b/api/src/main/java/me/lucko/luckperms/api/event/events/PermissionNodeExpireEvent.java
@@ -28,7 +28,7 @@ import me.lucko.luckperms.api.event.AbstractPermissionEvent;
/**
* Called when a temporary permission node expires
- * @since 1.6
+ * @since 2.6
*/
public class PermissionNodeExpireEvent extends AbstractPermissionEvent {
public PermissionNodeExpireEvent(PermissionHolder target, Node node) {
diff --git a/api/src/main/java/me/lucko/luckperms/api/event/events/PermissionNodeSetEvent.java b/api/src/main/java/me/lucko/luckperms/api/event/events/PermissionNodeSetEvent.java
index b0473e5b4..78688ce60 100644
--- a/api/src/main/java/me/lucko/luckperms/api/event/events/PermissionNodeSetEvent.java
+++ b/api/src/main/java/me/lucko/luckperms/api/event/events/PermissionNodeSetEvent.java
@@ -28,7 +28,7 @@ import me.lucko.luckperms.api.event.AbstractPermissionEvent;
/**
* Called when a permission node is set on a holder
- * @since 1.6
+ * @since 2.6
*/
public class PermissionNodeSetEvent extends AbstractPermissionEvent {
public PermissionNodeSetEvent(PermissionHolder target, Node node) {
diff --git a/api/src/main/java/me/lucko/luckperms/api/event/events/PermissionNodeUnsetEvent.java b/api/src/main/java/me/lucko/luckperms/api/event/events/PermissionNodeUnsetEvent.java
index 8f6ebdf6a..9f063a6ba 100644
--- a/api/src/main/java/me/lucko/luckperms/api/event/events/PermissionNodeUnsetEvent.java
+++ b/api/src/main/java/me/lucko/luckperms/api/event/events/PermissionNodeUnsetEvent.java
@@ -28,7 +28,7 @@ import me.lucko.luckperms.api.event.AbstractPermissionEvent;
/**
* Called when a permission node is unset from a holder
- * @since 1.6
+ * @since 2.6
*/
public class PermissionNodeUnsetEvent extends AbstractPermissionEvent {
public PermissionNodeUnsetEvent(PermissionHolder target, Node node) {
diff --git a/api/src/main/java/me/lucko/luckperms/exceptions/MembershipException.java b/api/src/main/java/me/lucko/luckperms/exceptions/MembershipException.java
new file mode 100644
index 000000000..28ed05b32
--- /dev/null
+++ b/api/src/main/java/me/lucko/luckperms/exceptions/MembershipException.java
@@ -0,0 +1,8 @@
+package me.lucko.luckperms.exceptions;
+
+/**
+ * Thrown when a permission holding object doesn't / already has a permission or isn't / is already is a member of a group
+ * @since 2.7
+ */
+public abstract class MembershipException extends Exception {
+}
diff --git a/api/src/main/java/me/lucko/luckperms/exceptions/ObjectAlreadyHasException.java b/api/src/main/java/me/lucko/luckperms/exceptions/ObjectAlreadyHasException.java
index 2d7da1d5f..4355c8936 100644
--- a/api/src/main/java/me/lucko/luckperms/exceptions/ObjectAlreadyHasException.java
+++ b/api/src/main/java/me/lucko/luckperms/exceptions/ObjectAlreadyHasException.java
@@ -26,5 +26,5 @@ package me.lucko.luckperms.exceptions;
* Thrown when a permission holding object already has a permission, is already a member of a group, or when a track
* already contains a group.
*/
-public class ObjectAlreadyHasException extends Exception {
+public class ObjectAlreadyHasException extends MembershipException {
}
diff --git a/api/src/main/java/me/lucko/luckperms/exceptions/ObjectLacksException.java b/api/src/main/java/me/lucko/luckperms/exceptions/ObjectLacksException.java
index b327cab3e..33b1338b5 100644
--- a/api/src/main/java/me/lucko/luckperms/exceptions/ObjectLacksException.java
+++ b/api/src/main/java/me/lucko/luckperms/exceptions/ObjectLacksException.java
@@ -26,5 +26,5 @@ package me.lucko.luckperms.exceptions;
* Thrown when a permission holding object does not already have a permission, is not already a member of a group,
* or when a track doesn't contain a group.
*/
-public class ObjectLacksException extends Exception {
+public class ObjectLacksException extends MembershipException {
}
diff --git a/bukkit-placeholders/pom.xml b/bukkit-placeholders/pom.xml
index 5a200e7a8..fb1e97a94 100644
--- a/bukkit-placeholders/pom.xml
+++ b/bukkit-placeholders/pom.xml
@@ -5,7 +5,7 @@
luckpermsme.lucko.luckperms
- 2.6-SNAPSHOT
+ 2.7-SNAPSHOT4.0.0
@@ -30,7 +30,7 @@
me.lucko.luckpermsluckperms-api
- ${project.version}
+ 2.5compile
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 a86e46b05..3be84f2ca 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,7 +51,6 @@ 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";
@@ -76,7 +75,7 @@ public class LuckPermsPlaceholderExpansion extends PlaceholderExpansion {
@Override
public String getVersion() {
- return api == null ? "null" : api.getVersion();
+ return "2.5";
}
@Override
diff --git a/bukkit/pom.xml b/bukkit/pom.xml
index 725b58048..76853a691 100644
--- a/bukkit/pom.xml
+++ b/bukkit/pom.xml
@@ -5,7 +5,7 @@
luckpermsme.lucko.luckperms
- 2.6-SNAPSHOT
+ 2.7-SNAPSHOT4.0.0
diff --git a/bukkit/src/main/java/me/lucko/luckperms/BukkitListener.java b/bukkit/src/main/java/me/lucko/luckperms/BukkitListener.java
index a50087276..513575e1a 100644
--- a/bukkit/src/main/java/me/lucko/luckperms/BukkitListener.java
+++ b/bukkit/src/main/java/me/lucko/luckperms/BukkitListener.java
@@ -46,7 +46,7 @@ class BukkitListener extends AbstractListener implements Listener {
@EventHandler
public void onPlayerPreLogin(AsyncPlayerPreLoginEvent e) {
if (!plugin.getDatastore().isAcceptingLogins()) {
- // Datastore is disabled, prevent players from joining the server
+ // The datastore is disabled, prevent players from joining the server
e.disallow(AsyncPlayerPreLoginEvent.Result.KICK_OTHER, Message.LOADING_ERROR.toString());
return;
}
@@ -70,6 +70,11 @@ class BukkitListener extends AbstractListener implements Listener {
PermissionAttachment attachment = player.addAttachment(plugin);
Map newPermMap = new ConcurrentHashMap<>();
try {
+ /* Replace the standard LinkedHashMap in the attachment with a ConcurrentHashMap.
+ This means that we can iterate over and change the permissions within our attachment asynchronously,
+ without worrying about thread safety. The Bukkit side of things should still operate normally. Internal
+ permission stuff should work the same. This is by far the most easy and efficient way to do things, without
+ having to do tons of reflection. */
BukkitUser.getPermissionsField().set(attachment, newPermMap);
} catch (Throwable t) {
t.printStackTrace();
diff --git a/bukkit/src/main/java/me/lucko/luckperms/LPBukkitPlugin.java b/bukkit/src/main/java/me/lucko/luckperms/LPBukkitPlugin.java
index b057cebd7..385350a33 100644
--- a/bukkit/src/main/java/me/lucko/luckperms/LPBukkitPlugin.java
+++ b/bukkit/src/main/java/me/lucko/luckperms/LPBukkitPlugin.java
@@ -25,6 +25,7 @@ package me.lucko.luckperms;
import lombok.Getter;
import me.lucko.luckperms.api.Logger;
import me.lucko.luckperms.api.LuckPermsApi;
+import me.lucko.luckperms.api.PlatformType;
import me.lucko.luckperms.api.implementation.ApiProvider;
import me.lucko.luckperms.api.vault.VaultHook;
import me.lucko.luckperms.commands.ConsecutiveExecutor;
@@ -161,8 +162,8 @@ public class LPBukkitPlugin extends JavaPlugin implements LuckPermsPlugin {
}
@Override
- public Type getType() {
- return Type.BUKKIT;
+ public PlatformType getType() {
+ return PlatformType.BUKKIT;
}
@Override
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 ffee11e91..5160b75d8 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
@@ -32,6 +32,7 @@ import me.lucko.luckperms.groups.Group;
import me.lucko.luckperms.users.User;
import net.milkbowl.vault.chat.Chat;
+import java.util.Iterator;
import java.util.Map;
import static me.lucko.luckperms.utils.ArgumentChecker.escapeCharacters;
@@ -80,108 +81,30 @@ public class VaultChatHook extends Chat {
node = escapeCharacters(node);
value = escapeCharacters(value);
- if (world == null || world.equals("")) {
- try {
- holder.setPermission("meta." + node + "." + value, true);
- } catch (ObjectAlreadyHasException ignored) {}
-
- } else {
- try {
- holder.setPermission("meta." + node + "." + value, true, "global", world);
- } catch (ObjectAlreadyHasException ignored) {}
+ Iterator nodes = holder.getNodes().iterator();
+ while (nodes.hasNext()) {
+ Node n = nodes.next();
+ if (n.isMeta() && n.getMeta().getKey().equals(node)) {
+ nodes.remove();
+ }
}
+
+ Node.Builder metaNode = new me.lucko.luckperms.utils.Node.Builder("meta." + node + "." + value).setValue(true);
+ if (!perms.getServer().equalsIgnoreCase("global")) {
+ metaNode.setServer(perms.getServer());
+ }
+ if (world != null && !world.equals("")) {
+ metaNode.setServer(perms.getServer()).setWorld(world);
+ }
+
+ try {
+ holder.setPermission(metaNode.build());
+ } catch (ObjectAlreadyHasException ignored) {}
perms.objectSave(holder);
}
- private static int getMeta(PermissionHolder holder, String world, String node, int defaultValue) {
- if (holder == null) return defaultValue;
- if (node.equals("")) return defaultValue;
- node = escapeCharacters(node);
-
- for (Node n : holder.getPermissions()) {
- if (!n.isMeta()) {
- continue;
- }
-
- if (!n.shouldApplyOnWorld(world, true, false)) {
- continue;
- }
-
- Map.Entry meta = n.getMeta();
- if (meta.getKey().equalsIgnoreCase(node)) {
-
- try {
- return Integer.parseInt(unescapeCharacters(meta.getValue()));
- } catch (Throwable t) {
- return defaultValue;
- }
-
- }
- }
-
- return defaultValue;
- }
-
- private static double getMeta(PermissionHolder holder, String world, String node, double defaultValue) {
- if (holder == null) return defaultValue;
- if (node.equals("")) return defaultValue;
- node = escapeCharacters(node);
-
- for (Node n : holder.getPermissions()) {
- if (!n.isMeta()) {
- continue;
- }
-
- if (!n.shouldApplyOnWorld(world, true, false)) {
- continue;
- }
-
- Map.Entry meta = n.getMeta();
- if (meta.getKey().equalsIgnoreCase(node)) {
-
- try {
- return Double.parseDouble(unescapeCharacters(meta.getValue()));
- } catch (Throwable t) {
- return defaultValue;
- }
-
- }
- }
-
- return defaultValue;
- }
-
- private static boolean getMeta(PermissionHolder holder, String world, String node, boolean defaultValue) {
- if (holder == null) return defaultValue;
- if (node.equals("")) return defaultValue;
- node = escapeCharacters(node);
-
- for (Node n : holder.getPermissions()) {
- if (!n.isMeta()) {
- continue;
- }
-
- if (!n.shouldApplyOnWorld(world, true, false)) {
- continue;
- }
-
- Map.Entry meta = n.getMeta();
- if (meta.getKey().equalsIgnoreCase(node)) {
-
- try {
- return Boolean.parseBoolean(unescapeCharacters(meta.getValue()));
- } catch (Throwable t) {
- return defaultValue;
- }
-
- }
- }
-
- return defaultValue;
- }
-
- private static String getMeta(PermissionHolder holder, String world, String node, String defaultValue) {
+ private String getMeta(PermissionHolder holder, String world, String node, String defaultValue) {
if (holder == null) return defaultValue;
if (node.equals("")) return defaultValue;
node = escapeCharacters(node);
@@ -195,29 +118,50 @@ public class VaultChatHook extends Chat {
continue;
}
- if (!n.shouldApplyOnWorld(world, true, false)) {
+ if (!perms.getServer().equalsIgnoreCase("global")) {
+ if (!n.shouldApplyOnServer(perms.getServer(), perms.isIncludeGlobal(), false)) {
+ continue;
+ }
+ }
+
+ if (!n.shouldApplyOnWorld(world, perms.isIncludeGlobal(), false)) {
continue;
}
Map.Entry meta = n.getMeta();
if (meta.getKey().equalsIgnoreCase(node)) {
-
- try {
- return unescapeCharacters(meta.getValue());
- } catch (Throwable t) {
- return defaultValue;
- }
-
+ return unescapeCharacters(meta.getValue());
}
}
return defaultValue;
}
- private static String getChatMeta(boolean prefix, PermissionHolder holder, String world) {
+ private void setChatMeta(boolean prefix, PermissionHolder holder, String value, String world) {
+ if (holder == null) return;
+ if (value.equals("")) return;
+
+ Node.Builder node = new me.lucko.luckperms.utils.Node.Builder(prefix ? "prefix" : "suffix" + ".1000." + escapeCharacters(value));
+ node.setValue(true);
+ if (!perms.getServer().equalsIgnoreCase("global")) {
+ node.setServer(perms.getServer());
+ }
+
+ if (world != null && !world.equals("")) {
+ node.setServer(perms.getServer()).setWorld(world);
+ }
+
+ try {
+ holder.setPermission(node.build());
+ } catch (ObjectAlreadyHasException ignored) {}
+
+ perms.objectSave(holder);
+ }
+
+ private String getChatMeta(boolean prefix, PermissionHolder holder, String world) {
if (holder == null) return "";
- int priority = -1000;
+ int priority = Integer.MIN_VALUE;
String meta = null;
for (Node n : holder.getAllNodes(null)) {
@@ -225,30 +169,24 @@ public class VaultChatHook extends Chat {
continue;
}
- if (!n.shouldApplyOnWorld(world, true, false)) {
+ if (!perms.getServer().equalsIgnoreCase("global")) {
+ if (!n.shouldApplyOnServer(perms.getServer(), perms.isIncludeGlobal(), false)) {
+ continue;
+ }
+ }
+
+ if (!n.shouldApplyOnWorld(world, perms.isIncludeGlobal(), false)) {
continue;
}
- if (prefix) {
- if (!n.isPrefix()) {
- continue;
- }
+ if (prefix ? !n.isPrefix() : !n.isSuffix()) {
+ 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();
- }
+ Map.Entry value = prefix ? n.getPrefix() : n.getSuffix();
+ if (value.getKey() > priority) {
+ meta = value.getValue();
+ priority = value.getKey();
}
}
@@ -262,15 +200,7 @@ public class VaultChatHook extends Chat {
public void setPlayerPrefix(String world, @NonNull String player, @NonNull String prefix) {
final User user = plugin.getUserManager().get(player);
- if (user == null) return;
-
- if (prefix.equals("")) return;
-
- try {
- user.setPermission("prefix.1000." + escapeCharacters(prefix), true);
- } catch (ObjectAlreadyHasException ignored) {}
-
- perms.objectSave(user);
+ setChatMeta(true, user, prefix, world);
}
public String getPlayerSuffix(String world, @NonNull String player) {
@@ -280,15 +210,7 @@ public class VaultChatHook extends Chat {
public void setPlayerSuffix(String world, @NonNull String player, @NonNull String suffix) {
final User user = plugin.getUserManager().get(player);
- if (user == null) return;
-
- if (suffix.equals("")) return;
-
- try {
- user.setPermission("suffix.1000." + escapeCharacters(suffix), true);
- } catch (ObjectAlreadyHasException ignored) {}
-
- perms.objectSave(user);
+ setChatMeta(false, user, suffix, world);
}
public String getGroupPrefix(String world, @NonNull String group) {
@@ -298,15 +220,7 @@ public class VaultChatHook extends Chat {
public void setGroupPrefix(String world, @NonNull String group, @NonNull String prefix) {
final Group g = plugin.getGroupManager().get(group);
- if (g == null) return;
-
- if (prefix.equals("")) return;
-
- try {
- g.setPermission("prefix.1000." + escapeCharacters(prefix), true);
- } catch (ObjectAlreadyHasException ignored) {}
-
- perms.objectSave(g);
+ setChatMeta(true, g, prefix, world);
}
public String getGroupSuffix(String world, @NonNull String group) {
@@ -316,20 +230,16 @@ public class VaultChatHook extends Chat {
public void setGroupSuffix(String world, @NonNull String group, @NonNull String suffix) {
final Group g = plugin.getGroupManager().get(group);
- if (g == null) return;
-
- if (suffix.equals("")) return;
-
- try {
- g.setPermission("suffix.1000." + escapeCharacters(suffix), true);
- } catch (ObjectAlreadyHasException ignored) {}
-
- perms.objectSave(g);
+ setChatMeta(false, g, suffix, world);
}
public int getPlayerInfoInteger(String world, @NonNull String player, @NonNull String node, int defaultValue) {
final User user = plugin.getUserManager().get(player);
- return getMeta(user, world, node, defaultValue);
+ try {
+ return Integer.parseInt(getMeta(user, world, node, String.valueOf(defaultValue)));
+ } catch (NumberFormatException e) {
+ return defaultValue;
+ }
}
public void setPlayerInfoInteger(String world, @NonNull String player, @NonNull String node, int value) {
@@ -339,7 +249,11 @@ public class VaultChatHook extends Chat {
public int getGroupInfoInteger(String world, @NonNull String group, @NonNull String node, int defaultValue) {
final Group g = plugin.getGroupManager().get(group);
- return getMeta(g, world, node, defaultValue);
+ try {
+ return Integer.parseInt(getMeta(g, world, node, String.valueOf(defaultValue)));
+ } catch (NumberFormatException e) {
+ return defaultValue;
+ }
}
public void setGroupInfoInteger(String world, @NonNull String group, @NonNull String node, int value) {
@@ -349,7 +263,11 @@ public class VaultChatHook extends Chat {
public double getPlayerInfoDouble(String world, @NonNull String player, @NonNull String node, double defaultValue) {
final User user = plugin.getUserManager().get(player);
- return getMeta(user, world, node, defaultValue);
+ try {
+ return Double.parseDouble(getMeta(user, world, node, String.valueOf(defaultValue)));
+ } catch (NumberFormatException e) {
+ return defaultValue;
+ }
}
public void setPlayerInfoDouble(String world, @NonNull String player, @NonNull String node, double value) {
@@ -359,7 +277,11 @@ public class VaultChatHook extends Chat {
public double getGroupInfoDouble(String world, @NonNull String group, @NonNull String node, double defaultValue) {
final Group g = plugin.getGroupManager().get(group);
- return getMeta(g, world, node, defaultValue);
+ try {
+ return Double.parseDouble(getMeta(g, world, node, String.valueOf(defaultValue)));
+ } catch (NumberFormatException e) {
+ return defaultValue;
+ }
}
public void setGroupInfoDouble(String world, @NonNull String group, @NonNull String node, double value) {
@@ -369,7 +291,11 @@ public class VaultChatHook extends Chat {
public boolean getPlayerInfoBoolean(String world, @NonNull String player, @NonNull String node, boolean defaultValue) {
final User user = plugin.getUserManager().get(player);
- return getMeta(user, world, node, defaultValue);
+ String s = getMeta(user, world, node, String.valueOf(defaultValue));
+ if (!s.equalsIgnoreCase("true") && !s.equalsIgnoreCase("false")) {
+ return defaultValue;
+ }
+ return Boolean.parseBoolean(s);
}
public void setPlayerInfoBoolean(String world, @NonNull String player, @NonNull String node, boolean value) {
@@ -379,7 +305,11 @@ public class VaultChatHook extends Chat {
public boolean getGroupInfoBoolean(String world, @NonNull String group, @NonNull String node, boolean defaultValue) {
final Group g = plugin.getGroupManager().get(group);
- return getMeta(g, world, node, defaultValue);
+ String s = getMeta(g, world, node, String.valueOf(defaultValue));
+ if (!s.equalsIgnoreCase("true") && !s.equalsIgnoreCase("false")) {
+ return defaultValue;
+ }
+ return Boolean.parseBoolean(s);
}
public void setGroupInfoBoolean(String world, @NonNull String group, @NonNull String node, boolean value) {
diff --git a/bukkit/src/main/java/me/lucko/luckperms/api/vault/VaultHook.java b/bukkit/src/main/java/me/lucko/luckperms/api/vault/VaultHook.java
index 09f69446c..d9d12e830 100644
--- a/bukkit/src/main/java/me/lucko/luckperms/api/vault/VaultHook.java
+++ b/bukkit/src/main/java/me/lucko/luckperms/api/vault/VaultHook.java
@@ -39,6 +39,8 @@ public class VaultHook {
permissionHook = new VaultPermissionHook();
}
permissionHook.setPlugin(plugin);
+ permissionHook.setServer(plugin.getConfiguration().getVaultServer());
+ permissionHook.setIncludeGlobal(plugin.getConfiguration().getVaultIncludeGlobal());
if (chatHook == null) {
chatHook = new VaultChatHook(permissionHook);
diff --git a/bukkit/src/main/java/me/lucko/luckperms/api/vault/VaultPermissionHook.java b/bukkit/src/main/java/me/lucko/luckperms/api/vault/VaultPermissionHook.java
index 8234233b9..b95f95355 100644
--- a/bukkit/src/main/java/me/lucko/luckperms/api/vault/VaultPermissionHook.java
+++ b/bukkit/src/main/java/me/lucko/luckperms/api/vault/VaultPermissionHook.java
@@ -22,6 +22,7 @@
package me.lucko.luckperms.api.vault;
+import lombok.Getter;
import lombok.NonNull;
import lombok.Setter;
import me.lucko.luckperms.LPBukkitPlugin;
@@ -38,6 +39,14 @@ public class VaultPermissionHook extends Permission {
@Setter
private LPBukkitPlugin plugin;
+ @Getter
+ @Setter
+ private String server = "global";
+
+ @Getter
+ @Setter
+ private boolean includeGlobal = true;
+
@Override
public String getName() {
return "LuckPerms";
@@ -57,9 +66,9 @@ public class VaultPermissionHook extends Permission {
if (object == null) return false;
if (world != null && !world.equals("")) {
- return object.hasPermission(permission, true, "global", world);
+ return object.hasPermission(permission, true, server, world);
} else {
- return object.hasPermission(permission, true);
+ return object.hasPermission(permission, true, server);
}
}
@@ -68,9 +77,9 @@ public class VaultPermissionHook extends Permission {
try {
if (world != null && !world.equals("")) {
- object.setPermission(permission, true, "global", world);
+ object.setPermission(permission, true, server, world);
} else {
- object.setPermission(permission, true);
+ object.setPermission(permission, true, server);
}
} catch (ObjectAlreadyHasException ignored) {}
@@ -83,9 +92,9 @@ public class VaultPermissionHook extends Permission {
try {
if (world != null && !world.equals("")) {
- object.unsetPermission(permission, "global", world);
+ object.unsetPermission(permission, server, world);
} else {
- object.unsetPermission(permission);
+ object.unsetPermission(permission, server);
}
} catch (ObjectLacksException ignored) {}
@@ -147,7 +156,7 @@ public class VaultPermissionHook extends Permission {
if (group1 == null) return false;
if (world != null && !world.equals("")) {
- return user.isInGroup(group1, "global", world);
+ return user.isInGroup(group1, server, world);
} else {
return user.isInGroup(group1);
}
@@ -163,7 +172,7 @@ public class VaultPermissionHook extends Permission {
try {
if (world != null && !world.equals("")) {
- user.addGroup(group, "global", world);
+ user.addGroup(group, server, world);
} else {
user.addGroup(group);
}
@@ -182,7 +191,7 @@ public class VaultPermissionHook extends Permission {
try {
if (world != null && !world.equals("")) {
- user.removeGroup(group, "global", world);
+ user.removeGroup(group, server, world);
} else {
user.removeGroup(group);
}
@@ -195,7 +204,7 @@ public class VaultPermissionHook extends Permission {
public String[] getPlayerGroups(String world, @NonNull String player) {
final User user = plugin.getUserManager().get(player);
return (user == null) ? new String[0] :
- world != null && !world.equals("") ? user.getGroups("global", world, true).toArray(new String[0]) :
+ world != null && !world.equals("") ? user.getGroups(server, world, includeGlobal).toArray(new String[0]) :
user.getGroupNames().toArray(new String[0]);
}
diff --git a/bukkit/src/main/java/me/lucko/luckperms/users/BukkitUser.java b/bukkit/src/main/java/me/lucko/luckperms/users/BukkitUser.java
index 49c995c3f..0eb6e8260 100644
--- a/bukkit/src/main/java/me/lucko/luckperms/users/BukkitUser.java
+++ b/bukkit/src/main/java/me/lucko/luckperms/users/BukkitUser.java
@@ -84,7 +84,7 @@ public class BukkitUser extends User {
);
try {
- // The map in the LP PermissionAttachment is a ConcurrentHashMap. We can modify it's contents async.
+ // The map in the LP PermissionAttachment is a ConcurrentHashMap. We can modify and iterate over its contents async.
Map existing = attachment.getPermissions();
boolean different = false;
diff --git a/bukkit/src/main/resources/config.yml b/bukkit/src/main/resources/config.yml
index e802d9073..63d6c39c7 100644
--- a/bukkit/src/main/resources/config.yml
+++ b/bukkit/src/main/resources/config.yml
@@ -46,6 +46,13 @@ apply-shorthand: true
# If the plugin should send log notifications to users whenever permissions are modified.
log-notify: true
+# The name of the server used within Vault operations. If you don't want Vault operations to be server specific, set this
+# to "global".
+vault-server: global
+
+# If global permissions should be considered when retrieving meta or player groups
+vault-include-global: true
+
# Which storage method the plugin should use.
# Currently supported: mysql, sqlite, h2, json, yaml, mongodb
# Fill out connection info below if you're using MySQL or MongoDB
diff --git a/bukkit/src/main/resources/plugin.yml b/bukkit/src/main/resources/plugin.yml
index 6a8f094e2..f26b324f0 100644
--- a/bukkit/src/main/resources/plugin.yml
+++ b/bukkit/src/main/resources/plugin.yml
@@ -1,13 +1,17 @@
name: LuckPerms
-author: Luck
version: ${release.version}.${git.closest.tag.commit.count}
+description: A permissions plugin
+author: Luck
+website: https://github.com/lucko/LuckPerms
+
main: me.lucko.luckperms.LPBukkitPlugin
softdepend: [Vault, PermissionsEx, GroupManager, PowerfulPerms, zPermissions, bPermissions] # For migration
-description: A permissions plugin
+
commands:
luckperms:
description: Manage permissions
aliases: [perms, permissions, lp, p, perm]
+
permissions:
luckperms.*:
description: Gives access to all LuckPerms commands
diff --git a/bungee/pom.xml b/bungee/pom.xml
index 05b3f5505..ad4f826a8 100644
--- a/bungee/pom.xml
+++ b/bungee/pom.xml
@@ -5,7 +5,7 @@
luckpermsme.lucko.luckperms
- 2.6-SNAPSHOT
+ 2.7-SNAPSHOT4.0.0
diff --git a/bungee/src/main/java/me/lucko/luckperms/BungeeListener.java b/bungee/src/main/java/me/lucko/luckperms/BungeeListener.java
index c796d1233..c9f3f1d60 100644
--- a/bungee/src/main/java/me/lucko/luckperms/BungeeListener.java
+++ b/bungee/src/main/java/me/lucko/luckperms/BungeeListener.java
@@ -33,7 +33,6 @@ import net.md_5.bungee.api.event.*;
import net.md_5.bungee.api.plugin.Listener;
import net.md_5.bungee.event.EventHandler;
-import java.lang.ref.WeakReference;
import java.util.Collections;
import java.util.Map;
import java.util.UUID;
@@ -109,16 +108,10 @@ public class BungeeListener extends AbstractListener implements Listener {
@EventHandler
public void onPlayerPostLogin(PostLoginEvent e) {
final ProxiedPlayer player = e.getPlayer();
- final WeakReference p = new WeakReference<>(player);
-
final User user = plugin.getUserManager().get(plugin.getUuidCache().getUUID(e.getPlayer().getUniqueId()));
+
if (user == null) {
- plugin.getProxy().getScheduler().schedule(plugin, () -> {
- final ProxiedPlayer pl = p.get();
- if (pl != null) {
- pl.sendMessage(WARN_MESSAGE);
- }
- }, 3, TimeUnit.SECONDS);
+ plugin.getProxy().getScheduler().schedule(plugin, () -> player.sendMessage(WARN_MESSAGE), 3, TimeUnit.SECONDS);
} else {
user.refreshPermissions();
}
diff --git a/bungee/src/main/java/me/lucko/luckperms/LPBungeePlugin.java b/bungee/src/main/java/me/lucko/luckperms/LPBungeePlugin.java
index 63d92c735..29c49372d 100644
--- a/bungee/src/main/java/me/lucko/luckperms/LPBungeePlugin.java
+++ b/bungee/src/main/java/me/lucko/luckperms/LPBungeePlugin.java
@@ -24,6 +24,7 @@ package me.lucko.luckperms;
import lombok.Getter;
import me.lucko.luckperms.api.Logger;
+import me.lucko.luckperms.api.PlatformType;
import me.lucko.luckperms.api.implementation.ApiProvider;
import me.lucko.luckperms.commands.CommandManager;
import me.lucko.luckperms.commands.ConsecutiveExecutor;
@@ -135,8 +136,8 @@ public class LPBungeePlugin extends Plugin implements LuckPermsPlugin {
}
@Override
- public Type getType() {
- return Type.BUNGEE;
+ public PlatformType getType() {
+ return PlatformType.BUNGEE;
}
@Override
diff --git a/bungee/src/main/resources/plugin.yml b/bungee/src/main/resources/plugin.yml
index 3b8647d97..d13bf3371 100644
--- a/bungee/src/main/resources/plugin.yml
+++ b/bungee/src/main/resources/plugin.yml
@@ -1,6 +1,6 @@
name: LuckPerms
-author: Luck
version: ${release.version}.${git.closest.tag.commit.count}
-main: me.lucko.luckperms.LPBungeePlugin
-softdepend: [PowerfulPerms] # For migration
description: A permissions plugin
+author: Luck
+main: me.lucko.luckperms.LPBungeePlugin
+softdepends: [PowerfulPerms] # For migration
diff --git a/common/pom.xml b/common/pom.xml
index ef6b59192..2a1c43ddf 100644
--- a/common/pom.xml
+++ b/common/pom.xml
@@ -5,7 +5,7 @@
luckpermsme.lucko.luckperms
- 2.6-SNAPSHOT
+ 2.7-SNAPSHOT4.0.0
diff --git a/common/src/main/java/me/lucko/luckperms/LuckPermsPlugin.java b/common/src/main/java/me/lucko/luckperms/LuckPermsPlugin.java
index 3be248b7e..af2da9a20 100644
--- a/common/src/main/java/me/lucko/luckperms/LuckPermsPlugin.java
+++ b/common/src/main/java/me/lucko/luckperms/LuckPermsPlugin.java
@@ -23,6 +23,7 @@
package me.lucko.luckperms;
import me.lucko.luckperms.api.Logger;
+import me.lucko.luckperms.api.PlatformType;
import me.lucko.luckperms.api.implementation.ApiProvider;
import me.lucko.luckperms.commands.ConsecutiveExecutor;
import me.lucko.luckperms.commands.Sender;
@@ -68,7 +69,7 @@ public interface LuckPermsPlugin {
/**
* @return the platform type
*/
- Type getType();
+ PlatformType getType();
/**
* @return the main plugin directory
@@ -166,8 +167,4 @@ public interface LuckPermsPlugin {
*/
void doSync(Runnable r);
-
- enum Type {
- BUKKIT, BUNGEE, SPONGE;
- }
}
diff --git a/common/src/main/java/me/lucko/luckperms/api/implementation/ApiProvider.java b/common/src/main/java/me/lucko/luckperms/api/implementation/ApiProvider.java
index f2f66e2d2..8c26904c1 100644
--- a/common/src/main/java/me/lucko/luckperms/api/implementation/ApiProvider.java
+++ b/common/src/main/java/me/lucko/luckperms/api/implementation/ApiProvider.java
@@ -67,7 +67,7 @@ public class ApiProvider implements LuckPermsApi {
@Override
public double getApiVersion() {
- return 1.6;
+ return 2.6;
}
@Override
@@ -75,6 +75,11 @@ public class ApiProvider implements LuckPermsApi {
return plugin.getVersion();
}
+ @Override
+ public PlatformType getPlatformType() {
+ return plugin.getType();
+ }
+
@Override
public void registerListener(@NonNull LPListener listener) {
eventBus.register(listener);
diff --git a/common/src/main/java/me/lucko/luckperms/api/implementation/internal/LPConfigurationLink.java b/common/src/main/java/me/lucko/luckperms/api/implementation/internal/LPConfigurationLink.java
index 6d779b571..4659ee89e 100644
--- a/common/src/main/java/me/lucko/luckperms/api/implementation/internal/LPConfigurationLink.java
+++ b/common/src/main/java/me/lucko/luckperms/api/implementation/internal/LPConfigurationLink.java
@@ -27,6 +27,8 @@ import me.lucko.luckperms.api.LPConfiguration;
import me.lucko.luckperms.api.data.DatastoreConfiguration;
import me.lucko.luckperms.api.data.MySQLConfiguration;
+import java.util.Map;
+
/**
* Provides a link between {@link LPConfiguration} and {@link me.lucko.luckperms.core.LPConfiguration}
*/
@@ -79,6 +81,21 @@ public class LPConfigurationLink implements LPConfiguration {
return master.getApplyShorthand();
}
+ @Override
+ public boolean getLogNotify() {
+ return master.getLogNotify();
+ }
+
+ @Override
+ public String getVaultServer() {
+ return master.getVaultServer();
+ }
+
+ @Override
+ public boolean getVaultIncludeGlobal() {
+ return master.getVaultIncludeGlobal();
+ }
+
@SuppressWarnings("deprecation")
@Override
public MySQLConfiguration getDatabaseValues() {
@@ -94,4 +111,15 @@ public class LPConfigurationLink implements LPConfiguration {
public String getStorageMethod() {
return master.getStorageMethod();
}
+
+ @Override
+ public boolean getSplitStorage() {
+ return master.getSplitStorage();
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public Map getSplitStorageOptions() {
+ return master.getSplitStorageOptions();
+ }
}
diff --git a/common/src/main/java/me/lucko/luckperms/commands/SubCommand.java b/common/src/main/java/me/lucko/luckperms/commands/SubCommand.java
index fed730fc0..bb103b8fe 100644
--- a/common/src/main/java/me/lucko/luckperms/commands/SubCommand.java
+++ b/common/src/main/java/me/lucko/luckperms/commands/SubCommand.java
@@ -110,10 +110,11 @@ public abstract class SubCommand {
return permission.isAuthorized(sender);
}
+
/*
- ----------------------------------------------------------------------------------
- Utility methods used by #onTabComplete and #execute implementations in sub classes
- ----------------------------------------------------------------------------------
+ * ----------------------------------------------------------------------------------
+ * Utility methods used by #onTabComplete and #execute implementations in sub classes
+ * ----------------------------------------------------------------------------------
*/
protected static List getGroupTabComplete(List args, LuckPermsPlugin plugin) {
diff --git a/common/src/main/java/me/lucko/luckperms/commands/log/subcommands/LogExport.java b/common/src/main/java/me/lucko/luckperms/commands/log/subcommands/LogExport.java
index 0407d856b..272248dfb 100644
--- a/common/src/main/java/me/lucko/luckperms/commands/log/subcommands/LogExport.java
+++ b/common/src/main/java/me/lucko/luckperms/commands/log/subcommands/LogExport.java
@@ -108,7 +108,7 @@ public class LogExport extends SubCommand {
break track;
}
- b.append("track ").append(e.getActedName()).append(" ").append(e.getAction());;
+ b.append("track ").append(e.getActedName()).append(" ").append(e.getAction());
}
data.add(b.toString());
diff --git a/common/src/main/java/me/lucko/luckperms/commands/migration/subcommands/MigrationPermissionsEx.java b/common/src/main/java/me/lucko/luckperms/commands/migration/subcommands/MigrationPermissionsEx.java
index 78ecd6bf9..0df7363cc 100644
--- a/common/src/main/java/me/lucko/luckperms/commands/migration/subcommands/MigrationPermissionsEx.java
+++ b/common/src/main/java/me/lucko/luckperms/commands/migration/subcommands/MigrationPermissionsEx.java
@@ -24,6 +24,7 @@ package me.lucko.luckperms.commands.migration.subcommands;
import me.lucko.luckperms.LuckPermsPlugin;
import me.lucko.luckperms.api.Logger;
+import me.lucko.luckperms.api.PlatformType;
import me.lucko.luckperms.commands.CommandResult;
import me.lucko.luckperms.commands.Predicate;
import me.lucko.luckperms.commands.Sender;
@@ -62,7 +63,7 @@ public class MigrationPermissionsEx extends SubCommand