PlayerHandler

服务端:玩家登录时下发世界种子

基本信息

属性 值
路径 com.github.lunatrius.ingameinfo.handler.PlayerHandler
行数 25(handler 包最短)
注册方 ServerProxy.init(:21)
事件 PlayerEvent.PlayerLoggedInEvent

唯一方法 onPlayerLogin(:14-24)

@SubscribeEvent
public void onPlayerLogin(PlayerEvent.PlayerLoggedInEvent event) {
    if (event.player instanceof EntityPlayerMP) {
        try {
            PacketHandler.INSTANCE.sendTo(
                new MessageSeed(event.player.worldObj.getSeed()),
                (EntityPlayerMP) event.player);
        } catch (Exception ex) {
            Reference.logger.error("Failed to send the seed!", ex);
        }
    }
}
步骤 说明
① instanceof EntityPlayerMP 排除客户端实体
② new MessageSeed(worldObj.getSeed()) 取该玩家所在世界的种子
③ sendTo(msg, player) 只发给这一个玩家
④ catch (Exception) 失败只记日志

关键细节

worldObj 而非 theWorld

用 event.player.worldObj(玩家所在维度的 World), 不是服务器主世界。跨维度时每个维度的种子不同 —— 玩家换维度后会拿到新维度的种子。

⚠️ 但 sendTo 只在登录时发一次(PlayerLoggedInEvent), 换维度不会重新触发。 所以跨维度后 TagWorld 的 seed tag 显示的是登录时那个维度的种子。

为什么不广播

用 sendTo(单个玩家) 而非 sendToDimension, 所以 N 人在线只发 N 条 —— 每玩家每登录 1 次,开销可忽略。 对比 WorldHandler 的每秒全维度广播, 这是本 mod 网络设计里合理的一处。

种子需要网络传输的原因

World.getSeed() 在客户端 WorldClient 上不保证与服务器一致 (客户端世界由服务端分块下发,种子不随区块传输), 所以必须显式下发。

异常处理

catch (Exception ex) 覆盖 sendTo 的所有失败 (含未连接完成的 NetworkRegistry 状态), logger.error("Failed to send the seed!", ex) 保留堆栈。

⚠️ 失败后不重试 —— hasSeed 保持 false,TagWorld 的 seed tag 在整个会话内都拿不到值。

只在服务端注册

ServerProxy(:21)注册本类; 客户端不注册 —— 客户端不需要知道种子从哪来,只接收。

相关