VPM入門

# はじめに
この記事ではVPMを0から作って配布可能なurl,unitypackageができるまでのメモです。

> VRChat Package Manager (VPM) は現在 Creator Companion のメイン機能です。VRChat SDK とパッケージの更新をサポートし、VRChat プロジェクトの作成と管理をスピードアップします。
[公式サイト](https://vcc.docs.vrchat.com/vpm/)(DeepLにて翻訳)より
- VRChatをやっている方の多くはModular AvatarやlilToonなどをVCCから追加した経験があると思います。とても便利そうなので作ってみたいですね。作ってみましょう
    - 「Package Maker」というアセットをVPMに変換する公式ツールがありますが、それを使う方法についてはここでは扱いません[^PackageMakerなにもわからない]
[^PackageMakerなにもわからない]:サンプルをダウンロードして開くと2019環境と認識されるのですがC#が2022環境で作られていて、何も解らなかった…　あと個別のプロジェクトがpackageフォルダの2階層上で作られてしまって気持ち悪かった…
- 筆者はかなり雑な性格で(jsonの細かい設定など)色々と消しがちです。また英語もわからないため自動翻訳を通した情報に基づいた記事です。各位一次ソースを充分ご確認の上注意してご覧下さい
- この記事で作るVPMはからっぽです。なんの処理も実装しません。実装上の注意はRuntimeとEditorフォルダはルートに置く必要がある、ということくらいで、あとは普通のAsset開発と大差ないと思います


# 著者の環境
- Unity 2019.4.31f1[^unityのバージョン]
- [Github Desktop](https://desktop.github.com/download/) 3.3.11(x64)
- [ALCOM](https://vrc-get.anatawa12.com/alcom/) v0.1.14
[^unityのバージョン]:この記事は中身を実装しないのでUnityのバージョンはほとんど関係ないです

# 基礎知識
- VPMとは（[公式情報](https://vcc.docs.vrchat.com/vpm/packages/#:~:text=Package%20Format))
    - VPMは、Unity PackageをVRC向けに要件追加したもの。まず[Unity公式](https://docs.unity3d.com/2019.4/Documentation/Manual/CustomPackages.html)履修がお勧め
        - [ここ](https://docs.unity3d.com/ja/2021.3/Manual/CustomPackages.html)によると[パッケージレイアウト](https://docs.unity3d.com/ja/2021.3/Manual/cus-layout.html)に従ったファイル構造のまとまりのこと
    - Unity Packageにはpackage.son(Package Manifest file)が必要。よってVPMにも必要。**太字**はVPM上必須項目[^必須とかいてあるけど]
        - package.json に記載する情報
            - [Unity標準](https://docs.unity3d.com/2019.4/Documentation/Manual/upm-manifestPkg.html)の内容
                - **name** … パッケージの正式名称。逆ドメイン[^ドメインがない場合]形式(例：nadena.dev.modular-avatar)
                - **version** … パッケージの[セマンティックバージョン](https://semver.org/lang/ja/)
                - **displayName** … パッケージの読みやすい名称(例：Modular Avatar)
                - description … 簡単な説明
                - unity … パッケージが互換性を持つ最低のUnityバージョン
                - author … パッケージの作者(**name**, **email**, url)
                - license … [ライセンス符号](https://spdx.org/licenses/)又は「See LICENSE.md file」
                - その他色々(気になる方は公式を読んで下さい、あまり使わなさそう)
            - VPM特有の内容
                - vpmDependencies … VPMの依存関係
                - **url** … パッケージのzipファイルの直接ダウンロードリンク
                - legacyFolders … 書いてあると、UnityPackage版のものが見つかったとき自動で削除[^legacyFolders]
                - legacyFiles … 上のファイル版
                - legacyPackages … 上のVPM版（統合などしたときに使う）
                - zipSHA256 … ダウンロードしたzipの整合確認用チェックサム
                - changelogUrl … パッケージの変更ログファイル(現在VCCで使われていない)
        - licenseは必須でないが、記載を強く推奨
    - 重要情報
        - VPMにするには(Unity Packageとして)[適切なフォルダ構造](https://docs.unity3d.com/ja/2021.3/Manual/cus-layout.html)が必要
            - たとえば、Root直下にEditor, Runtime, package.jsonが必須など
        - package.jsonというものを作る必要があり、Unity Package・VPMそれぞれとして入力可能・必須な情報がある
- VPMの公開（Webサイト）
    - 次の手順を行うことでVPMをコミュニティパッケージとして公開することができる（詳細手順はページ下）
        - 作成したVPMをgithubにアップロード
        - ビルド＆リリース
        - [Creating a Package Listing](https://vcc.docs.vrchat.com/guides/create-listing)
- VPMの公開（unitypackage）
    - [VPAI](https://github.com/anatawa12/VPMPackageAutoInstaller)を使うことでVPMをインストールするunitypackageを作ることができる。この方法で入れたものはVCC/ALCOMを操作して導入したのと同じように管理される


[^必須とかいてあるけど]: 太字は必須と公式サイトには書いてあるが、実際にはmailとurlは要らない気がする。
[^ドメインがない場合]:「\<domain-name-extension>.\<company-name>」で始まることとされている。小文字英数字[^小文字だけなんです]、ドット、ハイフンのみ。筆者はドメインを持っていないのでcom.githubをお借りしました（他にそうしている方もいたので…）
[^小文字だけなんです]:なぜかVRC公式サンプルには大文字が入っていますが、大文字はだめです
[^legacyFolders]:これを設定してあれば配布アセットに同梱しつつ、VCCに登録している人はそっち優先ということができる。すごく便利！（後日追記：これあんまり[過信したらだめかもしれない](#legacyfolders%E3%81%AE%E3%83%86%E3%82%B9%E3%83%88)）

# ローカルVPMの作成
- VPMの最小構成はpackage.jsonだけの形。実際にそれだけで構成されるVPMを作ってみる
- 作業フォルダとjsonの作成(普段Unityで使っているフォルダに作った)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2935918/a3a500f9-a787-de56-91d9-7189e1af90a4.png)
- [公式](https://vcc.docs.vrchat.com/vpm/packages/#:~:text=Altogether%20that%20makes)からとりあえずコピー
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2935918/a5448511-c1ed-9990-9775-c75ac414383d.png)

- 自分の情報を入力
::: note warn
後で書きますが、下の情報はvpmDependenciesを修正し忘れていて極めて有害です。
:::
```package.json (例)
{
    "name" : "com.github.pandrabox.testvpm",
    "displayName" : "Pan Test VPM",
    "version" : "1.0.0",
    "author": {
      "name": "pandra"
    },
    "unity" : "2019.4",
    "description" : "Hello World!",
    "vpmDependencies" : {
      "com.vrchat.avatars" : "3.1.0"
    },
    "legacyFolders" : {
      "Assets\\Pan\\TestVPM": ""
    }
}
```


- 読み込んでみる
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2935918/a138068a-1480-2bd7-336d-8877f6dfd0f9.png)

- できた
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2935918/2025fac2-873a-58e6-62fd-243e73ecc876.png)

- プロジェクトに入れてみる
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2935918/85a6b379-ff2d-4f93-401f-d012cf1a48f4.png)

- 怒られる。SDKの依存関係設定がだめらしい
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2935918/ece09c44-0ee7-e6bc-32cc-c6e858762716.png)

- MAに合わせてvpmDependenciesを修正
```package.json
{
    "name" : "com.github.pandrabox.testvpm",
    "displayName" : "Pan Test VPM",
    "version" : "1.0.0",
    "author": {
      "name": "pandra"
    },
    "unity" : "2019.4",
    "description" : "Hello World!",
    "vpmDependencies" : {
      "com.vrchat.avatars" : ">=3.7.0"
    },
    "legacyFolders" : {
      "Assets\\Pan\\TestVPM": ""
    }
}
```

- 一度パッケージを管理から外して、もう一度管理にしてプロジェクトにいれてみる。今度は通った
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2935918/21b4cd51-0097-0db1-feda-6f56b799e597.png)

- packageフォルダ内にVPMが読み込まれている
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2935918/e7f79d33-3b1d-ecc0-eeb2-15e25b8d7d69.png)

- UnityのPackageにも準拠しているのでPackageManagerにも表示される
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2935918/896fade8-d8f0-6e34-2573-b689571742b7.png)

- (感想)ローカルを作るだけだったら簡単[^ローカルは簡単]だった
- (感想)普段使うパッケージを全部依存関係に設定しただけのパッケージを作っておいたらすごく便利そう
[^ローカルは簡単]:package.jsonの仕様を書いてあるページを見つけるのに2日かかった。公式、ちゃんと読もう。


## legacyFoldersのテスト
<details><summary>(番外編)legacyFoldersのテスト</summary>

- jsonでlegacyFoldersに設定したフォルダを作ってみる
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2935918/c795c4f8-26a5-bc9b-c9e2-194bd027df1f.png)
- 起動する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2935918/b07395ce-a461-6675-f651-19154bea0256.png)
- 勝手に消え…ない。あれ？
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2935918/d2ba24ee-6ad3-7da2-03c3-c062574c1ab9.png)
- レガシーがある状態でVPMを読もうとすると削除判定があるみたい
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2935918/ef2a0c1d-ab3b-ce3b-379a-4a0dad61dcff.png)
- 今回は空っぽだから問題はないけれども、VPM入れてからレガシーを入れると問題が起きるかもしれない？
</details>


----
ここから公開設定

# ビルド&リリース
:::note info
ファイルをgithubにあげて配布可能な形(unitypackage)にする手順です
:::
- [Releace用のworkflow](https://github.com/vrchat-community/template-package/blob/main/.github/workflows/release.yml)[^Releace用のworkflow]をダウンロード
[^Releace用のworkflow]:公開するにはビルド、タグ付け、リリースと言う作業をする必要があり、大変。これを入れておくと自動でやってくれる。
- 作業フォルダの下に.github/workflowsフォルダを作成し、その中にダウンロードしたファイルを入れる
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2935918/09abf58f-acc3-2534-cf4c-ed912c07564d.png)
- 次を参考に、変数の確認なし[^変数めんどくさい]、packageフォルダをルート[^ルートおかしい]に変更する
```release.yml
    steps:
    # Ensure that required repository variable has been created for the Package
    - name: Validate Package Config
      id: config_package
      run: |
          echo "configPackage=true" >> $GITHUB_OUTPUT;

  # Build and release the Package
  # If the repository is not configured properly, this job will be skipped
  build:
    needs: config
    runs-on: ubuntu-latest
    permissions:
      contents: write
    env:
      packagePath: .
```
[^変数めんどくさい]: 本来githubの変数を使ってpackageを選択しつつ正しいものか判定する処理があるのですが、面倒なので消します…
[^ルートおかしい]: 元々のテンプレートがなんでpackageの上で配布する仕様なのかとても謎　先駆者の方々をみるとだいたい配布するpackageそのものをリポジトリにしているのでこの変更はほぼ必須

- Github DesktopでAdd local repository[^Newだとうまくいかない]
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2935918/0748777c-3580-d7f3-a4cb-b3e8531d012b.png)
[^Newだとうまくいかない]: Newでやると作業フォルダの中に同名のフォルダが作成されるのでこの手順でいつもやっている。正しいんだろうか
- 作業フォルダをいれてcreate a repository
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2935918/d39db593-589e-f876-eb10-ce9cda279dab.png)
- 適当に設定してCreate repository
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2935918/2e78db3d-109a-1e77-edf7-41cb62abe48d.png)
- Publish
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2935918/d6238c67-f467-2d70-e671-a29f96b60d8c.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2935918/5cd8125b-9080-dafe-8322-4dda4d7bdcbc.png)
- View on GitHub
 ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2935918/7269b444-97a7-832a-2798-25cab28c79a8.png)
