From f12a91fd384e44f830b74746dddd7e97f79e2c68 Mon Sep 17 00:00:00 2001 From: John Paul Rutigliano Date: Sat, 23 Jul 2022 21:09:51 -0400 Subject: [PATCH] Add `PermissionNode`s and groups, for helpers with numerics --- .../fibermc/essentialcommands/ECPerms.java | 176 +++++++++--------- .../EssentialCommandRegistry.java | 2 +- .../essentialcommands/PlayerTeleporter.java | 3 +- .../config/EssentialCommandsConfig.java | 3 +- .../permission/NumericPermissionGroup.java | 44 +++++ .../permission/NumericPermissionNode.java | 15 ++ .../permission/PermissionGroup.java | 38 ++++ .../permission/PermissionNode.java | 18 ++ 8 files changed, 207 insertions(+), 92 deletions(-) create mode 100644 src/main/java/com/fibermc/essentialcommands/permission/NumericPermissionGroup.java create mode 100644 src/main/java/com/fibermc/essentialcommands/permission/NumericPermissionNode.java create mode 100644 src/main/java/com/fibermc/essentialcommands/permission/PermissionGroup.java create mode 100644 src/main/java/com/fibermc/essentialcommands/permission/PermissionNode.java diff --git a/src/main/java/com/fibermc/essentialcommands/ECPerms.java b/src/main/java/com/fibermc/essentialcommands/ECPerms.java index db86bd8d..b41478f6 100644 --- a/src/main/java/com/fibermc/essentialcommands/ECPerms.java +++ b/src/main/java/com/fibermc/essentialcommands/ECPerms.java @@ -1,74 +1,77 @@ package com.fibermc.essentialcommands; +import com.fibermc.essentialcommands.permission.NumericPermissionGroup; +import com.fibermc.essentialcommands.permission.NumericPermissionNode; +import com.fibermc.essentialcommands.permission.PermissionGroup; +import com.fibermc.essentialcommands.permission.PermissionNode; import me.lucko.fabric.api.permissions.v0.Permissions; import net.minecraft.command.CommandSource; import net.minecraft.server.command.ServerCommandSource; import org.jetbrains.annotations.NotNull; -import java.util.Arrays; -import java.util.Collection; +import java.util.Optional; import java.util.function.Predicate; import static com.fibermc.essentialcommands.EssentialCommands.CONFIG; public class ECPerms { - //`essentialcommands..` -// `essentialcommands..*` +// `essentialcommands..` public static final class Registry { - public static final String tpa = "essentialcommands.tpa"; - public static final String tpahere = "essentialcommands.tpahere"; - public static final String tpaccept = "essentialcommands.tpaccept"; - public static final String tpdeny = "essentialcommands.tpdeny"; - public static final String home_set = "essentialcommands.home.set"; - public static final String home_tp = "essentialcommands.home.tp"; - public static final String home_tp_others = "essentialcommands.home_tp_others"; - public static final String home_delete = "essentialcommands.home.delete"; - public static final String warp_set = "essentialcommands.warp.set"; - public static final String warp_tp = "essentialcommands.warp.tp"; - public static final String warp_delete = "essentialcommands.warp.delete"; - public static final String warp_tp_named = "essentialcommands.warp.tp_named"; - public static final String back = "essentialcommands.back"; - public static final String spawn_tp = "essentialcommands.spawn.tp"; - public static final String spawn_set = "essentialcommands.spawn.set"; - public static final String nickname_self = "essentialcommands.nickname.self"; - public static final String nickname_others = "essentialcommands.nickname.others"; - public static final String nickname_reveal = "essentialcommands.nickname.reveal"; - public static final String nickname_style_color = "essentialcommands.nickname.style.color"; - public static final String nickname_style_fancy = "essentialcommands.nickname.style.fancy"; - public static final String nickname_style_hover = "essentialcommands.nickname.style.hover"; - public static final String nickname_style_click = "essentialcommands.nickname.style.click"; - public static final String randomteleport = "essentialcommands.randomteleport"; - public static final String fly_self = "essentialcommands.fly.self"; - public static final String fly_others = "essentialcommands.fly.others"; - public static final String invuln_self = "essentialcommands.invuln.self"; - public static final String invuln_others = "essentialcommands.invuln.others"; - public static final String workbench = "essentialcommands.workbench"; - public static final String stonecutter = "essentialcommands.stonecutter"; - public static final String grindstone = "essentialcommands.grindstone"; - public static final String anvil = "essentialcommands.anvil"; - public static final String enderchest = "essentialcommands.enderchest"; - public static final String wastebin = "essentialcommands.wastebin"; - public static final String top = "essentialcommands.top"; - public static final String gametime = "essentialcommands.gametime"; - public static final String time_set_day = "essentialcommands.day"; - public static final String afk = "essentialcommands.afk"; - public static final String config_reload = "essentialcommands.config.reload"; - public static final String bypass_teleport_delay = "essentialcommands.bypass.teleport_delay"; - public static final String bypass_allow_teleport_between_dimensions = "essentialcommands.bypass.allow_teleport_between_dimensions"; - public static final String bypass_teleport_interrupt_on_damaged = "essentialcommands.bypass.teleport_interrupt_on_damaged"; - public static final String bypass_teleport_interrupt_on_move = "essentialcommands.bypass.teleport_interrupt_on_move"; + public static final PermissionNode tpa = new PermissionNode("essentialcommands.tpa"); + public static final PermissionNode tpahere = new PermissionNode("essentialcommands.tpahere"); + public static final PermissionNode tpaccept = new PermissionNode("essentialcommands.tpaccept"); + public static final PermissionNode tpdeny = new PermissionNode("essentialcommands.tpdeny"); + public static final PermissionNode home_set = new PermissionNode("essentialcommands.home.set"); + public static final PermissionNode home_tp = new PermissionNode("essentialcommands.home.tp"); + public static final PermissionNode home_tp_others = new PermissionNode("essentialcommands.home_tp_others"); + public static final PermissionNode home_delete = new PermissionNode("essentialcommands.home.delete"); + public static final PermissionNode warp_set = new PermissionNode("essentialcommands.warp.set"); + public static final PermissionNode warp_tp = new PermissionNode("essentialcommands.warp.tp"); + public static final PermissionNode warp_delete = new PermissionNode("essentialcommands.warp.delete"); + public static final PermissionNode warp_tp_named = new PermissionNode("essentialcommands.warp.tp_named"); + public static final PermissionNode back = new PermissionNode("essentialcommands.back"); + public static final PermissionNode spawn_tp = new PermissionNode("essentialcommands.spawn.tp"); + public static final PermissionNode spawn_set = new PermissionNode("essentialcommands.spawn.set"); + public static final PermissionNode nickname_self = new PermissionNode("essentialcommands.nickname.self"); + public static final PermissionNode nickname_others = new PermissionNode("essentialcommands.nickname.others"); + public static final PermissionNode nickname_reveal = new PermissionNode("essentialcommands.nickname.reveal"); + public static final PermissionNode nickname_style_color = new PermissionNode("essentialcommands.nickname.style.color"); + public static final PermissionNode nickname_style_fancy = new PermissionNode("essentialcommands.nickname.style.fancy"); + public static final PermissionNode nickname_style_hover = new PermissionNode("essentialcommands.nickname.style.hover"); + public static final PermissionNode nickname_style_click = new PermissionNode("essentialcommands.nickname.style.click"); + public static final PermissionNode randomteleport = new PermissionNode("essentialcommands.randomteleport"); + public static final PermissionNode fly_self = new PermissionNode("essentialcommands.fly.self"); + public static final PermissionNode fly_others = new PermissionNode("essentialcommands.fly.others"); + public static final PermissionNode invuln_self = new PermissionNode("essentialcommands.invuln.self"); + public static final PermissionNode invuln_others = new PermissionNode("essentialcommands.invuln.others"); + public static final PermissionNode workbench = new PermissionNode("essentialcommands.workbench"); + public static final PermissionNode stonecutter = new PermissionNode("essentialcommands.stonecutter"); + public static final PermissionNode grindstone = new PermissionNode("essentialcommands.grindstone"); + public static final PermissionNode anvil = new PermissionNode("essentialcommands.anvil"); + public static final PermissionNode enderchest = new PermissionNode("essentialcommands.enderchest"); + public static final PermissionNode wastebin = new PermissionNode("essentialcommands.wastebin"); + public static final PermissionNode top = new PermissionNode("essentialcommands.top"); + public static final PermissionNode gametime = new PermissionNode("essentialcommands.gametime"); + public static final PermissionNode time_set_day = new PermissionNode("essentialcommands.day"); + public static final PermissionNode afk = new PermissionNode("essentialcommands.afk"); + public static final PermissionNode config_reload = new PermissionNode("essentialcommands.config.reload"); + public static final PermissionNode admin_last_pos = new PermissionNode("essentialcommands.admin.lastpos"); + public static final PermissionNode bypass_teleport_delay = new PermissionNode("essentialcommands.bypass.teleport_delay"); + public static final PermissionNode bypass_allow_teleport_between_dimensions = new PermissionNode("essentialcommands.bypass.allow_teleport_between_dimensions"); + public static final PermissionNode bypass_teleport_interrupt_on_damaged = new PermissionNode("essentialcommands.bypass.teleport_interrupt_on_damaged"); + public static final PermissionNode bypass_teleport_interrupt_on_move = new PermissionNode("essentialcommands.bypass.teleport_interrupt_on_move"); public static final class Group { - public static final String[] tpa_group = {tpa, tpahere, tpaccept, tpdeny}; - public static final String[] home_group = {home_set, home_tp, home_delete}; - public static final String[] warp_group = {warp_set, warp_tp, warp_delete}; - public static final String[] spawn_group = {spawn_tp, spawn_set}; - public static final String[] nickname_group = {nickname_self, nickname_others, nickname_reveal}; - public static final String[] fly_group = {fly_self, fly_others}; - public static final String[] config_group = {config_reload}; - public static String[] home_limit_group; + public static final PermissionGroup tpa_group = PermissionGroup.of(tpa, tpahere, tpaccept, tpdeny); + public static final PermissionGroup home_group = PermissionGroup.of(home_set, home_tp, home_delete); + public static final PermissionGroup warp_group = PermissionGroup.of(warp_set, warp_tp, warp_delete); + public static final PermissionGroup spawn_group = PermissionGroup.of(spawn_tp, spawn_set); + public static final PermissionGroup nickname_group = PermissionGroup.of(nickname_self, nickname_others, nickname_reveal); + public static final PermissionGroup fly_group = PermissionGroup.of(fly_self, fly_others); + public static final PermissionGroup config_group = PermissionGroup.of(config_reload); + public static NumericPermissionGroup home_limit_group; } - public static String[] per_warp_permissions = null; + public static PermissionGroup per_warp_permissions = null; } /** @@ -76,9 +79,9 @@ public static final class Group { */ static void init() { var worldDataManager = ManagerLocator.getInstance().getWorldDataManager(); - Registry.per_warp_permissions = worldDataManager.getWarpNames().toArray(new String[0]); + Registry.per_warp_permissions = PermissionGroup.ofStrings(worldDataManager.getWarpNames().toArray(new String[0])); worldDataManager.WARPS_LOAD_EVENT.register((warps) -> { - Registry.per_warp_permissions = warps.keySet().toArray(new String[0]); + Registry.per_warp_permissions = PermissionGroup.ofStrings(warps.keySet().toArray(String[]::new)); }); } @@ -86,12 +89,11 @@ private static boolean isSuperAdmin(CommandSource source) { return source.hasPermissionLevel(4); } - - public static @NotNull Predicate require(@NotNull String permission, int defaultRequireLevel) { + public static @NotNull Predicate require(@NotNull PermissionNode permission, int defaultRequireLevel) { return player -> check(player, permission, defaultRequireLevel); } - public static @NotNull Predicate requireAny(@NotNull String[] permissions, int defaultRequireLevel) { + public static @NotNull Predicate requireAny(@NotNull PermissionGroup permissions, int defaultRequireLevel) { return player -> checkAny(player, permissions, defaultRequireLevel); } @@ -99,7 +101,9 @@ public static boolean check(@NotNull CommandSource source, @NotNull String permi if (CONFIG.USE_PERMISSIONS_API) { try { // TODO: In the future, config option for granting ops all perms. - return Permissions.getPermissionValue(source, permission).orElse(source.hasPermissionLevel(Math.max(2, defaultRequireLevel))); + return Permissions + .getPermissionValue(source, permission) + .orElse(source.hasPermissionLevel(Math.max(2, defaultRequireLevel))); } catch (Exception e) { EssentialCommands.LOGGER.error(e); return false; @@ -109,61 +113,55 @@ public static boolean check(@NotNull CommandSource source, @NotNull String permi } } + public static boolean check(@NotNull CommandSource source, @NotNull PermissionNode permission, int defaultRequireLevel) { + return check(source, permission.getString(), defaultRequireLevel); + } + + public static boolean check(@NotNull CommandSource source, @NotNull String permission) { return check(source, permission, 4); } - public static boolean checkAny(@NotNull CommandSource source, @NotNull String[] permissions, int defaultRequireLevel) { - for (String permission : permissions) { - if (check(source, permission, defaultRequireLevel)) { - return true; - } - } - return false; + public static boolean check(@NotNull CommandSource source, @NotNull TNode permission) { + return check(source, permission, 4); + } + + public static boolean checkAny(@NotNull CommandSource source, @NotNull PermissionGroup permissions, int defaultRequireLevel) { + return permissions.streamNodes().anyMatch(permission -> check(source, permission, defaultRequireLevel)); } private static int getNumericValue(String permission) { return Integer.parseInt(permission.substring(permission.lastIndexOf('.') + 1)); } - static int getHighestNumericPermission(@NotNull CommandSource source, @NotNull String[] permissionGroup) { + static int getHighestNumericPermission(@NotNull CommandSource source, @NotNull NumericPermissionGroup permissionGroup) { // No effective numeric limits for ops. if (isSuperAdmin(source)) { return Integer.MAX_VALUE; } // If ONLY -1 is present as possibility, treat as no effective limit. - if (permissionGroup.length == 1 && getNumericValue(permissionGroup[0]) == -1) { + if (permissionGroup.size() == 1 && permissionGroup.getHighest().getNumericValue() == -1) { return Integer.MAX_VALUE; } // If permissions API is disabled, min int value in permission group is used for all non-op players. if (!CONFIG.USE_PERMISSIONS_API) { - return Arrays.stream(permissionGroup).mapToInt(ECPerms::getNumericValue).min().getAsInt(); + return permissionGroup.getLowest().getNumericValue(); } // If permissions api is enabled, find the highest numeric permission node that the user has & return its // numeric value. - int highestValue; - if (CONFIG.GRANT_LOWEST_NUMERIC_BY_DEFAULT) { + var highestValue = permissionGroup + .getHighestGranted(permission -> check(source, permission)) + .map(NumericPermissionNode::getNumericValue); + + if (highestValue.isEmpty() && CONFIG.GRANT_LOWEST_NUMERIC_BY_DEFAULT) { // Grant min perm value in group by default, if none are set. - highestValue = Arrays.stream(permissionGroup).mapToInt(ECPerms::getNumericValue).min().getAsInt(); - } else { - // Set value to -1 in the case where the user has no relevant permissions set. - highestValue = -1; - } - for (String permission: permissionGroup) { - if (check(source, permission)) { - highestValue = Math.max(highestValue, getNumericValue(permission)); - } + highestValue = Optional.of(permissionGroup.getLowest().getNumericValue()); } - return highestValue; - } - public static String[] makeNumericPermissionGroup(String basePermission, Collection numericValues) { - String trueBasePermission = basePermission.endsWith(".") ? basePermission : basePermission + "."; - return numericValues.stream().map(el -> trueBasePermission.concat(el.toString())).toArray(String[]::new); + // Set value to -1 in the case where the user has no relevant permissions set. + return highestValue.orElse(-1); } - - } \ No newline at end of file diff --git a/src/main/java/com/fibermc/essentialcommands/EssentialCommandRegistry.java b/src/main/java/com/fibermc/essentialcommands/EssentialCommandRegistry.java index 234de906..6d782f4d 100644 --- a/src/main/java/com/fibermc/essentialcommands/EssentialCommandRegistry.java +++ b/src/main/java/com/fibermc/essentialcommands/EssentialCommandRegistry.java @@ -391,7 +391,7 @@ public static void register( } registerNode.accept(CommandManager.literal("lastPos") - .requires(ECPerms.require("essentialcommands.admin.lastpos", 2)) + .requires(ECPerms.require(ECPerms.Registry.admin_last_pos, 2)) .then(argument("target_player", StringArgumentType.word()) .executes((context) -> { var targetPlayerName = StringArgumentType.getString(context, "target_player"); diff --git a/src/main/java/com/fibermc/essentialcommands/PlayerTeleporter.java b/src/main/java/com/fibermc/essentialcommands/PlayerTeleporter.java index 8187dca8..d98a5b83 100644 --- a/src/main/java/com/fibermc/essentialcommands/PlayerTeleporter.java +++ b/src/main/java/com/fibermc/essentialcommands/PlayerTeleporter.java @@ -1,6 +1,7 @@ package com.fibermc.essentialcommands; import com.fibermc.essentialcommands.access.ServerPlayerEntityAccess; +import com.fibermc.essentialcommands.permission.PermissionNode; import com.fibermc.essentialcommands.types.MinecraftLocation; import net.minecraft.network.message.MessageType; import net.minecraft.server.network.ServerPlayerEntity; @@ -80,7 +81,7 @@ private static void execTeleport(ServerPlayerEntity playerEntity, MinecraftLocat ); } - public static boolean playerHasTpRulesBypass(ServerPlayerEntity player, String permission) { + public static boolean playerHasTpRulesBypass(ServerPlayerEntity player, PermissionNode permission) { return ( (player.hasPermissionLevel(4) && CONFIG.OPS_BYPASS_TELEPORT_RULES) || ECPerms.check(player.getCommandSource(), permission, 5) diff --git a/src/main/java/com/fibermc/essentialcommands/config/EssentialCommandsConfig.java b/src/main/java/com/fibermc/essentialcommands/config/EssentialCommandsConfig.java index 8a7dc17f..ad9103e7 100644 --- a/src/main/java/com/fibermc/essentialcommands/config/EssentialCommandsConfig.java +++ b/src/main/java/com/fibermc/essentialcommands/config/EssentialCommandsConfig.java @@ -1,6 +1,7 @@ package com.fibermc.essentialcommands.config; import com.fibermc.essentialcommands.ECPerms; +import com.fibermc.essentialcommands.permission.NumericPermissionGroup; import dev.jpcode.eccore.config.Config; import dev.jpcode.eccore.config.ConfigOption; import dev.jpcode.eccore.config.ConfigUtil; @@ -76,7 +77,7 @@ public final class EssentialCommandsConfig extends Config - ECPerms.Registry.Group.home_limit_group = ECPerms.makeNumericPermissionGroup("essentialcommands.home.limit", newValue) + ECPerms.Registry.Group.home_limit_group = NumericPermissionGroup.create("essentialcommands.home.limit", newValue) ); } diff --git a/src/main/java/com/fibermc/essentialcommands/permission/NumericPermissionGroup.java b/src/main/java/com/fibermc/essentialcommands/permission/NumericPermissionGroup.java new file mode 100644 index 00000000..604ad7a8 --- /dev/null +++ b/src/main/java/com/fibermc/essentialcommands/permission/NumericPermissionGroup.java @@ -0,0 +1,44 @@ +package com.fibermc.essentialcommands.permission; + +import java.util.Collection; +import java.util.Comparator; +import java.util.Optional; +import java.util.function.Predicate; +import java.util.stream.Stream; + +public class NumericPermissionGroup extends PermissionGroup { + private NumericPermissionGroup(Collection nodes) { + super(nodes); + } + + public static NumericPermissionGroup create(String basePermission, Collection numericValues) { + String trueBasePermission = basePermission.endsWith(".") ? basePermission : basePermission + "."; + var nodes = numericValues.stream() + .sorted(Comparator.comparingInt(a -> -a)) // Order Descending + .map(num -> new NumericPermissionNode(trueBasePermission, num)) + .toList(); + + return new NumericPermissionGroup(nodes); + } + + public NumericPermissionNode getHighest() { + return super.nodes.get(0); + } + + public NumericPermissionNode getLowest() { + return super.nodes.get(super.nodes.size() - 1); + } + + public Optional getHighestGranted(Predicate checkGrantedFn) { + return super.nodes.stream() + .filter(checkGrantedFn) + .findFirst(); + } + + public Optional getLowestGranted(Predicate checkGrantedFn) { + var iterator = super.nodes.listIterator(); + return Stream.generate(iterator::previous).limit(super.nodes.size()) + .filter(checkGrantedFn) + .findFirst(); + } +} diff --git a/src/main/java/com/fibermc/essentialcommands/permission/NumericPermissionNode.java b/src/main/java/com/fibermc/essentialcommands/permission/NumericPermissionNode.java new file mode 100644 index 00000000..eaf3559c --- /dev/null +++ b/src/main/java/com/fibermc/essentialcommands/permission/NumericPermissionNode.java @@ -0,0 +1,15 @@ +package com.fibermc.essentialcommands.permission; + +public class NumericPermissionNode extends PermissionNode { + + private final int numericValue; + + public NumericPermissionNode(String node, int numericValue) { + super(node + numericValue); + this.numericValue = numericValue; + } + + public int getNumericValue() { + return numericValue; + } +} diff --git a/src/main/java/com/fibermc/essentialcommands/permission/PermissionGroup.java b/src/main/java/com/fibermc/essentialcommands/permission/PermissionGroup.java new file mode 100644 index 00000000..c7f8aa43 --- /dev/null +++ b/src/main/java/com/fibermc/essentialcommands/permission/PermissionGroup.java @@ -0,0 +1,38 @@ +package com.fibermc.essentialcommands.permission; + +import java.util.Arrays; +import java.util.Collection; +import java.util.List; +import java.util.stream.Stream; + +public class PermissionGroup { + protected final List nodes; + + public PermissionGroup(Collection nodes) { + this.nodes = nodes.stream().toList(); + } + + public List toList() { + return nodes.stream().toList(); + } + + public Stream streamStrings() { + return nodes.stream().map(PermissionNode::getString); + } + + public Stream streamNodes() { + return nodes.stream(); + } + + public static PermissionGroup of(PermissionNode... nodes) { + return new PermissionGroup<>(Arrays.stream(nodes).toList()); + } + + public static PermissionGroup ofStrings(String... nodes) { + return new PermissionGroup<>(Arrays.stream(nodes).map(PermissionNode::new).toList()); + } + + public int size() { + return nodes.size(); + } +} diff --git a/src/main/java/com/fibermc/essentialcommands/permission/PermissionNode.java b/src/main/java/com/fibermc/essentialcommands/permission/PermissionNode.java new file mode 100644 index 00000000..704b330b --- /dev/null +++ b/src/main/java/com/fibermc/essentialcommands/permission/PermissionNode.java @@ -0,0 +1,18 @@ +package com.fibermc.essentialcommands.permission; + +public class PermissionNode { + + final String node; + + public PermissionNode(String node) { + this.node = node; + } + + public String getString() { + return node; + } + +// public boolean equals(PermissionNode other) { +// return this.getString().equals(other.getString()); +// } +}