高级 - LingFeng-bbben/MajdataPlay GitHub Wiki

此页用于记录Majdata Play部分实现细节

判定

Majdata Play每帧会对处于活动状态的Note进行判定,判定区间为半开半闭区间

请注意,Majdata Play内所有判定区间上界与下界单位都是ms,特殊情况会额外进行说明

PlayerLoop流程简化图如下:

      ---------------
      |  PreUpdate  |
      ---------------
             |
    MajTimeline.PreUpdate
             |
   InputManager.PreUpdate
             |
INoteTimeProvider.PreUpdate
             |
   NoteManager.PreUpdate
             |
     NoteDrop.PreUpdate
             |
        ------------
        |  Update  |
        ------------
             |
      NoteDrop.Update
             |
      ----------------
      |  LateUpdate  |
      ----------------
             |
 NoteAudioManager.LateUpdate
             |
     NoteDrop.LateUpdate (if exists)
             |
   EachLineDrop.LateUpdate

Tap

Source: NoteDrop.cs#L165

总区间: [-150,150]

详情:

为方便查看,表格内使用帧数表示区间上界与下界

1f 表示60帧下的1帧间隔,换算成ms1f * 16.6666

等级 范围 累计
TooFast (-inf, -9f) None
FastGood [-9f, -6f) 3f
FastGreat 3rd [-6f, -5f) 1f
FastGreat 2nd [-5f, -4f) 1f
FastGteat 1st [-4f, -3f) 1f
FastPerfect 3nd [-3f, -2f) 1f
FastPerfect 2nd [-2f, -1f) 1f
Perfect [-1f, 1f] 2f
LatePerfect 2nd (1f, 2f] 1f
LatePerfect 3nd (2f, 3f] 1f
LateGteat 1st (3f, 4f] 1f
LateGreat 2nd (4f, 5f] 1f
LateGreat 3rd (5f, 6f] 1f
LateGood (6f, 9f] 3f
Miss (9f, inf) None

Hold

Head

参见 Tap

Body

Source: HoldDrop.cs#L449

Majdata Play会忽略Hold的开头6f与结尾12f,并且会根据头部判定对Hold时值进行修正,详情参见Hold 尾判判定

当累计释放时长大于2f,也就是33.3333ms时,才会认为Hold被释放,并累计释放时长

Tail

Source

Deluxe

当判定误差(_judgeDiff)为Fast(_judgeDiff < 0) 时,不对Hold时值进行修正

当判定误差为Late时,会从Length减去_judgeDiff再进行尾判

如果Hold修正后的时值小于等于0.3s,不会进行尾判,最终判定等级为头部判定等级

以下是尾判修正的详细说明:

Tip: 为方便表述,下面将使用p表示“Hold完成比例”

  • p >= 1
    • 如果头判为Great 2nd/3rd,向上修正为Great
    • 如果头判为Good,向上修正为Great
    • 如果头判为Miss,向上修正为Good
    • 其他等级不进行任何修正
  • p >= 0.67
    • 如果头判为Critical Perfect, 向下修正为Perfect 2nd
    • 如果头判为Great 2nd/3rd,向上修正为Great
    • 如果头判为Good,向上修正为Great
    • 如果头判为Miss,向上修正为Good
  • p >= 0.33
    • 如果头判等级比Great高,向下修正为Great
    • 如果头判为Great 2nd/3rd,向上修正为Great
    • 如果头判为Good,向上修正为Great
    • 如果头判为Miss,向上修正为Good
  • p >= 0.05
    • 如果头判等级比Good高,向下修正为Good
    • 如果头判为Miss,向上修正为Good
  • p >= 0
    • 如果头判等级比Good高,向下修正为Good

Slide

注意

Slide常数由内录/判定区图片叠加分析得出,数值可能不准确

Slide Deluxe判定实现参考自: maimai判定详解 - Moying

感谢软壳与热心mai友提供Great子区间

总区间: (-inf,600]

_lastWaitTime为Slide在最后一个判定区的停留时间

_table.Const/wifiConst为Slide在最后一个判定区滞留时间与Slide时值的比例

Deluxe

Perfect区间不是静态的,此区间会根据_lastWaitTime动态扩展,由基础区间+扩展区间组成

基础区间: [-14f, 14f]

扩展区间: ext = _lastWaitTime / 4,最大为22f

扩展时,Perfect会挤占Great、Good区间,详情见图:

扩展前:

| <-  Fast Great(15f)  ->| <-  Perfect(28f)  -> | <-  Late Great(15f)  -> |

扩展后:

| <-  Fast Great(10f)  ->| <-       Perfect(28 + 10f)     -> | <-  Late Great(10f)  -> |

对比:
| <-  Fast Great(15f)  ->| <-  Perfect(28f)  -> | <-  Late Great(15f)  -> |
                | <-           Perfect(28 + 10f)      -> |

为实现旧框体的严判,Majdata Play自行实现了Perfect子区间:

Perfect: (基础区间+扩展区间) * 0.3333

Perfect 2nd: (基础区间+扩展区间) * 0.6666

Perfect 3rd: 基础区间+扩展区间

当严判被关闭时,Slide会自动将Perfect 2ndPerfect 3rd修正为Perfect

详情:

等级 范围 累计
FastGood (-inf, -29f) None
FastGreat 3rd [-29f, -25f) 4f
FastGreat 2nd [-25f, -21f) 4f
FastGteat 1st [-21f, -14f) 7f
Perfect [-14f, 14f] 28f
LateGteat 1st (14f, 21f] 7f
LateGreat 2nd (21f, 25f] 4f
LateGreat 3rd (25f, 29f] 4f
LateGood (36f, 29f] 7f
Miss (36f, inf) None

FiNALE

Warning

FiNALE Slide判定由手元、谱面确认、软壳经验分析而得,数据可能不准确

欢迎在issue提出任何提案

Finale的Perfect区间是静态的,不会根据Slide在最后一个判定区停留时长动态扩展

为兼容Deluxe的Break Slide,Majdata Play自行实现了FiNALE的Great子区间:

详情:

等级 范围 累计
FastGood (-inf, -27f) None
FastGreat 3rd [-27f, -21f) 6f
FastGreat 2nd [-21f, -15f) 6f
FastGteat 1st [-15f, -9f) 6f
FastPerfect 3nd [-9f, -6f) 3f
FastPerfect 2nd [-6f, -3f) 3f
Perfect [-3f, 3f] 6f
LatePerfect 2nd (3f, 6f] 3f
LatePerfect 3nd (6f, 9f] 3f
LateGteat 1st (9f, 15f] 6f
LateGreat 2nd (15f, 21f] 6f
LateGreat 3rd (21f, 27f] 6f
LateGood (36f, 21f] 15f
Miss (36f, inf) None

Touch

Source: NoteDrop.cs#L177

总区间: [-150, 316.6666]

Touch不存在Fast子判定,当当前帧时间大于-150ms时接受判定

为兼容Break Touch,Majdata Play自行实现了Perfect与Great的子区间:

Perfect子区间Step: (12f - 9f) / 2 = 1.5f
Great子区间Step: (15f - 12f) / 3 = 1f

因此,Perfect的子区间并不是完整的1帧

详情:

等级 范围 累计
Perfect [-9f, 9f] 18f
LatePerfect 2nd (9f, 10.5f] 1.5f
LatePerfect 3nd (10.5f, 12f] 1.5f
LateGteat 1st (12f, 13f] 1f
LateGreat 2nd (13f, 14f] 1f
LateGreat 3rd (14f, 15f] 1f
LateGood (15f, 18f] 3f
Miss (38f, inf) None