SceneManager - an annoyance I have with the documentation and API

So currently I’m writing some code to deal with the SceneManager… the SceneManager doesn’t have a ‘before scene is loaded’ event, so I basically am writing my own wrapper for that so that I can hook my own event in, and any time I use this wrapper to load a scene (instead of SceneManager) I’ll get the event as needed.

Here’s the thing.

When writing the interface for it I instinctively write it in this format:

public Scene LoadScene(string sceneName)

And that’s when I notice something… LoadScene doesn’t return anything!

Ok… weird. Because we have all these other methods on SceneManager where one could pass in a Scene object to do stuff. How am I supposed to get the reference to the scene? This is starting to stink like coroutine in older versions of Unity… they’re going to want me to use strings, but then the object identity is uncertain… I’ll get to that.

Anyways, so I’m like. All right, I’ll use this ‘GetSceneByName’:

Huh? What does that mean? Does that mean it’s included in the build settings? Or that it’s been… ‘added’… to the SceneManager? Like it’s been previously loaded? So it only works if I’ve loaded it?

Lets look at the rest of the documentation, maybe that’ll help resolve things!

Hrmm… here’s a ‘GetSceneByBuildIndex’…

Hrmmm… ok, this implies that it can’t just be in the build settings, it must also have been loaded! Cause if you must load it first to validly find a scene by build index… you can’t find a scene by name either just because it’s the buildSettings. I mean… why wouldn’t you be able to by build index if you could by name? So if you can’t by build index, you logically can’t by name?

I’m still not certain though, lets run a test where I try to ‘GetSceneByName’ when that scene has yet to be loaded…

var scene = SceneManager.GetSceneByName("SomeSceneNotLoadedYet");

Hrmmm… it returns a valid scene!

Is this because I’m in the editor?

Ughhhh… am I going to have to build a test project to test this code?

Why am I having to do this?

[edit]
Just noticed that the Scene object is actually a struct… so that’s why it appeared valid. It’s not though… so ok, that explains if I want to get the Scene token, the scene has to be loaded. The rest of my post still stands.
[/edit]

Unity… I thought you were getting your shiznit together! I thought you were finally building more appropriate APIs. I was so happy when you created the ‘Coroutine’ class giving us object identity for that, so that way you can actually stop a specific Coroutine… rather than magic strings. And when I saw a while back that you released this new SceneManager (I know… I’m a little to this game, I just hadn’t needed it as of late to do anything complex until very recently). But yeah… I was super excited to see you also gave Scenes some object identity instead of just string names (well not fully object identity since it’s a struct, but better… definitely better).

But this brings me to an issue.

So one of the reasons I really like the ‘Coroutine’ object y’all added way back when. It’s because if I started 2 coroutines from the same method, I could stop one, and know which one I was actually stopping. Cause when using the strings… who knows what happens!?

So… with this Scene object. My question is… lets say I load the same scene twice… additively. Is this even possible? If it is, how do I get a reference to the ‘Scene’ token for each unique scene?

Why the heck doesn’t LoadScene return the Scene token!?

This just boggles my freaking mind!

Sorry, had to vent.

Just sometimes I wonder about the API design choices unity makes.

Like I’m not arguing I’m the best at creating an API either… but jeez guys, way to half heartedly approach this thing. You have ways to Unload scenes by a Scene token… but no way to consistently get that Token! Nor document the behaviour of it!

3 Likes

Just tested to make sure…

Yep, you can load the same scene additively multiple times.

So… like… how do I get the ‘Scene’ token for each one additively loaded? How do I load it twice and than Unload one of the two?

I’m so glad I am bald… less I’d be pulling out my hair.

So… i resolved my issue. I have to do this:

        public Scene LoadScene(string sceneName, LoadSceneMode mode = LoadSceneMode.Single)
        {
            //TODO - my stuff
            SceneManager.LoadScene(sceneName, mode);
            return SceneManager.GetSceneAt(SceneManager.sceneCount - 1);
        }

        public LoadSceneAsyncWaitHandle LoadSceneAsync(string sceneName, LoadSceneMode mode = LoadSceneMode.Single)
        {
            //TODO - my stuff
            var op = SceneManager.LoadSceneAsync(sceneName, mode);
            return new LoadSceneAsyncWaitHandle(op, SceneManager.GetSceneAt(SceneManager.sceneCount - 1));
        }

Or at least… I hope so. This works currently as far as I know.

Imagine if Unity were to ever become multi-threaded… LOL.

Threading is already possible in beta.

Is it?

I haven’t heard about this.

Unity has moved their API to be thread-safe?

I highly doubt that, that’s 1) a LOT of work, and 2) would be pretty big news!

I may be in for a surprise though… but that’ll make the API one hell of a nightmare to wrestle with, without some heavy modification to it.

Are you sure you don’t mean that you can spin up your own thread? Cause we can do that already. And the new beta gives access to the ‘async’ stuff in C# 6… but I’m not talking about using your own threads. I’m talking about Unity actually being threaded… like accessing its API in a thread safe manner.

My point is… if it were. Then my code as shown would be a huge problem. If 2 threads attempted to load a scene at the same time, there’s not guarantee that the ‘sceneCount’ is correct when I access it, meaning I’d get the wrong Scene back… which again returns me back to my OP… why didn’t they have the freaking LoadScene method return the Scene token (which would be the only thread safe way to do it)!?

Hahah no way that would be too surprising.

You sure? System.threading is not present in .Net 3.5. Did you mean a Coroutine?

Yeah, I’m sure. I’ve been using it for 10 years now.

It’s existed all the way back in .Net 1.1:

2 Likes

Multithreading has been around for ages. You can do it in your own scripts. Unity does it in the background.

Where its single threaded is the interface between your code and the engine. Unity only does callbacks on the main thread. You can only call Unity on the main thread. I’ve heard nothing indicating this will change.

2 Likes

Oh. How did you change your name?

https://support.unity3d.com/hc/en-us/articles/205053589-How-do-I-change-my-username-

1 Like

Thank you.