CloneCommands.java

net.minecraft.server.commands.CloneCommands

信息

  • 全限定名:net.minecraft.server.commands.CloneCommands
  • 类型:public class
  • 包:net.minecraft.server.commands
  • 源码路径:src/main/java/net/minecraft/server/commands/CloneCommands.java
  • 起始行号:L37
  • 职责:

    TODO

字段/常量

  • LOGGER

    • 类型: Logger
    • 修饰符: private static final
    • 源码定位: L38
    • 说明:

      TODO

  • ERROR_OVERLAP

    • 类型: SimpleCommandExceptionType
    • 修饰符: private static final
    • 源码定位: L39
    • 说明:

      TODO

  • ERROR_AREA_TOO_LARGE

    • 类型: Dynamic2CommandExceptionType
    • 修饰符: private static final
    • 源码定位: L40
    • 说明:

      TODO

  • ERROR_FAILED

    • 类型: SimpleCommandExceptionType
    • 修饰符: private static final
    • 源码定位: L43
    • 说明:

      TODO

  • FILTER_AIR

    • 类型: Predicate<BlockInWorld>
    • 修饰符: public static final
    • 源码定位: L44
    • 说明:

      TODO

内部类/嵌套类型

  • net.minecraft.server.commands.CloneCommands.CloneBlockEntityInfo

    • 类型: record
    • 修饰符: private
    • 源码定位: L317
    • 说明:

      TODO

  • net.minecraft.server.commands.CloneCommands.CloneBlockInfo

    • 类型: record
    • 修饰符: private
    • 源码定位: L320
    • 说明:

      TODO

  • net.minecraft.server.commands.CloneCommands.DimensionAndPosition

    • 类型: record
    • 修饰符: private
    • 源码定位: L325
    • 说明:

      TODO

  • net.minecraft.server.commands.CloneCommands.Mode

    • 类型: enum
    • 修饰符: private static
    • 源码定位: L328
    • 说明:

      TODO

构造器

方法

下面的方法块按源码顺序生成。

public static void register(CommandDispatcher<CommandSourceStack> dispatcher, CommandBuildContext context) @ L46

  • 方法名:register
  • 源码定位:L46
  • 返回类型:void
  • 修饰符:public static

参数:

  • dispatcher: CommandDispatcher
  • context: CommandBuildContext

说明:

TODO

private static ArgumentBuilder<CommandSourceStack,?> beginEndDestinationAndModeSuffix(CommandBuildContext context, InCommandFunction<CommandContext<CommandSourceStack>,ServerLevel> fromDimension) @ L61

  • 方法名:beginEndDestinationAndModeSuffix
  • 源码定位:L61
  • 返回类型:ArgumentBuilder<CommandSourceStack,?>
  • 修饰符:private static

参数:

  • context: CommandBuildContext
  • fromDimension: InCommandFunction<CommandContext,ServerLevel>

说明:

TODO

private static CloneCommands.DimensionAndPosition getLoadedDimensionAndPosition(CommandContext<CommandSourceStack> context, ServerLevel level, String positionArgument) @ L78

  • 方法名:getLoadedDimensionAndPosition
  • 源码定位:L78
  • 返回类型:CloneCommands.DimensionAndPosition
  • 修饰符:private static

参数:

  • context: CommandContext
  • level: ServerLevel
  • positionArgument: String

说明:

TODO

private static ArgumentBuilder<CommandSourceStack,?> destinationAndStrictSuffix(CommandBuildContext context, InCommandFunction<CommandContext<CommandSourceStack>,ServerLevel> fromDimension, InCommandFunction<CommandContext<CommandSourceStack>,ServerLevel> toDimension) @ L85

  • 方法名:destinationAndStrictSuffix
  • 源码定位:L85
  • 返回类型:ArgumentBuilder<CommandSourceStack,?>
  • 修饰符:private static

参数:

  • context: CommandBuildContext
  • fromDimension: InCommandFunction<CommandContext,ServerLevel>
  • toDimension: InCommandFunction<CommandContext,ServerLevel>

