Minecraft 21w08a-21w11a代码简析

这么多次版本更新都没法快照代码解析,那么今天都发出来吧!
版本文件对比表:
21w06a->21w07a https://paste.ubuntu.com/p/GYDNmJW6N7/
21w07a->21w08b https://paste.ubuntu.com/p/cZcxZ9KN4V/
21w08b->21w10a https://paste.ubuntu.com/p/bKRD2vF8cc/
21w10a->21w11a https://paste.ubuntu.com/p/YJZQWkhvmf/
一.铜块去蜡去锈
铜块在21w11a中能够被斧子去蜡和去锈。

首先是去蜡,现在斧子能把带蜡的铜块变为不带蜡的变种,在此期间消耗1耐久度(无耐久附魔)。
去锈也类似,不过只能将铜块恢复到上一锈蚀阶段,也消耗1耐久度(无耐久附魔)
public InteractionResult useOn(UseOnContext useOnContext) {
Level level = useOnContext.getLevel();
BlockPos blockPos = useOnContext.getClickedPos();
Player player2 = useOnContext.getPlayer();
BlockState blockState = level.getBlockState(blockPos);
Optional
在被闪电劈中后,铜块也能被清除锈蚀,它的实现如下:

首先选择判定点:判断闪电是不是劈到了避雷针,如果是,那么判定点为避雷针的附着方块;如果不是,则判定点就是闪电劈中的位置。
接下来,判断判定点位置上是不是未涂蜡铜块,如果是,将这一块铜块直接还原到普通未锈蚀铜块,并进行接下来的操作;如果不是,则停止判定。
private static void clearCopperOnLightningStrike(Level level, BlockPos blockPos) {
// 闪电劈下时判定
BlockPos blockPos2;
BlockState blockState;
BlockState blockState2 = level.getBlockState(blockPos);
if (blockState2.is(Blocks.LIGHTNING_ROD)) {
blockPos2 = blockPos
.relative(((Direction) blockState2.getValue((Property) LightningRodBlock.FACING)).getOpposite());
blockState = level.getBlockState(blockPos2);
} else {
blockPos2 = blockPos;
blockState = blockState2;
}
if (!(blockState.getBlock() instanceof WeatheringCopper)) {
return;
}
level.setBlockAndUpdate(blockPos2, WeatheringCopper.getFirst((BlockState) level.getBlockState(blockPos2)));
BlockPos.MutableBlockPos mutableBlockPos = blockPos.mutable();
int n = level.random.nextInt(3) + 3;
for (int i = 0; i < n; ++i) {
int n2 = level.random.nextInt(8) + 1;
LightningBolt.randomWalkCleaningCopper(level, blockPos2, mutableBlockPos, n2);
}
}
在修改了判定点方块后,系统将执行3-5次旁边铜块的除锈。每次都会在判定游走点周围3x3x3范围内随机选取10个方块,如果选中的方块不是铜块及其变种,则跳过;如果是,则将这个铜块清理回到上一阶段,并重新设置游走点为原先的判定点,如果这10个方块都不是铜类方块,则游走停止,不再继续,这个过程重复1-8次。
不好理解?下面是一个形象化的小栗子:
在闪电之中,诞生了3-5个神奇的人类。他们脚踩着闪电劈下的方块或者劈中的避雷针下面的方块。它们诞生时拥有1-8格体力,供他们"游走"。在闪电彻底除掉方块的锈蚀之后,他们开始随机的向前走。他们每一个人每走一步都会在他们周围的3x3x3的方块范围内找10个方块(包括自己踩的),如果找到了没有蜡的铜块,他们就会跳上这个方块,除去这个铜块的一层锈(如果有的话);如果没有找到,就原地歇息一下,什么都不干。无论他们这一步有没有成功的游走,都会消耗1体力。当他们走完了所有体力,他们就会消失。
根据这个原理,我们可以知道为了让闪电清除掉一片铜锈,我们必须要保证铜块相连或相邻(3x3x3范围内有别的铜块)。如果我们只放了一个单独的铜块,但是3x3x3内没有其它铜块,那么,即使你在其他很近的位置上放置铜块,闪电也无法清除它们的锈,因为判定点无法移动到除原先判定点的位置。同样,根据这个原理,我们可以知道一次闪电最多可以清除41个方块(起始点还原回铜块,其他都只清除到上一阶段),最远也能清除8个方块。
private static void randomWalkCleaningCopper(Level level, BlockPos blockPos,
BlockPos.MutableBlockPos mutableBlockPos, int n) {
// 随机行进清除
Optional
二.垂滴叶的“涨水”特性
这个版本中有不少bug(特性),这就是一个。

这个特性是:当你在催熟含水的垂滴叶柄的时候,水会“涨”上来。

下面是特性的原理:当催熟垂滴叶柄的时候,系统会去寻找垂滴叶柄顶端的大型垂滴叶,如果没有,则催熟不成功;如果有的话,先读取现在催熟的方块的流体状态,然后会用这个流体状态去放置新的垂滴叶柄!所以导致了水被“顶”了起来。下面就是详细的代码:
public void performBonemeal(ServerLevel serverLevel, Random random, BlockPos blockPos, BlockState blockState) {
Optional optional = BlockUtil.getTopConnectedBlock((BlockGetter) serverLevel, (BlockPos) blockPos,
(Block) blockState.getBlock(), (Direction) Direction.UP, (Block) Blocks.BIG_DRIPLEAF);
if (!optional.isPresent()) {
return;
}
BlockPos blockPos2 = (BlockPos) optional.get();
BlockPos blockPos3 = blockPos2.above();
FluidState fluidState = serverLevel.getFluidState(blockPos3);
Direction direction = (Direction) blockState.getValue((Property) FACING);
BigDripleafStemBlock.place((LevelAccessor) serverLevel, blockPos2, blockState.getFluidState(), direction);
BigDripleafBlock.place((LevelAccessor) serverLevel, (BlockPos) blockPos3, (FluidState) fluidState,
(Direction) direction);
}
三.F3+L保存性能分析数据
这是一个对于模组开发者的福利(?),这个新功能的代码net.minecraft.client.profiling里面,它记录的有JVM信息、FPS信息、渲染区块数量、待上传区块数量、其他渲染信息等。和debug命令差不多,只是没有了各种实体运算方块运算的数据,主要都是客户端的渲染信息。

(由于CFK反编译器在此处无法翻译lambda表达式,就不放出源码了)
四.网络系统的暗改(可能?)
在21w08a的时候,network包的文件都被修改了一回,就像下面一样:
(21w07a)
public ClientboundAddEntityPacket(int n, UUID uUID, double d, double d2, double d3, float f, float f2,
EntityType entityType, int n2, Vec3 vec3) {
this.id = n;
this.uuid = uUID;
this.x = d;
this.y = d2;
this.z = d3;
this.xRot = Mth.floor((float) (f * 256.0f / 360.0f));
this.yRot = Mth.floor((float) (f2 * 256.0f / 360.0f));
this.type = entityType;
this.data = n2;
this.xa = (int) (Mth.clamp((double) vec3.x, (double) -3.9, (double) 3.9) * 8000.0);
this.ya = (int) (Mth.clamp((double) vec3.y, (double) -3.9, (double) 3.9) * 8000.0);
this.za = (int) (Mth.clamp((double) vec3.z, (double) -3.9, (double) 3.9) * 8000.0);
}
public void read(FriendlyByteBuf friendlyByteBuf) throws IOException {
this.id = friendlyByteBuf.readVarInt();
this.uuid = friendlyByteBuf.readUUID();
this.type = (EntityType) Registry.ENTITY_TYPE.byId(friendlyByteBuf.readVarInt());
this.x = friendlyByteBuf.readDouble();
this.y = friendlyByteBuf.readDouble();
this.z = friendlyByteBuf.readDouble();
this.xRot = friendlyByteBuf.readByte();
this.yRot = friendlyByteBuf.readByte();
this.data = friendlyByteBuf.readInt();
this.xa = friendlyByteBuf.readShort();
this.ya = friendlyByteBuf.readShort();
this.za = friendlyByteBuf.readShort();
}
(21w11a)
public ClientboundAddEntityPacket(FriendlyByteBuf friendlyByteBuf) {
this.id = friendlyByteBuf.readVarInt();
this.uuid = friendlyByteBuf.readUUID();
this.type = (EntityType) Registry.ENTITY_TYPE.byId(friendlyByteBuf.readVarInt());
this.x = friendlyByteBuf.readDouble();
this.y = friendlyByteBuf.readDouble();
this.z = friendlyByteBuf.readDouble();
this.xRot = friendlyByteBuf.readByte();
this.yRot = friendlyByteBuf.readByte();
this.data = friendlyByteBuf.readInt();
this.xa = friendlyByteBuf.readShort();
this.ya = friendlyByteBuf.readShort();
this.za = friendlyByteBuf.readShort();
}
可以看到,在21w08a后构造函数和read方法就整合到一起了,这也许代表了MC网络系统即将优化?(也许想多了)

代码源:21w11a,以Mojang Name反混淆
反混淆器:MCDynamicExchanger(beta6)
[项目地址 https://github.com/Nickid2018/MCDynamicExchanger]
如果专栏中有问题,欢迎在评论区指出。