package net.minecraft.commands.arguments.selector.options; import com.google.common.collect.Maps; import com.mojang.brigadier.StringReader; import com.mojang.brigadier.exceptions.CommandSyntaxException; import com.mojang.brigadier.exceptions.DynamicCommandExceptionType; import com.mojang.brigadier.exceptions.SimpleCommandExceptionType; import com.mojang.brigadier.suggestion.SuggestionsBuilder; import java.util.Arrays; import java.util.Locale; import java.util.Map; import java.util.Objects; import java.util.Optional; import java.util.Map.Entry; import java.util.function.Consumer; import java.util.function.Predicate; import net.minecraft.advancements.AdvancementHolder; import net.minecraft.advancements.AdvancementProgress; import net.minecraft.advancements.CriterionProgress; import net.minecraft.advancements.critereon.MinMaxBounds; import net.minecraft.advancements.critereon.WrappedMinMaxBounds; import net.minecraft.commands.SharedSuggestionProvider; import net.minecraft.commands.arguments.selector.EntitySelector; import net.minecraft.commands.arguments.selector.EntitySelectorParser; import net.minecraft.core.Holder; import net.minecraft.core.HolderSet; import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.core.registries.Registries; import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.NbtUtils; import net.minecraft.nbt.TagParser; import net.minecraft.network.chat.Component; import net.minecraft.resources.ResourceKey; import net.minecraft.resources.ResourceLocation; import net.minecraft.server.PlayerAdvancements; import net.minecraft.server.ServerAdvancementManager; import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; import net.minecraft.tags.TagKey; import net.minecraft.util.Mth; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.EntityType; import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.GameType; import net.minecraft.world.level.storage.loot.LootContext; import net.minecraft.world.level.storage.loot.LootParams; import net.minecraft.world.level.storage.loot.parameters.LootContextParamSets; import net.minecraft.world.level.storage.loot.parameters.LootContextParams; import net.minecraft.world.level.storage.loot.predicates.LootItemCondition; import net.minecraft.world.scores.Objective; import net.minecraft.world.scores.ReadOnlyScoreInfo; import net.minecraft.world.scores.Scoreboard; import net.minecraft.world.scores.Team; public class EntitySelectorOptions { private static final Map OPTIONS = Maps.newHashMap(); public static final DynamicCommandExceptionType ERROR_UNKNOWN_OPTION = new DynamicCommandExceptionType( p_308416_ -> Component.translatableEscape("argument.entity.options.unknown", p_308416_) ); public static final DynamicCommandExceptionType ERROR_INAPPLICABLE_OPTION = new DynamicCommandExceptionType( p_308412_ -> Component.translatableEscape("argument.entity.options.inapplicable", p_308412_) ); public static final SimpleCommandExceptionType ERROR_RANGE_NEGATIVE = new SimpleCommandExceptionType(Component.translatable("argument.entity.options.distance.negative")); public static final SimpleCommandExceptionType ERROR_LEVEL_NEGATIVE = new SimpleCommandExceptionType(Component.translatable("argument.entity.options.level.negative")); public static final SimpleCommandExceptionType ERROR_LIMIT_TOO_SMALL = new SimpleCommandExceptionType(Component.translatable("argument.entity.options.limit.toosmall")); public static final DynamicCommandExceptionType ERROR_SORT_UNKNOWN = new DynamicCommandExceptionType( p_308411_ -> Component.translatableEscape("argument.entity.options.sort.irreversible", p_308411_) ); public static final DynamicCommandExceptionType ERROR_GAME_MODE_INVALID = new DynamicCommandExceptionType( p_308419_ -> Component.translatableEscape("argument.entity.options.mode.invalid", p_308419_) ); public static final DynamicCommandExceptionType ERROR_ENTITY_TYPE_INVALID = new DynamicCommandExceptionType( p_308410_ -> Component.translatableEscape("argument.entity.options.type.invalid", p_308410_) ); private static void register(String p_121454_, EntitySelectorOptions.Modifier p_121455_, Predicate p_121456_, Component p_121457_) { OPTIONS.put(p_121454_, new EntitySelectorOptions.Option(p_121455_, p_121456_, p_121457_)); } public static void bootStrap() { if (OPTIONS.isEmpty()) { register("name", p_368973_ -> { int i = p_368973_.getReader().getCursor(); boolean flag = p_368973_.shouldInvertValue(); String s = p_368973_.getReader().readString(); if (p_368973_.hasNameNotEquals() && !flag) { p_368973_.getReader().setCursor(i); throw ERROR_INAPPLICABLE_OPTION.createWithContext(p_368973_.getReader(), "name"); } else { if (flag) { p_368973_.setHasNameNotEquals(true); } else { p_368973_.setHasNameEquals(true); } p_368973_.addPredicate(p_175209_ -> p_175209_.getName().getString().equals(s) != flag); } }, p_121423_ -> !p_121423_.hasNameEquals(), Component.translatable("argument.entity.options.name.description")); register( "distance", p_121421_ -> { int i = p_121421_.getReader().getCursor(); MinMaxBounds.Doubles minmaxbounds$doubles = MinMaxBounds.Doubles.fromReader(p_121421_.getReader()); if ((!minmaxbounds$doubles.min().isPresent() || !(minmaxbounds$doubles.min().get() < 0.0)) && (!minmaxbounds$doubles.max().isPresent() || !(minmaxbounds$doubles.max().get() < 0.0))) { p_121421_.setDistance(minmaxbounds$doubles); p_121421_.setWorldLimited(); } else { p_121421_.getReader().setCursor(i); throw ERROR_RANGE_NEGATIVE.createWithContext(p_121421_.getReader()); } }, p_121419_ -> p_121419_.getDistance().isAny(), Component.translatable("argument.entity.options.distance.description") ); register( "level", p_121417_ -> { int i = p_121417_.getReader().getCursor(); MinMaxBounds.Ints minmaxbounds$ints = MinMaxBounds.Ints.fromReader(p_121417_.getReader()); if ((!minmaxbounds$ints.min().isPresent() || minmaxbounds$ints.min().get() >= 0) && (!minmaxbounds$ints.max().isPresent() || minmaxbounds$ints.max().get() >= 0)) { p_121417_.setLevel(minmaxbounds$ints); p_121417_.setIncludesEntities(false); } else { p_121417_.getReader().setCursor(i); throw ERROR_LEVEL_NEGATIVE.createWithContext(p_121417_.getReader()); } }, p_121415_ -> p_121415_.getLevel().isAny(), Component.translatable("argument.entity.options.level.description") ); register("x", p_121413_ -> { p_121413_.setWorldLimited(); p_121413_.setX(p_121413_.getReader().readDouble()); }, p_121411_ -> p_121411_.getX() == null, Component.translatable("argument.entity.options.x.description")); register("y", p_121409_ -> { p_121409_.setWorldLimited(); p_121409_.setY(p_121409_.getReader().readDouble()); }, p_121407_ -> p_121407_.getY() == null, Component.translatable("argument.entity.options.y.description")); register("z", p_121405_ -> { p_121405_.setWorldLimited(); p_121405_.setZ(p_121405_.getReader().readDouble()); }, p_121403_ -> p_121403_.getZ() == null, Component.translatable("argument.entity.options.z.description")); register("dx", p_121401_ -> { p_121401_.setWorldLimited(); p_121401_.setDeltaX(p_121401_.getReader().readDouble()); }, p_121399_ -> p_121399_.getDeltaX() == null, Component.translatable("argument.entity.options.dx.description")); register("dy", p_121397_ -> { p_121397_.setWorldLimited(); p_121397_.setDeltaY(p_121397_.getReader().readDouble()); }, p_121395_ -> p_121395_.getDeltaY() == null, Component.translatable("argument.entity.options.dy.description")); register("dz", p_121562_ -> { p_121562_.setWorldLimited(); p_121562_.setDeltaZ(p_121562_.getReader().readDouble()); }, p_121560_ -> p_121560_.getDeltaZ() == null, Component.translatable("argument.entity.options.dz.description")); register( "x_rotation", p_121558_ -> p_121558_.setRotX(WrappedMinMaxBounds.fromReader(p_121558_.getReader(), true, Mth::wrapDegrees)), p_121556_ -> p_121556_.getRotX() == WrappedMinMaxBounds.ANY, Component.translatable("argument.entity.options.x_rotation.description") ); register( "y_rotation", p_121554_ -> p_121554_.setRotY(WrappedMinMaxBounds.fromReader(p_121554_.getReader(), true, Mth::wrapDegrees)), p_121552_ -> p_121552_.getRotY() == WrappedMinMaxBounds.ANY, Component.translatable("argument.entity.options.y_rotation.description") ); register("limit", p_121550_ -> { int i = p_121550_.getReader().getCursor(); int j = p_121550_.getReader().readInt(); if (j < 1) { p_121550_.getReader().setCursor(i); throw ERROR_LIMIT_TOO_SMALL.createWithContext(p_121550_.getReader()); } else { p_121550_.setMaxResults(j); p_121550_.setLimited(true); } }, p_121548_ -> !p_121548_.isCurrentEntity() && !p_121548_.isLimited(), Component.translatable("argument.entity.options.limit.description")); register( "sort", p_247983_ -> { int i = p_247983_.getReader().getCursor(); String s = p_247983_.getReader().readUnquotedString(); p_247983_.setSuggestions( (p_175153_, p_175154_) -> SharedSuggestionProvider.suggest(Arrays.asList("nearest", "furthest", "random", "arbitrary"), p_175153_) ); p_247983_.setOrder(switch (s) { case "nearest" -> EntitySelectorParser.ORDER_NEAREST; case "furthest" -> EntitySelectorParser.ORDER_FURTHEST; case "random" -> EntitySelectorParser.ORDER_RANDOM; case "arbitrary" -> EntitySelector.ORDER_ARBITRARY; default -> { p_247983_.getReader().setCursor(i); throw ERROR_SORT_UNKNOWN.createWithContext(p_247983_.getReader(), s); } }); p_247983_.setSorted(true); }, p_121544_ -> !p_121544_.isCurrentEntity() && !p_121544_.isSorted(), Component.translatable("argument.entity.options.sort.description") ); register("gamemode", p_121542_ -> { p_121542_.setSuggestions((p_175193_, p_175194_) -> { String s1 = p_175193_.getRemaining().toLowerCase(Locale.ROOT); boolean flag1 = !p_121542_.hasGamemodeNotEquals(); boolean flag2 = true; if (!s1.isEmpty()) { if (s1.charAt(0) == '!') { flag1 = false; s1 = s1.substring(1); } else { flag2 = false; } } for (GameType gametype1 : GameType.values()) { if (gametype1.getName().toLowerCase(Locale.ROOT).startsWith(s1)) { if (flag2) { p_175193_.suggest("!" + gametype1.getName()); } if (flag1) { p_175193_.suggest(gametype1.getName()); } } } return p_175193_.buildFuture(); }); int i = p_121542_.getReader().getCursor(); boolean flag = p_121542_.shouldInvertValue(); if (p_121542_.hasGamemodeNotEquals() && !flag) { p_121542_.getReader().setCursor(i); throw ERROR_INAPPLICABLE_OPTION.createWithContext(p_121542_.getReader(), "gamemode"); } else { String s = p_121542_.getReader().readUnquotedString(); GameType gametype = GameType.byName(s, null); if (gametype == null) { p_121542_.getReader().setCursor(i); throw ERROR_GAME_MODE_INVALID.createWithContext(p_121542_.getReader(), s); } else { p_121542_.setIncludesEntities(false); p_121542_.addPredicate(p_175190_ -> { if (p_175190_ instanceof ServerPlayer serverplayer) { GameType gametype1 = serverplayer.gameMode(); return gametype1 == gametype ^ flag; } else { return false; } }); if (flag) { p_121542_.setHasGamemodeNotEquals(true); } else { p_121542_.setHasGamemodeEquals(true); } } } }, p_121540_ -> !p_121540_.hasGamemodeEquals(), Component.translatable("argument.entity.options.gamemode.description")); register("team", p_121538_ -> { boolean flag = p_121538_.shouldInvertValue(); String s = p_121538_.getReader().readUnquotedString(); p_121538_.addPredicate(p_389651_ -> { Team team = p_389651_.getTeam(); String s1 = team == null ? "" : team.getName(); return s1.equals(s) != flag; }); if (flag) { p_121538_.setHasTeamNotEquals(true); } else { p_121538_.setHasTeamEquals(true); } }, p_121536_ -> !p_121536_.hasTeamEquals(), Component.translatable("argument.entity.options.team.description")); register( "type", p_121534_ -> { p_121534_.setSuggestions( (p_358070_, p_358071_) -> { SharedSuggestionProvider.suggestResource(BuiltInRegistries.ENTITY_TYPE.keySet(), p_358070_, String.valueOf('!')); SharedSuggestionProvider.suggestResource( BuiltInRegistries.ENTITY_TYPE.getTags().map(p_358072_ -> p_358072_.key().location()), p_358070_, "!#" ); if (!p_121534_.isTypeLimitedInversely()) { SharedSuggestionProvider.suggestResource(BuiltInRegistries.ENTITY_TYPE.keySet(), p_358070_); SharedSuggestionProvider.suggestResource( BuiltInRegistries.ENTITY_TYPE.getTags().map(p_358068_ -> p_358068_.key().location()), p_358070_, String.valueOf('#') ); } return p_358070_.buildFuture(); } ); int i = p_121534_.getReader().getCursor(); boolean flag = p_121534_.shouldInvertValue(); if (p_121534_.isTypeLimitedInversely() && !flag) { p_121534_.getReader().setCursor(i); throw ERROR_INAPPLICABLE_OPTION.createWithContext(p_121534_.getReader(), "type"); } else { if (flag) { p_121534_.setTypeLimitedInversely(); } if (p_121534_.isTag()) { TagKey> tagkey = TagKey.create(Registries.ENTITY_TYPE, ResourceLocation.read(p_121534_.getReader())); p_121534_.addPredicate(p_205691_ -> p_205691_.getType().is(tagkey) != flag); } else { ResourceLocation resourcelocation = ResourceLocation.read(p_121534_.getReader()); EntityType entitytype = BuiltInRegistries.ENTITY_TYPE.getOptional(resourcelocation).orElseThrow(() -> { p_121534_.getReader().setCursor(i); return ERROR_ENTITY_TYPE_INVALID.createWithContext(p_121534_.getReader(), resourcelocation.toString()); }); if (Objects.equals(EntityType.PLAYER, entitytype) && !flag) { p_121534_.setIncludesEntities(false); } p_121534_.addPredicate(p_175151_ -> Objects.equals(entitytype, p_175151_.getType()) != flag); if (!flag) { p_121534_.limitToType(entitytype); } } } }, p_121532_ -> !p_121532_.isTypeLimited(), Component.translatable("argument.entity.options.type.description") ); register("tag", p_121530_ -> { boolean flag = p_121530_.shouldInvertValue(); String s = p_121530_.getReader().readUnquotedString(); p_121530_.addPredicate(p_175166_ -> "".equals(s) ? p_175166_.getTags().isEmpty() != flag : p_175166_.getTags().contains(s) != flag); }, p_121528_ -> true, Component.translatable("argument.entity.options.tag.description")); register("nbt", p_389652_ -> { boolean flag = p_389652_.shouldInvertValue(); CompoundTag compoundtag = TagParser.parseCompoundAsArgument(p_389652_.getReader()); p_389652_.addPredicate(p_175176_ -> { CompoundTag compoundtag1 = p_175176_.saveWithoutId(new CompoundTag()); if (p_175176_ instanceof ServerPlayer serverplayer) { ItemStack itemstack = serverplayer.getInventory().getSelectedItem(); if (!itemstack.isEmpty()) { compoundtag1.put("SelectedItem", itemstack.save(serverplayer.registryAccess())); } } return NbtUtils.compareNbt(compoundtag, compoundtag1, true) != flag; }); }, p_121524_ -> true, Component.translatable("argument.entity.options.nbt.description")); register("scores", p_121522_ -> { StringReader stringreader = p_121522_.getReader(); Map map = Maps.newHashMap(); stringreader.expect('{'); stringreader.skipWhitespace(); while (stringreader.canRead() && stringreader.peek() != '}') { stringreader.skipWhitespace(); String s = stringreader.readUnquotedString(); stringreader.skipWhitespace(); stringreader.expect('='); stringreader.skipWhitespace(); MinMaxBounds.Ints minmaxbounds$ints = MinMaxBounds.Ints.fromReader(stringreader); map.put(s, minmaxbounds$ints); stringreader.skipWhitespace(); if (stringreader.canRead() && stringreader.peek() == ',') { stringreader.skip(); } } stringreader.expect('}'); if (!map.isEmpty()) { p_121522_.addPredicate(p_308418_ -> { Scoreboard scoreboard = p_308418_.getServer().getScoreboard(); for (Entry entry : map.entrySet()) { Objective objective = scoreboard.getObjective(entry.getKey()); if (objective == null) { return false; } ReadOnlyScoreInfo readonlyscoreinfo = scoreboard.getPlayerScoreInfo(p_308418_, objective); if (readonlyscoreinfo == null) { return false; } if (!entry.getValue().matches(readonlyscoreinfo.value())) { return false; } } return true; }); } p_121522_.setHasScores(true); }, p_121518_ -> !p_121518_.hasScores(), Component.translatable("argument.entity.options.scores.description")); register("advancements", p_121514_ -> { StringReader stringreader = p_121514_.getReader(); Map> map = Maps.newHashMap(); stringreader.expect('{'); stringreader.skipWhitespace(); while (stringreader.canRead() && stringreader.peek() != '}') { stringreader.skipWhitespace(); ResourceLocation resourcelocation = ResourceLocation.read(stringreader); stringreader.skipWhitespace(); stringreader.expect('='); stringreader.skipWhitespace(); if (stringreader.canRead() && stringreader.peek() == '{') { Map> map1 = Maps.newHashMap(); stringreader.skipWhitespace(); stringreader.expect('{'); stringreader.skipWhitespace(); while (stringreader.canRead() && stringreader.peek() != '}') { stringreader.skipWhitespace(); String s = stringreader.readUnquotedString(); stringreader.skipWhitespace(); stringreader.expect('='); stringreader.skipWhitespace(); boolean flag1 = stringreader.readBoolean(); map1.put(s, p_175186_ -> p_175186_.isDone() == flag1); stringreader.skipWhitespace(); if (stringreader.canRead() && stringreader.peek() == ',') { stringreader.skip(); } } stringreader.skipWhitespace(); stringreader.expect('}'); stringreader.skipWhitespace(); map.put(resourcelocation, p_175169_ -> { for (Entry> entry : map1.entrySet()) { CriterionProgress criterionprogress = p_175169_.getCriterion(entry.getKey()); if (criterionprogress == null || !entry.getValue().test(criterionprogress)) { return false; } } return true; }); } else { boolean flag = stringreader.readBoolean(); map.put(resourcelocation, p_175183_ -> p_175183_.isDone() == flag); } stringreader.skipWhitespace(); if (stringreader.canRead() && stringreader.peek() == ',') { stringreader.skip(); } } stringreader.expect('}'); if (!map.isEmpty()) { p_121514_.addPredicate(p_358074_ -> { if (!(p_358074_ instanceof ServerPlayer serverplayer)) { return false; } else { PlayerAdvancements $$4 = serverplayer.getAdvancements(); ServerAdvancementManager $$5x = serverplayer.getServer().getAdvancements(); for (Entry> entry : map.entrySet()) { AdvancementHolder advancementholder = $$5x.get(entry.getKey()); if (advancementholder == null || !entry.getValue().test($$4.getOrStartProgress(advancementholder))) { return false; } } return true; } }); p_121514_.setIncludesEntities(false); } p_121514_.setHasAdvancements(true); }, p_121506_ -> !p_121506_.hasAdvancements(), Component.translatable("argument.entity.options.advancements.description")); register( "predicate", p_325634_ -> { boolean flag = p_325634_.shouldInvertValue(); ResourceKey resourcekey = ResourceKey.create(Registries.PREDICATE, ResourceLocation.read(p_325634_.getReader())); p_325634_.addPredicate( p_358077_ -> { if (!(p_358077_.level() instanceof ServerLevel)) { return false; } else { ServerLevel serverlevel = (ServerLevel)p_358077_.level(); Optional optional = serverlevel.getServer() .reloadableRegistries() .lookup() .get(resourcekey) .map(Holder::value); if (optional.isEmpty()) { return false; } else { LootParams lootparams = new LootParams.Builder(serverlevel) .withParameter(LootContextParams.THIS_ENTITY, p_358077_) .withParameter(LootContextParams.ORIGIN, p_358077_.position()) .create(LootContextParamSets.SELECTOR); LootContext lootcontext = new LootContext.Builder(lootparams).create(Optional.empty()); lootcontext.pushVisitedElement(LootContext.createVisitedEntry(optional.get())); return flag ^ optional.get().test(lootcontext); } } } ); }, p_121435_ -> true, Component.translatable("argument.entity.options.predicate.description") ); } } public static EntitySelectorOptions.Modifier get(EntitySelectorParser p_121448_, String p_121449_, int p_121450_) throws CommandSyntaxException { EntitySelectorOptions.Option entityselectoroptions$option = OPTIONS.get(p_121449_); if (entityselectoroptions$option != null) { if (entityselectoroptions$option.canUse.test(p_121448_)) { return entityselectoroptions$option.modifier; } else { throw ERROR_INAPPLICABLE_OPTION.createWithContext(p_121448_.getReader(), p_121449_); } } else { p_121448_.getReader().setCursor(p_121450_); throw ERROR_UNKNOWN_OPTION.createWithContext(p_121448_.getReader(), p_121449_); } } public static void suggestNames(EntitySelectorParser p_121441_, SuggestionsBuilder p_121442_) { String s = p_121442_.getRemaining().toLowerCase(Locale.ROOT); for (Entry entry : OPTIONS.entrySet()) { if (entry.getValue().canUse.test(p_121441_) && entry.getKey().toLowerCase(Locale.ROOT).startsWith(s)) { p_121442_.suggest(entry.getKey() + "=", entry.getValue().description); } } } public interface Modifier { void handle(EntitySelectorParser p_121564_) throws CommandSyntaxException; } record Option(EntitySelectorOptions.Modifier modifier, Predicate canUse, Component description) { } }