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
{
// 反馈通道故障绝不能影响判定/计分。
}
}
}