VPM開発: 基礎のNDMFを実装

[これ](https://qiita.com/pandrabox/items/7d80c0a6d5663da58dc1)のつづき

VPM開発する環境ができたのでNDMFを実装してみよう

基本的に普通のAssets開発と変わりませんが、最初だけasmdefというファイルの定義が必要です

# 空のRuntimeの実装
- Packages/現在開発中のVPM名フォルダ直下にRuntimeフォルダを作る
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2935918/8c8f095b-4b54-4bf8-3cc0-e2f2d7bffe53.png)

- Projectビューを右クリックして　Assembly Definitionを作成
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2935918/43c4e542-8fb5-95e8-fd82-ce95b40f8564.png)

- 名称をVPMの逆ドメイン名.runtimeにする。ここでは「com.github.pandrabox.emoteprefab.runtime」
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2935918/880ee2b3-045c-9bfb-d641-b5f3d2fbf6c6.png)

- ダブルクリックで開き、次を参考に設定（これはMAを参考に設定した）　[asmdef公式情報](https://docs.unity3d.com/ja/2022.1/Manual/AssemblyDefinitionFileFormat.html)
```asmdef
{
    "name": "com.github.pandrabox.emoteprefab.runtime",
    "references": [
        "nadena.dev.ndmf.runtime"
    ],
    "includePlatforms": [],
    "excludePlatforms": [],
    "allowUnsafeCode": true,
    "overrideReferences": true,
    "precompiledReferences": [
        "VRCSDKBase.dll",
        "VRCSDK3A.dll",
        "VRC.Dynamics.dll",
        "VRC.SDK3.Dynamics.Contact.dll",
        "VRC.SDK3.Dynamics.PhysBone.dll",
        "System.Collections.Immutable.dll"
    ],
    "autoReferenced": true,
    "defineConstraints": [],
    "versionDefines": [],
    "noEngineReferences": false
}
```
- ProjectビューでC# Scriptを作成
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2935918/f5a0b949-19b3-6415-b091-6f3bbdbea677.png)

- 名称をMyTestにする（他の名前でも良いが、覚えておく）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2935918/b0570b6e-f155-6f93-4432-0f30eb18ade6.png)

- ダブルクリックして、下を参考にコードを作成
```MyTest.cs
using UnityEngine;

namespace com.github.pandrabox.emoteprefab.runtime
{
    [AddComponentMenu("Pan/MyTest")]
    public class MyTest : MonoBehaviour, VRC.SDKBase.IEditorOnly
    {
    }
}
```
- この時点でソリューション　エクスプローラーを見ると、恐らくasmdefに設定したプロジェクトが作成されているはず。出来ていなかったら色々トラブルシュートが必要（ここでは扱わない）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2935918/be2ea847-6bd1-e8aa-6dda-35bb6a7c57dd.png)

- HierarchyにGameObjectを作成し、今作ったものをAdd Componentできることを確認
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2935918/7a02d07d-6455-cd48-7896-472f42c8d0c5.png)

# VPMの更新をしてテスト環境で確認
- この程度別にいいやと思ったら飛ばして下さい
- package.jsonのバージョンを上げる
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2935918/32edc8ce-fa6b-cdb5-d1d8-3ed62b5b5516.png)
- Github desktopでCommit→Push
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2935918/ea155317-1c77-5c38-a5cd-b29455940715.png)
- 適当な別プロジェクトで開発しているVPMを使用設定しておく（下は既にしてあったので今あげたバージョンになった）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2935918/162a9efa-117a-103c-4494-834dded19fa6.png)
- さっき作ったRuntimeが動いている。OK。これは閉じてPackage開発用のUnityに戻る
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2935918/f10d04d7-c1bf-c9dd-886c-5a30514be6b9.png)