说明:

TODO

private static ArgumentBuilder<CommandSourceStack,?> modeSuffix(CommandBuildContext context, InCommandFunction<CommandContext<CommandSourceStack>,CloneCommands.DimensionAndPosition> beginPos, InCommandFunction<CommandContext<CommandSourceStack>,CloneCommands.DimensionAndPosition> endPos, InCommandFunction<CommandContext<CommandSourceStack>,CloneCommands.DimensionAndPosition> destinationPos, boolean strict, ArgumentBuilder<CommandSourceStack,?> builder) @ L103

  • 方法名:modeSuffix
  • 源码定位:L103
  • 返回类型:ArgumentBuilder<CommandSourceStack,?>
  • 修饰符:private static

参数:

  • context: CommandBuildContext
  • beginPos: InCommandFunction<CommandContext,CloneCommands.DimensionAndPosition>
  • endPos: InCommandFunction<CommandContext,CloneCommands.DimensionAndPosition>
  • destinationPos: InCommandFunction<CommandContext,CloneCommands.DimensionAndPosition>
  • strict: boolean
  • builder: ArgumentBuilder<CommandSourceStack,?>

说明:

TODO

private static ArgumentBuilder<CommandSourceStack,?> wrapWithCloneMode(InCommandFunction<CommandContext<CommandSourceStack>,CloneCommands.DimensionAndPosition> beginPos, InCommandFunction<CommandContext<CommandSourceStack>,CloneCommands.DimensionAndPosition> endPos, InCommandFunction<CommandContext<CommandSourceStack>,CloneCommands.DimensionAndPosition> destinationPos, InCommandFunction<CommandContext<CommandSourceStack>,Predicate<BlockInWorld>> filter, boolean strict, ArgumentBuilder<CommandSourceStack,?> builder) @ L131

  • 方法名:wrapWithCloneMode
  • 源码定位:L131
  • 返回类型:ArgumentBuilder<CommandSourceStack,?>
  • 修饰符:private static

参数:

  • beginPos: InCommandFunction<CommandContext,CloneCommands.DimensionAndPosition>
  • endPos: InCommandFunction<CommandContext,CloneCommands.DimensionAndPosition>
  • destinationPos: InCommandFunction<CommandContext,CloneCommands.DimensionAndPosition>
  • filter: InCommandFunction<CommandContext,Predicate>
  • strict: boolean
  • builder: ArgumentBuilder<CommandSourceStack,?>

说明:

TODO

private static int clone(CommandSourceStack source, CloneCommands.DimensionAndPosition startPosAndDimension, CloneCommands.DimensionAndPosition endPosAndDimension, CloneCommands.DimensionAndPosition destPosAndDimension, Predicate<BlockInWorld> predicate, CloneCommands.Mode mode, boolean strict) @ L166

  • 方法名:clone
  • 源码定位:L166
  • 返回类型:int
  • 修饰符:private static

参数:

  • source: CommandSourceStack
  • startPosAndDimension: CloneCommands.DimensionAndPosition
  • endPosAndDimension: CloneCommands.DimensionAndPosition
  • destPosAndDimension: CloneCommands.DimensionAndPosition
  • predicate: Predicate
  • mode: CloneCommands.Mode
  • strict: boolean

说明:

TODO

代码

public class CloneCommands {
    private static final Logger LOGGER = LogUtils.getLogger();
    private static final SimpleCommandExceptionType ERROR_OVERLAP = new SimpleCommandExceptionType(Component.translatable("commands.clone.overlap"));
    private static final Dynamic2CommandExceptionType ERROR_AREA_TOO_LARGE = new Dynamic2CommandExceptionType(
        (max, count) -> Component.translatableEscape("commands.clone.toobig", max, count)
    );
    private static final SimpleCommandExceptionType ERROR_FAILED = new SimpleCommandExceptionType(Component.translatable("commands.clone.failed"));
    public static final Predicate<BlockInWorld> FILTER_AIR = b -> !b.getState().isAir();
 
