### Changed - Scene groups to contain three different types of behaviours for grouping: - Load As Group: Groups all scenes into a single entry - Sort As Group: Sorts all scenes into entries close to each other in the dropdown - Sort In Submenu As Group: Sorts all scenes into entries in a submenu ### Removed - Removed "Scene sorting by Asset label" groups
410 lines
14 KiB
C#
410 lines
14 KiB
C#
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using UnityEditor;
|
|
using UnityEngine;
|
|
using UnityEngine.SceneManagement;
|
|
|
|
namespace Module.NavigationTool.Editor.Toolbar
|
|
{
|
|
internal sealed class ScenePickerList
|
|
{
|
|
public GUIContent[] labels = new GUIContent[0];
|
|
public readonly List<SceneElement> scenes = new List<SceneElement>();
|
|
public readonly List<int> selected = new List<int>();
|
|
|
|
public void Refresh()
|
|
{
|
|
scenes.Clear();
|
|
selected.Clear();
|
|
|
|
var projectSettings = new ToolbarProjectSettings();
|
|
projectSettings.Load();
|
|
var settings = projectSettings.GetValueAs<ToolbarScenePickerProjectSettings.Settings>();
|
|
|
|
List<WorkingSetScene> assets = GetWorkingSet();
|
|
FetchAllScenesFromBuildSettings(assets);
|
|
FetchAllScenesFromSceneGroups(assets, settings.sceneGroups);
|
|
FetchAllRemainingScenes(assets);
|
|
|
|
FetchAllLabels();
|
|
FetchAllSelectedIndices();
|
|
}
|
|
|
|
private void FetchAllScenesFromBuildSettings(List<WorkingSetScene> assets)
|
|
{
|
|
for (var i = 0; i < assets.Count; i++)
|
|
{
|
|
WorkingSetScene asset = assets[i];
|
|
|
|
if (!asset.inBuildSettings)
|
|
continue;
|
|
|
|
scenes.Add(new SceneElement
|
|
{
|
|
name = asset.name,
|
|
shortname = asset.shortname,
|
|
paths = { asset.path }
|
|
});
|
|
}
|
|
}
|
|
|
|
private void FetchAllScenesFromSceneGroups(List<WorkingSetScene> assets, SceneGroupArray sceneGroups)
|
|
{
|
|
for (var i = 0; i < sceneGroups.Count; i++)
|
|
{
|
|
SceneGroup sceneGroup = sceneGroups[i];
|
|
string name = sceneGroup.name;
|
|
List<WorkingSetScene> filteredScenes;
|
|
|
|
if (sceneGroup.filterType == ESceneGroupFilterType.AssetLabels)
|
|
{
|
|
filteredScenes = GetAllWorkingSetScenesWithLabels(assets, sceneGroup.filters);
|
|
}
|
|
else if (sceneGroup.filterType == ESceneGroupFilterType.NameContains)
|
|
{
|
|
filteredScenes = GetAllWorkingSetScenesWithNameContaining(assets, sceneGroup.filters);
|
|
}
|
|
else
|
|
{
|
|
filteredScenes = GetAllWorkingSetScenesWithPathContaining(assets, sceneGroup.filters);
|
|
name = sceneGroup.name.Replace("/", "\\");
|
|
}
|
|
|
|
if (sceneGroup.behaviourType == ESceneGroupBehaviourType.LoadAsGroup)
|
|
{
|
|
if (sceneGroups.Count != 0)
|
|
scenes.Add(new SceneElement{ includeAsSelectable = false });
|
|
|
|
if (!string.IsNullOrEmpty(sceneGroup.optionalMainScenePath))
|
|
SetWorkingSceneAsFirst(filteredScenes, sceneGroup.optionalMainScenePath);
|
|
|
|
filteredScenes = FilterToUniques(filteredScenes);
|
|
|
|
var scene = new SceneElement
|
|
{
|
|
name = name,
|
|
shortname = name,
|
|
isGroup = true
|
|
};
|
|
|
|
for (var j = 0; j < filteredScenes.Count; j++)
|
|
{
|
|
scene.paths.Add(filteredScenes[j].path);
|
|
}
|
|
|
|
scene.name += $" ({scene.paths.Count})";
|
|
scenes.Add(scene);
|
|
}
|
|
else if (sceneGroup.behaviourType == ESceneGroupBehaviourType.SortAsGroup)
|
|
{
|
|
filteredScenes = FilterToUniques(filteredScenes);
|
|
filteredScenes = FilterAllExcept(filteredScenes, scenes);
|
|
|
|
if (filteredScenes.Count != 0)
|
|
scenes.Add(new SceneElement{ includeAsSelectable = false });
|
|
|
|
for (var j = 0; j < filteredScenes.Count; j++)
|
|
{
|
|
scenes.Add(new SceneElement
|
|
{
|
|
name = filteredScenes[j].name,
|
|
shortname = filteredScenes[j].shortname,
|
|
paths = { filteredScenes[j].path }
|
|
});
|
|
}
|
|
}
|
|
else if (sceneGroup.behaviourType == ESceneGroupBehaviourType.SortInSubmenuAsGroup)
|
|
{
|
|
if (string.IsNullOrEmpty(sceneGroup.subMenuPath))
|
|
continue;
|
|
|
|
filteredScenes = FilterToUniques(filteredScenes);
|
|
filteredScenes = FilterAllExcept(filteredScenes, scenes);
|
|
|
|
if (filteredScenes.Count != 0)
|
|
scenes.Add(new SceneElement{ includeAsSelectable = false });
|
|
|
|
for (var j = 0; j < filteredScenes.Count; j++)
|
|
{
|
|
scenes.Add(new SceneElement
|
|
{
|
|
name = $"{sceneGroup.subMenuPath}/{filteredScenes[j].name}",
|
|
shortname = filteredScenes[j].shortname,
|
|
paths = { filteredScenes[j].path }
|
|
});
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private void FetchAllRemainingScenes(List<WorkingSetScene> assets)
|
|
{
|
|
List<WorkingSetScene> filteredScenes = FilterAllExcept(assets, scenes);
|
|
|
|
if (filteredScenes.Count != 0)
|
|
scenes.Add(new SceneElement{ includeAsSelectable = false });
|
|
|
|
for (var i = 0; i < filteredScenes.Count; i++)
|
|
{
|
|
scenes.Add(new SceneElement
|
|
{
|
|
name = filteredScenes[i].name,
|
|
shortname = filteredScenes[i].shortname,
|
|
paths = { filteredScenes[i].path }
|
|
});
|
|
}
|
|
}
|
|
|
|
private static List<WorkingSetScene> FilterToUniques(List<WorkingSetScene> list)
|
|
{
|
|
var uniques = new List<WorkingSetScene>(list.Count);
|
|
|
|
for (var i = 0; i < list.Count; i++)
|
|
{
|
|
if (!uniques.Contains(list[i]))
|
|
uniques.Add(list[i]);
|
|
}
|
|
|
|
return uniques;
|
|
}
|
|
|
|
private static List<WorkingSetScene> FilterAllExcept(List<WorkingSetScene> list, List<SceneElement> except, bool includeGroups = false)
|
|
{
|
|
var filtered = new List<WorkingSetScene>(list.Count);
|
|
|
|
for (var i = 0; i < list.Count; i++)
|
|
{
|
|
var contains = false;
|
|
|
|
for (var j = 0; j < except.Count; j++)
|
|
{
|
|
if (except[j].isGroup && !includeGroups)
|
|
continue;
|
|
if (!except[j].paths.Contains(list[i].path))
|
|
continue;
|
|
|
|
contains = true;
|
|
break;
|
|
}
|
|
|
|
if (!contains)
|
|
filtered.Add(list[i]);
|
|
}
|
|
|
|
return filtered;
|
|
}
|
|
|
|
private void FetchAllLabels()
|
|
{
|
|
labels = new GUIContent[scenes.Count];
|
|
|
|
for (var i = 0; i < scenes.Count; i++)
|
|
{
|
|
labels[i] = new GUIContent(scenes[i].name);
|
|
}
|
|
}
|
|
|
|
private void FetchAllSelectedIndices()
|
|
{
|
|
for (var i = 0; i < SceneManager.sceneCount; i++)
|
|
{
|
|
Scene scene = SceneManager.GetSceneAt(i);
|
|
|
|
if (string.IsNullOrEmpty(scene.path))
|
|
continue;
|
|
|
|
int index = IndexOfPath(scenes, scene.path, false);
|
|
|
|
if (index != -1)
|
|
selected.Add(index);
|
|
}
|
|
}
|
|
|
|
private static List<WorkingSetScene> GetAllWorkingSetScenesWithLabels(List<WorkingSetScene> assets, List<string> labels)
|
|
{
|
|
var list = new List<WorkingSetScene>();
|
|
|
|
for (var i = 0; i < labels.Count; i++)
|
|
{
|
|
list.AddRange(GetAllWorkingSetScenesWithLabel(assets, labels[i]));
|
|
}
|
|
|
|
return list;
|
|
}
|
|
|
|
private static List<WorkingSetScene> GetAllWorkingSetScenesWithLabel(List<WorkingSetScene> assets, string label)
|
|
{
|
|
var list = new List<WorkingSetScene>();
|
|
|
|
for (var i = 0; i < assets.Count; i++)
|
|
{
|
|
if (assets[i].labels.Contains(label))
|
|
list.Add(assets[i]);
|
|
}
|
|
|
|
return list;
|
|
}
|
|
|
|
private static List<WorkingSetScene> GetAllWorkingSetScenesWithNameContaining(List<WorkingSetScene> assets, List<string> filters)
|
|
{
|
|
var list = new List<WorkingSetScene>();
|
|
|
|
for (var i = 0; i < assets.Count; i++)
|
|
{
|
|
for (var j = 0; j < filters.Count; j++)
|
|
{
|
|
if (!assets[i].shortname.Contains(filters[j]))
|
|
continue;
|
|
|
|
list.Add(assets[i]);
|
|
break;
|
|
}
|
|
}
|
|
|
|
return list;
|
|
}
|
|
|
|
private static List<WorkingSetScene> GetAllWorkingSetScenesWithPathContaining(List<WorkingSetScene> assets, List<string> filters)
|
|
{
|
|
var list = new List<WorkingSetScene>();
|
|
|
|
for (var i = 0; i < assets.Count; i++)
|
|
{
|
|
for (var j = 0; j < filters.Count; j++)
|
|
{
|
|
if (!PathContains(assets[i].path, filters[j]))
|
|
continue;
|
|
|
|
list.Add(assets[i]);
|
|
break;
|
|
}
|
|
}
|
|
|
|
return list;
|
|
}
|
|
|
|
private static bool IsValidScene(string path)
|
|
{
|
|
if (string.IsNullOrEmpty(path))
|
|
return false;
|
|
if (!path.StartsWith("Assets"))
|
|
return false;
|
|
|
|
return AssetDatabase.LoadAssetAtPath<SceneAsset>(path) != null;
|
|
}
|
|
|
|
public int IndexOfPath(string path, bool includeGroups)
|
|
{
|
|
return IndexOfPath(scenes, path, includeGroups);
|
|
}
|
|
|
|
private static int IndexOfPath(List<SceneElement> list, string path, bool includeGroups)
|
|
{
|
|
for (var i = 0; i < list.Count; i++)
|
|
{
|
|
if (!includeGroups && list[i].isGroup)
|
|
continue;
|
|
if (!list[i].includeAsSelectable)
|
|
continue;
|
|
|
|
if (list[i].paths.IndexOf(path) != -1)
|
|
return i;
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
private static bool PathContains(string path, string subpath)
|
|
{
|
|
path = path.Replace("\\", "/");
|
|
subpath = subpath.Replace("\\", "/");
|
|
return path.Contains(subpath);
|
|
}
|
|
|
|
private static bool PathEquals(string path, string subpath)
|
|
{
|
|
path = path.Replace("\\", "/");
|
|
subpath = subpath.Replace("\\", "/");
|
|
return path.Equals(subpath);
|
|
}
|
|
|
|
private static void SetWorkingSceneAsFirst(List<WorkingSetScene> scenes, string path)
|
|
{
|
|
int index = -1;
|
|
|
|
for (var i = 0; i < scenes.Count; i++)
|
|
{
|
|
if (!PathEquals(scenes[i].path, path))
|
|
continue;
|
|
|
|
index = i;
|
|
break;
|
|
}
|
|
|
|
if (index == -1)
|
|
return;
|
|
|
|
WorkingSetScene temp = scenes[0];
|
|
scenes[0] = scenes[index];
|
|
scenes[index] = temp;
|
|
}
|
|
|
|
private static List<WorkingSetScene> GetWorkingSet()
|
|
{
|
|
var workingSet = new List<WorkingSetScene>();
|
|
string[] guids = AssetDatabase.FindAssets("t:scene");
|
|
EditorBuildSettingsScene[] buildSettingsScenes = EditorBuildSettings.scenes;
|
|
|
|
for (var i = 0; i < guids.Length; i++)
|
|
{
|
|
string path = AssetDatabase.GUIDToAssetPath(guids[i]);
|
|
|
|
if (!IsValidScene(path))
|
|
continue;
|
|
|
|
var asset = AssetDatabase.LoadAssetAtPath<SceneAsset>(path);
|
|
string sceneName = path.Substring(7, path.Length - 13).Replace('/', '\\');
|
|
var inBuildSettings = false;
|
|
|
|
for (var j = 0; j < buildSettingsScenes.Length; j++)
|
|
{
|
|
if (!buildSettingsScenes[j].path.Equals(path))
|
|
continue;
|
|
|
|
inBuildSettings = true;
|
|
break;
|
|
}
|
|
|
|
workingSet.Add(new WorkingSetScene
|
|
{
|
|
path = path,
|
|
name = sceneName,
|
|
shortname = Path.GetFileNameWithoutExtension(path),
|
|
labels = AssetDatabase.GetLabels(asset),
|
|
inBuildSettings = inBuildSettings
|
|
});
|
|
}
|
|
|
|
return workingSet;
|
|
}
|
|
|
|
public sealed class SceneElement
|
|
{
|
|
public string name;
|
|
public string shortname;
|
|
public bool includeAsSelectable = true;
|
|
public bool isGroup;
|
|
public readonly List<string> paths = new List<string>();
|
|
}
|
|
|
|
private sealed class WorkingSetScene
|
|
{
|
|
public string path;
|
|
public string name;
|
|
public string shortname;
|
|
public string[] labels;
|
|
public bool inBuildSettings;
|
|
}
|
|
}
|
|
} |