From 23a17891f653670aa430a99dbac2abf857110c06 Mon Sep 17 00:00:00 2001 From: William Date: Mon, 17 Jun 2024 18:49:48 +0100 Subject: [PATCH] feat: add Permissions API for commands --- .../uniform/bukkit/BukkitCommandUser.java | 12 ++++ .../net/william278/uniform/BaseCommand.java | 30 +++++++- .../java/net/william278/uniform/Command.java | 31 ++++++--- .../net/william278/uniform/CommandUser.java | 7 ++ .../net/william278/uniform/Permission.java | 69 +++++++++++++++++++ fabric-1.20.1/build.gradle | 1 + .../uniform/fabric/FabricCommandUser.java | 10 +++ fabric-1.20.6/build.gradle | 1 + .../uniform/fabric/FabricCommandUser.java | 10 +++ gradle.properties | 2 +- .../uniform/paper/LegacyPaperCommandUser.java | 12 ++++ .../uniform/paper/PaperCommandUser.java | 12 ++++ .../uniform/velocity/VelocityCommandUser.java | 10 +++ 13 files changed, 196 insertions(+), 11 deletions(-) create mode 100644 common/src/main/java/net/william278/uniform/Permission.java diff --git a/bukkit/src/main/java/net/william278/uniform/bukkit/BukkitCommandUser.java b/bukkit/src/main/java/net/william278/uniform/bukkit/BukkitCommandUser.java index 8eca4f4..5673ac0 100644 --- a/bukkit/src/main/java/net/william278/uniform/bukkit/BukkitCommandUser.java +++ b/bukkit/src/main/java/net/william278/uniform/bukkit/BukkitCommandUser.java @@ -23,7 +23,9 @@ package net.william278.uniform.bukkit; import net.kyori.adventure.audience.Audience; import net.william278.uniform.CommandUser; +import net.william278.uniform.Permission; import org.bukkit.command.CommandSender; +import org.bukkit.command.ConsoleCommandSender; import org.bukkit.entity.Player; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -49,4 +51,14 @@ public record BukkitCommandUser(@NotNull CommandSender sender) implements Comman return sender instanceof Player player ? player.getUniqueId() : null; } + @Override + public boolean checkPermission(@NotNull Permission permission) { + if (sender.isPermissionSet(permission.node())) { + return sender.hasPermission(permission.node()); + } + return permission.defaultValue().check( + sender.isOp() || sender instanceof ConsoleCommandSender + ); + } + } diff --git a/common/src/main/java/net/william278/uniform/BaseCommand.java b/common/src/main/java/net/william278/uniform/BaseCommand.java index b918b93..0254655 100644 --- a/common/src/main/java/net/william278/uniform/BaseCommand.java +++ b/common/src/main/java/net/william278/uniform/BaseCommand.java @@ -55,6 +55,7 @@ public abstract class BaseCommand { this.name = command.getName(); this.aliases = command.getAliases(); this.description = command.getDescription(); + command.getPermission().ifPresent(this::setPermission); command.provide(this); } @@ -78,6 +79,18 @@ public abstract class BaseCommand { this.condition = condition; } + public final void setPermission(@NotNull Permission permission) { + this.setCondition(this.createPermission(permission)); + } + + public final void setPermission(@NotNull String permission) { + this.setCondition(this.createPermission(new Permission(permission))); + } + + public final void setPermission(@NotNull String permission, @NotNull Permission.Default permissionDefault) { + this.setCondition(this.createPermission(new Permission(permission, permissionDefault))); + } + public final void setDefaultExecutor(@NotNull CommandExecutor executor) { this.defaultExecutor = executor; } @@ -102,15 +115,30 @@ public abstract class BaseCommand { this.addSubCommand(new Command.SubCommand(name, provider).command()); } + public final void addSubCommand(@NotNull String name, @NotNull Permission permission, + @NotNull CommandProvider provider) { + this.addSubCommand(new Command.SubCommand(name, permission, provider).command()); + } + public final void addSubCommand(@NotNull String name, @NotNull List aliases, @NotNull CommandProvider provider) { - this.addSubCommand(new Command.SubCommand(name, provider, aliases).command()); + this.addSubCommand(new Command.SubCommand(name, aliases, provider).command()); + } + + public final void addSubCommand(@NotNull String name, @NotNull List aliases, + @NotNull Permission permission, @NotNull CommandProvider provider) { + this.addSubCommand(new Command.SubCommand(name, aliases, permission, provider).command()); } public abstract void addSubCommand(@NotNull Command command); public abstract Uniform getUniform(); + @NotNull + public final Predicate createPermission(@NotNull Permission permission) { + return permission.toPredicate(this); + } + @NotNull public final LiteralCommandNode build() { return Graph.create(this).build(); diff --git a/common/src/main/java/net/william278/uniform/Command.java b/common/src/main/java/net/william278/uniform/Command.java index 78db99a..3cf9b5d 100644 --- a/common/src/main/java/net/william278/uniform/Command.java +++ b/common/src/main/java/net/william278/uniform/Command.java @@ -21,13 +21,12 @@ package net.william278.uniform; -import lombok.AllArgsConstructor; -import lombok.Getter; -import lombok.RequiredArgsConstructor; -import lombok.Setter; +import lombok.*; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.util.List; +import java.util.Optional; @Getter @Setter @@ -36,17 +35,31 @@ import java.util.List; public abstract class Command implements CommandProvider { private final String name; - private String description = ""; private List aliases = List.of(); + private String description = ""; + @Getter(AccessLevel.NONE) + private @Nullable Permission permission = null; + + public Optional getPermission() { + return Optional.ofNullable(permission); + } + + public record SubCommand(@NotNull String name, @NotNull List aliases, @Nullable Permission permission, @NotNull CommandProvider provider) { + public SubCommand(@NotNull String name, @NotNull List aliases, @NotNull CommandProvider provider) { + this(name, aliases, null, provider); + } + + public SubCommand(@NotNull String name, @NotNull CommandProvider provider) { + this(name, List.of(),null, provider); + } - record SubCommand(@NotNull String name, @NotNull CommandProvider provider, @NotNull List aliases) { - SubCommand(@NotNull String name, @NotNull CommandProvider provider) { - this(name, provider, List.of()); + public SubCommand(@NotNull String name, @Nullable Permission permission, @NotNull CommandProvider provider) { + this(name, List.of(), permission, provider); } @NotNull Command command() { - return new Command(name, "", aliases) { + return new Command(name, aliases, "", permission) { @Override public void provide(@NotNull BaseCommand command) { provider.provide(command); diff --git a/common/src/main/java/net/william278/uniform/CommandUser.java b/common/src/main/java/net/william278/uniform/CommandUser.java index 7043ab3..9852dc2 100644 --- a/common/src/main/java/net/william278/uniform/CommandUser.java +++ b/common/src/main/java/net/william278/uniform/CommandUser.java @@ -39,6 +39,13 @@ public interface CommandUser { @Nullable UUID getUuid(); + boolean checkPermission(@NotNull Permission permission); + + default boolean checkPermission(@NotNull String permission, + @NotNull Permission.Default permissionDefault) { + return checkPermission(new Permission(permission, permissionDefault)); + } + default boolean isConsole() { return getName() == null; } diff --git a/common/src/main/java/net/william278/uniform/Permission.java b/common/src/main/java/net/william278/uniform/Permission.java new file mode 100644 index 0000000..ca2df73 --- /dev/null +++ b/common/src/main/java/net/william278/uniform/Permission.java @@ -0,0 +1,69 @@ +/* + * This file is part of Uniform, licensed under the GNU General Public License v3.0. + * + * Copyright (c) Tofaa2 + * Copyright (c) William278 + * Copyright (c) contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package net.william278.uniform; + +import org.jetbrains.annotations.NotNull; + +import java.util.function.Predicate; + +@SuppressWarnings("unused") +public record Permission(@NotNull String node, @NotNull Default defaultValue) { + + Permission(@NotNull String node) { + this(node, Default.FALSE); + } + + @NotNull + public static Permission defaultIfOp(@NotNull String node) { + return new Permission(node, Default.IF_OP); + } + + @NotNull + public static Permission defaultTrue(@NotNull String node) { + return new Permission(node, Default.TRUE); + } + + @NotNull + public static Permission defaultFalse(@NotNull String node) { + return new Permission(node, Default.FALSE); + } + + public enum Default { + IF_OP, + TRUE, + FALSE; + + public boolean check(boolean op) { + return switch (this) { + case IF_OP -> op; + case TRUE -> true; + case FALSE -> false; + }; + } + } + + @NotNull + public Predicate toPredicate(@NotNull BaseCommand command) { + return user -> command.getUser(user).checkPermission(this); + } + +} diff --git a/fabric-1.20.1/build.gradle b/fabric-1.20.1/build.gradle index 85e257e..b896dcc 100644 --- a/fabric-1.20.1/build.gradle +++ b/fabric-1.20.1/build.gradle @@ -12,6 +12,7 @@ dependencies { modCompileOnly 'net.fabricmc:fabric-loader:0.15.11' modCompileOnly 'net.fabricmc.fabric-api:fabric-api:0.92.2+1.20.1' + modImplementation include('me.lucko:fabric-permissions-api:0.3.1') compileOnly 'org.projectlombok:lombok:1.18.32' diff --git a/fabric-1.20.1/src/main/java/net/william278/uniform/fabric/FabricCommandUser.java b/fabric-1.20.1/src/main/java/net/william278/uniform/fabric/FabricCommandUser.java index b231a59..9235845 100644 --- a/fabric-1.20.1/src/main/java/net/william278/uniform/fabric/FabricCommandUser.java +++ b/fabric-1.20.1/src/main/java/net/william278/uniform/fabric/FabricCommandUser.java @@ -21,9 +21,11 @@ package net.william278.uniform.fabric; +import me.lucko.fabric.api.permissions.v0.Permissions; import net.kyori.adventure.audience.Audience; import net.minecraft.server.command.ServerCommandSource; import net.william278.uniform.CommandUser; +import net.william278.uniform.Permission; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -48,4 +50,12 @@ public record FabricCommandUser(@NotNull ServerCommandSource source) implements return source.getPlayer() != null ? source.getPlayer().getUuid() : null; } + @Override + public boolean checkPermission(@NotNull Permission permission) { + return Permissions.check( + source, permission.node(), + permission.defaultValue().check(source.hasPermissionLevel(4)) + ); + } + } diff --git a/fabric-1.20.6/build.gradle b/fabric-1.20.6/build.gradle index d36a024..2722a06 100644 --- a/fabric-1.20.6/build.gradle +++ b/fabric-1.20.6/build.gradle @@ -12,6 +12,7 @@ dependencies { modCompileOnly 'net.fabricmc:fabric-loader:0.15.11' modCompileOnly 'net.fabricmc.fabric-api:fabric-api:0.100.0+1.20.6' + modImplementation include('me.lucko:fabric-permissions-api:0.3.1') compileOnly 'org.projectlombok:lombok:1.18.32' diff --git a/fabric-1.20.6/src/main/java/net/william278/uniform/fabric/FabricCommandUser.java b/fabric-1.20.6/src/main/java/net/william278/uniform/fabric/FabricCommandUser.java index b231a59..9235845 100644 --- a/fabric-1.20.6/src/main/java/net/william278/uniform/fabric/FabricCommandUser.java +++ b/fabric-1.20.6/src/main/java/net/william278/uniform/fabric/FabricCommandUser.java @@ -21,9 +21,11 @@ package net.william278.uniform.fabric; +import me.lucko.fabric.api.permissions.v0.Permissions; import net.kyori.adventure.audience.Audience; import net.minecraft.server.command.ServerCommandSource; import net.william278.uniform.CommandUser; +import net.william278.uniform.Permission; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -48,4 +50,12 @@ public record FabricCommandUser(@NotNull ServerCommandSource source) implements return source.getPlayer() != null ? source.getPlayer().getUuid() : null; } + @Override + public boolean checkPermission(@NotNull Permission permission) { + return Permissions.check( + source, permission.node(), + permission.defaultValue().check(source.hasPermissionLevel(4)) + ); + } + } diff --git a/gradle.properties b/gradle.properties index 015e27d..03b6d84 100644 --- a/gradle.properties +++ b/gradle.properties @@ -3,6 +3,6 @@ javaVersion=17 org.gradle.jvmargs='-Dfile.encoding=UTF-8' org.gradle.daemon=true -library_version=1.0.13 +library_version=1.1 library_archive=uniform library_description=Cross-platform wrapper for making Brigadier commands, based on BrigadierWrapper by Tofaa2, itself inspired by emortalmcs command system. \ No newline at end of file diff --git a/paper/src/main/java/net/william278/uniform/paper/LegacyPaperCommandUser.java b/paper/src/main/java/net/william278/uniform/paper/LegacyPaperCommandUser.java index d947895..c0082f4 100644 --- a/paper/src/main/java/net/william278/uniform/paper/LegacyPaperCommandUser.java +++ b/paper/src/main/java/net/william278/uniform/paper/LegacyPaperCommandUser.java @@ -24,6 +24,8 @@ package net.william278.uniform.paper; import com.destroystokyo.paper.brigadier.BukkitBrigadierCommandSource; import net.kyori.adventure.audience.Audience; import net.william278.uniform.CommandUser; +import net.william278.uniform.Permission; +import org.bukkit.command.ConsoleCommandSender; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -50,4 +52,14 @@ public record LegacyPaperCommandUser(@NotNull BukkitBrigadierCommandSource sourc return source.getBukkitEntity() != null ? source.getBukkitEntity().getUniqueId() : null; } + @Override + public boolean checkPermission(@NotNull Permission permission) { + if (source.getBukkitSender().isPermissionSet(permission.node())) { + return source.getBukkitSender().hasPermission(permission.node()); + } + return permission.defaultValue().check( + source.getBukkitSender().isOp() || source.getBukkitSender() instanceof ConsoleCommandSender + ); + } + } diff --git a/paper/src/main/java/net/william278/uniform/paper/PaperCommandUser.java b/paper/src/main/java/net/william278/uniform/paper/PaperCommandUser.java index 462de50..9b4e646 100644 --- a/paper/src/main/java/net/william278/uniform/paper/PaperCommandUser.java +++ b/paper/src/main/java/net/william278/uniform/paper/PaperCommandUser.java @@ -24,6 +24,8 @@ package net.william278.uniform.paper; import io.papermc.paper.command.brigadier.CommandSourceStack; import net.kyori.adventure.audience.Audience; import net.william278.uniform.CommandUser; +import net.william278.uniform.Permission; +import org.bukkit.command.ConsoleCommandSender; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -50,4 +52,14 @@ public record PaperCommandUser(@NotNull CommandSourceStack source) implements Co public UUID getUuid() { return source.getExecutor() != null ? source.getExecutor().getUniqueId() : null; } + + @Override + public boolean checkPermission(@NotNull Permission permission) { + if (source.getSender().isPermissionSet(permission.node())) { + return source.getSender().hasPermission(permission.node()); + } + return permission.defaultValue().check( + source.getSender().isOp() || source.getSender() instanceof ConsoleCommandSender + ); + } } diff --git a/velocity/src/main/java/net/william278/uniform/velocity/VelocityCommandUser.java b/velocity/src/main/java/net/william278/uniform/velocity/VelocityCommandUser.java index defaf59..d154194 100644 --- a/velocity/src/main/java/net/william278/uniform/velocity/VelocityCommandUser.java +++ b/velocity/src/main/java/net/william278/uniform/velocity/VelocityCommandUser.java @@ -22,9 +22,11 @@ package net.william278.uniform.velocity; import com.velocitypowered.api.command.CommandSource; +import com.velocitypowered.api.permission.Tristate; import com.velocitypowered.api.proxy.Player; import net.kyori.adventure.audience.Audience; import net.william278.uniform.CommandUser; +import net.william278.uniform.Permission; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -50,4 +52,12 @@ public record VelocityCommandUser(CommandSource source) implements CommandUser { return source instanceof Player ? ((Player) source).getUniqueId() : null; } + @Override + public boolean checkPermission(@NotNull Permission permission) { + if (source.getPermissionValue(permission.node()) != Tristate.UNDEFINED) { + return source.getPermissionValue(permission.node()) == Tristate.TRUE; + } + return permission.defaultValue().check(source.hasPermission(permission.node())); + } + }