Slide 1

Slide 1 text

Haruto Otake

Slide 2

Slide 2 text

● (Unityを対象とした)モバイルゲームのリソース 管理基盤が解決すべき課題と、DeNAが取ったそ れらへの解決策 ● 基盤ライブラリとフレームワークを分離するアプ ローチとその利点

Slide 3

Slide 3 text

● 大竹 悠人 (Haruto Otake) ● 経歴 ○ 2009~2013 ドワンゴ ○ 2013~ DeNA ■ ブラウザやUnity製ゲームの新規開発/運用 ■ 現在はUnity用ライブラリやSDK開発に従事

Slide 4

Slide 4 text

モバイルゲームのリソース基盤が 解決すべき課題

Slide 5

Slide 5 text

● 継続的なゲーム運営の為の差分管理 ● 巨大な初期ダウンロード ● アプリバイナリに組み込むリソースへの対応 ● コンテンツ保護と高速なロードの両立 ● アップデート実施までのリソースの秘匿 ● 開発のイテレーション速度を阻害しないビルド

Slide 6

Slide 6 text

● ゲーム運営の為の継続的なコンテンツ追加 ○ 月3,4回前後のイベント運用を行うには、アプリ更 新を伴わないリソース更新が必須 ○ ネットワーク経由でのリソース公開 ■ 必要な差分を適宜算出する

Slide 7

Slide 7 text

● 追加が主だが、既存リソースの 差し替えも発生 ● 更新のタイミングは利用者に依 る為、アップデート元が不定 ● DL途中のアプリ終了の考慮 ○ ダウンロード済みかどうかや、 ファイル破損のチェック実施 A B C B’ D E A' Ver.1 Ver.2 Ver.3 Ver.4

Slide 8

Slide 8 text

● 今のモバイルゲームでは1GB以上のダウンロード がインストールに発生してしまう事が多い ● 利用者に待ち時間を強いると、離脱に繋がる ● サイズが大きいと、利用者のモバイル通信容量を 無駄にする

Slide 9

Slide 9 text

● 必要に応じてダウンロードする戦略もあるが... ○ コンスタントに利用者の通信容量を消費する ○ 非同期にアセットを見せる等の工夫が必要 ○ すべての場面で適用出来るものではない

Slide 10

Slide 10 text

● チュートリアル用など追加DLを挟まずに利用し たいリソースはアプリに組み込みたい ○ iOSではAppStore規約上必須 ● Android / iOS共に、アプリバイナリへのリソー スの組み込みには一定の制限が存在

Slide 11

Slide 11 text

● Android ○ 2021年後半からAndroid App Bundle(AAB)の適 用が義務化(OBBが利用不可に) ○ OBBでは2GBまで配信可だが、AABでは150MB 以上は配信不可 ■ PlayAssetDeliveryの導入で1GB迄配信可 ○ apk(zip)として格納されるため、ファイルアクセス の手段に制限が生まれる

Slide 12

Slide 12 text

● iOS ○ AppStoreの規約上、起動時にAppが正しく機能 するよう、バイナリに十分なコンテンツを含む 必要 がある ■ チュートリアル等も含める為、巨大に ○ 2GBまで配信可 ○ OnDemandResources利用で+2GB迄配信可 ○ 通常のファイルシステムとして扱える

Slide 13

Slide 13 text

● 特に他社IPを使わせて頂くタイトルでは、暗号化 によるコンテンツ保護の仕組みが必要 ● 暗号化による負荷がゲーム体験を損ねないよう に、高速なロードを両立する必要がある ○ 特にUnityでは、長らくAssetBundleの暗号化と チャンク読み込みの両立が難しく、メモリを消費し がち

Slide 14

Slide 14 text

● ゲームからまだ利用されていないリソースがダウ ンロード可能になると、攻撃者から解析される ○ ”ネタバレ” / “解析” / “リーク” と呼ばれる ○ イベントやキャラなどの情報が、公式な情報公開 前に広まる可能性が高い

Slide 15

