Skip to content

Instantly share code, notes, and snippets.

@svermeulen
Created October 23, 2016 17:32
Show Gist options
  • Star 48 You must be signed in to star a gist
  • Fork 7 You must be signed in to fork a gist
  • Save svermeulen/8927b29b2bfab4e84c950b6788b0c677 to your computer and use it in GitHub Desktop.
Save svermeulen/8927b29b2bfab4e84c950b6788b0c677 to your computer and use it in GitHub Desktop.
Simple editor script to save and load multi-scene setups within Unity3D
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("\\", "/");
}
}
@svermeulen
Copy link
Author

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 select Overwrite or Load to load it again

@timmeh4242
Copy link

nice, we've been using a much crappier version of this!

@13Flo
Copy link

13Flo commented Jul 28, 2017

Very helpful. Thank you for sharing!

@ameliemaia
Copy link

Very nice, thank you.

@Mathijs-Bakker
Copy link

Very good and helpful indeed!

@c0nfused
Copy link

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.

@JaXt0r
Copy link

JaXt0r commented Dec 26, 2022

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment