MixinBlock
基本信息
| 属性 | 值 |
|---|---|
| Mixin 目标 | net.minecraft.block.Block |
| Phase | EARLY |
| 角色 | 把 Block.harvestTool[] / harvestLevel[] 大小 16 的固定数组换成 HashMap |
| 依赖 | it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap + Int2ObjectOpenHashMap |
解决的问题
Forge 给 Block 加了一个"按 metadata 指定挖掘工具+等级"的系统:
- vanilla + Forge:
String[16] harvestTool+int[16] harvestLevel,每个 Block 实例预分配 16 个槽(即使只用了 1 个)。 - NEID 把 metadata 上限扩到 16-bit (65536),如果沿用 Forge 方案,单个 Block 实例就是 65536 个 String + 65536 个 int → 数十 GB 级内存。
NEID 改用 HashMap 仅在用到的 metadata 上分配,节省 GB 级内存(注释中 Cleptomania 写 “classdump of full GTNH shows nothing else ASMing/mixin to this”)。
注入字段
@Unique private String neid$defaultHarvestTool = null; // 没有 metadata 时的默认工具
@Unique private int neid$defaultHarvestLevel = -1; // 默认挖掘等级(-1 = 不限制)
@Unique private Int2ObjectOpenHashMap<String> harvestToolMap = new Int2ObjectOpenHashMap<>();
@Unique private Int2IntOpenHashMap harvestLevelMap = new Int2IntOpenHashMap<>();
@Shadow(remap = false) private String[] harvestTool = null; // 屏蔽原版字段(防止误读)
@Shadow(remap = false) private int[] harvestLevel = null;
@Overwrite 方法
| 方法 | 行为 |
|---|---|
setHarvestLevel(String toolClass, int level) |
设默认工具/等级(写入 neid$defaultHarvest* 字段) |
setHarvestLevel(String toolClass, int level, int metadata) |
设指定 metadata 的工具/等级(写入 HashMap) |
getHarvestTool(int metadata) |
harvestToolMap.getOrDefault(metadata, neid$defaultHarvestTool) |
getHarvestLevel(int metadata) |
harvestLevelMap.getOrDefault(metadata, neid$defaultHarvestLevel) |
isToolEffective(String type, int metadata) |
先硬编码三例外:pickaxe + (redstone_ore | lit_redstone_ore | obsidian) → false;否则查 getHarvestTool(metadata) 是否等于 type |
兼容性
- API 兼容:所有 public 方法签名一致,外部 mod 沿用 Forge API 即可。
- 反射/ASM/私有访问的破坏:直接读
Block.harvestTool/harvestLevel私有字段的代码会拿到 null/-1。注释明确指出 GTNH 全量 classdump 没有发现此类访问方。
相关条目
- MixinBlockFire - 兄弟类,用
MAX_BLOCK_ID数组扩展 - Constants -
MAX_BLOCK_ID = 32767