Slide 15 text

● リソースのビルド/デプロイが開発中の確認やリ リース作業を時間的に阻害するのを避ける ○ 運用してきた時間に比例してビルド対象物は線形 に増加する

Slide 16

Slide 16 text

● 継続的なゲーム運営の為の差分管理 ● 巨大な初期ダウンロード ● アプリバイナリに組み込むリソースへの対応 ● コンテンツ保護と高速なロードの両立 ● アップデート実施までのリソースの秘匿 ● 開発のイテレーション速度を阻害しないビルド

Slide 17

Slide 17 text

これらの課題をどう解決するか?

Slide 18

Slide 18 text

● 統合された1つのソリューションにせず、課題領 域を絞った複数のライブラリ/モジュールに分割 ● 全体を通して見たときに、利用側が前述した課題 を全て解決できている状態を目指す

Slide 19

Slide 19 text

● Aladin ○ 空間効率に優れたリソースのリビジョン管理 と暗 号化 ● AssetFetcher ○ HTTP/2によるリソースの並列ダウンロード ● Abdool ○ 高速な増分AssetBundleビルド & ロード

Slide 20

Slide 20 text

● ファイルベースのリソース管理ライブラリ ● 特徴 ○ Addressによるリソースへのアクセス ○ 複数のリビジョンのリソースを効率的に保持 ○ 高速なデプロイ ○ 様々なストレージへの対応と透過的な利用 ○ 透過的な暗号化 & 解析によるネタバレ防止

Slide 21

Slide 21 text

● 特定のリビジョンのリソース全 体をTreeと呼ぶ ● Tree毎に、Addressを識別子と した仮想的なストレージを持つ

Slide 22

Slide 22 text

● リソースの実体は中 身をハッシュ化した 値をファイル名にし てBlobとして保存 ● AddressとBlobの 紐付けをIndex として保持

Slide 23

Slide 23 text

● リビジョン間で共通するリ ソースは同一Blobで保持 ● 中身が同一なら、異なる Addressでも同一Blobで保持 ● 追加/変更差分のストレージ 消費のみで複数リビジョン を同時に保持可能

Slide 24

Slide 24 text

● ファイルを上書きしない 為、安全かつ高速なリビ ジョン切り替えが可能 ● 中身のハッシュ値とファイ ル名を比較するだけで破損 チェックが可能

Slide 25

Slide 25 text

● シリアライズしたIndexの ハッシュ値がリビジョン ● IndexもBlob同様にハッシュ 値をファイル名として保持

Slide 26

Slide 26 text

● ハッシュ値の先頭1バイトで サブディレクトリを作る ○ 大量のファイルを1つのディ レクトリに保存することによる パフォーマンス低下を回避

Slide 27

Slide 27 text

● Flatbuffersでデシリアライ ズ不要の問い合わせを可能に ○ メモリ軽減 ● Addressを64bitハッシュ化 ○ ソート済のFlatbuffers上のリ スト構造を直接二分探索

Slide 28

Slide 28 text

● Index同士の比較や、Indexに含まれるがストレー ジに存在しないBlobの特定 ○ ダウンロードが必要なリソースの特定に利用 ● 複数のリビジョンを指定して、どのTreeからも参 照されなくなったBlobの削除 ○ リビジョン更新後の旧リソースの削除に利用

Slide 29

Slide 29 text

1. CLIツールからTreeの形式にリソースを変換 2. 変換結果をディレクトリごとCDNにデプロイ 3. デプロイ先のベースURLと最新のリビジョンから IndexのURLを特定してダウンロード 4. Indexを読み込み、未ダウンロードなBlobを列挙 5. Blobをダウンロード 6. Treeが読み込み可能に

Slide 30

Slide 30 text

● 以前にデプロイしていないBlobのみを転送するだ けで済む為、極めて高速なデプロイが可能 ● 上書きが発生しないので、サーバー側に存在する ファイルは転送する必要がない ○ gsutils cpの-nオプションによって、サーバーに存 在しないファイルのみの転送を実現可能 ● デプロイ先のサーバーでも同時に多数のリビジョ ンを保持可能

