開発者の裏話:パーク配分の問題

2024年11月月27日 - Destiny 2 Dev Team

皆さん、こんにちは。『Destiny 2』の報酬システムなどを担当するエンジニアリングチームのテクニカル責任者Andrew Friedlandです。パーク配分の問題調査におけるプログラミング作業を率いることになりましたので、今回の経緯についてご説明させていただきます。

コミュニティチームからこの問題の報告を受けたタイミングは、実は非常に偶然が重なりました。この問題がチームで浮上したのは、チームのエンジニアの一人であるVincent Daviesが、フロンティア用の次世代アーマーのステータス分布を検証するためのスクリプト作業を丁度終えた頃でした。このスクリプトに少し手を加えることで、武器パークの検証にも活用できるようになり、1分間に何千もの装備ドロップをシミュレーションして、そのデータを記録・分析することができました。このツールを使って、コミュニティの発見を素早く検証することもできました。

私たちの発見は何だったのか?個々のパークの確率は均等でしたが、パークの組み合わせの確率は全く均等ではありませんでした。

約10万回にわたる「VS チル・インヒビター」のドロップ結果がこちらです。コミュニティが発見していた通り、特定のパークの組み合わせは頻繁に出現し、一部の組み合わせは出現頻度が低く、そして中には事実上入手不可能な組み合わせも存在していました。

image.png

この現象を理解するために、まず数学とコンピュータサイエンスの観点から、私たちにとってランダムが何を意味するのかを詳しく見ていく必要があります。

ランダムとは何か?

真のランダムイベントとは、確率を割り当てることはできても予測できないものです。コインの裏表やサイコロの出目といった単純なものから、落雷の位置や放射性原子の崩壊時期といったより広範な物理現象まで含まれます。これらはすべて、何かが起こる可能性について一般的な予測はできますが、正確に何が起こるかを予測することはできません。また、望んだ結果を再現することもできません。コンピュータは単独で真のランダムを生成することができず、真のランダムが必要な場合、大気ノイズ(ラジオやテレビのノイズ)、宇宙背景放射の記録、あるいはラバランプの壁といったものが利用されてきました。ただし、純粋な乱数が必要となるケースは実は多くありません。特にゲームでは、真のランダム性はコントロールができないため一般に避けたい要素となります。

何年も前に、何人かの賢い人たちが擬似乱数生成器(PRNG)という手法を開発しました。PRNGの基本的な考え方は、シード値(多くの場合、現在のシステム時刻)を基に一連の数学的演算を実行することで、十分にランダムな数値を作り出すという仕組みです。その新しい数値を次の乱数のシードとして使用することで、十分にランダムな数列を生成できます。

ゲームにおいてPRNGが真の乱数より優れている大きな利点は、再現可能な点です。特定の開始シードを使用すると、必ず同じ数列が生成されます。つまり、同じ開始シードと同じ入力があれば、ゲームは同じ結果をもたらします。ゲームではこの特性を、保存された映像や公平なトーナメント、その他多くの用途に活用しています。

PRNGの大きな欠点は、名前が示す通り、擬似的なランダム性しか持たないことです。PRNGの出力には一定のパターンが現れる可能性があり、使用方法によってはランダムに見える結果を得るどころか、そのパターンを増幅してしまう可能性があります。

様々なアルゴリズムを視覚化するため、エンジニアリングディレクターのJoe Venzonの協力を得て生成したサンプルデータを使用します。まず、PRNGの基本的な使用例として、最初のシードとして1を使用し、その後は直前の結果を次の値のシードとして使用します。これにより、古いテレビの静電ノイズのような、明確なパターンのない点の集合が生成されます。これはまさに私たちが求めているものです。なぜなら、乱数が可能性空間内でかなり均等に分布しており、数列に明確なパターンが見られないことを意味するからです。  

Random.png

残念ながら、『Destiny』では常に前回の結果を次のシードとして使用することはできません。新しい乱数を生成する際に安定した予測可能なシードが必要な場面が多くあり、この新しいシード選択が最終的に問題を引き起こしていました。

バグについて

『Destiny 2』では、ソケットとプラグと呼ばれる新しいアイテム用システムを作成しました。このシステムは、武器のパーク、改造パーツ、シェーダー、マスターワーク、さらにはアーマーのステータスなど、プレイヤーが装備として目にするものの大部分を処理します。ランダム化されたアイテムは「孤独と影」で追加された機能で、主にソケットとプラグシステムを通じて機能します。『Destiny 2』では、武器にはバレル、マガジン、その他のパーク用のソケットがあります。武器がドロップした時、合法的なプラグのリストからそれらのソケットに挿入するプラグを選択し、それらのプラグがそれぞれ皆さんがよく知るパークを表しています。昨年の作成事件の混乱は、このシステムの柔軟性が原因です。

プレイヤーは、何をしたか、どのように入手したかによって、同じアイテムでも異なるソケットを有効にできます。これは元々のアーティフィスアーマーの実装で見られました。つまり、新しいドロップを初期化する際、常に同じ順序でソケットを初期化できるとは限りません。一部のプレイヤーがより多くのソケットを持っていても、ベンダーが全プレイヤーに同じパークを提供できるようにするため、初期化される各ソケットに異なるシードを使用しています。残念ながら、この安定性を追加するための追加作業が、バグの原因となってしまいました。

アイテムの各ソケットに安定したシードを選択するため、ハッシュ関数(大量のデータを1つの数値に変換する数学的な方法)を使用して、複数の異なる情報を組み合わせていました。この新しいハッシュ値は当初の意図通り安定していることは保証されていましたが、ソケットのインデックスがハッシュに最後に追加される要素だったため、たまにハッシュ値が連続的になってしまい、これらの連続的なシードが最終的に問題のある動作を引き起こしていました。

