欢迎光临散文网 会员登陆 & 注册

Minecraft 21w08a-21w11a代码简析

2021-03-21 16:21 作者:Nickid2018  | 我要投稿

这么多次版本更新都没法快照代码解析,那么今天都发出来吧!

版本文件对比表:

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命令差不多,只是没有了各种实体运算方块运算的数据,主要都是客户端的渲染信息。

F3+L触发演示

(由于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]

如果专栏中有问题,欢迎在评论区指出。

Minecraft 21w08a-21w11a代码简析的评论 (共 条)

分享到微博请遵守国家法律