Slide 31

Slide 31 text

● ストレージへの読み書きは抽象化して実装 ● アプリバンドルしたリソースとダウンロードした リソースを透過的に効率的に使い分ける ● 対応するストレージ ○ 通常のReadOnly/Writableなファイルシステム ○ AndroidのStreamingAssets ○ Play Asset Delivery

Slide 32

Slide 32 text

● Google Play Plugins for Unityを利用 ● Play Asset Deliveryの任意のAsset Pack内に保 存したAladinのTreeを読み込む ○ ファイルパスとOffsetとSizeを得られるため、範囲 を制限しただけのFileStreamとして少ないオー バーヘッドで読み込める

Slide 33

Slide 33 text

● アプリ同梱のリソースとダウン ロードしたリソースを完全に透過 的に扱う事を可能にする ● Decoratorによる宣言的な合成

Slide 34

Slide 34 text

No content

Slide 35

Slide 35 text

● 暗号化後のデータをBlobとして保存 ● 暗号化の実装は適宜入れ替えが容易に可能 ● 標準はランダムアクセス可能なストリーム暗号 ○ AssetBundle.LoadFromStreamに利用可能 ○ 暗号化利用時もチャンクロードが可能 ○ unsafeで高速,アロケーションフリーに最適化 ■ C#での相互運用性と速度を両立 ■ Unity特化版としてBurstへの対応も進行中

Slide 36

Slide 36 text

● クライアント内に隠した単一の鍵をコード解析等 で解読されるのが、ネタバレの主要要因 ○ 難読化しても、一度暴かれた時点でアウト ○ URLの難読化や、利用開始の直前までゲームか らダウンロードさせないことで以前は解決 ● 鍵をクライアントが知るのが不可能なら、解析耐 性は暗号化アルゴリズムの強度に依存

Slide 37

Slide 37 text

● 暗号化鍵を複数かつTreeとは独立して配布可能 ○ リソース毎に鍵IDを指定される ○ ランタイムで取得できるのは鍵IDのみ、鍵IDに紐 づく鍵情報は別途利用開始前に公開 ○ 公開済みの鍵は独自キーストアに格納 ● イベント開始前のリソースの柔軟な配布が可能 ○ 開始前に鍵を知ることが出来ないので、解読でき ない

Slide 38

Slide 38 text

● 継続的なゲーム運営の為の差分管理 ● 巨大な初期ダウンロード ● アプリバイナリに組み込むリソースへの対応 ● コンテンツ保護と高速なロードの両立 ● アップデート実施までのリソースの秘匿 ● 開発のイテレーション速度を阻害しないビルド Aladin Aladin

Slide 39

Slide 39 text

● 高速な並列リソースダウンローダ ● 特徴 ○ HTTP/2による高速並列ダウンロード ○ 様々な配信方式に幅広く対応 ○ ゲームエンジンを問わず利用可能

Slide 40

Slide 40 text

● 指定されたリソースをストレージに展開すること に特化 ○ URL,保存先,ハッシュ値の組のリストを受取る ○ 指定されたURLから並列にダウンロード ○ 結果のハッシュ値を計算し破損判定&リトライ ○ 保存先に展開 ● ダウンロードの必要性の判定は行わない ○ Aladin側ですべて判定可能

Slide 41

Slide 41 text

● HTTP/2では1接続で並列に大 量のリクエストとレスポンス のやり取りが可能 ○ 効率的に並列数を上げられ る為、受信完了から次の受 信開始までの時間が短い ○ 大量の小さなファイル向き イメージ図

Slide 42

Slide 42 text

● 旧来でも1ファイルにアー カイブすることで転送効率 は高められる ● Aladinのようにアーカイブ を行わない配信形式では HTTP/2は相性がよく、大 きな効果 イメージ図

Slide 43

Slide 43 text

