Release 2.7

This commit is contained in:
Luck
2016-09-05 20:00:01 +01:00
Unverified
parent ba04fb320b
commit 60bcd5f643
53 changed files with 676 additions and 284 deletions
@@ -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 <code>null</code> 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<UUID> getUniqueUsers();
@@ -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 {
@@ -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<String, String> getSplitStorageOptions();
}
@@ -23,7 +23,7 @@
package me.lucko.luckperms.api;
/**
* A wrapper class for platform logger instances.
* A wrapper interface for platform logger instances.
*
* <p> 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.
@@ -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;
@@ -0,0 +1,314 @@
/*
* Copyright (c) 2016 Lucko (Luck) <luck@lucko.me>
*
* 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<Node> 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<String, String> 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<Integer, String> 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);
}
}
@@ -30,7 +30,7 @@ import java.util.Optional;
/**
* Represents an immutable node object
* <p> Use {@link LuckPermsApi#buildNode(String)} to get an instance.
* @since 1.6
* @since 2.6
*/
@SuppressWarnings("unused")
public interface Node extends Map.Entry<String, Boolean> {
@@ -260,6 +260,9 @@ public interface Node extends Map.Entry<String, Boolean> {
*/
boolean almostEquals(Node node);
/**
* Builds a Node instance
*/
interface Builder {
Builder setNegated(boolean negated);
Builder setValue(boolean value);
@@ -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<Node> getPermissions();
/**
* Similar to {@link #getPermissions()}, except excluding transient permissions
* @return a set of nodes
* @since 1.6
* @since 2.6
*/
Set<Node> getEnduringPermissions();
/**
* Similar to {@link #getPermissions()}, except excluding non-transient permissions
* @return a set of nodes
* @since 1.6
* @since 2.6
*/
Set<Node> 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<Node> 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<String, Boolean> getPermissions(String server, String world, Map<String, String> extraContext, boolean includeGlobal, List<String> 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<Node> 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<Node> getPermanentPermissionNodes();
@@ -0,0 +1,44 @@
/*
* Copyright (c) 2016 Lucko (Luck) <luck@lucko.me>
*
* 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;
}
}
@@ -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 {
@@ -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 {
@@ -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.
*
* <p> 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.
@@ -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<PermissionHolder> {
@@ -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) {
@@ -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) {
@@ -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) {
@@ -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 {
}
@@ -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 {
}
@@ -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 {
}