判定差のお話
2019.04.28
前回の続きっぽい別バナです。
って感じに前後関係が追いにくいからblogって嫌いなのよね。このあたりはそのうちまとめて別ページにします。

まず判定差(ここではプレイの度に挙動が違う場合のある動作すべての意味)について、ガチ勢な方から提供頂いた貴重な情報をまとめてみます。
Ringedge時代はさらに他にも要因があったようですがとりあえずそこは省略します。

・筐体差
筐体(Nu/IOボード)に依存する固有の挙動。基本的に固定。アップデートで変化することがある。

・日付差/起動差
divaアプリ自体の再起動(筐体再起動/一旦Nuのサービスモードに戻る等)をする度に判定が変化することがある。

・ステージ差
特定のステージのみで判定が変化することがある。

・PV分岐差
分岐する/しないにより、その後のノーツの判定が変化することがある。

・時間差
上記の要因によらず、判定が変化することがある。

ということらしいですが、もちろん体感さっぱりわからん。
判別方法というのもあるらしく、

とのことだけど
「○が広ければxxx台」
とか言われてもどうやって○が広いかどうかを判別しろと。いや、原理は解るけどできません。

ところで、ここの記事はあくまで判定差の原因を突き止めようというだけで、ハイスコアを出してランキングインを目指そう、とかそういうページではないですよ。
腕があればお立ち台とか載ってみたいがな!
というわけなので、情報ソースはランカーの人達が気にするノーツ、つまりHOLDの入出ノーツになるけど、そんなに偶然キーとなるノーツばかりが変化する訳はないので、スコアタに関係ないノーツでもこのような事象は発生しているはず。

ただ、何をもって、「変化した」と定義するかは難しい。
たとえば「C-C MAX」が限られた条件だけで入るという判定差で、もしその筐体のすべての動作が正確に2倍速で動いたとして、超人が居ればやはり「C-C MAX」は入る。明らかに実時間で言えばCOOL期間は半分だけど、それは今回の検証として「変化した」とは言えない。
やはり、指標としては、ホールドノーツのちょうど5秒後にノーツがあって、MAXを取った後に判定がどうなるか、かな。
前回の解析結果によると、SAD/SAFEが一番期間が短いので、SAFEでホールド入って、5秒後のノーツでMAX取ったあとにSAFEを取れるか、とか。
でもHOLDを絡めないで検証したいんだよね。
※HOLDを絡めると、PVをそこまで進めないと検証できない、という、めんどくさいだけの話です。

まあそれはそれとして、課題だった奴。HOLD点の増加基準。結果解れば単純ですが、処理は結構やっかいでした。

はい、またいきなりソースです。HOLD関連処理関数です。
・引数
rcx=HOLD処理構造体アドレス
r8=押されているボタン(0x40)、○(0x80)、×(0x100)、□(0x200)のor
xmm1=前回この関数が呼ばれてからの経過時間

ちなみにこの関数自体は、どうやらVSYNCに同期して呼び出されるようです。
わりと冗長な処理とかもあるので関係ないところはがっつり削ったり順序変えたりしてます

14012C9F3: mov         rdi,rcx
14012C9F6: mov         ecx,dword ptr [rcx+0Ch]         ;ホールド状態
14012CA15: dec         ecx
14012CA17: je          000000014012CA97                ;ホールド中はjmp
14012CA1C: dec         ecx
14012CA1E: je          000000014012CA73                ;MAX到達で飛ぶ


14012CA97: mov         ecx,dword ptr [rdi+10h]         ;ホールド中のボタン。
14012CA9A: test        ecx,ecx
14012CA9C: je          000000014012CA44


14012CA9E: mov         eax,ecx
14012CAA0: and         eax,r8d
14012CAA3: cmp         eax,ecx
14012CAA5: jne         000000014012CA84                ;押されているボタンが減った処理へ


14012CAAC: xorps       xmm0,xmm0
14012CAA7: addss       xmm6,dword ptr [rdi+14h]        ;ホールド開始からの時間
14012CAB8: movss       dword ptr [rdi+14h],xmm6        ;ホールド時間を更新
14012CAB4: mov         r15d,dword ptr [rdi+18h]        ;ホールド点(ゲーム中のHOLDボーナスバー表示)
14012CABD: subss       xmm6,dword ptr [rdi+2Ch]        ;最後にボタンが追加されてからの時間
14012CACC: comiss      xmm6,dword ptr [140999A70h]     ;5.000
14012CAD3: jb          000000014012CADD                ;最後にボタン追加されてから5秒経ってないとjmp
14012CAD5: movss       xmm6,dword ptr [140999A70h]     ;5.000を超過したら5.000に丸め込み
14012CADD: comiss      xmm6,dword ptr [rdi+1Ch]        ;0.167。ただしボタン追加されたら0になる。
14012CAE1: jbe         000000014012CB2D                ;ホールド開始から0.167s経過していないとjmp


