unityroomでAddressableに対応するためのテンプレート作った
背景
unityroomで英語翻訳のためにLocalizationパッケージを導入したゲームをアップロードしようとしたのですが、このパッケージはAddressableに依存しています。
このAddressableを使ったときに追加でビルドされる./StreamingAssets
のアップロードには、現状unityroom本体では対応しておらず、WebGLビルドの加工や、自前でサーバーを用意して読み込ませる必要があることが分かりました。
unityroom本体でのAddressable対応を待つ...でも良かったのですが、既にunityroomでAddressableを使ってみようとする記事をちょこちょこ見かけたので、それらを参考に、
- unityroom用に必要なビルド後処理
- 1のビルドと
StreamingAssets
のサーバへのアップロード
を、なるべく簡単に(サーバー代もお安く)できる仕組みを作ってみることにしました。
ソースコード
2Dプロジェクトです。パッケージ化とかはしてませんめんどうなので
使い方
今回、自動ビルドとサーバーアップロードにはGithub ActionsとCloudflare Pagesを使うのでアカウント登録が必要です。
どちらも個人で使う分には無料アカウントで充分ですが、一応制限があります(後述)
GithubリポジトリとCloudflare Pagesの準備
メインのGithubリポジトリを作成
自動ビルド用に、Unityプロジェクトを管理するGithubリポジトリを作成します。
(既にある場合はスルーしてください)
(今回はGithub Actionsしか使わないので、実はself-hosted runnerを使えばローカルでいいのではという説がありますが、未検証です)
公開用Githubリポジトリを作成
ビルドしたStreamingAssetsを配置するためのもので、privateでもOKです。
今回は公開用のブランチcf-pages
を作成しておきます。
Cloudflare Pagesのプロジェクトを作成
Cloudflare Pagesはまだ情報が少なめなので画像付きで紹介します。
ダッシュボードにログインして Pages に飛び、Create Project から Connect to Git を選びます。
連携するGithubリポジトリを選ぶと、以下のようなプロジェクト設定画面が出ます。
Production branch に公開用ブランチの名前 cf-page
、
Build output directory に公開ディレクトリの名前 public
を設定して、プロジェクトを登録します。
(同時に初回のビルドが走りますが、まだリポジトリに何もないのでスルーしてください)
登録が完了して Pages の最初のページに戻ってくると、連携しているリポジトリ名の下に
Cloudflare Pagesプロジェクトのドメインが表示されます。
ビルド後処理のセットアップ
ソースのUnityプロジェクトをまるっとコピーするか、Assets/UnityroomBuilder/
を使いたいプロジェクトのAssets/
以下のどこかに配置します。
その後 Edit -> Project Settings でプロジェクト設定ウィンドウを開き、Unityroom Builder タブで Steaming Assets Urlを設定します。
{version}
にはUnityのApplication.version
が自動で入るので、今回は後々の自動サーバーアップロードの仕様に合わせて、以下のような設定にします。
https://Cloudflare Pagesプロジェクトのドメイン/{version}/StreamingAssets
ビルド後処理をローカルで実行する
ためしにビルド後処理をローカルでも動かしてみます。
通常のビルド設定で、ビルドターゲットをWebGLに変更し、Tool -> Build WebGL for unityroom を選びます。
後処理の結果、ビルド内の*.loader.js
の内容の一部が設定したURLに置換されます。
通常のビルドウィンドウからビルドした場合、後処理は行われません。
自動ビルド&アップロードのセットアップ
だいぶ簡略化できましたがそれでも長めです...。
ポチポチしたら終わる(はず)なのでがんばりましょう。
Github Actionsのワークフロー作成
ソース内の.github/workflow/
にGithub Actions用の定義ファイルがあるので
これをまるっと使いたいプロジェクトの直下に配置します。
以下の2つのファイルはプロジェクトに合わせて一部変更が必要です。
PUBLISH_REPOSITORY: your-account/your-project-repo # 公開用のGithubリポジトリ名
PROJECT_NAME: your-project # 自分のプロジェクト名。なんでもOK
PUBLISH_REPOSITORY: your-account/your-project-repo # 公開用のGithubリポジトリ名
上記の設定ができたらGithubにpushします。
Unityライセンスの認証
定義ファイルをpushすると、GithubのActionsタブに3つのワークフローが登録されます。
Github上でUnityをビルドするにはライセンス認証が必要なので
以下を参考にAcquire activation fileワークフローを実行し、Unityのulf
認証ファイルを取得します。(Unityのバージョンは自動でセットされるので、以下の記事にあるUnityバージョンの修正は不要です)
Github ActionsのSecrets登録
ワークフローの実行に必要な認証情報をSecretsに登録します。
- PERSONAL_TOKEN : Githubの個人トークン
- UNITY_EMAIL : Unityのログイン用メールアドレス
- UNITY_PASSWORD : Unityのログイン用パスワード
- UNITY_LICENSE :
ulf
認証ファイルの中身をそのままコピペ
最終的にこんな感じになります。
Cloudflare Pagesの基本ワークフロー実行
ワークフロー一覧画面に戻り、Publish Cloudflare base filesを実行します。これによりhttps://**Cloudflare Pagesプロジェクトのドメイン**/
へのHTTPリクエストで、HTTPレスポンスにCORSヘッダーが返却されるようになります。
CORS対応をすることで、unityroomなどの外部サイトからもアセットが取得できるようになります。
自動ビルド&アップロードを実行する
ワークフロー一覧にあるBuild WebGL for unityroom and Publish StreamingAssetsが自動ビルド&アップロード用のワークフローです。
ここまでの設定を行ったあとに実行すると、リモートでunityroom用のWebGLビルドが作成され、StreamingAssets
以下のビルドファイルがhttps://**Cloudflare Pagesプロジェクトのドメイン**/{version}/StreamingAssets/**ビルドファイル名**
でアクセスできるようになります。
もしくは、メインのGithubリポジトリにci
ブランチを用意して、ビルドしたいブランチをciブランチにマージすると、上記のワークフローが自動的に実行されます。
unityroomに本体をアップロードする
unityroom用にビルドしたゲーム本体を、通常通りの手順でアップします。
本体はローカルでビルドしたものでもOKですが、Build WebGL for unityroom and Publish StreamingAssetsワークフローを実行すると、ゲーム本体のほうもビルドされてGithub Actionsからダウンロードできるようになっています。
最後にゲームの起動確認を行います。もしアセットのロードが失敗している場合、まずはブラウザのDeveloper Tools -> Network からsetting.jsonの読み込み結果を確認してみましょう。
大丈夫そうならこれで完了です。おつかれさまでした!
補足1: Github Actions と Cloudflare Pagesの制限
Github ActionsもCloudflare Pagesも基本無料ですが、やっぱりサーバなので制限があります。
Cloudflare Pagesは転送量自体は無制限(すごい)なので、一旦アップロードした分に関してはそうそう問題にはならないかと思いますが、Addressable用としては特にファイルサイズ制限(Cloudflare Pagesが25MB、Githubが100MB)がやや小さめで、内容次第では個人でも引っかかることがありえそうです。
また、高頻度でのビルド実行やビルド成果物のサイズが大きなプロジェクトも要注意です。
補足2: Strip Engine Code の対応
自分は再現しませんでした(Unity 2020.3.16f)が、プロジェクトによってはStrip Engine Code機能によって必要なコードなのに削除される可能性があるそうです。その場合、以下の記事のように適宜link.xml
を作成するのがよさそうです。
ここからはおまけ。
WebGLでのAddressable(AssetBundle)読込の流れ
Addressableは、アセットを環境によってローカルに置くかリモートに置くか選べるやつでは…?と当初思っていたのですが、WebGLにおいては「アセットがどこに配置されているか」を定義するファイル(たぶんStreamingAssets/aa/setting.json
やStreamingAssets/aa/catalog.json
)はデフォルトでは必ずローカル側にあることが想定された作りになっています。
index.html
-> Build/*.loader.js
-> StreamingAssets/aa/setting.json
...
この挙動をUnityが提供している機能で変更する場合、独自のWebGLテンプレートを用意して読み込み先を書き換えることになります。
DefaultのWebGLテンプレートでいうここら辺ですね。
var config = {
dataUrl: buildUrl + "/{{{ DATA_FILENAME }}}",
frameworkUrl: buildUrl + "/{{{ FRAMEWORK_FILENAME }}}",
codeUrl: buildUrl + "/{{{ CODE_FILENAME }}}",
#if MEMORY_FILENAME
memoryUrl: buildUrl + "/{{{ MEMORY_FILENAME }}}",
#endif
#if SYMBOLS_FILENAME
symbolsUrl: buildUrl + "/{{{ SYMBOLS_FILENAME }}}",
#endif
streamingAssetsUrl: "StreamingAssets", // ここを書き換えたい
companyName: "{{{ COMPANY_NAME }}}",
productName: "{{{ PRODUCT_NAME }}}",
productVersion: "{{{ PRODUCT_VERSION }}}",
};
………が、unityroomにはそもそもビルド成果物のうちindex.html
はアップロードせず、unityroom側で固定で用意されているhtmlから各種ファイルがロードされることになります。
そのため、ビルド後処理では*.loader.js
の中身を以下のように気合いで書き換えています。
// NOTICE: Deeply dependent on loader.js generation logic
var originalUrl = $"new URL(l.streamingAssetsUrl,document.URL)";
var newUrl = $"new URL(\"{newStreamingAssetUrl}\")";
Debug.Log($"Replace StreamingAssetUrl file: {loaderJsPath} from: {originalUrl} to: {newUrl}");
ReplaceStringInFile(loaderJsPath, originalUrl, newUrl);
SettingsProviderによるプロジェクト設定の拡張
以下を参考に実装しました。
ScriptableSingleton
と組み合わせることで結構スッキリ書けて便利でした
Addressableを使ったほうがよいか
WebGLでは、最初に書いたような何らかの背景があるか、脱Resourcesしてでも起動を早くしたい場合以外は使わなくていい気がします…!
※執筆時点での個人のかんそうです
参考
実装にあたり、特にお世話になったページたち
Discussion