package net.minecraft.server.commands; import com.google.common.base.Stopwatch; import com.mojang.brigadier.CommandDispatcher; import com.mojang.brigadier.context.CommandContext; import com.mojang.brigadier.exceptions.CommandSyntaxException; import com.mojang.brigadier.exceptions.DynamicCommandExceptionType; import com.mojang.datafixers.util.Pair; import com.mojang.logging.LogUtils; import java.time.Duration; import java.util.Optional; import net.minecraft.ChatFormatting; import net.minecraft.Util; import net.minecraft.commands.CommandBuildContext; import net.minecraft.commands.CommandSourceStack; import net.minecraft.commands.Commands; import net.minecraft.commands.arguments.ResourceOrTagArgument; import net.minecraft.commands.arguments.ResourceOrTagKeyArgument; import net.minecraft.core.BlockPos; import net.minecraft.core.Holder; import net.minecraft.core.HolderSet; import net.minecraft.core.Registry; import net.minecraft.core.registries.Registries; import net.minecraft.network.chat.ClickEvent; import net.minecraft.network.chat.Component; import net.minecraft.network.chat.ComponentUtils; import net.minecraft.network.chat.HoverEvent; import net.minecraft.network.chat.Style; import net.minecraft.resources.ResourceKey; import net.minecraft.server.level.ServerLevel; import net.minecraft.tags.TagKey; import net.minecraft.util.Mth; import net.minecraft.world.entity.ai.village.poi.PoiManager; import net.minecraft.world.entity.ai.village.poi.PoiType; import net.minecraft.world.level.biome.Biome; import net.minecraft.world.level.levelgen.structure.Structure; import org.slf4j.Logger; public class LocateCommand { private static final Logger LOGGER = LogUtils.getLogger(); private static final DynamicCommandExceptionType ERROR_STRUCTURE_NOT_FOUND = new DynamicCommandExceptionType( p_308765_ -> Component.translatableEscape("commands.locate.structure.not_found", p_308765_) ); private static final DynamicCommandExceptionType ERROR_STRUCTURE_INVALID = new DynamicCommandExceptionType( p_308764_ -> Component.translatableEscape("commands.locate.structure.invalid", p_308764_) ); private static final DynamicCommandExceptionType ERROR_BIOME_NOT_FOUND = new DynamicCommandExceptionType( p_308763_ -> Component.translatableEscape("commands.locate.biome.not_found", p_308763_) ); private static final DynamicCommandExceptionType ERROR_POI_NOT_FOUND = new DynamicCommandExceptionType( p_308766_ -> Component.translatableEscape("commands.locate.poi.not_found", p_308766_) ); private static final int MAX_STRUCTURE_SEARCH_RADIUS = 100; private static final int MAX_BIOME_SEARCH_RADIUS = 6400; private static final int BIOME_SAMPLE_RESOLUTION_HORIZONTAL = 32; private static final int BIOME_SAMPLE_RESOLUTION_VERTICAL = 64; private static final int POI_SEARCH_RADIUS = 256; public static void register(CommandDispatcher p_249870_, CommandBuildContext p_248936_) { p_249870_.register( Commands.literal("locate") .requires(p_214470_ -> p_214470_.hasPermission(2)) .then( Commands.literal("structure") .then( Commands.argument("structure", ResourceOrTagKeyArgument.resourceOrTagKey(Registries.STRUCTURE)) .executes( p_258233_ -> locateStructure( p_258233_.getSource(), ResourceOrTagKeyArgument.getResourceOrTagKey(p_258233_, "structure", Registries.STRUCTURE, ERROR_STRUCTURE_INVALID) ) ) ) ) .then( Commands.literal("biome") .then( Commands.argument("biome", ResourceOrTagArgument.resourceOrTag(p_248936_, Registries.BIOME)) .executes( p_258232_ -> locateBiome(p_258232_.getSource(), ResourceOrTagArgument.getResourceOrTag(p_258232_, "biome", Registries.BIOME)) ) ) ) .then( Commands.literal("poi") .then( Commands.argument("poi", ResourceOrTagArgument.resourceOrTag(p_248936_, Registries.POINT_OF_INTEREST_TYPE)) .executes( p_258234_ -> locatePoi(p_258234_.getSource(), ResourceOrTagArgument.getResourceOrTag(p_258234_, "poi", Registries.POINT_OF_INTEREST_TYPE)) ) ) ) ); } private static Optional> getHolders( ResourceOrTagKeyArgument.Result p_251212_, Registry p_249691_ ) { return p_251212_.unwrap() .map(p_358601_ -> p_249691_.get((ResourceKey)p_358601_).map(p_214491_ -> HolderSet.direct(p_214491_)), p_249691_::get); } private static int locateStructure(CommandSourceStack p_214472_, ResourceOrTagKeyArgument.Result p_249893_) throws CommandSyntaxException { Registry registry = p_214472_.getLevel().registryAccess().lookupOrThrow(Registries.STRUCTURE); HolderSet holderset = (HolderSet)getHolders(p_249893_, registry).orElseThrow(() -> ERROR_STRUCTURE_INVALID.create(p_249893_.asPrintable())); BlockPos blockpos = BlockPos.containing(p_214472_.getPosition()); ServerLevel serverlevel = p_214472_.getLevel(); Stopwatch stopwatch = Stopwatch.createStarted(Util.TICKER); Pair> pair = serverlevel.getChunkSource().getGenerator().findNearestMapStructure(serverlevel, holderset, blockpos, 100, false); stopwatch.stop(); if (pair == null) { throw ERROR_STRUCTURE_NOT_FOUND.create(p_249893_.asPrintable()); } else { return showLocateResult(p_214472_, p_249893_, blockpos, pair, "commands.locate.structure.success", false, stopwatch.elapsed()); } } private static int locateBiome(CommandSourceStack p_252062_, ResourceOrTagArgument.Result p_249756_) throws CommandSyntaxException { BlockPos blockpos = BlockPos.containing(p_252062_.getPosition()); Stopwatch stopwatch = Stopwatch.createStarted(Util.TICKER); Pair> pair = p_252062_.getLevel().findClosestBiome3d(p_249756_, blockpos, 6400, 32, 64); stopwatch.stop(); if (pair == null) { throw ERROR_BIOME_NOT_FOUND.create(p_249756_.asPrintable()); } else { return showLocateResult(p_252062_, p_249756_, blockpos, pair, "commands.locate.biome.success", true, stopwatch.elapsed()); } } private static int locatePoi(CommandSourceStack p_252013_, ResourceOrTagArgument.Result p_249480_) throws CommandSyntaxException { BlockPos blockpos = BlockPos.containing(p_252013_.getPosition()); ServerLevel serverlevel = p_252013_.getLevel(); Stopwatch stopwatch = Stopwatch.createStarted(Util.TICKER); Optional, BlockPos>> optional = serverlevel.getPoiManager().findClosestWithType(p_249480_, blockpos, 256, PoiManager.Occupancy.ANY); stopwatch.stop(); if (optional.isEmpty()) { throw ERROR_POI_NOT_FOUND.create(p_249480_.asPrintable()); } else { return showLocateResult(p_252013_, p_249480_, blockpos, optional.get().swap(), "commands.locate.poi.success", false, stopwatch.elapsed()); } } public static int showLocateResult( CommandSourceStack p_263098_, ResourceOrTagArgument.Result p_262956_, BlockPos p_262917_, Pair> p_263074_, String p_262937_, boolean p_263051_, Duration p_263028_ ) { String s = p_262956_.unwrap() .map(p_248147_ -> p_262956_.asPrintable(), p_326290_ -> p_262956_.asPrintable() + " (" + p_263074_.getSecond().getRegisteredName() + ")"); return showLocateResult(p_263098_, p_262917_, p_263074_, p_262937_, p_263051_, s, p_263028_); } public static int showLocateResult( CommandSourceStack p_263019_, ResourceOrTagKeyArgument.Result p_263031_, BlockPos p_262989_, Pair> p_262959_, String p_263045_, boolean p_262934_, Duration p_262960_ ) { String s = p_263031_.unwrap() .map(p_214498_ -> p_214498_.location().toString(), p_326287_ -> "#" + p_326287_.location() + " (" + p_262959_.getSecond().getRegisteredName() + ")"); return showLocateResult(p_263019_, p_262989_, p_262959_, p_263045_, p_262934_, s, p_262960_); } private static int showLocateResult( CommandSourceStack p_262983_, BlockPos p_263016_, Pair> p_262941_, String p_263083_, boolean p_263010_, String p_263048_, Duration p_263040_ ) { BlockPos blockpos = p_262941_.getFirst(); int i = p_263010_ ? Mth.floor(Mth.sqrt((float)p_263016_.distSqr(blockpos))) : Mth.floor(dist(p_263016_.getX(), p_263016_.getZ(), blockpos.getX(), blockpos.getZ())); String s = p_263010_ ? String.valueOf(blockpos.getY()) : "~"; Component component = ComponentUtils.wrapInSquareBrackets(Component.translatable("chat.coordinates", blockpos.getX(), s, blockpos.getZ())) .withStyle( p_214489_ -> p_214489_.withColor(ChatFormatting.GREEN) .withClickEvent(new ClickEvent(ClickEvent.Action.SUGGEST_COMMAND, "/tp @s " + blockpos.getX() + " " + s + " " + blockpos.getZ())) .withHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, Component.translatable("chat.coordinates.tooltip"))) ); p_262983_.sendSuccess(() -> Component.translatable(p_263083_, p_263048_, component, i), false); LOGGER.info("Locating element " + p_263048_ + " took " + p_263040_.toMillis() + " ms"); return i; } private static float dist(int p_137854_, int p_137855_, int p_137856_, int p_137857_) { int i = p_137856_ - p_137854_; int j = p_137857_ - p_137855_; return Mth.sqrt((float)(i * i + j * j)); } }