minecraft-src/net/minecraft/server/commands/FillCommand.java
2025-07-04 01:41:11 +03:00

208 lines
8.3 KiB
Java

package net.minecraft.server.commands;
import com.google.common.collect.Lists;
import com.mojang.brigadier.CommandDispatcher;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
import com.mojang.brigadier.exceptions.Dynamic2CommandExceptionType;
import com.mojang.brigadier.exceptions.SimpleCommandExceptionType;
import java.util.Collections;
import java.util.List;
import java.util.function.Predicate;
import net.minecraft.commands.CommandBuildContext;
import net.minecraft.commands.CommandSourceStack;
import net.minecraft.commands.Commands;
import net.minecraft.commands.arguments.blocks.BlockInput;
import net.minecraft.commands.arguments.blocks.BlockPredicateArgument;
import net.minecraft.commands.arguments.blocks.BlockStateArgument;
import net.minecraft.commands.arguments.coordinates.BlockPosArgument;
import net.minecraft.core.BlockPos;
import net.minecraft.network.chat.Component;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.Clearable;
import net.minecraft.world.level.GameRules;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.state.pattern.BlockInWorld;
import net.minecraft.world.level.levelgen.structure.BoundingBox;
import org.jetbrains.annotations.Nullable;
public class FillCommand {
private static final Dynamic2CommandExceptionType ERROR_AREA_TOO_LARGE = new Dynamic2CommandExceptionType(
(object, object2) -> Component.translatableEscape("commands.fill.toobig", object, object2)
);
static final BlockInput HOLLOW_CORE = new BlockInput(Blocks.AIR.defaultBlockState(), Collections.emptySet(), null);
private static final SimpleCommandExceptionType ERROR_FAILED = new SimpleCommandExceptionType(Component.translatable("commands.fill.failed"));
public static void register(CommandDispatcher<CommandSourceStack> dispatcher, CommandBuildContext context) {
dispatcher.register(
Commands.literal("fill")
.requires(commandSourceStack -> commandSourceStack.hasPermission(2))
.then(
Commands.argument("from", BlockPosArgument.blockPos())
.then(
Commands.argument("to", BlockPosArgument.blockPos())
.then(
Commands.argument("block", BlockStateArgument.block(context))
.executes(
commandContext -> fillBlocks(
commandContext.getSource(),
BoundingBox.fromCorners(BlockPosArgument.getLoadedBlockPos(commandContext, "from"), BlockPosArgument.getLoadedBlockPos(commandContext, "to")),
BlockStateArgument.getBlock(commandContext, "block"),
FillCommand.Mode.REPLACE,
null
)
)
.then(
Commands.literal("replace")
.executes(
commandContext -> fillBlocks(
commandContext.getSource(),
BoundingBox.fromCorners(BlockPosArgument.getLoadedBlockPos(commandContext, "from"), BlockPosArgument.getLoadedBlockPos(commandContext, "to")),
BlockStateArgument.getBlock(commandContext, "block"),
FillCommand.Mode.REPLACE,
null
)
)
.then(
Commands.argument("filter", BlockPredicateArgument.blockPredicate(context))
.executes(
commandContext -> fillBlocks(
commandContext.getSource(),
BoundingBox.fromCorners(BlockPosArgument.getLoadedBlockPos(commandContext, "from"), BlockPosArgument.getLoadedBlockPos(commandContext, "to")),
BlockStateArgument.getBlock(commandContext, "block"),
FillCommand.Mode.REPLACE,
BlockPredicateArgument.getBlockPredicate(commandContext, "filter")
)
)
)
)
.then(
Commands.literal("keep")
.executes(
commandContext -> fillBlocks(
commandContext.getSource(),
BoundingBox.fromCorners(BlockPosArgument.getLoadedBlockPos(commandContext, "from"), BlockPosArgument.getLoadedBlockPos(commandContext, "to")),
BlockStateArgument.getBlock(commandContext, "block"),
FillCommand.Mode.REPLACE,
blockInWorld -> blockInWorld.getLevel().isEmptyBlock(blockInWorld.getPos())
)
)
)
.then(
Commands.literal("outline")
.executes(
commandContext -> fillBlocks(
commandContext.getSource(),
BoundingBox.fromCorners(BlockPosArgument.getLoadedBlockPos(commandContext, "from"), BlockPosArgument.getLoadedBlockPos(commandContext, "to")),
BlockStateArgument.getBlock(commandContext, "block"),
FillCommand.Mode.OUTLINE,
null
)
)
)
.then(
Commands.literal("hollow")
.executes(
commandContext -> fillBlocks(
commandContext.getSource(),
BoundingBox.fromCorners(BlockPosArgument.getLoadedBlockPos(commandContext, "from"), BlockPosArgument.getLoadedBlockPos(commandContext, "to")),
BlockStateArgument.getBlock(commandContext, "block"),
FillCommand.Mode.HOLLOW,
null
)
)
)
.then(
Commands.literal("destroy")
.executes(
commandContext -> fillBlocks(
commandContext.getSource(),
BoundingBox.fromCorners(BlockPosArgument.getLoadedBlockPos(commandContext, "from"), BlockPosArgument.getLoadedBlockPos(commandContext, "to")),
BlockStateArgument.getBlock(commandContext, "block"),
FillCommand.Mode.DESTROY,
null
)
)
)
)
)
)
);
}
private static int fillBlocks(
CommandSourceStack source, BoundingBox area, BlockInput newBlock, FillCommand.Mode mode, @Nullable Predicate<BlockInWorld> replacingPredicate
) throws CommandSyntaxException {
int i = area.getXSpan() * area.getYSpan() * area.getZSpan();
int j = source.getLevel().getGameRules().getInt(GameRules.RULE_COMMAND_MODIFICATION_BLOCK_LIMIT);
if (i > j) {
throw ERROR_AREA_TOO_LARGE.create(j, i);
} else {
List<BlockPos> list = Lists.<BlockPos>newArrayList();
ServerLevel serverLevel = source.getLevel();
int k = 0;
for (BlockPos blockPos : BlockPos.betweenClosed(area.minX(), area.minY(), area.minZ(), area.maxX(), area.maxY(), area.maxZ())) {
if (replacingPredicate == null || replacingPredicate.test(new BlockInWorld(serverLevel, blockPos, true))) {
BlockInput blockInput = mode.filter.filter(area, blockPos, newBlock, serverLevel);
if (blockInput != null) {
BlockEntity blockEntity = serverLevel.getBlockEntity(blockPos);
Clearable.tryClear(blockEntity);
if (blockInput.place(serverLevel, blockPos, 2)) {
list.add(blockPos.immutable());
k++;
}
}
}
}
for (BlockPos blockPosx : list) {
Block block = serverLevel.getBlockState(blockPosx).getBlock();
serverLevel.blockUpdated(blockPosx, block);
}
if (k == 0) {
throw ERROR_FAILED.create();
} else {
int l = k;
source.sendSuccess(() -> Component.translatable("commands.fill.success", l), true);
return k;
}
}
}
static enum Mode {
REPLACE((boundingBox, blockPos, blockInput, serverLevel) -> blockInput),
OUTLINE(
(boundingBox, blockPos, blockInput, serverLevel) -> blockPos.getX() != boundingBox.minX()
&& blockPos.getX() != boundingBox.maxX()
&& blockPos.getY() != boundingBox.minY()
&& blockPos.getY() != boundingBox.maxY()
&& blockPos.getZ() != boundingBox.minZ()
&& blockPos.getZ() != boundingBox.maxZ()
? null
: blockInput
),
HOLLOW(
(boundingBox, blockPos, blockInput, serverLevel) -> blockPos.getX() != boundingBox.minX()
&& blockPos.getX() != boundingBox.maxX()
&& blockPos.getY() != boundingBox.minY()
&& blockPos.getY() != boundingBox.maxY()
&& blockPos.getZ() != boundingBox.minZ()
&& blockPos.getZ() != boundingBox.maxZ()
? FillCommand.HOLLOW_CORE
: blockInput
),
DESTROY((boundingBox, blockPos, blockInput, serverLevel) -> {
serverLevel.destroyBlock(blockPos, true);
return blockInput;
});
public final SetBlockCommand.Filter filter;
private Mode(final SetBlockCommand.Filter filter) {
this.filter = filter;
}
}
}