複数タイトルの開発・運営で得られたAddressables活用術と課題解決事例

293 Views

March 05, 26

スライド概要

profile-image

リアルタイム3Dコンテンツを制作・運用するための世界的にリードするプラットフォームである「Unity」の日本国内における販売、サポート、コミュニティ活動、研究開発、教育支援を行っています。ゲーム開発者からアーティスト、建築家、自動車デザイナー、映画製作者など、さまざまなクリエイターがUnityを使い想像力を発揮しています。

Docswellを使いましょう

(ダウンロード不可)

関連スライド

各ページのテキスト
1.

複数タイトルの開発・運営 で得られた Addressables活用術と 課題解決事例 株式会社Aiming Tokyo December 11

2.

講演概要 - お話しすること - 運営型・複数プロジェクトでの Addressables活用の取り組み - Addressables で発生する課題と解決事例 - 前提 - iOS/Android/Windows を中心とした運営型タイトル - Addressables(AssetBundle)・ビルドパイプライン・ C# の知識 - おことわり - Aiming 全てのプロジェクトの取り組みを反映したものではありません Tokyo December 11

3.

アジェンダ → イントロダクション → アセットのアプリ内蔵化 → ビルドマシンのクラウド化 → ライフタイム管理 → 最適化 → その他の取り組み・今後の課題 Tokyo December 11

4.

イントロダクション Tokyo December 11

5.

Presentation Title 金井 亮太 株式会社Aiming 第二事業部 マネージャー/リードソフトウェアエンジニア 2016年度新卒入社 リードエンジニアとして新規プロジェクトの開発に複数関わっている 最適化や共通パッケージの開発など基盤・研究開発としての業務も担当 Tokyo December 11

6.

Addressables との歴史 → 2019年以前 (非Addressables時代) ⎯ 「CARAVAN STORIES」で AssetBundleManager を改修して利用 ⎯ → 2019年 ⎯ 開発中の一部プロジェクトで Addressables を採用開始 ⎯ → Unite 2018 Tokyo 『CARAVAN STORIES』のアセットバンドル事例 当時はまだ 0.5.3-preview 2022年 ⎯ 「キャラスト魔法学園」で Addressables を採用した初リリース ⎯ 以降の複数プロジェクトで Addressables を採用してリリース Tokyo December 11

7.

r&d-aas → 「aas を完全に理解しよう委員会」 から発足した研究 開発プロジェクト ⎯ → aas: Addressable Asset System 2023年頃から週1回の定例ミーティングを継続的に開 催 ⎯ ゲーム開発プロジェクトの各代表者が集まり情 報共有・ディスカッション Tokyo December 11

8.

ビルドパイプライン → GitHub モノリポジトリ ⎯ → → Unity モノプロジェクト ⎯ アセットも同一プロジェクト ⎯ ミドルウェアのアセットも Addressables で管理 アドレスの割り振りは自動化 ⎯ → 正規表現でアセットのパスから決定論的 Jenkins でアセットビルド ⎯ → C# サーバなども含む 社内ノード・クラウドノード Cloud Storage Google Cloud) にビルドしたアセットをアップロード ⎯ ビルドしたブランチ単位のディレクトリへ Tokyo December 11

9.

アセットのアプリ内蔵化 Tokyo December 11

10.

Presentation Title 吉田 杏平 (よしだ きょうへい) 2019年入社 おもにクライアントエンジニアの業務を行う傍ら、研究開発を進めている Tokyo December 11

11.

“タイトル画面で離脱するユー ザーを減らしたいˮ Tokyo December 11

12.

ソーシャルゲームでよくある流れ → ストアからアプリを DLする → タイトル画面で追加のアセット DLをする ⎯ ここでゲームを遊ぶのをやめてしまうユーザーが一定の割 合いることがわかった → チュートリアルが始まる ゲームを始めようと思ってくれて ストアからダウンロードしてくれたはずなのに なぜ? Tokyo December 11

13.

仮説: ストア上では ~~MBのアプリだったのに、数 GBのア セットダウンロードを要求されるから ストア上のアプリサイズはせいぜい数百 MB程度 ゲームを遊ぶために追加で数 GBのDLが必要 この程度のサイズなら...とストアからアプリをインストールしてくれたユー ザーも タイトル画面で表示される通信量を前に「今すぐ遊べないなら別に遊ば なくていいや...」と諦める人が増えている? →追加のアセットダウンロードを最小にして ユーザーの離脱を防ぎたい! Tokyo December 11

