366 lines
16 KiB
Java
366 lines
16 KiB
Java
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<CommandSourceStack> SUGGEST_TEMPLATES = (commandContext, suggestionsBuilder) -> {
|
|
StructureTemplateManager structureTemplateManager = commandContext.getSource().getLevel().getStructureManager();
|
|
return SharedSuggestionProvider.suggestResource(structureTemplateManager.listTemplates(), suggestionsBuilder);
|
|
};
|
|
|
|
public static void register(CommandDispatcher<CommandSourceStack> 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<ConfiguredFeature<?, ?>> 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<StructureTemplatePool> 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> 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<StructureTemplate> 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();
|
|
}
|
|
}
|
|
}
|