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 @@ luckperms me.lucko.luckperms - 2.6-SNAPSHOT + 2.7-SNAPSHOT 4.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 @@ luckperms me.lucko.luckperms - 2.6-SNAPSHOT + 2.7-SNAPSHOT 4.0.0 @@ -30,7 +30,7 @@ me.lucko.luckperms luckperms-api - ${project.version} + 2.5 compile 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 @@ luckperms me.lucko.luckperms - 2.6-SNAPSHOT + 2.7-SNAPSHOT 4.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 @@ luckperms me.lucko.luckperms - 2.6-SNAPSHOT + 2.7-SNAPSHOT 4.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 @@ luckperms me.lucko.luckperms - 2.6-SNAPSHOT + 2.7-SNAPSHOT 4.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 { return CommandResult.STATE_ERROR; } - if (plugin.getType() != LuckPermsPlugin.Type.BUKKIT) { + if (plugin.getType() != PlatformType.BUKKIT) { // Sponge uses a completely different version of PEX. log.severe("PEX import is not supported on this platform."); return CommandResult.STATE_ERROR; diff --git a/common/src/main/java/me/lucko/luckperms/core/LPConfiguration.java b/common/src/main/java/me/lucko/luckperms/core/LPConfiguration.java index 747757bc6..f97c24c82 100644 --- a/common/src/main/java/me/lucko/luckperms/core/LPConfiguration.java +++ b/common/src/main/java/me/lucko/luckperms/core/LPConfiguration.java @@ -70,17 +70,19 @@ public abstract class LPConfiguration { } /** - * As of 1.6, this value is a constant + * As of 2.6, this value is a constant * @return the default group node */ + @SuppressWarnings("SameReturnValue") public String getDefaultGroupNode() { return "group.default"; } /** - * As of 1.6, this value is a constant + * As of 2.6, this value is a constant * @return the name of the default group */ + @SuppressWarnings("SameReturnValue") public String getDefaultGroupName() { return "default"; } @@ -109,6 +111,14 @@ public abstract class LPConfiguration { return getBoolean("log-notify", true); } + public String getVaultServer() { + return getString("vault-server", "global"); + } + + public boolean getVaultIncludeGlobal() { + return getBoolean("vault-include-global", true); + } + public DatastoreConfiguration getDatabaseValues() { return new DatastoreConfiguration( getString("data.address", null), diff --git a/common/src/main/java/me/lucko/luckperms/core/UuidCache.java b/common/src/main/java/me/lucko/luckperms/core/UuidCache.java index 8af279f13..af6c7dd83 100644 --- a/common/src/main/java/me/lucko/luckperms/core/UuidCache.java +++ b/common/src/main/java/me/lucko/luckperms/core/UuidCache.java @@ -30,7 +30,7 @@ import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; /** - * @see me.lucko.luckperms.api.UuidCache + * @see me.lucko.luckperms.api.UuidCache for docs */ public class UuidCache { diff --git a/common/src/main/java/me/lucko/luckperms/data/Importer.java b/common/src/main/java/me/lucko/luckperms/data/Importer.java index 7c83ac589..9f0d208d6 100644 --- a/common/src/main/java/me/lucko/luckperms/data/Importer.java +++ b/common/src/main/java/me/lucko/luckperms/data/Importer.java @@ -59,7 +59,6 @@ public class Importer { running = true; return true; - } public void start(Sender executor, List commands) { diff --git a/common/src/main/java/me/lucko/luckperms/runnables/UpdateTask.java b/common/src/main/java/me/lucko/luckperms/runnables/UpdateTask.java index 00ef06f51..1893af5c1 100644 --- a/common/src/main/java/me/lucko/luckperms/runnables/UpdateTask.java +++ b/common/src/main/java/me/lucko/luckperms/runnables/UpdateTask.java @@ -53,6 +53,6 @@ public class UpdateTask implements Runnable { // Refresh all online users. plugin.getUserManager().updateAllUsers(); - plugin.getApiProvider().fireEvent(new PostSyncEvent());; + plugin.getApiProvider().fireEvent(new PostSyncEvent()); } } diff --git a/common/src/main/java/me/lucko/luckperms/storage/methods/MongoDBDatastore.java b/common/src/main/java/me/lucko/luckperms/storage/methods/MongoDBDatastore.java index 688d924c2..c46540779 100644 --- a/common/src/main/java/me/lucko/luckperms/storage/methods/MongoDBDatastore.java +++ b/common/src/main/java/me/lucko/luckperms/storage/methods/MongoDBDatastore.java @@ -445,14 +445,12 @@ public class MongoDBDatastore extends Datastore { The following two methods convert the node maps so they can be stored. */ private static Map convert(Map map) { return map.entrySet().stream() - .map(e -> new AbstractMap.SimpleEntry<>(e.getKey().replace(".", "[**DOT**]").replace("$", "[**DOLLAR**]"), e.getValue())) - .collect(Collectors.toMap(AbstractMap.SimpleEntry::getKey, AbstractMap.SimpleEntry::getValue)); + .collect(Collectors.toMap(e -> e.getKey().replace(".", "[**DOT**]").replace("$", "[**DOLLAR**]"), Map.Entry::getValue)); } private static Map revert(Map map) { return map.entrySet().stream() - .map(e -> new AbstractMap.SimpleEntry<>(e.getKey().replace("[**DOT**]", ".").replace("[**DOLLAR**]", "$"), e.getValue())) - .collect(Collectors.toMap(AbstractMap.SimpleEntry::getKey, AbstractMap.SimpleEntry::getValue)); + .collect(Collectors.toMap(e -> e.getKey().replace("[**DOT**]", ".").replace("[**DOLLAR**]", "$"), Map.Entry::getValue)); } private static Document fromUser(User user) { diff --git a/common/src/main/java/me/lucko/luckperms/storage/methods/YAMLDatastore.java b/common/src/main/java/me/lucko/luckperms/storage/methods/YAMLDatastore.java index 3dd36c4f5..bc039e57a 100644 --- a/common/src/main/java/me/lucko/luckperms/storage/methods/YAMLDatastore.java +++ b/common/src/main/java/me/lucko/luckperms/storage/methods/YAMLDatastore.java @@ -367,6 +367,6 @@ public class YAMLDatastore extends FlatfileDatastore { } interface ReadOperation { - boolean onRun(Map values) throws IOException; + boolean onRun(Map values); } } diff --git a/common/src/main/java/me/lucko/luckperms/utils/AbstractManager.java b/common/src/main/java/me/lucko/luckperms/utils/AbstractManager.java index 14f8e6538..420def3ee 100644 --- a/common/src/main/java/me/lucko/luckperms/utils/AbstractManager.java +++ b/common/src/main/java/me/lucko/luckperms/utils/AbstractManager.java @@ -63,7 +63,7 @@ public abstract class AbstractManager> { } } - public void preSet(T t) { + protected void preSet(T t) { } @@ -108,7 +108,7 @@ public abstract class AbstractManager> { } } - public void preUnload(T t) { + protected void preUnload(T t) { } diff --git a/pom.xml b/pom.xml index beb0b1c54..00f4fa61b 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ me.lucko.luckperms luckperms - 2.6-SNAPSHOT + 2.7-SNAPSHOT common api @@ -37,7 +37,7 @@ UTF-8 - 2.6 + 2.7 diff --git a/sponge/pom.xml b/sponge/pom.xml index 35017b73c..5ff696eda 100644 --- a/sponge/pom.xml +++ b/sponge/pom.xml @@ -5,7 +5,7 @@ luckperms me.lucko.luckperms - 2.6-SNAPSHOT + 2.7-SNAPSHOT 4.0.0 diff --git a/sponge/src/main/java/me/lucko/luckperms/LPSpongePlugin.java b/sponge/src/main/java/me/lucko/luckperms/LPSpongePlugin.java index 430ee0094..4cc95dd8c 100644 --- a/sponge/src/main/java/me/lucko/luckperms/LPSpongePlugin.java +++ b/sponge/src/main/java/me/lucko/luckperms/LPSpongePlugin.java @@ -25,6 +25,7 @@ package me.lucko.luckperms; import com.google.inject.Inject; import lombok.Getter; import me.lucko.luckperms.api.LuckPermsApi; +import me.lucko.luckperms.api.PlatformType; import me.lucko.luckperms.api.implementation.ApiProvider; import me.lucko.luckperms.api.sponge.LuckPermsService; import me.lucko.luckperms.commands.ConsecutiveExecutor; @@ -196,8 +197,8 @@ public class LPSpongePlugin implements LuckPermsPlugin { } @Override - public Type getType() { - return Type.SPONGE; + public PlatformType getType() { + return PlatformType.SPONGE; } @Override 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 index 0104ae555..f8b625508 100644 --- a/sponge/src/main/java/me/lucko/luckperms/api/sponge/LuckPermsSubject.java +++ b/sponge/src/main/java/me/lucko/luckperms/api/sponge/LuckPermsSubject.java @@ -342,9 +342,7 @@ public class LuckPermsSubject implements 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)); + Map contexts = set.stream().collect(Collectors.toMap(Context::getKey, Context::getValue)); try { holder.setPermission(new me.lucko.luckperms.utils.Node.Builder("group." + permsSubject.getIdentifier()) @@ -363,9 +361,7 @@ public class LuckPermsSubject implements 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)); + Map contexts = set.stream().collect(Collectors.toMap(Context::getKey, Context::getValue)); try { holder.unsetPermission(new me.lucko.luckperms.utils.Node.Builder("group." + permsSubject.getIdentifier()) @@ -671,9 +667,7 @@ public class LuckPermsSubject implements 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)); + Map contexts = set.stream().collect(Collectors.toMap(Context::getKey, Context::getValue)); try { holder.setTransientPermission(new me.lucko.luckperms.utils.Node.Builder("group." + permsSubject.getIdentifier()) @@ -691,9 +685,7 @@ public class LuckPermsSubject implements 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)); + Map contexts = set.stream().collect(Collectors.toMap(Context::getKey, Context::getValue)); try { holder.unsetTransientPermission(new me.lucko.luckperms.utils.Node.Builder("group." + permsSubject.getIdentifier())