14.

ストアのアプリサイズ上限 アプリ本体は 200MBまで インストール時のアセットパックは 4GBまで 4GBのアプリをストアにアップロードできるか も! Tokyo December 11

15.

Unity のアセットパック対応状況 LocalBundleをStreamingAssetsに配置すると、Unityがアセットパックを自動で作ってくれる! ※ただし1GB程度までしか対応してないので、これだけだと不十分 https://docs.unity3d.com/ja/2022.3/Manual/play-asset-delivery.html Tokyo December 11

16.

どうやって? Unityでカスタムアセットパックを作成するサンプル 最終的にはこれをベースに複数のアセットパックを作成できるようにした https://github.com/Unity-Technologies/Addressables-Sample/tree/master/Advanced/Play%20Asset%20Delivery Tokyo December 11

17.

どうやって? アセットバンドルのグループ分け ファイルサイズ1GBごとに1グループとして仕分ける カスタムアセットパックとしてまとめる AddressableAssetContent{n}としてパックされる ※実装イメージ Tokyo December 11

18.

アプリの公開とリソース更新の流れ アプリ公開時 リソース更新後 次のアプリ公開時 各アセットグループについて、アプリに含める ローカルバンドルと追加DLするリモートバンドル に振り分け アプリ公開後、リソースの更新があった場合は リモートバンドルに変更されたアセットグループ ローカルバンドルをリモートバンドルに移動する は、次のアプリ提出時にローカルバンドルと なってアプリに内包される Tokyo December 11

19.

工夫したところ ・リソースの更新検知にgit ls-filesを使った →addressables_content_state.binを用いた場合、差分の量に比例して差分検出にかかる時間が増加する ため ・Spriteの差分を検知した場合、依存関係を辿ってSpriteAtlasも一緒に更新しないと行けない 依存関係はAssetDatabase.GetDependencies()で辿れる ・SeparateになっているGroupの中で変更があった場合、Group全体を作り直す必要がある →変更があったアセット以外もダウンロードし直しが必要になる →なるべくSeparateではなく、個別のGroupとして扱うように設定 Tokyo December 11

20.

どうなった? →タイトル画面のアセットダウンロードで離脱するユーザーが大幅に減った! 興味を持ってくれたユーザーがゲーム体験を損なうことなく楽しんでもらえているようです こんな嬉しい副次効果も AppStoreとGooglePlayの差分アップデート機能により、容量の大きいアプリでも実際のDLサイズが小さく抑 えられてる -事前登録でアプリの自動ダウンロード機能に乗っかれた Tokyo December 11

21.

今後の展望 ・4GBのアプリをストアにアップロードできるようになった →次は? - AppStore: Background Assetsを対応しないといけない? Google Play: PADをオンデマンドまたはfast-followで配信する方法の模索? ・サービス継続とともに増え続けるリソースとアプリサイズ...どう向き合う? 4GBを超えた分のリソースはダウンロードしてもらうほかない Tokyo December 11

22.

参考資料 https://support.google.com/googleplay/android-developer/ answer/9859372 https://docs.unity3d.com/ja/2022.3/Manual/play-asset-deli very.html https://github.com/google/play-asset-delivery-unity https://developers-jp.googleblog.com/2016/12/saving-data -reducing-the-size-of-app-updates-by-65-percent.html Tokyo December 11

23.

ビルドマシンのクラウド化事例 Tokyo December 11

24.

Presentation Title 小野寺 真悠 株式会社Aiming 第二事業部 研究開発部・スペシャリスト 2014年にAimingへ入社し、以降11年間、クライアント・サーバー・インフラと幅広く担当。 現在は研究開発部に所属し、スペシャリストとして、技術基盤や開発環境整備、アーキテ クチャ設計、負荷試験など、各プロジェクトの技術的課題解決に取り組んでいます。 Tokyo December 11

25.

何故、クラウド化が必要だったのか? プロジェクト数の増加に比例して、社内ビルドマシンが増加 ↓ その結果… → 設置場所の確保が困難 → 電源容量の限界 → 法令停電によるダウンタイム → 物理故障による不安定な個体の発生 → 日常的な保守作業(清掃など) 現状も 60台前後の社内ビルドマシンが稼働 → クラウド化で解決! Tokyo December 11

26.