    public static void register(CommandDispatcher<CommandSourceStack> dispatcher, CommandBuildContext context) {
        dispatcher.register(
            Commands.literal("clone")
                .requires(Commands.hasPermission(Commands.LEVEL_GAMEMASTERS))
                .then(beginEndDestinationAndModeSuffix(context, c -> c.getSource().getLevel()))
                .then(
                    Commands.literal("from")
                        .then(
                            Commands.argument("sourceDimension", DimensionArgument.dimension())
                                .then(beginEndDestinationAndModeSuffix(context, c -> DimensionArgument.getDimension(c, "sourceDimension")))
                        )
                )
        );
    }
 
    private static ArgumentBuilder<CommandSourceStack, ?> beginEndDestinationAndModeSuffix(
        CommandBuildContext context, InCommandFunction<CommandContext<CommandSourceStack>, ServerLevel> fromDimension
    ) {
        return Commands.argument("begin", BlockPosArgument.blockPos())
            .then(
                Commands.argument("end", BlockPosArgument.blockPos())
                    .then(destinationAndStrictSuffix(context, fromDimension, c -> c.getSource().getLevel()))
                    .then(
                        Commands.literal("to")
                            .then(
                                Commands.argument("targetDimension", DimensionArgument.dimension())
                                    .then(destinationAndStrictSuffix(context, fromDimension, c -> DimensionArgument.getDimension(c, "targetDimension")))
                            )
                    )
            );
    }
 
    private static CloneCommands.DimensionAndPosition getLoadedDimensionAndPosition(
        CommandContext<CommandSourceStack> context, ServerLevel level, String positionArgument
    ) throws CommandSyntaxException {
        BlockPos blockPos = BlockPosArgument.getLoadedBlockPos(context, level, positionArgument);
        return new CloneCommands.DimensionAndPosition(level, blockPos);
    }
 
    private static ArgumentBuilder<CommandSourceStack, ?> destinationAndStrictSuffix(
        CommandBuildContext context,
        InCommandFunction<CommandContext<CommandSourceStack>, ServerLevel> fromDimension,
        InCommandFunction<CommandContext<CommandSourceStack>, ServerLevel> toDimension
    ) {
        InCommandFunction<CommandContext<CommandSourceStack>, CloneCommands.DimensionAndPosition> beginPos = c -> getLoadedDimensionAndPosition(
            c, fromDimension.apply(c), "begin"
        );
        InCommandFunction<CommandContext<CommandSourceStack>, CloneCommands.DimensionAndPosition> endPos = c -> getLoadedDimensionAndPosition(
            c, fromDimension.apply(c), "end"
        );
        InCommandFunction<CommandContext<CommandSourceStack>, CloneCommands.DimensionAndPosition> destinationPos = c -> getLoadedDimensionAndPosition(
            c, toDimension.apply(c), "destination"
        );
        return modeSuffix(context, beginPos, endPos, destinationPos, false, Commands.argument("destination", BlockPosArgument.blockPos()))
            .then(modeSuffix(context, beginPos, endPos, destinationPos, true, Commands.literal("strict")));
    }
 
    private static ArgumentBuilder<CommandSourceStack, ?> modeSuffix(
        CommandBuildContext context,
        InCommandFunction<CommandContext<CommandSourceStack>, CloneCommands.DimensionAndPosition> beginPos,
        InCommandFunction<CommandContext<CommandSourceStack>, CloneCommands.DimensionAndPosition> endPos,
        InCommandFunction<CommandContext<CommandSourceStack>, CloneCommands.DimensionAndPosition> destinationPos,
        boolean strict,
        ArgumentBuilder<CommandSourceStack, ?> builder
    ) {
        return builder.executes(
                c -> clone(c.getSource(), beginPos.apply(c), endPos.apply(c), destinationPos.apply(c), b -> true, CloneCommands.Mode.NORMAL, strict)
            )
            .then(wrapWithCloneMode(beginPos, endPos, destinationPos, c -> b -> true, strict, Commands.literal("replace")))
            .then(wrapWithCloneMode(beginPos, endPos, destinationPos, c -> FILTER_AIR, strict, Commands.literal("masked")))
            .then(
                Commands.literal("filtered")
                    .then(
                        wrapWithCloneMode(
                            beginPos,
                            endPos,
                            destinationPos,
                            c -> BlockPredicateArgument.getBlockPredicate(c, "filter"),
                            strict,
                            Commands.argument("filter", BlockPredicateArgument.blockPredicate(context))
                        )
                    )
            );
    }
 
