Mixin 清单

基本信息

属性 值
类型 早期(EARLY)字节码注入
源包 com.gtnewhorizons.foundation.mixins(Gradle mixinsPackage = mixins)
mixin 类总数 6 个
EARLY 阶段 6 个(全部)
LATE 阶段 0 个
注册方式 Mixins 枚举 + GTNHLib MixinBuilder
挂载配置 mixins.foundation.early.json

行为

Foundation 的全部 6 个 mixin 都被声明为 Phase.EARLY——grep "Phase\." 在全仓库只命中 Mixins.java 的两处,且两处都是 Phase.EARLY,没有任何 Phase.LATE。原因是这些 mixin 要在原版网络封包类被别的 coremod / mixin 触碰之前拿到 @Overwrite 权限:S21/S22/S23 都是协议类,晚一步就可能与其他模组的注入冲突。

Mixins 枚举把 6 个类分成两组(Side 决定物理加载,Phase 决定时序):

枚举常量 显示名 目标模组 Side Phase applyIf 包含的 mixin
PACKETS Packet Mixins TargetedMod.VANILLA Side.BOTH Phase.EARLY () -> true MixinS21PacketChunkData、MixinS22PacketMultiBlockChange、MixinS23PacketBlockChange、MixinS26PacketMapChunkBulk
CLIENT_ONLY Client Only Mixins TargetedMod.VANILLA Side.CLIENT Phase.EARLY () -> true client.MixinChunk、client.MixinNetHandlerPlayClient

枚举构造函数有两处防御性校验:targetedMods 为空抛 RuntimeException("No targeted mods specified for " + name()),applyIf 为 null 抛 RuntimeException("No ApplyIf function specified for " + name())。 excludedMods 字段存在但从未被填充(无 addExcludedMod 调用),getExcludedMods() 恒返回空列表。

Mixin 全表

# Mixin 类 @Mixin 目标 注入方法签名(源码原样) 注入类型 阶段 Side 修补的原版行为
1 early/MixinS21PacketChunkData S21PacketChunkData public static int func_149275_c() @Overwrite EARLY BOTH 把「整个区块数据的字节长度」常量替换为 HandlerRegistry.getChunkPacketBytes(),即所有已注册 chunk handler 的 maxBytesPerChunk() 之和
2 early/MixinS21PacketChunkData S21PacketChunkData public static S21PacketChunkData.Extracted func_149269_a(Chunk chunk, boolean sendUpdates, int flagSubChunks) @Overwrite EARLY BOTH 保留子区块掩码 extracted.field_150280_b 与 chunk.sendUpdates 的原版语义,主体改为 HandlerRegistry.writeChunkPackets(...)
3 early/MixinS22PacketMultiBlockChange S22PacketMultiBlockChange public void newConstructor(int count, short[] positions, Chunk chunk) 普通方法(接口 IMixinS22PacketMultiBlockChange 提供) EARLY BOTH 新增能力:原版构造丢弃 Chunk 引用,此处逐项 chunk.getBlock / getBlockMetadata 填充 BlockPacketInfo[]
4 early/MixinS22PacketMultiBlockChange S22PacketMultiBlockChange public void readPacketData(PacketBuffer data) @Overwrite EARLY BOTH 解析出每个方块后交 HandlerRegistry.readS22Packets(info, data) 读取 block + metadata
5 early/MixinS22PacketMultiBlockChange S22PacketMultiBlockChange public void writePacketData(PacketBuffer data) @Overwrite EARLY BOTH 逐项交 HandlerRegistry.writeS22Packets(info, data) 写出;blockPackets == null 时写 0 长度
6 early/MixinS23PacketBlockChange S23PacketBlockChange public void writePacketData(PacketBuffer data) @Overwrite EARLY BOTH x/y/z 三字段写完后交 HandlerRegistry.writeS23Packets(...)
7 early/MixinS23PacketBlockChange S23PacketBlockChange public void readPacketData(PacketBuffer data) @Overwrite EARLY BOTH x/y/z 三字段读完后交 HandlerRegistry.readS23Packets(...)
8 early/MixinS26PacketMapChunkBulk S26PacketMapChunkBulk private void foundation$injectS21SizeReads(PacketBuffer data, CallbackInfo ci, @Local(ordinal = 0) short chunks) @Inject @At(INVOKE PacketBuffer.readInt()I ordinal = 0) EARLY BOTH 批量封包里每个内嵌 S21 前面多出的「长度 int」需要先吃掉,否则后续按原版偏移读会错位
9 early/MixinS26PacketMapChunkBulk S26PacketMapChunkBulk private int foundation$modifyI1Value1(int original, @Local(ordinal = 1) int j) @ModifyVariable @At(LOAD ordinal = 5) ordinal = 4 EARLY BOTH 用 s21Sizes[j] 替换原版算出的内嵌 S21 长度
10 early/MixinS26PacketMapChunkBulk S26PacketMapChunkBulk private int foundation$modifyI1Value2(int original, @Local(ordinal = 1) int j) @ModifyVariable @At(LOAD ordinal = 6) ordinal = 4 EARLY BOTH 同上,第二个长度读取点
11 early/MixinS26PacketMapChunkBulk S26PacketMapChunkBulk private int foundation$modifyI1Value3(int original, @Local(ordinal = 1) int j) @ModifyVariable @At(LOAD ordinal = 7) ordinal = 4 EARLY BOTH 同上,第三个长度读取点
12 early/MixinS26PacketMapChunkBulk S26PacketMapChunkBulk private void foundation$injectSizeWrites(PacketBuffer data, CallbackInfo ci) @Inject @At(INVOKE PacketBuffer.writeInt(I)Lio/netty/buffer/ByteBuf; ordinal = 0) EARLY BOTH 写出前为每个内嵌 chunk 补写 field_149260_f[i].length
13 early/client/MixinChunk net.minecraft.world.chunk.Chunk public void fillChunk(byte[] data, int flagSubChunks, int flagMsb, boolean sendUpdates) @Overwrite EARLY CLIENT 整段原版「压缩块 + nibble 数组」解包逻辑改为 HandlerRegistry.readChunkPackets(thisObject, sendUpdates, flagSubChunks, data);flagMsb 参数保留但不再被读取
14 early/client/MixinNetHandlerPlayClient NetHandlerPlayClient public void handleMultiBlockChange(S22PacketMultiBlockChange packetIn) @Overwrite EARLY CLIENT 不再逐条解析位置,改为遍历 getInfos() 并调 clientWorldController.func_147492_c(x + chunkX, y, z + chunkZ, block, metadata)

