Backhand 集成
BetterBuildersWands 集成 xonin 的 Backhand 模组,允许把副手中的方块 当作魔杖的材料,从而在不占用快捷栏的情况下批量放置。
触发条件
源码中所有入口都用运行时类检测:
if (Loader.isModLoaded("backhand")) { … }
WandWorker.getProperItemStackBackhand 标注了 @Optional.Method(modid = "backhand"):
@Optional.Method(modid = "backhand")
public static ItemStack getProperItemStackBackhand(IPlayerShim player) {
return BackhandUtils.getOffhandItem(player.getPlayer());
}
这是 Forge 的**可选依赖(optional dependency)**声明:Backhand 不在时 该方法被剔除,调用点也不会被执行,因此未安装 Backhand 时本 mod 正常工作。
行为一:材料来源改为副手
WandWorker.getProperItemStack() 先查副手,优先级高于被点中的方块:
boolean usedBackhand = false;
if (Loader.isModLoaded("backhand")) {
ItemStack itemStack = getProperItemStackBackhand(player);
if (itemStack != null && itemStack.getItem() instanceof ItemBlock) {
Block offhandBlock = ((ItemBlock) itemStack.getItem()).field_150939_a;
if (offhandBlock != null && offhandBlock != Blocks.air) {
block = offhandBlock;
meta = itemStack.getItemDamage();
usedBackhand = true;
}
}
}
if (!usedBackhand) { …查自定义映射 / 精确匹配 / 等效物品… }
| 条件 | 结果 |
|---|---|
副手是 ItemBlock 且方块不是空气 |
完全无视点中的方块,改用副手方块作为材料和目标 |
| 副手是其它物品 / 为空 / 是空气 | 回退到正常逻辑(点中的方块 → 映射 → 精确 → 等效) |
usedBackhand 为真时会跳过自定义映射查询 —— 也就是说副手方块
不会经过 forced_blocks 映射。
行为二:临时映射(ItemBasicWand.getCustomMapping)
这是一个容易忽略的独立分支:
public static ICustomMapping getCustomMapping(IWorldShim worldShim, IPlayerShim playerShim, Point3d clickedPos) {
if (Loader.isModLoaded("backhand")) {
ItemStack backhandItem = WandWorker.getProperItemStackBackhand(playerShim);
if (backhandItem != null && backhandItem.getItem() instanceof ItemBlock) {
Block offhandBlock = ((ItemBlock) backhandItem.getItem()).field_150939_a;
int meta = backhandItem.getItemDamage();
ICustomMapping existing = BetterBuildersWandsMod.instance.mappingManager.getMapping(offhandBlock, meta);
if (existing != null) return existing; // 复用已注册映射
return new CustomMapping(offhandBlock, meta, backhandItem, offhandBlock, meta); // 临时 1:1 映射
}
}
… 正常的按点击方块查表 …
}
| 情况 | 返回 |
|---|---|
| 副手方块已注册过映射 | 返回注册表里那条(可能 shouldCopyTileNBT = true) |
| 副手方块未注册 | 临时构造 1:1 映射,shouldCopyTileNBT = false |
| 没装 Backhand | 按被点中的方块 + metadata 查表 |
因为这条临时映射的 shouldCopyTileNBT 是 false,通过副手放置不会复制
TileEntity 的 NBT,与 Forestry / ArchitectureCraft 的正式映射行为不同。
行为三:BFS 过滤中的额外校验
WandWorker.shouldContinue() 里多了一道针对副手方块的放置校验:
if (Loader.isModLoaded("backhand")) {
ItemStack backhandItem = WandWorker.getProperItemStackBackhand(player);
if (backhandItem != null && backhandItem.getItem() instanceof ItemBlock) {
if (!((ItemBlock) backhandItem.getItem()).field_150939_a
.canPlaceBlockAt(world.getWorld(), x, y, z))
return false;
}
}
即:副手方块在每个候选位置都必须通过 canPlaceBlockAt,
否则该点被丢弃(且不再向它扩展)。
行为四:消耗改为扣副手
WandWorker.placeBlocks() 把 needItem 换成副手物品:
ItemStack needItem = sourceItems.copy();
if (Loader.isModLoaded("backhand")) {
ItemStack backhandItem = WandWorker.getProperItemStackBackhand(playerShim);
if (backhandItem != null && backhandItem.getItem() instanceof ItemBlock) {
needItem = backhandItem.copy();
}
}
Block targetBlock = Block.getBlockFromItem(needItem.getItem());
注意扣材料的动作仍然是 playerShim.useItem(needItem, …),即从
主背包里扣 —— needItem 只作为"要扣什么/放什么"的描述。
副手在此只扮演"指定建造目标"的角色,不直接提供材料
(材料仍需来自背包、Botania 或 AE2)。
BasicPlayerShim 的 slotPriority 注释 Inventory > Hotbar > Backhand
也印证了这一顺序:主背包优先扣,热键栏最后扣。
使用场景
装好 Backhand 后,把方块放在副手、魔杖拿在主手右键任意方块,
即可在副手方块的空位上批量铺开 —— 主手快捷栏不会被材料占掉。
/wandOops 撤销同样适用(见 BFS 方块扩展算法)。
相关条目
- BFS 方块扩展算法 -
getProperItemStack/shouldContinue/placeBlocks - Custom Mapping - 正式映射与这条临时映射的区别
- Botania 集成 - 材料的另一来源
- 魔杖物品通用行为 -
IWandItem接口