Code/net/minecraft/commands/arguments/selector/options/EntitySelectorOptions.java

541 lines
29 KiB
Java

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<String, EntitySelectorOptions.Option> 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<EntitySelectorParser> 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<EntityType<?>> 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<String, MinMaxBounds.Ints> 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<String, MinMaxBounds.Ints> 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<ResourceLocation, Predicate<AdvancementProgress>> 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<String, Predicate<CriterionProgress>> 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<String, Predicate<CriterionProgress>> 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<ResourceLocation, Predicate<AdvancementProgress>> 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<LootItemCondition> 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<LootItemCondition> 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<String, EntitySelectorOptions.Option> 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<EntitySelectorParser> canUse, Component description) {
}
}