字段注入(@Shadow / @Unique)

Mixin 字段 注解 源码声明
MixinS21PacketChunkData private static byte[] field_149286_i = null; @Shadow 整个区块数据的字节数组
MixinS22PacketMultiBlockChange private ChunkCoordIntPair field_148925_b; @Shadow
MixinS22PacketMultiBlockChange private BlockPacketInfo[] blockPackets; @Unique
MixinS23PacketBlockChange private int field_148887_a; @Shadow x
MixinS23PacketBlockChange private int field_148885_b; @Shadow y
MixinS23PacketBlockChange private int field_148886_c; @Shadow z
MixinS23PacketBlockChange public Block field_148883_d; @Shadow block
MixinS23PacketBlockChange public int field_148884_e; @Shadow metadata
MixinS26PacketMapChunkBulk private byte[][] field_149260_f; @Shadow 每个内嵌 chunk 的原始数据
MixinS26PacketMapChunkBulk private int[] s21Sizes; 无注解(既非 @Shadow 也非 @Unique) mixin 私有字段,但按 Mixin 规范应加 @Unique;此处靠 foundation$ 命名的方法前缀区分
client/MixinChunk public Map<ChunkPosition, TileEntity> chunkTileEntityMap; @Shadow
client/MixinChunk public World worldObj; @Shadow
client/MixinChunk private ExtendedBlockStorage[] storageArrays; @Shadow
client/MixinChunk public boolean isLightPopulated; @Shadow
client/MixinChunk public boolean isTerrainPopulated; @Shadow
client/MixinNetHandlerPlayClient private WorldClient clientWorldController; @Shadow

注入点接口

mixins/interfaces/ 下有 2 个接口,把 mixin 新增/改写的能力暴露给非 mixin 代码调用:

接口 方法 实现方
IMixinS22PacketMultiBlockChange void newConstructor(int count, short[] positions, Chunk chunk) MixinS22PacketMultiBlockChange
IMixinS22PacketMultiBlockChange BlockPacketInfo[] getInfos() MixinS22PacketMultiBlockChange
IMixinS23PacketBlockChange void syncBlockPacketInfo(BlockPacketInfo info) MixinS23PacketBlockChange
IMixinS23PacketBlockChange BlockPacketInfo createBlockPacketInfo() MixinS23PacketBlockChange

newConstructor 的声明是唯一走 ASM 转换器链 而非 mixin 本身调用路径的方法——S22ConstructorTransformer 生成 INVOKEINTERFACE 指向它。

数值

数值 值
mixin 类总数 6
EARLY 阶段数 6
LATE 阶段数 0
@Overwrite 数量 9(#1、2、4、5、6、7、13、14 共 8 处 + 构造重写由 ASM 承担)
@Inject 数量 2(#8、#12)
@ModifyVariable 数量 3(#9、#10、#11)
Side.CLIENT 组内 mixin 数 2
Side.BOTH 组内 mixin 数 4

相关条目