Unity Editor を自動実行モジュールとして利用する

# 想定する対象
1. Unityで実装された機能を自動化に組み込まなければならないが、移植が面倒なのでUnityのまま使いたい
2. ランタイムでできない（ランタイムだと面倒な）機能を使いたい

私です。
指定のFBXを読み込みたかったんですが、Unityってランタイムでリソース読むの面倒なんですね……。
2に相当しないのであれば、ビルドした方が楽だと思います。
確認環境はWin10ですが、一部を各環境に置き換えれば同じ方法でできると思います。

※ Unity始めて1ヶ月経たないので、Unity分からん状態です。
※ 「間違ってるゾ」「こうした方がいいゾ」なことがあれば教えて頂けると嬉しいです。

# 手順概要
1. バッチからUnityEditorを起動する
2. 起動直後、自動でPlayModeへ移行する
3. 処理が終わったら自動でUnityEditorを終了する

なお、必然的にUnityEditorの画面が表示されます。
完全にバックグラウンドで行う方法については、分かりません。

# 手順1 バッチからUnityEditorを起動する
バッチといいましたが、あくまでコマンドの実行方法なので、任意のプログラムから実行可能でしょう。
Unityのコマンドライン引数は[ここ](https://docs.unity3d.com/ja/current/Manual/CommandLineArguments.html)にあります。必須なのはprojectPathくらいでしょう。
単純に起動する場合は、例えば次のコマンドとなります。

``` RunEditor.bat
rem "UnityEditorのパス" -projectPath "読み込みたいプロジェクトのパス"
"C:\Program Files\Unity\Editor\Unity.exe" -projectPath "D:\UnityProjects\RunAuto"
```

私の場合、動的なファイルロードが必要だったので、事前にResourceフォルダへファイルをコピー、終了時に削除するようにしました。

``` RunEditor.bat
set ResourceDirectoryPath=D:\UnityProjects\RunAuto\Assets\Resources
set ResourceFilePath=%ResourceDirectoryPath%\file.fbx
set ResourceSourceFilePath=D:\Hogehoge\filesource.fbx

rem make temporary files
copy "%ResourceSourceFilePath%" "%ResourceFilePath%"

rem Run UnityEditor
"C:\Program Files\Unity\Editor\Unity.exe" -projectPath "D:\UnityProjects\RunAuto"

rem delete temporary files
rem /Q %ResourceFilePath%
```

とりあえずこのファイルを実行して、UnityEditorが自動に起動してプロジェクトを読み込めば成功です。
実行時引数については後で読み込めるので、必要なものを追加するといいでしょう。

# 手順2 UnityEditor起動後、自動でPlayModeへ移行する
スクリプトを作成し、適当なGameObjectにアタッチします。
クラスに[ExecuteInEditMode]属性を付与することで、PlayMode移行前でもスクリプトが実行されます。

``` AutoRunner.cs
using UnityEngine;

[ExecuteInEditMode]
public class AutoRunner : MonoBehaviour
{
}
```

次に、PlayModeへ移行する処理を実行しますが、最初に一度だけ実行すればいいので、Awakeの中でいいでしょう。
EditorApplication.isPlayingをtrueにすることで、PlayModeへ移行します。

``` AutoRunner.cs
using UnityEditor;
using UnityEngine;

[ExecuteInEditMode]
public class AutoRunner : MonoBehaviour
{
    private void Awake()
    {
#if UNITY_EDITOR
        if (!EditorApplication.isPlaying) {
            EditorApplication.isPlaying = true;
        }
#endif
    }
}
```

スクリプトを保存し、UnityEditor起動時に自動でPlayModeへ移行すれば成功です。
ですがこのままだと、PlayModeから戻った時にまたAwakeが実行され、またPlayModeへ移行し、UnityEditorとして使うどころではなくなります。
実行時引数を参照し、特定の引数が指定された場合のみ自動で移行するようにするといいでしょう。

``` RunningParameters.cs
using System;

public class RunningParameters
{
    public bool autoRun
    { get; private set; } = false;
    public bool autoClose
    { get; private set; } = false;

    public void ReadParameter()
    {
        foreach (string arg in Environment.GetCommandLineArgs()) {
            switch (arg) {
                case "-autoRun":
                    autoRun = true;
                    break;
                case "-autoClose":
                    autoClose = true;
                    break;
            }
        }
    }
}
```

``` AutoRunner.cs
using UnityEditor;
using UnityEngine;

[ExecuteInEditMode]
public class AutoRunner : MonoBehaviour
{
    private void Awake()
    {
        instance = this;
        arguments.ReadParameter();

#if UNITY_EDITOR
        if (arguments.autoRun && (!EditorApplication.isPlaying)) {
            EditorApplication.isPlaying = true;
        }
#endif
    }

    public RunningParameters arguments
    { get; private set; } = new RunningParameters();
    public static AutoRunner instance
    { get; private set; } = null;
}
}

```

"autoRun"があれば自動起動し、"autoClose"があれば自動で終了するよう認識します。
また、他のスクリプトから実行時引数を参照することを想定し、AutoRunner自体のインスタンスを静的に保持します。
（もちろん、argumentsを静的変数プロパティとしてもいいです。）
改めて、UnityEditorをバッチなどで引数付きで起動した時に自動でPlayModeへ移行する、また、引数なしで実行した時にはPlayModeへ移行しないことを確認できたら成功です。

# 手順3 処理が終わったら自動でUnityEditorを終了する
UnityEditorをスクリプトから実行するには、EditorApplication.Exitを実行します。
以下は例です。

``` SomeTask.cs
using UnityEditor;
using UnityEngine;

public class SomeTask : MonoBehaviour
{
    private void Update()
    {
        // なんらかの処理

#if UNITY_EDITOR
        if (finishedAutoProcess && AutoRunner.instance.arguments.autoClose) {
            EditorApplication.Exit(0);
        }
#endif
    }

    public RunningParameters arguments
    { get; private set; } = new RunningParameters();
}
```

ここまでで、自動実行と自動終了が実装できました。
後は通常のUnityスクリプトで自動化したい処理を実装しましょう。