diff --git a/src/main/java/com/denizenscript/depenizen/bukkit/bridges/LuckPermsBridge.java b/src/main/java/com/denizenscript/depenizen/bukkit/bridges/LuckPermsBridge.java index 475719189..79229abdd 100644 --- a/src/main/java/com/denizenscript/depenizen/bukkit/bridges/LuckPermsBridge.java +++ b/src/main/java/com/denizenscript/depenizen/bukkit/bridges/LuckPermsBridge.java @@ -1,10 +1,12 @@ package com.denizenscript.depenizen.bukkit.bridges; +import com.denizenscript.denizencore.DenizenCore; import com.denizenscript.denizencore.objects.ObjectFetcher; import com.denizenscript.denizencore.objects.core.ListTag; import com.denizenscript.denizencore.tags.PseudoObjectTagBase; import com.denizenscript.denizencore.tags.TagManager; import com.denizenscript.depenizen.bukkit.Bridge; +import com.denizenscript.depenizen.bukkit.commands.luckperms.LuckPermsCommand; import com.denizenscript.depenizen.bukkit.objects.luckperms.LuckPermsGroupTag; import com.denizenscript.depenizen.bukkit.objects.luckperms.LuckPermsTrackTag; import com.denizenscript.depenizen.bukkit.properties.luckperms.LuckPermsPlayerExtensions; @@ -65,6 +67,7 @@ public void register() { @Override public void init() { luckPermsInstance = LuckPermsProvider.get(); + DenizenCore.commandRegistry.registerCommand(LuckPermsCommand.class); LuckPermsPlayerExtensions.register(); ObjectFetcher.registerWithObjectFetcher(LuckPermsGroupTag.class, LuckPermsGroupTag.tagProcessor); ObjectFetcher.registerWithObjectFetcher(LuckPermsTrackTag.class, LuckPermsTrackTag.tagProcessor); diff --git a/src/main/java/com/denizenscript/depenizen/bukkit/commands/luckperms/LuckPermsCommand.java b/src/main/java/com/denizenscript/depenizen/bukkit/commands/luckperms/LuckPermsCommand.java new file mode 100644 index 000000000..48489cd65 --- /dev/null +++ b/src/main/java/com/denizenscript/depenizen/bukkit/commands/luckperms/LuckPermsCommand.java @@ -0,0 +1,133 @@ +package com.denizenscript.depenizen.bukkit.commands.luckperms; + +import com.denizenscript.denizen.objects.PlayerTag; +import com.denizenscript.denizencore.exceptions.InvalidArgumentsRuntimeException; +import com.denizenscript.denizencore.objects.ObjectTag; +import com.denizenscript.denizencore.objects.core.*; +import com.denizenscript.denizencore.scripts.ScriptEntry; +import com.denizenscript.denizencore.scripts.commands.AbstractCommand; +import com.denizenscript.denizencore.scripts.commands.generator.*; +import com.denizenscript.denizencore.utilities.text.StringHolder; +import com.denizenscript.depenizen.bukkit.bridges.LuckPermsBridge; +import com.denizenscript.depenizen.bukkit.objects.luckperms.LuckPermsGroupTag; +import net.luckperms.api.model.user.User; +import net.luckperms.api.node.Node; +import net.luckperms.api.node.NodeBuilder; + +import java.util.Map; +import java.util.concurrent.TimeUnit; + +public class LuckPermsCommand extends AbstractCommand { + + public LuckPermsCommand() { + setName("luckperms"); + setSyntax("luckperms [{set}/unset] [user:/group:] [permission] (state:{true}/false) (duration:) (contexts:)"); + setRequiredArguments(2, 6); + autoCompile(); + } + + // <--[command] + // @Name mcMMO + // @Syntax luckperms [{set}/unset] [user:/group:] [permission] (state:{true}/false) (duration:) (contexts:) + // @Group Depenizen + // @Plugin Depenizen, mcMMO + // @Required 2 + // @Maximum 6 + // @Short Edits LuckPerms permissions. + // + // @Description + // This command allows you to add or unset permission nodes from players and LuckPerms groups. + // + // The 'duration' argument specifies how long a player or group will have the specified permission + // before it is removed. Not using this argument will result in the permission staying until manually removed. + // + // The 'contexts' argument sets the contexts in which the permission and state specified is active. + // Format is in MapTag format: 'type=value'. + // The 'value' accepts a ListTag for multiple entries of the same key. + // + // @Tags + // ]> + // ]> + // ]> + // ]> + // + // @Usage + // Use to give a player the 'dscript.help' permission. + // - luckperms set user: dscript.help state:true + // + // @Usage + // Use to give a player the 'dscript.warp' permission for 5 minutes in the main world. + // - luckperms user: dscript.warp duration:5m contexts:[world=world] + // + // @Usage + // Use to disallow a group access to the 'dscript.spawn' permission in the nether and end. + // - luckperms group: dscript.spawn state:false contexts:[dimension_type=the_nether|the_end] + // + // @Usage + // Use to unset the 'dscript.ban' permission back to the default for a player when in survival mode on the hub server. + // - luckperms unset user: dscript.ban contexts:[gamemode=survival;server=hub] + // + // --> + + public enum Action {SET, UNSET} + + public static void autoExecute(ScriptEntry scriptEntry, + @ArgName("action") @ArgDefaultText("set") Action action, + @ArgName("user") @ArgPrefixed @ArgDefaultNull PlayerTag player, + @ArgName("group") @ArgPrefixed @ArgDefaultNull LuckPermsGroupTag group, + @ArgName("permission") @ArgLinear String permission, + @ArgName("state") @ArgPrefixed @ArgDefaultText("true") boolean state, + @ArgName("duration") @ArgPrefixed @ArgDefaultNull DurationTag duration, + @ArgName("contexts") @ArgPrefixed @ArgDefaultNull MapTag contexts) { + if (player == null && group == null) { + throw new InvalidArgumentsRuntimeException("Must specify either a player or a group!"); + } + if (player != null && group != null) { + throw new InvalidArgumentsRuntimeException("Cannot specify both a player and a group!"); + } + NodeBuilder nodeBuilder = Node.builder(permission).value(state); + if (duration != null) { + nodeBuilder = nodeBuilder.expiry((long) duration.getSeconds(), TimeUnit.SECONDS); + } + if (contexts != null) { + for (Map.Entry entry : contexts.entrySet()) { + for (String value : entry.getValue().asType(ListTag.class, scriptEntry.context)) { + nodeBuilder = nodeBuilder.withContext(entry.getKey().low, value); + } + } + } + Node node = nodeBuilder.build(); + switch (action) { + case SET: { + if (player != null) { + User user = LuckPermsBridge.luckPermsInstance.getUserManager().getUser(player.getUUID()); + if (user == null) { + throw new InvalidArgumentsRuntimeException("This user does not exist, have they joined the server before?"); + } + user.data().add(node); + LuckPermsBridge.luckPermsInstance.getUserManager().saveUser(user); + } + else { + group.getGroup().data().add(node); + LuckPermsBridge.luckPermsInstance.getGroupManager().saveGroup(group.getGroup()); + } + break; + } + case UNSET: { + if (player != null) { + User user = LuckPermsBridge.luckPermsInstance.getUserManager().getUser(player.getUUID()); + if (user == null) { + throw new InvalidArgumentsRuntimeException("This user does not exist, have they joined the server before?"); + } + user.data().remove(node); + LuckPermsBridge.luckPermsInstance.getUserManager().saveUser(user); + } + else { + group.getGroup().data().remove(node); + LuckPermsBridge.luckPermsInstance.getGroupManager().saveGroup(group.getGroup()); + } + break; + } + } + } +} diff --git a/src/main/java/com/denizenscript/depenizen/bukkit/objects/luckperms/LuckPermsGroupTag.java b/src/main/java/com/denizenscript/depenizen/bukkit/objects/luckperms/LuckPermsGroupTag.java index 53bbb3850..9cc88183f 100644 --- a/src/main/java/com/denizenscript/depenizen/bukkit/objects/luckperms/LuckPermsGroupTag.java +++ b/src/main/java/com/denizenscript/depenizen/bukkit/objects/luckperms/LuckPermsGroupTag.java @@ -2,12 +2,15 @@ import com.denizenscript.denizencore.objects.Fetchable; import com.denizenscript.denizencore.objects.ObjectTag; +import com.denizenscript.denizencore.objects.core.DurationTag; import com.denizenscript.denizencore.objects.core.ElementTag; import com.denizenscript.denizencore.tags.Attribute; import com.denizenscript.denizencore.tags.ObjectTagProcessor; import com.denizenscript.denizencore.tags.TagContext; import com.denizenscript.depenizen.bukkit.bridges.LuckPermsBridge; import net.luckperms.api.model.group.Group; +import net.luckperms.api.node.NodeType; +import net.luckperms.api.node.types.PermissionNode; import java.util.OptionalInt; @@ -153,6 +156,37 @@ public static void register() { tagProcessor.registerTag(ElementTag.class, ElementTag.class, "has_permission", (attribute, object, p) -> { return new ElementTag(object.getGroup().getCachedData().getPermissionData().checkPermission(p.asString()).asBoolean()); }); + + // <--[tag] + // @attribute ]> + // @returns DurationTag + // @plugin Depenizen, LuckPerms + // @description + // Returns how long a group has a permission for. + // If the group does not have the specific permission set, this will return the time for the closest wildcard permission, if any. + // --> + tagProcessor.registerTag(DurationTag.class, ElementTag.class, "permission_expiry", (attribute, object, p) -> { + String permission = p.asString(); + PermissionNode bestNode = null; + int wildcardLevel = 0; + for (PermissionNode node : object.getGroup().getNodes(NodeType.PERMISSION)) { + if (node.getKey().equalsIgnoreCase(permission)) { + bestNode = node; + break; + } + else if (node.isWildcard() && node.getWildcardLevel().isPresent()) { + int size = node.getKey().substring(0, node.getKey().length() - 1).length(); + if (permission.length() < size || !permission.substring(0, size).equalsIgnoreCase(node.getKey().substring(0, size))) { + continue; + } + if (node.getWildcardLevel().getAsInt() > wildcardLevel) { + bestNode = node; + wildcardLevel = node.getWildcardLevel().getAsInt(); + } + } + } + return bestNode != null ? new DurationTag(bestNode.getExpiryDuration() != null ? (int) bestNode.getExpiryDuration().getSeconds() : 0) : null; + }); } public static ObjectTagProcessor tagProcessor = new ObjectTagProcessor<>(); diff --git a/src/main/java/com/denizenscript/depenizen/bukkit/properties/luckperms/LuckPermsPlayerExtensions.java b/src/main/java/com/denizenscript/depenizen/bukkit/properties/luckperms/LuckPermsPlayerExtensions.java index 1a8662e30..b55f03daa 100644 --- a/src/main/java/com/denizenscript/depenizen/bukkit/properties/luckperms/LuckPermsPlayerExtensions.java +++ b/src/main/java/com/denizenscript/depenizen/bukkit/properties/luckperms/LuckPermsPlayerExtensions.java @@ -1,6 +1,8 @@ package com.denizenscript.depenizen.bukkit.properties.luckperms; import com.denizenscript.denizen.objects.PlayerTag; +import com.denizenscript.denizencore.objects.core.DurationTag; +import com.denizenscript.denizencore.objects.core.ElementTag; import com.denizenscript.denizencore.objects.core.ListTag; import com.denizenscript.depenizen.bukkit.bridges.LuckPermsBridge; import com.denizenscript.depenizen.bukkit.objects.luckperms.LuckPermsGroupTag; @@ -8,6 +10,7 @@ import net.luckperms.api.model.group.Group; import net.luckperms.api.model.user.User; import net.luckperms.api.node.NodeType; +import net.luckperms.api.node.types.PermissionNode; import net.luckperms.api.query.QueryOptions; import net.luckperms.api.track.Track; @@ -67,5 +70,39 @@ public static void register() { return new LuckPermsGroupTag(group); }); + // <--[tag] + // @attribute ]> + // @returns DurationTag + // @plugin Depenizen, LuckPerms + // @description + // Returns how long a player has a permission for. + // If the player does not have the specific permission set, this will return the time for the closest wildcard permission, if any. + // --> + PlayerTag.tagProcessor.registerTag(DurationTag.class, ElementTag.class, "luckperms_permission_expiry", (attribute, player, param) -> { + User user = LuckPermsBridge.luckPermsInstance.getUserManager().getUser(player.getUUID()); + if (user == null) { + return null; + } + String permission = param.asString(); + PermissionNode bestNode = null; + int wildcardLevel = 0; + for (PermissionNode node : user.getNodes(NodeType.PERMISSION)) { + if (node.getKey().equalsIgnoreCase(permission)) { + bestNode = node; + break; + } + else if (node.isWildcard() && node.getWildcardLevel().isPresent()) { + int size = node.getKey().substring(0, node.getKey().length() - 1).length(); + if (permission.length() < size || !permission.substring(0, size).equalsIgnoreCase(node.getKey().substring(0, size))) { + continue; + } + if (node.getWildcardLevel().getAsInt() > wildcardLevel) { + bestNode = node; + wildcardLevel = node.getWildcardLevel().getAsInt(); + } + } + } + return bestNode != null ? new DurationTag(bestNode.getExpiryDuration() != null ? (int) bestNode.getExpiryDuration().getSeconds() : 0) : null; + }); } }