Fake Player

基本信息

属性 值
类 FakePlayerLogic(tmechworks/lib/player/FakePlayerLogic.java,22 行)
父类 net.minecraftforge.common.util.FakePlayer
使用者 Drawbridge / Long Drawbridge / Advanced Drawbridge
GameProfile 名 Player.Drawbridge
UUID null(new GameProfile(null, "Player.Drawbridge"))
惰性创建 是(initFakePlayer())

用途

Drawbridge 用它作为放置方块时 onBlockPlaced 看到的「玩家」,使受保护方块(ForgeProtection)、统计与事件系统认为方块是被玩家放置而非凭空出现。

实现

DrawbridgeLogic(blocks/logic/DrawbridgeLogic.java):

private FakePlayerLogic fakePlayer = null;          // 字段,序列化时不写入

private void initFakePlayer() {
    fakePlayer = new FakePlayerLogic(new GameProfile(null, "Player.Drawbridge"), this);
}

fakePlayer 的创建时机是惰性的(每次 updateEntity 放置前调 initFakePlayer()),而非在 validate() / onChunkLoad 中。源码注释明确说明原因:

Because of some weird shit, creating the FakePlayer in validate() causes the TileEntity to be created twice.

setFakePlayerRotation() 在放置前把假玩家的 yaw / pitch 对齐 Drawbridge 当前的 direction。

数值

数值 值
类行数 22
GameProfile 名 Player.Drawbridge
GameProfile UUID null
字段 logicPos(ChunkCoordinates,构造时快照 TE 的 xyz)
getPlayerCoordinates() 返回构造时快照的 logicPos(非实时)
序列化 不写入 NBT(无 writeToNBT / readFromNBT 覆写)
创建时机 惰性,initFakePlayer()
生命周期 区块卸载 / TE 失效后被 GC

交互

触发 行为
Drawbridge 放置方块 调 initFakePlayer() 确保存在 → setFakePlayerRotation() → placeBlockAt(..., fakePlayer, ...)
区块卸载 invalidate() 置 fakePlayer = null(源码在 updateEntity 的 isInvalid() 检查中)
重载区块 从 NBT 恢复,fakePlayer 仍为 null,下次放置时惰性重建

源码缺陷

  • UUID 为 null(new GameProfile(null, "Player.Drawbridge")):FakePlayer 继承自 EntityPlayer,其 getGameProfile().getId() 在 Forge 1.7.10 中可能被用于权限与统计查询。FakePlayerFactory 官方实现会 UUID.randomUUID() 补齐,此处只给了名字。当前靠惰性创建 + invalidate() 置空规避了主要问题,但若两个不同位置的 Drawbridge 在同一 tick 各自重建,会得到两个 UUID 为 null 的同名 profile,某些按 UUID 索引的统计/权限表可能冲突。
  • logicPos 是构造时快照(FakePlayerLogic.java:16):new ChunkCoordinates(te.xCoord, te.yCoord, te.zCoord) 只在构造时读一次。若 TE 被移动(FakePlayer 理论上支持 setPosition),getPlayerCoordinates() 返回的仍是旧坐标。源码无 setPosition 覆写,故当前 TE 不移动则无害。
  • 未覆写 getPlayerCoordinates() 的实时语义:其他代码若依赖该方法获取当前位置会读到陈旧值。
  • 无 NBT 序列化:设计正确(假玩家本就不该持久化),但若将来需要 FakePlayer 的权限设置(Forge 的 fakePlayer.addPermission)会无处存储。
  • 无权限授予:未调用 fakePlayer.addPermission(...) 任何节点,因此**ForgeProtection 保护的方块仍会阻止 Drawbridge 放置**(ForgeProtection.canPlayerEdit 查权限节点)。这实际上是一道「保护」而非缺陷,但源码无注释说明,玩家容易困惑「为什么我的 Drawbridge 放不下被保护的方块」。
  • GameProfile 每次重建都新建对象:区块反复加载会持续分配 GameProfile(含内部 PropertyMap),无复用。

相关条目