部件替换修饰符 ModTGregPartReplacement
vexatos.tgregworks.integration.iguanatweakstconstruct.ModTGregPartReplacement。
只有装了 IguanaTweaksTConstruct 且其 ToolPartReplacing 模块启用时才注册,
允许在工具台/改装台里把已用材料 A 的部件换成材料 B 的部件而不损失整把工具。
源码头部注释:“Copied from IguanaTweaksTConstruct with only minor changes. All credits go to their authors. Copied with permission from boni.”
注册
TGregworks.init → IntegrationITT.init():
if (IguanaTweaksTConstruct.pulsar.isPulseLoaded("ToolPartReplacing"))
ModifyBuilder.registerModifier(new ModTGregPartReplacement());
构造是 super(new ItemStack[0], 0, "")——getIdentifier() 是空字符串,
所以这个修饰符在 NEI/工具台里没有可显示的名字(这是"minor changes"之一:
它复用了父类的无标识构造,不改 canModify 语义)。addMatchingEffect 也是空实现。
这是本 mod 在 init 阶段注册的修饰符,与 修复修饰符 的
postInit 注册互不影响(两者可同时存在)。
canModify 的 8 道门
if (!(itemStack.getItem() instanceof ToolCore)) return false; // ① 必须是工具
NBTTagCompound tags = itemStack.getTagCompound().getCompoundTag("InfiTool");
if (tags.getBoolean("Special")) return false; // ② 特殊工具不可换
if (tags.getInteger("Damage") > 0) return false; // ③ 必须无损伤
if (Config.disableStoneTools) { … } // ④ 见下
ToolRecipe recipe = findRecipe(tool); if (recipe == null) return false; // ⑤ 必须能找到配方
… 遍历 parts …
if (!(item instanceof IToolPart)) return false; // ⑥ 每个输入都得是部件
if (replacementPartItem != null) return false; // ⑦ 只允许换一个
… 判定 partType,不认识就 return false …
if (replacementPartItem == null || partIndex == -1) return false; // ⑧ 至少一个可用部件
④ disableStoneTools
IguanaTweaksTConstruct 的 Config.disableStoneTools 为真时,若工具的
头 / 手柄 / 配件 / 附加件任一当前材料 ID == 1(石头),直接拒绝——
源码注释说明原因:“we have to prevent exchanging that with disabled stone tools because otherwise
the replacement-logic would not be able to obtain necessary information and crash.”
手柄位与配件位额外豁免 TinkerWeaponry.bowstring / TinkerWeaponry.partArrowShaft /
TinkerWeaponry.fletching(这些不是"材料部件",不能拿它们去比材料 ID)。
⑤ findRecipe 的限制
for (ToolRecipe r : ToolBuilder.instance.combos)
if (r instanceof TGregToolRecipe && r.getType().getClass().equals(tool.getClass()))
return r;
return null;
只接受 TGregToolRecipe,且只按 getType().getClass() 匹配工具类型、
返回第一个命中项。后果:
- 只能替换用本 mod 工具配方表 造出来的工具;
- 工具类型相同的多个配方会串——例如锤与战斧都用
TinkerTools.hammerHead系列但ToolCore类不同,源码靠getClass()区分;可是一旦两类共用同一个ToolCore类就会取错。
⑥⑦ 材料 ID 提取
int newMatId = ToolBuilder.instance.getMaterialID(parts[partIndex]);
int oldMatId = getToolPartMaterial(tags, partType);
int modifiers = tags.getInteger("Modifiers");
for (int i = partIndex; i > 0; i--) {
partType = detectAdditionalPartType(recipe, replacementPartItem, partType);
oldMatId = getToolPartMaterial(tags, partType);
}
for (int i = partIndex; i > 0; i--) 沿槽位下标回退(partIndex 是网格位置,不是槽位类型),
用来处理"同一个部件出现在多个槽位"的情况(如锤的大板同时是配件和附加件)。
降级保护:不能把有经验的头换成 0 级头
if (partType == HEAD) {
if (TConstructRegistry.getMaterial(newMatId).harvestLevel == 0 && LevelingLogic.hasBoostXp(tags))
return false;
}
IguanaTweaksTConstruct 的升级经验不允许因降级而白给。
修饰符槽位守恒
if (hasExtraModifier(oldMatId)) modifiers--; // 源码注释:paper or thaumium. sadly hardcoded.
if (hasExtraModifier(newMatId)) modifiers++;
if (modifiers < 0) return false;
hasExtraModifier 走 IguanaTweaksTConstruct 的静态实现,该实现是硬编码的
(源码自己吐槽 sadly hardcoded),本 mod 无法扩展。
纸/秘银这类"额外吃一个修饰符槽"的材料换走时释放槽位,换入时占用。
⚠️ 源码注释指出一个已知缺陷:“This probably doesn’t work right for bolts (which replace two parts at a time).” ——弩箭是双材料部件,槽位收支算不准。
同材料特判
if (newMatId == oldMatId) {
if (tool == TinkerWeaponry.boltAmmo && replacementPartItem instanceof DualMaterialToolPart) {
int newHeadMatId = ((DualMaterialToolPart) replacementPartItem).getMaterialID2(parts[partIndex]);
int oldHeadMatId = getToolPartMaterial(tags, HEAD);
return newHeadMatId != oldHeadMatId;
}
return false;
}
手柄材料相同但箭头材料不同时,允许替换弩箭;否则一律拒绝(同材料替换无意义)。
输入物品的隐式替换
if (tool == TinkerWeaponry.arrowAmmo) {
if (item == Items.reeds || item == Items.blaze_rod || item == Items.bone || item == Items.stick)
item = TinkerWeaponry.partArrowShaft;
}
if (item == Items.bone || item == Items.stick) item = TinkerTools.toolRod;
木棍/骨头(箭上还包括芦苇与烈焰棒)被隐式当作箭杆 / 手柄。
modify 的重复计算
modify 里把 canModify 的整套判定重跑一遍(源码注释 “do all the stuff that we did in
canModify again to obtain the necessary information :-”),只为拿到 partType,
然后 exchangeToolPart(tool, tags, partType, parts[partIndex], itemStack)。