インディーズゲームを作った時に便利だったUnity拡張の紹介①　スプレのマスターデータ管理ツール

# 前書き
別名義で活動しているのでタイトルは伏せさせていただきますが、個人でインディーズゲームを作成しておりました
その際に作って便利だったUnityの拡張などの機能や仕組みの紹介をします
今回はスプレッドシートでのマスターデータ管理ツール編となります
基本的には生成物や生成前のデータ、最低限のロジックなどは説明しますがコードは記載しません
自身で作成する際のヒントになればと思います

## 概要

機能として下記の物を作成してました

- GASの機能
   - 翻訳リストの自動作成機能（GAS）
   - 自動翻訳機能（翻訳APIの呼び出し、リストに自動追加
- Unity 
  - カラムからコード自動生成機能
  - マスタで定義したEnumのリストの自動生成
  - 翻訳リストと各マスタの紐づけ、差し替え機能
  - Unityのみで完結するマスタデータのビルド機能
     - 完成後のデータはMessagePackになる（今後MasterMemoryに変えたい
  - 画面上に設定されているTextデータをスプレッドシートにアップロードする機能


## データのイメージと生成物

マスターデータのイメージ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/370747/c9a00a9e-d5b7-6c53-9343-1b578e2a5166.png)


Unity側のインターフェイス
![スクリーンショット 2024-03-27 082349.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/370747/67972bcc-fc64-06b0-56b6-3d11655945a4.png)


自動生成されるソースコード
``` C#
///Don't write
///This is Generated Code

using System;
using Cysharp.Threading.Tasks;
using MessagePack;
using System.IO;
using System.Collections.Generic;
using UnityEngine;
using System.Linq;


[MessagePackObject(keyAsPropertyName: true)]
public class MstTextObject
{
    public MstTextData[] datas;

    public MstTextObject()
    {
    }

    public MstTextObject(object[] ob)
    {
        List<MstTextData> list = new List<MstTextData>();

        foreach(var o in ob)
        {
            list.Add(o as MstTextData);
        }

        datas = list.ToArray();
    }
}

[MessagePackObject(keyAsPropertyName: true)]
public class MstTextData
{
    public string key;
    public string text => LoacalizationSupport.Get($@"翻訳リスト用のIDが入る");

}

public class MstText
{
    const string filename = "/Mst/MstText.dat";

    private MstTextData[] items { get; set; }

    public static MstTextData Get(string key)
    {
        return GameMst.Text.items.FirstOrDefault(m => m.key == key);
    }
    
    public static MstTextData[] GetAll()
    {
        return GameMst.Text.items;
    }
    
    private MstText(MstTextObject entity)
    {
        items = entity.datas;
    }

    public static async UniTask<MstText> Load(string filePath)
    {
        var path = filePath + filename;
        if (!File.Exists(path))
        {
            Debug.Log(path);
            return new MstText(new MstTextObject());
        }

        MstTextObject entity;
        using (var stream = new FileStream(path, FileMode.Open, FileAccess.Read))
        {
            entity = await MessagePackSerializer.DeserializeAsync<MstTextObject>(stream);
        }


        return new MstText(entity);
    }
    
    public static MstTextData[] ReadDataOnly(string filePath)
    {
        var path = filePath + filename;
        if (!File.Exists(path))
        {
            throw new Exception("File Not Found" + path);
        }

        MstTextObject entity;
        using (var stream = new FileStream(path, FileMode.Open, FileAccess.Read))
        {
            entity = MessagePackSerializer.Deserialize<MstTextObject>(stream);
        }
        
        return entity.datas;
    }
}

```

## ざっくりとした仕組み解説

### やってること

```mermaid
sequenceDiagram

participant gas as Gas
participant api as GoogleApi
participant csharp as CSharp

csharp ->> api : 接続
api ->> gas : 認証
csharp ->> api : データリクエスト
api ->> gas : データリクエスト
gas ->> api : data
api ->> csharp : 受け取り
csharp ->> csharp : 解析
csharp ->> csharp : カラム情報からcsファイル自動生成
csharp ->> csharp : messagePackのcsファイル生成
csharp ->> csharp : データの作成と挿入

```


### 実装ヒント
仕様技術
 - Gas
 - C#
 - Google.Apis
 - Google.Apis.Auth
 - Google.Apis.Sheets.v4
これだけあれば大体できます

↓ここの記事を読めば大体できると思われます

https://qiita.com/tat_tt/items/b9757cc940338c7deeab

あとはC#でゴリゴリに加工しています
ファイルの自動生成に関しては
基本的にはTemprate用のTextファイルを用意して、文字を置き換えるような形で対応してます


```mermaid
sequenceDiagram

participant temp as Template
participant gen as Generate
participant data as Data

data ->> data : Apiから取得したデータ
gen ->> data : dataの取得
gen ->> gen : Header部分の解析
gen ->> temp : テキストデータの読込み
gen ->> temp : テキストの特定のキーワードをdataから取得したカラム名などに置き換える
gen ->> temp : ファイル名を書き換えて別名で保存

```
自動生成の流れはこんな感じです


## ツールの使い方、拡張性の話
アプリケーションやスプレッドシートIDで分けられるため、体験版用、ベータ版、製品版、DLC版などでスプレッドシートを分けて開発したりしてました

また、こちらの機能をもとに業務用で開発した際は、グーグルドライブのフォルダ単位で同じことできるようにしてました
具体的には、GASでフォルダ内のスプレIDを全取得->スプレに記載->Unityで↑のツールと同じ要領でマスタを作る
といった感じで作成したことがあります

また、解析自体はCSVデータを解析しているよなものなので、どの言語でもできますし、ジェンキンスへの移行なども用意にできます


## 余談
8割はC#で作成されているので、Godotエンジンに移行してもほぼ動きました
この経験からツールを作る際は極力Engineではなく言語寄りに機能を作成したほうが良いなと思いました