API 参考 / 事件系统
事件总表
| 事件类 | 包 | 是否可取消 | 宿主投递时机 | 监听器可读的访问器 |
|---|---|---|---|---|
TickEvent.Pre / TickEvent.Post | com.seecmd.mod.api.event | 否 | 主循环每帧一次;Pre 在本帧逻辑更新之前,Post 在其之后、渲染之前 | deltaSeconds() |
SceneChangeEvent.Pre | com.seecmd.mod.api.event | 是 | 场景切换的决议阶段(历史栈尚未改动) | from()、to()、kind()、params()、isRedirected()、redirectTarget()、redirectParams() |
SceneChangeEvent.Post | com.seecmd.mod.api.event | 否 | 场景切换完成之后(新场景已进入) | from()、to()(均为 SceneInfo) |
SoundPlayEvent | com.seecmd.mod.api.event | 否 | 宿主成功播放一个音效之后 | soundId()、path()、category() |
SettingsChangedEvent | com.seecmd.mod.api.event | 否 | 宿主保存设置后 | changedKeys() |
GameStartupEvent | com.seecmd.mod.api.event | 否 | 契约:装配结束、进入主循环之前;当前源码未见投递点 | 无(纯通知) |
GameShutdownEvent | com.seecmd.mod.api.event | 否 | 契约:释放资源之前;当前源码未见投递点 | 无(纯通知) |
SceneUnregisteredEvent | com.seecmd.mod.api.event | 否 | 模组场景注册被归属校验注销成事实之后 | declaredId()、modId() |
GameStartEvent | com.seecmd.mod.api.event.gameplay | 否 | 一局游玩开始时(谱面就绪、音乐启动) | context() |
GameEndEvent | com.seecmd.mod.api.event.gameplay | 否 | 一局游玩结束时(结算 / 重试 / 退出 / 预览会话关闭) | context() |
ChartLoadEvent | com.seecmd.mod.api.event.gameplay | 否 | 谱面解析完成、进入可游玩状态时(同帧先于 GameStartEvent) | context() |
GameplayTickEvent.Pre / GameplayTickEvent.Post | com.seecmd.mod.api.event.gameplay | 否 | 每个游玩帧各一次;Pre 在本帧游玩逻辑更新之前,Post 在其之后(含倒带重演窗口内的帧) | musicTimeMs()、rewinding()、deltaSeconds()、stepIndex() |
BeatEvent | com.seecmd.mod.api.event.gameplay | 否 | 游玩帧内拍序号与上一帧不同时(每帧至多一次,正反向跨拍都算) | beatIndex()、phase()、bpm()、periodMs()、rewinding() |
NoteJudgedEvent | com.seecmd.mod.api.event.gameplay | 否 | 一个音符完成判定时(含长音符结尾判定),且判定已经落地 | judgeResult()、context() |
ComboBreakEvent | com.seecmd.mod.api.event.gameplay | 否 | 连击被打断时(本次 MISS 导致 combo 归零),且打断已经发生 | context() |
PauseEvent | com.seecmd.mod.api.event.gameplay | 是 | 暂停请求受理时(宿主改状态之前) | context() |
ResumeEvent | com.seecmd.mod.api.event.gameplay | 是 | 恢复请求受理时(宿主改状态之前) | context() |
RewindEvent | com.seecmd.mod.api.event.gameplay | 否 | 倒带重演窗口开始(BEGIN)/ 结束(END)时各一次 | phase()、isBegin()、isEnd()、fromMs()、toMs()、durationMs() |
GhostHitEvent | com.seecmd.mod.api.event.gameplay | 否 | 回放期幽灵音符被击打并产生表现层反馈时(不计分,宿主不再为此发 SoundPlayEvent) | lane()、noteType()、judgment()、musicTimeMs()、note() |
HitEffectLifecycleEvent | com.seecmd.mod.api.event.gameplay | 否 | 打击特效实例创建 / 取消 / 自然到期时;每实例恰好一个消亡事件 | phase()、lane()、noteType()、grade()、startMs()、durationMs()、note() |
PreviewSeekEvent | com.seecmd.mod.api.event.gameplay | 否 | 预览会话完成一次确定性跳转后、下一次正常 Tick 之前 | fromMs()、toMs()、reason()、generation()、context()、durationMs() |
KeyEvent | com.seecmd.mod.api.event.input | 是(契约) | 全局按键分发时(按下 / 抬起 / 长按) | keyCode()、type() |
MouseEvent | com.seecmd.mod.api.event.input | 是(契约) | 契约:场景级鼠标分发时;当前宿主未投递 | type()、x()、y()、button() |
LaneInputEvent.Pre | com.seecmd.mod.api.event.input | 是 | 本局游玩期间玩家按键映射到轨道、判定之前 | lane()、keyCode()、musicTimeMs() |
LaneInputEvent.Post | com.seecmd.mod.api.event.input | 否 | 本局游玩期间输入已被消费之后 | lane()、keyCode()、musicTimeMs() |
RenderEvent.Pre / RenderEvent.Post | com.seecmd.mod.api.event.render | 否 | 每个渲染层内容绘制的前后各一次;共 7 层,每帧 14 次 | layer()、context() |
TrackRenderEvent.Pre / TrackRenderEvent.Post | com.seecmd.mod.api.event.render | 否 | 轨道渲染器入口 / 出口各一次(只在游玩场景投递) | context()、musicTimeMs()、scrollSpeed()、visibleNoteCount() |
ResourceReloadEvent | com.seecmd.mod.api.event.resource | 否 | 宿主真实切换语言并完成重载时投递 LANGUAGE;RESOURCES 当前无发布点 | kind()、detail() |
HostCommandEvent | com.seecmd.mod.api.event.host | 否 | 宿主终端执行命令时(宿主事实转播) | command() |
HostGameResultEvent | com.seecmd.mod.api.event.host | 否 | 结算界面统计定稿时(与 GameEndEvent 时机 / 信息面均不同) | chartFile()、cleared()、misses()、perfects()、greats()、maxCombo()、totalScore()、grade() |
HostAudioSpeedEvent | com.seecmd.mod.api.event.host | 否 | 全局播放速度变化生效时(局部变速不投递) | oldSpeed()、newSpeed() |
实现核验补充(按当前宿主源码):
SceneUnregisteredEvent位于根包com.seecmd.mod.api.event,不在gameplay包。GameStartupEvent/GameShutdownEvent在全仓源码中未检索到new .../post(...)投递点,订阅后可能永远收不到;初始化与收尾请以Mod#onInit/Mod#onUnload为准。com.seecmd.mod.api.event.input.MouseEvent当前宿主没有投递点(仅验收壳直接post用于验证短路语义),不要依赖它接收鼠标。KeyEvent在类型上可取消,但宿主转播桥(GlobalKeyEventRelay)只转译、不读取结果,因此DENY目前不会阻止按键继续分发;需要拦截按键请用LaneInputEvent.Pre。ResourceReloadEvent.Kind.RESOURCES没有宿主发布点;Kind.LANGUAGE有真实发布点。