    private static ArgumentBuilder<CommandSourceStack, ?> wrapWithCloneMode(
        InCommandFunction<CommandContext<CommandSourceStack>, CloneCommands.DimensionAndPosition> beginPos,
        InCommandFunction<CommandContext<CommandSourceStack>, CloneCommands.DimensionAndPosition> endPos,
        InCommandFunction<CommandContext<CommandSourceStack>, CloneCommands.DimensionAndPosition> destinationPos,
        InCommandFunction<CommandContext<CommandSourceStack>, Predicate<BlockInWorld>> filter,
        boolean strict,
        ArgumentBuilder<CommandSourceStack, ?> builder
    ) {
        return builder.executes(
                c -> clone(c.getSource(), beginPos.apply(c), endPos.apply(c), destinationPos.apply(c), filter.apply(c), CloneCommands.Mode.NORMAL, strict)
            )
            .then(
                Commands.literal("force")
                    .executes(
                        c -> clone(
                            c.getSource(), beginPos.apply(c), endPos.apply(c), destinationPos.apply(c), filter.apply(c), CloneCommands.Mode.FORCE, strict
                        )
                    )
            )
            .then(
                Commands.literal("move")
                    .executes(
                        c -> clone(c.getSource(), beginPos.apply(c), endPos.apply(c), destinationPos.apply(c), filter.apply(c), CloneCommands.Mode.MOVE, strict)
                    )
            )
            .then(
                Commands.literal("normal")
                    .executes(
                        c -> clone(
                            c.getSource(), beginPos.apply(c), endPos.apply(c), destinationPos.apply(c), filter.apply(c), CloneCommands.Mode.NORMAL, strict
                        )
                    )
            );
    }
 
