Applied Energistics 2 Integration
BetterBuildersWands 与 Applied Energistics 2(AE2)集成,支持 ME 网络库存查询和物品数量同步。
触发条件
此功能仅在检测到 AE2 模组加载时激活:
if (Loader.isModLoaded("appliedenergistics2")) {
// 注册 AE2 相关网络包
}
BasicPlayerShim 在构造时把 aeEnabled 固定为 Loader.isModLoaded("appliedenergistics2")。
MEHandler 里的所有方法都标注了 @Optional.Method(modid = "appliedenergistics2"),
未安装 AE2 时这些代码被 Forge 剔除。
网络包
SynchronizeAEItemQuantity
让客户端知道 ME 网络里有多少目标方块 —— 客户端本身没有 AE2 网格访问权。
| 包类 | discriminator | 处理端 | 方向 | 载荷 |
|---|---|---|---|---|
SyncServer |
1 |
Side.SERVER |
客户端 → 服务端 | ItemStack(ByteBufUtils.writeItemStack) |
SyncClient |
2 |
Side.CLIENT |
服务端 → 客户端 | int size(存入 BasicPlayerShim.AEItemSize) |
Side.SERVER/Side.CLIENT指的是处理端所在的一侧。SyncServer里的 “Server” 指的是"发给服务端处理的请求"。
服务端 SyncServer.onMessage 的回复逻辑:
| 情况 | 回复 |
|---|---|
取不到无线终端 GUI 对象,或 stack == null |
SyncClient(0) |
obj.rangeCheck() 为假(超出范围) |
SyncClient(0) |
| 网格中匹配到物品 | SyncClient(min(found.getStackSize(), Integer.MAX_VALUE)) |
| 未匹配到 | SyncClient(0) |
客户端缓存策略
BasicPlayerShim.getAEItem 的客户端分支:
| 情况 | 行为 |
|---|---|
| 查询的物品变了 | 立即发 SyncServer,返回上一次缓存的 AEItemSize |
物品没变,且 worldObj.getTotalWorldTime() % 10 == 0 |
每 10 个世界刻(0.5 秒)发一次 |
| 玩家身上没有任何无线终端 | AEItemSize = 0 |
因为回复是异步的,第一次查询某个新物品时返回的是上一次的缓存值(可能是 0), 所以"刚切换目标方块时放不出方块"是预期行为,等 0.5 秒后重试即可。
MEHandler
MEHandler.java 负责定位玩家的 AE2 无线终端,并做权限/电量校验:
终端搜索顺序
| 顺序 | 来源 |
|---|---|
| 1 | 主背包 player.inventory(36 格) |
| 2 | Baubles 饰品栏(需安装 Baubles,见 Baubles 集成) |
命中的槽位会传给 getTerminalGuiObject(item, player, x, y),其中
主背包命中传 y = 0、饰品栏命中传 y = 1(影响 AE2 GUI 的定位行)。
取到 GUI 对象后的校验链
| 校验 | 不通过的后果 |
|---|---|
Platform.isClient()(必须服务端执行) |
返回 null |
item.getItem() instanceof IWirelessTermHandler |
返回 null |
handler.canHandle(item) |
返回 null |
registry.isWirelessTerminal(item) |
返回 null |
handler.getEncryptionKey(item) 非空 |
返回 null |
key 对应的 ILocatable 是 TileSecurity |
返回 null |
handler.hasPower(player, 1000F, item) |
返回 null |
obj.rangeCheck() |
数量按 0 计 |
⚠️ 必须把无线终端绑定到一个 AE2 安全站(Security Station), 否则查不到
TileSecurity,整个 AE2 集成对本玩家失效。 还要消耗 1000 AE 的检查功率。
与材料扣取的联动
BasicPlayerShim.countItems 会把 AE2 网络数量累加进总数(SIMULATE,不真扣):
if (aeEnabled) total += getAEItem(itemStack, Integer.MAX_VALUE - total, false);
return itemStack.stackSize > 0 ? total / itemStack.stackSize : 0;
BasicPlayerShim.useItem 则优先从 AE2 真扣(MODULATE):
if (aeEnabled) {
toUse += getAEItem(itemStack, needUse, true);
if (toUse >= needUse) return needUse;
}
getAEItem 的服务端分支还要求 EXTRACT 权限:
if (MEHandler.securityCheck(player, obj.getGrid(), SecurityPermissions.EXTRACT)) {
… inventory.extractItems(…, Actionable.MODULATE, new PlayerSource(player, obj)) …
}
AE2 在材料来源中的优先级(useItem 顺序):
| 优先级 | 来源 |
|---|---|
| 1 | Ztones ofanix(目标是圆石时直接返回全额,不扣任何东西) |
| 2 | AE2 网络(真扣) |
| 3 | 背包(按 slotPriority 反向扣,热键栏留到最后) |
| 4 | Botania IBlockProvider(见 Botania 集成) |
使用场景
当玩家使用魔杖放置需要从 ME 网络提取大量相同方块的建筑时:
getProperItemStack取出目标物品(若装了 Backhand 则取副手)countItems= 背包 + Botania 花盆 + AE2 网络,三者求和numBlocks = min(wand.getMaxBlocks(itemstack), countItems)—— 魔杖等级与 AE2 库存取小- BFS 搜索出
numBlocks个坐标 useItem先从 AE2 抽,AE2 不够再从背包抽
⚠️ 因为取
min,AE2 库存再大也不会突破魔杖等级上限 (Diamond Wand 封顶 1561,Unbreakable Wand 各 meta 见 魔杖等级系统)。AE2 集成的价值在于不受背包容量限制, 而不在于提高上限。
相关条目
- Baubles 集成 - 无线终端放在饰品栏时的查找
- 网络协议 - 通道名与包注册表
- Botania 集成 -
countItems/useItem的另一个数据源 - BFS 方块扩展算法 -
countItems如何决定搜索上限 - 魔杖等级系统 -
min的另一半