# Editorの開発
- Runtime同様にフォルダ、asmdefを作成する。今度の内容は次を参考に
```asmdef
{
    "name": "com.github.pandrabox.emoteprefab.editor",
    "references": [
        "nadena.dev.modular-avatar.core",
        "nadena.dev.modular_avatar.core.editor",
        "VRC.SDK3A",
        "VRC.SDKBase",
        "nadena.dev.ndmf",
        "nadena.dev.ndmf.vrchat",
        "VRC.SDK3A.Editor",
        "com.github.pandrabox.emoteprefab.runtime"
    ],
    "includePlatforms": [
        "Editor"
    ],
    "excludePlatforms": [],
    "allowUnsafeCode": false,
    "overrideReferences": true,
    "precompiledReferences": [
        "Newtonsoft.Json.dll",
        "System.Collections.Immutable.dll",
        "VRCSDKBase.dll",
        "VRCSDKBase-Editor.dll",
        "VRCSDK3A.dll",
        "VRCSDK3A-Editor.dll",
        "VRC.Dynamics.dll",
        "VRC.SDK3.Dynamics.Contact.dll",
        "VRC.SDK3.Dynamics.Contact.Editor.dll",
        "VRC.SDK3.Dynamics.PhysBone.dll",
        "VRC.SDK3.Dynamics.PhysBone.Editor.dll",
        "VRCCore-Editor.dll"
    ],
    "autoReferenced": false,
    "defineConstraints": [],
    "versionDefines": [],
    "noEngineReferences": false
}
```
- C#を作って、開く。プロジェクトが作られていることを確認
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2935918/d22298b3-5f8c-6fd4-6404-52a9e9bc124a.png)


- 適当にEditorを書く
```MyTest.cs
using System;
using System.Linq;
using System.Collections.Generic;
using nadena.dev.ndmf;
using nadena.dev.modular_avatar.core;
using nadena.dev.modular_avatar.core.editor;
using UnityEngine;
using UnityEditor;
using UnityEditor.Animations;
using VRC.SDK3.Avatars.Components;
using com.github.pandrabox.emoteprefab.runtime;
using com.github.pandrabox.emoteprefab.editor;

[assembly: ExportsPlugin(typeof(MyTestPass))]

namespace com.github.pandrabox.emoteprefab.editor
{
    /// <summary>
    /// To call from Unity menu (Debug Only, Comment out upon release.)
    /// </summary>
    public class MyTestUnityMenu : MonoBehaviour
    {
        [MenuItem("PanDev/MyTest")]
        static void GenMyTest()
        {
            new MyTestMain().Run(Selection.activeGameObject);
        }
    }
    /// <summary>
    /// To call from NDMF
    /// </summary>
    public class MyTestPass : Plugin<MyTestPass>
    {
        protected override void Configure()
        {
            try
            {
                InPhase(BuildPhase.Transforming).BeforePlugin("nadena.dev.modular-avatar").Run("PanMyTest", ctx =>
                {
                    var TargetComponents = ctx.AvatarRootTransform.GetComponentsInChildren<MyTest>(false);
                    foreach (var T in TargetComponents)
                    {
                        new MyTestMain().Run(T.gameObject);
                    }
                });
            }
            catch (Exception e)
            {
                Debug.LogError($@"[Pan:MyTest]{e}");
            }
        }
    }
    /// <summary>
    /// Actual operation
    /// Retrieving ctx is not recommended to maintain debug availability.
    /// </summary>
    public class MyTestMain : MonoBehaviour
    {
        public void Run(GameObject Target)
        {
            Target.SetActive(false);
            Debug.LogWarning($@"MyTest:{Target.name}");
        }
    }
}

```

- 動作チェックする
    - 上のコードのままなら
        - Hierarchyで何かをアクティブにして上部メニューPanDev→MyTestを実行するとそのオブジェクトが非表示になる
        - アバター内のなにかにMyTestをAdd ComponentしてAv3有効でPlayにする等するとそのオブジェクトが非表示になる
        
- Commit,Push
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2935918/fd69a607-3976-e6d0-7570-1cb1f3268dd5.png)

- 適当な他のプロジェクトで動作確認(2019で開発して2022で確認が最も有意義そう)