diff --git a/api/pom.xml b/api/pom.xml
index 373c71a5..c43589f7 100644
--- a/api/pom.xml
+++ b/api/pom.xml
@@ -5,7 +5,7 @@
luckperms
me.lucko.luckperms
- 2.7-SNAPSHOT
+ 2.8-SNAPSHOT
4.0.0
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 db3c5c42..d56b0fb8 100644
--- a/api/src/main/java/me/lucko/luckperms/api/LPConfiguration.java
+++ b/api/src/main/java/me/lucko/luckperms/api/LPConfiguration.java
@@ -88,6 +88,18 @@ public interface LPConfiguration {
*/
boolean getLogNotify();
+ /**
+ * @return true if the vanilla op system is enabled
+ * @since 2.8
+ */
+ boolean getEnableOps();
+
+ /**
+ * @return true if opped players are allowed to use LuckPerms commands
+ * @since 2.8
+ */
+ boolean getCommandsAllowOp();
+
/**
* @return the name of the server used within Vault operations
* @since 2.7
diff --git a/api/src/main/java/me/lucko/luckperms/api/MetaUtils.java b/api/src/main/java/me/lucko/luckperms/api/MetaUtils.java
index 8cb1880b..9145c83a 100644
--- a/api/src/main/java/me/lucko/luckperms/api/MetaUtils.java
+++ b/api/src/main/java/me/lucko/luckperms/api/MetaUtils.java
@@ -36,6 +36,8 @@ import java.util.Set;
*/
public class MetaUtils {
+ private MetaUtils(){}
+
/**
* Escapes special characters used within LuckPerms, so the string can be saved without issues
* @param s the string to escape
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 2e07a322..5d9f9f80 100644
--- a/api/src/main/java/me/lucko/luckperms/api/Node.java
+++ b/api/src/main/java/me/lucko/luckperms/api/Node.java
@@ -247,18 +247,34 @@ public interface Node extends Map.Entry {
Map.Entry getSuffix();
/**
- * Similar to {@link #equals(Object)}, except doesn't take note of the value
- * @param node the other node
- * @return true if the two nodes are almost equal
+ * Checks if this Node is equal to another node
+ * @param obj the other node
+ * @return true if this node is equal to the other provided
+ * @see #equalsIgnoringValue(Node) for a less strict implementation of this method
*/
- boolean equalsIgnoringValue(Node node);
+ boolean equals(Object obj);
/**
- * Similar to {@link #equals(Object)}, except doesn't take note of the expiry time or value
- * @param node the other node
+ * Similar to {@link Node#equals(Object)}, except doesn't take note of the value
+ * @param other the other node
* @return true if the two nodes are almost equal
*/
- boolean almostEquals(Node node);
+ boolean equalsIgnoringValue(Node other);
+
+ /**
+ * Similar to {@link Node#equals(Object)}, except doesn't take note of the expiry time or value
+ * @param other the other node
+ * @return true if the two nodes are almost equal
+ */
+ boolean almostEquals(Node other);
+
+ /**
+ * Similar to {@link Node#equals(Object)}, except doesn't take note of the value or if the node is temporary
+ * @param other the other node
+ * @return true if the two nodes are almost equal
+ * @since 2.8
+ */
+ boolean equalsIgnoringValueOrTemp(Node other);
/**
* Builds a Node instance
diff --git a/bukkit-placeholders/pom.xml b/bukkit-placeholders/pom.xml
index fb1e97a9..f2ae87a6 100644
--- a/bukkit-placeholders/pom.xml
+++ b/bukkit-placeholders/pom.xml
@@ -5,7 +5,7 @@
luckperms
me.lucko.luckperms
- 2.7-SNAPSHOT
+ 2.8-SNAPSHOT
4.0.0
diff --git a/bukkit/pom.xml b/bukkit/pom.xml
index 76853a69..eb888b42 100644
--- a/bukkit/pom.xml
+++ b/bukkit/pom.xml
@@ -5,7 +5,7 @@
luckperms
me.lucko.luckperms
- 2.7-SNAPSHOT
+ 2.8-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 513575e1..233d972c 100644
--- a/bukkit/src/main/java/me/lucko/luckperms/BukkitListener.java
+++ b/bukkit/src/main/java/me/lucko/luckperms/BukkitListener.java
@@ -105,4 +105,22 @@ class BukkitListener extends AbstractListener implements Listener {
plugin.getUserManager().getWorldCache().remove(e.getPlayer().getUniqueId());
onLeave(e.getPlayer().getUniqueId());
}
+
+ @EventHandler
+ public void onPlayerCommand(PlayerCommandPreprocessEvent e) {
+ if (plugin.getConfiguration().getEnableOps()) {
+ return;
+ }
+
+ String s = e.getMessage()
+ .replace("/", "")
+ .replace("bukkit:", "")
+ .replace("spigot:", "")
+ .replace("minecraft:", "");
+
+ if (s.startsWith("op") || s.startsWith("deop")) {
+ e.setCancelled(true);
+ e.getPlayer().sendMessage(Message.OP_DISABLED.toString());
+ }
+ }
}
diff --git a/bukkit/src/main/java/me/lucko/luckperms/LPBukkitPlugin.java b/bukkit/src/main/java/me/lucko/luckperms/LPBukkitPlugin.java
index 385350a3..cc8536b1 100644
--- a/bukkit/src/main/java/me/lucko/luckperms/LPBukkitPlugin.java
+++ b/bukkit/src/main/java/me/lucko/luckperms/LPBukkitPlugin.java
@@ -44,6 +44,8 @@ import me.lucko.luckperms.users.BukkitUserManager;
import me.lucko.luckperms.utils.LogFactory;
import org.bukkit.command.PluginCommand;
import org.bukkit.entity.Player;
+import org.bukkit.permissions.Permission;
+import org.bukkit.permissions.PermissionDefault;
import org.bukkit.plugin.PluginManager;
import org.bukkit.plugin.ServicePriority;
import org.bukkit.plugin.java.JavaPlugin;
@@ -133,6 +135,11 @@ public class LPBukkitPlugin extends JavaPlugin implements LuckPermsPlugin {
e.printStackTrace();
}
+ registerPermissions(getConfiguration().getCommandsAllowOp() ? PermissionDefault.OP : PermissionDefault.FALSE);
+ if (!getConfiguration().getEnableOps()) {
+ getServer().getOperators().forEach(o -> o.setOp(false));
+ }
+
getLog().info("Successfully loaded.");
}
@@ -237,4 +244,34 @@ public class LPBukkitPlugin extends JavaPlugin implements LuckPermsPlugin {
public void runUpdateTask() {
getServer().getScheduler().runTaskAsynchronously(this, new UpdateTask(this));
}
+
+ private void registerPermissions(PermissionDefault def) {
+ PluginManager pm = getServer().getPluginManager();
+
+ Map> wildcards = new HashMap<>();
+ List all = new ArrayList<>();
+ for (me.lucko.luckperms.constants.Permission p : me.lucko.luckperms.constants.Permission.values()) {
+ pm.addPermission(new Permission(p.getNode(), def));
+ if (p.getGroup() != null) {
+ if (!wildcards.containsKey(p.getGroup())) {
+ wildcards.put(p.getGroup(), new ArrayList<>());
+ }
+ wildcards.get(p.getGroup()).add(p.getTag());
+ }
+
+ all.add(p.getNode());
+ }
+
+ for (Map.Entry> e : wildcards.entrySet()) {
+ pm.addPermission(new Permission(
+ "luckperms." + e.getKey() + ".*", def,
+ e.getValue().stream()
+ .map(tag -> "luckperms." + e.getKey() + "." + tag)
+ .collect(Collectors.toMap(s -> s, s -> false))
+ )
+ );
+ }
+
+ pm.addPermission(new Permission("luckperms.*", def, all.stream().collect(Collectors.toMap(s -> s, s -> false))));
+ }
}
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 5160b75d..c0d94c26 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
@@ -109,7 +109,7 @@ public class VaultChatHook extends Chat {
if (node.equals("")) return defaultValue;
node = escapeCharacters(node);
- for (Node n : holder.getPermissions()) {
+ for (Node n : holder.getPermissions(true)) {
if (!n.getValue()) {
continue;
}
diff --git a/bukkit/src/main/resources/config.yml b/bukkit/src/main/resources/config.yml
index 63d6c39c..6a222eb7 100644
--- a/bukkit/src/main/resources/config.yml
+++ b/bukkit/src/main/resources/config.yml
@@ -46,6 +46,12 @@ apply-shorthand: true
# If the plugin should send log notifications to users whenever permissions are modified.
log-notify: true
+# If the vanilla OP system is enabled. If set to false, all users will be de-opped, and the op/deop commands will be disabled.
+enable-ops: true
+
+# If opped players should be allowed to use LuckPerms commands. Set to false to only allow users with the permission access
+commands-allow-op: 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
diff --git a/bukkit/src/main/resources/plugin.yml b/bukkit/src/main/resources/plugin.yml
index f26b324f..a5854a40 100644
--- a/bukkit/src/main/resources/plugin.yml
+++ b/bukkit/src/main/resources/plugin.yml
@@ -12,159 +12,5 @@ commands:
description: Manage permissions
aliases: [perms, permissions, lp, p, perm]
-permissions:
- luckperms.*:
- description: Gives access to all LuckPerms commands
- children:
- luckperms.sync: true
- luckperms.info: true
- luckperms.debug: true
- luckperms.import: true
- luckperms.creategroup: true
- luckperms.deletegroup: true
- luckperms.listgroups: true
- luckperms.createtrack: true
- luckperms.deletetrack: true
- luckperms.listtracks: true
- luckperms.user.info: true
- luckperms.user.getuuid: true
- luckperms.user.listnodes: true
- luckperms.user.haspermission: true
- luckperms.user.inheritspermission: true
- luckperms.user.setpermission: true
- luckperms.user.unsetpermission: true
- luckperms.user.addgroup: true
- luckperms.user.removegroup: true
- luckperms.user.settemppermission: true
- luckperms.user.unsettemppermission: true
- luckperms.user.addtempgroup: true
- luckperms.user.removetempgroup: true
- luckperms.user.setprimarygroup: true
- luckperms.user.showtracks: true
- luckperms.user.promote: true
- luckperms.user.demote: true
- luckperms.user.showpos: true
- luckperms.user.chatmeta: true
- luckperms.user.addprefix: true
- luckperms.user.addsuffix: true
- luckperms.user.removeprefix: true
- luckperms.user.removesuffix: true
- luckperms.user.addtempprefix: true
- luckperms.user.addtempsuffix: true
- luckperms.user.removetempprefix: true
- luckperms.user.removetempsuffix: true
- luckperms.user.clear: true
- luckperms.group.info: true
- luckperms.group.listnodes: true
- luckperms.group.haspermission: true
- luckperms.group.inheritspermission: true
- luckperms.group.setpermission: true
- luckperms.group.unsetpermission: true
- luckperms.group.setinherit: true
- luckperms.group.unsetinherit: true
- luckperms.group.settemppermission: true
- luckperms.group.unsettemppermission: true
- luckperms.group.settempinherit: true
- luckperms.group.unsettempinherit: true
- luckperms.group.showtracks: true
- luckperms.group.chatmeta: true
- luckperms.group.addprefix: true
- luckperms.group.addsuffix: true
- luckperms.group.removeprefix: true
- luckperms.group.removesuffix: true
- luckperms.group.addtempprefix: true
- luckperms.group.addtempsuffix: true
- luckperms.group.removetempprefix: true
- luckperms.group.removetempsuffix: true
- luckperms.group.clear: true
- luckperms.group.rename: true
- luckperms.track.info: true
- luckperms.track.append: true
- luckperms.track.insert: true
- luckperms.track.remove: true
- luckperms.track.clear: true
- luckperms.track.rename: true
- luckperms.log.export: true
- luckperms.log.userhistory: true
- luckperms.log.grouphistory: true
- luckperms.log.trackhistory: true
- luckperms.log.notify: true
- luckperms.log.recent: true
- luckperms.log.search: true
- luckperms.user.*:
- description: Gives access to all LuckPerms user commands
- children:
- luckperms.user.info: true
- luckperms.user.getuuid: true
- luckperms.user.listnodes: true
- luckperms.user.haspermission: true
- luckperms.user.inheritspermission: true
- luckperms.user.setpermission: true
- luckperms.user.unsetpermission: true
- luckperms.user.addgroup: true
- luckperms.user.removegroup: true
- luckperms.user.settemppermission: true
- luckperms.user.unsettemppermission: true
- luckperms.user.addtempgroup: true
- luckperms.user.removetempgroup: true
- luckperms.user.setprimarygroup: true
- luckperms.user.showtracks: true
- luckperms.user.promote: true
- luckperms.user.demote: true
- luckperms.user.showpos: true
- luckperms.user.chatmeta: true
- luckperms.user.addprefix: true
- luckperms.user.addsuffix: true
- luckperms.user.removeprefix: true
- luckperms.user.removesuffix: true
- luckperms.user.addtempprefix: true
- luckperms.user.addtempsuffix: true
- luckperms.user.removetempprefix: true
- luckperms.user.removetempsuffix: true
- luckperms.user.clear: true
- luckperms.group.*:
- description: Gives access to all LuckPerms group commands
- children:
- luckperms.group.info: true
- luckperms.group.listnodes: true
- luckperms.group.haspermission: true
- luckperms.group.inheritspermission: true
- luckperms.group.setpermission: true
- luckperms.group.unsetpermission: true
- luckperms.group.setinherit: true
- luckperms.group.unsetinherit: true
- luckperms.group.settemppermission: true
- luckperms.group.unsettemppermission: true
- luckperms.group.settempinherit: true
- luckperms.group.unsettempinherit: true
- luckperms.group.showtracks: true
- luckperms.group.chatmeta: true
- luckperms.group.addprefix: true
- luckperms.group.addsuffix: true
- luckperms.group.removeprefix: true
- luckperms.group.removesuffix: true
- luckperms.group.addtempprefix: true
- luckperms.group.addtempsuffix: true
- luckperms.group.removetempprefix: true
- luckperms.group.removetempsuffix: true
- luckperms.group.clear: true
- luckperms.group.rename: true
- luckperms.track.*:
- description: Gives access to all LuckPerms track commands
- children:
- luckperms.track.info: true
- luckperms.track.append: true
- luckperms.track.insert: true
- luckperms.track.remove: true
- luckperms.track.clear: true
- luckperms.track.rename: true
- luckperms.log.*:
- description: Gives access to all LuckPerms log commands
- children:
- luckperms.log.export: true
- luckperms.log.userhistory: true
- luckperms.log.grouphistory: true
- luckperms.log.trackhistory: true
- luckperms.log.notify: true
- luckperms.log.recent: true
- luckperms.log.search: true
\ No newline at end of file
+
+# Permissions are registered programmatically instead of here.
\ No newline at end of file
diff --git a/bungee/pom.xml b/bungee/pom.xml
index ad4f826a..6466420c 100644
--- a/bungee/pom.xml
+++ b/bungee/pom.xml
@@ -5,7 +5,7 @@
luckperms
me.lucko.luckperms
- 2.7-SNAPSHOT
+ 2.8-SNAPSHOT
4.0.0
diff --git a/common/pom.xml b/common/pom.xml
index 2a1c43dd..0e2fcf5a 100644
--- a/common/pom.xml
+++ b/common/pom.xml
@@ -5,7 +5,7 @@
luckperms
me.lucko.luckperms
- 2.7-SNAPSHOT
+ 2.8-SNAPSHOT
4.0.0
@@ -112,6 +112,10 @@
org.bukkit
bukkit
+
+ net.gravitydevelopment.updater
+ updater
+
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 16a98be0..342fb6f3 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 2.7;
+ return 2.8;
}
@Override
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 4659ee89..4be9a22f 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
@@ -86,6 +86,16 @@ public class LPConfigurationLink implements LPConfiguration {
return master.getLogNotify();
}
+ @Override
+ public boolean getEnableOps() {
+ return master.getEnableOps();
+ }
+
+ @Override
+ public boolean getCommandsAllowOp() {
+ return master.getCommandsAllowOp();
+ }
+
@Override
public String getVaultServer() {
return master.getVaultServer();
diff --git a/common/src/main/java/me/lucko/luckperms/api/implementation/internal/PermissionHolderLink.java b/common/src/main/java/me/lucko/luckperms/api/implementation/internal/PermissionHolderLink.java
index 4bb2f96a..2cbf0016 100644
--- a/common/src/main/java/me/lucko/luckperms/api/implementation/internal/PermissionHolderLink.java
+++ b/common/src/main/java/me/lucko/luckperms/api/implementation/internal/PermissionHolderLink.java
@@ -52,7 +52,7 @@ public class PermissionHolderLink implements PermissionHolder {
@Override
public SortedSet getPermissions() {
- return Collections.unmodifiableSortedSet(master.getPermissions());
+ return Collections.unmodifiableSortedSet(master.getPermissions(false));
}
@Override
diff --git a/common/src/main/java/me/lucko/luckperms/commands/SenderFactory.java b/common/src/main/java/me/lucko/luckperms/commands/SenderFactory.java
index 26b1daa6..c79dfd33 100644
--- a/common/src/main/java/me/lucko/luckperms/commands/SenderFactory.java
+++ b/common/src/main/java/me/lucko/luckperms/commands/SenderFactory.java
@@ -24,6 +24,7 @@ package me.lucko.luckperms.commands;
import com.google.common.collect.ImmutableMap;
import lombok.Getter;
+import me.lucko.luckperms.constants.Constants;
import me.lucko.luckperms.constants.Permission;
import java.lang.ref.WeakReference;
@@ -46,39 +47,7 @@ public abstract class SenderFactory implements Runnable {
protected abstract boolean hasPermission(T t, String node);
public final Sender wrap(T t) {
- return new Sender() {
- final WeakReference tRef = new WeakReference<>(t);
-
- // Cache these permissions, so they can be accessed async
- final Map perms = ImmutableMap.copyOf(Arrays.stream(Permission.values())
- .collect(Collectors.toMap(p -> p, p -> factory.hasPermission(t, p.getNode()))));
-
- @Getter
- final String name = factory.getName(t);
-
- @Getter
- final UUID uuid = factory.getUuid(t);
-
- @Override
- public void sendMessage(String s) {
- final T t = tRef.get();
- if (t != null) {
- synchronized (messages) {
- if (!messages.containsKey(t)) {
- messages.put(t, new ArrayList<>());
- }
-
- messages.get(t).add(s);
- }
- shouldSend.set(true);
- }
- }
-
- @Override
- public boolean hasPermission(Permission permission) {
- return perms.get(permission);
- }
- };
+ return new SenderImp(t);
}
@Override
@@ -97,4 +66,51 @@ public abstract class SenderFactory implements Runnable {
messages.clear();
}
}
+
+ private class SenderImp implements Sender {
+ private final WeakReference tRef;
+
+ // Cache these permissions, so they can be accessed async
+ private Map perms;
+
+ @Getter
+ private final String name;
+
+ @Getter
+ private final UUID uuid;
+
+ private final boolean console;
+
+ private SenderImp(T t) {
+ this.tRef = new WeakReference<>(t);
+ this.name = factory.getName(t);
+ this.uuid = factory.getUuid(t);
+ this.console = this.uuid.equals(Constants.getConsoleUUID()) || this.uuid.equals(Constants.getImporterUUID());
+
+ if (!this.console) {
+ this.perms = ImmutableMap.copyOf(Arrays.stream(Permission.values())
+ .collect(Collectors.toMap(p -> p, p -> factory.hasPermission(t, p.getNode()))));
+ }
+ }
+
+ @Override
+ public void sendMessage(String s) {
+ final T t = tRef.get();
+ if (t != null) {
+ synchronized (messages) {
+ if (!messages.containsKey(t)) {
+ messages.put(t, new ArrayList<>());
+ }
+
+ messages.get(t).add(s);
+ }
+ shouldSend.set(true);
+ }
+ }
+
+ @Override
+ public boolean hasPermission(Permission permission) {
+ return console || perms.get(permission);
+ }
+ }
}
diff --git a/common/src/main/java/me/lucko/luckperms/commands/group/subcommands/GroupListNodes.java b/common/src/main/java/me/lucko/luckperms/commands/group/subcommands/GroupListNodes.java
index 98a4da5a..11707b4d 100644
--- a/common/src/main/java/me/lucko/luckperms/commands/group/subcommands/GroupListNodes.java
+++ b/common/src/main/java/me/lucko/luckperms/commands/group/subcommands/GroupListNodes.java
@@ -38,8 +38,8 @@ public class GroupListNodes extends SubCommand {
@Override
public CommandResult execute(LuckPermsPlugin plugin, Sender sender, Group group, List args, String label) {
- Message.LISTNODES.send(sender, group.getName(), Util.permNodesToString(group.getPermissions()));
- Message.LISTNODES_TEMP.send(sender, group.getName(), Util.tempNodesToString(group.getPermissions()));
+ Message.LISTNODES.send(sender, group.getName(), Util.permNodesToString(group.getPermissions(false)));
+ Message.LISTNODES_TEMP.send(sender, group.getName(), Util.tempNodesToString(group.getPermissions(false)));
return CommandResult.SUCCESS;
}
}
diff --git a/common/src/main/java/me/lucko/luckperms/commands/user/subcommands/UserListNodes.java b/common/src/main/java/me/lucko/luckperms/commands/user/subcommands/UserListNodes.java
index 854c2637..8d34d0dc 100644
--- a/common/src/main/java/me/lucko/luckperms/commands/user/subcommands/UserListNodes.java
+++ b/common/src/main/java/me/lucko/luckperms/commands/user/subcommands/UserListNodes.java
@@ -38,8 +38,8 @@ public class UserListNodes extends SubCommand {
@Override
public CommandResult execute(LuckPermsPlugin plugin, Sender sender, User user, List args, String label) {
- Message.LISTNODES.send(sender, user.getName(), Util.permNodesToString(user.getPermissions()));
- Message.LISTNODES_TEMP.send(sender, user.getName(), Util.tempNodesToString(user.getPermissions()));
+ Message.LISTNODES.send(sender, user.getName(), Util.permNodesToString(user.getPermissions(false)));
+ Message.LISTNODES_TEMP.send(sender, user.getName(), Util.tempNodesToString(user.getPermissions(false)));
return CommandResult.SUCCESS;
}
}
diff --git a/common/src/main/java/me/lucko/luckperms/constants/Message.java b/common/src/main/java/me/lucko/luckperms/constants/Message.java
index 0eba3f02..231e67bd 100644
--- a/common/src/main/java/me/lucko/luckperms/constants/Message.java
+++ b/common/src/main/java/me/lucko/luckperms/constants/Message.java
@@ -40,6 +40,7 @@ public enum Message {
PLAYER_ONLINE("&aOnline", false),
PLAYER_OFFLINE("&cOffline", false),
LOADING_ERROR("Permissions data could not be loaded. Please contact an administrator.", true),
+ OP_DISABLED("&eThe vanilla OP system is disabled on this server.", false),
LOG("&3LOG &3&l> %s", true),
COMMAND_NOT_RECOGNISED("Command not recognised.", true),
diff --git a/common/src/main/java/me/lucko/luckperms/constants/Permission.java b/common/src/main/java/me/lucko/luckperms/constants/Permission.java
index c783a258..cb72a936 100644
--- a/common/src/main/java/me/lucko/luckperms/constants/Permission.java
+++ b/common/src/main/java/me/lucko/luckperms/constants/Permission.java
@@ -23,9 +23,11 @@
package me.lucko.luckperms.constants;
import lombok.AllArgsConstructor;
+import lombok.Getter;
import me.lucko.luckperms.commands.Sender;
@SuppressWarnings("SpellCheckingInspection")
+@Getter
@AllArgsConstructor
public enum Permission {
@@ -113,15 +115,15 @@ public enum Permission {
MIGRATION("migration", null);
- private String node;
+ private String tag;
private String group;
public String getNode() {
if (group != null) {
- return "luckperms." + group + "." + node;
+ return "luckperms." + group + "." + tag;
}
- return "luckperms." + node;
+ return "luckperms." + tag;
}
public boolean isAuthorized(Sender sender) {
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 f97c24c8..4d36c267 100644
--- a/common/src/main/java/me/lucko/luckperms/core/LPConfiguration.java
+++ b/common/src/main/java/me/lucko/luckperms/core/LPConfiguration.java
@@ -111,6 +111,14 @@ public abstract class LPConfiguration {
return getBoolean("log-notify", true);
}
+ public boolean getEnableOps() {
+ return getBoolean("enable-ops", true);
+ }
+
+ public boolean getCommandsAllowOp() {
+ return getBoolean("commands-allow-op", true);
+ }
+
public String getVaultServer() {
return getString("vault-server", "global");
}
diff --git a/common/src/main/java/me/lucko/luckperms/core/PermissionHolder.java b/common/src/main/java/me/lucko/luckperms/core/PermissionHolder.java
index 39bbc5ba..8743065c 100644
--- a/common/src/main/java/me/lucko/luckperms/core/PermissionHolder.java
+++ b/common/src/main/java/me/lucko/luckperms/core/PermissionHolder.java
@@ -77,20 +77,26 @@ public abstract class PermissionHolder {
* Returns a Set of nodes in priority order
* @return the holders transient and permanent nodes
*/
- public SortedSet getPermissions() {
+ public SortedSet getPermissions(boolean mergeTemp) {
// Returns no duplicate nodes. as in, nodes with the same value.
- TreeSet combined = new TreeSet<>(PRIORITY_COMPARATOR);
+ TreeSet combined = new TreeSet<>(PriorityComparator.reverse());
combined.addAll(nodes);
combined.addAll(transientNodes);
- TreeSet permissions = new TreeSet<>(PRIORITY_COMPARATOR);
+ TreeSet permissions = new TreeSet<>(PriorityComparator.reverse());
combined:
for (Node node : combined) {
for (Node other : permissions) {
- if (node.equalsIgnoringValue(other)) {
- continue combined;
+ if (mergeTemp) {
+ if (node.equalsIgnoringValueOrTemp(other)) {
+ continue combined;
+ }
+ } else {
+ if (node.almostEquals(other)) {
+ continue combined;
+ }
}
}
@@ -138,7 +144,7 @@ public abstract class PermissionHolder {
* @return a set of nodes
*/
public SortedSet getAllNodes(List excludedGroups) {
- SortedSet all = getPermissions();
+ SortedSet all = getPermissions(true);
if (excludedGroups == null) {
excludedGroups = new ArrayList<>();
@@ -146,7 +152,7 @@ public abstract class PermissionHolder {
excludedGroups.add(getObjectName().toLowerCase());
- Set parents = getPermissions().stream()
+ Set parents = getPermissions(true).stream()
.filter(Node::isGroupNode)
.map(Node::getGroupName)
.collect(Collectors.toSet());
@@ -190,11 +196,12 @@ public abstract class PermissionHolder {
SortedSet allNodes;
if (applyGroups) {
- allNodes = sort(getAllNodes(null), true);
+ allNodes = getAllNodes(null);
} else {
- allNodes = sort(getPermissions(), true);
+ allNodes = getPermissions(true);
}
+ all:
for (Node node : allNodes) {
if (!node.shouldApplyOnServer(server, includeGlobal, plugin.getConfiguration().getApplyRegex())) {
continue;
@@ -208,6 +215,13 @@ public abstract class PermissionHolder {
continue;
}
+ // Force higher priority nodes to override
+ for (Node alreadyIn : perms) {
+ if (node.getPermission().equals(alreadyIn.getPermission())) {
+ continue all;
+ }
+ }
+
perms.add(node);
}
@@ -502,7 +516,7 @@ public abstract class PermissionHolder {
* @return The temporary nodes held by the holder
*/
public Set getTemporaryNodes() {
- return getPermissions().stream().filter(Node::isTemporary).collect(Collectors.toSet());
+ return getPermissions(false).stream().filter(Node::isTemporary).collect(Collectors.toSet());
}
@Deprecated
@@ -520,7 +534,7 @@ public abstract class PermissionHolder {
* @return The permanent nodes held by the holder
*/
public Set getPermanentNodes() {
- return getPermissions().stream().filter(Node::isPermanent).collect(Collectors.toSet());
+ return getPermissions(false).stream().filter(Node::isPermanent).collect(Collectors.toSet());
}
/*
@@ -541,51 +555,4 @@ public abstract class PermissionHolder {
public Map getLocalPermissions(String server, List excludedGroups) {
return getLocalPermissions(server, null, excludedGroups, null);
}
-
- public static SortedSet sort(Set toSort, boolean reversed) {
- TreeSet set = new TreeSet<>(reversed ? PRIORITY_COMPARATOR.reversed() : PRIORITY_COMPARATOR);
- set.addAll(toSort);
- return set;
- }
-
- private static final PriorityComparator PRIORITY_COMPARATOR = new PriorityComparator();
- private static class PriorityComparator implements Comparator {
-
- @Override
- public int compare(Node o1, Node o2) {
- if (o1.equals(o2)) {
- return 0;
- }
-
- if (o1.isOverride() != o2.isOverride()) {
- return o1.isOverride() ? 1 : -1;
- }
-
- if (o1.isServerSpecific() != o2.isServerSpecific()) {
- return o1.isServerSpecific() ? 1 : -1;
- }
-
- if (o1.isWorldSpecific() != o2.isWorldSpecific()) {
- return o1.isWorldSpecific() ? 1 : -1;
- }
-
- if (o1.isTemporary() != o2.isTemporary()) {
- return o1.isTemporary() ? 1 : -1;
- }
-
- if (o1.isWildcard() != o2.isWildcard()) {
- return o1.isWildcard() ? 1 : -1;
- }
-
- if (o1.isTemporary()) {
- return o1.getSecondsTilExpiry() < o2.getSecondsTilExpiry() ? 1 : -1;
- }
-
- if (o1.isWildcard()) {
- return o1.getWildcardLevel() > o2.getWildcardLevel() ? 1 : -1;
- }
-
- return 1;
- }
- }
}
diff --git a/common/src/main/java/me/lucko/luckperms/core/PriorityComparator.java b/common/src/main/java/me/lucko/luckperms/core/PriorityComparator.java
new file mode 100644
index 00000000..9103b4da
--- /dev/null
+++ b/common/src/main/java/me/lucko/luckperms/core/PriorityComparator.java
@@ -0,0 +1,79 @@
+/*
+ * 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.core;
+
+import lombok.AccessLevel;
+import lombok.NoArgsConstructor;
+import me.lucko.luckperms.api.Node;
+
+import java.util.Comparator;
+
+@NoArgsConstructor(access = AccessLevel.PRIVATE)
+public class PriorityComparator implements Comparator {
+ private static final PriorityComparator instance = new PriorityComparator();
+
+ public static Comparator get() {
+ return instance;
+ }
+
+ public static Comparator reverse() {
+ return instance.reversed();
+ }
+
+ @Override
+ public int compare(Node o1, Node o2) {
+ if (o1.equals(o2)) {
+ return 0;
+ }
+
+ if (o1.isOverride() != o2.isOverride()) {
+ return o1.isOverride() ? 1 : -1;
+ }
+
+ if (o1.isServerSpecific() != o2.isServerSpecific()) {
+ return o1.isServerSpecific() ? 1 : -1;
+ }
+
+ if (o1.isWorldSpecific() != o2.isWorldSpecific()) {
+ return o1.isWorldSpecific() ? 1 : -1;
+ }
+
+ if (o1.isTemporary() != o2.isTemporary()) {
+ return o1.isTemporary() ? 1 : -1;
+ }
+
+ if (o1.isWildcard() != o2.isWildcard()) {
+ return o1.isWildcard() ? 1 : -1;
+ }
+
+ if (o1.isTemporary()) {
+ return o1.getSecondsTilExpiry() < o2.getSecondsTilExpiry() ? 1 : -1;
+ }
+
+ if (o1.isWildcard()) {
+ return o1.getWildcardLevel() > o2.getWildcardLevel() ? 1 : -1;
+ }
+
+ return 1;
+ }
+}
diff --git a/common/src/main/java/me/lucko/luckperms/users/UserManager.java b/common/src/main/java/me/lucko/luckperms/users/UserManager.java
index 0e565784..3f6b79fe 100644
--- a/common/src/main/java/me/lucko/luckperms/users/UserManager.java
+++ b/common/src/main/java/me/lucko/luckperms/users/UserManager.java
@@ -74,7 +74,7 @@ public abstract class UserManager extends AbstractManager {
*/
public void giveDefaultIfNeeded(User user, boolean save) {
boolean hasGroup = false;
- for (Node node : user.getPermissions()) {
+ for (Node node : user.getPermissions(false)) {
if (node.isGroupNode()) {
hasGroup = true;
break;
diff --git a/common/src/main/java/me/lucko/luckperms/utils/Node.java b/common/src/main/java/me/lucko/luckperms/utils/Node.java
index 27867d2f..4963f610 100644
--- a/common/src/main/java/me/lucko/luckperms/utils/Node.java
+++ b/common/src/main/java/me/lucko/luckperms/utils/Node.java
@@ -156,7 +156,7 @@ public class Node implements me.lucko.luckperms.api.Node {
}
public boolean isServerSpecific() {
- return getServer().isPresent();
+ return getServer().isPresent() && !getServer().get().equalsIgnoreCase("global");
}
public boolean isWorldSpecific() {
@@ -170,28 +170,7 @@ public class Node implements me.lucko.luckperms.api.Node {
}
if (isServerSpecific()) {
- if (server.toLowerCase().startsWith("r=") && applyRegex) {
- Pattern p = Patterns.compile(server.substring(2));
- if (p == null) {
- return false;
- }
- return p.matcher(this.server).matches();
- }
-
- if (server.startsWith("(") && server.endsWith(")") && server.contains("|")) {
- final String bits = server.substring(1, server.length() - 1);
- String[] parts = Patterns.VERTICAL_BAR.split(bits);
-
- for (String s : parts) {
- if (s.equalsIgnoreCase(this.server)) {
- return true;
- }
- }
-
- return false;
- }
-
- return this.server.equalsIgnoreCase(server);
+ return shouldApply(server, applyRegex, this.server);
} else {
return includeGlobal;
}
@@ -204,33 +183,37 @@ public class Node implements me.lucko.luckperms.api.Node {
}
if (isWorldSpecific()) {
- if (world.toLowerCase().startsWith("r=") && applyRegex) {
- Pattern p = Patterns.compile(world.substring(2));
- if (p == null) {
- return false;
- }
- return p.matcher(this.world).matches();
- }
-
- if (world.startsWith("(") && world.endsWith(")") && world.contains("|")) {
- final String bits = world.substring(1, world.length() - 1);
- String[] parts = Patterns.VERTICAL_BAR.split(bits);
-
- for (String s : parts) {
- if (s.equalsIgnoreCase(this.world)) {
- return true;
- }
- }
-
- return false;
- }
-
- return this.world.equalsIgnoreCase(world);
+ return shouldApply(world, applyRegex, this.world);
} else {
return includeGlobal;
}
}
+ private static boolean shouldApply(String world, boolean applyRegex, String thisWorld) {
+ if (world.toLowerCase().startsWith("r=") && applyRegex) {
+ Pattern p = Patterns.compile(world.substring(2));
+ if (p == null) {
+ return false;
+ }
+ return p.matcher(thisWorld).matches();
+ }
+
+ if (world.startsWith("(") && world.endsWith(")") && world.contains("|")) {
+ final String bits = world.substring(1, world.length() - 1);
+ String[] parts = Patterns.VERTICAL_BAR.split(bits);
+
+ for (String s : parts) {
+ if (s.equalsIgnoreCase(thisWorld)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ return thisWorld.equalsIgnoreCase(world);
+ }
+
@Override
public boolean shouldApplyWithContext(Map context) {
if (context == null || context.isEmpty()) {
@@ -530,6 +513,8 @@ public class Node implements me.lucko.luckperms.api.Node {
return false;
}
}
+ } else {
+ return false;
}
if (other.getWorld().isPresent() == this.getWorld().isPresent()) {
@@ -538,6 +523,8 @@ public class Node implements me.lucko.luckperms.api.Node {
return false;
}
}
+ } else {
+ return false;
}
if (!other.getExtraContexts().equals(this.getExtraContexts())) {
@@ -563,6 +550,8 @@ public class Node implements me.lucko.luckperms.api.Node {
return false;
}
}
+ } else {
+ return false;
}
if (other.getWorld().isPresent() == this.getWorld().isPresent()) {
@@ -571,6 +560,41 @@ public class Node implements me.lucko.luckperms.api.Node {
return false;
}
}
+ } else {
+ return false;
+ }
+
+ if (!other.getExtraContexts().equals(this.getExtraContexts())) {
+ return false;
+ }
+
+ return true;
+ }
+
+ @Override
+ public boolean equalsIgnoringValueOrTemp(me.lucko.luckperms.api.Node other) {
+ if (!other.getPermission().equalsIgnoreCase(this.getPermission())) {
+ return false;
+ }
+
+ if (other.getServer().isPresent() == this.getServer().isPresent()) {
+ if (other.getServer().isPresent()) {
+ if (!other.getServer().get().equalsIgnoreCase(this.getServer().get())) {
+ return false;
+ }
+ }
+ } else {
+ return false;
+ }
+
+ if (other.getWorld().isPresent() == this.getWorld().isPresent()) {
+ if (other.getWorld().isPresent()) {
+ if (!other.getWorld().get().equalsIgnoreCase(this.getWorld().get())) {
+ return false;
+ }
+ }
+ } else {
+ return false;
}
if (!other.getExtraContexts().equals(this.getExtraContexts())) {
diff --git a/pom.xml b/pom.xml
index 00f4fa61..89dcb172 100644
--- a/pom.xml
+++ b/pom.xml
@@ -6,7 +6,7 @@
me.lucko.luckperms
luckperms
- 2.7-SNAPSHOT
+ 2.8-SNAPSHOT
common
api
@@ -37,7 +37,7 @@
UTF-8
- 2.7
+ 2.8
diff --git a/sponge/pom.xml b/sponge/pom.xml
index 5ff696ed..16848800 100644
--- a/sponge/pom.xml
+++ b/sponge/pom.xml
@@ -5,7 +5,7 @@
luckperms
me.lucko.luckperms
- 2.7-SNAPSHOT
+ 2.8-SNAPSHOT
4.0.0