3.7K Views
September 26, 19
スライド概要
2019/9/25-6に開催されたUnite Tokyo 2019の講演スライドです。
秋友 覚(株式会社コロプラ)
山本 康平(株式会社コロプラ)
松浦 章人(株式会社コロプラ)
こんな人におすすめ
・短期~中期(リリース1~2年目)運用タイトルに携わる開発者
・リリース前タイトルの開発に携わるエンジニア
・ビルドパイプラインを構築しているエンジニア
受講者が得られる知見
・移行に伴った必要作業の見積もりの一端
・大量ファイルのビルド環境構築の手法
・運用を長期化できた場合に準備すべきこと
Unityのイベント資料はこちらから:
https://www.slideshare.net/UnityTechnologiesJapan/clipboards
リアルタイム3Dコンテンツを制作・運用するための世界的にリードするプラットフォームである「Unity」の日本国内における販売、サポート、コミュニティ活動、研究開発、教育支援を行っています。ゲーム開発者からアーティスト、建築家、自動車デザイナー、映画製作者など、さまざまなクリエイターがUnityを使い想像力を発揮しています。
運用中超大規模タイトルにおける Unityアップデート課題の解決手法と事例 ~将来アップデートするために~ 株式会社コロプラ 秋友覚 山本康平 松浦章人
自己紹介 *秋友 覚* 全社横断的な技術サポートを行う部の部長 1. コンソールゲーム、モバイルアプリ開発を経験 2. 2014年コロプラ入社 3. 『クイズRPG 魔法使いと黒猫のウィズ』や 『白猫テニス』などの開発、運用を経験 2
講演概要 ❏ アップデートプロジェクト全体像 ❏ アップデート時に発生した問題事例 ❏ アップデートを支えた技術 3
アップデートプロジェクト 全体像 4
アップデート理由 ❏ ストア要件を満たさなくなった ❏ Google Play にて 64bit 対応が必須 ❏ 使用していた Unity バージョンでのサポートアナウンス無し ❏ 2019年8月以降、非対応はアプリ更新時の審査通過不可 ❏ その他 ❏ Unityの最新機能が使えない (JobSystem, Timeline … ) ❏ 社内共通ツール/フレームワークの導入が困難 5
Unityアップデート理由 6
アップデート対象 ❏ Unity4 から Unity2018.2 ❏ Unity2017 LTS でのサポートアナウンス以前に着手 ❏ Unity2018.2 から Target Architecture 「ARM64 」の Experimental が外れた ❏ Unity2018 LTS のリリース前に対応が必要だった ❏ 弊社内の超大規模な運用中タイトルすべて ❏ 運用6年 『クイズRPG 魔法使いと黒猫のウィズ』 ❏ 運用5年 『白猫プロジェクト』 本講演は上記2タイトルでの事例をご説明します 7
アップデート対応体制 ❏ 専任の対応チームを結成 ❏ 理由 ❏ アップデートに関する情報の集約 ❏ 仕様や問題解決方法の共有が容易 ❏ サービス運用タスクによる影響が少ない 8
アップデート対応体制 ❏ 専任の対応チームを結成 ❏ メンバー構成 ❏ ❏ ❏ ❏ 黒猫 : 1人 白猫 : 2人 共通で発生する問題対応 : 3人 全体の管理調整 : 1人 9
アップデート対応体制 ❏ 期間 ❏ 黒猫 2018/6 ~ 2018/11 ❏ 白猫 2018/6 ~ 2019/2 10
アップデート対応の課題 ❏ アップデートするアセットの量 ❏ Unity の仕様変更追従 ❏ サービス運用との連携 ❏ アプリ、アセットビルド環境の構築 11
アセット数
アセットに関わる数字 ❏ 白猫 ❏ プロジェクトサイズ ❏ 総ファイル数 ❏ 黒猫 ❏ プロジェクトサイズ ❏ 総ファイル数 約210GB 1,037,972ファイル 約107GB 397,615ファイル 13
盛ってるでしょ? 14
証拠のデバッグ進捗表 15
キャラモデル 約2,400体
キャラスキル 約2,800種 ※ さらに武器固有スキル約750種
クエスト 約5,000 over ※ 復刻予定なしや、共通クエスト (プレゼント企画とか)を除く
エフェクト 約17,000
ボイス 約226,000
iOS / Android 両端末 = x2 もちろんAndroidは、最低でも 各GPUアーキテクチャで確認
これぞ 超大規模 22
アセット数の影響 ❏ QA項目の増加 ❏ 個別対応作業の増加 ❏ インポート時間の増加 ❏ ビルド時間の増加 ❏ バージョン管理コストの増加 23
アップデートプロジェクト再確認 ❏ ストア要件を満たすために ❏ 対応チームを結成して ❏ 8~9ヶ月くらいで ❏ 5~6年運用したタイトルの ❏ 数十万規模のアセットを ❏ なるべく楽な手法でがんばる 24
必要なアップデート処理 25
自己紹介 *山本 康平* 全社的な効率化ツール・ライブラリ開発者 1. 2. 3. 4. コンソールゲーム開発を経験 2014年コロプラ入社 タイトルのメインプログラマーを経験 『白猫プロジェクト』の運用を経験 26
アップデート初期作業 ❏ Unity の自動更新かける ❏ 自動更新でコンパイルエラーが残った箇所を修正 ❏ ストアアセットのバージョンマクロなどに対応 ❏ Obsolete 指定関数もできれば修正 ❏ 不正なアセットを検出する ❏ Missing 存在しないアセットを参照しているアセット ❏ 正常動作しなくなったストアアセットを参照しているアセット 27
アップデート初期作業 ❏ 実行して不正な挙動を確認、調査 ❏ 実行時の例外、エラー、警告 ❏ 必要なものが消えている ❏ メニューが遷移しない ❏ ゲーム内の要素をどれだけ知っているかが重要 ❏ アップデート処理をかける ❏ 自動化できそうなものはスクリプト用意する ❏ 自動化できなさそうなものは検出スクリプト用意する 28
ストアアセットの更新 例:2Dスプライト、アニメーションアセットが使えない ❏ ❏ ❏ ❏ ❏ なぜなら アセットが生成する Atlas が生成されない なぜなら 内部で TextureType を指定している部分が通らない なぜなら 定数指定されていた TextureType がもうない そして そのアセットはもう更新されてない そして そのアセットは改変ライセンスが不明確でパッチ当てられない 対応:アセット同等の2Dライブラリを作る 教訓:サポート継続可能性はよく検討する 29
不正スクリプト修正(一例) ❏ MonoBehaviour の new Unity の作法としてそもそも is not allowed. 対応スクリプト: new キーワードに続くシンボル名で GetAssemblies して IsSubclassOf(typeof(MonoBehaviour)) だったら検出 ❏ NameToLayer をクラス変数に代入 初歩的ミス、仕様勘違いは スクリプトでチェック 少し気付き難いが実行時エラーとなる AddComponent() 出来ない、のちに Null 参照などの原因となる “NameToLayer is not allowed to be called from a MonoBehaviour constructor” 対応スクリプト: NameToLayer() の論理行頭に private などの修飾子があれば検出 30
不正アセット修正 ❏ 仕様変更の煽りを受けたシェーダー ❏ 仕様変更の煽りを受けたパーティクル ❏ アセットそのものをうっかり消した ❏ 他のアセット作るときに上書した ❏ 当たり判定不要なエフェクトに Collider がついている なるべくスクリプトで検出、修正する 31
目でみる 不正アセット 32
正常なアセット例 ほぼ Mobile Unlit なモデル 33
不正アセット例 まっしろ Material は無事だが Texture アセットが無い 対応: Git の歴史を遡り、 元気だった頃の Texture を救出 34
不正アセット例 ピンク Material が不正な状態 大体の原因は Shader エラー グラフィックプログラマは この色が大嫌い 対応: Particle などは Renderer の Material モデルの場合は対象 Shader コンパイルのログなどを調査、修正 35
不正アセット例 ???? UVマッピングがぐちゃぐちゃ 目を凝らしてみないと気付かない 最悪のパターン 対応: 発生パターンの絞り込みは断念 Maya から再出力すると回復 異なる FBX エクスポーターを 使用されていたのか? 36
Unityの仕様変更への対応 37
シェーダーの仕様変更 ❏ Unity4 時代の TexGen は廃止 ❏ Unity4 時代の Fog は廃止 シェーダー自体は grep なりで探して修正 もしくは参照している Material を検索して 別シェーダーに置換 38
スクリプト処理例 Unity4 系で Fog を利用していた Shader に対する処理 これをすべての Material に対して行う場合 39
スクリプト処理にかかる時間 ❏ AssetDatabase に 55万個 ❏ うち t:Material が 15万個 ❏ 1 Material 処理に0.1秒 ❏ かかる時間は 15,000秒 = 4時間弱 ❏ こんな処理が 10 個程度 40
こんなペースじゃ 修正おわらない 41
処理を効率化した手法 ❏ スクリプト処理専用マシンを用意する ❏ 物量には物量で対抗する ❏ 絶対に修正作業と競合するのでタイミングは調整する ❏ なるべく yaml テキストとして編集する ❏ 全 Asset を Dirty にして SerializeVersion 上げる ❏ .meta, .prefab にほとんどの情報がある 例えば prefab なら ❏ 参照は GUID を grep する Component 要素の値=参照が ❏ なるべく AssetDatabase 使わない 42 4桁から8桁になる
処理を実装する上で ❏ 処理によっては検出するだけにとどめる ❏ Missing が正しいことも稀によくある ❏ 検出されたリストを目視チェックでも十分では? ❏ 数個エラーがある程度なら人力でも十分では? 例:制作中のアセットがたまにまぎれこんでしまうエラー リストアップだけして作業者に確認してもらうのが楽&速い&堅実では? 43
処理を実装する上で ❏ スクリプト処理にはかならず進捗表示と キャンセル機能を実装しておく ❏ 処理経過のログを less ❏ アセットを diff ❏ 想定外の差分などが出たら即座に停止 想定外の処理内容になったら早めに止めないと 時間が無駄になります 44
ParticleSystemの仕様変更 パラメーターの意味が違う 左: Unity4 右: Unity2018.2 「Render Alignment」が「Render Alignment」「Simulation Space」に分離 もちろん変換などしてくれないので見た目が変化する 45
対応手法例 Particle を元の状態に変換する処理を作成 master からマージしてエフェクトを取り込む毎に実行 46
AudioClipのデフォルト値 「force to mono」が有効な AudioClip にノイズが出る。 Normalize がデフォルト有効になっているのが原因。 0 Normalize なし Normalize あり 47
物理挙動仕様変更 Physics + CharacterController を使用 ❏ PhysX 2 ( Unity4 以前) ❏ PhysX 3 ( Unity5 以降) ❏ PhysX 3.4 ( Unity2018.3 ) ❏ PhysX 4.1 ( Unity2019.3 ) Unity 内部物理エンジン( PhysX )はバージョン毎に異なる Unity4 から アップデートで大きく挙動が変化した ※残念ながら Unity2018以降も挙動が変化する可能性があります 48
あなたのPhysXはどれ? お使いの環境を思い出してください ❏ ❏ ❏ ❏ ❏ CharacterController 制御のモデルを操作 Collider 形状は Capsule モデルを右方向に移動させる 別のモデルに Collider つける 操作モデル方向に移動させる RigidBody がある / ない場合 どのような挙動になりますか? 49
RigidbodyなしのCollider 50
RigidbodyありのCollider ※ ちなみに Unity2018.3 以降だと押し出されます 51
挙動変更への対応 ❏ 原因は CharacterController の OverlapRecovery ❏ めり込みからの回復を制御する機能 ❏ Unity4 にはなかった機能 この機能により移動オブジェクトにめり込んだ際の 挙動が変化 52
挙動変更への対応 ❏ 対抗策は enableOverlapRecovery ❏ 押し出しが有効になるフラグがある ❏ 無効にしても Unity4 と同じ挙動にはならない ❏ しかも地面下への落下が多発する ❏ 地面への設置判定が Unity4 比較で厳格化した 挙動が変化する箇所の量、重要度を比較して enableOverlapRecovery は有効にしておくことに・・・ 53
ParticleSystemのバグ (リリースノートより) ParticleSystem Particles: Particle System bounds no longer ignore Shape Y scale when using Rectangle emission shape. ❏ メインモジュールの 3D Start Size で変更された Y ( Z ) スケールが Bounds に反映されない ❏ Unity2018.3 で修正済み ❏ Unity2018.2 にはバックポートされなかった 54
右から左にフレームインする演出 理想 現実 55
対応策 エフェクトの Awake で Bounds を広げる ??? 56
ParticleSystemの“バグ修正” Particle の SubEmitter がちゃんと機能する ❏ Unity4 では SubEmitter は出たり出なかった(バグ仕様) ❏ Unity2018 ではちゃんと出るようになった(バグ修正) ❏ Unity4 ではデザイナがエミット数を増やして対応 ❏ 出ないことがあるので若干多めに設定 ❏ バグ修正によってエミッション量が増加(正常化) バグ修正は大変ありがたいのですが... 57
エディタ仕様変更例 細かな仕様変更 Depth 精度がシーンビューとプレビューで異なるため見た目も異なる https://github.com/UnityTechnologies/UnityCsReference/blob/master/Editor/Mono/Inspector/PreviewRenderUtility.cs#L29 58 6
リリースまでの流れ 59
リリースまでのイテレーション ❏ ゲーム内のイベント単位でマージ ❏ マージ時に競合したアセットをチェック ❏ prefab がマージできてても基本的に theirs をとる ※ちなみに施策ブランチマージした日は軽く 1000 コミットとびます ❏ 更新スクリプトの実行&対応 ❏ “Unity2018 のためにこう作ってくださいね”が浸透すれば不要になる ❏ 運用で追加要素をデバッグリストへ追加 ❏ 創意工夫に溢れたレベルデザインによる不具合は対応方法考える... 60
リリーススケジュール 基本的にアセットに下位互換はないので、 どのアップデートから Unity2018 で作業するか決めておく 61
今後の バージョンアップに 向けたご提案 62
次のバージョンアップのために ❏ アセットは適宜バリデーションする ❏ アップデート時に気付いても手遅れです ❏ バージョン固有のものはリストアップしておく ❏ 例)バグを回避するためのコードやデータ ❏ アセットの参照経路を把握しておく ❏ 数値で参照されるアセットも追えるように ❏ 創意工夫はほどほどに ❏ 物事には適切な方法があります 63
アップデートを 支えた技術 〜弊社の取り組み〜 64
自己紹介 *松浦 章人* ビルド環境改善に取り組むビルドエンジニア 1. 2015年コロプラ入社 2. ゲームプログラマとして運用を経験 3. 全社的な開発環境の改善に着手 65
アプリビルド 66
バックエンドが 相当進化しました From いらすとや Unity4 Unity2018
でも弊社では
かなり少ない変更で 対応が可能でした
アプリビルドの対応 ❏ ❏ ❏ ❏ Android のアーキテクチャ修正 Scripting Backend を Mono から IL2CPP に変更 NDK の設定追加 mainTemplate.gradle の追加 以上 70
なぜ少ない変更で 対応が可能だったのか?
弊社のビルドパイプライン方針 ❏ ビルドスクリプトは共通化 ❏ ビルドパイプラインは Unity4 ~ 最新 Unity まで対応 ❏ ❏ ❏ ❏ ❏ 移行完了したので現在は Unity2018.2 から最新まで 必要最低限の機能のみ実装 コードは全て Git で管理 アップデート時には設定変更のみで対応 Jenkins 構成も共通化 72
スクリプト構成 ❏ 1) Jenkins Common Tools ❏ 2) App Build Tools ❏ 基本的にはこの2つをメインに機能追加する ❏ ライブラリを更新する方式で各プロジェクトがとりこむ ❏ 3) プロジェクト個別 Tools ❏ テンプレートを提供し、各プロジェクトが固有の処理を追加する ❏ 4) Jenkins Plugin ❏ 社内でアップデートセンターを作って配布する 73
パッケージ構成 74
Jenkins構成 ❏ GCP 上に master 構築 ❏ Mac マシンを slave 化 ❏ 統一ディレクトリ構成 ❏ アプリケーションパス命名規則 ❏ ワークスペース使用方法 75
アプリビルドのフロー ❏ フローは全プロジェクトで共通 ❏ Unity ビルド → Xcode / Gradle ビルド ❏ Gradle ビルド不要のプロジェクトもあり ❏ サーバへのビルド成果物アップロード ❏ ビルド通知 76
ビルドスクリプト ❏ Unity ビルド ❏ 複数バージョンあるがほとんど同じコード ❏ Xcode ビルド ❏ 今はバージョンによるスクリプトの違いは無い ❏ Gradle ❏ apk と aab による違いはあるが、ほとんど同じ 77
Unity ビルドスクリプトの変化 Unity4 Unity2018 78
追加・変更された機能の例 ❏ Application Identifier の設定方法が変更 ❏ Automatic Signing が追加 ❏ Scripting Backend の設定方法が変更 ❏ Android の IL2CPP が追加 ❏ Android のアーキテクチャ設定が変更 ❏ .Net 4.6 が追加 ❏ コマンドラインオプションが変更 など 79
設定項目 エディタ スクリプト ❏ API Compatibility Lv ❏ Scripting Backend ❏ Scripting Define Symbols ❏ Application Identifier ❏ (Android)Target Architecture 他 他 80
プロジェクト個別Tools 共通化してもプロジェクトの個別対応は必要 ❏ なるべく Unity の PreProcess や PostProcess で対応 ❏ なるべく個別対応を入れやすいように設計 ❏ 全く同じコードで全てのプロジェクトを ビルドできるとは思わない ❏ 独自進化をしすぎないように注意 ❏ 共通化の意味がなくなるような進化はさせない 81
設計の利点 / 欠点 利点 欠点 ❏ ❏ ❏ ❏ ❏ コードが難読 アップデート対応容易 新機能の横展開容易 全体の把握が容易 Jenkins の学習コストが 低い ❏ 原因はコード内の複数バー ジョン分岐 ❏ 属人化しやすい ❏ コア部分を一部の人しか触 らなくなるため 82
負の遺産 ❏ ifdef に頼り切った難読コード ❏ 特定バージョンのみ実行する処理 ❏ 追加意図が不明になった処理 対策: 全社的に不要な Unity バージョンは消す 専用処理を消しやすくしておく 83
アプリビルドまとめ ❏ なるべく複数バージョンで共通化する ❏ 実は Unity からビルド出力する処理は Unity4 ~ Unity2019 まで変化は少ない ❏ バージョン固有の処理は削除しやすくする ❏ 負の遺産はどんどんたまる 84
Asset Bundle ビルド 85
アセット バンドル総数
280,000 files 7 GB
760,000 files 28 GB
これと 戦います
Asset Bundle ビルド更新の方針 ❏ クリティカルな問題のみ更新対応する ❏ 変更しなくていいところは変更しない ❏ Asset Bundle のロード処理は引き継ぐ ❏ Asset Bundle のビルド処理は変更しない ❏ 旧 Unity バージョンのまま動くところはそのままにする ❏ ロードまわりに不具合が出た際に問題切り分けしやすくする ❏ Asset Bundle のバージョン管理は更新する ❏ Git から Git LFS へ ❏ ところでみなさん何使っておられます? 90
ビルド処理を変更しない理由 現状のプロジェクトでの運用 ❏ 施策ごとに分離してビルド ❏ アセットのパスを指定してビルド ❏ BuildPipeline.BuildAssetBundle() を使用 ❏ 現在は Obsolete になっているのでいつかは.. Single Manifest などを導入すると 運用フローの大幅な変更が必要になるため ビルドフローは変更しない 91
アップデート対応時の諸問題 ❏ 依存関係情報がない ❏ 依存調査しながらビルドすると処理時間が膨大すぎる ❏ そもそもビルドすべきアセットがわからない ❏ 運用から Merge のどれをビルドすべきかはプロジェクト進行に依存 ❏ どれが fix されたアセットかがわからない 対策:全部ビルドしよう 92
全 Asset Bundle ビルド ❏ Deploy 用リポジトリからビルド済みアセットを取得 ❏ 取得したアセットのパスから元アセットリストを作成 ❏ リストにあるアセットを全部ビルド 依存関係がわからなくても、 全部ビルドしたら問題解決! 93
とはいかない
そう 数の暴力
Asset Bundle ビルド時間問題 ❏ Asset Bundle の数は約760,000 ❏ 1 秒/ Asset Bundleで処理すると約8日かかる ❏ 実際は1秒以上かかる ❏ 何も考えずにやったら「終了までxxxx日」って出た ❏ iOS / Android を分割してビルドしても約4日 遅すぎて無理 96
Asset Bundle ビルド並列化 ❏ やっぱり物量には物量で対抗 ❏ アセットをリストアップ ❏ ビルドリストを12分割 ❏ 1プラットフォームあたり12並列でビルド ❏ 全 Asset Bundle ビルドするのに20時間 ❏ 修正確認ギリギリ許容できる 97
しかし半年後
ビルド時間が再度限界に到達 ❏ アップデート対応終盤にはビルド頻度増加 ❏ 各ゲーム内イベント施策を Unity 4 / 2018 並行デバッグでさらに増加 ❏ Git リポジトリサイズ増加で 処理にかかる時間も増加 ビルド時間3日に突入、再対応へ 99
さらなる高速化 ❏ 差分ビルド化 ❏ ビルド時ファイル毎に Hash をチェック ❏ 単体ファイルは AssetDatabase.GetAssetDependencyHash ❏ フォルダは子ファイル全てに AssetDatabase.GetAssetDependencyHash ❏ ビルドアセットの内部アセットも Hash 保存 ビルド時間3日→5時間 今度こそ対応完了 100
遠くない未来の課題 ❏ 当然 次のアップデートまでにアセットは急増 ❏ 当然 さらなる高速化が必要 ❏ バージョン管理方針の変更が必要そう ❏ Git LFS がファイル数の増加に弱い ❏ 通信速度が出なくて遅い ファイル数減らさないと... 101
Asset Bundle ビルドまとめ ❏ ビルドフローは変えなくても対応可能 ❏ Obsolete なのでバージョンアップ後に切替え推奨 ❏ ビルド機能はどんどん良くなってるので切替え推奨 ❏ 規模増加にともなってビルド高速化が必須 ❏ Unity の外側での対応も有効 ❏ 新しいビルド機能の方が最善最速とは限らない 102
全体まとめ 103
全体まとめ ❏ アップデート作業はお早めに ❏ 対応方針はサービス等の規模に応じて ❏ 今後の課題 ❏ 一部 Legacy 機能の排除 ❏ 定期更新が可能な環境構築 104
ご清聴 ありがとう ございました 今後も数の暴力には屈しない... 105