This script lets you link scenes in scripts using a property drawer. Based on Network Manager code
Place this script in Editor script location
using UnityEditor;
using UnityEngine;
[CustomPropertyDrawer (typeof (SceneAttribute))]
public class SceneDrawer : PropertyDrawer {
public override void OnGUI (Rect position, SerializedProperty property, GUIContent label) {
if (property.propertyType == SerializedPropertyType.String) {
var sceneObject = GetSceneObject(property.stringValue);
var scene = EditorGUI.ObjectField(position, label, sceneObject, typeof(SceneAsset), true);
if (scene == null) {
property.stringValue = "";
} else if (scene.name != property.stringValue) {
var sceneObj = GetSceneObject(scene.name);
if (sceneObj == null) {
Debug.LogWarning("The scene " + scene.name + " cannot be used. To use this scene add it to the build settings for the project");
} else {
property.stringValue = scene.name;
}
}
}
else
EditorGUI.LabelField (position, label.text, "Use [Scene] with strings.");
}
protected SceneAsset GetSceneObject(string sceneObjectName) {
if (string.IsNullOrEmpty(sceneObjectName)) {
return null;
}
foreach (var editorScene in EditorBuildSettings.scenes) {
if (editorScene.path.IndexOf(sceneObjectName) != -1) {
return AssetDatabase.LoadAssetAtPath(editorScene.path, typeof(SceneAsset)) as SceneAsset;
}
}
Debug.LogWarning("Scene [" + sceneObjectName + "] cannot be used. Add this scene to the 'Scenes in the Build' in build settings.");
return null;
}
}
Place this script in normal script location
using UnityEngine;
public class SceneAttribute : PropertyAttribute {
}
Example of how to use [Scene] Attribute to access scenes
using UnityEngine;
using UnityEngine.Networking;
using UnityEngine.SceneManagement;
public class SceneSelector : MonoBehaviour
{
[Scene]
public string newScene;
public void ChangeScene() {
SceneManager.LoadScene(newScene, LoadSceneMode.Single);
}
public void ChangeNetworkScene() {
if(NetworkServer.active && NetworkManager.singleton != null) {
NetworkManager.singleton.ServerChangeScene(newScene);
}
}
}
I think this is a useful concept. What I personally need is a field that will allow me to drag assets into it, and only the asset’s path will be stored. This would probably be used in conjunction with a [Path] attribute or something similar.
The motivation for this is that referencing the asset itself makes it automatically get loaded with the scene. This is not always desirable. Instead, i’d like to store only the path for the asset, and later load it using Resources.Load
Just storing a path string (as the SceneAsset documentation suggests) is inadequate for production, because if the scene file is renamed, moved, or otherwise looked at funny, you’ve lost your reference. We can use an Object reference to the SceneAsset but we no longer have access to AssetDatabase to look up the path when not in editor.
To reliably handle both file renames and runtime paths you need two serialized pieces of data (Object reference in editor, string path at runtime). You can create a SceneReference object that uses ISerializationCallbackReceiver to ensure that the stored path is always valid based on the specified SceneAsset Object.
Custom PropertyDrawer that displays the current Build Settings status, including BuildIndex and convenient buttons for managing it with destructive action confirmation dialogues.
If (and only if) the serialized Object reference is invalid but path is still valid (for example if someone merged incorrectly) will recover object using path.
Buttons collapse to smaller text if full text cannot be displayed.
Includes detailed tooltips and respects Version Control if EditorBuildSettings.asset is not checked out (tested with Perforce)
#if UNITY_EDITOR
// What we use in editor to select the scene
[SerializeField] private Object sceneAsset = null;
bool IsValidSceneAsset
{
get
{
if (sceneAsset == null)
return false;
return sceneAsset.GetType().Equals(typeof(SceneAsset));
}
}
#endif