163.93s から 20.93s HTTP/2での並列ダウ ンロードのあり無し で、約8倍もの差 5KB * 20000ファイル での計測

Slide 44

Slide 44 text

● 配信にサーバーの対応状況を確認する ○ 主要なCDNであれば殆ど問題ない ● nginxなどでリバースプロキシを挟むと速度が出 ないことがある ○ 開発用のIPアドレス制限などの利用に注意

Slide 45

Slide 45 text

● ZIPアーカイブ対応 ○ ダウンロードが完了したZIPの内容を、順番に保 存先ディレクトリに展開する ○ ZIP形式のパッチを順に適用する形式をカバー ● 独自アーカイブ(DnArchiver)対応 ○ リソース毎に圧縮の有無を選択できる独自のアー カイバでもZIP同様の運用が可能

Slide 46

Slide 46 text

● libcurlをバックエンドとして、C++で実装 ○ Unity向けにはネイティブプラグインとしてのイン ターフェースを用意 ● Unityはもちろん、内製エンジン(LiftEngine)を 含むその他のエンジンでも利用可能 ● macOS/Windows/Linux/iOS/Androidの5プラッ トフォームに対応

Slide 47

Slide 47 text

● 継続的なゲーム運営の為の差分管理 ● 巨大な初期ダウンロード ● アプリバイナリに組み込むリソースへの対応 ● コンテンツ保護と高速なロードの両立 ● アップデート実施までのリソースの秘匿 ● 開発のイテレーション速度を阻害しないビルド Aladin Aladin AssetFetcher

Slide 48

Slide 48 text

● AssetBundleビルド&ロードライブラリ ● 特徴 ○ VCSベースの高速インクリメンタルビルド機能 ○ シンプルなアドレッシングと最適化された独自カタロ グ管理 ○ 厳密な重複排除ポリシー ○ ResourceManagerベースの柔軟なロード機能

Slide 49

Slide 49 text

● Addressable Assets Systemの一部のみを利用 ○ AddressableのバックエンドであるResource Manager, Scriptable Build Pipelineを利用 ○ ロード状況を見れるEvent Viewerも利用 ● Addressable本体のAssetBundle管理機能は利用 しない

Slide 50

Slide 50 text

● Scriptable Build Pipelineでカスタムしたパイプ ライン ● Gitから以前のビルド以降で変化したアセットの リストを取得 ○ interface経由で他のVCSにも対応可能な設計 ● アセット間依存を元に、ビルドする必要のある AssetBundleを特定した上で実ビルド ● カタログを差分更新

Slide 51

Slide 51 text

アセットごとにグローバルなアドレスを設定可 カタログファイルのシリアライズには Flatbuffersを採用し、アロケーションを回避 カタログは非常に大量の文字列を含む 基数木による文字列保持を実装し、共通化 アセットの読み込みは文字列のハッシュのみを使 い、文字列比較を排除

Slide 52

Slide 52 text

● AssetBundleでは容易にアセットの重複が起こる ○ Addressableの場合ではAnalyzerで重複を検知 できるが、その代替が必要 ● ビルド中の全てのアセットに対して所属する AssetBundleが一意に定まれば重複しない ○ 所属するAssetBundleが定まらないアセットがビ ルドされた際にエラーとなるように

Slide 53

Slide 53 text

● AssetBundle構成はinterface経由で実装を注入 ○ バンドル名, ファイルパス, アドレスの組のリストを 返せることと、幾つかの逆引きも要求 ○ このinterfaceをPackRuleと呼ぶ ● フォルダ単位のシンプルな物は標準実装 ○ フレームワークやゲーム側でのポリシーにあわせ て個別に実装する

Slide 54

Slide 54 text

● Locatorを実装し残りはResourceManagerを利用 ○ Provider/Locatorの差し替えでカスタマイズ

Slide 55

Slide 55 text

● ResourceManagerの管理機構をそのまま利用 ○ ロード開始時に得られるHandleを ResourceManager.Releaseに渡すことで開放 ○ 参照カウントも行う為、同じアセットを複数ロードし ていても意識する必要はない ● AssetBundleは所属するアセットを全て開放した 時点で自動的に開放される

