-
-
Save svermeulen/8927b29b2bfab4e84c950b6788b0c677 to your computer and use it in GitHub Desktop.
using System.Collections.Generic; | |
using System.IO; | |
using UnityEngine; | |
using UnityEditor.SceneManagement; | |
using UnityEditor; | |
using System.Collections; | |
using System.Linq; | |
public class MultiSceneSetup : ScriptableObject | |
{ | |
public SceneSetup[] Setups; | |
} | |
public static class MultiSceneSetupMenu | |
{ | |
[MenuItem("Assets/Multi Scene Setup/Create")] | |
public static void CreateNewSceneSetup() | |
{ | |
var folderPath = TryGetSelectedFolderPathInProjectsTab(); | |
var assetPath = ConvertFullAbsolutePathToAssetPath( | |
Path.Combine(folderPath, "SceneSetup.asset")); | |
SaveCurrentSceneSetup(assetPath); | |
} | |
[MenuItem("Assets/Multi Scene Setup/Create", true)] | |
public static bool CreateNewSceneSetupValidate() | |
{ | |
return TryGetSelectedFolderPathInProjectsTab() != null; | |
} | |
[MenuItem("Assets/Multi Scene Setup/Overwrite")] | |
public static void SaveSceneSetup() | |
{ | |
var assetPath = ConvertFullAbsolutePathToAssetPath( | |
TryGetSelectedFilePathInProjectsTab()); | |
SaveCurrentSceneSetup(assetPath); | |
} | |
static void SaveCurrentSceneSetup(string assetPath) | |
{ | |
var loader = ScriptableObject.CreateInstance<MultiSceneSetup>(); | |
loader.Setups = EditorSceneManager.GetSceneManagerSetup(); | |
AssetDatabase.CreateAsset(loader, assetPath); | |
AssetDatabase.SaveAssets(); | |
AssetDatabase.Refresh(); | |
Debug.Log(string.Format("Scene setup '{0}' saved", Path.GetFileNameWithoutExtension(assetPath))); | |
} | |
[MenuItem("Assets/Multi Scene Setup/Load")] | |
public static void RestoreSceneSetup() | |
{ | |
var assetPath = ConvertFullAbsolutePathToAssetPath( | |
TryGetSelectedFilePathInProjectsTab()); | |
var loader = AssetDatabase.LoadAssetAtPath<MultiSceneSetup>(assetPath); | |
EditorSceneManager.RestoreSceneManagerSetup(loader.Setups); | |
Debug.Log(string.Format("Scene setup '{0}' restored", Path.GetFileNameWithoutExtension(assetPath))); | |
} | |
[MenuItem("Assets/Multi Scene Setup", true)] | |
public static bool SceneSetupRootValidate() | |
{ | |
return HasSceneSetupFileSelected(); | |
} | |
[MenuItem("Assets/Multi Scene Setup/Overwrite", true)] | |
public static bool SaveSceneSetupValidate() | |
{ | |
return HasSceneSetupFileSelected(); | |
} | |
[MenuItem("Assets/Multi Scene Setup/Load", true)] | |
public static bool RestoreSceneSetupValidate() | |
{ | |
return HasSceneSetupFileSelected(); | |
} | |
static bool HasSceneSetupFileSelected() | |
{ | |
return TryGetSelectedFilePathInProjectsTab() != null; | |
} | |
static List<string> GetSelectedFilePathsInProjectsTab() | |
{ | |
return GetSelectedPathsInProjectsTab() | |
.Where(x => File.Exists(x)).ToList(); | |
} | |
static string TryGetSelectedFilePathInProjectsTab() | |
{ | |
var selectedPaths = GetSelectedFilePathsInProjectsTab(); | |
if (selectedPaths.Count == 1) | |
{ | |
return selectedPaths[0]; | |
} | |
return null; | |
} | |
// Returns the best guess directory in projects pane | |
// Useful when adding to Assets -> Create context menu | |
// Returns null if it can't find one | |
// Note that the path is relative to the Assets folder for use in AssetDatabase.GenerateUniqueAssetPath etc. | |
static string TryGetSelectedFolderPathInProjectsTab() | |
{ | |
var selectedPaths = GetSelectedFolderPathsInProjectsTab(); | |
if (selectedPaths.Count == 1) | |
{ | |
return selectedPaths[0]; | |
} | |
return null; | |
} | |
// Note that the path is relative to the Assets folder | |
static List<string> GetSelectedFolderPathsInProjectsTab() | |
{ | |
return GetSelectedPathsInProjectsTab() | |
.Where(x => Directory.Exists(x)).ToList(); | |
} | |
static List<string> GetSelectedPathsInProjectsTab() | |
{ | |
var paths = new List<string>(); | |
UnityEngine.Object[] selectedAssets = Selection.GetFiltered( | |
typeof(UnityEngine.Object), SelectionMode.Assets); | |
foreach (var item in selectedAssets) | |
{ | |
var relativePath = AssetDatabase.GetAssetPath(item); | |
if (!string.IsNullOrEmpty(relativePath)) | |
{ | |
var fullPath = Path.GetFullPath(Path.Combine( | |
Application.dataPath, Path.Combine("..", relativePath))); | |
paths.Add(fullPath); | |
} | |
} | |
return paths; | |
} | |
static string ConvertFullAbsolutePathToAssetPath(string fullPath) | |
{ | |
return "Assets/" + Path.GetFullPath(fullPath) | |
.Remove(0, Path.GetFullPath(Application.dataPath).Length + 1) | |
.Replace("\\", "/"); | |
} | |
} |
nice, we've been using a much crappier version of this!
Very helpful. Thank you for sharing!
Very nice, thank you.
Very good and helpful indeed!
in latest Unity (2018.3.3), there's a bit of a hiccup. Reproduction experience steps: Create a multiscene edit, save it via this facility, and load another scene from the project, uniquely, not in the current multiscene edit. Clicking on the saved scene setup reveals it's lost its connection to its script. Playing the newly loaded scene, and immediately stopping the play, restores that connection, and the saved scene setup now works as desired, until a another scene is loaded uniquely into the editor.
I'm working with Unity 2022.2 but unfortunately the AssetDatabase.LoadAssetAtPath() was very unreliable (It often - but not always - couldn't load the asset even if it was visible inside the AssetDatabase). I therefore changed the Save and Load as an Asset to JsonUtility.FromJson/ToJson. You just need to remove extends ScriptableObject from MultiSceneSetup class to work properly.
Just add to an Editor/ folder in your project, and then you can right click on a folder in the Project tab and select
Multi Scene Setup -> Create
to save the current multi-scene setup. Or right click on an existing one then selectOverwrite
orLoad
to load it again