GameStateAccess
游玩状态机与游玩访问能力:读 / 改音乐时间与暂停结束状态、控制每轨视觉几何(流速、旋转、缩放、斜切、弧线、3D 偏移)、读写相机位姿与投影查询、查询轨道区布局、读写游戏内光标、强制 altHUD,以及查询面形态的模组实体层级。经 ctx.capabilities().get(GameStateAccess.class) 取用,只在游玩中注册(其它场景返回 null,且取到的是携带调用方模组 id 的包装视图,用于实体所有权校验)。
除 setLaneSpeedFactor(改变音符下落外观与收集窗口)外,轨道几何与相机类入口都是纯视觉:判定引擎零消费,画面写得再激进也不影响判定结果与成绩。
方法速览
| 方法 | 用途 |
|---|---|
musicTimeMs() | 当前音乐时间(毫秒) |
isPaused() | 是否暂停 |
isFinished() | 是否已结束 |
play() | 开始游玩(进入播放) |
pause() | 暂停(与 ESC 同路径,可被 PauseEvent 否决) |
resume() | 恢复(含恢复倒计时与倒带,可被 ResumeEvent 否决) |
seek(long) | 跳转到指定音乐时间 |
setSpeed(double) | 设置播放速度倍率 |
requestMode(String) | 程序化激活已注册玩法模式 |
endGame() | 结束当前游玩(进入结算) |
setLaneSpeedFactor(int, double) | 设置单轨流速倍率 |
getLaneSpeedFactor(int) | 读取单轨流速倍率 |
setLaneRotation(int, double) | 设置单轨旋转(弧度) |
getLaneRotation(int) | 读取单轨旋转(弧度) |
setLaneScale(int, double, double) | 设置单轨渲染缩放 |
getLaneScaleX(int) / getLaneScaleY(int) | 读取单轨缩放 |
setLaneSkew(int, double, double) | 设置单轨斜切形变 |
getLaneSkew(int) | 读取单轨斜切系数 |
setLaneArc(int, double, double, double) | 设置单轨弧线形变 |
getLaneArcBend(int) | 读取单轨有符号弧幅 |
setLaneOffset(int, double, double, double) | 设置单轨 3D 偏移 |
flashLane(int, long) | 触发单轨原生按压高亮 |
project(double, double, double) | 内容坐标 → 屏幕坐标 |
unproject(double, double, double) | 屏幕坐标 → 内容坐标(指定深度平面) |
cameraPose() | 当前生效相机位姿 |
setTrackTilt3D(double) | 轨道区 3D 倾斜(度) |
setTrackTilt3DAuto() | 复位 3D 倾斜 |
setCameraPose(double, double, double, double, double, double) | 直接写相机位姿(接管视角) |
setCameraPoseAuto() | 复位相机位姿接管 |
setAltHudForced(boolean) | 强制 / 恢复备用 HUD |
cursorPosition() / setCursorPosition(int, int) | 读写游戏内光标(画布逻辑坐标) |
laneRotationPivot(int) | 单轨旋转圆心(世界坐标) |
trackAreaGeometry() | 轨道区布局快照 |
setTrackOffset(double, double) | 整区 X/Y 平移 |
createEntity(String) | 创建本模组实体(未挂载) |
mountToTrackArea(SceneEntity) | 挂到轨道区节点 |
mountToTrack(SceneEntity, int) | 挂到指定轨道节点 |
mountToEntity(SceneEntity, SceneEntity) | 挂到自有实体之下 |
entityPose(SceneEntity) | 本 tick 本地位姿写入面 |
entityWorldMatrix(SceneEntity) | 世界矩阵(列主序 double[16]) |
entityVisible(SceneEntity) | 有效可见性(父 ∧ 本) |
setEntityVisible(SceneEntity, boolean) | 写本节点自身可见性 |
entityAlpha(SceneEntity) | 有效 alpha(父链连乘) |
setEntityAlpha(SceneEntity, double) | 写本节点自身 alpha |
destroyEntity(SceneEntity) | 显式销毁(级联子树) |
完整签名
public interface GameStateAccess {
long musicTimeMs();
boolean isPaused();
boolean isFinished();
void play();
void pause();
void resume();
void seek(long musicTimeMs);
void setSpeed(double speed);
boolean requestMode(String modeId);
void setLaneSpeedFactor(int lane, double factor);
double getLaneSpeedFactor(int lane);
void setLaneRotation(int lane, double rotationRad);
double getLaneRotation(int lane);
void setLaneScale(int lane, double sx, double sy);
double getLaneScaleX(int lane);
double getLaneScaleY(int lane);
void setLaneSkew(int lane, double skew, double anchorY);
double getLaneSkew(int lane);
void setLaneArc(int lane, double bendDir, double bendAmp, double arcCenterY);
double getLaneArcBend(int lane);
void setLaneOffset(int lane, double offsetX, double offsetY, double offsetZ);
void flashLane(int lane, long durationMs);
default double[] project(double x, double y, double z);
default double[] unproject(double screenX, double screenY, double z);
default double[] cameraPose();
void setTrackTilt3D(double tiltDeg);
void setTrackTilt3DAuto();
void setCameraPose(double x, double y, double z, double yawDeg, double pitchDeg, double fovDeg);
void setCameraPoseAuto();
void setAltHudForced(boolean forced);
int[] cursorPosition();
void setCursorPosition(int x, int y);
double[] laneRotationPivot(int lane);
double[] trackAreaGeometry();
void setTrackOffset(double x, double y);
default SceneEntity createEntity(String name);
default void mountToTrackArea(SceneEntity e);
default void mountToTrack(SceneEntity e, int lane);
default void mountToEntity(SceneEntity child, SceneEntity parent);
default EntityPose entityPose(SceneEntity e);
default double[] entityWorldMatrix(SceneEntity e);
default boolean entityVisible(SceneEntity e);
default void setEntityVisible(SceneEntity e, boolean v);
default double entityAlpha(SceneEntity e);
default void setEntityAlpha(SceneEntity e, double a);
default void destroyEntity(SceneEntity e);
void endGame();
}musicTimeMs()
签名:
long musicTimeMs();行为:返回当前音乐时间(毫秒),即游玩时间轴——倒带期间会随倒带一起回退。暂停时返回冻结值。单位毫秒、long。
示例:
GameStateAccess gs = ctx.capabilities().get(GameStateAccess.class);
if (gs != null) {
long now = gs.musicTimeMs();
}isPaused()
签名:
boolean isPaused();行为:当前是否处于暂停态(pause() 或 ESC 暂停置位;resume() 受理后立即复位为 false,恢复倒计时期间不算暂停)。
示例:
if (gs.isPaused()) {
// 暂停中
}isFinished()
签名:
boolean isFinished();行为:本局是否已结束(已进入结算流程)。
示例:
if (!gs.isFinished()) {
// 仍在游玩
}play()
签名:
void play();行为:开始游玩:启动谱面音频(谱面声明了音频且文件存在时)并把音乐标记为已开始,同时发布 GameplayStart。已开始或仍在加载时为空操作;本方法不解除暂停(恢复请用 resume())。
示例:
gs.play();pause()
签名:
void pause();行为:暂停游玩,与 ESC 暂停走同一路径:先发布可取消的 PauseEvent(DENY 时状态一律不变),随后置暂停、暂停谱面音频并播放提示音。已暂停或已结束时空操作。
示例:
gs.pause();resume()
签名:
void resume();行为:恢复游玩,与暂停菜单 RESUME 同一路径:先发布可取消的 ResumeEvent(DENY 时保持暂停),随后进入恢复倒计时 + 倒带——判定 / 渲染时间从暂停点按缓动回退到 max(0, T−3s),音频同步反向回放,倒带结束后从终点重新正放。倒带期按键被丢弃,不产生任何新判定;已判定音符状态与计数不变。未暂停或已结束时空操作。
示例:
gs.resume();seek(long musicTimeMs)
签名:
void seek(long musicTimeMs);行为:设置音乐时间到指定毫秒;负值钳为 0。若音乐已开始且谱面声明了音频,同时向音频引擎 seek。不改变暂停态。
示例:
gs.seek(30_000L); // 跳到 30 秒setSpeed(double speed)
签名:
void setSpeed(double speed);行为:设置播放速度倍率。宿主实现把 max(0.05, speed) 作为绝对播放速率下发给音频命令通道,同时把当前滚动速度乘以该倍率——因此连续多次调用会累乘滚动速度,需要绝对设定时按当前值一次调用即可。
示例:
gs.setSpeed(1.5); // 1.5 倍速requestMode(String modeId)
签名:
boolean requestMode(String modeId);行为:程序化激活一个已注册的玩法模式("<ns>:<name>"),语义与选曲面板传 modeId 参数的进场选择一致:旧模式 onExit → 切换 → 新模式 onEnter(每步异常隔离)。激活后 mapLane / 镜像 / 每帧回调立即按新模式派发;激活 seecmd:disorder 与面板显式选择同语义(整曲强制无序)。
- 返回
true= 已激活(目标即当前模式时幂等成功,不重复回调)。 - 返回
false=modeId为null/ 空、id 解析失败或模式未注册;本局模式不变,宿主限频告警。 - 重试谱面仍按进场面板选择的模式(程序化激活不改变重试指向)。
示例:
if (!gs.requestMode("mymod:hardcore")) {
ctx.getLogger().warning("模式未注册,保持当前模式");
}endGame()
签名:
void endGame();行为:结束当前游玩并进入结算;已结束时为空操作。
示例:
gs.endGame();setLaneSpeedFactor(int lane, double factor)
签名:
void setLaneSpeedFactor(int lane, double factor);行为:设置指定真轨道的流速倍率(乘在全局 scrollSpeed 上),瞬时生效。1.0 = 与全局一致,0 = 静止,负值 = 反向下落;不钳制,接受任意有限值。只影响音符下落外观与该轨收集窗口,判定仍按音乐时间,不改变判定时机。lane 越界时静默忽略。
示例:
gs.setLaneSpeedFactor(0, 1.5); // 第 0 轨 1.5 倍速
gs.setLaneSpeedFactor(1, -1.0); // 第 1 轨反向下落getLaneSpeedFactor(int lane)
签名:
double getLaneSpeedFactor(int lane);行为:读取该轨流速倍率;越界或无布局时返回 1.0。
示例:
double f = gs.getLaneSpeedFactor(0);setLaneRotation(int lane, double rotationRad)
签名:
void setLaneRotation(int lane, double rotationRad);行为:设置指定真轨道绕判定线中点的旋转角(弧度,正值顺时针),纯视觉,不影响判定与输入。宿主把弧度换算为度写入每轨 rollDeg,因此与谱面额外内容特效 lane_pose.rollDeg 写同一份每轨状态(同时使用会互相覆盖)。旋转轨道的背景、分隔线、音符(含自定义类型)与顶端剔除窗口都会跟随变换。
3.0 起无 pivot 参数:圆心固定为该轨判定线中点;旧 TRACK_CENTER 等价形态请改用 EntityPose.rotateZ(deg, pivotX, pivotY) 显式给圆心。lane 越界时静默忽略。
示例:
gs.setLaneRotation(0, Math.toRadians(15)); // 第 0 轨顺时针 15°getLaneRotation(int lane)
签名:
double getLaneRotation(int lane);行为:读取该轨旋转角(弧度,由存储的度值反算);越界或无布局时返回 0.0。
示例:
double rad = gs.getLaneRotation(0);setLaneScale(int lane, double sx, double sy)
签名:
void setLaneScale(int lane, double sx, double sy);行为:设置指定真轨道的渲染缩放(纯视觉)。该轨的背景、分隔线、判定线(按键框顶边)、按键指示器与音符在同一仿射变换内缩放,pivot = 该轨几何中心。sx / sy 钳制 ≥0.01(防止 0 缩放导致绘制异常)。与谱面每轨缩放通道写同一份 LanePose 状态(后写生效)。
示例:
gs.setLaneScale(2, 1.2, 0.8);getLaneScaleX(int lane)
签名:
double getLaneScaleX(int lane);行为:读取该轨水平缩放因子;默认 / 越界 1.0。
示例:
double sx = gs.getLaneScaleX(2);getLaneScaleY(int lane)
签名:
double getLaneScaleY(int lane);行为:读取该轨垂直缩放因子;默认 / 越界 1.0。
示例:
double sy = gs.getLaneScaleY(2);setLaneSkew(int lane, double skew, double anchorY)
签名:
void setLaneSkew(int lane, double skew, double anchorY);行为:设置指定真轨道的斜切形变(纯视觉)。合成偏移 = skew×(y−anchorY) + 弧线项(y)(与 setLaneArc 共享同一 per-lane 形变通道,纯 y 函数、每帧 O(1) 求值——确定性契约:无状态 / 无随机 / 无墙钟)。该轨背景 / 分隔线 / 按键框 / 音符绘制的 x 统一叠加;判定线保持水平直线(按键框整体横移),音符中心 x 跟随其所在 y 的偏移、自身不旋转不变形。
skew 钳 |skew|≤1(每 px 纵移的横移系数,1 = 45° 斜切极限);anchorY 为零偏移锚点(画布 y)。与谱面额外内容特效 lane_skew 写同一份每轨形变状态(后写生效)。lane 越界时静默忽略。
示例:
gs.setLaneSkew(0, 0.25, gs.trackAreaGeometry()[3]); // 以判定线高度为锚点getLaneSkew(int lane)
签名:
double getLaneSkew(int lane);行为:读取该轨斜切系数(已钳制后的值);默认 / 越界 0.0。
示例:
double k = gs.getLaneSkew(0);setLaneArc(int lane, double bendDir, double bendAmp, double arcCenterY)
签名:
void setLaneArc(int lane, double bendDir, double bendAmp, double arcCenterY);行为:把指定真轨道整轨弯成圆弧(纯视觉)。标准圆弧:弧心处偏移 0、切线水平,距弧心 600px 竖直距离处弧偏移 = bendAmp。bendDir 钳 [-1,1](-1 = 向左弯、+1 = 向右弯);bendAmp 取绝对值后钳 ≤300px;宿主内部存的是有符号幅度 bendDir×bendAmp。arcCenterY 为弧心 y(画布坐标)。与谱面额外内容特效 lane_arc 写同一份每轨形变状态。lane 越界时静默忽略。
示例:
gs.setLaneArc(1, 1.0, 120.0, 360.0);getLaneArcBend(int lane)
签名:
double getLaneArcBend(int lane);行为:读取该轨有符号弧线幅度(bendDir×bendAmp,px);默认 / 越界 0.0。
示例:
double bend = gs.getLaneArcBend(1);setLaneOffset(int lane, double offsetX, double offsetY, double offsetZ)
签名:
void setLaneOffset(int lane, double offsetX, double offsetY, double offsetZ);行为:设置指定真轨道的 3D 偏移(世界坐标 px,纯视觉,不影响判定)。真轨本地 (0,0,0) = 世界原点,未写 lane_pose 时所有轨默认堆叠在世界原点;本方法与谱面 lane_pose.x/y/z 写同一份每轨状态(后写生效)。轨道的背景、分隔线、音符(含自定义类型)均跟随偏移。
offsetZ 为沿 +z(屏幕内) 的深度(px),在旋转之后施加,与旋转圆心无交互;只传 x/y 的旧代码补 0 即像素输出不变。lane 越界时静默忽略。
示例:
gs.setLaneOffset(0, 0.0, 0.0, -120.0); // 第 0 轨向屏幕外推 120pxflashLane(int lane, long durationMs)
签名:
void flashLane(int lane, long durationMs);行为:触发指定真轨道的原生按压高亮:与玩家按键时轨道指示器 / 轨道背景点亮完全同源(同一份按下状态),当帧立即点亮,持续 durationMs 毫秒后自动熄灭,期间真实按键状态照常叠加。重复调用刷新持续时间。用于模组判定命中时复用原生视觉反馈,无需自绘。lane 越界或 durationMs ≤ 0 时无操作。
示例:
gs.flashLane(2, 120);project(double x, double y, double z)
签名:
double[] project(double x, double y, double z);行为:内容坐标 → 屏幕坐标。内容坐标 = 轨道绘制使用的世界坐标(画布 px、y 向下、z 沿 +z 向屏幕内,0 = 内容平面)。使用最近一帧渲染生效的世界相机(含 setCameraPose、tilt 与位姿 adjuster 链的结果),与屏幕所见一致;在 tick 中调用时拿到的是上一帧相机状态(本帧渲染前宿主才更新)。
返回 double[]{screenX, screenY, ndcDepth}(像素,与画布逻辑坐标同空间);ndcDepth ∈ [-1,1](-1 近裁面、+1 远裁面),可直接用于排序 / 可见性。点位于相机后方(齐次 w ≤ 1e-9)或视锥退化时返回 null;超出远裁面的点仍会返回 ndcDepth > 1,调用方需自行判断裁剪。默认实现返回 null。
示例:
double[] p = gs.project(640, 360, 0);
if (p != null && p[2] >= -1.0 && p[2] <= 1.0) {
// p[0], p[1] 为屏幕像素坐标
}unproject(double screenX, double screenY, double z)
签名:
double[] unproject(double screenX, double screenY, double z);行为:屏幕坐标 → 内容坐标,落在指定深度平面 z 上(project 的逆)。给定屏幕点与内容深度,求出该屏幕射线与 z 平面的交点;典型用途是 3D 内容的鼠标拾取(先把光标落到目标深度平面,再做 2D 命中判定)。返回 double[]{x, y, z}(内容坐标)。
屏幕坐标按画布逻辑像素(0..canvasWidth / 0..canvasHeight)解释;视线与该平面平行(行列式 ≈ 0)等退化情形返回 null。默认实现返回 null。
示例:
int[] c = gs.cursorPosition();
double[] hit = gs.unproject(c[0], c[1], 0.0); // 光标落在内容平面上的点cameraPose()
签名:
double[] cameraPose();行为:读取当前生效的相机位姿,口径与 setCameraPose 一致(内容坐标 / 度)。返回 double[]{x, y, z, yawDeg, pitchDeg, fovDeg}(宿主实现恒 6 元素);fovDeg 为 Double.NaN 表示 AUTO(由宿主按画布推导)。仅作信息与近似计算用——精确换算请用 project / unproject(它们包含 tilt / adjuster 链等全部合成)。默认实现返回 null。
示例:
double[] pose = gs.cameraPose();
if (pose != null) {
boolean autoFov = Double.isNaN(pose[5]);
}setTrackTilt3D(double tiltDeg)
签名:
void setTrackTilt3D(double tiltDeg);行为:整个轨道区绕判定线锚点的 X 轴做真 3D 透视倾斜(单位度,正值 = 顶部远离相机向后倒,Arcaea 式;宿主钳 ±89°)。轨道向消失点汇聚、顶部纵深收缩;tilt = 0 完全等价默认正交画面。作用于渲染 WORLD / BACKGROUND 层的相机矩阵,HUD 与系统 UI 恒为正交、不受影响。
与谱面特效通道 track_tilt 写同一份执行体状态(后写生效),生命周期为玩家会话级。2026-10-11 起内部归一为相机位姿 pitch 分量的语法糖,画面效果与旧 tilt 模型数学恒等。纯视觉,判定零消费;在 GameplayTickEvent.Post 内每帧重写 = 确定性最高优先级。
示例:
gs.setTrackTilt3D(30.0);setTrackTilt3DAuto()
签名:
void setTrackTilt3DAuto();行为:把轨道 3D 倾斜复位到默认(tilt = 0,恒等正交)。模组停用 / 退出自绘效果时还原用;与谱面 track_tilt 共用同一份状态,因此也会覆盖谱面写入。
示例:
gs.setTrackTilt3DAuto();setCameraPose(double x, double y, double z, double yawDeg, double pitchDeg, double fovDeg)
签名:
void setCameraPose(double x, double y, double z, double yawDeg, double pitchDeg, double fovDeg);行为:直接设置相机位姿——相机无特殊设计,模组挪相机即接管视角,无需宿主开关。
- 写入语义:每帧可写、后写生效(绝对写,构成
CameraPoseAdjuster链的输入;GameplayTickEvent.Post内每帧重写 = 确定性最高优先级)。写入后相机由本位姿完全接管:宿主默认位姿不再作用于视图;setTrackTilt3D的倾斜分量不再改相机 pitch,而是转为内容旋转参与合成(同帧可共存),直至倒带 / 新谱面复位。 - 口径:
x/y/z为内容坐标像素(y 向下),z 单位 = 像素、+z 向屏幕内、有效范围|z| ≤ 2000(远裁面 = d + 2000);默认相机在(W/2, H/2, −d)、视线沿 +z。yawDeg/pitchDeg单位为度(与 MatrixStack 3D 原语的弧度口径区分),yaw 正值向右转、pitch 正值视线上抬。fovDeg为垂直视场角(度),传CameraPose.FOV_AUTO(Double.NaN)= 现行推导(d = 内容高 × 0.5,z=0 平面映射与正交恒等)。 - 宿主不做参数钳制;把几何挪到距相机极近处(内容 z 低于
near − d ≈ −2d/3,720p 下 near ≈ 120px)会被近裁剪面裁掉。 - 纯视觉,判定引擎零消费。
示例:
double[] geo = gs.trackAreaGeometry();
gs.setCameraPose(geo[0] / 2.0, geo[3] - 160.0, -520.0, 0.0, -15.0,
com.seecmd.mod.api.render.CameraPose.FOV_AUTO);setCameraPoseAuto()
签名:
void setCameraPoseAuto();行为:清除 setCameraPose 的接管标志,宿主恢复默认位姿推导(直视轨道,setTrackTilt3D / 谱面 track_tilt 通道重新作用于视图),相机位姿 adjuster 链输入回到默认推导。对未接管的相机是无害空操作。
为什么需要它:setCameraPose 是绝对写、接管持续到倒带 / 新谱面复位——只写「看起来像默认」的位姿不能恢复宿主默认推导(tilt 通道会被持续压制);这是唯一干净的还原入口。纯视觉,判定零消费。
示例:
gs.setCameraPoseAuto();
gs.setTrackTilt3DAuto();setAltHudForced(boolean forced)
签名:
void setAltHudForced(boolean forced);行为:强制切换游玩 HUD 至备用 UI(altHUD:顶部中央大号 COMBO + 判定等级 + 右上角准度 + 左上角 HP 条)。altHUD 原本由玩家「界面不透明度」滑杆驱动;本方法直接强制启用 / 恢复,与滑杆状态无关。
true:本局 altHUD 完全显示,同时标准 HUD 面板整体隐藏。false:恢复滑杆驱动。- 每局开始宿主自动重置为
false;每局开始后调用一次即可。
示例:
gs.setAltHudForced(true);cursorPosition()
签名:
int[] cursorPosition();行为:查询当前游戏内光标坐标 int[]{x, y},为画布逻辑坐标(与 NoteRenderContext 的 x() / y() 同一空间),与真实光标、自绘光标同源。返回最后已知位置(光标未进入画布时为上次位置),恒返回 2 元素数组。
示例:
int[] cur = gs.cursorPosition();setCursorPosition(int x, int y)
签名:
void setCursorPosition(int x, int y);行为:直接设置游戏内光标位置(画布逻辑坐标)。写入的就是 cursorPosition() 返回的那份位置;不影响系统真实光标、不做 OS 级 warp。自绘光标与场景轮询随之自然跟随;玩家移动真实鼠标后照常在其基础上累加位移(后发生者生效——模组若需与玩家共存,须自行检测真实输入并让位)。
示例:
double[] pivot = gs.laneRotationPivot(0);
if (pivot != null) {
gs.setCursorPosition((int) pivot[0], (int) pivot[1] - 120);
}laneRotationPivot(int lane)
签名:
double[] laneRotationPivot(int lane);行为:查询指定真轨道当前旋转圆心的世界坐标 double[]{x, y}:含该轨 lane_pose 平移(随轨道移动),不含 setTrackOffset(整区偏移)。3.0 起圆心恒为判定线中点,不再有「模式」概念。轨道索引无效时返回 null。
示例:
double[] pv = gs.laneRotationPivot(0);
if (pv != null) {
// pv[0], pv[1] 为圆心世界坐标
}trackAreaGeometry()
签名:
double[] trackAreaGeometry();行为:查询当前轨道区布局几何快照 double[]{canvasWidth, trackAreaLeft, trackAreaWidth, judgeLineY, laneCount}。轨道区 = 含两侧 padding 的完整轨道区域(padding 左右对称——区域居中即轨道组居中)。
只读布局快照:坐标为默认布局基准,不含 setTrackOffset / lane_move 等运行时视觉偏移(那些偏移渲染期才整体平移,不回写布局字段),因此可安全用于几何决策。布局未就绪(谱面未绑定)时 laneCount 为 0、几何为宿主默认,调用方按 laneCount <= 0 / trackAreaWidth <= 0 自行守卫(每帧轮询即可自愈)。恒返回 5 元素数组。
示例:
double[] geo = gs.trackAreaGeometry();
if (geo[4] > 0 && geo[2] > 0) {
gs.setTrackOffset((geo[0] - geo[2]) / 2.0 - geo[1], 0.0);
}setTrackOffset(double x, double y)
签名:
void setTrackOffset(double x, double y);行为:整个轨道区的 X/Y 平移(画布 px,相对默认布局的偏移量,(0,0) = 默认布局;正值右移 / 下移)。
与谱面特效通道 ExtraContentApi.setTrackOffset 写同一执行体(后写生效),但生命周期为玩家会话级(与 setLaneRotation 同类,随模组会话持有)。纯视觉,判定零消费;在 GameplayTickEvent.Post 内每帧重写 = 确定性最高优先级。
整区深度偏移不在本方法:用轨道位姿 adjuster 的 PoseOps.translate3D(0, 0, dz);逐轨深度用 setLaneOffset。
示例:
gs.setTrackOffset(0.0, 0.0); // 归位到默认布局createEntity(String name)
签名:
default SceneEntity createEntity(String name);行为:创建一个调用方模组所有的场景实体(未挂载)。实体 = 纯变换节点(组,无渲染内容):查询面形态下模组经 entityWorldMatrix 取世界矩阵后自行变换自绘内容。创建后需经 mountToTrackArea / mountToTrack / mountToEntity 挂载才进入世界层级。
name 仅用于日志,null 时宿主自动命名。返回实体句柄;世界层级未装配(布局未就绪)时返回 null 并限频告警。默认实现返回 null。生命周期:随游玩场景存续,游玩结束时宿主自动级联销毁全部模组实体。
示例:
SceneEntity marker = gs.createEntity("marker");mountToTrackArea(SceneEntity e)
签名:
default void mountToTrackArea(SceneEntity e);行为:把调用方模组的实体挂到轨道区节点之下(任何模组可挂,轨道区是宿主实体)。
- 挂载窗口 = 非 tick 上下文(如
GameStartEvent回调);tick 分发期间调用被拒([ModConflict]风格限频告警,不抛异常)。 - 重复挂载 = 改挂位置(自动从旧父摘除);深度上限 16 与成环由宿主校验并拒绝。
- 实体为
null时静默忽略;无效 / 已销毁句柄或属于他人时拒绝 + 限频告警。
示例:
gs.mountToTrackArea(marker);mountToTrack(SceneEntity e, int lane)
签名:
default void mountToTrack(SceneEntity e, int lane);行为:把实体挂到指定轨道节点之下;窗口 / 所有权 / 深度校验同 mountToTrackArea。lane 为真轨道索引(0 起),无效轨道被拒绝 + 限频告警。
示例:
gs.mountToTrack(marker, 1);mountToEntity(SceneEntity child, SceneEntity parent)
签名:
default void mountToEntity(SceneEntity child, SceneEntity parent);行为:把模组实体挂到另一个模组实体之下。父子都必须属于调用方模组(所有权)——挂到他人实体之下被拒绝。窗口 / 深度 / 成环校验同 mountToTrackArea。
示例:
SceneEntity group = gs.createEntity("group");
gs.mountToTrackArea(group);
gs.mountToEntity(marker, group);entityPose(SceneEntity e)
签名:
default EntityPose entityPose(SceneEntity e);行为:取实体的本 tick 本地位姿写入面(标量偏移可写 + op 追加面,见 SceneEntity 与 EntityPose(render 包))。
- 仅在
GameplayTickEvent.Pre/Post分发期间合法;窗口外返回null+ 限频告警,无效句柄同样返回null。 - 每 tick 契约:宿主每 tick 开始时清空全部模组实体本地位姿——未写 = 恒等、帧间不累积;需持续位姿就在 tick 回调内每帧重写。
- 合成口径与
TrackPose同款:标量平移先、op 列表按序右乘后;圆心一律写实体本地坐标。
示例:
EntityPose pose = gs.entityPose(marker);
if (pose != null) {
pose.setOffsetX(120);
pose.rotateZ(30.0, 0, 0);
}entityWorldMatrix(SceneEntity e)
签名:
default double[] entityWorldMatrix(SceneEntity e);行为:查询实体世界矩阵:16 元素列主序 double[16](与 CameraState 的 V/P 同布局)= 世界(父)·本地(实体) 自顶向下累积(含轨道区偏移与位姿链、本 tick 写入的实体位姿)。返回防御性拷贝,模组可留存;查询任何时机合法(无窗口限制)。无效 / 已销毁句柄返回 null + 限频告警。默认实现返回 null。
示例:
double[] m = gs.entityWorldMatrix(marker);
if (m != null) {
double wx = m[0] * 0 + m[4] * 0 + m[12]; // 本地原点 → 世界
double wy = m[1] * 0 + m[5] * 0 + m[13];
}entityVisible(SceneEntity e)
签名:
default boolean entityVisible(SceneEntity e);行为:查询有效可见性(继承量:父 ∧ 本——任一祖先不可见或已销毁即 false)。无效句柄返回 false。默认实现返回 false。
示例:
if (gs.entityVisible(marker)) {
// 整条父链都可见
}setEntityVisible(SceneEntity e, boolean v)
签名:
default void setEntityVisible(SceneEntity e, boolean v);行为:写实体自身可见性(只影响本节点,默认 true)。不提供「子强制可见」——父不可见 ⇒ 整棵子树不可见。改他人实体被拒绝 + 限频告警;无 tick 窗口限制。
示例:
gs.setEntityVisible(marker, false);entityAlpha(SceneEntity e)
签名:
default double entityAlpha(SceneEntity e);行为:查询有效 alpha(沿父链连乘,默认恒 1)。无效句柄返回 0。默认实现返回 0.0。
示例:
double a = gs.entityAlpha(marker);setEntityAlpha(SceneEntity e, double a)
签名:
default void setEntityAlpha(SceneEntity e, double a);行为:写本节点自身 alpha(乘性继承因子,默认 1)。改他人实体被拒绝 + 限频告警;无 tick 窗口限制。
示例:
gs.setEntityAlpha(marker, 0.5);destroyEntity(SceneEntity e)
签名:
default void destroyEntity(SceneEntity e);行为:显式销毁实体,并级联销毁其子树(挂在其下的模组实体一并销毁)。挂载窗口约束同 mountToTrackArea(tick 内拒绝);改他人实体被拒绝。游玩结束时宿主自动级联销毁全部模组实体,此后句柄失效(查询返回 null / false / 0 + 限频告警),不要跨局缓存句柄。
示例:
gs.destroyEntity(marker);线程:源码未声明额外线程约束。宿主实现直接读写游玩场景与渲染器状态,且 entityPose 仅在 tick 分发期间有效——请在游戏线程(事件回调、tick、渲染回调)调用,不要在自建网络线程上操作。
稳定性:2.0 起冻结:2.x 内只增不破。其中「轨道几何」区块(setLaneRotation / getLaneRotation、setLaneScale / getLaneScaleX / getLaneScaleY、setLaneSkew / getLaneSkew、setLaneArc / getLaneArcBend、setLaneOffset、flashLane、setAltHudForced、cursorPosition / setCursorPosition、laneRotationPivot、trackAreaGeometry、setTrackOffset、setLaneSpeedFactor / getLaneSpeedFactor)标记为实验性:签名稳定,语义仍可能微调;setTrackTilt3D / setTrackTilt3DAuto、setCameraPose / setCameraPoseAuto、project / unproject / cameraPose 与「模组可见层级」区块(createEntity / mountTo* / entityPose / entityWorldMatrix / entityVisible / setEntityVisible / entityAlpha / setEntityAlpha / destroyEntity)同为实验性。3.0 已删除旧的每轨旋转圆心常量(LANE_ROTATE_PIVOT_*)与 setLaneRotation 的 pivot 参数——圆心固定为判定线中点。