【Unity】Addressableのアドレス設定を自動化するツール「EZAddresser」を公開しました

Addressableアセットシステムのアドレス設定を自動化するツール「EZAddresser」を公開しました。

github.com

EZAddresserとは?

EZAddresserはUnityのAddressableアセットシステムにおけるアドレスの割り当てを自動化するツールです。
導入すると以下の2ステップで簡単にアセットがロードできるようになります。

  1. ロードしたいアセットを「Addressables」フォルダに入れる
  2. Addressables.LoadAssetAsync("[ここにアセット名]") を呼ぶ

f:id:halya_11:20210126141418g:plain
動作サンプル

Unityのバージョンは2020.1以上に対応しています(Generic型のシリアライズを使っているため)。

インストール

  1. Window > Package ManagerからPackage Managerを開く
  2. 「+」ボタン > Add package from git URL
  3. 以下を入力

f:id:halya_11:20210407093633p:plain
Package Manager

あるいはPackages/manifest.jsonを開き、dependenciesブロックに以下を追記します。

{
    "dependencies": {
        "com.harumak.ezaddresser": "https://github.com/Haruma-K/EZAddresser.git?path=/Packages/com.harumak.ezaddresser"
    }
}

バージョンを指定したい場合には以下のように記述します。

基本的な使い方

EZAddresserでは以下の手順でアセットを読み込みます。

  1. 「Addressables」という名前のフォルダを作成する
  2. 読み込みたいアセットを1.のフォルダに格納する
  3. Addressables.LoadAssetAsync(ファイル名)で読む

このときアドレスやグループは以下のルールに従って作成されます。

  • アドレスは拡張子なしのファイル名と一致するように作られる(変更可能・後述)
  • 「Addressables」フォルダは複数作成できる、ネストも可能
  • AssetBundleは「Addressables」フォルダ毎に分割される(変更可能・後述)

グローバル設定

Window > EZAddresser > Settings からグローバル設定を編集できます。

f:id:halya_11:20210126141606p:plain
Settings

各設定項目の説明は以下の通りです。

項目名 説明
Base Packing Mode Pack By Addressables Folder: AssetBundleは「Addressables」フォルダ毎に分割される
Pack Together: すべてのアセットが同じAssetBundleに格納される
Base Addressing Mode Asset Name: 拡張子付きのファイル名をアドレスとする
Asset Name Without Extensions: 拡張子なしのファイル名をアドレスとする
Addressable Path: 拡張子付きの「Addressables」フォルダからの相対パスをアドレスとする
Addressable Path Without Extensions: 拡張子なしの「Addressables」フォルダからの相対パスをアドレスとする
Group Template グループを作る際に使用されるテンプレート
未設定の場合にはAddressableAssetSettingsに設定されている最初のテンプレートが使用される

これらの設定項目を変更すると以下のダイアログが表示され、すべてのアドレスやグループが更新されます。

f:id:halya_11:20210126141636p:plain
ダイアログ

Group Templateを変更した際にはすべてのグループが一度削除されてグループ毎の設定がリセットされるので注意してください。

アセット毎の設定

Window EZAddresser > Entry Rule Editorからアセット毎の設定を編集できます。

f:id:halya_11:20210203223822p:plain
Entry Rule Editor

ツールバーのCreateボタンから各ルールを作成できます。
ルール毎の各設定項目の説明は以下の通りです。

項目名 説明
Addressable Path Rule 対象とするアセットの「Addressables」フォルダからの相対パス正規表現で表したもの
Addressing Mode 対象アセットに適用するAddressing Mode
Group Name Rule 対象アセットを格納するグループ名
Regex.Replace([Addressable Path], [Addressable Path Rule], [Group Name Rule])により実際のグループ名が求められる
ただしその際/は-に置換される。
Label Rule(s) 対象アセットにつけるラベル
Regex.Replace([Addressable Path], [Addressable Path Rule], [Label Rule])により実際のラベル名が求められる
カンマで区切ることで複数指定可能。
ラベル名にスペースは禁止。

例えば、Addressable Path Ruleをprefab_sample_(?<prefab_id>[0-9]{3})\.prefabのように設定した場合、
prefab_sample_001.prefabとprefab_sample_002.prefabの両方がこのルールの適用対象になります。
さらにこのルールのGroup Name RuleをPrefab${prefab_id}とした場合、上記のPrefabはそれぞれPrefab001とPrefab002というグループに格納されます。

なおこれらの設定項目を変更すると以下のダイアログが表示され、すべてのアドレスやグループが更新されます。

f:id:halya_11:20210126145944p:plain
ダイアログ

想定するワークフロー

EZAddresserは以下のようなワークフローを想定して設計しています。

まずプロトタイプやプロジェクト初期のことを考えます。
この時期にはリソースはすべてアプリに組み込まれていれば十分で、またAssetBundleの分割単位について考慮する必要もまだありません。 従って細かいことは考えずに読み込みたいリソースをAddressablesフォルダに放り込んでおけばOKです。
ただし読み込みインターフェースに関わる部分、つまりSettingsのBase Addressing Modeだけは決めておいた方が良いです。

プロジェクトが進んでくると、リソースの配信サーバが用意されてリソースのダウンロードが行えるようになります。
この時点で各グループに対して、Addressalbeアセットシステムの機能を使ってContent Packing & Loadingの設定をしていきます。
またグループのテンプレートを変更したい場合、この時点でやっておくことをお勧めします。

そしてプロジェクトが完成に近づくにつれてよく問題に挙がるのがAssetBundleの分割単位です。
大抵、大きすぎるアセットバンドルを適切な粒度に分割する必要が出てきます。
この時点でEntry Rule Editorを使って、適切なアセットを適切なAssetBundleに格納します。

スクリプトから操作する

グローバル設定やアセット毎の設定はスクリプトから操作することができます。

まずグローバル設定は以下のように操作します。

var settingsService = new SettingsService(new SettingsRepository());
settingsService.UpdateSetting(packingMode, addressingMode, groupTemplateGuid);
settingsService.Save();

アセット毎の設定は以下のように操作します。

var entryRulesService = new EntryRulesService(new EntryRulesRepository());

// Get all rules.
var allRules = entryRulesService.GetState();
// Get the first rule.
var firstRule = allRules.First();
// Update the first rule.
entryRulesService.UpdateRule(firstRule.Id, new EntryRuleUpdateCommand(addressablePathRule, addressingMode, groupNameRule));
// Add rule.
entryRulesService.AddRule(new EntryRuleUpdateCommand(addressablePathRule, addressingMode, groupNameRule));
// Remove Rule.
entryRulesService.RemoveRule(firstRule.Id);
// Save changes.
entryRulesService.Save();

リポジトリ

github.com