    private static int clone(
        CommandSourceStack source,
        CloneCommands.DimensionAndPosition startPosAndDimension,
        CloneCommands.DimensionAndPosition endPosAndDimension,
        CloneCommands.DimensionAndPosition destPosAndDimension,
        Predicate<BlockInWorld> predicate,
        CloneCommands.Mode mode,
        boolean strict
    ) throws CommandSyntaxException {
        BlockPos startPos = startPosAndDimension.position();
        BlockPos endPos = endPosAndDimension.position();
        BoundingBox from = BoundingBox.fromCorners(startPos, endPos);
        BlockPos destPos = destPosAndDimension.position();
        BlockPos destEndPos = destPos.offset(from.getLength());
        BoundingBox destination = BoundingBox.fromCorners(destPos, destEndPos);
        ServerLevel fromDimension = startPosAndDimension.dimension();
        ServerLevel toDimension = destPosAndDimension.dimension();
        if (!mode.canOverlap() && fromDimension == toDimension && destination.intersects(from)) {
            throw ERROR_OVERLAP.create();
        } else {
            long area = (long)from.getXSpan() * from.getYSpan() * from.getZSpan();
            int limit = source.getLevel().getGameRules().get(GameRules.MAX_BLOCK_MODIFICATIONS);
            if (area > limit) {
                throw ERROR_AREA_TOO_LARGE.create(limit, area);
            } else if (!fromDimension.hasChunksAt(startPos, endPos) || !toDimension.hasChunksAt(destPos, destEndPos)) {
                throw BlockPosArgument.ERROR_NOT_LOADED.create();
            } else if (toDimension.isDebug()) {
                throw ERROR_FAILED.create();
            } else {
                List<CloneCommands.CloneBlockInfo> solidList = Lists.newArrayList();
                List<CloneCommands.CloneBlockInfo> blockEntitiesList = Lists.newArrayList();
                List<CloneCommands.CloneBlockInfo> otherBlocksList = Lists.newArrayList();
                Deque<BlockPos> clearBlocksList = Lists.newLinkedList();
                int count = 0;
                ProblemReporter.ScopedCollector reporter = new ProblemReporter.ScopedCollector(LOGGER);
 
                try {
                    BlockPos offset = new BlockPos(destination.minX() - from.minX(), destination.minY() - from.minY(), destination.minZ() - from.minZ());
 
                    for (int z = from.minZ(); z <= from.maxZ(); z++) {
                        for (int y = from.minY(); y <= from.maxY(); y++) {
                            for (int x = from.minX(); x <= from.maxX(); x++) {
                                BlockPos sourcePos = new BlockPos(x, y, z);
                                BlockPos destinationPos = sourcePos.offset(offset);
                                BlockInWorld block = new BlockInWorld(fromDimension, sourcePos, false);
                                BlockState blockState = block.getState();
                                if (predicate.test(block)) {
                                    BlockEntity blockEntity = fromDimension.getBlockEntity(sourcePos);
                                    if (blockEntity != null) {
                                        TagValueOutput output = TagValueOutput.createWithContext(
                                            reporter.forChild(blockEntity.problemPath()), source.registryAccess()
                                        );
                                        blockEntity.saveCustomOnly(output);
                                        CloneCommands.CloneBlockEntityInfo blockEntityInfo = new CloneCommands.CloneBlockEntityInfo(
                                            output.buildResult(), blockEntity.components()
                                        );
                                        blockEntitiesList.add(
                                            new CloneCommands.CloneBlockInfo(
                                                destinationPos, blockState, blockEntityInfo, toDimension.getBlockState(destinationPos)
                                            )
                                        );
                                        clearBlocksList.addLast(sourcePos);
                                    } else if (!blockState.isSolidRender() && !blockState.isCollisionShapeFullBlock(fromDimension, sourcePos)) {
                                        otherBlocksList.add(
                                            new CloneCommands.CloneBlockInfo(destinationPos, blockState, null, toDimension.getBlockState(destinationPos))
                                        );
                                        clearBlocksList.addFirst(sourcePos);
                                    } else {
                                        solidList.add(
                                            new CloneCommands.CloneBlockInfo(destinationPos, blockState, null, toDimension.getBlockState(destinationPos))
                                        );
                                        clearBlocksList.addLast(sourcePos);
                                    }
                                }
                            }
                        }
                    }
 
                    int defaultUpdateFlags = 2 | (strict ? 816 : 0);
                    if (mode == CloneCommands.Mode.MOVE) {
                        for (BlockPos pos : clearBlocksList) {
                            fromDimension.setBlock(pos, Blocks.BARRIER.defaultBlockState(), defaultUpdateFlags | 816);
                        }
 
                        int standardUpdateFlags = strict ? defaultUpdateFlags : 3;
 
                        for (BlockPos pos : clearBlocksList) {
                            fromDimension.setBlock(pos, Blocks.AIR.defaultBlockState(), standardUpdateFlags);
                        }
                    }
 
                    List<CloneCommands.CloneBlockInfo> blockInfoList = Lists.newArrayList();
                    blockInfoList.addAll(solidList);
                    blockInfoList.addAll(blockEntitiesList);
                    blockInfoList.addAll(otherBlocksList);
                    List<CloneCommands.CloneBlockInfo> reverse = Lists.reverse(blockInfoList);
 
                    for (CloneCommands.CloneBlockInfo cloneInfo : reverse) {
                        toDimension.setBlock(cloneInfo.pos, Blocks.BARRIER.defaultBlockState(), defaultUpdateFlags | 816);
                    }
 
                    for (CloneCommands.CloneBlockInfo cloneInfo : blockInfoList) {
                        if (toDimension.setBlock(cloneInfo.pos, cloneInfo.state, defaultUpdateFlags)) {
                            count++;
                        }
                    }
 
                    for (CloneCommands.CloneBlockInfo cloneInfox : blockEntitiesList) {
                        BlockEntity newBlockEntity = toDimension.getBlockEntity(cloneInfox.pos);
                        if (cloneInfox.blockEntityInfo != null && newBlockEntity != null) {
                            newBlockEntity.loadCustomOnly(
                                TagValueInput.create(
                                    reporter.forChild(newBlockEntity.problemPath()), toDimension.registryAccess(), cloneInfox.blockEntityInfo.tag
                                )
                            );
                            newBlockEntity.setComponents(cloneInfox.blockEntityInfo.components);
                            newBlockEntity.setChanged();
                        }
 
                        toDimension.setBlock(cloneInfox.pos, cloneInfox.state, defaultUpdateFlags);
                    }
 
                    if (!strict) {
                        for (CloneCommands.CloneBlockInfo cloneInfox : reverse) {
                            toDimension.updateNeighboursOnBlockSet(cloneInfox.pos, cloneInfox.previousStateAtDestination);
                        }
                    }
 
                    toDimension.getBlockTicks().copyAreaFrom(fromDimension.getBlockTicks(), from, offset);
                } catch (Throwable var36) {
                    try {
                        reporter.close();
                    } catch (Throwable var35) {
                        var36.addSuppressed(var35);
                    }
 
                    throw var36;
                }
 
                reporter.close();
                if (count == 0) {
                    throw ERROR_FAILED.create();
                } else {
                    int finalCount = count;
                    source.sendSuccess(() -> Component.translatable("commands.clone.success", finalCount), true);
                    return count;
                }
            }
        }
    }
 