表に戻って、連続する数値のハッシュを見てみましょう。ハッシュ自体は連続的ではありませんが、数値の出方にはかなり明確なパターンが見られます。これは、連続する数値のハッシュを見ると、出力されるハッシュにパターンを見つけられる可能性が高いことを意味します。これ自体は悪いことではありませんが、PRNGに供給されるデータに興味深いパターンが存在することを意味します。

Sequentials-Hash.png

これらの数値を乱数生成器に投入すると、入力データのパターンが出力を歪め、データにパターンが生じていることがわかります。これらのパターンが、特定のパークの組み合わせが得やすく、他のものがほぼ入手不可能になっていた具体的な原因でした。

初期のサンドボックス調査

究極の疑問:なぜもっと早くRNGを調査しなかったのか?

プレイヤーから特定のロールの入手困難についてフィードバックを受けるたび、サンドボックスチームはまず武器データを確認していました。武器パークには意図的な重み付けは一切なく、さらに深刻な問題が起きているという強力な証拠がない限り、そこで調査を終えていました。

乱数生成は非常に基礎的なゲームの要素(実際、すべてのゲームにおいて)であり、明確または豊富な証拠がない限り、エンジニアに調査を依頼することは必ずしも理にかなっていません。このような問題が頻繁に明白な問題として発生していれば、もっと早く気付いていたはずです。

すべてのゲーム開発と同様、これは優先順位とトレードオフの問題です。エンジニアリングとQAの多くは『Destiny』の将来の開発に注力しています。潜在的な問題に優先順位をシフトすることは、それらの機能とコンテンツにとってコストとリスクを伴います。

今回のケースでは、コミュニティがデータ収集の取り組みを組織化したことで、問題の存在が強く示唆され、RNGコードのより深い調査を開始する必要が生じました。

調査から、この問題はかなり前からゲーム内に存在していたことが判明しましたが、コミュニティに注目されて大きな関心を集めたのは最近のことでした。プレイヤーは主にアイアンバナーのサブマシンガン「マルチマーチCCX」と、迷宮「べスパーの宿主」のヘビーグレネードランチャー「VS チル・インヒビター」に注目し始めました。

バグはすべての武器に影響を与えていましたが、時には望ましいパークが取得しやすくなることもあり、そのため長い間気付かれませんでした。

これには複数の重なり合う問題が関係しています:

  • この問題は、1列あたり6つのパークを持つ武器で最も顕著でした。
    • 年月を経て同様に望まれる武器の中には、これより多いまたは少ないパークを持つものがあり、問題の影響が部分的に隠されていました。
  • このバグは、複数の選択肢を持つパーク列によって大きく緩和されていました。
    • 「新」武器とプレイリスト武器は、1列に複数のパークを持つことができます。
      • レイド、オシリスの試練、ナイトフォールストライクなどのほとんどのエンドゲーム武器ソースには「新」武器があります。
    • プレイヤーは評価リセットを通じて、バンガード、クルーシブル、ギャンビット武器の1列あたりのパークを増やすことができました。
  • このバグは、「漆黒の女王」で武器作成機能が導入されて以来、レイドやほとんどの非エンドゲーム武器ソースに適用されている作成可能な武器ではほとんど関係ありません。

最終的に、コミュニティは時間をかけて十分な証拠を集め、適切に配分されたパークのコンテンツ設定であっても、より深い問題があることを証明することができました。

修正について

ベテランエンジニアのBen Thompsonは、この問題をほぼ即座に認識しました。オリジナルのミッション「虫の囁き」がローンチされた時期にいた人なら、公開イベント「宿りの汚染」がなかなかアクティブ化しない問題(Cabal、また!?)を覚えているかもしれません。根本的な問題は同じで、乱数生成器のシードに連続的な入力を使用していたことでした。その時も今回も、修正方法は入力ハッシュに大きな素数を掛けることで、より良く分散させる、いわゆるデータのソルト化でした。連続する入力間には依然として規則的な間隔がありますが、実際の値は連続する入力間で大きく異なるため、パターン化の問題を回避できています。これらのソルト化された入力をハッシュ化すると、より良く分散されたハッシュ値のシリーズが得られます。

Sequentials-Salt-Hash.png

そして、ソルト化されたハッシュを乱数生成器に供給すると、再び明確なパターンのない良好な点の分布が得られます。

Sequentials-Salt-Hash-Random.png

元のテストケースの「VS チル・インヒビター」に戻ると、修正後のパーク抽選はどうなったでしょうか?すべてのパークの組合せがランダムなイベントのサンプリングから期待される通り、平均値の周りでわずかな変動を伴いながら、比較的均等に出現するようになりました。特定のパークの組合せを得る確率は、当初の意図通り、真の乱数に近くなりました。

image.jpg

パーク選択の修正は更新8.1.0.4で実装され、同様の問題がないか、コードベースの複数のエリアで近々監査を実施する予定です。全体として、これらの学びは、この問題の再発を防ぎ、少なくとも時々スポットチェックを行ってバグが再発しないようにするのに役立つはずです。この古くて実績のあるコードに潜む厄介な問題を特定するのに役立つ印象的なデータ収集を行ってくれたコミュニティの皆さんに感謝します。

このサイトでは、できる限り最高のユーザーエクスペリエンスを提供することを目的にクッキーを使用しています。「承諾」をクリックすると、クッキーに関する方針およびプライバシーポリシーに記載されている方針に同意したことになります。