はじめに
Assembly Definition Files( *.asmdef
)については解説を見かけるのですがAssembly Definition Reference Files( *.asmref
)についての解説を見かけないのでメモがてら書き残します。
Assembly Definition Files
影響下にあるスクリプトを一つのDLLとしてコンパイルすることで全体のコンパイル時間を短縮してくれたりするやつです。
参考:
- Unity Assembly Definition 完全に理解した
- 【Unity】「AssemblyDefinitionを分けるとコンパイルが高速になる」ってホント?検証してみた!
- 【Unity】asmdefのVersion Definesを使って特定のPackageがインストールされていたら自動的に処理を変える
Assembly Definition Reference Files
Scripting: Added support for Assembly Definition Reference Files (asmref). These allow for adding additional source code directories to an existing Assembly Definition File (asmdef).
DeepL翻訳:
アセンブリ定義参照ファイル(asmref)のサポートを追加しました。これにより、既存のアセンブリ定義ファイル(asmdef)にソースコードのディレクトリを追加することができます。
とのことです。
機能としてはシンプルで、
- 自身の影響下にあるスクリプトを指定した
*.asmdef
と同じDLLファイルに含める - 以下のスクリプトファイルに影響する(
*.asmdef
と同じ)-
*.asmref
が存在するディレクトリ内 - 同ディレクトリ内に存在するディレクトリ、その子,孫,..(以下ループ)ディレクトリ
- 子ディレクトリを辿る途中で別の
*.asmref
(X)が存在したら、それ以下は(X)の影響下になる
- 子ディレクトリを辿る途中で別の
-
となっています。
作成方法は *.asmdef
とほぼ同じで、
Projectウィンドウを右クリック → Create
→ Assembly Definition Reference
で作成できます。
実際に *.asmref
ファイルを作ってInspectorで確認するとこんな感じ。
ファイルの実態は短いテキストファイルで、開いて確認してみると
Use GUID
がオンのとき:
{
"reference": "GUID:d00ea8eea3b8a4df79ba6bcba16173ef"
}
Use GUID
がオフのとき:
{
"reference": "AutoScreen"
}
といった感じになります。
用途
とりあえず思いついたやつを3つほどご紹介します。
*.asmdefによって強制されるスクリプトの配置を好きに変更できる
*.asmdef
を使用するとディレクトリ構造がある程度強制されますが、*.asmref
を使うことで *.asmdef
の配置場所とは関係なくスクリプトを配置できます。
ちなみに同一の *.asmdef
を参照する *.asmref
は複数追加できます。
アセットやPackage Managerから入れたパッケージに外から手を加える
例えば UniRx には Observable.Using()
が実装されてないのですが、これを追加するためにリポジトリをForkして手を加えたり、 Assets/
以下にソースコードをすべて配置してカスタマイズするのは面倒です。
*.asmref
を使用すると UniRx をPackage Managerから追加しつつ、 Observable.Using()
のような独自の処理を追加できます。
- Package ManagerからUniRxを追加
- 適当なディレクトリ(例えば
Assets/UniRxExtensions/
)(A)を作成 - (A)に
*.asmref
ファイルを追加&Assembly Definition
にUniRx.asmdef
を指定 - UniRxに追加したい処理を(A)に追加
- 以下のコードは UniRx で使える Observable.Using から引用
using System;
namespace UniRx
{
public static partial class Observable
{
// https://github.com/Reactive-Extensions/Rx.NET/blob/371c83c621562a2259580a03f0cb5bf8680ea720/Rx.NET/Source/System.Reactive.Linq/Reactive/Linq/QueryLanguage.Creation.cs#L417-L441
public static IObservable<TSource> Using<TSource, TResource>(
Func<TResource> resourceFactory,
Func<TResource, IObservable<TSource>> observableFactory)
where TResource : IDisposable
{
return Observable.Create<TSource> (observer =>
{
var source = default(IObservable<TSource>);
var disposable = Disposable.Empty;
try
{
var resource = resourceFactory();
if (resource != null)
{
disposable = resource;
}
source = observableFactory(resource);
}
catch (Exception exception)
{
return new CompositeDisposable(Throw<TSource>(exception).Subscribe(observer), disposable);
}
return new CompositeDisposable(source.Subscribe(observer), disposable);
});
}
}
}
*** 注意点 ***
- 処理を「足す」ことはできるが「引く/変更する」ことはできない
- Package Managerで入れたパッケージ内の
*.asmdef
のAssembly Definition References
に何かを足す・上書きすることはできない- 例えば こちら で紹介されてる
Observable.FromUniTask()
を*.asmref
で足すのは無理- そもそも
UniRx.asmdef
にはUniTask.asmdef
への参照が含まれていない - なので
UniRx.dll
からUniTask.dll
を参照できない
- そもそも
- 例えば こちら で紹介されてる
Unityの internal
クラスにアクセスする
(使用は自己責任でお願いします)
こちらの記事では特殊な *.asmdef
を追加する手法が紹介されてますが、同様のことは *.asmref
でも可能です。
例えば UnityEditor.UI
を指定した *.asmref
を作成すると、その影響下にあるスクリプトはUnityの internal
クラスにアクセスできます。
*.asmdef
を使用する場合は同一名のものを複数追加するとコンフリクトが起きて以下のようなエラーになります。
Assembly with name 'Unity.InternalAPIEditorBridgeDev.001' already exists (Assets/Foo/NewAssembly.asmdef)
が、*.asmref
を使用する場合は上記のようなコンフリクトを気にする必要がありません。
ただし、配布するライブラリなどでこのテクニックを使用する場合は、 *.asmref
に指定した *.asmdef
がプロジェクトに確実に含まれている必要があります。不要なパッケージは削除されてる場合があるので注意が必要です。
ちなみに
同一のディレクトリに *.asmdef
と *.asmref
を両方配置すると以下のようなエラーになります。
Folder 'Assets/Foo/' contains multiple assembly definition files (Assets/Foo/NewAssemblyReference.asmref)
Folder 'Assets/Foo/' contains multiple assembly definition files (Assets/Foo/NewAssembly.asmdef)
同一のディレクトリに *.asmref
を複数配置した場合は、同じ *.asmdef
を指定してある分にはエラーになりませんでした。エラーになるかと思った😇
さいごに
*.asmref
は *.asmdef
のかゆいところに手が届く、そんな存在。ぜひ使ってみてください。