package net.minecraft.commands.arguments; import com.google.common.collect.Maps; import com.mojang.brigadier.StringReader; import com.mojang.brigadier.arguments.ArgumentType; import com.mojang.brigadier.context.CommandContext; import com.mojang.brigadier.exceptions.CommandSyntaxException; import com.mojang.brigadier.exceptions.DynamicCommandExceptionType; import com.mojang.brigadier.suggestion.Suggestions; import com.mojang.brigadier.suggestion.SuggestionsBuilder; import java.util.Arrays; import java.util.Collection; import java.util.Map; import java.util.concurrent.CompletableFuture; import java.util.function.BiFunction; import net.minecraft.Util; import net.minecraft.commands.CommandSourceStack; import net.minecraft.commands.SharedSuggestionProvider; import net.minecraft.network.chat.Component; import net.minecraft.world.entity.Entity; import net.minecraft.world.phys.Vec3; import org.jetbrains.annotations.Nullable; public class EntityAnchorArgument implements ArgumentType { private static final Collection EXAMPLES = Arrays.asList("eyes", "feet"); private static final DynamicCommandExceptionType ERROR_INVALID = new DynamicCommandExceptionType( object -> Component.translatableEscape("argument.anchor.invalid", object) ); public static EntityAnchorArgument.Anchor getAnchor(CommandContext context, String name) { return context.getArgument(name, EntityAnchorArgument.Anchor.class); } public static EntityAnchorArgument anchor() { return new EntityAnchorArgument(); } public EntityAnchorArgument.Anchor parse(StringReader reader) throws CommandSyntaxException { int i = reader.getCursor(); String string = reader.readUnquotedString(); EntityAnchorArgument.Anchor anchor = EntityAnchorArgument.Anchor.getByName(string); if (anchor == null) { reader.setCursor(i); throw ERROR_INVALID.createWithContext(reader, string); } else { return anchor; } } @Override public CompletableFuture listSuggestions(CommandContext commandContext, SuggestionsBuilder suggestionsBuilder) { return SharedSuggestionProvider.suggest(EntityAnchorArgument.Anchor.BY_NAME.keySet(), suggestionsBuilder); } @Override public Collection getExamples() { return EXAMPLES; } public static enum Anchor { FEET("feet", (vec3, entity) -> vec3), EYES("eyes", (vec3, entity) -> new Vec3(vec3.x, vec3.y + entity.getEyeHeight(), vec3.z)); static final Map BY_NAME = Util.make(Maps.newHashMap(), hashMap -> { for (EntityAnchorArgument.Anchor anchor : values()) { hashMap.put(anchor.name, anchor); } }); private final String name; private final BiFunction transform; private Anchor(final String name, final BiFunction transform) { this.name = name; this.transform = transform; } @Nullable public static EntityAnchorArgument.Anchor getByName(String name) { return (EntityAnchorArgument.Anchor)BY_NAME.get(name); } /** * Gets the coordinate based on the given entity's position. */ public Vec3 apply(Entity entity) { return (Vec3)this.transform.apply(entity.position(), entity); } /** * Gets the coordinate based on the given command source's position. If the source is not an entity, no offsetting occurs. */ public Vec3 apply(CommandSourceStack source) { Entity entity = source.getEntity(); return entity == null ? source.getPosition() : (Vec3)this.transform.apply(source.getPosition(), entity); } } }