要件定義 → 既存のワークフローを変えない ⎯ → → 既存ビルドスクリプトの活用 ⎯ 既存資産の有効利用 ⎯ 既存プロジェクトでの移行も視野 従量課金 ⎯ → 未使用時は出来るだけ課金されないように ワークスペースの保持 ⎯ → 利用者の負担を考えると変更は最低限が望ましい 毎回FullImportが発生するのは許容出来ない 柔軟なスケーリング ⎯ 需要に合わせて並列ビルド数を増減可 Tokyo December 11

27.

技術選定 「既存のワークフローを変えない」 「既存ビルドスクリプトの活用」 「従量課金」 「柔軟なスケーリング」 ここまでは、JenkinsのGCPプラグインのみで実現でき た。 「One-Shot」という機能を利用すると、 Job実行毎に新規でインスタンスが建てられ、Job終了 後に自動で削除されるようになる。 建てられたインスタンスは、ラベル付きのノードとして取 り扱える。 このプラグインをベースに足りない機能を補っ ていく方針とした。 Tokyo December 11

28.

ワークスペースの保持 この要件はプラグインの機能だけでは実現できなかったの で、永続ディスクをマウントするサービスを別途開発した。 右はiOSのアセットバンドルビルドを複数個並列に実行した 例。 iOS Node 1 → オリジナルのディスクは永続的に保持される為、常に 課金される。 iOS Node 2 → Node2 以降のクローンディスクは、直前のビルドで自 動的に作成されたオリジナルディスクのスナップショッ トから復元される。このディスクはビルド完了後にイン スタンスと共に削除される。 この 1連の処理を、ベースイメージに埋め込む事で利用者側 で意識する事なく、ワークスペースが維持されるようにした。 Disk Original) Disk Clone iOS Node 3 ・ ・ ・ Disk Clone ・ ・ ・ Tokyo December 11

29.

柔軟なスケーリング - ライセンスの取り扱い → → → → Unity Floating Licensingシステムを採用。 Unity Licensing Serverは事業部内で共通。 各プロジェクト一定数ライセンスを購入し、最大並列数を 購入数の1.5倍までにして運用している。 利用可能なライセンス数は Grafanaにて監視。 ※ 但し、深夜のデイリービルドに関しては購入数を出来るだけ上回ら ないように設定 Tokyo December 11

30.

ベースイメージについて → LTSがリリースされると自動で最新の Unityがイン ストールされた Ubuntuイメージがビルドされるよう になっている。 ○ GitHub Actions + Packer → リリース済みの Editor一覧は、 Unity Services Web APIs を使って取得。 → 各プロジェクト依存するツールやバージョンが異な る為、このベースイメージを元に各プロジェクト専 用のベースイメージを作ってもらっている。 Tokyo December 11

31.

全体像 Tokyo December 11

32.

月額ランニングコストの例 合計目安: 約 78,000円 / 月 (前提: c2-standard-16 / 3プラットフォーム計 300時間稼働 / SSD 250GB3台) 1. コンピュート費用(VM) → → → 2. 約 45,000円 (変動費) スペック: c2-standard-16 16 vCPU / 64GB Mem) 稼働: 月間 300時間(100時間 × 3プラットフォーム) ストレージ費用(Disk) → → 約 33,000円 (固定費+変動費) 構成 ● 固定(親機): Original SSD 250GB × 3台 + スナップショット → 約 29,000円(環境維持費) ● 変動(クローン): ビルド一時領域(300時間分) → 約 4,000円(使い捨てディスク代) ※ $1155円で概算。 Tokyo December 11

33.

ライフタイム管理 Tokyo December 11

34.

ライフタイム管理の難しさ → アセットが読み込まれてから解放されるまでのライフタイムの管理 ⎯ 自分たちで管理する必要がある → リークすることなく扱いたい → AsyncOperationHandle<T で操作・管理するのはアプリケーションのコードとしては厳しい ⎯ メソッドを跨いだ操作 ⎯ ⎯ 保持するためのフィールド変数 (状態) ⎯ ⎯ ロードをStart(), 解放をOnDestroy() など 複数のアセットがあるとその分増える コードの記述量が増えると解放漏れのリスクも高まる Tokyo December 11

35.

IDisposable.Dispose() を解放として扱う → IDisposableAsset<T として扱う ⎯ IDisposable.Dispose() で Release() を実行 ⎯ AsyncOperationHandle<T を包む ※一部簡略化したコードです Tokyo December 11

