using System; /// /// FAST/SLOW 早晚反馈预埋接口。 /// /// 判定命中时(非 Miss)由判定逻辑广播一次带符号的时间偏移,供 UI 层显示"早/晚"提示、 /// 或供校准/统计模块消费。默认无任何订阅者时为 no-op,不产生任何行为、不影响判定与计分。 /// /// 约定(与 osu 系惯例一致): /// signedOffsetMs = (pressTime - hitTime) * 1000 /// > 0 → 按晚了(SLOW / Late) /// < 0 → 按早了(FAST / Early) /// = 0 → 正中 /// /// 纯附加接口:不改变任何现有判定/计分业务逻辑。接入方只需订阅 OnJudgeOffset。 /// public static class JudgeFeedback { public enum Timing { Exact, Fast, // 偏早 Slow // 偏晚 } /// /// 判定偏移事件。参数:(trackIndex, judgeResult, signedOffsetMs, timing)。 /// 仅在命中档(Perfect/Great/Good)判定成功时触发;Miss 不触发(无有效偏移)。 /// public static event Action OnJudgeOffset; /// /// 将带符号偏移归类为 Fast/Slow/Exact。deadZoneMs 内视为正中(默认 0,即严格按符号)。 /// public static Timing Classify(float signedOffsetMs, float deadZoneMs = 0f) { if (signedOffsetMs > deadZoneMs) return Timing.Slow; if (signedOffsetMs < -deadZoneMs) return Timing.Fast; return Timing.Exact; } /// /// 由判定逻辑调用,广播一次早晚反馈。无订阅者时为 no-op。 /// 内部吞掉订阅者异常,保证反馈通道永不影响判定主流程。 /// public static void Report(int trackIndex, string judgeResult, float signedOffsetMs) { var handler = OnJudgeOffset; if (handler == null) return; // 预埋:默认无接入,零开销、零副作用。 try { handler.Invoke(trackIndex, judgeResult, signedOffsetMs, Classify(signedOffsetMs)); } catch { // 反馈通道故障绝不能影响判定/计分。 } } }