事件处理器
PlayerEventHandler(core/event/PlayerEventHandler.java,149 行)是本 mod 唯一不依赖 mixin 的功能入口,通过 MinecraftForge.EVENT_BUS.register(new PlayerEventHandler()) 注册于 ProxyCommon.init(core/proxy/ProxyCommon.java:56)。它包含 3 个 @SubscribeEvent 处理器,其中两处实现了未在物品描述或研究中体现的隐藏机制。
1. onPlayerInteract(PlayerInteractEvent)
:37-81,三段互不相干的逻辑:
1a. 徒手拆隐形方块
未戴 IRevealer 护目镜时右键 Metaphysical Brick / Metaphysical Rose:
if (event.action == RIGHT_CLICK_BLOCK && !(BlockMetaphysical.hasGoggles(player))) {
Vec3 vec = BlockHelper.getCentralCoords(event.x, event.y, event.z, event.face);
if (blockAt(vec) instanceof BlockMetaphysical && player.getHeldItem() != null) {
worldObj.setBlock(..., Blocks.air); // 直接删方块
player.setItemInUse(heldItem, heldItem.getMaxItemUseDuration());
}
}
这是绕过「戴眼镜才可见」限制的后门:准隐形方块可以被直接右键删除,且无任何物品掉落。
1b. 深红研究解锁(有意设计)
右键时手持 ConfigItems.itemEldritchObject 且 getItemDamage() == 1,若玩家未完成 @CRIMSON_PHILOSOPHY:
PacketHandler.INSTANCE.sendTo(new PacketResearchComplete(rname), (EntityPlayerMP) player);
Thaumcraft.proxy.getResearchManager().completeResearch(player, rname);
这不是后门。CRIMSON_PHILOSOPHY 在 ResearchHelper.loadCrimsonResearch() 中注册时带 setSpecial() + setStub() + setHidden()(research/ResearchHelper.java:263-273),即刻意做成不可见、不可手动完成的事件型研究,本处理器就是它唯一的完成途径。详见 研究树。
1c. 法杖右键 Flux 预扫描
RIGHT_CLICK_BLOCK 且手持 ItemWandCasting 时,扫描点击点周围 5×5×5 的 BlockFluxGas / BlockFluxGoo,命中即 player.setItemInUse(stack, Integer.MAX_VALUE)。这是 Taint Capping 的触发前提 —— 让 useItem 状态持续足够长,PlayerUseItemEvent.Tick 才会反复执行。
2. onUseItem(PlayerUseItemEvent.Tick)
:82-124。Taint Capping 的全部实现,详见 Taint Capping。5×5×5 扫描,随机要素注入(0–99),约 2/50 概率清除 Flux 方块。
3. onAttackEntity(AttackEntityEvent)—— 隐藏的 Vis 近战
:127-148。未被任何 Augmentation NBT 触发,纯靠法杖自身的 Vis 存量判定:
if (!(event.target instanceof EntityLivingBase target)) return;
if (stack == null || !(stack.getItem() instanceof ItemWandCasting wand)) return;
int aspectCount = 0;
for (Aspect aspect : wand.getAllVis(stack))
if (aspectList.getAmount(aspect) > 15) ++aspectCount; // 存量 > 15 才计数
if (aspectCount >= 6) {
target.attackEntityFrom(DamageSource.magic, 4.0f);
for (Aspect aspect : aspectList.getAspects())
wand.consumeVis(stack, player, aspect, 15, false);
worldObj.playSoundAtEntity(player, "thaumcraft:zap", 1.0f, 1.1f);
}
法杖敲生物:若法杖上有 ≥ 6 个要素各自存量 > 15,每次攻击造成 4 点 DamageSource.magic 伤害,并从每一个要素扣 15 点 Vis,播放 thaumcraft:zap 音效(音调 1.1)。
数值
| 处理器 | 关键数值 |
|---|---|
| onPlayerInteract 1a | 护目镜判定 = hasGoggles;方块直接置 Blocks.air;无掉落 |
| onPlayerInteract 1b | 物品 = itemEldritchObject meta 1;研究 = @CRIMSON_PHILOSOPHY |
| onPlayerInteract 1c | 扫描 5×5×5(i/j/k ∈ [-2,2]);setItemInUse(stack, Integer.MAX_VALUE) |
| onUseItem | 5×5×5;Vis 0–99;Entropy 约 21%;无效约 11%;清方块约 2/50 |
| onAttackEntity | 要素阈值 6;单要素存量阈值 > 15;伤害 4.0F(DamageSource.magic);每要素扣 15;音效 thaumcraft:zap 1.0f / 1.1f |
源码缺陷
- onAttackEntity 在客户端也会执行伤害计算。
AttackEntityEvent双端触发,但代码只判event.target instanceof EntityLivingBase,未做worldObj.isRemote检查。客户端会重复调用consumeVis与attackEntityFrom(客户端attackEntityFrom通常不生效,但consumeVis会改本地 NBT,服务端包随后覆盖)。 - 1a 的隐形方块后门:准隐形机制(见 Metaphysical Brick)的整个意义是「看不见就摸不着」,但本处理器允许无眼镜直接右键删除,且要求
player.getHeldItem() != null(不能空手删)—— 这是未文档化的绕过路径。 - 1a 只删方块不给物品:
worldObj.setBlock(..., Blocks.air)不走dropBlockAsItem,两个 metaphysical 方块无掉落。 - 1b 缺服务端二次校验:仅
!player.worldObj.isRemote一道判断,物品 meta 判定在双端都做,客户端会重复构造PacketResearchComplete。 - onAttackEntity 的
getAllVis调用两次(:135与:140),每次都新建AspectList;getAspectsWithRoom语义未用,可能允许扣成负值。 onAttackEntity与 Contact Discharge 名称高度相关但无代码关联 —— 后者是无实现的空改装,二者易被误认为同一机制。
相关条目
- Taint Capping - onUseItem 的完整实现
- Flux Wand Trigger - 被本处理器空实现的原生 Flux 触发器
- Metaphysical Brick - 1a 的作用目标
- Contact Discharge - 名称相近但无实现的空改装
- 研究树 - 1b 涉及的深红研究分支