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;
}
}
}引用的其他类
-
- 引用位置:
参数
- 引用位置:
-
- 引用位置:
参数/返回值
- 引用位置:
-
- 引用位置:
方法调用 - 关联成员:
Commands.argument(), Commands.hasPermission(), Commands.literal()
- 引用位置:
-
- 引用位置:
方法调用 - 关联成员:
DimensionArgument.dimension(), DimensionArgument.getDimension()
- 引用位置:
-
- 引用位置:
方法调用 - 关联成员:
BlockPredicateArgument.blockPredicate(), BlockPredicateArgument.getBlockPredicate()
- 引用位置:
-
- 引用位置:
方法调用 - 关联成员:
BlockPosArgument.blockPos(), BlockPosArgument.getLoadedBlockPos()
- 引用位置:
-
- 引用位置:
构造调用 - 关联成员:
BlockPos()
- 引用位置:
-
- 引用位置:
方法调用 - 关联成员:
Component.translatable(), Component.translatableEscape()
- 引用位置:
-
- 引用位置:
参数
- 引用位置:
-
- 引用位置:
参数
- 引用位置:
-
- 引用位置:
方法调用/构造调用 - 关联成员:
ProblemReporter.ScopedCollector(), ScopedCollector()
- 引用位置:
-
- 引用位置:
参数/字段/构造调用 - 关联成员:
BlockInWorld()
- 引用位置:
-
- 引用位置:
方法调用 - 关联成员:
BoundingBox.fromCorners()
- 引用位置:
-
- 引用位置:
方法调用 - 关联成员:
TagValueInput.create()
- 引用位置:
-
- 引用位置:
方法调用 - 关联成员:
TagValueOutput.createWithContext()
- 引用位置: