package net.minecraft.server.commands; import com.mojang.brigadier.CommandDispatcher; import com.mojang.brigadier.arguments.FloatArgumentType; import com.mojang.brigadier.arguments.IntegerArgumentType; import com.mojang.brigadier.exceptions.CommandSyntaxException; import com.mojang.brigadier.exceptions.DynamicCommandExceptionType; import com.mojang.brigadier.exceptions.SimpleCommandExceptionType; import com.mojang.brigadier.suggestion.SuggestionProvider; import java.util.Optional; import net.minecraft.ResourceLocationException; import net.minecraft.commands.CommandSourceStack; import net.minecraft.commands.Commands; import net.minecraft.commands.SharedSuggestionProvider; import net.minecraft.commands.arguments.ResourceKeyArgument; import net.minecraft.commands.arguments.ResourceLocationArgument; import net.minecraft.commands.arguments.TemplateMirrorArgument; import net.minecraft.commands.arguments.TemplateRotationArgument; import net.minecraft.commands.arguments.coordinates.BlockPosArgument; import net.minecraft.core.BlockPos; import net.minecraft.core.Holder; import net.minecraft.core.SectionPos; import net.minecraft.core.Holder.Reference; import net.minecraft.core.registries.Registries; import net.minecraft.network.chat.Component; import net.minecraft.resources.ResourceLocation; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.level.ChunkPos; import net.minecraft.world.level.block.Mirror; import net.minecraft.world.level.block.Rotation; import net.minecraft.world.level.block.entity.StructureBlockEntity; import net.minecraft.world.level.chunk.ChunkGenerator; import net.minecraft.world.level.levelgen.feature.ConfiguredFeature; import net.minecraft.world.level.levelgen.structure.BoundingBox; import net.minecraft.world.level.levelgen.structure.Structure; import net.minecraft.world.level.levelgen.structure.StructureStart; import net.minecraft.world.level.levelgen.structure.pools.JigsawPlacement; import net.minecraft.world.level.levelgen.structure.pools.StructureTemplatePool; import net.minecraft.world.level.levelgen.structure.templatesystem.BlockRotProcessor; import net.minecraft.world.level.levelgen.structure.templatesystem.StructurePlaceSettings; import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplate; import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplateManager; public class PlaceCommand { private static final SimpleCommandExceptionType ERROR_FEATURE_FAILED = new SimpleCommandExceptionType(Component.translatable("commands.place.feature.failed")); private static final SimpleCommandExceptionType ERROR_JIGSAW_FAILED = new SimpleCommandExceptionType(Component.translatable("commands.place.jigsaw.failed")); private static final SimpleCommandExceptionType ERROR_STRUCTURE_FAILED = new SimpleCommandExceptionType( Component.translatable("commands.place.structure.failed") ); private static final DynamicCommandExceptionType ERROR_TEMPLATE_INVALID = new DynamicCommandExceptionType( object -> Component.translatableEscape("commands.place.template.invalid", object) ); private static final SimpleCommandExceptionType ERROR_TEMPLATE_FAILED = new SimpleCommandExceptionType( Component.translatable("commands.place.template.failed") ); private static final SuggestionProvider SUGGEST_TEMPLATES = (commandContext, suggestionsBuilder) -> { StructureTemplateManager structureTemplateManager = commandContext.getSource().getLevel().getStructureManager(); return SharedSuggestionProvider.suggestResource(structureTemplateManager.listTemplates(), suggestionsBuilder); }; public static void register(CommandDispatcher dispatcher) { dispatcher.register( Commands.literal("place") .requires(commandSourceStack -> commandSourceStack.hasPermission(2)) .then( Commands.literal("feature") .then( Commands.argument("feature", ResourceKeyArgument.key(Registries.CONFIGURED_FEATURE)) .executes( commandContext -> placeFeature( commandContext.getSource(), ResourceKeyArgument.getConfiguredFeature(commandContext, "feature"), BlockPos.containing(commandContext.getSource().getPosition()) ) ) .then( Commands.argument("pos", BlockPosArgument.blockPos()) .executes( commandContext -> placeFeature( commandContext.getSource(), ResourceKeyArgument.getConfiguredFeature(commandContext, "feature"), BlockPosArgument.getLoadedBlockPos(commandContext, "pos") ) ) ) ) ) .then( Commands.literal("jigsaw") .then( Commands.argument("pool", ResourceKeyArgument.key(Registries.TEMPLATE_POOL)) .then( Commands.argument("target", ResourceLocationArgument.id()) .then( Commands.argument("max_depth", IntegerArgumentType.integer(1, 20)) .executes( commandContext -> placeJigsaw( commandContext.getSource(), ResourceKeyArgument.getStructureTemplatePool(commandContext, "pool"), ResourceLocationArgument.getId(commandContext, "target"), IntegerArgumentType.getInteger(commandContext, "max_depth"), BlockPos.containing(commandContext.getSource().getPosition()) ) ) .then( Commands.argument("position", BlockPosArgument.blockPos()) .executes( commandContext -> placeJigsaw( commandContext.getSource(), ResourceKeyArgument.getStructureTemplatePool(commandContext, "pool"), ResourceLocationArgument.getId(commandContext, "target"), IntegerArgumentType.getInteger(commandContext, "max_depth"), BlockPosArgument.getLoadedBlockPos(commandContext, "position") ) ) ) ) ) ) ) .then( Commands.literal("structure") .then( Commands.argument("structure", ResourceKeyArgument.key(Registries.STRUCTURE)) .executes( commandContext -> placeStructure( commandContext.getSource(), ResourceKeyArgument.getStructure(commandContext, "structure"), BlockPos.containing(commandContext.getSource().getPosition()) ) ) .then( Commands.argument("pos", BlockPosArgument.blockPos()) .executes( commandContext -> placeStructure( commandContext.getSource(), ResourceKeyArgument.getStructure(commandContext, "structure"), BlockPosArgument.getLoadedBlockPos(commandContext, "pos") ) ) ) ) ) .then( Commands.literal("template") .then( Commands.argument("template", ResourceLocationArgument.id()) .suggests(SUGGEST_TEMPLATES) .executes( commandContext -> placeTemplate( commandContext.getSource(), ResourceLocationArgument.getId(commandContext, "template"), BlockPos.containing(commandContext.getSource().getPosition()), Rotation.NONE, Mirror.NONE, 1.0F, 0, false ) ) .then( Commands.argument("pos", BlockPosArgument.blockPos()) .executes( commandContext -> placeTemplate( commandContext.getSource(), ResourceLocationArgument.getId(commandContext, "template"), BlockPosArgument.getLoadedBlockPos(commandContext, "pos"), Rotation.NONE, Mirror.NONE, 1.0F, 0, false ) ) .then( Commands.argument("rotation", TemplateRotationArgument.templateRotation()) .executes( commandContext -> placeTemplate( commandContext.getSource(), ResourceLocationArgument.getId(commandContext, "template"), BlockPosArgument.getLoadedBlockPos(commandContext, "pos"), TemplateRotationArgument.getRotation(commandContext, "rotation"), Mirror.NONE, 1.0F, 0, false ) ) .then( Commands.argument("mirror", TemplateMirrorArgument.templateMirror()) .executes( commandContext -> placeTemplate( commandContext.getSource(), ResourceLocationArgument.getId(commandContext, "template"), BlockPosArgument.getLoadedBlockPos(commandContext, "pos"), TemplateRotationArgument.getRotation(commandContext, "rotation"), TemplateMirrorArgument.getMirror(commandContext, "mirror"), 1.0F, 0, false ) ) .then( Commands.argument("integrity", FloatArgumentType.floatArg(0.0F, 1.0F)) .executes( commandContext -> placeTemplate( commandContext.getSource(), ResourceLocationArgument.getId(commandContext, "template"), BlockPosArgument.getLoadedBlockPos(commandContext, "pos"), TemplateRotationArgument.getRotation(commandContext, "rotation"), TemplateMirrorArgument.getMirror(commandContext, "mirror"), FloatArgumentType.getFloat(commandContext, "integrity"), 0, false ) ) .then( Commands.argument("seed", IntegerArgumentType.integer()) .executes( commandContext -> placeTemplate( commandContext.getSource(), ResourceLocationArgument.getId(commandContext, "template"), BlockPosArgument.getLoadedBlockPos(commandContext, "pos"), TemplateRotationArgument.getRotation(commandContext, "rotation"), TemplateMirrorArgument.getMirror(commandContext, "mirror"), FloatArgumentType.getFloat(commandContext, "integrity"), IntegerArgumentType.getInteger(commandContext, "seed"), false ) ) .then( Commands.literal("strict") .executes( commandContext -> placeTemplate( commandContext.getSource(), ResourceLocationArgument.getId(commandContext, "template"), BlockPosArgument.getLoadedBlockPos(commandContext, "pos"), TemplateRotationArgument.getRotation(commandContext, "rotation"), TemplateMirrorArgument.getMirror(commandContext, "mirror"), FloatArgumentType.getFloat(commandContext, "integrity"), IntegerArgumentType.getInteger(commandContext, "seed"), true ) ) ) ) ) ) ) ) ) ) ); } public static int placeFeature(CommandSourceStack source, Reference> feature, BlockPos pos) throws CommandSyntaxException { ServerLevel serverLevel = source.getLevel(); ConfiguredFeature configuredFeature = feature.value(); ChunkPos chunkPos = new ChunkPos(pos); checkLoaded(serverLevel, new ChunkPos(chunkPos.x - 1, chunkPos.z - 1), new ChunkPos(chunkPos.x + 1, chunkPos.z + 1)); if (!configuredFeature.place(serverLevel, serverLevel.getChunkSource().getGenerator(), serverLevel.getRandom(), pos)) { throw ERROR_FEATURE_FAILED.create(); } else { String string = feature.key().location().toString(); source.sendSuccess(() -> Component.translatable("commands.place.feature.success", string, pos.getX(), pos.getY(), pos.getZ()), true); return 1; } } public static int placeJigsaw(CommandSourceStack source, Holder templatePool, ResourceLocation target, int maxDepth, BlockPos pos) throws CommandSyntaxException { ServerLevel serverLevel = source.getLevel(); ChunkPos chunkPos = new ChunkPos(pos); checkLoaded(serverLevel, chunkPos, chunkPos); if (!JigsawPlacement.generateJigsaw(serverLevel, templatePool, target, maxDepth, pos, false)) { throw ERROR_JIGSAW_FAILED.create(); } else { source.sendSuccess(() -> Component.translatable("commands.place.jigsaw.success", pos.getX(), pos.getY(), pos.getZ()), true); return 1; } } public static int placeStructure(CommandSourceStack source, Reference structure, BlockPos pos) throws CommandSyntaxException { ServerLevel serverLevel = source.getLevel(); Structure structure2 = structure.value(); ChunkGenerator chunkGenerator = serverLevel.getChunkSource().getGenerator(); StructureStart structureStart = structure2.generate( structure, serverLevel.dimension(), source.registryAccess(), chunkGenerator, chunkGenerator.getBiomeSource(), serverLevel.getChunkSource().randomState(), serverLevel.getStructureManager(), serverLevel.getSeed(), new ChunkPos(pos), 0, serverLevel, holder -> true ); if (!structureStart.isValid()) { throw ERROR_STRUCTURE_FAILED.create(); } else { BoundingBox boundingBox = structureStart.getBoundingBox(); ChunkPos chunkPos = new ChunkPos(SectionPos.blockToSectionCoord(boundingBox.minX()), SectionPos.blockToSectionCoord(boundingBox.minZ())); ChunkPos chunkPos2 = new ChunkPos(SectionPos.blockToSectionCoord(boundingBox.maxX()), SectionPos.blockToSectionCoord(boundingBox.maxZ())); checkLoaded(serverLevel, chunkPos, chunkPos2); ChunkPos.rangeClosed(chunkPos, chunkPos2) .forEach( chunkPosx -> structureStart.placeInChunk( serverLevel, serverLevel.structureManager(), chunkGenerator, serverLevel.getRandom(), new BoundingBox( chunkPosx.getMinBlockX(), serverLevel.getMinY(), chunkPosx.getMinBlockZ(), chunkPosx.getMaxBlockX(), serverLevel.getMaxY() + 1, chunkPosx.getMaxBlockZ() ), chunkPosx ) ); String string = structure.key().location().toString(); source.sendSuccess(() -> Component.translatable("commands.place.structure.success", string, pos.getX(), pos.getY(), pos.getZ()), true); return 1; } } public static int placeTemplate( CommandSourceStack source, ResourceLocation template, BlockPos pos, Rotation rotation, Mirror mirror, float integrity, int seed, boolean strict ) throws CommandSyntaxException { ServerLevel serverLevel = source.getLevel(); StructureTemplateManager structureTemplateManager = serverLevel.getStructureManager(); Optional optional; try { optional = structureTemplateManager.get(template); } catch (ResourceLocationException var14) { throw ERROR_TEMPLATE_INVALID.create(template); } if (optional.isEmpty()) { throw ERROR_TEMPLATE_INVALID.create(template); } else { StructureTemplate structureTemplate = (StructureTemplate)optional.get(); checkLoaded(serverLevel, new ChunkPos(pos), new ChunkPos(pos.offset(structureTemplate.getSize()))); StructurePlaceSettings structurePlaceSettings = new StructurePlaceSettings().setMirror(mirror).setRotation(rotation).setKnownShape(strict); if (integrity < 1.0F) { structurePlaceSettings.clearProcessors().addProcessor(new BlockRotProcessor(integrity)).setRandom(StructureBlockEntity.createRandom(seed)); } boolean bl = structureTemplate.placeInWorld(serverLevel, pos, pos, structurePlaceSettings, StructureBlockEntity.createRandom(seed), 2 | (strict ? 816 : 0)); if (!bl) { throw ERROR_TEMPLATE_FAILED.create(); } else { source.sendSuccess( () -> Component.translatable("commands.place.template.success", Component.translationArg(template), pos.getX(), pos.getY(), pos.getZ()), true ); return 1; } } } private static void checkLoaded(ServerLevel level, ChunkPos start, ChunkPos end) throws CommandSyntaxException { if (ChunkPos.rangeClosed(start, end).filter(chunkPos -> !level.isLoaded(chunkPos.getWorldPosition())).findAny().isPresent()) { throw BlockPosArgument.ERROR_NOT_LOADED.create(); } } }