- Actions
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2935918/90d32173-3026-b1dd-b69a-0bd61534694d.png)
- Build Releace　→ Run workflow　→ Run workflow
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2935918/cdb70ab7-d51e-4043-f88d-5d1f37ffa0cb.png)
- しばらく(数分間)待ってチェックマークになれば[^なれば成功]成功
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2935918/186b6a40-e12e-a4f5-d96e-a7f866c77b02.png)
[^なれば成功]:ならなかったらymlの編集を何かしら間違えていると思われるので、確認してみる


# 公開サイトの作成
:::note info
リリースしたものから最新版を自動的にダウンロードするリンクを作る手順です
:::
- [テンプレート](https://github.com/vrchat-community/template-package-listing)を開く
- ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2935918/e4dd7c27-09b0-1f6e-099e-cb0595641409.png)を押す
- 適当に名前をつけてCreate repositoryする(配布時この名前がみえます、これは大きなフォルダのような概念で、今後VPMを公開するときに使われます)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2935918/d6438547-100e-e161-2133-cbfd4a7bc7bb.png)
- Setting → Pages → BuildのSourceをGitHub Actionsに設定
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2935918/b3015398-1634-64fa-f2ed-efcb2bf83a38.png)
- Code → source.json
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2935918/ecf154c8-bd75-74d3-6d03-cc22e0ab2c68.png)
- 編集ボタンを押す
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2935918/5a656182-0a78-555d-7c1c-cd8594e7c707.png)

