Skip to content

Instantly share code, notes, and snippets.

@aybe
Last active November 12, 2025 06:14
Show Gist options
  • Select an option

  • Save aybe/8b7ea7c6c95d381c7a431417bd2b65d2 to your computer and use it in GitHub Desktop.

Select an option

Save aybe/8b7ea7c6c95d381c7a431417bd2b65d2 to your computer and use it in GitHub Desktop.
Serializable scene reference for Unity 6
using System;
using UnityEngine;
using Object = UnityEngine.Object;
#if UNITY_EDITOR
using System.IO;
using UnityEditor;
using UnityEditor.Build;
using UnityEditor.Build.Reporting;
using UnityEditor.UIElements;
using UnityEngine.UIElements;
using UnityEngine.SceneManagement;
#endif
namespace WIP
{
[Serializable]
public sealed class SceneReference
{
[SerializeField] private Object Source;
[SerializeField] private string Target;
public string Name => Target;
#if UNITY_EDITOR
[CustomPropertyDrawer(typeof(SceneReference))]
private sealed class Drawer : PropertyDrawer
{
public override VisualElement CreatePropertyGUI(SerializedProperty property)
{
var asset = property.FindPropertyRelative(nameof(Source));
var field = new ObjectField(preferredLabel) { allowSceneObjects = false, objectType = typeof(SceneAsset) };
field.AddToClassList(ObjectField.alignedFieldUssClassName);
field.BindProperty(asset);
field.RegisterCallback<AttachToPanelEvent>(_ => { EditorApplication.projectChanged += OnProjectChanged; });
field.RegisterCallback<DetachFromPanelEvent>(_ => { EditorApplication.projectChanged -= OnProjectChanged; });
return field;
void OnProjectChanged()
{
if (field.value == null && asset.objectReferenceValue is { } value)
{
field.value = value; // fix deleted/restored = broken icon/ping
}
}
}
}
[BuildCallbackVersion(1)]
private sealed class Processor : IProcessSceneWithReport
{
public int callbackOrder => 0;
public void OnProcessScene(Scene scene, BuildReport report)
{
var objects = scene.GetRootGameObjects();
foreach (var obj in objects)
{
var components = obj.GetComponentsInChildren<Component>();
foreach (var component in components)
{
using var so = new SerializedObject(component);
using var sp = so.GetIterator();
while (sp.NextVisible(true))
{
if (sp is not { propertyType: SerializedPropertyType.Generic, type: nameof(SceneReference), boxedValue: SceneReference sr })
{
continue;
}
var target = sp.FindPropertyRelative(nameof(Target));
var path = AssetDatabase.GetAssetPath(sr.Source);
target.stringValue = Application.isEditor ? path : Path.ChangeExtension(path, null);
}
so.ApplyModifiedPropertiesWithoutUndo();
}
}
}
}
#endif
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment