Synamon’s Engineer blog

Synamonはリアルとデジタルの融合を加速させるため、メタバース領域で法人向けにサービス提供を行うテックカンパニーです。現在開発を進めている「メタバース総合プラットフォーム」をはじめ、メタバース市場の発展に向けた事業展開を行っています。このブログでは、メタバース技術とその周辺の技術、開発全般に関してエンジニアがお話しします。

unitypackage形式のアセットをupmパッケージに改造する

エンジニアの岡村です。

Unity2020.1から実装されたupmはバージョンアップを重ね、GUIでのインストールやカスタムレジストリの登録まで出来るようになり、かなり実用的といえる機能になってきています。

しかし、Unity AssetStoreで配布されているアセットは.unitypackage形式での配布形態しかサポートしておらず、未だに多くのアセットがAssetsフォルダに直接インストールされる仕様になっています。

社内のプロジェクトにおいてはUnity向けに作成した作成したライブラリはそのほとんどがupm化して管理されているので、Assetsに直接インポートしなければならないアセットも同様に管理できないか試してみた、というのが今回の趣旨となります。

当然ながら、Unityもしくはアセット提供者が公式で対応してもらえたら不要となるので、あまり長く使えるテクニックではありませんが、自作ライブラリを後からupm対応する時などに参考にしていただければ幸いです。

⚠️注意!⚠️

Asset Storeで販売されているアセットを含め、誰かが制作したアセットをupm化して第三者がダウンロードできる様な状態にする事は、ライセンスによって認められていない限り著作権の侵害にあたります。必ずアセットの改変が許されているかどうかを確認し、upm化する場合はプライベートリポジトリやLAN内など、第三者がアクセスできない場所に置いてください。

特にAssetStoreのアセットの場合、アドオン>サービス のカテゴリに含まれるアセットは標準Unity Asset Store EULAにて改変自体が禁止されている為注意が必要です。

アセットをupm化するメリット

  • Assetsフォルダ内に第三者の作ったアセットが入らないので、プロジェクトの見通しが良くなります。

  • プロジェクトの領域ではないコードやアセットをReadOnlyにし、リファクタ等による思わぬ変更の発生を防ぐことが出来ます。

  • アセットのバージョン情報がPackages/manifest.json及びPackages/packages-lock.jsonに残るので、現在プロジェクトで利用しているアセットのバージョンを一元管理できます。

  • プロジェクトのgitリポジトリサイズが小さくなります。

upm化に向かないパターン

Assetsフォルダ以下に直接置く場合とパッケージとして参照する場合とでは仕様が異なる部分があるため、upm化が不可能、もしくはメンテコストを考えた場合に釣り合わないアセットもあります。

  • 複雑な処理をするEditor拡張を含んでいる場合、ReadOnlyになること、本来のAssetsフォルダ内ではない場所にアセットが配置されることにより、正しく動作しなくなる可能性があります。

  • アセットがnpm semverに準拠しないバージョンを付けている場合、そのままではパッケージレジストリでは管理出来ないので、独自のバージョンを付けるなどの対応が必要です。

  • 3Dモデルやテンプレートなど、改変を前提としたアセット。

upm化する判断基準

以下に当てはまるパッケージはupm化の適性が高いです。

  • C#やdll等のプラグインがメインのパッケージ
  • Editor拡張がメインではない
  • AssemblyDefinitionや名前空間が定義されている

アセットをupm化するワークフロー

大まかな手順は以下の通りです。

  1. 対象アセットをパッケージとして管理する為の専用プロジェクトを作る

  2. プロジェクト内に対象アセットをインポートする

  3. パッケージ管理したい単位でpackage.jsonを作成する(記法はこちら

  4. 必要に応じてアセットを改変し、改変した個所をREADME.md等にメモしておく

  5. Unityで正常に動作するか確認し、ダメなら4を繰り返す

  6. バージョン名のタグをつけてプロジェクトで利用できるようにする

例えば PUN2 - FREE (2.40)をupm化するとなると、以下のようなプロジェクト構造になると思います。(一例)

Assets
└─Photon
   ├─PhotonChat
   ├─PhotonLibs
   │  └─package.json
   ├─PhotonRealtime
   │  ├─Code
   │  │  └─package.json
   │  └─Demos
   └─PhotonUnityNetworking
      └─package.json

package.jsonを配置した個所がパッケージとして管理するようにした部分です。PUNはChat, Libs, Realtime, PUNの4つのライブラリが一つになったアセットとして配布されて いるので、その中でRealtime, PhotonLib, PUNを個別にパッケージ化しています。

またPUNに関しては、PunSceneSettingsPhotonNetwork.LoadOrCreateSettings() などのプロジェクト固有の設定ファイルを自動生成するスクリプトが含まれている為、それらのコードを改造する必要があります。簡単な対処をするならば、これらのコードにおけるアセットファイルの生成パスをAssets以下の固定パスに強制し、利用先プロジェクト内で生成されたアセットを管理していく形になると思います。下のコードは改変場所と改変例です。

// Assets\Photon\PhotonUnityNetworking\Code\Editor\PunSceneSettings.cs:50
public static string PunSceneSettingsCsPath => "Assets/Photon/" + SceneSettingsFileName

// Assets\Photon\PhotonUnityNetworking\Code\PhotonNetwork.cs:3212-3214
string punResourcesDirectory = "Assets/Photon/Resources/";
string serverSettingsAssetPath = punResourcesDirectory + PhotonNetwork.ServerSettingsFileName + ".asset";
string serverSettingsDirectory = Path.GetDirectoryName(serverSettingsAssetPath);

ただし、これらの改変を施した場合は今後のアップデート時にも同様の修正をする必要があります。

作成したパッケージをプロジェクトから参照する

改変したアセットはGitHub上にプライベートリポジトリとして配置し、URLで直接参照してインポートすることができます。プライベートリポジトリに配置したパッケージを実際に利用するには、以前書いた以下の記事が参考になると思います。

synamon.hatenablog.com

この方式では依存関係の解決など高度なパッケージの機能は使えないのですが、.unitypackageからパッケージ化したアセットに関しては大きな問題にならず、パッケージレジストリを準備する必要もないため、このスタイルを採用しても問題は少なそうです。今後パッケージ数が多くなりメンテナンスが大変になれば社内専用パッケージレジストリを採用するかもしれません。ただ、便利になればなるほどライセンス数の管理などが大変になりそうな気がするので、その前にUnity AssetStoreで配布されているアセットがupmパッケージに対応してくれるといいなと思っています。