BMSのバージョン分けとハッシュ値について
この記事はBMSをプレイする立場である筆者が、BMS作者の方、特に初心者の方に注意していただきたいとある問題について書いたものです。
BMSイベントで作品を公開する前に読んで頂けると幸いです。
BMSのバージョン分け
BMSイベントで公開されているBMSには、wav版/ogg版や高画質BGA版/低画質BGA版のように、同梱している音声・動画ファイルの形式や品質によって、複数のバージョンに分かれて用意されているものが存在します。
wavは大容量ですが、無圧縮で読み込み速度や音質に優れています。
oggは圧縮されているので音質と読み込み速度がwavにやや劣る代わりに、wavよりかなり軽量です。
このため、PCのストレージ容量が少ない人や回線速度の遅い人向けにはogg、音質にこだわる人向けにはwavと、住み分けのために2つのバージョンが用意されていることが多いです。
また動画に関しても、beatorajaなどの次世代プレイヤー向けにHD画質などの高解像度BGA版が別バージョンとして用意されることもあります。
このようなバージョン分けが行われているBMSには、とある問題が発生しているものがたびたび見られます。それは、各バージョンに同梱している譜面は同じはずなのに、BMSプレイヤーやIR(インターネットランキング)上ではそれぞれ異なる譜面として認識されているのです。
実際に何が起きているのか
wav版/ogg版でバージョンを分けていて、かつその問題が起きているBMSとして、G2R2018からGiselleを例に取って見てみます。
LR2IRでGiselleを検索してみると、なぜか[b]~[a]の譜面がそれぞれ2個ずつ存在しているのが確認できると思います。
これは、wav版の譜面とogg版の譜面が異なる譜面として認識されていることによって発生しています。
しかし、wav版とogg版の譜面をBMSプレイヤー上でプレイして比較しても、これらの譜面の間には配置やキー音などの違いはありません。
ではなぜこのような現象が起きているのでしょうか?それは実は、wav版とogg版で譜面データの記述が微妙に異なっていて、それによって譜面のハッシュ値の分裂が起こっているからです。
ハッシュ値とは?
ハッシュ値とは、元になるデータから一定の計算手順により求められた固定長の値。その性質から暗号や認証、データ構造などに応用されている。ハッシュ値を求めるための計算手順のことをハッシュ関数、要約関数、メッセージダイジェスト関数などという。
ざっくり言うと、ハッシュ関数という入れたデータを決まった法則でぐちゃぐちゃにして吐き出してくれるものがあって、あるデータ(数値や文字列)を元にハッシュ関数が吐き出した値(文字列)をハッシュ値といいます。
ハッシュ値にはいくつか特徴があり、
このような特徴を持つため、ハッシュ値はあるデータが他のデータと一致するかを特定するのに使われたりします。(IDみたいなイメージ)
BMSとハッシュ値の関係
ではハッシュ値とBMSに何の関係があるのかと言うと、一般的なBMSプレイヤーやIRでは、ハッシュ値を使って譜面を認識・特定しています。
LR2ではハッシュ値の生成にMD5という有名なハッシュ関数を使っています。このMD5を使って ★1 星の器~STAR OF ANDROMEDA(ANOTHER) の譜面データをハッシュ値にすると、be6a3f3f38dccc7b49497c852885cc8cという値になります。
BMSプレイヤーやIRは、譜面データを管理する際に、譜面データそのものではなくハッシュ値を使っています。ハッシュ値によって譜面データを特定し、プレイヤーのスコアデータに紐付けているのです。
ハッシュ値の弱点
このように活用されているハッシュ値ですが、一つ問題があります。それは、元となる譜面データが1文字でも違うと、ハッシュ値も別物になってしまうという点です。
先ほど例に出した 星の器~STAR OF ANDROMEDA(ANOTHER) ですが、仮にこの譜面のTOTAL値を500から600に変更したとしましょう。
すると、変更後の譜面データを元にMD5が生成するハッシュ値はf8dcdfe070630bbb365323c662561a1aになり、元のハッシュ値be6a3f3f38dccc7b49497c852885cc8cとは全く違う値になってしまいます。
つまり、変更前と変更後の2つの譜面は全く違う譜面として扱われることになり、スコアも別々に保存され、IRページも別々になってしまうのです。
今回の例ではTOTAL値を変更しましたが、他にも、
- タイトルを1文字変える
- レベルを変える
- 音声ファイル定義のファイル名を変える
- COMMENT定義でコメントを追加する
- 譜面情報とは関係ない場所に半角スペースを1個入れる
といった様に、BMSファイルというテキスト上で何か1文字でも変更をした場合、生成されるハッシュ値は全くの別物になります。
※ちなみに、譜面のファイル名はハッシュ値の生成とは関係がありません。ファイルの内容のみを元にハッシュ値が作られています。
バージョン分けによるハッシュ値の分裂
ここでバージョン分けの話に戻ります。
wav版/ogg版でバージョンを分けて用意する時に、元々作ってあるwav版の音声ファイルをwavからoggに変換し、それに伴ってBMSファイル内の音声ファイル定義の拡張子もwavからoggに書き換えたとします。
すると勿論、wav版のBMSファイルとogg版のBMSファイルの記述に違いがあるので、それぞれの譜面データから生成されるハッシュ値も別になります。
このように、バージョン分け作業の過程で譜面データの一部を変更してしまうと、バージョンごとに異なるハッシュ値の譜面になってしまい、BMSプレイヤーやIRからは別の譜面として扱われることになります。
前述した通り、同じタイトル、同じノーツ配置の譜面でも、音声ファイル定義の拡張子が違うだけで、それぞれは全く別の譜面として認識されてしまうのです。
この本来同一のハッシュ値であるべき譜面が、バージョン分け作業などによって意図せず別々のハッシュ値に分かれてしまう現象を、私は個人的にハッシュ値の分裂と呼んでいます。
ハッシュ値の分裂が起きている譜面は、IRページが別になり、DLしたバージョンによってスコアが分散してしまいます。こうなるとプレイヤーは別バージョンをプレイした他のプレイヤーとスコアを比較できなくなってしまいます。
ハッシュ値の分裂が起こる主な原因としては、
- wav版/ogg版で分ける際に、BMSファイル内の音声ファイル定義の拡張子をwavからoggに書き換えてしまう
- 高画質BGA/低画質BGAで分ける際に、BMSファイル内の動画ファイル定義の拡張子を書き換えてしまう(mpegとmp4など)
- 高画質BGA/低画質BGAで分ける際に、BGAファイルのファイル名を高画質/低画質で別々にしてしまう("bga_hq.mpg"と"bga_lq.mpg"のように)
などがあります。
往々にしてやりがちなのは、BMSファイル内の音声/動画ファイル定義の書き換えです。
正しいバージョン分けの方法
では、バージョン分けをしたい場合はどうすればいいのかと言うと、BMSファイルの内容は同じまま、分けたい音声/動画ファイルのみを別々に用意してください。
実はLR2やbeatorajaなどのBMSプレイヤーには音声ファイルの拡張子を補完してくれる機能があり、BMSファイルで定義した拡張子と実際のファイルの拡張子が違っても、ファイル名が同じであれば勝手に拡張子を補完して再生してくれるのです。
また、LR2向けの低画質動画とbeatoraja向けの高画質動画を分けて用意したい場合も、BMSファイルは同じまま、バージョンごとに拡張子の違うBGAファイルを同梱すればOKです。
beatorajaには動画の拡張子に優先度があり、以下の様になっています。
mp4 > wmv > m4v > webm > mpeg > m1v > m2v > avi
この優先度を利用して、以下の手順で用意します。
- LR2用にmpegのBGAファイルを用意する(例:bga.mpeg)
- beatoraja用に同名のmp4のBGAファイルを用意する(例:bga.mp4)
- BMSファイルのBMP定義にはbga.mpegを書く
このようにすると、LR2でプレイする際にはbga.mpegが再生され、beatorajaでプレイする際には拡張子の優先度の高いbga.mp4が再生されるようになります。
beatoraja用のBGA作成についてはMALVA.さんの記事に詳細に書かれているので、ぜひ参考にしてみて下さい。
まとめ
配布するBMSのバージョンを分ける時は、いずれも同じBMSファイルを同梱しましょう。
譜面の内容が一文字でも違うとハッシュ値は別物になり、BMSプレイヤーやIRで全く別の譜面として扱われます。
BMSを公開する時にはこのことを意識して下さると、プレイヤーの立場としては非常に有難いです。どうかよろしくお願いします。
余談:修正・更新によるハッシュ値の変更
BMS公開後にBGA追加やミスの修正によってBMSファイルが更新され、譜面のハッシュ値が変更されることがあります。
BMS作品がより良くなっていくという点では喜ばしい事なのですが、ハッシュ値が変わってしまうと修正前にプレイした時に出したスコアはパーになり、プレイヤーはもう一度プレイし直す羽目になります。
このようなこともあり、BMSイベントにおけるBMSファイル書き換えを伴う更新は、インプレイヤーの心証を悪くすることがあります。
ですので、公開前になるべくBMSファイルを書き換えなくて済むよう工夫した方が良いのです。
後からBGAを追加したい場合
もし後からBGAを追加する予定がある場合は、あらかじめBGA定義をBMSファイルに記載しておいてください。一枚絵を仮BGIとして入れたい場合は、動画化してBGAとして同梱してください。こうすることで、BGAを追加する時に譜面のハッシュ値が変わってしまうのを防げますし、追加する際もBGAファイルを同梱するだけなので楽に済みます。
どうしても後からBMSファイルを書き換えたい
公開後にミスが発覚したり、気に入らない点が見つかったりして、どうしても後から譜面を書き換えたくなることはあると思います。その場合は、BMSの公開ページにBMSファイルの中身を書き換えた旨を明確に記載してください。既にダウンロードした人向けに最新版の存在を告知することは非常に重要です。これを疎かにすると修正前の譜面がずっと遊ばれ続けることになるので、注意が必要です。