Slide 56

Slide 56 text

● Editorでの確認は 元アセットを AssetDatabase からロードしたい ○ Locatorの差替 ○ カタログを使わ ずPackRuleを 利用

Slide 57

Slide 57 text

● AssetBundle.LoadFromStreamを利用すること で、StreamからAssetBundleをロード可能 ○ 固定長の内部バッファの消費のみで、高速なラン ダムアクセスを行ってくれる ■ メモリフットプリントの大幅軽減 ■ 暗号化の計算量の大幅削減 ● Aladinの暗号化Streamを扱うことで実現 ○ 以前はAbdool側で実装していたが、全て移譲

Slide 58

Slide 58 text

● 専用のLocator /Providerを利用 ● 平文のものは通 常のProviderを 利用 ○ LoadFromFile が利用可なら こちらが軽量

Slide 59

Slide 59 text

● 継続的なゲーム運営の為の差分管理 ● 巨大な初期ダウンロード ● アプリバイナリに組み込むリソースへの対応 ● コンテンツ保護と高速なロードの両立 ● アップデート実施までのリソースの秘匿 ● 開発のイテレーション速度を阻害しないビルド Aladin Aladin AssetFetcher Abdool

Slide 60

Slide 60 text

● 設計に柔軟性を持たせて幅広いユースケースに対 応できるということは、ユースケース毎にそれに 応じた引数等を注入しなければならない ● 多くのタイトルに導入するにあたっては、これら を仲介する層が必要

Slide 61

Slide 61 text

● 内製フレームワークの一部、Sharin.Resourcesが 直接的なフロントエンド ○ Aladin, AssetFetcher, Abdoolを中心に他の基盤 モジュールも組み合わせ、よりユースケースを絞り 込んだフレームワークとして実装

Slide 62

Slide 62 text

● 実機確認のイテレーション問題 ○ リソースを実機確認する際にはアプリに組み込ん でビルドするか、サーバにアップロード&実機でダ ウンロードする必要がある ○ 少しずつ調整しながら実機確認をしたい場合に何 回もアプリをビルドorアップロード・ダウンロードす る必要がある ○ イテレーションが回しづらく開発効率が低下

Slide 63

Slide 63 text

● PC上のリソースを直接参照してしまう事で解決 ○ USB接続したPC上のリソースを実機のリソースの ように扱う 参照

Slide 64

Slide 64 text

Aladin Abdool Sharin.Resources AssetFetcher Sharin’の その他の様々な モジュール Abdool + Aladin インテグレーション vfs ゲームタイトル devwire DebugFileSyste mから利用 TechCon2020で の講演を参照

Slide 65

Slide 65 text

65

Slide 66

Slide 66 text

● フレームワークを導入しなくても、部分的に成果 を取り入れることが可能になる ○ Sharin.Resourcesを使わないタイトルでも、同じラ イブラリの導入に成功 ○ AssetFetcherに関しては非Unityでも導入済 ● 問題を小さなサンプルで再現が可能に ○ 問題のあるモジュールのみに集中できる ○ 自動テストがしやすく、問題解決が容易に

Slide 67

Slide 67 text

● ライブラリ側の責任範囲が限定的かつ明確になる ○ それぞれを単純化でき、柔軟性を担保可能 ○ 向き合う領域が単純な方が尖った設計を行えて、 競争力を持つ機能を開発できる ○ ゲーム側での“決め”になる部分をフレームワーク層 に委ねることができる ■ ライブラリが意思決定の速度的なボトルネックに なるのを避ける

Slide 68

Slide 68 text

● モバイルゲームのリソース管理基盤には様々な課 題がある ● 役割を絞って尖った機能性と柔軟性を持った様々 なライブラリを開発して課題解決を行った ● わかりやすいインターフェースのフレームワーク 層を提供して使い手側に寄り添っている

Slide 69

Slide 69 text

No content