diff --git a/bukkit/src/main/java/me/lucko/luckperms/bukkit/migration/MigrationGroupManager.java b/bukkit/src/main/java/me/lucko/luckperms/bukkit/migration/MigrationGroupManager.java index 856599ba..74443d09 100644 --- a/bukkit/src/main/java/me/lucko/luckperms/bukkit/migration/MigrationGroupManager.java +++ b/bukkit/src/main/java/me/lucko/luckperms/bukkit/migration/MigrationGroupManager.java @@ -238,7 +238,7 @@ public class MigrationGroupManager extends SubCommand { String primaryGroup = primaryGroups.get(e.getKey()); if (primaryGroup != null) { user.setPermissionUnchecked(NodeFactory.make("group." + primaryGroup)); - user.setPrimaryGroup(primaryGroup); + user.getPrimaryGroup().setStoredValue(primaryGroup); user.unsetPermissionUnchecked(NodeFactory.make("group.default")); } diff --git a/bukkit/src/main/java/me/lucko/luckperms/bukkit/migration/MigrationPermissionsEx.java b/bukkit/src/main/java/me/lucko/luckperms/bukkit/migration/MigrationPermissionsEx.java index ac9f5a9c..9923be1c 100644 --- a/bukkit/src/main/java/me/lucko/luckperms/bukkit/migration/MigrationPermissionsEx.java +++ b/bukkit/src/main/java/me/lucko/luckperms/bukkit/migration/MigrationPermissionsEx.java @@ -221,7 +221,7 @@ public class MigrationPermissionsEx extends SubCommand { if (primary != null && !primary.equalsIgnoreCase("default")) { lpUser.setPermissionUnchecked(NodeFactory.make("group." + primary.toLowerCase())); - lpUser.setPrimaryGroup(primary); + lpUser.getPrimaryGroup().setStoredValue(primary); lpUser.unsetPermissionUnchecked(NodeFactory.make("group.default")); } diff --git a/bukkit/src/main/java/me/lucko/luckperms/bukkit/migration/MigrationPowerfulPerms.java b/bukkit/src/main/java/me/lucko/luckperms/bukkit/migration/MigrationPowerfulPerms.java index c70f7a0f..630c5ba6 100644 --- a/bukkit/src/main/java/me/lucko/luckperms/bukkit/migration/MigrationPowerfulPerms.java +++ b/bukkit/src/main/java/me/lucko/luckperms/bukkit/migration/MigrationPowerfulPerms.java @@ -262,7 +262,7 @@ public class MigrationPowerfulPerms extends SubCommand { String primary = joinFuture(pm.getPlayerPrimaryGroup(uuid)).getName().toLowerCase(); if (!primary.equals("default")) { user.setPermissionUnchecked(NodeFactory.make("group." + primary)); - user.setPrimaryGroup(primary); + user.getPrimaryGroup().setStoredValue(primary); } plugin.getUserManager().cleanup(user); diff --git a/bukkit/src/main/java/me/lucko/luckperms/bukkit/migration/MigrationZPermissions.java b/bukkit/src/main/java/me/lucko/luckperms/bukkit/migration/MigrationZPermissions.java index 4bef499f..726fb801 100644 --- a/bukkit/src/main/java/me/lucko/luckperms/bukkit/migration/MigrationZPermissions.java +++ b/bukkit/src/main/java/me/lucko/luckperms/bukkit/migration/MigrationZPermissions.java @@ -132,7 +132,7 @@ public class MigrationZPermissions extends SubCommand { plugin.getStorage().loadUser(u, username).join(); User user = plugin.getUserManager().get(u); migrateEntity(user, entity, internalService.getGroups(u)); - user.setPrimaryGroup(MigrationUtils.standardizeName(service.getPlayerPrimaryGroup(u))); + user.getPrimaryGroup().setStoredValue(MigrationUtils.standardizeName(service.getPlayerPrimaryGroup(u))); plugin.getUserManager().cleanup(user); plugin.getStorage().saveUser(user); diff --git a/bukkit/src/main/java/me/lucko/luckperms/bukkit/vault/VaultPermissionHook.java b/bukkit/src/main/java/me/lucko/luckperms/bukkit/vault/VaultPermissionHook.java index 64bde9a4..b79fd7ad 100644 --- a/bukkit/src/main/java/me/lucko/luckperms/bukkit/vault/VaultPermissionHook.java +++ b/bukkit/src/main/java/me/lucko/luckperms/bukkit/vault/VaultPermissionHook.java @@ -323,7 +323,7 @@ public class VaultPermissionHook extends Permission { // nothing special, just return the value. if (!isPgo()) { - String g = user.getPrimaryGroup(); + String g = user.getPrimaryGroup().getValue(); return plugin.getConfiguration().get(ConfigKeys.GROUP_NAME_REWRITES).getOrDefault(g, g); } @@ -376,7 +376,7 @@ public class VaultPermissionHook extends Permission { } // Fallback - String g = user.getPrimaryGroup(); + String g = user.getPrimaryGroup().getValue(); return plugin.getConfiguration().get(ConfigKeys.GROUP_NAME_REWRITES).getOrDefault(g, g); } diff --git a/bukkit/src/main/resources/config.yml b/bukkit/src/main/resources/config.yml index 7a0f6195..41c88811 100644 --- a/bukkit/src/main/resources/config.yml +++ b/bukkit/src/main/resources/config.yml @@ -56,6 +56,14 @@ log-notify: true # If "deny": the command will just fail if you try to add another node with the same expiry temporary-add-behaviour: deny +# How should LuckPerms determine a users "primary" group. +# +# Available Options: +# -> stored use the value stored against the users record in the file/database +# -> parents-by-weight just use the users most highly weighted parent +# -> all-parents-by-weight same as above, but calculates based upon all parents inherits from both directly and indirectly +primary-group-calculation: stored + diff --git a/bungee/src/main/resources/config.yml b/bungee/src/main/resources/config.yml index b918ddd2..b65cfeef 100644 --- a/bungee/src/main/resources/config.yml +++ b/bungee/src/main/resources/config.yml @@ -66,6 +66,14 @@ group-name-rewrite: # If "deny": the command will just fail if you try to add another node with the same expiry temporary-add-behaviour: deny +# How should LuckPerms determine a users "primary" group. +# +# Available Options: +# -> stored use the value stored against the users record in the file/database +# -> parents-by-weight just use the users most highly weighted parent +# -> all-parents-by-weight same as above, but calculates based upon all parents inherits from both directly and indirectly +primary-group-calculation: stored + diff --git a/common/src/main/java/me/lucko/luckperms/common/api/delegates/UserDelegate.java b/common/src/main/java/me/lucko/luckperms/common/api/delegates/UserDelegate.java index 301c8f02..b76b9777 100644 --- a/common/src/main/java/me/lucko/luckperms/common/api/delegates/UserDelegate.java +++ b/common/src/main/java/me/lucko/luckperms/common/api/delegates/UserDelegate.java @@ -63,7 +63,7 @@ public final class UserDelegate extends PermissionHolderDelegate implements User @Override public String getPrimaryGroup() { - return master.getPrimaryGroup(); + return master.getPrimaryGroup().getValue(); } @Override @@ -76,7 +76,7 @@ public final class UserDelegate extends PermissionHolderDelegate implements User throw new IllegalStateException("User is not a member of that group."); } - master.setPrimaryGroup(s.toLowerCase()); + master.getPrimaryGroup().setStoredValue(s.toLowerCase()); } @Override diff --git a/common/src/main/java/me/lucko/luckperms/common/commands/impl/generic/parent/ParentRemove.java b/common/src/main/java/me/lucko/luckperms/common/commands/impl/generic/parent/ParentRemove.java index 5342a065..07f2d434 100644 --- a/common/src/main/java/me/lucko/luckperms/common/commands/impl/generic/parent/ParentRemove.java +++ b/common/src/main/java/me/lucko/luckperms/common/commands/impl/generic/parent/ParentRemove.java @@ -29,6 +29,7 @@ import me.lucko.luckperms.common.commands.abstraction.SharedSubCommand; import me.lucko.luckperms.common.commands.sender.Sender; import me.lucko.luckperms.common.commands.utils.ArgumentUtils; import me.lucko.luckperms.common.commands.utils.ContextHelper; +import me.lucko.luckperms.common.config.ConfigKeys; import me.lucko.luckperms.common.constants.Message; import me.lucko.luckperms.common.constants.Permission; import me.lucko.luckperms.common.core.model.PermissionHolder; @@ -68,7 +69,8 @@ public class ParentRemove extends SharedSubCommand { boolean shouldPrevent = (context == ContextHelper.CommandContext.NONE || (context == ContextHelper.CommandContext.SERVER && server.equalsIgnoreCase("global"))) && - user.getPrimaryGroup().equalsIgnoreCase(groupName); + plugin.getConfiguration().get(ConfigKeys.PRIMARY_GROUP_CALCULATION_METHOD).equals("stored") && + user.getPrimaryGroup().getStoredValue().equalsIgnoreCase(groupName); if (shouldPrevent) { Message.USER_REMOVEGROUP_ERROR_PRIMARY.send(sender); diff --git a/common/src/main/java/me/lucko/luckperms/common/commands/impl/generic/parent/ParentSet.java b/common/src/main/java/me/lucko/luckperms/common/commands/impl/generic/parent/ParentSet.java index 498d3f9d..79d6abc7 100644 --- a/common/src/main/java/me/lucko/luckperms/common/commands/impl/generic/parent/ParentSet.java +++ b/common/src/main/java/me/lucko/luckperms/common/commands/impl/generic/parent/ParentSet.java @@ -82,7 +82,7 @@ public class ParentSet extends SharedSubCommand { } catch (ObjectAlreadyHasException ignored) {} if (holder instanceof User) { - ((User) holder).setPrimaryGroup(group.getName()); + ((User) holder).getPrimaryGroup().setStoredValue(group.getName()); } Message.SET_PARENT_SUCCESS.send(sender, holder.getFriendlyName(), group.getDisplayName()); @@ -96,7 +96,7 @@ public class ParentSet extends SharedSubCommand { } if (server.equalsIgnoreCase("global") && holder instanceof User) { - ((User) holder).setPrimaryGroup(group.getName()); + ((User) holder).getPrimaryGroup().setStoredValue(group.getName()); } Message.SET_PARENT_SERVER_SUCCESS.send(sender, holder.getFriendlyName(), group.getDisplayName(), server); diff --git a/common/src/main/java/me/lucko/luckperms/common/commands/impl/user/UserDemote.java b/common/src/main/java/me/lucko/luckperms/common/commands/impl/user/UserDemote.java index cd0a11d9..16c956c8 100644 --- a/common/src/main/java/me/lucko/luckperms/common/commands/impl/user/UserDemote.java +++ b/common/src/main/java/me/lucko/luckperms/common/commands/impl/user/UserDemote.java @@ -170,8 +170,8 @@ public class UserDemote extends SubCommand { user.setPermission(NodeFactory.newBuilder("group." + previousGroup.getName()).setServer(server).setWorld(world).build()); } catch (ObjectAlreadyHasException ignored) {} - if (server == null && world == null && user.getPrimaryGroup().equalsIgnoreCase(old)) { - user.setPrimaryGroup(previousGroup.getName()); + if (server == null && world == null && user.getPrimaryGroup().getStoredValue().equalsIgnoreCase(old)) { + user.getPrimaryGroup().setStoredValue(previousGroup.getName()); } switch (ContextHelper.determine(server, world)) { diff --git a/common/src/main/java/me/lucko/luckperms/common/commands/impl/user/UserInfo.java b/common/src/main/java/me/lucko/luckperms/common/commands/impl/user/UserInfo.java index bfa9d3be..bfd14104 100644 --- a/common/src/main/java/me/lucko/luckperms/common/commands/impl/user/UserInfo.java +++ b/common/src/main/java/me/lucko/luckperms/common/commands/impl/user/UserInfo.java @@ -54,7 +54,7 @@ public class UserInfo extends SubCommand { user.getName(), user.getUuid(), plugin.getPlayerStatus(user.getUuid()), - user.getPrimaryGroup(), + user.getPrimaryGroup().getValue(), user.getPermanentNodes().size(), user.getTemporaryNodes().size(), user.getPrefixNodes().size(), diff --git a/common/src/main/java/me/lucko/luckperms/common/commands/impl/user/UserPromote.java b/common/src/main/java/me/lucko/luckperms/common/commands/impl/user/UserPromote.java index 9845067c..a5c60f64 100644 --- a/common/src/main/java/me/lucko/luckperms/common/commands/impl/user/UserPromote.java +++ b/common/src/main/java/me/lucko/luckperms/common/commands/impl/user/UserPromote.java @@ -187,8 +187,8 @@ public class UserPromote extends SubCommand { user.setPermission(NodeFactory.newBuilder("group." + nextGroup.getName()).setServer(server).setWorld(world).build()); } catch (ObjectAlreadyHasException ignored) {} - if (server == null && world == null && user.getPrimaryGroup().equalsIgnoreCase(old)) { - user.setPrimaryGroup(nextGroup.getName()); + if (server == null && world == null && user.getPrimaryGroup().getStoredValue().equalsIgnoreCase(old)) { + user.getPrimaryGroup().setStoredValue(nextGroup.getName()); } switch (ContextHelper.determine(server, world)) { diff --git a/common/src/main/java/me/lucko/luckperms/common/commands/impl/user/UserSwitchPrimaryGroup.java b/common/src/main/java/me/lucko/luckperms/common/commands/impl/user/UserSwitchPrimaryGroup.java index 04dcb6ed..e0b2d7c8 100644 --- a/common/src/main/java/me/lucko/luckperms/common/commands/impl/user/UserSwitchPrimaryGroup.java +++ b/common/src/main/java/me/lucko/luckperms/common/commands/impl/user/UserSwitchPrimaryGroup.java @@ -27,6 +27,7 @@ import me.lucko.luckperms.common.commands.CommandException; import me.lucko.luckperms.common.commands.CommandResult; import me.lucko.luckperms.common.commands.abstraction.SubCommand; import me.lucko.luckperms.common.commands.sender.Sender; +import me.lucko.luckperms.common.config.ConfigKeys; import me.lucko.luckperms.common.constants.Message; import me.lucko.luckperms.common.constants.Permission; import me.lucko.luckperms.common.core.model.Group; @@ -47,13 +48,18 @@ public class UserSwitchPrimaryGroup extends SubCommand { @Override public CommandResult execute(LuckPermsPlugin plugin, Sender sender, User user, List args, String label) throws CommandException { + String opt = plugin.getConfiguration().get(ConfigKeys.PRIMARY_GROUP_CALCULATION_METHOD); + if (!opt.equals("stored")) { + Message.USER_PRIMARYGROUP_WARN_OPTION.send(sender, opt); + } + Group group = plugin.getGroupManager().getIfLoaded(args.get(0).toLowerCase()); if (group == null) { Message.GROUP_DOES_NOT_EXIST.send(sender); return CommandResult.INVALID_ARGS; } - if (user.getPrimaryGroup().equalsIgnoreCase(group.getName())) { + if (user.getPrimaryGroup().getStoredValue().equalsIgnoreCase(group.getName())) { Message.USER_PRIMARYGROUP_ERROR_ALREADYHAS.send(sender); return CommandResult.STATE_ERROR; } @@ -66,7 +72,7 @@ public class UserSwitchPrimaryGroup extends SubCommand { } } - user.setPrimaryGroup(group.getName()); + user.getPrimaryGroup().setStoredValue(group.getName()); Message.USER_PRIMARYGROUP_SUCCESS.send(sender, user.getName(), group.getDisplayName()); LogEntry.build().actor(sender).acted(user) .action("setprimarygroup " + group.getName()) diff --git a/common/src/main/java/me/lucko/luckperms/common/commands/impl/usersbulkedit/BulkEditGroup.java b/common/src/main/java/me/lucko/luckperms/common/commands/impl/usersbulkedit/BulkEditGroup.java index 22b40fe2..5e05061e 100644 --- a/common/src/main/java/me/lucko/luckperms/common/commands/impl/usersbulkedit/BulkEditGroup.java +++ b/common/src/main/java/me/lucko/luckperms/common/commands/impl/usersbulkedit/BulkEditGroup.java @@ -91,7 +91,7 @@ public class BulkEditGroup extends SubCommand { continue; } - if (element.getGroupName().equals(user.getPrimaryGroup())) { + if (element.getGroupName().equals(user.getPrimaryGroup().getStoredValue())) { if (!element.isServerSpecific() && !element.isWorldSpecific() && !element.isTemporary()) { continue; } @@ -117,7 +117,7 @@ public class BulkEditGroup extends SubCommand { continue; } - if (element.getGroupName().equals(user.getPrimaryGroup())) { + if (element.getGroupName().equals(user.getPrimaryGroup().getStoredValue())) { continue; } diff --git a/common/src/main/java/me/lucko/luckperms/common/config/ConfigKeys.java b/common/src/main/java/me/lucko/luckperms/common/config/ConfigKeys.java index 4c233ec1..37c619d1 100644 --- a/common/src/main/java/me/lucko/luckperms/common/config/ConfigKeys.java +++ b/common/src/main/java/me/lucko/luckperms/common/config/ConfigKeys.java @@ -37,7 +37,12 @@ import me.lucko.luckperms.common.config.keys.MapKey; import me.lucko.luckperms.common.config.keys.StaticKey; import me.lucko.luckperms.common.config.keys.StringKey; import me.lucko.luckperms.common.core.TemporaryModifier; +import me.lucko.luckperms.common.core.model.User; import me.lucko.luckperms.common.defaults.Rule; +import me.lucko.luckperms.common.primarygroup.AllParentsByWeightHolder; +import me.lucko.luckperms.common.primarygroup.ParentsByWeightHolder; +import me.lucko.luckperms.common.primarygroup.PrimaryGroupHolder; +import me.lucko.luckperms.common.primarygroup.StoredHolder; import me.lucko.luckperms.common.storage.DatastoreConfiguration; import me.lucko.luckperms.common.utils.ImmutableCollectors; @@ -46,6 +51,7 @@ import java.lang.reflect.Modifier; import java.util.ArrayList; import java.util.List; import java.util.Map; +import java.util.function.Function; @UtilityClass public class ConfigKeys { @@ -70,6 +76,25 @@ public class ConfigKeys { return TemporaryModifier.valueOf(option.toUpperCase()); }); + public static final ConfigKey PRIMARY_GROUP_CALCULATION_METHOD = EnduringKey.wrap(AbstractKey.of(c -> { + String option = c.getString("primary-group-calculation", "stored").toLowerCase(); + if (!option.equals("stored") && !option.equals("parents-by-weight") && !option.equals("all-parents-by-weight")) { + option = "stored"; + } + + return option; + })); + public static final ConfigKey> PRIMARY_GROUP_CALCULATION = EnduringKey.wrap(AbstractKey.of(c -> { + String option = PRIMARY_GROUP_CALCULATION_METHOD.get(c); + switch (option) { + case "stored": + return (Function) StoredHolder::new; + case "parents-by-weight": + return (Function) ParentsByWeightHolder::new; + default: + return (Function) AllParentsByWeightHolder::new; + } + })); public static final ConfigKey APPLYING_WILDCARDS = EnduringKey.wrap(BooleanKey.of("apply-wildcards", true)); public static final ConfigKey APPLYING_REGEX = EnduringKey.wrap(BooleanKey.of("apply-regex", true)); public static final ConfigKey APPLYING_SHORTHAND = EnduringKey.wrap(BooleanKey.of("apply-shorthand", true)); diff --git a/common/src/main/java/me/lucko/luckperms/common/constants/Message.java b/common/src/main/java/me/lucko/luckperms/common/constants/Message.java index ff26e164..d262055f 100644 --- a/common/src/main/java/me/lucko/luckperms/common/constants/Message.java +++ b/common/src/main/java/me/lucko/luckperms/common/constants/Message.java @@ -330,6 +330,7 @@ public enum Message { USER_GETUUID("&bThe UUID of &b{0}&b is &b{1}&b.", true), USER_REMOVEGROUP_ERROR_PRIMARY("You cannot remove a user from their primary group.", true), USER_PRIMARYGROUP_SUCCESS("&b{0}&a's primary group was set to &b{1}&a.", true), + USER_PRIMARYGROUP_WARN_OPTION("&cWarning: The primary group calculation method being used by this server &7({0}) &cmay not reflect this change.", true), USER_PRIMARYGROUP_ERROR_ALREADYHAS("The user already has this group set as their primary group.", true), USER_PRIMARYGROUP_ERROR_NOTMEMBER("&b{0}&a was not already a member of &b{1}&a, adding them now.", true), USER_TRACK_ERROR_NOT_CONTAIN_GROUP("The user specified isn't already in any groups on this track.", true), diff --git a/common/src/main/java/me/lucko/luckperms/common/core/model/PermissionHolder.java b/common/src/main/java/me/lucko/luckperms/common/core/model/PermissionHolder.java index 7bb6d79b..88fc82fa 100644 --- a/common/src/main/java/me/lucko/luckperms/common/core/model/PermissionHolder.java +++ b/common/src/main/java/me/lucko/luckperms/common/core/model/PermissionHolder.java @@ -95,7 +95,7 @@ public abstract class PermissionHolder { /** * Reference to the main plugin instance */ - @Getter(AccessLevel.PROTECTED) + @Getter private final LuckPermsPlugin plugin; /** @@ -168,10 +168,6 @@ public abstract class PermissionHolder { } }); - - - /* Caching apply methods. Are just called by the caching instances to gather data about the instance. */ - protected void forceCleanup() { getAllNodesCache.cleanUp(); getAllNodesFilteredCache.cleanUp(); @@ -221,6 +217,8 @@ public abstract class PermissionHolder { declareState(); } + /* Caching apply methods. Are just called by the caching instances to gather data about the instance. */ + private ImmutableSortedSet cacheApply(boolean mergeTemp) { TreeSet combined = new TreeSet<>(PriorityComparator.reverse()); Set enduring = getNodes(); diff --git a/common/src/main/java/me/lucko/luckperms/common/core/model/User.java b/common/src/main/java/me/lucko/luckperms/common/core/model/User.java index 6cbda6e0..4717181b 100644 --- a/common/src/main/java/me/lucko/luckperms/common/core/model/User.java +++ b/common/src/main/java/me/lucko/luckperms/common/core/model/User.java @@ -32,8 +32,10 @@ import me.lucko.luckperms.common.api.delegates.UserDelegate; import me.lucko.luckperms.common.caching.UserCache; import me.lucko.luckperms.common.caching.handlers.HolderReference; import me.lucko.luckperms.common.caching.handlers.UserReference; +import me.lucko.luckperms.common.config.ConfigKeys; import me.lucko.luckperms.common.core.UserIdentifier; import me.lucko.luckperms.common.plugin.LuckPermsPlugin; +import me.lucko.luckperms.common.primarygroup.PrimaryGroupHolder; import me.lucko.luckperms.common.utils.BufferedRequest; import me.lucko.luckperms.common.utils.Identifiable; @@ -60,8 +62,7 @@ public class User extends PermissionHolder implements Identifiable im public static boolean giveDefaultIfNeeded(User user, boolean save, LuckPermsPlugin plugin) { boolean hasGroup = false; - if (user.getPrimaryGroup() != null && !user.getPrimaryGroup().isEmpty()) { + if (user.getPrimaryGroup().getStoredValue() != null && !user.getPrimaryGroup().getStoredValue().isEmpty()) { for (Node node : user.getPermissions(false)) { if (node.isServerSpecific() || node.isWorldSpecific()) { continue; @@ -57,10 +57,8 @@ public class GenericUserManager extends AbstractManager im return false; } - user.setPrimaryGroup("default"); - try { - user.setPermission("group.default", true); - } catch (ObjectAlreadyHasException ignored) {} + user.getPrimaryGroup().setStoredValue("default"); + user.setPermissionUnchecked(NodeFactory.make("group.default")); if (save) { plugin.getStorage().saveUser(user); @@ -97,7 +95,7 @@ public class GenericUserManager extends AbstractManager im } // Not in the default primary group - return !user.getPrimaryGroup().equalsIgnoreCase("default"); + return !user.getPrimaryGroup().getStoredValue().equalsIgnoreCase("default"); } private final LuckPermsPlugin plugin; diff --git a/common/src/main/java/me/lucko/luckperms/common/primarygroup/AllParentsByWeightHolder.java b/common/src/main/java/me/lucko/luckperms/common/primarygroup/AllParentsByWeightHolder.java new file mode 100644 index 00000000..da32dc9f --- /dev/null +++ b/common/src/main/java/me/lucko/luckperms/common/primarygroup/AllParentsByWeightHolder.java @@ -0,0 +1,64 @@ +/* + * 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.primarygroup; + +import me.lucko.luckperms.api.Contexts; +import me.lucko.luckperms.api.Node; +import me.lucko.luckperms.common.core.model.Group; +import me.lucko.luckperms.common.core.model.User; +import me.lucko.luckperms.common.utils.ExtractedContexts; + +import java.util.Comparator; +import java.util.Optional; + +public class AllParentsByWeightHolder extends StoredHolder { + + private String cachedValue = null; + private boolean useCached = false; + + public AllParentsByWeightHolder(User user) { + super(user); + user.getStateListeners().add(() -> useCached = false); + } + + @Override + public String getValue() { + if (useCached) { + return cachedValue; + } + + cachedValue = user.getAllNodes(null, ExtractedContexts.generate(Contexts.allowAll())).stream() + .filter(Node::isGroupNode) + .filter(Node::getValue) + .map(n -> Optional.ofNullable(user.getPlugin().getGroupManager().getIfLoaded(n.getGroupName()))) + .filter(Optional::isPresent) + .map(Optional::get) + .sorted(Comparator.comparingInt(o -> o.getWeight().orElse(0))) + .findFirst() + .map(Group::getName) + .orElse(null); + + useCached = true; + return cachedValue; + } +} diff --git a/common/src/main/java/me/lucko/luckperms/common/primarygroup/ParentsByWeightHolder.java b/common/src/main/java/me/lucko/luckperms/common/primarygroup/ParentsByWeightHolder.java new file mode 100644 index 00000000..71d6a8a9 --- /dev/null +++ b/common/src/main/java/me/lucko/luckperms/common/primarygroup/ParentsByWeightHolder.java @@ -0,0 +1,62 @@ +/* + * 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.primarygroup; + +import me.lucko.luckperms.api.Node; +import me.lucko.luckperms.common.core.model.Group; +import me.lucko.luckperms.common.core.model.User; + +import java.util.Comparator; +import java.util.Optional; + +public class ParentsByWeightHolder extends StoredHolder { + + private String cachedValue = null; + private boolean useCached = false; + + public ParentsByWeightHolder(User user) { + super(user); + user.getStateListeners().add(() -> useCached = false); + } + + @Override + public String getValue() { + if (useCached) { + return cachedValue; + } + + cachedValue = user.getPermissions(true).stream() + .filter(Node::isGroupNode) + .filter(Node::getValue) + .map(n -> Optional.ofNullable(user.getPlugin().getGroupManager().getIfLoaded(n.getGroupName()))) + .filter(Optional::isPresent) + .map(Optional::get) + .sorted(Comparator.comparingInt(o -> o.getWeight().orElse(0))) + .findFirst() + .map(Group::getName) + .orElse(null); + + useCached = true; + return cachedValue; + } +} diff --git a/common/src/main/java/me/lucko/luckperms/common/primarygroup/PrimaryGroupHolder.java b/common/src/main/java/me/lucko/luckperms/common/primarygroup/PrimaryGroupHolder.java new file mode 100644 index 00000000..2fa1d4db --- /dev/null +++ b/common/src/main/java/me/lucko/luckperms/common/primarygroup/PrimaryGroupHolder.java @@ -0,0 +1,33 @@ +/* + * 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.primarygroup; + +public interface PrimaryGroupHolder { + + String getValue(); + + String getStoredValue(); + + void setStoredValue(String storedValue); + +} diff --git a/common/src/main/java/me/lucko/luckperms/common/primarygroup/StoredHolder.java b/common/src/main/java/me/lucko/luckperms/common/primarygroup/StoredHolder.java new file mode 100644 index 00000000..c1151366 --- /dev/null +++ b/common/src/main/java/me/lucko/luckperms/common/primarygroup/StoredHolder.java @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2016 Lucko (Luck) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package me.lucko.luckperms.common.primarygroup; + +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import lombok.Setter; + +import me.lucko.luckperms.common.core.model.User; + +@RequiredArgsConstructor +public class StoredHolder implements PrimaryGroupHolder { + + protected final User user; + + @Getter + @Setter + private String storedValue = null; + + public String getValue() { + return storedValue; + } + +} diff --git a/common/src/main/java/me/lucko/luckperms/common/storage/backing/JSONBacking.java b/common/src/main/java/me/lucko/luckperms/common/storage/backing/JSONBacking.java index 8bef881f..f21b52c2 100644 --- a/common/src/main/java/me/lucko/luckperms/common/storage/backing/JSONBacking.java +++ b/common/src/main/java/me/lucko/luckperms/common/storage/backing/JSONBacking.java @@ -118,7 +118,7 @@ public class JSONBacking extends FlatfileBacking { reader.nextName(); // name record String name = reader.nextString(); // name reader.nextName(); // primaryGroup record - user.setPrimaryGroup(reader.nextString()); // primaryGroup + user.getPrimaryGroup().setStoredValue(reader.nextString()); // primaryGroup reader.nextName(); // perms reader.beginObject(); Map map = new HashMap<>(); @@ -146,7 +146,7 @@ public class JSONBacking extends FlatfileBacking { writer.beginObject(); writer.name("uuid").value(user.getUuid().toString()); writer.name("name").value(user.getName()); - writer.name("primaryGroup").value(user.getPrimaryGroup()); + writer.name("primaryGroup").value(user.getPrimaryGroup().getStoredValue()); writer.name("perms"); writer.beginObject(); for (Map.Entry e : exportToLegacy(user.getNodes()).entrySet()) { @@ -162,7 +162,7 @@ public class JSONBacking extends FlatfileBacking { } else { if (GenericUserManager.shouldSave(user)) { user.clearNodes(); - user.setPrimaryGroup(null); + user.getPrimaryGroup().setStoredValue(null); plugin.getUserManager().giveDefaultIfNeeded(user, false); } return true; @@ -202,7 +202,7 @@ public class JSONBacking extends FlatfileBacking { writer.beginObject(); writer.name("uuid").value(user.getUuid().toString()); writer.name("name").value(user.getName()); - writer.name("primaryGroup").value(user.getPrimaryGroup()); + writer.name("primaryGroup").value(user.getPrimaryGroup().getStoredValue()); writer.name("perms"); writer.beginObject(); for (Map.Entry e : exportToLegacy(user.getNodes()).entrySet()) { diff --git a/common/src/main/java/me/lucko/luckperms/common/storage/backing/MongoDBBacking.java b/common/src/main/java/me/lucko/luckperms/common/storage/backing/MongoDBBacking.java index 2d178fa6..2e4a839b 100644 --- a/common/src/main/java/me/lucko/luckperms/common/storage/backing/MongoDBBacking.java +++ b/common/src/main/java/me/lucko/luckperms/common/storage/backing/MongoDBBacking.java @@ -94,7 +94,7 @@ public class MongoDBBacking extends AbstractBacking { private static Document fromUser(User user) { Document main = new Document("_id", user.getUuid()) .append("name", user.getName()) - .append("primaryGroup", user.getPrimaryGroup()); + .append("primaryGroup", user.getPrimaryGroup().getStoredValue()); Document perms = new Document(); for (Map.Entry e : convert(exportToLegacy(user.getNodes())).entrySet()) { @@ -238,7 +238,7 @@ public class MongoDBBacking extends AbstractBacking { // User exists, let's load. Document d = cursor.next(); user.setNodes(revert((Map) d.get("perms"))); - user.setPrimaryGroup(d.getString("primaryGroup")); + user.getPrimaryGroup().setStoredValue(d.getString("primaryGroup")); boolean save = plugin.getUserManager().giveDefaultIfNeeded(user, false); @@ -256,7 +256,7 @@ public class MongoDBBacking extends AbstractBacking { } else { if (GenericUserManager.shouldSave(user)) { user.clearNodes(); - user.setPrimaryGroup(null); + user.getPrimaryGroup().setStoredValue(null); plugin.getUserManager().giveDefaultIfNeeded(user, false); } } diff --git a/common/src/main/java/me/lucko/luckperms/common/storage/backing/SQLBacking.java b/common/src/main/java/me/lucko/luckperms/common/storage/backing/SQLBacking.java index 752598a7..bc6378c2 100644 --- a/common/src/main/java/me/lucko/luckperms/common/storage/backing/SQLBacking.java +++ b/common/src/main/java/me/lucko/luckperms/common/storage/backing/SQLBacking.java @@ -301,7 +301,7 @@ public class SQLBacking extends AbstractBacking { if (pg == null) { pg = "default"; } - user.setPrimaryGroup(pg); + user.getPrimaryGroup().setStoredValue(pg); String name = userName.get(); if (name == null) { @@ -328,7 +328,7 @@ public class SQLBacking extends AbstractBacking { // User has no data in storage. if (GenericUserManager.shouldSave(user)) { user.clearNodes(); - user.setPrimaryGroup(null); + user.getPrimaryGroup().setStoredValue(null); plugin.getUserManager().giveDefaultIfNeeded(user, false); } } @@ -436,7 +436,7 @@ public class SQLBacking extends AbstractBacking { try (Connection c = provider.getConnection()) { try (PreparedStatement ps = c.prepareStatement(prefix.apply(PLAYER_UPDATE_PRIMARY_GROUP))) { - ps.setString(1, user.getPrimaryGroup() == null ? "default" : user.getPrimaryGroup()); + ps.setString(1, user.getPrimaryGroup().getStoredValue() == null ? "default" : user.getPrimaryGroup().getStoredValue()); ps.setString(2, user.getUuid().toString()); ps.execute(); } diff --git a/common/src/main/java/me/lucko/luckperms/common/storage/backing/YAMLBacking.java b/common/src/main/java/me/lucko/luckperms/common/storage/backing/YAMLBacking.java index be6f97d1..28258733 100644 --- a/common/src/main/java/me/lucko/luckperms/common/storage/backing/YAMLBacking.java +++ b/common/src/main/java/me/lucko/luckperms/common/storage/backing/YAMLBacking.java @@ -115,7 +115,7 @@ public class YAMLBacking extends FlatfileBacking { return readMapFromFile(userFile, values -> { // User exists, let's load. String name = (String) values.get("name"); - user.setPrimaryGroup((String) values.get("primary-group")); + user.getPrimaryGroup().setStoredValue((String) values.get("primary-group")); Map perms = (Map) values.get("perms"); user.setNodes(perms); @@ -133,7 +133,7 @@ public class YAMLBacking extends FlatfileBacking { Map data = new HashMap<>(); data.put("uuid", user.getUuid().toString()); data.put("name", user.getName()); - data.put("primary-group", user.getPrimaryGroup()); + data.put("primary-group", user.getPrimaryGroup().getStoredValue()); data.put("perms", exportToLegacy(user.getNodes())); writeMapToFile(userFile, data); } @@ -142,7 +142,7 @@ public class YAMLBacking extends FlatfileBacking { } else { if (GenericUserManager.shouldSave(user)) { user.clearNodes(); - user.setPrimaryGroup(null); + user.getPrimaryGroup().setStoredValue(null); plugin.getUserManager().giveDefaultIfNeeded(user, false); } return true; @@ -180,7 +180,7 @@ public class YAMLBacking extends FlatfileBacking { Map values = new HashMap<>(); values.put("uuid", user.getUuid().toString()); values.put("name", user.getName()); - values.put("primary-group", user.getPrimaryGroup()); + values.put("primary-group", user.getPrimaryGroup().getStoredValue()); values.put("perms", exportToLegacy(user.getNodes())); return writeMapToFile(userFile, values); }, false); diff --git a/default-lang.yml b/default-lang.yml index 969ed1d7..4d762281 100644 --- a/default-lang.yml +++ b/default-lang.yml @@ -252,6 +252,7 @@ info-temp-parent-header: "&f- &aTemporary Parent Groups:" user-getuuid: "&bThe UUID of &b{0}&b is &b{1}&b." user-removegroup-error-primary: "You cannot remove a user from their primary group." user-primarygroup-success: "&b{0}&a's primary group was set to &b{1}&a." +user-primarygroup-warn-option: "&cWarning: The primary group calculation method being used by this server &7({0}) &cmay not reflect this change." user-primarygroup-error-alreadyhas: "The user already has this group set as their primary group." user-primarygroup-error-notmember: "&b{0}&a was not already a member of &b{1}&a, adding them now." user-track-error-not-contain-group: "The user specified isn't already in any groups on this track." diff --git a/sponge/src/main/resources/luckperms.conf b/sponge/src/main/resources/luckperms.conf index 3eb26bc9..25483506 100644 --- a/sponge/src/main/resources/luckperms.conf +++ b/sponge/src/main/resources/luckperms.conf @@ -67,6 +67,14 @@ group-name-rewrite { # If "deny": the command will just fail if you try to add another node with the same expiry temporary-add-behaviour="deny" +# How should LuckPerms determine a users "primary" group. +# +# Available Options: +# -> stored use the value stored against the users record in the file/database +# -> parents-by-weight just use the users most highly weighted parent +# -> all-parents-by-weight same as above, but calculates based upon all parents inherits from both directly and indirectly +primary-group-calculation="parents-by-weight" +