开发者指南
WARNING
在发布正式版之前,API 可能随时发生破坏性变更。
凭啥让大伙儿用这个?
统一的相机状态管理机制让多种需要修改相机状态的模组得以共存:
- 玩家安装模组时不必再在两种第三人称视角间二选一
- 某些模组不会再霸道地覆盖掉其他模组对相机状态的更改
此外:
- 对于一些简单的视角或修饰效果,不必再费劲研究如何注入到Minecraft以修改相机状态
- 同步支持从 1.20.1 开始的大部分主流 Minecraft 版本
基本概念
相机状态
包括位置、旋转、投影方式、透视视野角度、正交画面高度等信息。
视角
- 视角可以通过SPI注册,也可以在运行时被动态注册和卸载
- 视角具有id、名称等恒定的元数据
- 视角的行为包括在渲染帧中更新相机状态、在解析时报告可用性,以及一些生命周期事件回调
工作原理
Perspective API 将“选择视角”和“计算相机状态”分为两个相互配合的阶段。解析阶段只决定 当前应使用哪个视角,不直接写入相机;渲染阶段在解析结果上计算最终相机状态。
解析当前视角
每次主相机渲染更新之前,API 按覆盖链的优先级解析当前视角:
- 覆盖链按优先级从高到低求值。
- 每个覆盖项返回一个视角 ID,或返回
null表示跳过。 - 未注册、不可用的视角会被跳过,继续求值后续覆盖项。
- 如果没有有效候选,使用默认视角作为安全回退。
当前视角发生变化时,API 依次处理旧视角的停用、新视角的激活,并根据两侧视角的 allowTransitionOut() 和 allowTransitionIn() 决定是否启动过渡。同时,当前视角的 BaseType 会映射到原版 CameraType,以便原版继续执行依赖相机类型的行为。
可用性检查(isAvailable())和覆盖项求值在解析期间执行,API 不会按客户端游戏刻调度它们。 如果你的实现需要每刻更新状态,请订阅自己的加载器客户端刻事件,并在回调中返回缓存值。
渲染帧:计算最终相机状态
原版相机完成基础设置后,API 读取原版的位置和旋转,并以最近一次有效的原版 FOV 作为初始 状态。随后按以下顺序处理:
原版相机状态
-> 当前视角 computeCameraState
-> PerspectiveModifier 链
-> 视角切换过渡
-> 写回相机,向世界投影提供最终设置
-> 最终状态回调 afterCameraStateResolved具体过程如下:
computeCameraState在原版状态上建立当前视角的目标状态。- 视角和每个修饰器的结果都会经过有效性检查;失败的回调或无效状态会恢复到该阶段 之前的状态,不阻断后续管线。
- 修饰器按优先级从小到大依次作用于同一个目标状态。
- 若当前切换允许过渡,过渡算法根据固定时间窗口处理位置、旋转、FOV 和正交视野高度; 投影模式直接使用目标值。
- 最终位置和旋转写回原版
Camera;随后世界渲染相关事件读取最终投影设置,应用正交投影 或保持透视投影。 - 调用
afterCameraStateResolved,此时回调接收到的是已经完成修饰和过渡、实际写入相机的 状态,适合依赖最终视点的射线检测和命中测试。 - 主相机更新完成后,API 发布一个独立的最终状态快照,供
PerspectiveAPI.getPreviousCameraState()和下一次过渡使用。
FOV 的原版计算可能早于或晚于相机变换。API 在 FOV 注入点缓存本次有效的原版值,供下一次 相机状态计算使用;当前 FOV 调用则返回本帧管线已经计算出的最终值。正交投影的设置则由 最终状态写入世界渲染、剔除和相机投影相关上下文,界面和手持物等非世界投影不受影响。
回调失败与 API 禁用
扩展回调的普通异常会被隔离并记录,视角、修饰器和过渡产生的无效状态会恢复到安全快照。 Perspective API 被禁用时,视角解析、相机修改、FOV 修改和投影修改都会停止;已注册的视角、 覆盖项和修饰器保留,重新启用后继续参与解析。