diff --git a/Datura/src/main/java/me/totalfreedom/datura/cmd/ClearDropsCommand.java b/Datura/src/main/java/me/totalfreedom/datura/cmd/ClearDropsCommand.java index 495d2ed..d616def 100644 --- a/Datura/src/main/java/me/totalfreedom/datura/cmd/ClearDropsCommand.java +++ b/Datura/src/main/java/me/totalfreedom/datura/cmd/ClearDropsCommand.java @@ -19,7 +19,7 @@ import org.bukkit.plugin.java.JavaPlugin; import org.jetbrains.annotations.NotNull; @Info(name = "cleardrops", description = "Clears all item drops in the world" + ".", usage = "/", aliases = - {"cd", "clearitems", "ci", "wipeitems", "wi"}) + {"cd", "clearitems", "ci", "wipeitems", "wi", "removedrops", "rd"}) @Permissive(perm = "datura.cleardrops") public class ClearDropsCommand extends Commander { diff --git a/Datura/src/main/java/me/totalfreedom/datura/cmd/ClearEntitiesCommand.java b/Datura/src/main/java/me/totalfreedom/datura/cmd/ClearEntitiesCommand.java index 9868235..6460a33 100644 --- a/Datura/src/main/java/me/totalfreedom/datura/cmd/ClearEntitiesCommand.java +++ b/Datura/src/main/java/me/totalfreedom/datura/cmd/ClearEntitiesCommand.java @@ -3,6 +3,8 @@ package me.totalfreedom.datura.cmd; import me.totalfreedom.command.Commander; import me.totalfreedom.command.annotation.Base; import me.totalfreedom.command.annotation.Completion; +import me.totalfreedom.command.annotation.Info; +import me.totalfreedom.command.annotation.Permissive; import me.totalfreedom.command.annotation.Subcommand; import me.totalfreedom.utils.Tagged; import org.bukkit.World; @@ -12,6 +14,9 @@ import org.bukkit.entity.Player; import org.bukkit.plugin.java.JavaPlugin; import org.jetbrains.annotations.NotNull; +@Info(name = "clearentities", description = "Clears all entities in the world.", usage = "/ [world]", + aliases = {"ew", "ce", "entitywipe", "entityclear", "ec"}) +@Permissive(perm = "datura.clearentities") public class ClearEntitiesCommand extends Commander { /** diff --git a/Datura/src/main/java/me/totalfreedom/datura/cmd/ManageUserCommand.java b/Datura/src/main/java/me/totalfreedom/datura/cmd/ManageUserCommand.java new file mode 100644 index 0000000..9c0b86b --- /dev/null +++ b/Datura/src/main/java/me/totalfreedom/datura/cmd/ManageUserCommand.java @@ -0,0 +1,93 @@ +package me.totalfreedom.datura.cmd; + +import java.time.Duration; +import me.totalfreedom.base.Shortcuts; +import me.totalfreedom.command.Commander; +import me.totalfreedom.command.annotation.Completion; +import me.totalfreedom.command.annotation.Info; +import me.totalfreedom.command.annotation.Permissive; +import me.totalfreedom.command.annotation.Subcommand; +import me.totalfreedom.datura.perms.PermissionNodeBuilder; +import me.totalfreedom.security.Node; +import me.totalfreedom.security.NodeType; +import me.totalfreedom.security.PermissionHolder; +import me.totalfreedom.user.User; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; +import org.bukkit.plugin.java.JavaPlugin; +import org.jetbrains.annotations.NotNull; + +@Info(name = "manageuser", description = "Manage a user's permissions", usage = "/manageuser )>", aliases = {"mu", "userdata", "ud", "usermanager", "um"}) +@Permissive(perm = "datura.manageuser") +public class ManageUserCommand extends Commander +{ + + /** + * Initializes this command object. The provided {@link JavaPlugin} should be the plugin which contains the + * command. + *

+ * This constructor will automatically register all subcommands and completions for this command. It will also + * automatically infer all required information from the provided {@link Info} and {@link Permissive} annotations. + * + * @param plugin The plugin which contains this command. + */ + protected ManageUserCommand(final @NotNull JavaPlugin plugin) + { + super(plugin); + } + + @Subcommand(permission = "datura.manageuser", args = {Player.class, String.class, String.class, Long.class}) + @Completion(index = 0, args = {"%player%"}) + @Completion(index = 1, args = {"info", "add", "remove"}) + @Completion(index = 2, args = {""}) + public void manageUser(final CommandSender sender, final Player player, final String addOrRemove, + final String permission, final long duration) + { + final PermissionHolder user = Shortcuts.getUser(player); + final Node node = new PermissionNodeBuilder().key(permission) + .type(NodeType.PERMISSION) + .expiry(Duration.ofMinutes(duration) + .getSeconds() + System.currentTimeMillis()) + .build(); + ifElse(addOrRemove, user, node); + } + + @Subcommand(permission = "datura.manageuser", args = {Player.class, String.class, String.class}) + public void manageUser(final CommandSender sender, final Player player, final String addOrRemove, + final String permission) + { + final PermissionHolder user = Shortcuts.getUser(player); + final Node node = new PermissionNodeBuilder().key(permission).type(NodeType.PERMISSION).build(); + ifElse(addOrRemove, user, node); + } + + @Subcommand(permission = "datura.manageuser", args = {Player.class, String.class}) + public void userInfo(final CommandSender sender, final Player player, final String info) + { + final User user = Shortcuts.getUser(player); + if (info.equalsIgnoreCase("info")) + { + final StringBuilder permissions = new StringBuilder(); + user.getEffectivePermissions().forEach(node -> permissions.append(node.getPermission())); + final String text = """ + User: %s + Group: %s + Permissions: %s""".formatted(user.getName(), user.getUserData().getGroup(), + permissions.toString()); + sender.sendPlainMessage(text); + } + } + + private void ifElse(final String addOrRemove, final PermissionHolder user, final Node node) + { + if (addOrRemove.equalsIgnoreCase("add")) + { + user.addPermission(node); + } + else if (addOrRemove.equalsIgnoreCase("remove")) + { + user.removePermission(node); + } + } +} diff --git a/Datura/src/main/java/me/totalfreedom/datura/perms/FreedomGroup.java b/Datura/src/main/java/me/totalfreedom/datura/perms/FreedomGroup.java index affa495..7627933 100644 --- a/Datura/src/main/java/me/totalfreedom/datura/perms/FreedomGroup.java +++ b/Datura/src/main/java/me/totalfreedom/datura/perms/FreedomGroup.java @@ -114,7 +114,7 @@ public class FreedomGroup implements Group .findFirst() .orElse(null); - return node != null && node.value(); + return node != null; } @Override @@ -127,7 +127,7 @@ public class FreedomGroup implements Group .findFirst() .orElse(null); - return node != null && node.value(); + return node != null; } @Override @@ -139,7 +139,7 @@ public class FreedomGroup implements Group .findFirst() .orElse(null); - return node != null && node.value(); + return node != null; } @Override @@ -152,7 +152,7 @@ public class FreedomGroup implements Group .findFirst() .orElse(null); - return node != null && node.value(); + return node != null; } /** @@ -214,8 +214,7 @@ public class FreedomGroup implements Group .map(n -> new PermissionAttachmentInfo( this, n.key(), - attachment, - n.value())) + attachment, true)) .collect(Collectors.toSet()); } @@ -228,7 +227,7 @@ public class FreedomGroup implements Group .findFirst() .orElse(null); - return node != null && node.value(); + return node != null; } @Override diff --git a/Datura/src/main/java/me/totalfreedom/datura/perms/PermissionNode.java b/Datura/src/main/java/me/totalfreedom/datura/perms/PermissionNode.java index 48870b9..a83c115 100644 --- a/Datura/src/main/java/me/totalfreedom/datura/perms/PermissionNode.java +++ b/Datura/src/main/java/me/totalfreedom/datura/perms/PermissionNode.java @@ -5,29 +5,19 @@ import me.totalfreedom.security.NodeType; import org.bukkit.permissions.Permission; import org.bukkit.permissions.PermissionDefault; -record PermissionNode(String key, - boolean value, - long expiry, - NodeType type, - boolean wildcard) implements Node +record PermissionNode(String key, long expiry, NodeType type, boolean wildcard) implements Node { @Override public Permission bukkit() { - return new Permission(key(), - value() - ? PermissionDefault.TRUE - : PermissionDefault.FALSE); + return new Permission(key(), PermissionDefault.FALSE); } @Override public boolean compare(final Node node) { - return node.key() - .equalsIgnoreCase(key()) - && node.value() == value() - && node.type() == type(); + return node.key().equalsIgnoreCase(key()) && node.type().equals(type()) && !node.isExpired(); } @Override diff --git a/Datura/src/main/java/me/totalfreedom/datura/perms/PermissionNodeBuilder.java b/Datura/src/main/java/me/totalfreedom/datura/perms/PermissionNodeBuilder.java index a89e69b..87b8fa0 100644 --- a/Datura/src/main/java/me/totalfreedom/datura/perms/PermissionNodeBuilder.java +++ b/Datura/src/main/java/me/totalfreedom/datura/perms/PermissionNodeBuilder.java @@ -7,11 +7,9 @@ import me.totalfreedom.security.NodeType; public class PermissionNodeBuilder implements NodeBuilder { private String key = "freedom.default"; - private boolean value = true; private long expiry = -1; private NodeType type = NodeType.PERMISSION; private boolean wildcard = false; - private boolean negated = false; @Override public NodeBuilder key(final String key) @@ -20,13 +18,6 @@ public class PermissionNodeBuilder implements NodeBuilder return this; } - @Override - public NodeBuilder value(final boolean value) - { - this.value = value; - return this; - } - @Override public NodeBuilder expiry(final long expiry) { @@ -48,16 +39,9 @@ public class PermissionNodeBuilder implements NodeBuilder return this; } - @Override - public NodeBuilder negated(final boolean negated) - { - this.negated = negated; - return this; - } - @Override public Node build() { - return new PermissionNode(key, value, expiry, type, wildcard, negated); + return new PermissionNode(key, expiry, type, wildcard); } } diff --git a/Patchwork/src/main/java/me/totalfreedom/command/BukkitDelegate.java b/Patchwork/src/main/java/me/totalfreedom/command/BukkitDelegate.java index 6da4d29..e5ee289 100644 --- a/Patchwork/src/main/java/me/totalfreedom/command/BukkitDelegate.java +++ b/Patchwork/src/main/java/me/totalfreedom/command/BukkitDelegate.java @@ -155,6 +155,10 @@ public final class BukkitDelegate extends Command implements PluginIdentifiableC } final Object obj = provider.fromString(arg, argType); + if (obj == null) { + FreedomLogger.getLogger("Datura").error("Failed to parse argument " + arg + " for type " + argType.getName()); + return; + } objects[i] = obj; } try diff --git a/Patchwork/src/main/java/me/totalfreedom/provider/ContextProvider.java b/Patchwork/src/main/java/me/totalfreedom/provider/ContextProvider.java index 0b28a8b..aaf5d2d 100644 --- a/Patchwork/src/main/java/me/totalfreedom/provider/ContextProvider.java +++ b/Patchwork/src/main/java/me/totalfreedom/provider/ContextProvider.java @@ -40,25 +40,26 @@ public class ContextProvider { public T fromString(final String string, final Class clazz) { - return Stream.of(toBoolean(string), - toDouble(string), - toInt(string), - toLong(string), - toFloat(string), - toMaterial(string), - toPlayer(string), - toWorld(string), - toLocation(string), - toCommandSender(string), - toComponent(string)) + return Stream.of(toBoolean(string, clazz), + toDouble(string, clazz), + toInt(string, clazz), + toLong(string, clazz), + toFloat(string, clazz), + toMaterial(string, clazz), + toPlayer(string, clazz), + toWorld(string, clazz), + toLocation(string, clazz), + toComponent(string, clazz)) .filter(Objects::nonNull) .findFirst() .map(clazz::cast) .orElse(null); } - private @Nullable Boolean toBoolean(final String string) + private @Nullable Boolean toBoolean(final String string, final Class clazz) { + if (clazz != Boolean.class) return null; + // Previously we used Boolean#parseBoolean, but that will always return a value and does not throw // an exception. This means that if the string is not "true" or "false", it will return false. if (string.equalsIgnoreCase("true")) return true; @@ -67,8 +68,10 @@ public class ContextProvider return null; } - private @Nullable Double toDouble(final String string) + private @Nullable Double toDouble(final String string, final Class clazz) { + if (clazz != Double.class) return null; + try { return Double.parseDouble(string); @@ -78,8 +81,10 @@ public class ContextProvider } } - private @Nullable Integer toInt(final String string) + private @Nullable Integer toInt(final String string, final Class clazz) { + if (clazz != Integer.class) return null; + try { return Integer.parseInt(string); @@ -89,8 +94,10 @@ public class ContextProvider } } - private @Nullable Long toLong(final String string) + private @Nullable Long toLong(final String string, final Class clazz) { + if (clazz != Long.class) return null; + try { return Long.parseLong(string); @@ -100,8 +107,10 @@ public class ContextProvider } } - private @Nullable Float toFloat(final String string) + private @Nullable Float toFloat(final String string, final Class clazz) { + if (clazz != Float.class) return null; + try { return Float.parseFloat(string); @@ -111,18 +120,21 @@ public class ContextProvider } } - private @Nullable Material toMaterial(final String string) + private @Nullable Material toMaterial(final String string, final Class clazz) { + if (clazz != Material.class) return null; return Material.matchMaterial(string); } - private @Nullable Player toPlayer(final String string) + private @Nullable Player toPlayer(final String string, final Class clazz) { + if (clazz != Player.class) return null; return Bukkit.getPlayer(string); } - private @Nullable World toWorld(final String string) + private @Nullable World toWorld(final String string, final Class clazz) { + if (clazz != World.class) return null; return Bukkit.getWorld(string); } @@ -135,32 +147,28 @@ public class ContextProvider * @return A location object if xyz is valid * @see BukkitDelegate#processSubCommands(String[], CommandSender, ContextProvider, Subcommand) */ - private @Nullable Location toLocation(final String string) + private @Nullable Location toLocation(final String string, final Class clazz) { + if (clazz != Location.class) return null; + final String[] split = string.split(" "); - if (split.length != 4 || toWorld(split[0]) == null) return null; + if (split.length != 4 || toWorld(split[0], World.class) == null) return null; try { final double x = Double.parseDouble(split[1]); final double y = Double.parseDouble(split[2]); final double z = Double.parseDouble(split[3]); - return new Location(toWorld(split[0]), x, y, z); + return new Location(toWorld(split[0], World.class), x, y, z); } catch (NumberFormatException ex) { return null; } } - private @Nullable CommandSender toCommandSender(final String string) - { - if (toPlayer(string) == null) return null; - - return toPlayer(string); - } - - private @NotNull Component toComponent(final String string) + private @Nullable Component toComponent(final String string, final Class clazz) { + if (clazz != Component.class) return null; return Component.text(string); } } diff --git a/Patchwork/src/main/java/me/totalfreedom/security/Node.java b/Patchwork/src/main/java/me/totalfreedom/security/Node.java index 8af9348..38fe451 100644 --- a/Patchwork/src/main/java/me/totalfreedom/security/Node.java +++ b/Patchwork/src/main/java/me/totalfreedom/security/Node.java @@ -9,8 +9,6 @@ public interface Node { String key(); - boolean value(); - Permission bukkit(); NodeType type(); diff --git a/Patchwork/src/main/java/me/totalfreedom/security/NodeBuilder.java b/Patchwork/src/main/java/me/totalfreedom/security/NodeBuilder.java index c0503ff..05c3ee9 100644 --- a/Patchwork/src/main/java/me/totalfreedom/security/NodeBuilder.java +++ b/Patchwork/src/main/java/me/totalfreedom/security/NodeBuilder.java @@ -4,15 +4,11 @@ public interface NodeBuilder { NodeBuilder key(String key); - NodeBuilder value(boolean value); - NodeBuilder expiry(long expiry); NodeBuilder type(NodeType type); NodeBuilder wildcard(boolean wildcard); - NodeBuilder negated(boolean negated); - Node build(); }