UnityでMessagePack-CSharpのSourceGeneratorを使ってみる

## はじめに

今まで [MessagePack-CSharp](https://github.com/MessagePack-CSharp/MessagePack-CSharp) を IL2CPP 環境下で動かすには事前のコード生成が必要でなかなか面倒だったんですが、 v2.6.100 からは SourceGenerator に対応するため、コード生成用コマンドを打つ必要がなくなるようです。

## インストール

### ダウンロード
[Releases](https://github.com/MessagePack-CSharp/MessagePack-CSharp/releases) の v2.6.100 以降の最新版を探し、以下のファイルをダウンロードします。
* MessagePack.Unity.unitypackage
* MessagePack.SourceGenerator.Unity.zip

:::note warn
2024/1/20時点では v2.6.100 は正式リリースされていないようです。
:::

### 本体インストール
MessagePack.Unity.unitypackage を開き、Unity に取り込みます。
<details><summary>PackageManagerで管理したい場合</summary>

Plugins フォルダ内の dll だけを取り込み、 packages.json に以下を追記します。

```
"com.neuecc.messagepack": "https://github.com/neuecc/MessagePack-CSharp.git?path=src/MessagePack.UnityClient/Assets/Scripts/MessagePack#v2.6.100-alpha"
```
#以降に指定するバージョンは最新に合わせてください。
</details>

### SourceGenerator インストール

MessagePack.SourceGenerator.Unity.zip を解凍して出てきたすべての dll を Unity に取り込み、以下の設定を行います。
* すべてのプラットフォーム選択を外す ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/368570/d69039dd-2dc2-e0b5-e69b-ff3a1b531dde.png)
* `RoslynAnalyzer` ラベルを付与する ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/368570/1769b92f-e04f-342d-7c9a-8fb7c767c034.png)

### 初期化処理追加

生成された Resolver をデフォルトの呼び出し時に使用するように設定します。
※現時点では Resolver が生成されていないのでエラーが出ます。

```cs
using MessagePack;
using UnityEngine;

public static class Startup
{
#if UNITY_EDITOR
    [UnityEditor.InitializeOnLoadMethod]
#endif
    [RuntimeInitializeOnLoadMethod]
    private static void Initialize()
    {
        MessagePackSerializer.DefaultOptions = MessagePackSerializerOptions.Standard
            .WithResolver(GeneratedMessagePackResolver.InstanceWithStandardAotResolver);
    }
}
```

### 動作確認

以下のクラスを定義してみます。

```cs
using MessagePack;
using UnityEngine;

[MessagePackObject]
public class SampleObject
{
    [Key(0)] public string Name { get; set; }
    [Key(1)] public Vector3 Position { get; set; }
}
```

すると、 `MessagePack.GeneratedMessagePackResolver` クラスが自動生成されます。
なお、Rider を使っている場合、生成コードの中身を見ることもできます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/368570/e1efdd68-31ff-43f2-18a1-61563be4421f.png)

以下のコードで動作確認します。

```cs
using System;
using MessagePack;
using UnityEngine;
using UnityEngine.UI;

public class Test : MonoBehaviour
{
    [SerializeField] private Text text;

    private void Start()
    {
        try
        {
            var obj = new SampleObject
            {
                Name = "Sample",
                Position = new Vector3(1, 3, 5),
            };
        
            var serialized = MessagePackSerializer.Serialize(obj);
            text.text = "シリアライズされたデータ\n" + BitConverter.ToString(serialized);
        
            var deserialized = MessagePackSerializer.Deserialize<SampleObject>(serialized);
            text.text += "\n\nデシリアライズされたデータ\n" + deserialized.Name + deserialized.Position;
        }
        catch (Exception e)
        {
            text.text = e.ToString();
        }
    }
}

```

エディタ上ではIL生成が動いてテストにならないためIL2CPPでビルドして動作を確認すると、以下のように想定通りの出力が表示されました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/368570/cfd854a8-3d2c-603a-c239-0b5deadb712b.png)