Extract Editor functions into seperate script

Hi, I want to seperate a mix-mash script into a build / runtime script and editor script, but I have difficulties getting the correct method calls at the correct moments. How would you approach this?

Take a look at my Init() function for example:

        private async void Init()
        {
            if (_initialized) return;
            WebView = Web.CreateWebView();
#if UNITY_EDITOR
            await EditorInit();
#endif

            // Inject PageLoadScrips from properties
            if (HideScrollbars) AddPageLoadScript(HideScrollbarsJS);

            WebView.PageLoadScripts.AddRange(_pageLoadScripts);
            Native2DWebView = WebView as IWithNative2DMode;
            Rect webViewSpace = GetAspectRatioRect(GetViewportRect(Viewport), AspectRatio);
            Native2DWebView?.InitInNative2DMode(webViewSpace);

            if (!string.IsNullOrEmpty(InitialUrl))
                WebView.LoadUrl(InitialUrl);

            _initialized = true;
            WebView.LoadProgressChanged += OnLoadProgressChanged;
        }

You can see that the Editor code must be called after the WebView was created, but before the WebView.LoadUrl() function is triggered. For now I have the wildest #if UNITY_EDITOR inside this script and it really bugs me. But I can’t find a way to seperate editor code into a seperate class like that.
The editor code on Init() won’t be called at the right time, and the runtime script also can’t call it, since the Editor Code is in another non-linked assembly. The only thing I could think of is to add a public event at this position that is only used by the editor script, but more confusing for anyone using this class…

This Property illustrates my problem also very good:

        public RectTransform Viewport
        {
            get
            {
                if (!viewport)
                    viewport = transform.ToRectTransform();

                return viewport;
            }
            set
            {
                viewport = value;
#if UNITY_EDITOR
                _editorWebViewTrans.SetParent(Viewport.transform, false);
#endif
            }
        }

Any suggestions on how to do this? I might stick with all these compiler tags if I can’t get this refactored.

I like partial classes for this. It keeps the noise down in your main runtime class. My base Datasack class is here:

https://github.com/kurtdekker/datasacks/blob/master/datasacks/Assets/Datasack/Core/Datasack.cs

And here is its custom inspector, plus a few more bits:

https://github.com/kurtdekker/datasacks/blob/master/datasacks/Assets/Datasack/Core/DatasackInspector.cs

That one class is chopped up into a bunch of files, giving nice simple compile-time extensibility and modularity in an AOT environment that plays well with Unity’s GUID system by not having 27 derived variants of a simple data object.

Also If you don’t like conditionals inside a method (which I also don’t really like) an alternative is to simply swap out the whole method that is called with a stub. So the calling code stays the same but the actual method with editor dependencies is simply replaced with an empty method when building. So in your case you may want to replace the “EditorInit” method. The same could be done for your SetParent code, though you would have to create another method you could call that you can replace.

A cleaner approach is probably the Conditional attribute. Though as far as I remember in the past it wasn’t supported. But I’m fairly sure Unity now supports it. Also it only works on method that has a return type of void. So your async method would not work. There are some workarounds, but those are not that pretty either.

1 Like

@Kurt-Dekker
Hm, I guess I could move the bigger editor block into a partial class, but there are quite some sections in the runtime code that would call these methods, surrounded in conditions. I see this in your example too. I might just keep it how it is. Maybe if it becomes more code I might move it.

@Bunny83
Well this would mean duplicated code, which also has to be maintained all the time, which is worse in my opinion.

I must admit, the way it is now is not really wrong, but it hurts my eyes in a way to see the editor code hacked into the runtime classes. But the way it must be connected with the runtime stuff is just too stict I think. Maybe its ok to have it how it is right now ^^