参考内容:
(内含各种出错日志信息)
缘由
昨天(2020年6月7号)看到 MutliMC 的 Discord 服务器里有人询问游戏崩溃的问题,然后根据提供的日志信息追踪到了上面两条 issue。感觉对 OptiFine 做兼容是一个很普遍的问题,尤其是在 Fabric 社区鼓励使用 Mixin 制作 CoreMod 的情况下,所以特地开一个提问帖。
引发问题的原因
Forge 对 net.minecraft.network.PacketBuffer
(MCP name) 进行了如下修改:
由于 OptiFine 需要对 Forge 兼容,只能也进行类似的修改,但是 Fabric 并没有修改过这些内容,因此当有 mod 需要用 Mixin 修改这个方法的时候,就会出问题。
下面是 Cardinal-Components-API 引发问题的相关代码:
在 Mixin refmap 中,writeItemStack
指向的是 Lnet/minecraft/class_2540;method_10793(Lnet/minecraft/class_1799;)Lnet/minecraft/class_2540;
,因此无法匹配 OptiFine 修改后的 Lnet/minecraft/class_2540;writeItemStack(Lnet/minecraft/class_1799;Z)Lnet/minecraft/class_2540;
,从而引发游戏崩溃。
做过的尝试
我对这段代码进行了如下修改:
import nerdhub.cardinal.components.internal.ItemStackAccessor;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.util.PacketByteBuf;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.Surrogate;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
// ...
@Inject(
method = { "writeItemStack(Lnet/minecraft/item/ItemStack;)Lnet/minecraft/util/PacketByteBuf;", "writeItemStack(Lnet/minecraft/item/ItemStack;Z)Lnet/minecraft/util/PacketByteBuf;" },
at = @At(value = "INVOKE", target = "Lnet/minecraft/util/PacketByteBuf;writeCompoundTag(Lnet/minecraft/nbt/CompoundTag;)Lnet/minecraft/util/PacketByteBuf;", shift = At.Shift.AFTER)
)
private void writeItemStack(ItemStack stack, boolean limitedTag, CallbackInfoReturnable<PacketByteBuf> cir) {
this.cardinal_writeItemStack(stack);
}
@Surrogate
private void writeItemStack(ItemStack stack, CallbackInfoReturnable<PacketByteBuf> cir) {
this.cardinal_writeItemStack(stack);
}
@Unique
private void cardinal_writeItemStack(ItemStack stack) {
//noinspection ConstantConditions
this.writeCompoundTag(((ItemStackAccessor)(Object)stack).cardinal_getComponentContainer().toTag(new CompoundTag()));
}
很不幸,问题依旧,崩溃原因与上述 issue 中的一致。
查看了一下编译后的 Mixin refmap,发现 writeItemStack(Lnet/minecraft/item/ItemStack;Z)Lnet/minecraft/util/PacketByteBuf;
并没有写入 refmap 中,所以如果手动添加一条:
"writeItemStack(Lnet/minecraft/item/ItemStack;Z)Lnet/minecraft/util/PacketByteBuf;": "Lnet/minecraft/class_2540;writeItemStack(Lnet/minecraft/class_1799;Z)Lnet/minecraft/class_2540;",
这样可以正常运行的,
或者在代码中将
method = { "writeItemStack(Lnet/minecraft/item/ItemStack;)Lnet/minecraft/util/PacketByteBuf;", "writeItemStack(Lnet/minecraft/item/ItemStack;Z)Lnet/minecraft/util/PacketByteBuf;" },
修改为
method = { "writeItemStack(Lnet/minecraft/item/ItemStack;)Lnet/minecraft/util/PacketByteBuf;", "writeItemStack(Lnet/minecraft/class_1799;Z)Lnet/minecraft/class_2540;" },
也可以正常运行。
但是毕竟这样手动混淆不优雅,并且在原生 Mixin 并配合 MixinGradle 的情况下,可以在 build.gradle
中添加下列内容达到增加混淆表内容的目的:
mixin {
extraMappings "additional-mappings.tsrg"
}
但是 Fabric Mixin 下我没有查到类似的东西,我能查到的是这个:tutorial:mappings [Fabric Wiki]
但是这是讲的自定义整个混淆表,很明显我们不需要这样的东西,所以就有了标题上的这个问题。