工具类别与有效工具判定
基本信息
| 属性 | 值 |
|---|---|
| 类型 | 判定辅助类 |
| 涉及类 | squeek.wailaharvestability.helpers.ToolHelper、squeek.wailaharvestability.helpers.BlockHelper |
| 职责 | 决定 harvestLevel(挖掘等级)、effectiveTool(有效工具类别)、canHarvest(当前手持物能否挖掘)三个量 |
| 初始化 | ToolHelper.init() 于 FMLPostInitializationEvent 调用 |
概述
这两个类回答三个问题,是整个模组判定链的地基:
| 问题 | 回答者 | 返回 |
|---|---|---|
| 这个方块需要什么工具类别? | BlockHelper.getEffectiveToolOf |
String(pickaxe/shovel/axe/…)或 null |
| 这个方块需要几级挖掘等级? | block.getHarvestLevel(meta)(原版方法,模组不包装) |
int,-1 表示无要求 |
| 手上的工具对得上吗? | ToolHelper.isToolEffectiveAgainst |
boolean |
| 手上的工具够等级吗? | ToolHelper.canToolHarvestLevel |
boolean |
| 手上的工具能破坏它吗? | ToolHelper.canToolHarvestBlock |
boolean |
BlockHelper
getEffectiveToolOf —— 有效工具类别的确定
分两级:
-
一级:方块自报。直接取
block.getHarvestTool(metadata)。绝大多数原版与 mod 方块走这一条。 -
二级:探测原版工具。当返回
null且block.getBlockHardness(...) > 0f时,用三把木制工具依次试:类别字符串 探测物品 pickaxeItems.wooden_pickaxeshovelItems.wooden_shovelaxeItems.wooden_axe判定式为
testTool.func_150997_a(block) >= ((ItemTool) testTool.getItem()).func_150913_i().getEfficiencyOnProperMaterial()——即"这把工具能否破坏该方块"与"该工具材质在正确材料上的效率"取比较。第一个命中者胜出。
⚠️
testTools是HashMap<String, ItemStack>,for (Map.Entry ... : testTools.entrySet())的遍历顺序由HashMap决定,不保证是上表的插入顺序。因此对于一个"未声明 harvest tool 但能被多种木制工具破坏"的方块,报出的类别在原理上是不确定的。
isBlockUnbreakable
block.getBlockHardness(world, x, y, z) == -1.0f。用于在 getHarvestability 第 4 步短路,输出一行"暗红 ✘"。
ToolHelper
Tinkers’ Construct 反射(init)
init() 在检测到 TConstruct 加载后,通过反射抓取四个成员:
| 反射目标 | 类型 |
|---|---|
tconstruct.library.tools.HarvestTool |
Class<?> |
tconstruct.library.tools.DualHarvestTool |
Class<?> |
HarvestTool.getHarvestType() |
Method |
DualHarvestTool.getSecondHarvestType() |
Method |
两个 Method 都被 setAccessible(true);成功则 tinkersConstructLoaded = true。捕获到异常直接 return,标志保持 false。
NBT 约定
Tinkers’ Construct 工具通过 NBT 标签 InfiTool 标识,等级存在两个整数键:
| 方法 | NBT 键 |
|---|---|
hasToolTag(ItemStack) |
顶层是否含 InfiTool |
getToolTag(ItemStack) |
getCompoundTag("InfiTool") |
getPrimaryHarvestLevel(NBTTagCompound) |
HarvestLevel |
getSecondaryHarvestLevel(NBTTagCompound) |
HarvestLevel2 |
isToolEffectiveAgainst —— 手持物是否对得上有效工具
两条分支:
- Tinkers’ HarvestTool(
tinkersConstructLoaded && HarvestTool.isInstance(tool.getItem())):反射调用getHarvestType()取主类别;若同时是DualHarvestTool再加getSecondHarvestType()的副类别;返回集合是否contains(effectiveToolClass)。 - 其它物品:
ForgeHooks.isToolEffective(tool, block, metadata) || (...),括号内是:- 物品声明了工具类别(
toolHasAnyToolClass)→ 按类别字符串匹配; - 物品没有声明任何工具类别 → 回退到
tool.getItem().getDigSpeed(tool, block, metadata) > 1.5f,即用 1.5 的挖掘速度阈值近似原版的"有效工具"。
- 物品声明了工具类别(
⚠️ Tinkers 反射分支里任一
invoke抛异常时会e.printStackTrace()并把tinkersConstructLoaded置为false——即模块自禁用,此后所有 Tinkers 工具都走通用分支。
canToolHarvestLevel —— 手持物是否够等级
(TC 工具:max(HarvestLevel, HarvestLevel2) >= harvestLevel)
|| ForgeHooks.canToolHarvestBlock(block, metadata, tool)
双持工具取两个等级里的较大值,即任一材质够等级即可。
canToolHarvestBlock
block.getMaterial().isToolNotRequired() || tool.func_150998_b(block)。func_150998_b 即 Item#canHarvestBlock(Block)。参数 metadata 未被使用。
工具类别查询(薄封装)
getToolClassesOf 直接转发 tool.getItem().getToolClasses(tool);isToolOfClass 是 contains;toolHasAnyToolClass 是 !isEmpty()。
语言文件中的工具类别
工具类别的显示名来自 wailaharvestability.toolclass.<类别>:
| 类别 | en_US | zh_CN |
|---|---|---|
pickaxe |
Pickaxe | 镐 |
shovel |
Shovel | 铲 |
axe |
Axe | 斧 |
chisel |
Chisel | 凿 |
scoop |
Scoop | 捕蜂网 |
crowbar |
Crowbar | 撬棍 |
sword |
Sword | 剑 |
wrench |
Wrench | (缺失) |
cutter |
Wire Cutter | (缺失) |
⚠️ 两处 zh_CN 问题:
wrench与cutter在zh_CN.lang中没有定义,会走effectiveTool.substring(0,1).toUpperCase() + substring(1)的回退,显示成Wrench与Cutter(注意cutter的英文正式名是Wire Cutter,回退值与 en_US 不一致)。scoop译作"捕蜂网"(bee net),与"scoop/铲勺"的语义不符,疑为误译。
相关条目
- WailaHandler 插件与提示栏组装 - 这三个判定量在提示栏中的使用位置
- 采集等级名称解析 -
harvestLevel的名字部分 - 缺失采集信息修正 - 给方块补上 harvest level 的唯一补丁
- 兼容代理 - GT 工具(
GT.ToolStats)与 Tinkers 工具并列的两套 NBT 约定