ExtraContentApi
谱面特效表演原语通道(接缝 ):宿主游玩上下文经 ChartRuntimeContext.extraContent() 注入,模组可在 parser 的 apply 阶段或游玩期,触发与谱面 extraContent 段同一执行体的轨道/假轨/假音符表演效果(执行体为宿主 TrackRenderer 的每轨状态与假实体实例),因此表现与谱面写法逐像素同管线。方法按「意图」命名,不映射谱面 JSON 类型名。相关类型:ChartRuntimeContext、SkinProvider。
通道的共享契约:
- 获取与判空:只在游玩上下文的运行时上下文里非
null;其他上下文返回null。取得后可保存到本局状态,在GameplayTickEvent.Post等回调中复用。 - 两段式时序:每局(
onEnter)新建实例。parser 的apply发生在谱面加载 step0,而轨道布局在 step1 才就绪,因此绑定前的调用进入保序缓冲队列,布局就绪后一次性重放;绑定后的调用直接执行。单次调用独立 try/catch,异常限频告警(5 秒),不拖垮其余调用与游玩流程。 - 立即生效:全部方法无动画。谱面特效的动画分支(
animated/fadeIn)与text渲染项依赖宿主触发引擎的活跃项生命周期,不在本接口内。 - 优先级契约:本通道与谱面
_extra.json动画共享执行体(后写生效)。正常帧序为ExtraContentRenderer.update(谱面动画写)→GameplayTickEvent.Post(模组写);倒带帧为声明面重生 → Post。因此在GameplayTickEvent.Post内每帧重写同一通道 = 确定性最高优先级,倒带期 Post 照发,契约同样成立。 - 纯视觉:判定引擎(判定窗口/判定线/输入映射)不消费这些渲染状态,偏移/旋转/形变/变换写得再激进也不影响判定结果。
- 倒带语义:模组经本通道写入的状态不随暂停/恢复倒带回滚(宿主不保存模组写入的起点快照),倒带后停留在「未来值」。宿主会对谱面声明面做全量重建与逐帧跟随,但不包含模组实时通道的写入;需要随倒带回滚请订阅
RewindEvent自行快照/重建。例外:setNoteTransform按noteId常驻,见该方法的生命周期说明。 - 越界容错:lane / id 越界或目标不存在时静默忽略(宿主可限频告警或打印一行错误),与谱面特效容错口径一致。
方法速览
| 方法 | 用途 |
|---|---|
setLaneAlpha(int, float) | 真轨背景与分隔线透明度 |
setKeyIndicatorAlpha(int, float) | 真轨快捷键框透明度 |
setTrackOffset(float, float) | 轨道区整体 X/Y 偏移 |
setLaneOffset(int, float, float, float) | 单轨 3D 偏移(含 z 深度) |
setLaneRotation(int, float) | 单轨纯视觉旋转(弧度,圆心固定判定线中点) |
setLaneSpeedFactor(int, float) | 单轨流速倍率(可为负) |
setLaneHeight(int, float) | 单轨手动高度延伸 |
setLaneHeightAuto(int) | 启用单轨自动高度 |
setLaneScale(int, float, float) | 单轨渲染缩放(pivot = 几何中心) |
setLaneScaleAuto(int) | 复位单轨缩放到 (1,1) |
setLaneSkew(int, float, float) | 单轨线性斜切 |
setLaneSkewAuto(int) | 复位单轨斜切到 0 |
setLaneArc(int, float, float, float) | 单轨圆弧形变 |
setLaneArcAuto(int) | 复位单轨弧线到 0 |
setTrackTilt3D(double) | 轨道区 3D 透视倾斜(度) |
setTrackTilt3DAuto() | 复位 3D 倾斜到正交 |
setNoteAlpha(int, float) | 单轨全部音符透明度 |
setUiAlpha(float) | 非轨道 HUD 透明度 |
createFakeTrack(int, int, float) | 创建/覆盖假轨道 |
setFakeTrackTransform(int, float, float, float, float, float, float) | 假轨位置/透明度/缩放/旋转一次写入 |
setFakeTrackAlpha(int, float) | 假轨背景与键框透明度 |
setFakeTrackRotation(int, float) | 假轨旋转(保留圆心) |
setFakeTrackRotation(int, float, String) | 假轨旋转 + 圆心模式 |
setFakeTrackSkew(int, float, float) | 假轨斜切 |
setFakeTrackArc(int, float, float, float) | 假轨弧线 |
setFakeTrackHeight(int, float) | 假轨高度延伸 |
setFakeTrackKeyIndicatorAlpha(int, float) | 假轨快捷键框透明度 |
createFakeNote(int, int, String, Long, float) | 创建/覆盖假音符 |
setFakeNoteAlpha(int, float) | 假音符透明度 |
setNoteTransform(long, float, float, float, float, float, float, float) | 真音符自身 3D 变换 |
clearNoteTransform(long) | 清除音符自身变换 |
获取通道
@Override
public void apply(Object parsed, ChartRuntimeContext ctx) {
ExtraContentApi api = ctx.extraContent(); // 非游玩上下文返回 null
if (api == null) {
return;
}
this.api = api; // 保存到本局状态,供 GameplayTickEvent.Post 使用
api.setLaneAlpha(0, 0.3f);
}以下各方法的示例都假定 api 是已经判空取得的非空通道,并可用在 apply 或游玩期回调中。
真轨道原语
setLaneAlpha(int lane, float alpha)
签名:
void setLaneAlpha(int lane, float alpha);行为:设置 lane(0 起)的轨道背景与分隔线透明度,alpha 由宿主钳制到 0..1。不影响该轨音符与快捷键框(后者见 setKeyIndicatorAlpha)。越界 lane 静默忽略。立即生效、纯视觉。
示例:
api.setLaneAlpha(0, 0.5f);setKeyIndicatorAlpha(int lane, float alpha)
签名:
void setKeyIndicatorAlpha(int lane, float alpha);行为:只设置该轨快捷键框的透明度(0..1 钳制),背景与分隔线不变。谱面 lane_alpha 的 affectKeyIndicator 会同时写两者,本原语用于分别控制。
示例:
api.setKeyIndicatorAlpha(0, 0.0f); // 隐藏快捷键提示,保留轨道背景setTrackOffset(float x, float y)
签名:
void setTrackOffset(float x, float y);行为:整个轨道区域相对默认布局的 X/Y 偏移(画布像素)。绝对写:每次调用同时写 x 与 y 两个分量,只想改一维时要传入另一维的当前值。跟随区域一起移动的是轨道区内容(背景、分隔线、判定线与其中的音符);HUD 不受影响。
示例:
api.setTrackOffset(32.0f, 0.0f);setLaneOffset(int lane, float x, float y, float z)
签名:
void setLaneOffset(int lane, float x, float y, float z);行为:单条真轨的 3D 偏移(lane_pose.x/y/z),以轨道区域为坐标系,叠加在 setTrackOffset 的区域偏移之上。x / y / z 单位均为画布像素;z 沿 +z(屏幕内)为深度,0 = 内容平面。3.0 起包含 z,旧两参调用补 0 即与旧输出逐字节一致。越界 lane 静默忽略。
示例:
api.setLaneOffset(1, 12.0f, -8.0f, 40.0f);setLaneRotation(int lane, float rotationRad)
签名:
void setLaneRotation(int lane, float rotationRad);行为:把整条真轨(背景、分隔线、判定线、快捷键框与音符)作纯视觉旋转,rotationRad 为弧度、顺时针为正(屏幕坐标系)。3.0 起删除 pivot 参数:圆心固定为该轨判定线中点,与 GameStateAccess.setLaneRotation 同口径;需要自定义圆心时改用 EntityPose.rotateZ(deg, pivotX, pivotY) 自绘。判定与输入不受影响。
示例:
api.setLaneRotation(2, (float) Math.toRadians(12.0));setLaneSpeedFactor(int lane, float factor)
签名:
void setLaneSpeedFactor(int lane, float factor);行为:该轨的流速倍率,实际下落速度 = 全局 scrollSpeed × factor;任意 float,负值表示反向下落,宿主不钳制。只改变音符的屏幕运动,判定仍按音符时间进行(纯视觉)。
示例:
api.setLaneSpeedFactor(3, -1.0f);setLaneHeight(int lane, float height)
签名:
void setLaneHeight(int lane, float height);行为:手动设置该轨向判定线反方向(轨道顶端)延伸的高度,单位画布像素,负值按 0 处理,并关闭该轨的自动高度。延伸影响轨道图形与音符出现高度。
示例:
api.setLaneHeight(0, 240.0f);setLaneHeightAuto(int lane)
签名:
void setLaneHeightAuto(int lane);行为:启用该轨自动高度:宿主每帧按轨道旋转与画布尺寸计算,保证旋转后轨道顶端不越出画布;此前手动设置的高度值被忽略(内部写 0 并置 auto)。
示例:
api.setLaneHeightAuto(0);setLaneScale(int lane, float sx, float sy)
签名:
void setLaneScale(int lane, float sx, float sy);行为:单条真轨的渲染缩放(lane_scale 对应物),pivot = 该轨几何中心;sx / sy 各自钳制 ≥ 0.01。全套跟随:背景、分隔线(线宽按 1/sx 补偿保持约 1px)、判定线/键框、按键指示器与音符在同一仿射变换内缩放。(1,1) 为原大小。纯视觉,判定引擎零消费。
示例:
api.setLaneScale(1, 1.5f, 0.8f);setLaneScaleAuto(int lane)
签名:
void setLaneScaleAuto(int lane);行为:把该轨缩放复位到 (1,1)。
示例:
api.setLaneScaleAuto(1);setLaneSkew(int lane, float skew, float anchorY)
签名:
void setLaneSkew(int lane, float skew, float anchorY);行为:单条真轨的线性斜切(lane_skew 对应物)。合成横移 offsetX(y) = skew × (y − anchorY) + 弧线项(y),skew 钳 |skew| ≤ 1,anchorY 为该画布 y 处零偏移的锚点。与 setLaneArc 共享同一条 per-lane 形变通道、坐标叠加;偏移是纯 y 函数,每帧 O(1) 求值,无状态/无随机/无墙钟(确定性契约)。全套跟随:背景与分隔线逐段弯曲、按键框整体横移、音符中心 x 跟随其所在 y,判定线保持水平直线,音符自身不旋转不变形(口径)。skew == 0 时回到既有直轨路径(默认零变化)。纯视觉,判定零消费。
示例:
api.setLaneSkew(0, 0.4f, 300.0f);setLaneSkewAuto(int lane)
签名:
void setLaneSkewAuto(int lane);行为:把该轨斜切系数归零(锚点保留;幅度为 0 时不参与偏移)。
示例:
api.setLaneSkewAuto(0);setLaneArc(int lane, float bendDir, float bendAmp, float arcCenterY)
签名:
void setLaneArc(int lane, float bendDir, float bendAmp, float arcCenterY);行为:单条真轨的圆弧形变(lane_arc 对应物),与 setLaneSkew 共享同一通道。弧线横移为纯 y 函数:offsetX(y) = sign(bend) × (R − √(R² − d²)),d = y − arcCenterY(钳 |d| ≤ R),R = (S² + A²) / (2A),S = 600px(弧线参考跨度),A = |bendDir × bendAmp|。bendDir 先钳 ±1(-1 左凸 / +1 右凸),bendAmp 取绝对值并钳 ≤ 300;距弧心竖直 600px 处的弧偏移恰好为 bendAmp。全套跟随与判定线水平口径同 setLaneSkew;纯视觉。
示例:
api.setLaneArc(0, -1.0f, 150.0f, 300.0f);setLaneArcAuto(int lane)
签名:
void setLaneArcAuto(int lane);行为:把该轨弧线归零(弧心保留;幅度为 0 时不参与偏移)。
示例:
api.setLaneArcAuto(0);setTrackTilt3D(double tiltDeg)
签名:
void setTrackTilt3D(double tiltDeg);行为:轨道区域的真 3D 透视倾斜(track_tilt 的会话级对应物)。tiltDeg 单位是度,正值 = 顶部远离相机向后倒(Arcaea 式),宿主钳 ±89°;0 = 正交(恒等,默认零变化)。宿主以 d = 内容高 × 0.5、锚点 = 判定线驱动透视相机:世界层(BACKGROUND / WORLD / NOTES / JUDGE_FX)随相机透视变形,HUD / OVERLAY 恒正交不受影响。与 GameStateAccess.setTrackTilt3D 写同一执行体(后写生效);倒带或加载新谱面时声明面与相机重建。纯视觉,判定零消费。
示例:
api.setTrackTilt3D(20.0);setTrackTilt3DAuto()
签名:
void setTrackTilt3DAuto();行为:把轨道 3D 倾斜复位到 0(正交)。
示例:
api.setTrackTilt3DAuto();setNoteAlpha(int lane, float alpha)
签名:
void setNoteAlpha(int lane, float alpha);行为:设置该轨全部音符的透明度,alpha 钳制到 0..1;不影响轨道背景、分隔线与快捷键框。宿主对该方法先检查 lane 范围,越界时打印 lane_note_alpha: lane N out of range 后忽略(非限频)。
示例:
api.setNoteAlpha(2, 0.25f);setUiAlpha(float alpha)
签名:
void setUiAlpha(float alpha);行为:设置非轨道 UI(分数、连击等 HUD)的整体透明度,期望 0..1。注意宿主此通道直写 HUD 透明度、不额外钳制,越界值会原样进入渲染,请自行限制。宿主未注入 UI 通道时静默无操作。
示例:
api.setUiAlpha(0.2f);假轨道原语
createFakeTrack(int id, int originLane, float alpha)
签名:
void createFakeTrack(int id, int originLane, float alpha);行为:创建一条表演用假轨道。id 是后续 setFakeTrackXxx 的寻址键,已存在时用新实例覆盖(位置、透明度、缩放、旋转、形变全部重置)。originLane 指定参考真轨,以其判定线中心为坐标原点;-1 = 画布原点模式(不绑定真轨,快捷键框显示 ?)。alpha 为初始透明度(0..1)。3.0 起没有 z 参数(画家算法层级已移除,前后关系由真 3D 深度决定)。假轨不参与判定/输入。
示例:
api.createFakeTrack(1, 0, 0.8f);setFakeTrackTransform(int id, float x, float y, float alpha, float scaleX, float scaleY, float rotationRad)
签名:
void setFakeTrackTransform(int id, float x, float y, float alpha, float scaleX, float scaleY, float rotationRad);行为:一次写入假轨的位置、透明度、缩放与旋转(fake_track_move 非动画分支)。rotationRad 为弧度、顺时针为正;alpha 同时写背景/分隔线与快捷键框(宿主内部 setAlpha);scaleX / scaleY 各钳 ≥ 0.01。id 不存在时限频告警并忽略。
示例:
api.setFakeTrackTransform(1, 20.0f, -40.0f, 0.8f, 1.2f, 0.9f, 0.0f);setFakeTrackAlpha(int id, float alpha)
签名:
void setFakeTrackAlpha(int id, float alpha);行为:只改假轨透明度(0..1 钳制);不影响位置/缩放/旋转。宿主实现中该写入会同时设置背景/分隔线与快捷键框两者,只想改键框请用 setFakeTrackKeyIndicatorAlpha。
示例:
api.setFakeTrackAlpha(1, 0.4f);setFakeTrackRotation(int id, float rotationRad)
签名:
void setFakeTrackRotation(int id, float rotationRad);行为:只改假轨旋转角(弧度,顺时针正),圆心保持当前设置(默认判定线中点)。
示例:
api.setFakeTrackRotation(1, (float) Math.toRadians(8.0));setFakeTrackRotation(int id, float rotationRad, String pivot)
签名:
void setFakeTrackRotation(int id, float rotationRad, String pivot);行为:设置旋转角并同时指定圆心。pivot 取 "judge_line"(该假轨判定线中点,默认)或 "track_center"(背景几何中心);null 与未知值都回退 "judge_line",未知的非 null 值额外打印告警。等价于先调用两参版本再设定圆心。
示例:
api.setFakeTrackRotation(1, (float) Math.toRadians(8.0), "track_center");setFakeTrackSkew(int id, float skew, float anchorY)
签名:
void setFakeTrackSkew(int id, float skew, float anchorY);行为:假轨斜切,口径与 setLaneSkew 一致——钳制算式与真轨共用宿主 TrackGeometry.normalizeSkew(|skew| ≤ 1)。anchorY 为该 y 处零偏移的锚点。假轨本不参与判定,零判定副作用。
示例:
api.setFakeTrackSkew(1, 0.3f, 300.0f);setFakeTrackArc(int id, float bendDir, float bendAmp, float arcCenterY)
签名:
void setFakeTrackArc(int id, float bendDir, float bendAmp, float arcCenterY);行为:假轨弧线,口径与 setLaneArc 一致——TrackGeometry.normalizeArcBend 统一钳制:方向钳 ±1、幅度取绝对值并钳 ≤ 300,返回有符号幅度;arcCenterY 为弧心 y。
示例:
api.setFakeTrackArc(1, 1.0f, 120.0f, 300.0f);setFakeTrackHeight(int id, float height)
签名:
void setFakeTrackHeight(int id, float height);行为:假轨高度延伸(向判定线反方向),负值按 0 处理,口径同 setLaneHeight 的手动分支。
示例:
api.setFakeTrackHeight(1, 180.0f);setFakeTrackKeyIndicatorAlpha(int id, float alpha)
签名:
void setFakeTrackKeyIndicatorAlpha(int id, float alpha);行为:只改假轨快捷键框透明度(0..1 钳制),背景/分隔线不变。谱面 fake_track_alpha 同时写两者,本原语用于分别控制。
示例:
api.setFakeTrackKeyIndicatorAlpha(1, 0.0f);假音符原语
createFakeNote(int id, int fakeTrackId, String noteType, Long lengthMs, float alpha)
签名:
void createFakeNote(int id, int fakeTrackId, String noteType, Long lengthMs, float alpha);行为:创建一个绑定到假轨的假音符。id 已存在时覆盖。noteType 取 "normal" 或 "hold"(null 按 normal,大小写不敏感);只有 "hold" 且 lengthMs != null && lengthMs > 0 时按长条绘制,否则按普通音符,normal 请传 null。fakeTrackId 应先用 createFakeTrack 创建;宿主不在此处校验,绑定的假轨不存在时该音符不会被绘制。alpha 初始透明度(0..1)。
示例:
api.createFakeNote(10, 1, "hold", 1200L, 0.9f);setFakeNoteAlpha(int id, float alpha)
签名:
void setFakeNoteAlpha(int id, float alpha);行为:只改指定假音符的透明度(0..1 钳制),不影响假轨与其他假音符;id 不存在时打印告警并忽略。
示例:
api.setFakeNoteAlpha(10, 0.5f);音符级原语
setNoteTransform(long noteId, float dx, float dy, float dz, float pitchDeg, float yawDeg, float rollDeg, float scale)
签名:
void setNoteTransform(long noteId, float dx, float dy, float dz, float pitchDeg, float yawDeg, float rollDeg, float scale);行为:真谱面音符的自身 3D 变换,按 noteId 寻址,偏移 + 三轴旋转 + 等比缩放一次写入。
- 中心与叠加:旋转/缩放中心 = 音符自身中心(其轨道中心 x 与音符 y 处);与轨道形变通道(
lane_skew/lane_arc形变偏移、lane_pose)坐标叠加——最终位置 = 轨道形变后的位置 + 自身变换;dx/dy/dz为屏幕像素,不随轨道形变旋转/缩放。 - 单位:
pitchDeg/yawDeg/rollDeg为度(pitch正值顶部向后、yaw正值右侧向后、roll正值顺时针;旧弧度参数换算为rollDeg = Math.toDegrees(rotationRad));dz为深度像素(+z 向屏幕内);scale钳制 ≥ 0.01。 noteId取NoteView.noteId()的取值域(解析期按谱面顺序分配,含已判定/MISS 音符),可配合GameplayContext.notesInWindow(...)批量查询;无对应音符的 id 静默无渲染效果,负 id 被忽略。- 生命周期(音符级通道特有):变换按
noteId常驻——不因判定(含 MISS)自动清除,不在谱面声明面倒带重置清单内,暂停倒带、音符复活后仍生效;模组自管状态(在GameplayTickEvent.Post内每帧重写即可获得确定性最高优先级,或显式 clear);每局重进清空,无跨局状态。 - 纯视觉,判定引擎零消费;三轴与
dz全为 0 时与旧 2D 输出逐字节一致。
示例:
// 对固定 noteId 做「上移 18px + 顺时针 15° + 放大 1.2 倍」
api.setNoteTransform(42L, 0.0f, -18.0f, 0.0f, 0.0f, 0.0f, 15.0f, 1.2f);clearNoteTransform(long noteId)
签名:
void clearNoteTransform(long noteId);行为:清除该 noteId 的自身变换条目,回到恒等;无条目时为 no-op。与 setNoteTransform 的「常驻」语义配套,是唯一的复位入口。
示例:
api.clearNoteTransform(42L);与 GameStateAccess 的双面差异(同一执行体、两套入口)
| 维度 | ExtraContentApi(谱面原语侧) | GameStateAccess(会话侧) |
|---|---|---|
| 参数类型 | float(与谱面 _extra.json 同口径) | double(模组会话写入) |
| 轨道旋转 | setLaneRotation(int, float rotationRad),无 pivot,圆心固定判定线中点 | setLaneRotation(int, double rotationRad),无 pivot,圆心固定判定线中点 |
| 每轨复位 | 有命名式复位入口:setLaneHeightAuto / setLaneScaleAuto / setLaneSkewAuto / setLaneArcAuto | 无 per-lane auto(部分通道有读取 getter 供模组自持值) |
| 轨道区偏移 | setTrackOffset(float x, float y) | setTrackOffset(double x, double y) |
| 3D 倾斜 | setTrackTilt3D(double) / setTrackTilt3DAuto() | setTrackTilt3D(double) / setTrackTilt3DAuto() |
| 相机通道 | 无相机原语(track_tilt 在宿主内归一为相机 pitch 分量) | 独占 setCameraPose(...) / setCameraPoseAuto() |
| per-lane 3D 朝向 | 无 pitch/yaw 原语:只有 setLaneOffset 的 z 深度与 setLaneRotation 的 roll;需要三轴朝向请用谱面 lane_pose 或自绘 MatrixStack | 同样无等价会话原语(setLaneOffset 的 z 之外无 3D 朝向) |
| 生命周期 | 谱面时间轴驱动(parser apply 阶段 / 游玩期一次性触发;宿主重建声明面时不包含模组写入) | 玩家会话级模组状态(随模组会话持有;setCameraPose 为绝对写、接管至倒带 / 新谱面复位) |
两套入口写同一执行体(TrackRenderer 每轨状态 / 相机位姿),后写生效——模组与谱面特效同时使用会互相覆盖;在 GameplayTickEvent.Post 内每帧重写 = 确定性最高优先级。本接口仅在游玩上下文非 null(见 ChartRuntimeContext.extraContent()),调用方必须判空。
完整签名
public interface ExtraContentApi {
void setLaneAlpha(int lane, float alpha);
void setKeyIndicatorAlpha(int lane, float alpha);
void setTrackOffset(float x, float y);
void setLaneOffset(int lane, float x, float y, float z);
void setLaneRotation(int lane, float rotationRad);
void setLaneSpeedFactor(int lane, float factor);
void setLaneHeight(int lane, float height);
void setLaneHeightAuto(int lane);
void setLaneScale(int lane, float sx, float sy);
void setLaneScaleAuto(int lane);
void setLaneSkew(int lane, float skew, float anchorY);
void setLaneSkewAuto(int lane);
void setLaneArc(int lane, float bendDir, float bendAmp, float arcCenterY);
void setLaneArcAuto(int lane);
void setTrackTilt3D(double tiltDeg);
void setTrackTilt3DAuto();
void setNoteAlpha(int lane, float alpha);
void setUiAlpha(float alpha);
void createFakeTrack(int id, int originLane, float alpha);
void setFakeTrackTransform(int id, float x, float y, float alpha,
float scaleX, float scaleY, float rotationRad);
void setFakeTrackAlpha(int id, float alpha);
void setFakeTrackRotation(int id, float rotationRad);
void setFakeTrackRotation(int id, float rotationRad, String pivot);
void setFakeTrackSkew(int id, float skew, float anchorY);
void setFakeTrackArc(int id, float bendDir, float bendAmp, float arcCenterY);
void setFakeTrackHeight(int id, float height);
void setFakeTrackKeyIndicatorAlpha(int id, float alpha);
void createFakeNote(int id, int fakeTrackId, String noteType, Long lengthMs, float alpha);
void setFakeNoteAlpha(int id, float alpha);
void setNoteTransform(long noteId, float dx, float dy, float dz,
float pitchDeg, float yawDeg, float rollDeg, float scale);
void clearNoteTransform(long noteId);
}线程:GL 主线程调用(与谱面加载/游玩同线程);通道内部不做同步,跨线程调用需自行切回主线程。
生命周期阶段:谱面加载(parser apply 阶段,绑定前缓冲、绑定后重放)与游玩期;每局新实例,onExit 清除,无跨局状态。
稳定性:1.x 加性新增;2.x 内新增方法只增不破。3.0 随世界模型升级做过一次签名删减:setLaneRotation 去掉 pivot 参数、createFakeTrack 去掉 z 参数——3.x 模组需按本页签名书写。