GameplayContext
游玩状态只读视图。宿主在事件发布与滤镜调用时构造快照,模组可在 GameStartEvent / ChartLoadEvent / NoteJudgedEvent / ComboBreakEvent / GameEndEvent / PauseEvent / ResumeEvent 的 context(),以及 FilterFrame#context()、JudgmentAdjuster#adjust(JudgeResult, GameplayContext) 中拿到它。下文示例中的 ctx 均指这样取得的 GameplayContext 快照。
方法速览
| 方法 | 用途 |
|---|---|
musicTimeMs() | 当前音乐时间 τ(毫秒),倒带期非单调 |
combo() | 当前连击数 |
score() | 当前分数 |
perfects() / greats() / misses() | 三种内置判定计数 |
maxCombo() | 历史最大连击 |
paused() | 是否暂停 |
finished() | 是否已结束 |
preview() | 是否来自编辑器/宿主的内嵌预览会话 |
sessionId() | 游玩会话 id(实机为空串) |
hostKind() | 宿主类型 game / editor / cli |
chartTitle() / chartAuthor() / chartDifficulty() | 谱面元数据三项 |
progress() | 按已判音符数计算的进度 0-1 |
disorderActive() 等 7 个 | 无序模式(disorder)状态与充能条数据 |
chartDurationMs() | 谱面末音符时间(毫秒) |
totalNoteCount() / judgedNoteCount() / remainingNoteCount() | 音符总数 / 已判 / 剩余 |
musicPositionRatio() | 按音乐时间线计算的进度 0-1 |
accuracy() | 准度 0-1 |
judgmentWindowMs() | 合并后的当前判定窗口(可能为 null) |
defaultJudgmentWindowMs() | 内置默认判定窗口 70/150/150/150/50 |
chartBpm() | 谱面 0ms 处的主 BPM |
pendingNotes() | 3 秒预告窗口内的待判定音符 |
nextNote() | 下一个待判定音符(比列表轻量) |
lanes() | 当前渲染中的全部轨道视图 |
altHudActive() / altComboCenterX() / altComboBottomY() | AltHud 激活状态与 COMBO 区定位 |
coverImage() | 谱面曲绘句柄(无则 null) |
currentModeId() | 当前激活模式 id |
chartView() | 谱面元数据只读视图 |
isRewinding() | 是否处于暂停恢复的倒带重演窗口 |
hp() / maxHp() | 游玩期血量快照(未提供为 -1) |
noteById(long) | 按稳定实例 id 反查音符 |
notesInWindow(int, long, long) | 时间窗批量查询音符 id |
activeHitEffects() | 存活的活动打击特效句柄 |
audioDurationMs() | 音频真实时长 |
beatNumerator() / beatDenominator() | 拍号(当前恒 4/4) |
beatIndex() / beatPhase() / beatBpm() / beatPeriodMs() | 节拍快照(τ 的纯函数) |
musicTimeMs()
long musicTimeMs();行为:当前音乐时间 τ(毫秒)。倒带重演窗口内非单调(先倒流回 T-3s 再正向重演回 T),依赖「时间只增」的模组必须先查 isRewinding()。
示例:
long now = ctx.musicTimeMs();combo()
int combo();行为:当前连击数,被 MISS 打断后归零;与 maxCombo() 不可互替。
示例:
if (ctx.combo() >= 100) { /* 百连演出 */ }score()
int score();行为:当前总分(宿主计分器实时值)。 示例:
int score = ctx.score();perfects()
int perfects();行为:本局 PERFECT 计数。示例:
int p = ctx.perfects();greats()
int greats();行为:本局 GREAT 计数。示例:
int g = ctx.greats();misses()
int misses();行为:本局 MISS 计数(含漏接与超窗)。示例:
int m = ctx.misses();maxCombo()
int maxCombo();行为:历史最大连击数(不随当前连击归零而减小)。示例:
int best = ctx.maxCombo();paused()
boolean paused();行为:当前是否处于暂停态。暂停菜单期间为 true;恢复倒计时期间为 false(宿主在进入倒计时前已清除暂停位,倒带窗口改由 isRewinding() 表达)。示例:
if (ctx.paused()) return;finished()
boolean finished();行为:本局是否已结束(结算流程启动后为 true)。示例:
boolean over = ctx.finished();preview()
default boolean preview();行为:本上下文是否来自编辑器/宿主的内嵌预览会话。预览与实机共用同一判定/渲染内核,但预览不访问音频设备、不写统计;模组据此决定是否把本局计入统计、是否播放真实音效。默认返回 false(既有实现者无需改动)。
示例:
if (ctx.preview()) { /* 预览模式:不要写持久化统计 */ }sessionId()
default String sessionId();行为:当前游玩会话 id。实机为空串;编辑器预览返回创建时指定的 id(如 "viewport-3"),用于多视口下区分同一模组的状态。默认返回 ""。
示例:
String key = "hud:" + ctx.sessionId();hostKind()
default String hostKind();行为:宿主类型。默认 "game";当前宿主在预览会话中返回 "editor"。"cli" 为预留取值。
示例:
boolean inEditor = "editor".equals(ctx.hostKind());chartTitle()
String chartTitle();行为:谱面标题;谱面元数据缺失时为空串。示例:
String title = ctx.chartTitle();chartAuthor()
String chartAuthor();行为:谱面作者(metadata.charter);缺失时为空串。示例:
String author = ctx.chartAuthor();chartDifficulty()
String chartDifficulty();行为:谱面难度名;缺失时为空串。示例:
String diff = ctx.chartDifficulty();progress()
double progress();行为:游玩进度 0-1,口径为「已判音符数 / 总音符数」,上限钳到 1;总音符数为 0 时返回 0。注意与 musicPositionRatio() 口径不同。
示例:
double byNotes = ctx.progress();disorderActive()
boolean disorderActive();行为:无序模式当前是否激活(无 disorder 引擎时为 false)。示例:
if (ctx.disorderActive()) { /* 绘制无序特效 */ }disorderRemainingRatio()
float disorderRemainingRatio();行为:无序剩余时间比例 1→0;未激活时为 0。示例:
float left = ctx.disorderRemainingRatio();disorderChargeRatio()
float disorderChargeRatio();行为:无序充能进度比例 0-1;未激活时为 0。示例:
float charge = ctx.disorderChargeRatio();disorderChargeBarVisible()
boolean disorderChargeBarVisible();行为:充能条当前是否可见(充能中 / 成功闪烁 / 失败闪烁)。示例:
boolean bar = ctx.disorderChargeBarVisible();disorderChargeBarFlashingOn()
boolean disorderChargeBarFlashingOn();行为:成功闪烁时当前是否为「亮」周期;按接口约定,非成功闪烁状态恒返回 true(宿主直接透传无序引擎的判定,无引擎时为 false)。示例:
boolean bright = ctx.disorderChargeBarFlashingOn();disorderEndingSoon()
boolean disorderEndingSoon();行为:无序剩余时间是否 ≤ 2000ms。示例:
if (ctx.disorderEndingSoon()) { /* 收尾提示 */ }disorderRemainingTimeMs()
long disorderRemainingTimeMs();行为:无序模式剩余毫秒;未激活时为 0。示例:
long ms = ctx.disorderRemainingTimeMs();chartDurationMs()
long chartDurationMs();行为:谱面总时长(毫秒),取末个音符的结束时间(长音符取 endTime,否则取 time),并非音频文件时长;无谱面时为 0。音频真实时长见 audioDurationMs()。
示例:
long chartLen = ctx.chartDurationMs();totalNoteCount()
int totalNoteCount();行为:谱面总音符数(Hold 算 1)。示例:
int total = ctx.totalNoteCount();judgedNoteCount()
int judgedNoteCount();行为:已判定音符数(含 MISS)。示例:
int judged = ctx.judgedNoteCount();remainingNoteCount()
int remainingNoteCount();行为:等于 totalNoteCount() - judgedNoteCount()。示例:
int rest = ctx.remainingNoteCount();musicPositionRatio()
double musicPositionRatio();行为:按音乐时间线计算的进度,musicTimeMs / chartDurationMs 并 clamp 到 [0,1];音乐未启动(τ ≤ 0)或谱面时长 ≤ 0 时返回 0。与按音符数计算的 progress() 不同,倒带期会随 τ 回退。
示例:
double byMusic = ctx.musicPositionRatio();accuracy()
double accuracy();行为:准度 0-1,口径为 PERFECT=1.0 / GREAT=0.5 / MISS=0,按已判音符加权平均(分母 = perfect+great+miss);无已判音符时为 0。注意与 ResultSnapshot.accuracy() 的 0-100 百分比口径不同。
示例:
double acc = ctx.accuracy();judgmentWindowMs()
JudgmentPolicy judgmentWindowMs();行为:合并后的当前判定窗口快照(含 perfect/great/miss/holdEnd/lateCutoff 5 个方法),实例不可变。宿主的模组系统未就绪时返回 null,调用前必须判空。
示例:
JudgmentPolicy w = ctx.judgmentWindowMs();
long perfectMs = w != null ? w.perfectWindowMs() : 70L;defaultJudgmentWindowMs()
JudgmentPolicy defaultJudgmentWindowMs();行为:游戏内置默认判定窗口(70/150/150/150/50),供对比当前窗口与默认窗口的差异;宿主恒返回同一不可变实例。示例:
long base = ctx.defaultJudgmentWindowMs().perfectWindowMs();chartBpm()
int chartBpm();行为:谱面主 BPM,取 0ms 处的 BPM 段并四舍五入为 int;无 BPM 信息时为 0。与 beatBpm()(τ 所在段)不同。
示例:
int bpm = ctx.chartBpm();pendingNotes()
List<NoteView> pendingNotes();行为:3 秒预告窗口内的待判定音符视图,按时间升序。窗口为 time ∈ [τ - missWindow, τ + 3000](missWindow 取当前合并判定窗口的 miss 值,默认 150ms),且只保留尚未判定的音符(Hold 以其起始时间入窗)。返回不可变列表(同一次快照内多次调用返回同一实例;宿主的每帧上下文快照本身是新的)。不要在每帧路径上反复取用或长期持有——建议在 ChartLoadEvent 缓存或用 nextNote() 代替。
示例:
List<NoteView> upcoming = ctx.pendingNotes();
for (NoteView n : upcoming) {
if (n.isHold()) { /* 预告长条 */ }
}nextNote()
NoteView nextNote();行为:预告列表的首个元素(时间最早、未判定),无则返回 null;比 pendingNotes() 轻量,逐帧场景优先用它。
示例:
NoteView next = ctx.nextNote();
long leadMs = next != null ? next.time() - ctx.musicTimeMs() : -1L;lanes()
List<LaneView> lanes();行为:当前渲染中的全部轨道视图(真轨在前、假轨在后,按渲染顺序),不可变列表。整份列表在上下文快照构造期生成,不要每帧调用后长期持有。几何语义见 LaneView。 示例:
List<LaneView> lanes = ctx.lanes();
double x = lanes.isEmpty() ? 0 : lanes.get(0).x();altHudActive()
boolean altHudActive();行为:AltHud(备用简单 HUD 取代普通 HUD)是否激活,等价于 altUiAlpha > 0.01。提示类 HUD 模组应仅在激活时绘制,避免与普通 HUD 重叠。
示例:
if (!ctx.altHudActive()) return;altComboCenterX()
double altComboCenterX();行为:AltHud 顶部中央 COMBO 矩形的水平中心(画布坐标,1280×720 逻辑空间);仅在 altHudActive() 为 true 时有意义,否则为上次记录的陈旧值。
示例:
double cx = ctx.altComboCenterX();altComboBottomY()
double altComboBottomY();行为:AltHud 顶部中央 COMBO 矩形的底边 y(画布坐标);提示 HUD 以此向下排布,同样仅在 altHudActive() 时有意义。
示例:
double baseline = ctx.altComboBottomY() + 8;coverImage()
com.seecmd.mod.api.render.RenderImage coverImage();行为:当前谱面曲绘(谱面选择界面展示的封面图,约定存放于 data/charts/chaets_ill/,文件名与谱面同名,支持 .png / .jpg);无曲绘返回 null。返回的句柄在整局游玩中复用(宿主懒加载一次并缓存),不是每次调用的新快照;像素处理结果请自行缓存,避免重复计算。
示例:
RenderImage cover = ctx.coverImage();
int[] pixels = cover != null ? cover.getPixelsARGB() : null;currentModeId()
String currentModeId();行为:当前激活的游戏模式 id(如 seecmd:normal / seecmd:disorder);模式未就绪时宿主回退为 seecmd:normal。
示例:
boolean normal = "seecmd:normal".equals(ctx.currentModeId());chartView()
ChartView chartView();行为:当前谱面元数据只读视图(含 JSON extensions 解析结果);当前宿主每次快照都构造新视图,字段来自 chartData,谱面未加载时为空串 / 0、chartPath() 可能为 null,调用不抛异常。详见 ChartView。
示例:
ChartView chart = ctx.chartView();
int lanes = chart.laneCount();isRewinding()
default boolean isRewinding();行为:是否处于暂停恢复的倒带重演窗口(含倒流段与正向重演段,与 GameplayTickEvent.rewinding() 同源同值)。窗口内 τ 非单调且不产生新判定;累积型状态应改为按 τ 求值或在窗口开始处重建。默认返回 false。
示例:
if (ctx.isRewinding()) { rebuildFromMusicTime(ctx.musicTimeMs()); }hp()
default int hp();行为:游玩期血量只读快照,与宿主结算页同源(0 = 死亡判定线);上下文未提供时为 -1。默认返回 -1。
示例:
int hp = ctx.hp();
if (hp >= 0 && hp < 200) { /* 低血量提示 */ }maxHp()
default int maxHp();行为:血量上限,与 hp() 同源;未提供时为 -1。默认返回 -1。
示例:
double hpRatio = ctx.maxHp() > 0 ? ctx.hp() / (double) ctx.maxHp() : 0.0;noteById(long)
default NoteView noteById(long noteId);行为:按稳定实例 id 反查音符,覆盖本局全部音符(已判定 / MISS / Payload 均在册);线性扫描全谱,id 不在册或上下文未提供查询时返回 null;id 为负直接返回 null。不应每帧调用。默认返回 null。
示例:
NoteView n = ctx.noteById(noteId);
if (n != null) { long t = n.time(); }notesInWindow(int, long, long)
default long[] notesInWindow(int lane, long fromMs, long toMs);行为:时间窗批量查询音符稳定 id。lane 为负 = 全轨,lane ≥ 0 仅该轨;时间窗按音符 time ∈ [fromMs, toMs] 双端含边界,fromMs > toMs 返回空数组;结果按谱面顺序(noteId 升序 = 解析期分配序)排列,无随机、无墙钟——同一谱面同一窗口恒得同一序列。覆盖本局全部音符(与 noteById 同一数据源)。这是只读查询,不是批量写原语;线性扫描全谱并构造新数组,不应每帧调用。默认返回空数组。
示例:
long[] ids = ctx.notesInWindow(-1, 10000L, 12000L);
for (long id : ids) { /* 逐个处理,例如读 NoteView 或写音符级变换 */ }activeHitEffects()
default List<ActiveHitEffect> activeHitEffects();行为:当前存活的活动打击特效句柄列表(只读、可能为空、不为 null)。特效以 τ 计活——倒带期 τ 回退到产生点之前时不在列表、正向重播期重演。句柄支持属性修改与销毁,见 ActiveHitEffect。宿主在每次上下文快照构造时收集并新建句柄,不应每帧调用。默认返回空列表。
示例:
for (ActiveHitEffect fx : ctx.activeHitEffects()) {
if (fx.durationMs() < 80L) fx.setDurationMs(80L);
}audioDurationMs()
default long audioDurationMs();行为:音频真实时长(毫秒)——实机取宿主音频引擎缓存的 chart_music 时长,预览会话取谱面末音符时长(不访问音频设备),未起播/未知为 0。与 chartDurationMs() 区分。默认返回 0。
示例:
long audio = ctx.audioDurationMs();beatNumerator()
default int beatNumerator();行为:拍号分子。谱面 JSON 不携带拍号,宿主当前恒返回 4;变拍号属未来扩展,不要假设它随谱面变化。默认返回 4。
示例:
int num = ctx.beatNumerator();beatDenominator()
default int beatDenominator();行为:拍号分母,与 beatNumerator() 同口径,当前恒为 4。默认返回 4。
示例:
int den = ctx.beatDenominator();beatIndex()
default long beatIndex();行为:当前拍序号——自 τ 所在 BPM 段起点的整拍数(floorDiv),可为负 = count-in。正常推进 / 倒带重演 / 暂停冻结三态下同一 τ 恒得同一值(与 BeatGrid 同一实现)。首帧前的快照为 -1。默认返回 -1。
示例:
long beat = ctx.beatIndex();
if (beat >= 0 && beat % 4 == 0) { /* 小节线 */ }beatPhase()
default double beatPhase();行为:当前拍相位 [0,1),0 = 正落在拍点上;与 beatIndex() 同源。不可用时为 -1。默认返回 -1。
示例:
double phase = ctx.beatPhase();beatBpm()
default double beatBpm();行为:τ 所在 BPM 段的 BPM(变 BPM 谱面在段切换处随之变化),区别于 chartBpm() 的「0ms 处主 BPM」;不可用为 0。默认返回 0。
示例:
double bpm = ctx.beatBpm();beatPeriodMs()
default long beatPeriodMs();行为:当前拍长(毫秒),= round(60000 / beatBpm);不可用为 0。默认返回 0。
示例:
long halfBeat = ctx.beatPeriodMs() / 2;完整签名
public interface GameplayContext {
long musicTimeMs();
int combo();
int score();
int perfects();
int greats();
int misses();
int maxCombo();
boolean paused();
boolean finished();
default boolean preview();
default String sessionId();
default String hostKind();
String chartTitle();
String chartAuthor();
String chartDifficulty();
double progress();
boolean disorderActive();
float disorderRemainingRatio();
float disorderChargeRatio();
boolean disorderChargeBarVisible();
boolean disorderChargeBarFlashingOn();
boolean disorderEndingSoon();
long disorderRemainingTimeMs();
long chartDurationMs();
int totalNoteCount();
int judgedNoteCount();
int remainingNoteCount();
double musicPositionRatio();
double accuracy();
JudgmentPolicy judgmentWindowMs();
JudgmentPolicy defaultJudgmentWindowMs();
int chartBpm();
List<NoteView> pendingNotes();
NoteView nextNote();
List<LaneView> lanes();
boolean altHudActive();
double altComboCenterX();
double altComboBottomY();
com.seecmd.mod.api.render.RenderImage coverImage();
String currentModeId();
ChartView chartView();
default boolean isRewinding();
default int hp();
default int maxHp();
default NoteView noteById(long noteId);
default long[] notesInWindow(int lane, long fromMs, long toMs);
default long audioDurationMs();
default int beatNumerator();
default int beatDenominator();
default long beatIndex();
default double beatPhase();
default double beatBpm();
default long beatPeriodMs();
default List<ActiveHitEffect> activeHitEffects();
}线程:源码未声明额外线程约束。宿主均在渲染线程构造快照并同步投递给模组回调(单线程语义)。
性能:pendingNotes() / lanes() / activeHitEffects() 的列表在快照构造期一次性生成、以不可变包装复用;noteById() / notesInWindow() 每次线性扫描全谱;coverImage() 句柄整局复用。这些都不要放进每帧路径。
稳定性:2.0 起冻结:2.x 内只增不破。preview() / sessionId() / hostKind() 为 3.2 新增、isRewinding() 为 2026-10 特性、 系列方法(hp / noteById / notesInWindow / beat* / activeHitEffects)均为 default,既有实现者零改动。