[Unity]BatchModeでHelloWorld


## 本記事について

備忘録。
目的はビルドで、テスト用のスクリプトは関数名と中身が全然一致しないが、
そこはテストごとにコマンド変えるのが手間というだけなのでご容赦ください。

## 前提
黒い画面叩ける。
Makefileの使い方がわかること。

## 環境
UnityHub
Unity 2021.3
Mac
Makefile (ビルドをMakefile使って叩きたかったので)

## やりたいこと
コマンドでstaticなメソッドを呼ぶ
ログを標準出力に出す
引数わたす

## vesion出してみる

https://docs.unity3d.com/ja/current/Manual/EditorCommandLineArguments.html

> macOS で Unity を起動するには、以下をターミナルに入力します。
>
> /Applications/Unity/Unity.app/Contents/MacOS/Unity

とのことですが、UnityHub使っていればパスは違う。

![スクリーンショット_2022-04-24_16_48_03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/113504/76734267-3371-9a10-0741-5cc6e9fc62f3.png)

ここに書いてあるやつの後に/Contents/MacOS/Unityってつける

これを使ってまずはversion出力する。

マニュアルより

> -version
> 	Print the version number of the Unity Editor in the command line, without launching the Editor.


```Makefile
UNITY_PATH := /Applications/Unity/Hub/Editor/2021.3.0f1/Unity.app/Contents/MacOS/Unity

.PHONY: unity-build-ios
unity-build-ios:
	$(UNITY_PATH) -version
```

```
$ make unity-build-ios
/Applications/Unity/Hub/Editor/2021.3.0f1/Unity.app/Contents/MacOS/Unity -version
2021.3.0f1
```

アプリのパスはあってるってことはわかった。

## Hello Worldする

以下のようなテスト用のスクリプトを作る
Assets > Editor > Scripts > ProjectBuilder.cs

```.cs
public class ProjectBuilder
{   
...
    public static void BatchBuildiOS()
    {
        UnityEngine.Debug.Log("Hello World!");
    }
```

以下で実行

```Makefile
.PHONY: unity-build-ios
unity-build-ios:
	$(UNITY_PATH) -batchmode -quit -projectPath . -logFile - \
	-executeMethod ProjectBuilder.BatchBuildiOS
```

```
EiscueClient(main)$ make unity-build-ios
/Applications/Unity/Hub/Editor/2021.3.0f1/Unity.app/Contents/MacOS/Unity -batchmode -quit -projectPath . -logFile - \
        -executeMethod ProjectBuilder.BatchBuildiOS
Unity Editor version:    2021.3.0f1 (6eacc8284459)
たくさんログ...
Hello World!
...
Exiting batchmode successfully now!
```

となって成功。

■ポイント
-logfile - とつけないとDebug.Logの内容が標準出力に出ない。

> Specify where Unity writes the Editor or Windows/Linux/OSX standalone log file. To output to the console, specify - for the path name. On Windows, specify the - option to direct the output to stdout, which by default is not the console.

すでにUnityでプロジェクト開いていると以下のようなエラー

```
Aborting batchmode due to fatal error:
It looks like another Unity instance is running with this project open.

Multiple Unity instances cannot open the same project.
```

## 引数を渡す

executeMethodの説明には

> To pass parameters, add them to the command line and retrieve them inside the function using System.Environment.GetCommandLineArgs. To use -executeMethod, you need to place the enclosing script in an Editor folder. The method you execute must be defined as static.

とある。

```.cs
public static string[] GetCommandLineArgs ();
```

[System.Environment.GetCommandLineArgs](https://docs.microsoft.com/ja-jp/dotnet/api/system.environment.getcommandlineargs?view=net-6.0)

> 戻り値
> 各要素にコマンド ライン引数を格納している文字列の配列。 先頭の要素には実行可能ファイルの名前、それに続く 0 個以上の要素には残りのコマンド ライン引数が格納されます。

### 失敗

```.cs
    // Args[0] Hello XXXX
    // Args[1] Hello! XXXX
    public static void BatchBuildiOS()
    {
        var args = System.Environment.GetCommandLineArgs();
        UnityEngine.Debug.Log("Hello " + args[0]);
        UnityEngine.Debug.Log("Hello! " + args[1]);
    }
```

```Makefile
.PHONY: unity-build-ios
unity-build-ios:
	$(UNITY_PATH) -batchmode -quit -projectPath . -logFile - \
	-executeMethod ProjectBuilder.BatchBuildiOS ABC DEF
```

Hello ABC
Hello! DEF

を期待していた。

が、こうなった

```
Hello /Applications/Unity/Hub/Editor/2021.3.0f1/Unity.app/Contents/MacOS/Unity
...
(Filename: Assets/Editor/Scripts/ProjectBuilder.cs Line: 25)

Hello! -batchmode
...
```

なるほどね。

ということで
```
-オプション名1 内容 1
```
っていう渡し方に変更する

## 成功

コマンドラインの引数を辞書で取ってこれるようにする

GetParametersFromCommandLineArgsというメソッドを同クラスに作成

```.cs
    static Dictionary<string, string> GetParametersFromCommandLineArgs(string[] args)
    {
        var parameters = new Dictionary<string, string>();
        for (int i = 0; i < args.Length; i++)
        {
            var arg = args[i];
            if (arg[0] == '-')
            {
                var key = arg.Substring(1);
                parameters[key] = args[i + 1];
            }
        }
        return parameters;
    }

    [MenuItem("Test/GetParametersFromCommandLineArgs")]
    static void TestGetParametersFromCommandLineArgs()
    {
        var args = new string[]{ "SomeApp", "-arg1", "ABC", "-arg2", "DEF" };
        var parameters = GetParametersFromCommandLineArgs(args);
        UnityEngine.Debug.Assert(parameters["arg1"] == "ABC");
        UnityEngine.Debug.Assert(parameters["arg2"] == "DEF");
        UnityEngine.Debug.Log("finished");
    }

```
この内容だと引数のないオプションが最後に来たりするとバグるなど問題はあるが、運用でカバーできるのでここでは気にしない。

これを使って以下のように書いた

```.cs
    // -firstArg Hello XXX
    // -secondArg Hello! XXX
    public static void BatchBuildiOS()
    {
        var parameters = GetParametersFromCommandLineArgs(System.Environment.GetCommandLineArgs());

        UnityEngine.Debug.Log("Hello " + parameters["firstArg"]);
        UnityEngine.Debug.Log("Hello! " + parameters["secondArg"]);
    }
```

```Makefile
.PHONY: unity-build-ios
unity-build-ios:
	$(UNITY_PATH) -batchmode -quit -projectPath . -logFile - \
	-executeMethod ProjectBuilder.BatchBuildiOS \
	-firstArg ABC \
	-secondArg DEF
```


結果
```
Hello ABC
...
(Filename: Assets/Editor/Scripts/ProjectBuilder.cs Line: 59)

Hello! DEF
...
ProjectBuilder:BatchBuildiOS () (at Assets/Editor/Scripts/ProjectBuilder.cs:60)
```

OK!





## 参考
Unity CLIの使い方
https://zenn.dev/mattak/articles/5dfa1a2369ebc0