    private record CloneBlockEntityInfo(CompoundTag tag, DataComponentMap components) {
    }
 
    private record CloneBlockInfo(
        BlockPos pos, BlockState state, CloneCommands.@Nullable CloneBlockEntityInfo blockEntityInfo, BlockState previousStateAtDestination
    ) {
    }
 
    private record DimensionAndPosition(ServerLevel dimension, BlockPos position) {
    }
 
    private static enum Mode {
        FORCE(true),
        MOVE(true),
        NORMAL(false);
 
        private final boolean canOverlap;
 
        private Mode(boolean canOverlap) {
            this.canOverlap = canOverlap;
        }
 
        public boolean canOverlap() {
            return this.canOverlap;
        }
    }
}

引用的其他类

  • CommandBuildContext

    • 引用位置: 参数
  • CommandSourceStack

    • 引用位置: 参数/返回值
  • Commands

    • 引用位置: 方法调用
    • 关联成员: Commands.argument(), Commands.hasPermission(), Commands.literal()
  • DimensionArgument

    • 引用位置: 方法调用
    • 关联成员: DimensionArgument.dimension(), DimensionArgument.getDimension()
  • BlockPredicateArgument

    • 引用位置: 方法调用
    • 关联成员: BlockPredicateArgument.blockPredicate(), BlockPredicateArgument.getBlockPredicate()
  • BlockPosArgument

    • 引用位置: 方法调用
    • 关联成员: BlockPosArgument.blockPos(), BlockPosArgument.getLoadedBlockPos()
  • BlockPos

    • 引用位置: 构造调用
    • 关联成员: BlockPos()
  • Component

    • 引用位置: 方法调用
    • 关联成员: Component.translatable(), Component.translatableEscape()
  • InCommandFunction

    • 引用位置: 参数
  • ServerLevel

    • 引用位置: 参数
  • ProblemReporter

    • 引用位置: 方法调用/构造调用
    • 关联成员: ProblemReporter.ScopedCollector(), ScopedCollector()
  • BlockInWorld

    • 引用位置: 参数/字段/构造调用
    • 关联成员: BlockInWorld()
  • BoundingBox

    • 引用位置: 方法调用
    • 关联成员: BoundingBox.fromCorners()
  • TagValueInput

    • 引用位置: 方法调用
    • 关联成员: TagValueInput.create()
  • TagValueOutput

    • 引用位置: 方法调用
    • 关联成员: TagValueOutput.createWithContext()