From 07254b36d712bf478c19c799f784be914e03c2d1 Mon Sep 17 00:00:00 2001 From: sciwhiz12 Date: Wed, 17 Aug 2022 05:11:54 +0800 Subject: [PATCH] Redirect checks for entity selector use to a permission (#8947) This allows greater flexibility for configuring servers with operator-like permissions to user groups through the permissions API and their permissions handler of choice without needing to grant the vanilla operator permission to any player. The new permission is "forge:use_entity_selectors", which is granted by default to players with permission level 2 (GAMEMASTERS) and above. The hook falls back to checking the permission level if the source of the command is not a ServerPlayer, such as for command blocks and functions. --- .../commands/arguments/EntityArgument.java.patch | 11 +++++++++++ .../commands/arguments/MessageArgument.java.patch | 11 +++++++++++ .../arguments/selector/EntitySelector.java.patch | 11 +++++++++++ .../java/net/minecraftforge/common/ForgeHooks.java | 13 +++++++++++++ .../java/net/minecraftforge/common/ForgeMod.java | 13 +++++++++++++ 5 files changed, 59 insertions(+) create mode 100644 patches/minecraft/net/minecraft/commands/arguments/EntityArgument.java.patch create mode 100644 patches/minecraft/net/minecraft/commands/arguments/MessageArgument.java.patch create mode 100644 patches/minecraft/net/minecraft/commands/arguments/selector/EntitySelector.java.patch diff --git a/patches/minecraft/net/minecraft/commands/arguments/EntityArgument.java.patch b/patches/minecraft/net/minecraft/commands/arguments/EntityArgument.java.patch new file mode 100644 index 0000000000..b06e3596a1 --- /dev/null +++ b/patches/minecraft/net/minecraft/commands/arguments/EntityArgument.java.patch @@ -0,0 +1,11 @@ +--- a/net/minecraft/commands/arguments/EntityArgument.java ++++ b/net/minecraft/commands/arguments/EntityArgument.java +@@ -115,7 +_,7 @@ + if (s instanceof SharedSuggestionProvider sharedsuggestionprovider) { + StringReader stringreader = new StringReader(p_91483_.getInput()); + stringreader.setCursor(p_91483_.getStart()); +- EntitySelectorParser entityselectorparser = new EntitySelectorParser(stringreader, sharedsuggestionprovider.m_6761_(2)); ++ EntitySelectorParser entityselectorparser = new EntitySelectorParser(stringreader, net.minecraftforge.common.ForgeHooks.canUseEntitySelectors(sharedsuggestionprovider)); + + try { + entityselectorparser.m_121377_(); diff --git a/patches/minecraft/net/minecraft/commands/arguments/MessageArgument.java.patch b/patches/minecraft/net/minecraft/commands/arguments/MessageArgument.java.patch new file mode 100644 index 0000000000..c500e4a287 --- /dev/null +++ b/patches/minecraft/net/minecraft/commands/arguments/MessageArgument.java.patch @@ -0,0 +1,11 @@ +--- a/net/minecraft/commands/arguments/MessageArgument.java ++++ b/net/minecraft/commands/arguments/MessageArgument.java +@@ -134,7 +_,7 @@ + } + + Component m_232196_(CommandSourceStack p_232197_) throws CommandSyntaxException { +- return this.m_96849_(p_232197_, p_232197_.m_6761_(2)); ++ return this.m_96849_(p_232197_, net.minecraftforge.common.ForgeHooks.canUseEntitySelectors(p_232197_)); + } + + public Component m_96849_(CommandSourceStack p_96850_, boolean p_96851_) throws CommandSyntaxException { diff --git a/patches/minecraft/net/minecraft/commands/arguments/selector/EntitySelector.java.patch b/patches/minecraft/net/minecraft/commands/arguments/selector/EntitySelector.java.patch new file mode 100644 index 0000000000..60fb7cad0b --- /dev/null +++ b/patches/minecraft/net/minecraft/commands/arguments/selector/EntitySelector.java.patch @@ -0,0 +1,11 @@ +--- a/net/minecraft/commands/arguments/selector/EntitySelector.java ++++ b/net/minecraft/commands/arguments/selector/EntitySelector.java +@@ -87,7 +_,7 @@ + } + + private void m_121168_(CommandSourceStack p_121169_) throws CommandSyntaxException { +- if (this.f_121123_ && !p_121169_.m_6761_(2)) { ++ if (this.f_121123_ && !net.minecraftforge.common.ForgeHooks.canUseEntitySelectors(p_121169_)) { + throw EntityArgument.f_91441_.create(); + } + } diff --git a/src/main/java/net/minecraftforge/common/ForgeHooks.java b/src/main/java/net/minecraftforge/common/ForgeHooks.java index c7cb25cc3b..ef85dc72cc 100644 --- a/src/main/java/net/minecraftforge/common/ForgeHooks.java +++ b/src/main/java/net/minecraftforge/common/ForgeHooks.java @@ -32,6 +32,9 @@ import com.mojang.serialization.Lifecycle; import it.unimi.dsi.fastutil.objects.ObjectArrayList; import net.minecraft.ResourceLocationException; import net.minecraft.advancements.Advancement; +import net.minecraft.commands.CommandSourceStack; +import net.minecraft.commands.Commands; +import net.minecraft.commands.SharedSuggestionProvider; import net.minecraft.core.*; import net.minecraft.network.chat.*; import net.minecraft.network.chat.contents.LiteralContents; @@ -147,6 +150,7 @@ import net.minecraftforge.registries.ForgeRegistry; import net.minecraftforge.registries.GameData; import net.minecraftforge.registries.RegistryManager; import net.minecraftforge.registries.holdersets.ICustomHolderSet; +import net.minecraftforge.server.permission.PermissionAPI; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -1491,4 +1495,13 @@ public class ForgeHooks { return registryKey.getNamespace().equals("minecraft") ? registryKey.getPath() : registryKey.getNamespace() + "/" + registryKey.getPath(); } + + public static boolean canUseEntitySelectors(SharedSuggestionProvider provider) + { + if (provider instanceof CommandSourceStack source && source.getEntity() instanceof ServerPlayer player) + { + return PermissionAPI.getPermission(player, ForgeMod.USE_SELECTORS_PERMISSION); + } + return provider.hasPermission(Commands.LEVEL_GAMEMASTERS); + } } diff --git a/src/main/java/net/minecraftforge/common/ForgeMod.java b/src/main/java/net/minecraftforge/common/ForgeMod.java index 8d9e42d727..62a47fe340 100644 --- a/src/main/java/net/minecraftforge/common/ForgeMod.java +++ b/src/main/java/net/minecraftforge/common/ForgeMod.java @@ -14,6 +14,7 @@ import net.minecraft.core.BlockPos; import net.minecraft.sounds.SoundEvents; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.Mob; +import net.minecraft.commands.Commands; import net.minecraft.world.entity.ai.attributes.Attribute; import net.minecraft.world.entity.ai.attributes.RangedAttribute; import net.minecraft.world.entity.item.ItemEntity; @@ -73,6 +74,9 @@ import net.minecraftforge.data.event.GatherDataEvent; import net.minecraftforge.network.filters.VanillaPacketSplitter; import net.minecraftforge.server.command.EnumArgument; import net.minecraftforge.server.command.ModIdArgument; +import net.minecraftforge.server.permission.events.PermissionGatherEvent; +import net.minecraftforge.server.permission.nodes.PermissionNode; +import net.minecraftforge.server.permission.nodes.PermissionTypes; import net.minecraftforge.versions.forge.ForgeVersion; import net.minecraftforge.versions.mcp.MCPVersion; @@ -461,6 +465,7 @@ public class ForgeMod MinecraftForge.EVENT_BUS.addListener(VillagerTradingManager::loadTrades); MinecraftForge.EVENT_BUS.register(MinecraftForge.INTERNAL_HANDLER); MinecraftForge.EVENT_BUS.addListener(this::mappingChanged); + MinecraftForge.EVENT_BUS.addListener(this::registerPermissionNodes); ForgeRegistries.ITEMS.tags().addOptionalTagDefaults(Tags.Items.ENCHANTING_FUELS, Set.of(ForgeRegistries.ITEMS.getDelegateOrThrow(Items.LAPIS_LAZULI))); } @@ -602,4 +607,12 @@ public class ForgeMod event.register(Registry.LOOT_ITEM_REGISTRY, new ResourceLocation("forge:loot_table_id"), () -> LootTableIdCondition.LOOT_TABLE_ID); event.register(Registry.LOOT_ITEM_REGISTRY, new ResourceLocation("forge:can_tool_perform_action"), () -> CanToolPerformAction.LOOT_CONDITION_TYPE); } + + public static final PermissionNode USE_SELECTORS_PERMISSION = new PermissionNode<>("forge", "use_entity_selectors", + PermissionTypes.BOOLEAN, (player, uuid, contexts) -> player != null && player.hasPermissions(Commands.LEVEL_GAMEMASTERS)); + + public void registerPermissionNodes(PermissionGatherEvent.Nodes event) + { + event.addNodes(USE_SELECTORS_PERMISSION); + } }