跳到主要内容

相机会话与控制权

同一个客户端同一时间只有一个临时场景持有相机控制权。CameraDirector 协调开场、死亡和其他演出,底层旁观状态则可以在场景播放期间继续更新。

申请与替换

play() 接收单个 Rig,默认生命周期是 PLAYER_LIFE,时长上限为 Integer.MAX_VALUE tick,通常由调用者或有效性条件结束。其重载允许指定 CameraLifetimeplaySequence() 使用序列总时长,生命周期为 SCENE

当前内置优先级为 DEATH_PRIORITY = 100CINEMATIC_PRIORITY = 200。更低优先级的申请被拒绝;相同或更高优先级会替换已有会话,旧会话收到 REPLACED

owner 是控制权记录中的场景标识,建议使用 模组ID:场景名。它不是队列,也不表示同名申请会合并。accepts(priority) 只预判优先级;实际播放仍可能因世界不存在、正在重置或有效性条件不满足而返回 null

保存自己的句柄

把成功取得的 CameraSession 保存在场景控制器中,通过 isActive() 判断是否仍持有控制权。提前结束调用 close(),或用 stop(reason) 指定结束原因。

旧会话被替换后仍可能被某个界面引用,但旧句柄无法释放新会话。扩展清理自己时应关闭自己的句柄;CameraDirector.reset() 会清除整个相机系统和基础旁观状态,属于全局重置路径。

结束回调

CameraEndReason典型来源
COMPLETED序列到达总时长
CANCELLED调用 close()
REPLACED相同或更高优先级会话取得控制权
INVALIDATED有效性条件失效,或玩家重生终止生命期镜头
WORLD_CHANGED世界改变、卸载或退出
MATCH_RESETFPSMatch 客户端比赛状态重置
FAILED运行中的采样、时钟或有效性处理失败

Director 先取消该会话的时钟,再调用结束回调。回调应释放本次场景创建的资源,并允许不同结束原因走同一条清理路径。申请未成功时不应依赖结束回调替你释放申请前创建的资源。

不要在回调中直接清空不属于本次会话的共享字幕、音乐或其他演出状态。尤其要避免旧会话的回调误清掉新会话的字段;可以按会话身份管理资源,或像第一章一样通过句柄的 isActive() 判断显示状态。

世界、重生与旁观

Director 每次处理时会检查客户端世界和有效性条件。valid 应只做轻量状态判断,初次申请时也会调用它。不要让它发包、播放音效或修改比赛状态。

玩家重生会结束 PLAYER_LIFE 会话,SCENE 会话可继续覆盖重生过程;世界变化仍会结束场景。比赛重置也会统一清理会话。

临时场景结束后恢复的是当前基础旁观状态。场景期间队友死亡或旁观目标改变时,不应手动恢复开场前缓存的实体。旁观状态的来源见客户端旁观

绑定后的场景效果

session.onCameraBound(action) 可以在底层相机重新绑定后重新应用场景专属效果,例如实体切换导致 Minecraft 清除的后处理。注册动作不会立即执行;框架检测到绑定版本改变后调用它。该方法设置的是一个回调,多次调用会覆盖前一个。

相机事件和 mixin/camera 已负责应用画面。扩展应围绕 Rig、Policy 和 Session 工作,避免另起一套每帧直接写入相机的控制器。

源码入口:common/client/camera/CameraSession.java