Skip to content

Instantly share code, notes, and snippets.

@darktable
Created July 17, 2023 13:23
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save darktable/26e95842c572f97af13aacc03b79f2e2 to your computer and use it in GitHub Desktop.
Save darktable/26e95842c572f97af13aacc03b79f2e2 to your computer and use it in GitHub Desktop.
Utility script to generate a menu items to load the scenes included in build settings.
// The contents of this file is free and unencumbered software released into the
// public domain. For more information, please refer to <http://unlicense.org/>
using System;
using System.IO;
using System.Text;
using UnityEditor;
using UnityEngine;
using UnityEngine.SceneManagement;
namespace DarkTable.Utils
{
/// <summary>
/// Generates a menu of *only* the scenes that are included in the build.
/// </summary>
public class GenerateSceneLoaderMenu : AssetModificationProcessor
{
private const string k_Header = "/* <auto-generated> DO NOT MODIFY\n (created by GenerateSceneLoaderMenu.cs. File->Save Project will usually trigger an update of this file) */\n\n";
private const string k_StandardAssets = "Standard Assets";
private const string k_DirectoryName = "Editor/Scripts/SceneLoaderMenu";
private const string k_FileName = "SceneLoaderMenu.cs";
private static readonly string[] k_SavedAssets = new[] { "EditorBuildSettings.asset" };
[InitializeOnLoadMethod]
private static void Initialize()
{
string rootPath = Path.Combine(Application.dataPath, k_StandardAssets, k_DirectoryName);
if (!Directory.Exists(rootPath))
{
UpdateSceneList();
return;
}
string fileName = Path.Combine(rootPath, k_FileName);
if (!File.Exists(fileName))
{
UpdateSceneList();
}
}
private static string[] OnWillSaveAssets(string[] paths)
{
foreach (string path in paths)
{
string filename = Path.GetFileName(path);
foreach (string asset in k_SavedAssets)
{
if (filename.Equals(asset, StringComparison.InvariantCultureIgnoreCase))
{
UpdateSceneList();
return paths;
}
}
}
return paths;
}
private static void UpdateSceneList()
{
var outfile = new StringBuilder(k_Header, 4096);
int count = SceneManager.sceneCountInBuildSettings;
AddClassHeader(outfile);
for (var i = 0; i < count; i++)
{
string scenePath = SceneUtility.GetScenePathByBuildIndex(i);
if (string.IsNullOrEmpty(scenePath))
{
continue;
}
AddCodeForFile(scenePath, outfile);
}
AddClassFooter(outfile);
SaveFile(outfile);
void AddClassHeader(StringBuilder output)
{
output.Append("using UnityEditor;\n")
.Append("using UnityEditor.SceneManagement;\n\n")
.Append("public static class SceneLoaderMenu {\n");
}
void AddClassFooter(StringBuilder output)
{
output.Append(" private static void OpenScene(string guid) {\n")
.Append(" if (EditorSceneManager.SaveCurrentModifiedScenesIfUserWantsTo()) {\n")
.Append(" EditorSceneManager.OpenScene(AssetDatabase.GUIDToAssetPath(guid), OpenSceneMode.Single);\n")
.Append(" }\n }\n}\n");
}
void AddCodeForFile(String scenePath, StringBuilder output)
{
scenePath = scenePath.Replace('\\', '/');
var directoryName = ObjectNames.NicifyVariableName(Path.GetFileName(Path.GetDirectoryName(scenePath)));
var sceneName = ObjectNames.NicifyVariableName(Path.GetFileNameWithoutExtension(scenePath));
if (!string.IsNullOrEmpty(directoryName)
&& !directoryName.Equals("Assets", StringComparison.InvariantCultureIgnoreCase)
&& !directoryName.Equals("Scenes", StringComparison.InvariantCultureIgnoreCase))
{
sceneName = $"{directoryName}/{sceneName}";
}
var guid = AssetDatabase.GUIDFromAssetPath(scenePath);
output.Append($" [MenuItem(\"Tools/Load Scene/{sceneName}\")]\n")
.Append($" public static void Load_{guid}() => OpenScene(\"{guid}\");\n\n");
}
}
private static void SaveFile(StringBuilder outfile)
{
string rootPath = Path.Combine(Application.dataPath, k_StandardAssets, k_DirectoryName);
if (!Directory.Exists(rootPath))
{
Directory.CreateDirectory(rootPath);
}
string filePath = Path.Combine(rootPath, k_FileName);
string current = null;
if (File.Exists(filePath))
{
current = File.ReadAllText(filePath);
}
var updated = outfile.ToString();
if (!string.Equals(current, updated))
{
Debug.Log("Generating scene loader file");
File.WriteAllText(filePath, updated);
AssetDatabase.Refresh();
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment