Unityでヒエラルキーのオブジェクト全てのActive状態を保存・再生するエディタ拡張

表題の通りです。

## 1. 概要

UnityのScene内に存在するすべてのGameObjectの表示状態（`activeSelf`）を保存し、あとから復元できる**エディタ拡張ツール**です。

- **SnapShotボタン**：現在の表示状態を保存  
- **Resumeボタン**：保存された状態を復元  
- Unityの再起動後は `instanceID` が無効になるため、**名前階層（path）で探索し復元**
(一度復元したあとは自動で `SnapShot` を再保存し、次回からは高速に復元可能)

---

## 2. スクリプト本体

`Assets/Editor/VisibilitySnapshot.cs` に以下のコードを配置してください：

```csharp:VisibilitySnapShot
using UnityEngine;
using UnityEditor;
using System.Collections.Generic;
using System.IO;


/// <summary>
/// Unityでヒエラルキーのオブジェクト全てのActive状態を保存・再生するエディタ拡張
/// </summary>
/// instanceIDが無くなった時だけパスでFindする。それ以外はinstanceIDで取得する。
public class VisibilitySnapshot : EditorWindow
{
    private const string FILE_PATH = "Library/VisibilitySnapshot.json";

    [System.Serializable]
    private class Entry
    {
        public int id;
        public string path;
        public bool active;
    }

    [System.Serializable]
    private class EntryList
    {
        public List<Entry> entries = new List<Entry>();
    }

    [MenuItem("Tools/Visibility Snapshot")]
    public static void ShowWindow()
    {
        GetWindow<VisibilitySnapshot>("Visibility Snapshot");
    }

    private void OnGUI()
    {
        if (GUILayout.Button("SnapShot (Save to File)"))
        {
            SaveSnapshotToFile();
        }

        if (GUILayout.Button("Resume (Load from File)"))
        {
            LoadSnapshotFromFile();
        }
    }

    private void SaveSnapshotToFile(bool _showMsg = true)
    {
        var list = new EntryList();
        foreach (GameObject root in GetAllRootGameObjectsInScene())
        {
            RecordRecursive(root, "", list.entries);
        }

        string json = JsonUtility.ToJson(list, true);
        File.WriteAllText(FILE_PATH, json);
        Debug.Log($"スナップショットを保存しました ({list.entries.Count}件): {FILE_PATH}");

        if (_showMsg)
        {
            EditorUtility.DisplayDialog("SnapShot完了", $"スナップショットを保存しました\n({list.entries.Count}件)", "OK");
        }
    }

    private void LoadSnapshotFromFile()
    {
        if (!File.Exists(FILE_PATH))
        {
            Debug.LogWarning("スナップショットファイルが見つかりません。");
            return;
        }

        string json = File.ReadAllText(FILE_PATH);
        var list = JsonUtility.FromJson<EntryList>(json);
        int changed = 0;

        bool foundPath = false;
        foreach (var entry in list.entries)
        {
            GameObject obj = EditorUtility.InstanceIDToObject(entry.id) as GameObject;

            if (obj == null)
            {
                // IDが無効なら、パスで探す
                obj = GameObject.Find(entry.path);
                foundPath = true;
            }

            if (obj != null && obj.activeSelf != entry.active)
            {
                obj.SetActive(entry.active);
                changed++;
            }
        }

        Debug.Log($"スナップショットを復元しました ({changed}件)");

        // 復元したオブジェクトの中に、パスで見つけたものがあった場合は、次の高速化のために再度保存しておく
        if (foundPath)
        {
            SaveSnapshotToFile(false); 
        }
    }

    private void RecordRecursive(GameObject obj, string parentPath, List<Entry> entries)
    {
        string path = string.IsNullOrEmpty(parentPath) ? obj.name : parentPath + "/" + obj.name;

        entries.Add(new Entry
        {
            id = obj.GetInstanceID(),
            path = path,
            active = obj.activeSelf
        });

        foreach (Transform child in obj.transform)
        {
            RecordRecursive(child.gameObject, path, entries);
        }
    }

    private GameObject[] GetAllRootGameObjectsInScene()
    {
        var scene = UnityEngine.SceneManagement.SceneManager.GetActiveScene();
        return scene.GetRootGameObjects();
    }
}

```

## 3. 導入手順
1.Unityエディタで Assets/Editor/ フォルダを作成（なければ）
2.下記スクリプトを作成：VisibilitySnapshot.cs

## 4. 使い方

### ① スナップショットの保存
Unity上部メニューから
　Tools > Visibility Snapshot をクリック

表示されたウィンドウで
「SnapShot (Save to File)」をクリック

現在のScene内にあるすべてのGameObjectの「表示状態（activeSelf）」を記録します。
◆保存先ファイル：/Library/VisibilitySnapshot.json に出力されます。


### ② スナップショットの復元
再び Tools > Visibility Snapshot ウィンドウを開く
「Resume (Load from File)」をクリック

保存時と同じScene内であれば、
　- InstanceIDベースで高速復元
　- 見つからない場合は GameObjectの名前階層（Root/Child/...）で復元
　　(その場合次の高速化に備えてSaveも行う)

Sceneを再起動してもファイルが残っていれば復元可能です。


## 5. メリットと注意点

- Unityセッション中は高速  
- 再起動後の初回復元は `GameObject.Find()` になるので少し遅い  
- ただし一度復元すれば、以後は再び `instanceID` を利用して高速化