- 最低限次を設定する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2935918/007e519b-06b4-dbb9-10b7-10a31e0d82a6.png)

- Actionsを見ると作業している（source.jsonを更新すると自動で作業が開始される）ので緑チェックになるのを待つ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2935918/97af50c7-befa-f518-4812-e926b00cffc4.png)

- Settings → Pages → Visit site
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2935918/3882a8d3-4aa6-cb5b-9978-0ed6060cd76b.png)

- 公開サイト完成
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2935918/0300c2fc-4c09-fe86-885c-e657ecbd9ac4.png)

- このurlを公開することでVPMを公開することができる

# unitypackage化
:::note info
url公開でもVPMは公開できるが、同等の動きをするすごいunitypackageが簡単に作れるという手順です
:::
- [VPAI](https://github.com/anatawa12/VPMPackageAutoInstaller)を開く
- 下の方に移動してWeb toolを開く
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2935918/d2e537d0-2a49-21a2-ae46-648154849d74.png)
- 適切なjson url, インストールするpackage name, [バージョン](https://qiita.com/takayukioda/items/359ed79e881ea7578291)を入力する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2935918/df88a1c9-2831-f14f-eb34-d45dbba890c5.png)
- 左下の![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2935918/365c095a-6f28-7123-5ba8-16abbcf9a5d5.png)を押す。unitypackageがダウンロードされる
- このunitypackageを入れることでVCC/ALCOMからVPMを導入したのと同じ結果を得ることができるので、これをBooth等で配布する


# このあと
初回アップロードできましたが、更新の仕組みがまだできていません。[作りましょう](https://qiita.com/pandrabox/items/7d80c0a6d5663da58dc1)


# asmdef
[Editor,Runtimeそれぞれにasmdefというファイルを作る必要がある](https://scrapbox.io/suzuryg/VPM%E3%83%91%E3%83%83%E3%82%B1%E3%83%BC%E3%82%B8%E3%81%AE%E4%BD%9C%E6%88%90)らしい
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2935918/fb37ca69-9f46-5bf4-4f31-8c6d5d66ac40.png)