SceneAsset is terrible

The SceneAsset is useless thing.
I just want to get some info about scene like build index. But I have to make ultra difficult alghorithm to get it
Why you just cant make things simple? I want to load scenes in runtime with SceneAsset, but I cant, I have to write own ScriptableObject decorator with buildIndex serialization.

public class SceneContainer : ScriptableObject
{
[field: SerializeField, HideInInspector]
public int sceneIndex { get; private set; }

#if UNITY_EDITOR
[SerializeField]
private SceneAsset _sceneAsset;

private void OnValidate()
{
string path = AssetDatabase.GetAssetOrScenePath(_sceneAsset);

List<EditorBuildSettingsScene> editorBuildSettingsScenes = EditorBuildSettings.scenes.ToList();

EditorBuildSettingsScene buildSettingsScene = editorBuildSettingsScenes.First(scene => scene.path == path);

int buildIndex = editorBuildSettingsScenes.IndexOf(buildSettingsScene);

if (sceneIndex == buildIndex) return;

sceneIndex = buildIndex;
}
#endif
}

It’s an editor only thing because they don’t exist at runtime. Scenes in your build settings get crunched up into a different file type for use in runtime.

It’s unwieldy, for sure. One of those old parts of Unity that we can’t really shed without Unity doing some big breaking update that probably will never happen.

The process for loading/unloading scenes is a lot more straightforward with Addressables as you can ā€˜reference’ scenes directly via an AddressableReference.

1 Like

Thanks for reply. I will see how it works with addresables.

It’s only perceived by you as ultra difficult. :wink:
For one, you are not using ā€˜var’ which makes your code far more verbose than it needs to be.
Then you are not utilizing LINQ to its fullest. For instance, it works with arrays too.
Lastly, you haven’t cleaned up your code … the second to last line doesn’t make any sense. You can just assign it, regardless of whether the value might be the same or not.

Here’s my version:

private void OnValidate()
{
    string path = AssetDatabase.GetAssetOrScenePath(_sceneAsset);

    var scenes = EditorBuildSettings.scenes;
    var exists = scenes.FirstOrDefault(s => s.path == path) != null;
    if (exists)
        sceneIndex = scenes.TakeWhile(s => s.path != path).Count();
}

Pretty sure there may be a way to combine both the exists and count check but it’s already simple enough to prove my point that there is nothing ā€œultra difficultā€ about this. And yes, I spent 2 minutes googling the LINQ usage myself and as usual, found the solutions on stackoverflow. I don’t know these off the top of my head either.

The first one just checks if the scene is in the list to begin with, because the TakeWhile only counts the ones that don’t match to increment up to the desired index - which would be wrong (equal to last index) if we didn’t check first whether the scene is actually in the build list.

Exactly why I redesigned the AssetDatabase. :slight_smile:
I might be doing more of the same for other ~20 year old rotten API depending on where I consistently run into pains myself.

Side-note, this is BAAAAAD:

#if UNITY_EDITOR
        [SerializeField]
        private SceneAsset _sceneAsset;
#endif

You can run into serious build issues if you #if out serialized fields because the serialization format then differs between editor and build.

Depending on where you add more fields Unity will throw an error in builds noting that something is off about the serialization format of the scene and fail to load the scene.

Have you tried to build and run this? If not, do that. If it works, add another [SerializeField] below the #endif and try again. At the latest that should throw an error in the build.

You should move that code to an editor-only script.

This has been supported for a long time.

I stand corrected! :slight_smile:

Found the earliest mention in the 2021.2 manual:
9552793--1350076--upload_2023-12-29_11-44-19.png

I think last time I ran into this was with Unity 2018 or 2019 and ever since that was ingrained as a no-no given how awful it was to figure out the cause.

1 Like

Its not difficult because I implemented this and gave you ready code. You just refactor it. But when you have only task: ā€œmake the runtime sceneAsset decorator because unity dont have itā€. You have to spent 20-30 minutes to find a solution.