【Unity】UnityがHeadlessモードで起動しているか確認する方法【UNET】

# はじめに
UNET使ってて専用サーバとしてビルドしたときはHeadlessモードで実行/ビルドするのが良いらしいのですが、いざやってみると[`NetworkManager.StartServer()`](https://docs.unity3d.com/ja/current/ScriptReference/Networking.NetworkManager.StartServer.html)を呼び出すボタンをクリックできない→専用サーバとして起動できないことに気づきました（そもそもUI表示しないモードだって話）。

調べたところランタイムでHeadlessモードかどうかを知るためのAPIはなく、自分でゴニョゴニョして判断する必要がありました。

# Headlessモードとは
[Unity スタンドアロンプレイヤーのコマンドライン引数](https://docs.unity3d.com/ja/540/Manual/CommandLineArguments.html)（公式のマニュアル）から引用。
> ゲームは何も表示せず、ユーザー入力を受付しません。これはネットワークゲーム でのサーバー実行に最も便利です。

## Headlessモードで起動する
ビルドしたアプリ起動時にコマンドライン引数「-batchmode」をつけるとHeadlessモードになります。

Macだと `$ open (アプリ名).app --args -batchmode` で起動。

## Headlessモードでビルドする
「Build Settings」で Target Platform を「Linux」にしてから「Development Build」のチェックを外して「Headless Mode」のチェックボックスにチェックを入れてビルド。

![公式マニュアルのBuildSettings](https://docs.unity3d.com/ja/540/uploads/Main/BuildSettings.png)
（[公式マニュアル](https://docs.unity3d.com/ja/540/Manual/BuildSettings.html)のスクショ）

Target Platform を「Linux」にしないとそもそもチェックボックスが表示されず、「Development Build」にチェックが入っていると「Headless Mode」のチェックボックスにチェックできないので注意。

### エディタAPIでビルドオプションのHeadlessモードを`true`にする
[`EditorUserBuildSettings.enableHeadlessMode`](https://docs.unity3d.com/ScriptReference/EditorUserBuildSettings-enableHeadlessMode.html)というAPIがあります。UnityCloudBuildを使ってる場合はこのAPIを使うみたいです。

参考：[How to enable headless mode on Unity Could Build?](https://forum.unity3d.com/threads/how-to-enable-headless-mode-on-unity-could-build.391136/)

# 確認方法
２パターンあるみたいです。

<font color="red">2019/9/13追記</font>
ドキュメントをたどった限りではUnity2018.2からバッチモードかどうか判断するためのAPIが追加されたみたいなので、そちらを使うと良さそうです。
[Application.isBatchMode](https://docs.unity3d.com/2018.2/Documentation/ScriptReference/Application-isBatchMode.html)（公式ドキュメント）
<font color="red">追記ここまで</font>

## `SystemInfo.graphicsDeviceType`で判断する
[Detect Headless Mode in Unity](https://noobtuts.com/unity/detect-headless-mode) から引用

>
```csharp
using UnityEngine.Rendering;
>
// detect headless mode (which has graphicsDeviceType Null)
bool IsHeadless() {
    return SystemInfo.graphicsDeviceType == GraphicsDeviceType.Null;
}
```

## `SystemInfo.graphicsDeviceID`で判断する
[Determine if Unity is running in batch mode/headless mode](https://forum.unity3d.com/threads/determine-if-unity-is-running-in-batch-mode-headless-mode.85571/) から引用

>
Checking SystemInfo.graphicsDeviceID == 0 works. 

「へ〜」と思ってiOS用にビルドしたら`true`を返しました。／(^o^)＼ Windowsだとうまく動くのかな。こっちの方法はおすすめしません。

# Macのスタンドアロンだと別な方法が必要
「なるほどな〜」と思ってMacのスタンドアロンでビルドしたら`-batchmode`の引数つけてもなぜか先述の値がどっちも変化しなかったので、単純にコマンドライン引数で判断するのが良さそうでした（参考：[Read Command Line Arguments](http://answers.unity3d.com/questions/138715/read-command-line-arguments.html)）。

```csharp
return System.Environment.GetCommandLineArgs().Any(arg => arg == "-batchmode");
```

ちなみに`-batchmode`で起動してみて`SystemInfo`の値を全部調べたら`SystemInfo.graphicsMultiThreaded`だけ`true`だったのが`false`になりました。でもこの値で判断するのは流石にちょっと。。。

# まとめ
以下のコードで判断するのがいいと思われます。

```csharp
public bool isHeadlessMode
{
    if (Application.isMobilePlatform)
    {
        return false;
    }
#if UNITY_STANDALONE_OSX
    return System.Environment.GetCommandLineArgs().Any(arg => arg == "-batchmode");
#else
    return SystemInfo.graphicsDeviceType == GraphicsDeviceType.Null;
#endif
}
```

# 関連
* [UNETのNetworkBehaviourクラスのコールバックとコンテキストフラグの罠](http://qiita.com/su10/items/f5b017e0990593cfa0ae)
* [UNETを捨ててPhotonを使おうと思った理由](http://qiita.com/su10/items/13f4b82bd55b5a81b205)