14012CAE3: mov         r8d,dword ptr [rdi+24h]         ;1フレームあたりのホールド点。ボタン数で変化
14012CAE7: mov         eax,r8d
14012CAEA: cdq
14012CAEB: sub         eax,edx
14012CAED: sar         eax,1
14012CAEF: movd        xmm0,r8d
14012CAF4: cvtdq2ps    xmm0,xmm0
14012CAF7: mulss       xmm0,xmm6
14012CAFB: divss       xmm0,dword ptr [rdi+20h]        ;[rdi+20h]=常に0.017 xmm0=xmm0/0.017
14012CB00: cvttss2si   ecx,xmm0
14012CB04: add         eax,ecx
14012CB06: cdq
14012CB07: idiv        eax,r8d
14012CB0A: mov         ebx,eax
14012CB0C: imul        ebx,r8d                         ;ebx=round([rdi+24h] * xmm6 / [rdi+20h])
14012CB10: cmp         dword ptr [rdi],esi
14012CB12: jne         000000014012CB23


14012CB2D: mov         ecx,dword ptr [rdi+30h]         ;ホールド追加した時点の点数
14012CB30: add         ecx,ebx
14012CB36: mov         ebp,ecx
14012CB38: mov         dword ptr [rdi+18h],ecx
;ebp=現時点の総ホールド点
;r15d=加算済みホールド点


14012CB41: sub         ebp,r15d                        ;今回の加算点
14012CB52: comiss      xmm6,dword ptr [140999A70h]     ;5.000
14012CB59: mov         dword ptr [rax+74h],3
14012CB60: mov         dword ptr [rax+78h],ebx
14012CB63: mov         dword ptr [rax+7Ch],r12d
14012CB67: jb          000000014012CA4C                ;5.000未満


;MAX到達処理
14012CB6D: mov         eax,dword ptr [rdi+34h]         ;同時押しボタン数
14012CB7B: imul        eax,eax,5DCh                    ;eax*1500=MAXボーナス
14012CB81: mov         dword ptr [rdi+3Ch],eax         ;MAX点を保持、この時点では加算されない
14012CB74: mov         dword ptr [rdi+0Ch],2
14012CB84: jmp         000000014012CA4C


;ホールドMAXでここにくる
14012CA79: mov         ebp,dword ptr [rdi+3Ch]
14012CA95: jmp         000000014012CA4C


14012CA4C:
14012CA60: mov         eax,ebp                 ;戻り値代入
14012CA72: ret


つまりどういうことかというと、
・ホールドは開始から0.167秒は加算されない(知らなかった・・・)
・得点(MAX BONUS除く)はround(基準点(10~40) × ホールド秒 ÷ 0.017)
・ホールドMAX BONUSは、ホールドMAXの次のフレームで加算
ですね。

ところで、単精度浮動小数点の丸め込み誤差っていうのに気づいて、上記0.017とかは正確ではありません。

0.167=(float)0x3E2AAAAB
=(bin)0.00101010101010101010101011
=1/8+・・・+1/67108864
=11453246464/68719476736
=10/60+1/(67108864*3)≒10/60

0.017 =(float)0x3c888889
=(bin)0.00000100010001000100010001001
=1/64+・・・+1/536870912
=8947849/536870912
=1/60+7/(536870912*15)≒1/60

まあ実質1フレ単位ですがフレーム数とは非同期で計算はされていますね。




後日に続く
2019.04.28 03:37 | 固定リンク | ミク | コメント (1)
コメント一覧
z - 2019年05月13日 05:18
ホールド開始から0.167秒は加算されないのは、いわゆる10フレルールと言われています(実はこのルールを知らない人が一定数います)

実装されてるいくつかの譜面で、最早COOLで取ると10フレルール適用で点数が消えてしまうので意図的に1フレーム2フレーム遅らせて取る必要がある譜面があります
(代表的で最も分かりやすいのがマージナルEXの最後の2同時→2同時連結)

HOLD中の画面左右にあるライト演出は10フレルール関係なくHOLD取った次フレームから発生します(次フレームで既にボタンを離してる場合は演出は発生しません)
コメント投稿

名前

URL

メッセージ

- CafeNote -