This post highlights a handy way to automatically validate scene name strings with a custom ‘[ValidatedSceneName]’ attribute! Let’s have a discussion about other handy uses of custom attributes here!

SETTING THE SCENE

Working with dynamic scene loading in unity can at times be annoying. I often find myself in a scenario where some component needs a reference to a scene in order to eg. load it at some point during the game. For some inconspicuous reason the Scene struct is not serializable, meaning it won’t draw in the inspector. Then there’s the SceneAsset class which gives us a standard object picker field which is actually really nice, however, using it to pick a Scene shows that it doesn’t really work that way unfortunately. It’s also in the UnityEditor namespace, which makes it practically unusable, at least for scripts we want to include in our builds.

(This is what we’ll be making if you follow along!)

In practice, loading a Scene during runtime using either the SceneManager.LoadScene or SceneManager.LoadSceneAsync methods, we see that both methods take either an integer for the build index or a string for the scene name. This means that for our MonoBehaviours that want to load a specific scene that is configured via the Inspector,  we have to make a public int, or as i used to prefer, string.

This is of course suboptimal, so instead of keeping the complain-train going, let’s fix that with our very own custom attribute!

ATTRIBUTES SAVE THE DAY

Since we’re forced to use a string for the scene name, there is ample room for messing up by misspelling a scene name in the Inspector window. That is of course no good, as the we’ll only notice that something has gone wrong when we play the game and get an error! Instead we would like the string that we input to be validated automatically, ensuring that a scene exists with the same name in the build settings. The sexiest way to do this is by making a PropertyAttribute that we can attach to our serialized string field. Have you ever put [Range(0f, 1f)] over a float or an int to limit the values that can be set in the Inspector, while making Unity draw the field as a nice slider? That’s a PropertyAttribute, and we’re gonna make our own now!

In order to accomplish our goal, we need two scripts. One that declares our attribute, and another for a custom PropertyDrawer that will take care of the validation, as well as display some helpful messages.

THE PROPERTY ATTRIBUTE

To start off, let’s declare a new class named ValidatedSceneName and make it inherit from PropertyAttribute. We’ll also define that we only want this attribute to be used for fields, ensuring a nasty red squiggly line in the IDE if we try to put the attribute over, for instance, a method.

And that’s it for the PropertyAttribute! No I’m not kidding. However, that’s because all the magic really happens in the PropertyDrawer! So let’s move on to that.

THE PROPERTY DRAWER

I absolutely love PropertyDrawers. They are a sort of mini custom inspector but for a single property, which allows us to make our custom serialized classes look nice in the inspector! if you’re not familiar with PropertyDrawers, I suggest you start looking at some of Unity’s own examples. Trust me, it will change your workflow in Unity for the better.

For this example, we’ll start by making sure we’re using the UnityEngine namespace, allowing our class to inherit from PropertyDrawer. We’ll also define that this class should be used to draw anything with the ValidatedSceneName attribute.

In order to control the way the string is drawn, we’ll override the OnGUI() method. Since we want to display a box with helpful information if the string doesn’t match the name of a scene in the build settings we also need to override the GetPropertyHeight() method to make it return a larger value in the case that the help box needs to be displayed (that way the help box won’t draw on top of any other properties).

When working with a SerializedProperty it is important to always remember to start by updating the SerializedObject that holds the property to make sure we are working with the most recent changes, as well as end by calling ApplyModifiedProperties() on the SerializedObject to ensure that any changes we have made will stick.

To get to the meat of it, we start by creating a rect that will hold the text field that represents the string that is input in the Inspector. Since we’ll modify GetPropertyHeight() to return a larger value if the string is invalid, we need to insure that the text field keeps that standard property height, which we accomplish by creating a rect with the height of EditorGUIUtility.singleLineHeight .

Note that I’m using an extension method to quickly create a Rect with a specific height from another Rect ( .WithHeight() ). If you’re not familiar with C# extension methods, I highly encourage you to check out this article! You can find the extension methods used in this example in the bottom of the article.

Now we need to get the string value of the property and validate it in a method we’ll call ValidateSceneName() (don’t worry, we’ll make that in a bit). The method should return a bool that signifies whether the string corresponds with the name of a scene in the build settings or not. If it doesn’t we’ll display a little help box with a message indicating what’s wrong (also if the string is simply empty).
At this point we can also return a value that will prevent our help box from drawing on top of other properties. the magic number 2.5f is simply added for a pleasant margin between the text field and the help box, as well as between the help box and the next property in the script.

Now it’s time to actually write the validation method. We’ll start by getting all the scenes in the build settings and then loop through them. Since the strings returned by EditorBuildSettingsScene.GetActiveSceneList() are the full paths to the scene in the project folders (eg. Assets/Scenes/MyScene.unity), the quickest way to just get a ‘clean’ version of the name of the scene is to simply load the SceneAsset and get its name property.
When we find a name that corresponds with the one in our text field we’ll simply return True  , and if not we’ll return False .

And that’s it! We can now tag any string in our MonoBehaviours with the [ValidatedSceneName] attribute, and we’ll get a nice help box with a red error symbol that only goes away if the string matches the name of a scene in the build settings!

CONCLUSION

Of course this attribute only makes potential errors more visible in the inspector. It is still just as easy to enter play mode and get an error in the console, but at least now it will be easier to debug the issue!

There are also a few things that could be done to extend this. For instance, the current implementation doesn’t really care if we actually put the attribute on a string field. Right now we could put it on a bool and the system would draw it as a text field while spamming the console with errors. This can be rectified by checking the type of the field that the attribute is attached to and drawing an error message in the Inspector in the case that the type is something other than a string (Eg. with if(property.propertyType != SerializedPropertyType.String) ).
Additionally, the validation check happens with every OnGUI() call, which can definitely be optimised by checking if the string has changed since the last validation check.

I hope you found this useful! Feel free to copy paste the full code below, or simply download this unitypackage (which also includes additional Rect extension methods) to include the [ValidatedSceneName] attribute in your own project!

SOURCE CODE

(place this in a non-editor folder)

(place this in an editor folder)

EXTENSION METHODS USED IN THIS EXAMPLE