工具类别与有效工具判定

基本信息

属性 值
类型 判定辅助类
涉及类 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 —— 有效工具类别的确定

分两级:

  1. 一级:方块自报。直接取 block.getHarvestTool(metadata)。绝大多数原版与 mod 方块走这一条。

  2. 二级:探测原版工具。当返回 null 且 block.getBlockHardness(...) > 0f 时,用三把木制工具依次试:

    类别字符串 探测物品
    pickaxe Items.wooden_pickaxe
    shovel Items.wooden_shovel
    axe Items.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 问题:

  1. wrench 与 cutter 在 zh_CN.lang 中没有定义,会走 effectiveTool.substring(0,1).toUpperCase() + substring(1) 的回退,显示成 Wrench 与 Cutter(注意 cutter 的英文正式名是 Wire Cutter,回退值与 en_US 不一致)。
  2. scoop 译作"捕蜂网"(bee net),与"scoop/铲勺"的语义不符,疑为误译。

相关条目