From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: Jake Potrebic Date: Sun, 22 Aug 2021 15:21:57 -0700 Subject: [PATCH] Fix entity type tags suggestions in selectors This would really be better as a client fix because just to fix it all EntityArguments have been told to ask the server for completions when if this was fixed on the client, that wouldn't be needed. Mojira Issue: https://bugs.mojang.com/browse/MC-235045 diff --git a/src/main/java/net/minecraft/commands/CommandSourceStack.java b/src/main/java/net/minecraft/commands/CommandSourceStack.java index 308b3a36f063c401a447f9b7f0364700eee5a54c..43c71d9bf2eac98023057b4483fdd143a8343e98 100644 --- a/src/main/java/net/minecraft/commands/CommandSourceStack.java +++ b/src/main/java/net/minecraft/commands/CommandSourceStack.java @@ -441,4 +441,20 @@ public class CommandSourceStack implements SharedSuggestionProvider, com.destroy return this.source.getBukkitSender(this); } // CraftBukkit end + // Paper start - override getSelectedEntities + @Override + public Collection getSelectedEntities() { + if (io.papermc.paper.configuration.GlobalConfiguration.get().commands.fixTargetSelectorTagCompletion && this.source instanceof ServerPlayer player) { + final Entity cameraEntity = player.getCamera(); + final double pickDistance = player.gameMode.getGameModeForPlayer().isCreative() ? 6.0F : 4.5F; + final Vec3 min = cameraEntity.getEyePosition(1.0F); + final Vec3 viewVector = cameraEntity.getViewVector(1.0F); + final Vec3 max = min.add(viewVector.x * pickDistance, viewVector.y * pickDistance, viewVector.z * pickDistance); + final net.minecraft.world.phys.AABB aabb = cameraEntity.getBoundingBox().expandTowards(viewVector.scale(pickDistance)).inflate(1.0D, 1.0D, 1.0D); + final net.minecraft.world.phys.EntityHitResult hitResult = net.minecraft.world.entity.projectile.ProjectileUtil.getEntityHitResult(cameraEntity, min, max, aabb, (e) -> !e.isSpectator() && e.isPickable(), pickDistance * pickDistance); + return hitResult != null ? java.util.Collections.singletonList(hitResult.getEntity().getStringUUID()) : SharedSuggestionProvider.super.getSelectedEntities(); + } + return SharedSuggestionProvider.super.getSelectedEntities(); + } + // Paper end } diff --git a/src/main/java/net/minecraft/commands/Commands.java b/src/main/java/net/minecraft/commands/Commands.java index 7592b592a541912f729d6b99f455cd87ebcb34b8..f967e9039c87ec458da3f133743df834437b3e02 100644 --- a/src/main/java/net/minecraft/commands/Commands.java +++ b/src/main/java/net/minecraft/commands/Commands.java @@ -472,6 +472,7 @@ public class Commands { private void fillUsableCommands(CommandNode tree, CommandNode result, CommandSourceStack source, Map, CommandNode> resultNodes) { Iterator iterator = tree.getChildren().iterator(); + boolean registeredAskServerSuggestionsForTree = false; // Paper - tell clients to ask server for suggestions for EntityArguments while (iterator.hasNext()) { CommandNode commandnode2 = (CommandNode) iterator.next(); // Paper start @@ -498,6 +499,12 @@ public class Commands { if (requiredargumentbuilder.getSuggestionsProvider() != null) { requiredargumentbuilder.suggests(SuggestionProviders.safelySwap(requiredargumentbuilder.getSuggestionsProvider())); + // Paper start - tell clients to ask server for suggestions for EntityArguments + registeredAskServerSuggestionsForTree = requiredargumentbuilder.getSuggestionsProvider() == net.minecraft.commands.synchronization.SuggestionProviders.ASK_SERVER; + } else if (io.papermc.paper.configuration.GlobalConfiguration.get().commands.fixTargetSelectorTagCompletion && !registeredAskServerSuggestionsForTree && requiredargumentbuilder.getType() instanceof net.minecraft.commands.arguments.EntityArgument) { + requiredargumentbuilder.suggests(requiredargumentbuilder.getType()::listSuggestions); + registeredAskServerSuggestionsForTree = true; // You can only + // Paper end - tell clients to ask server for suggestions for EntityArguments } } diff --git a/src/main/java/net/minecraft/commands/arguments/EntityArgument.java b/src/main/java/net/minecraft/commands/arguments/EntityArgument.java index 850db283bf12345e9e7d7e8e590dbe8135c6dce1..a71726cee91fb406875a4540c9fb7c0ecf757294 100644 --- a/src/main/java/net/minecraft/commands/arguments/EntityArgument.java +++ b/src/main/java/net/minecraft/commands/arguments/EntityArgument.java @@ -128,7 +128,7 @@ public class EntityArgument implements ArgumentType { StringReader stringreader = new StringReader(suggestionsbuilder.getInput()); stringreader.setCursor(suggestionsbuilder.getStart()); - EntitySelectorParser argumentparserselector = new EntitySelectorParser(stringreader, icompletionprovider.hasPermission(2)); + EntitySelectorParser argumentparserselector = new EntitySelectorParser(stringreader, icompletionprovider.hasPermission(2), true); // Paper try { argumentparserselector.parse(); @@ -137,7 +137,19 @@ public class EntityArgument implements ArgumentType { } return argumentparserselector.fillSuggestions(suggestionsbuilder, (suggestionsbuilder1) -> { - Collection collection = icompletionprovider.getOnlinePlayerNames(); + // Paper start + final Collection collection; + if (icompletionprovider instanceof CommandSourceStack commandSourceStack && commandSourceStack.getEntity() instanceof ServerPlayer sourcePlayer) { + collection = new java.util.ArrayList<>(); + for (final ServerPlayer player : commandSourceStack.getServer().getPlayerList().getPlayers()) { + if (sourcePlayer.getBukkitEntity().canSee(player.getBukkitEntity())) { + collection.add(player.getGameProfile().getName()); + } + } + } else { + collection = icompletionprovider.getOnlinePlayerNames(); + } + // Paper end Iterable iterable = this.playersOnly ? collection : Iterables.concat(collection, icompletionprovider.getSelectedEntities()); SharedSuggestionProvider.suggest((Iterable) iterable, suggestionsbuilder1); diff --git a/src/main/java/net/minecraft/commands/arguments/selector/EntitySelectorParser.java b/src/main/java/net/minecraft/commands/arguments/selector/EntitySelectorParser.java index cdc1319a7cb45a7c5ea30885958b8c3c54f0a241..4cc2ee22369aef22c9bf9d2b244c7278d6db39bb 100644 --- a/src/main/java/net/minecraft/commands/arguments/selector/EntitySelectorParser.java +++ b/src/main/java/net/minecraft/commands/arguments/selector/EntitySelectorParser.java @@ -113,12 +113,19 @@ public class EntitySelectorParser { private boolean hasScores; private boolean hasAdvancements; private boolean usesSelectors; + public boolean parsingEntityArgumentSuggestions; // Paper - track when parsing EntityArgument suggestions public EntitySelectorParser(StringReader reader) { this(reader, true); } public EntitySelectorParser(StringReader reader, boolean atAllowed) { + // Paper start + this(reader, atAllowed, false); + } + public EntitySelectorParser(StringReader reader, boolean atAllowed, boolean parsingEntityArgumentSuggestions) { + this.parsingEntityArgumentSuggestions = parsingEntityArgumentSuggestions; + // Paper end this.distance = MinMaxBounds.Doubles.ANY; this.level = MinMaxBounds.Ints.ANY; this.rotX = WrappedMinMaxBounds.ANY; diff --git a/src/main/java/net/minecraft/commands/arguments/selector/options/EntitySelectorOptions.java b/src/main/java/net/minecraft/commands/arguments/selector/options/EntitySelectorOptions.java index 027906d533717fa97a523f4b03b31270fe3fa5fc..c51bcb3d89936cf558a5fe8aa6371617274a02a1 100644 --- a/src/main/java/net/minecraft/commands/arguments/selector/options/EntitySelectorOptions.java +++ b/src/main/java/net/minecraft/commands/arguments/selector/options/EntitySelectorOptions.java @@ -68,6 +68,19 @@ public class EntitySelectorOptions { public static final DynamicCommandExceptionType ERROR_ENTITY_TYPE_INVALID = new DynamicCommandExceptionType((entity) -> { return Component.translatable("argument.entity.options.type.invalid", entity); }); + // Paper start + public static final DynamicCommandExceptionType ERROR_ENTITY_TAG_INVALID = new DynamicCommandExceptionType((object) -> { + return io.papermc.paper.adventure.PaperAdventure + .asVanilla(net.kyori.adventure.text.Component + .text("Invalid or unknown entity type tag '" + object + "'") + .hoverEvent(net.kyori.adventure.text.event.HoverEvent + .showText(net.kyori.adventure.text.Component + .text("You can disable this error in 'paper.yml'") + ) + ) + ); + }); + // Paper end private static void register(String id, EntitySelectorOptions.Modifier handler, Predicate condition, Component description) { OPTIONS.put(id, new EntitySelectorOptions.Option(handler, condition, description)); @@ -315,6 +328,12 @@ public class EntitySelectorOptions { if (reader.isTag()) { TagKey> tagKey = TagKey.create(Registries.ENTITY_TYPE, ResourceLocation.read(reader.getReader())); + // Paper start - throw error if invalid entity tag (only on suggestions to keep cmd success behavior) + if (reader.parsingEntityArgumentSuggestions && io.papermc.paper.configuration.GlobalConfiguration.get().commands.fixTargetSelectorTagCompletion && net.minecraft.core.registries.BuiltInRegistries.ENTITY_TYPE.getTag(tagKey).isEmpty()) { + reader.getReader().setCursor(i); + throw ERROR_ENTITY_TAG_INVALID.createWithContext(reader.getReader(), tagKey); + } + // Paper end reader.addPredicate((entity) -> { return entity.getType().is(tagKey) != bl; });