よく使うシーンなどを登録して便利に…

#はじめに
Unityで作業をしていると、シーンやフォルダを探すことがよくあります。
今回は自分が昔作った**お気に入り機能**をちょっと見栄えを整えて紹介します。
まあ **Two Column Layout** を使ってる方は標準のFavorites機能を使えば全て解決なんですが…

#使い方
・メニューのWindow/Favoriteでウィンドウを開きます。
・お気に入り登録したいものをDrag&Dropします。
・```登録名```：選択、```開く```：シーンを開く、```Show```：フォルダを開く、```除外```：登録を外す
　という感じで使用します。
![2020-11-24_10h56_08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/837803/5c26737f-da6a-0953-0e1e-beb06e587972.png)

#動作環境
動作を確認した環境です。
・Unity2017.4.24f1
・Unity2019.4.12f1
・Windows10

#コード
以下のスクリプトをEditorフォルダに入れて使用します。

```csharp:FavoriteWindow.cs  
﻿using UnityEngine;
using UnityEditor;
using UnityEditor.SceneManagement;
using System.Collections.Generic;
using System.Linq;
using System.IO;

public class FavoriteWindow : EditorWindow
{
	Vector2 scrollPos = Vector2.zero;
	const string saveFile = "/Workspace/JumpFavorite.txt";
	HashSet<string> hashGuid = null;

	// お気に入り選択
	[MenuItem("Window/Favorite")]
	static void ShowWindow()
	{
		var win = GetWindow<FavoriteWindow>();
		// お気に入りのBuilt-in Icon取得して設定
		var fav = EditorGUIUtility.IconContent("Favorite Icon");
		fav.text = "Favorite";
		win.titleContent = fav;
	}
	void OnGUI()
	{
		// NULLだったら読み込み
		if(null == hashGuid)
			LoadFavoriteGuid();

		GUILayout.Space(5);
		Object obj = null;
		obj = EditorGUILayout.ObjectField("お気に入り登録", obj, typeof(Object), false);
		if(null != obj) {
			// お気に入りを登録
			var path = AssetDatabase.GetAssetPath(obj);
			var guid = AssetDatabase.AssetPathToGUID(path);
			hashGuid.Add(guid);
			// 保存
			SaveFavoriteGuid();
			return;
		}

		if(0 == hashGuid.Count)
			return;

		using(var scroll = new GUILayout.ScrollViewScope(scrollPos)) {
			scrollPos = scroll.scrollPosition;
			string remove = "";
			foreach(var n in hashGuid) {
				using(new EditorGUILayout.HorizontalScope()) {
					var path = AssetDatabase.GUIDToAssetPath(n);
					var name = Path.GetFileNameWithoutExtension(path);
					var ext = Path.GetExtension(path);
					// 選択
					var icon = AssetDatabase.GetCachedIcon(path);
					GUILayout.Label(icon, GUILayout.Height(20), GUILayout.Width(20));
					if(GUILayout.Button(name, GUILayout.Width(200)))
					{
						if (!string.IsNullOrEmpty(n))
							Selection.activeObject = AssetDatabase.LoadAssetAtPath(AssetDatabase.GUIDToAssetPath(n), typeof(Object));
						break;
					}
					// 開く（シーンなら）
					using(new EditorGUI.DisabledGroupScope(ext != ".unity"))
					{
						if(GUILayout.Button("開く", GUILayout.Width(40))) {
							if(EditorSceneManager.SaveCurrentModifiedScenesIfUserWantsTo())
								EditorSceneManager.OpenScene(path);
							break;
						}
					}
					// Show in Explore
					if(GUILayout.Button("Show", GUILayout.Width(50))) {
						if(Directory.Exists(path)) {
							var fullPath = Application.dataPath + "/../" + path;
							System.Diagnostics.Process.Start(fullPath);
						}
						else
							EditorUtility.RevealInFinder(path);
						break;
					}
					// 除外
					if(GUILayout.Button("除外", GUILayout.Width(40))) {
						remove = n;
						break;
					}
				}
			}
			if(!string.IsNullOrEmpty(remove))
			{
				// 除外
				hashGuid.Remove(remove);
				// 保存
				SaveFavoriteGuid();
			}
		}
	}

	void SaveFavoriteGuid()
	{
		string path = Application.dataPath + saveFile;
		string dir = Path.GetDirectoryName(path);
		// フォルダがなかったら作る
		if(!Directory.Exists(dir))
			Directory.CreateDirectory(dir);
		// 保存
		string[] arrGuid = hashGuid.ToArray();
		var str = string.Join("\n", arrGuid);
		File.WriteAllText(path, str);
		AssetDatabase.Refresh();
	}
	void LoadFavoriteGuid()
	{
		hashGuid = new HashSet<string>();
		string path = Application.dataPath + saveFile;
		if(!File.Exists(path))
			return;

		var str = File.ReadAllText(path);
		var arrGuid = str.Split("\n"[0]);
		// 無かったら無視
		foreach(var n in arrGuid) {
			if("" != AssetDatabase.GUIDToAssetPath(n))
				hashGuid.Add(n);
		}
	}
}

```

#解説
注意が必要なのは、**OpenScene**を使用すると現在編集中のシーンが破棄されてしまうので`EditorSceneManager.SaveCurrentModifiedScenesIfUserWantsTo`で編集中のシーンを保存するかの確認をとった方がいいです。

あと、`EditorUtility.RevealInFinder`でフォルダを開く場合、ファイルを指定していればそのフォルダを開いてくれますが、フォルダを指定していると親フォルダが開かれます。
なので、`Process.Start`を使用してフォルダは開いています。

管理はGuidをHashSetで行ってるだけなので並び順は気にしてません。まあ、並び替えが必要なほど登録する時点でもはやこの機能を使う意味がないと思いますが…

#おわりに
すでに便利なアセットや似たようなことをやってる方たちがいるので今更感がありますが
自分の好みな感じに仕上がっています。
もし好みに合えば使っていただければと思います。