36.

IDisposable のメリット GameObject への紐付け → R3 (or UniRx) の AddTo() によって GameObject に紐付け ⎯ → 購読の破棄と同じ感覚で扱うことができる 一度に複数のアセットを扱う場合でも扱いやすい ⎯ 合成による一括 Dispose() ⎯ Disposable.Combine(), DisposableBag, CompositeDisposable など → ほとんどの場合は GameObject への紐付けで良い → VContainer の LifetimeScope で合わせて Dispose() してもらうなど Tokyo December 11

37.

IDisposable のメリット スコープへの紐付け → → スコープを抜けた時点で確実に解放 ⎯ C#の構文サポート ⎯ コンパイラに任せることができる 解放が漏れがちなパターンへの対処 ⎯ 早期リターン ⎯ 非同期処理での OperationCanceledException の発生 Tokyo December 11

38.

UPMパッケージとして横断的に利用 → 異なるプロジェクト間でも同じ記述ができるように → 複数のプロジェクトを並行して開発・運営する上での人員 の流動性の向上 ※Polkaは共通パッケージであることを示す名前 Tokyo December 11

39.

IDisposable で出来なかったこと → DotNetAnalyzers/IDisposableAnalyzers ⎯ Dispose() 漏れを検知できる Roslyn Analyzer ⎯ コードから静的に解放漏れを検知できるのでは!? ⎯ 追跡しきれない箇所での Warning が多発したため断念 Tokyo December 11

40.

最適化 Tokyo December 11

41.

パッキング調整の必要性 → アセット重複 ⎯ 明示的にアドレスが割り当てられていないアセットが参照 された場合、それぞれのバンドルに別物として入る → AssetBundle 粒度 ⎯ バンドル内で部分的にアンロードすることはできない ⎯ → メモリに大きいアセットが乗り続けることも ディスクサイズ・メモリサイズに影響が大きい https://docs.unity3d.com/ja/Packages/com.unity.addressables 1.20/manual/ManagingAssets.html より引用 Tokyo December 11

42.

アセット重複で特に注意したいポイント → シェーダー ⎯ メモリの圧迫 ⎯ シェーダーコンパイルによる CPUスパイク ⎯ バッチングの中断 → TextMeshPro フォントアセット → スプライトアトラス など シェーダーの重複について : https://docs.unity3d.com/6000.0/Documentation/Manual/avoid-shader-duplication.html Tokyo December 11

43.

その他アセット重複パターン → ビルトインシーン ⎯ → Resources ⎯ → 起動直後に何もないシーンを挟み、以降は全て Addressables のシーンへ なるべく使わない ProjectSettings 経由 ⎯ RenderPipelineAsset など Tokyo December 11

44.

不要な依存関係の削除 → そもそも不要な依存が意図せずあるパターンも ⎯ Prefab のオーバーライド ⎯ Material のプロパティ ⎯ Timeline の Bindings ⎯ Model Importer の Material Creation Mode ⎯ デフォルトの Lit なマテリアルが生成される Tokyo December 11

45.

パッキング調整方法 → アドレス割り当て ⎯ → → 暗黙的に入って重複しないようにアドレスを割り当てて明示化 Bundle Mode の調整 ⎯ Pack Together By Label) ⎯ Pack Separately パッキングの判断基準 ⎯ 更新頻度 ⎯ アンロード粒度 ⎯ 細かすぎないか Tokyo December 11

46.

主な調査方法 Memory Profiler Addressables Report Search Extensions メモリサイズ・アセット重複の確認などに利用 パッキング結果・バンドル間の依存関係・ディス クサイズ・アセット重複 の確認などに利用 Unity 公式から GitHub で公開されているパッ ケージ AssetDatabase での依存関係の追跡に利用 Tokyo December 11

47.

おわりに Tokyo December 11

48.

その他の取り組み → ローカライズ対応 → ミドルウェアアセットのインテグレーション → プラットフォーム対応 → etc Tokyo December 11

49.

今後の課題 → ビルドの高速化 → ダウンロードの高速化 ⎯ HTTP2 → バックグラウンドダウンロード → アドレス割り振り ⎯ → Addressables 以降の世代への対応 ⎯ → バージョン管理したくない Unity Discussions: Content Pipeline Modernization etc Tokyo December 11

50.

Thank you Tokyo December 11