diff --git a/bukkit/src/main/java/me/lucko/luckperms/bukkit/BukkitConfig.java b/bukkit/src/main/java/me/lucko/luckperms/bukkit/BukkitConfig.java index fbe89526..c17d3d32 100644 --- a/bukkit/src/main/java/me/lucko/luckperms/bukkit/BukkitConfig.java +++ b/bukkit/src/main/java/me/lucko/luckperms/bukkit/BukkitConfig.java @@ -28,7 +28,10 @@ import org.bukkit.configuration.file.YamlConfiguration; import java.io.File; import java.util.HashMap; +import java.util.List; import java.util.Map; +import java.util.Optional; +import java.util.stream.Collectors; class BukkitConfig extends AbstractConfiguration { private YamlConfiguration configuration; @@ -65,6 +68,21 @@ class BukkitConfig extends AbstractConfiguration { return configuration.getBoolean(path, def); } + @Override + protected List getList(String path, List def) { + return Optional.ofNullable(configuration.getStringList(path)).orElse(def); + } + + @Override + protected List getObjectList(String path, List def) { + ConfigurationSection section = configuration.getConfigurationSection(path); + if (section == null) { + return def; + } + + return Optional.ofNullable(section.getKeys(false).stream().collect(Collectors.toList())).orElse(def); + } + @SuppressWarnings("unchecked") @Override protected Map getMap(String path, Map def) { diff --git a/bukkit/src/main/java/me/lucko/luckperms/bukkit/BukkitListener.java b/bukkit/src/main/java/me/lucko/luckperms/bukkit/BukkitListener.java index 879bcb20..21f9e5ba 100644 --- a/bukkit/src/main/java/me/lucko/luckperms/bukkit/BukkitListener.java +++ b/bukkit/src/main/java/me/lucko/luckperms/bukkit/BukkitListener.java @@ -90,8 +90,6 @@ class BukkitListener extends AbstractListener implements Listener { t.printStackTrace(); } - - if (player.isOp()) { // We assume all users are not op, but those who are need extra calculation. diff --git a/bukkit/src/main/resources/config.yml b/bukkit/src/main/resources/config.yml index 3a3e2743..b2f5b2f7 100644 --- a/bukkit/src/main/resources/config.yml +++ b/bukkit/src/main/resources/config.yml @@ -5,6 +5,10 @@ # +------------------------------------------------------------------------+ # ############################################################################## +# +------------------------------------------------------------------------+ # +# | General | # +# +------------------------------------------------------------------------+ # + # The name of the server, used for server specific permissions. Set to 'global' to disable. server: global @@ -24,21 +28,34 @@ apply-global-world-groups: true # If this server is in offline or online mode. # This setting allows a player to have the same UUID across a network of offline mode/mixed servers. - +# # You should generally reflect the setting in server.properties here. Except when... - +# # 1. You have Spigot servers connected to a BungeeCord proxy, with online-mode set to false, but 'bungeecord' set to true in the spigot.yml # AND 'ip-forward' set to true in the BungeeCord config.yml # In this case, set online-mode in LuckPerms to true, despite the server being in offline mode. - +# # 2. You are only running one server instance using LuckPerms, (not a network) # In this case, set online-mode to true no matter what is set in server.properties. (we can just fallback to the servers uuid cache) - +# # 3. If your proxy is running in offline mode, and you are using PaperSpigot (https://ci.destroystokyo.com/job/PaperSpigot/), # you should set "bungee-online-mode" to false in the paper.yml, and set "online-mode" to true in all LuckPerms configs. # This approach is thoroughly recommended for offline mode networks. online-mode: true +# If the plugin should send log notifications to users whenever permissions are modified. +log-notify: true + +# If LuckPerms should print to console every time a plugin checks if a player has a permission +debug-permission-checks: false + + + + +# +------------------------------------------------------------------------+ # +# | Permission Calculation | # +# +------------------------------------------------------------------------+ # + # If the plugin should apply wildcard permissions. # If set to true, LuckPerms will detect wildcard permissions, and resolve & apply all registered permissions matching # the wildcard. @@ -53,11 +70,12 @@ apply-regex: true # If set to true, LuckPerms will detect and expand shorthand node patterns. apply-shorthand: true -# If the plugin should send log notifications to users whenever permissions are modified. -log-notify: true -# If LuckPerms should print to console every time a plugin checks if a player has a permission -debug-permission-checks: false + + +# +------------------------------------------------------------------------+ # +# | OP (Server Operator) Settings | # +# +------------------------------------------------------------------------+ # # 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 @@ -77,6 +95,13 @@ auto-op: false # If opped players should be allowed to use LuckPerms commands. Set to false to only allow users who have the permissions access to the commands commands-allow-op: true + + + +# +------------------------------------------------------------------------+ # +# | Vault | # +# +------------------------------------------------------------------------+ # + # 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 @@ -90,12 +115,19 @@ vault-ignore-world: false # Mirrors world names. Whenever LuckPerms checks what world a user is in, if the world name is in this list, the value assigned # will be sent forward for permission calculation instead. world-rewrite: - #world_nether: world - #world_the_end: world +# world_nether: world +# world_the_end: world # Rewrites group names. The underlying name of the group does not change, just the output in commands / placeholders / Vault. group-name-rewrite: - #default: Member +# default: Member + + + + +# +------------------------------------------------------------------------+ # +# | Storage | # +# +------------------------------------------------------------------------+ # # Which storage method the plugin should use. # Currently supported: mysql, sqlite, h2, json, yaml, mongodb @@ -121,3 +153,62 @@ data: # Set to -1 to disable. If this is the only instance accessing the datastore, you can disable syncing. # e.g. if you're using sqlite or flatfile, this can be set to -1 to save resources. sync-minutes: 3 + + + + +# +------------------------------------------------------------------------+ # +# | Default Assignments | # +# +------------------------------------------------------------------------+ # + +# This section allows you to define defaults to give users whenever they connect to the server. +# The default assignments are highly configurable and conditional. +# +# There is one default assignment built into LuckPerms, which will add all users to the "default" group if they +# are not a member of any other group. This setting cannot be disabled. However, you can use this section to add more of +# your own. +# +# IMPORTANT: +# In order to save storage space, LuckPerms does not store users who have no permissions defined, and are only a member +# of the default group. Adding default assignments to this section will negate this effect. It is HIGHLY RECCOMENDED +# that instead of assigning defaults here, you add permissions to the "default" group, or set the "default" group to inherit +# other groups, and then use the group-name-rewrite rule above. +# +# It is also important to note that these rules are considered every time a player logs into the server, and are applied +# directly to the user's data. Simply removing a rule here will not reserse the effect of that rule on any users who have +# already had it applied to them. +# +# The "has" and "lacks" conditions below support standard boolean logic, using the 'and' & 'or' characters used in Java. +# e.g. "(some.other.permission | some.permission.other) & some.thing.else" == a user has 'some.other.permission', or +# 'some.permission.other', and they also have 'some.thing.else' +# +# Groups are represented by the permission node: group. +# Per server and per world nodes are represented by: "server-world/permission" or "server/permission" +# +# Within conditions, permission nodes MUST be escaped using "<" and ">". See the example below. +# +# Explaination of the examples below: (they're just to demonstrate the features & use cases) +# +# rule1: +# If a user is either in the vip or vip+ group, and they have the "titles.titlecollector" permission set to true, and the +# "some.random.permission" set to false... if they're not in the group "prison_titlepack" on the "prison" server, then +# give add them to the "prison_titlepack" group on the "prison" server, and remove "some.random.permission". +# +# rule2: +# If the user isn't in any of the following groups on the skyblock server: sb_level1, sb_level2, sb_level3, then add +# them to sb_level1 on the skyblock server. +default-assignments: +# rule1: +# if: +# has-true: ( | ) & +# has-false: +# lacks: +# give: +# - prison/group.prison_titlepack +# take: +# - some.random.permission +# rule2: +# if: +# lacks: & & +# give: +# - skyblock/group.sb_level1 \ No newline at end of file diff --git a/bungee/src/main/java/me/lucko/luckperms/bungee/BungeeConfig.java b/bungee/src/main/java/me/lucko/luckperms/bungee/BungeeConfig.java index 9c0d532e..ec7d1d34 100644 --- a/bungee/src/main/java/me/lucko/luckperms/bungee/BungeeConfig.java +++ b/bungee/src/main/java/me/lucko/luckperms/bungee/BungeeConfig.java @@ -32,7 +32,10 @@ import java.io.IOException; import java.io.InputStream; import java.nio.file.Files; import java.util.HashMap; +import java.util.List; import java.util.Map; +import java.util.Optional; +import java.util.stream.Collectors; class BungeeConfig extends AbstractConfiguration { private Configuration configuration; @@ -79,6 +82,21 @@ class BungeeConfig extends AbstractConfiguration { return configuration.getBoolean(path, def); } + @Override + protected List getList(String path, List def) { + return Optional.ofNullable(configuration.getStringList(path)).orElse(def); + } + + @Override + protected List getObjectList(String path, List def) { + Configuration section = configuration.getSection(path); + if (section == null) { + return def; + } + + return Optional.ofNullable(section.getKeys().stream().collect(Collectors.toList())).orElse(def); + } + @Override protected Map getMap(String path, Map def) { Map map = new HashMap<>(); diff --git a/bungee/src/main/resources/config.yml b/bungee/src/main/resources/config.yml index 52adb7cd..f546e424 100644 --- a/bungee/src/main/resources/config.yml +++ b/bungee/src/main/resources/config.yml @@ -5,6 +5,10 @@ # +------------------------------------------------------------------------+ # ############################################################################## +# +------------------------------------------------------------------------+ # +# | General | # +# +------------------------------------------------------------------------+ # + # The name of the server, used for server specific permissions. Set to 'global' to disable. server: bungee @@ -24,21 +28,44 @@ apply-global-world-groups: true # If this server is in offline or online mode. # This setting allows a player to have the same UUID across a network of offline mode/mixed servers. - +# # You should generally reflect the setting in server.properties here. Except when... - +# # 1. You have Spigot servers connected to a BungeeCord proxy, with online-mode set to false, but 'bungeecord' set to true in the spigot.yml # AND 'ip-forward' set to true in the BungeeCord config.yml # In this case, set online-mode in LuckPerms to true, despite the server being in offline mode. - +# # 2. You are only running one server instance using LuckPerms, (not a network) # In this case, set online-mode to true no matter what is set in server.properties. (we can just fallback to the servers uuid cache) - +# # 3. If your proxy is running in offline mode, and you are using PaperSpigot (https://ci.destroystokyo.com/job/PaperSpigot/), # you should set "bungee-online-mode" to false in the paper.yml, and set "online-mode" to true in all LuckPerms configs. # This approach is thoroughly recommended for offline mode networks. online-mode: true +# If the plugin should send log notifications to users whenever permissions are modified. +log-notify: true + +# If LuckPerms should print to console every time a plugin checks if a player has a permission +debug-permission-checks: false + +# Mirrors world names. Whenever LuckPerms checks what world a user is in, if the world name is in this list, the value assigned +# will be sent forward for permission calculation instead. +world-rewrite: +# world_nether: world +# world_the_end: world + +# Rewrites group names. The underlying name of the group does not change, just the output in commands / placeholders / Vault. +group-name-rewrite: +# default: Member + + + + +# +------------------------------------------------------------------------+ # +# | Permission Calculation | # +# +------------------------------------------------------------------------+ # + # If the plugin should apply wildcard permissions. # If set to true, LuckPerms will detect wildcard permissions, and resolve & apply all registered permissions matching # the wildcard. @@ -53,23 +80,12 @@ apply-regex: true # If set to true, LuckPerms will detect and expand shorthand node patterns. apply-shorthand: true -# If the plugin should send log notifications to users whenever permissions are modified. -log-notify: true -# If LuckPerms should print to console every time a plugin checks if a player has a permission -debug-permission-checks: false -# Mirrors world names. Whenever LuckPerms checks what world a user is in, if the world name is in this list, the value assigned -# will be sent forward for permission calculation instead. -# Remember world names on BungeeCord relate to the backend server name a user is connected to. -world-rewrite: - #hub2: hub - #hub3: hub - #opfactions: factions -# Rewrites group names. The underlying name of the group does not change, just the output in commands / placeholders / Vault. -group-name-rewrite: - #default: Member +# +------------------------------------------------------------------------+ # +# | Storage | # +# +------------------------------------------------------------------------+ # # Which storage method the plugin should use. # Currently supported: mysql, sqlite, h2, json, yaml, mongodb @@ -94,4 +110,63 @@ data: # Set to -1 to disable. If this is the only instance accessing the datastore, you can disable syncing. # e.g. if you're using sqlite or flatfile, this can be set to -1 to save resources. - sync-minutes: 3 \ No newline at end of file + sync-minutes: 3 + + + + +# +------------------------------------------------------------------------+ # +# | Default Assignments | # +# +------------------------------------------------------------------------+ # + +# This section allows you to define defaults to give users whenever they connect to the server. +# The default assignments are highly configurable and conditional. +# +# There is one default assignment built into LuckPerms, which will add all users to the "default" group if they +# are not a member of any other group. This setting cannot be disabled. However, you can use this section to add more of +# your own. +# +# IMPORTANT: +# In order to save storage space, LuckPerms does not store users who have no permissions defined, and are only a member +# of the default group. Adding default assignments to this section will negate this effect. It is HIGHLY RECCOMENDED +# that instead of assigning defaults here, you add permissions to the "default" group, or set the "default" group to inherit +# other groups, and then use the group-name-rewrite rule above. +# +# It is also important to note that these rules are considered every time a player logs into the server, and are applied +# directly to the user's data. Simply removing a rule here will not reserse the effect of that rule on any users who have +# already had it applied to them. +# +# The "has" and "lacks" conditions below support standard boolean logic, using the 'and' & 'or' characters used in Java. +# e.g. "(some.other.permission | some.permission.other) & some.thing.else" == a user has 'some.other.permission', or +# 'some.permission.other', and they also have 'some.thing.else' +# +# Groups are represented by the permission node: group. +# Per server and per world nodes are represented by: "server-world/permission" or "server/permission" +# +# Within conditions, permission nodes MUST be escaped using "<" and ">". See the example below. +# +# Explaination of the examples below: (they're just to demonstrate the features & use cases) +# +# rule1: +# If a user is either in the vip or vip+ group, and they have the "titles.titlecollector" permission set to true, and the +# "some.random.permission" set to false... if they're not in the group "prison_titlepack" on the "prison" server, then +# give add them to the "prison_titlepack" group on the "prison" server, and remove "some.random.permission". +# +# rule2: +# If the user isn't in any of the following groups on the skyblock server: sb_level1, sb_level2, sb_level3, then add +# them to sb_level1 on the skyblock server. +default-assignments: +# rule1: +# if: +# has-true: ( | ) & +# has-false: +# lacks: +# give: +# - prison/group.prison_titlepack +# take: +# - some.random.permission +# rule2: +# if: +# lacks: & & +# give: +# - skyblock/group.sb_level1 \ No newline at end of file diff --git a/common/src/main/java/me/lucko/luckperms/common/config/AbstractConfiguration.java b/common/src/main/java/me/lucko/luckperms/common/config/AbstractConfiguration.java index 4852ac57..907accae 100644 --- a/common/src/main/java/me/lucko/luckperms/common/config/AbstractConfiguration.java +++ b/common/src/main/java/me/lucko/luckperms/common/config/AbstractConfiguration.java @@ -22,14 +22,18 @@ package me.lucko.luckperms.common.config; +import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import lombok.AccessLevel; import lombok.Getter; import me.lucko.luckperms.common.LuckPermsPlugin; import me.lucko.luckperms.common.constants.Patterns; +import me.lucko.luckperms.common.defaults.Rule; import me.lucko.luckperms.common.storage.DatastoreConfiguration; +import java.util.ArrayList; import java.util.Collections; +import java.util.List; import java.util.Map; /** @@ -65,6 +69,7 @@ public abstract class AbstractConfiguration implement private boolean vaultIgnoreWorld; private Map worldRewrites; private Map groupNameRewrites; + private List defaultAssignments; private DatastoreConfiguration databaseValues; private String storageMethod; private boolean splitStorage; @@ -80,6 +85,8 @@ public abstract class AbstractConfiguration implement protected abstract String getString(String path, String def); protected abstract int getInt(String path, int def); protected abstract boolean getBoolean(String path, boolean def); + protected abstract List getList(String path, List def); + protected abstract List getObjectList(String path, List def); protected abstract Map getMap(String path, Map def); public void load(String defaultServerName, boolean defaultIncludeGlobal, String defaultStorage) { @@ -105,6 +112,19 @@ public abstract class AbstractConfiguration implement vaultIgnoreWorld = getBoolean("vault-ignore-world", false); worldRewrites = ImmutableMap.copyOf(getMap("world-rewrite", Collections.emptyMap())); groupNameRewrites = ImmutableMap.copyOf(getMap("group-name-rewrite", Collections.emptyMap())); + + ImmutableList.Builder defs = ImmutableList.builder(); + List ruleNames = getObjectList("default-assignments", new ArrayList<>()); + for (String ruleName : ruleNames) { + String hasTrue = getString("default-assignments." + ruleName + ".if.has-true", null); + String hasFalse = getString("default-assignments." + ruleName + ".if.has-false", null); + String lacks = getString("default-assignments." + ruleName + ".if.lacks", null); + List give = getList("default-assignments." + ruleName + ".give", new ArrayList<>()); + List take = getList("default-assignments." + ruleName + ".take", new ArrayList<>()); + defs.add(new Rule(hasTrue, hasFalse, lacks, give, take)); + } + defaultAssignments = defs.build(); + databaseValues = new DatastoreConfiguration( getString("data.address", null), getString("data.database", null), diff --git a/common/src/main/java/me/lucko/luckperms/common/config/LPConfiguration.java b/common/src/main/java/me/lucko/luckperms/common/config/LPConfiguration.java index eea23951..cae17528 100644 --- a/common/src/main/java/me/lucko/luckperms/common/config/LPConfiguration.java +++ b/common/src/main/java/me/lucko/luckperms/common/config/LPConfiguration.java @@ -22,8 +22,10 @@ package me.lucko.luckperms.common.config; +import me.lucko.luckperms.common.defaults.Rule; import me.lucko.luckperms.common.storage.DatastoreConfiguration; +import java.util.List; import java.util.Map; public interface LPConfiguration { @@ -80,6 +82,8 @@ public interface LPConfiguration { Map getGroupNameRewrites(); + List getDefaultAssignments(); + DatastoreConfiguration getDatabaseValues(); String getStorageMethod(); diff --git a/common/src/main/java/me/lucko/luckperms/common/defaults/LogicParser.java b/common/src/main/java/me/lucko/luckperms/common/defaults/LogicParser.java new file mode 100644 index 00000000..c20f61cb --- /dev/null +++ b/common/src/main/java/me/lucko/luckperms/common/defaults/LogicParser.java @@ -0,0 +1,71 @@ +/* + * 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.common.defaults; + +import me.lucko.luckperms.api.Tristate; +import me.lucko.luckperms.common.core.Node; +import me.lucko.luckperms.common.core.PermissionHolder; + +import javax.script.ScriptEngine; +import javax.script.ScriptEngineManager; +import java.util.function.Function; +import java.util.regex.Pattern; + +public class LogicParser { + private static final ScriptEngine SCRIPT_ENGINE = new ScriptEngineManager().getEngineByName("nashorn"); + + public static boolean parse(String s, PermissionHolder holder, Tristate tristate) throws IllegalArgumentException { + try { + String expression = generateExpression(s, s1 -> holder.hasPermission(Node.fromSerialisedNode(s1, true)) == tristate); + String result = SCRIPT_ENGINE.eval(expression).toString(); + + if (!result.equals("true") && !result.equals("false")) { + throw new IllegalArgumentException(); + } + + return Boolean.parseBoolean(result); + + } catch (Throwable t) { + throw new IllegalArgumentException(s, t); + } + } + + private static String generateExpression(String input, Function checker) { + while (true) { + int i = input.indexOf("<"); + int i2 = input.indexOf(">"); + if (i == -1 || i2 == -1) { + break; + } + + String match = input.substring(i, i2 + 1); + String matchContent = match.substring(1, match.length() - 1); + + String matchReplacement = ("" + checker.apply(matchContent)).toLowerCase(); + + input = input.replaceFirst(Pattern.quote(match), matchReplacement); + } + + return input.replace("&", "&&").replace("|", "||"); + } +} diff --git a/common/src/main/java/me/lucko/luckperms/common/defaults/Rule.java b/common/src/main/java/me/lucko/luckperms/common/defaults/Rule.java new file mode 100644 index 00000000..17ca9ff7 --- /dev/null +++ b/common/src/main/java/me/lucko/luckperms/common/defaults/Rule.java @@ -0,0 +1,105 @@ +/* + * 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.common.defaults; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.ToString; +import me.lucko.luckperms.api.Tristate; +import me.lucko.luckperms.common.core.Node; +import me.lucko.luckperms.common.core.PermissionHolder; +import me.lucko.luckperms.exceptions.ObjectAlreadyHasException; +import me.lucko.luckperms.exceptions.ObjectLacksException; + +import java.util.List; + +@Getter +@ToString +@AllArgsConstructor +public class Rule { + private final String hasTrueExpression; + private final String hasFalseExpression; + private final String lacksExpression; + + private final List toGive; + private final List toTake; + + public boolean apply(PermissionHolder holder) { + if (hasTrueExpression != null) { + try { + boolean b = LogicParser.parse(hasTrueExpression, holder, Tristate.TRUE); + if (!b) { + // The holder does not meet this requirement + return false; + } + } catch (IllegalArgumentException e) { + // Couldn't parse + e.printStackTrace(); + return false; + } + } + + if (hasFalseExpression != null) { + try { + boolean b = LogicParser.parse(hasFalseExpression, holder, Tristate.FALSE); + if (!b) { + // The holder does not meet this requirement + return false; + } + } catch (IllegalArgumentException e) { + // Couldn't parse + e.printStackTrace(); + return false; + } + } + + if (lacksExpression != null) { + try { + boolean b = LogicParser.parse(lacksExpression, holder, Tristate.UNDEFINED); + if (!b) { + // The holder does not meet this requirement + return false; + } + } catch (IllegalArgumentException e) { + // Couldn't parse + e.printStackTrace(); + return false; + } + } + + // The holder meets all of the requirements of this rule. + for (String s : toTake) { + try { + holder.unsetPermission(Node.fromSerialisedNode(s, true)); + } catch (ObjectLacksException ignored) {} + } + + for (String s : toGive) { + try { + holder.setPermission(Node.fromSerialisedNode(s, true)); + } catch (ObjectAlreadyHasException ignored) {} + } + + return true; + } +} diff --git a/common/src/main/java/me/lucko/luckperms/common/utils/AbstractListener.java b/common/src/main/java/me/lucko/luckperms/common/utils/AbstractListener.java index a9f31c12..d53b6a77 100644 --- a/common/src/main/java/me/lucko/luckperms/common/utils/AbstractListener.java +++ b/common/src/main/java/me/lucko/luckperms/common/utils/AbstractListener.java @@ -27,6 +27,7 @@ import me.lucko.luckperms.api.data.Callback; import me.lucko.luckperms.api.event.events.UserFirstLoginEvent; import me.lucko.luckperms.common.LuckPermsPlugin; import me.lucko.luckperms.common.core.UuidCache; +import me.lucko.luckperms.common.defaults.Rule; import me.lucko.luckperms.common.users.User; import java.util.UUID; @@ -64,6 +65,19 @@ public class AbstractListener { if (user == null) { plugin.getLog().warn("Failed to load user: " + username); } else { + // Setup defaults for the user + boolean save = false; + for (Rule rule : plugin.getConfiguration().getDefaultAssignments()) { + if (rule.apply(user)) { + save = true; + } + } + + // If they were given a default, persist the new assignments back to the storage. + if (save) { + plugin.getDatastore().saveUser(user); + } + user.setupData(false); // Pretty nasty calculation call. Sets up the caching system so data is ready when the user joins. } diff --git a/sponge/src/main/java/me/lucko/luckperms/sponge/SpongeConfig.java b/sponge/src/main/java/me/lucko/luckperms/sponge/SpongeConfig.java index a530d262..290ef7e8 100644 --- a/sponge/src/main/java/me/lucko/luckperms/sponge/SpongeConfig.java +++ b/sponge/src/main/java/me/lucko/luckperms/sponge/SpongeConfig.java @@ -34,6 +34,7 @@ import java.io.IOException; import java.io.InputStream; import java.nio.file.Files; import java.nio.file.Path; +import java.util.List; import java.util.Map; import java.util.stream.Collectors; @@ -97,9 +98,33 @@ class SpongeConfig extends AbstractConfiguration { return getNode(path).getBoolean(def); } + @Override + protected List getList(String path, List def) { + ConfigurationNode node = getNode(path); + if (node.isVirtual()) { + return def; + } + + return node.getList(Object::toString); + } + + @Override + protected List getObjectList(String path, List def) { + ConfigurationNode node = getNode(path); + if (node.isVirtual()) { + return def; + } + + return node.getChildrenList().stream().map(n -> (String) n.getKey()).collect(Collectors.toList()); + } + @Override protected Map getMap(String path, Map def) { ConfigurationNode node = getNode(path); + if (node.isVirtual()) { + return def; + } + return node.getChildrenList().stream().collect(Collectors.toMap(n -> (String) n.getKey(), ConfigurationNode::getString)); } } diff --git a/sponge/src/main/resources/luckperms.conf b/sponge/src/main/resources/luckperms.conf index 487dc6db..67f50d4d 100644 --- a/sponge/src/main/resources/luckperms.conf +++ b/sponge/src/main/resources/luckperms.conf @@ -5,6 +5,10 @@ # +------------------------------------------------------------------------+ # ############################################################################## +# +------------------------------------------------------------------------+ # +# | General | # +# +------------------------------------------------------------------------+ # + # The name of the server, used for server specific permissions. Set to 'global' to disable. server="global" @@ -24,17 +28,42 @@ apply-global-world-groups=true # If this server is in offline or online mode. # This setting allows a player to have the same UUID across a network of offline mode/mixed servers. - +# # You should generally reflect the setting in server.properties here. Except when... - -# 1. You have Spigot servers connected to a BungeeCord proxy, with online-mode set to false, but 'bungeecord' set to -# true in the spigot.yml AND 'ip-forward' set to true in the BungeeCord config.yml +# +# 1. You have Sponge servers connected to a BungeeCord proxy, with online-mode set to false, but 'bungeecord ip-forwarding' +# set to true in the sponge/global.conf AND 'ip-forward' set to true in the BungeeCord config.yml # In this case, set online-mode in LuckPerms to true, despite the server being in offline mode. - +# # 2. You are only running one server instance using LuckPerms, (not a network) In this case, set online-mode to true no # matter what is set in server.properties. (we can just fallback to the servers uuid cache) online-mode=true +# If the plugin should send log notifications to users whenever permissions are modified. +log-notify=true + +# If LuckPerms should print to console every time a plugin checks if a player has a permission +debug-permission-checks=false + +# Mirrors world names. Whenever LuckPerms checks what world a user is in, if the world name is in this list, the value assigned +# will be sent forward for permission calculation instead. +world-rewrite { +# world_nether="world" +# world_the_end="world" +} + +# Rewrites group names. The underlying name of the group does not change, just the output in commands / placeholders / Vault. +group-name-rewrite { +# default="Member" +} + + + + +# +------------------------------------------------------------------------+ # +# | Permission Calculation | # +# +------------------------------------------------------------------------+ # + # If the plugin should apply wildcard permissions. # If set to true, LuckPerms will detect wildcard permissions, and resolve & apply all registered permissions matching # the wildcard. @@ -49,23 +78,12 @@ apply-regex=true # If set to true, LuckPerms will detect and expand shorthand node patterns. apply-shorthand=true -# If LuckPerms should print to console every time a plugin checks if a player has a permission -debug-permission-checks=false -# If the plugin should send log notifications to users whenever permissions are modified. -log-notify=true -# Mirrors world names. Whenever LuckPerms checks what world a user is in, if the world name is in this list, the value assigned -# will be sent forward for permission calculation instead. -world-rewrite: { - #world_nether="world" - #world_the_end="world" -} -# Rewrites group names. The underlying name of the group does not change, just the output in commands / placeholders / Vault. -group-name-rewrite: { - #default: "Member" -} +# +------------------------------------------------------------------------+ # +# | Storage | # +# +------------------------------------------------------------------------+ # # Which storage method the plugin should use. # Currently supported: mysql, sqlite, h2, json, yaml, mongodb @@ -73,9 +91,9 @@ group-name-rewrite: { storage-method="h2" # This block enables support for split datastores. -split-storage: { +split-storage { enabled=false - methods: { + methods { user="h2" group="h2" track="h2" @@ -84,7 +102,7 @@ split-storage: { } } -data: { +data { address="localhost:3306" database="minecraft" username="root" @@ -94,3 +112,70 @@ data: { # e.g. if you're using sqlite or flatfile, this can be set to -1 to save resources. sync-minutes=3 } + + + + +# +------------------------------------------------------------------------+ # +# | Default Assignments | # +# +------------------------------------------------------------------------+ # + +# This section allows you to define defaults to give users whenever they connect to the server. +# The default assignments are highly configurable and conditional. +# +# There is one default assignment built into LuckPerms, which will add all users to the "default" group if they +# are not a member of any other group. This setting cannot be disabled. However, you can use this section to add more of +# your own. +# +# IMPORTANT: +# In order to save storage space, LuckPerms does not store users who have no permissions defined, and are only a member +# of the default group. Adding default assignments to this section will negate this effect. It is HIGHLY RECCOMENDED +# that instead of assigning defaults here, you add permissions to the "default" group, or set the "default" group to inherit +# other groups, and then use the group-name-rewrite rule above. +# +# It is also important to note that these rules are considered every time a player logs into the server, and are applied +# directly to the user's data. Simply removing a rule here will not reserse the effect of that rule on any users who have +# already had it applied to them. +# +# The "has" and "lacks" conditions below support standard boolean logic, using the 'and' & 'or' characters used in Java. +# e.g. "(some.other.permission | some.permission.other) & some.thing.else" == a user has 'some.other.permission', or +# 'some.permission.other', and they also have 'some.thing.else' +# +# Groups are represented by the permission node: group. +# Per server and per world nodes are represented by: "server-world/permission" or "server/permission" +# +# Within conditions, permission nodes MUST be escaped using "<" and ">". See the example below. +# +# Explaination of the examples below: (they're just to demonstrate the features & use cases) +# +# rule1: +# If a user is either in the vip or vip+ group, and they have the "titles.titlecollector" permission set to true, and the +# "some.random.permission" set to false... if they're not in the group "prison_titlepack" on the "prison" server, then +# give add them to the "prison_titlepack" group on the "prison" server, and remove "some.random.permission". +# +# rule2: +# If the user isn't in any of the following groups on the skyblock server: sb_level1, sb_level2, sb_level3, then add +# them to sb_level1 on the skyblock server. +default-assignments { +# rule1 { +# if { +# has-true="( | ) & " +# has-false="" +# lacks="" +# } +# give = [ +# "prison/group.prison_titlepack" +# ] +# take = [ +# "some.random.permission" +# ] +# } +# rule2 { +# if { +# lacks=" & & " +# } +# give = [ +# "skyblock/group.sb_level1" +# ] +# } +}