So I’ve been implementing game editor needs by extending the Unity Editor, and for many of the tasks I’ve wanted to do I’ve needed to have stuff that runs anytime after the level changes to do some data fixup - to accomplish that, I’ve been (ab)using the “Update” call on monobehavior derived classes with the “ExecuteInEditMode” attribute on them. It’s been working fine, until I tried to build a pc player of the game, at which I point I get told that the type or namespace “UnityEditor” cannot be found from the scripts that have monobehaviors for my game objects that also implement the Editor code that runs when the objects update.
I naturally tried taking the code that needs UnityEditor, and moving it over to files in the “Editor” folder, which I get no complaints about when trying to build the player. However when I try to call the functions with the code I moved to my editor classes from the “Update” call of my monobehavior stuff, I now get errors that the Editor class’s names “do not exist in the current context” (i.e. I took code from the “Scripts/RailDirector” file that used “UnityEditor” funcs, and moved it to static funcs in “Editor/RailDirectorEditor”, but the “RailDirector” class can’t access any members of the class “RailDirectorEditor”), so apparently I can’t have my code outside of the Editor folder call the code inside of it.
So it seems the only option I am aware of is to make all the customer editor things I’m doing now run from my Editor subfolder code, but I don’t see any way to get any editor code to run unless an object that uses the editor class is selected (i.e. through a “Editor” derived class’ “OnSceneGui” or “OnInspectorGUI” for the object it is “CustomEditor” for) or through some EditorWindow window being active. The problem with both of those things is they very frequently are not active, so all the fix up I need usually doesn’t happen and it lead to very confusing behavior.
There are of course some delegates I can try and access (EditorApplication.update and the undocumented SceneView.onSceneGUIDelegate) but they aren’t exactly what I really want (a callback when the level is changed) and I still need to figure out when the heck I am supposed to actually hook up these 2 delegates.
So basically what I would love to know of is either some way to get my custom editor code getting called without any of my objects having to be selected or my custom windows having to be activated, or some way in which I can make calls to Editor code from non-Editor code but still be able to build the game.
anybody got any suggestions or fixes? thanks!
I won’t claim to have understood all the details of your post, but what you’re describing sounds similar to a problem I had to solve for my level editor as well, that is, ‘compiling’ the level if needed before playback starts.
I don’t have the reference (or my code) in front of me right now, but I used one of the callbacks that the editor provides for this. It’s something like ‘play state changed’ - you should be able to find it if you check the docs for Application and/or the various editor classes. (The whole thing is a little hacky, but it seems to work ok.)
Thanks Jesse,
I think what you are referring to is the delegate EditorApplication.playmodeStateChanged and what you are suggesting is rather than doing the fix up any time the level changes, do the fixup before the level is played
unfortunately that doesn’t really work for me - one of the things my editor does is a lot of live preview of the data through a camera preview, gizmos and rendered geometry as the level data is being modified, to make it so it’s easy to make the level data and verify it’s correct while editing it, making a play cycle required for that would defeat the whole purpose.
I’m curious though - when do you hook up your EditorApplication.playmodeStateChanged delegate function?
I’ve had some minor annoyances with all my delegates being disconnected when things recompile, and having to count on monobehavior.update being called to reconnect them, which means my delegates aren’t attached until I change the level, and I also needed to implement some code to not attach a delegate when already attached, so having a better place to connect delegates up for editor purposes would be nice.
Another option is to wrap your functions in preprocessor commands.
Change:
using UnityEditor;
to
#if UNITY_EDITOR
using UnityEditor;
#endif
And I’m not sure if it’s necessary, but you may also need to change
[ExecuteInEditMode]
public void MyFunc() { }
to
[ExecuteInEditMode]
[System.Diagnostics.Conditional(“UNITY_EDITOR”)]
public void MyFunc() { }
The # commands will compile a different set of code that excludes the editor namespace when compiling to non editor platforms. And the later will strip out the function from the build when not building to UNITY_EDITOR. The UNITY_EDITOR command is a Preprocessor define that is defined by Unity to help assist with platform specific builds.
Oops, I didn’t make the connection that you wanted this to be independent of any particular object being selected (my system does rely on an object being selected, so it’s probably not really relevant to the problem you’re trying to solve).