Is "Recompile during Playmode" supported or not?

There’s a preferences item called “Script Changes While Playing” with the option to “Recompile and Continue Playing”. This sounds like a nice feature, but it feels abandoned.

The two other options make sense depending on personal taste. We can either have playmode stop when scripts are recompiled or delay recompiling until playmode is exited. Both are valid options and work well 99.9% of the time.

But the third option, compiling scripts and continuing playmode seems like it won’t ever work. As a user, I would have to ensure that all of my scripts serialize their complete state. Either by using only serializable member variables or by restoring objects during OnEnable, for example. All of this is a lot of extra work, but it’s possible and can be immensely beneficial to testing and iterating. Basically, changing scripts while playing the game can alleviate many different issues such as long enter playmode times or generally avoid having to play portions of the game or investing in additional testing/debugging logic.

However, any chance of implementing recompile during playmode is blocked by Unity provided components. I can’t say for certain which these are, but basically, whenever I try to use recompile during playmode I get a spew of warnings like:

Warning Message

The referenced script (Unknown) on this Behaviour is missing!
0x00007ff613a7195c (Unity) StackWalker::GetCurrentCallstack
0x00007ff613a77af9 (Unity) StackWalker::ShowCallstack
0x00007ff614264823 (Unity) GetStacktrace
0x00007ff61515aa6a (Unity) DebugStringToFile
0x00007ff613a12ba8 (Unity) SerializableManagedRef::RebuildMonoInstance
0x00007ff613979c0c (Unity) SerializableManagedRefTransfer::RestoreBackup
0x00007ff613a13221 (Unity) SerializableManagedRefsUtilities::RestoreBackups
0x00007ff61398cc29 (Unity) MonoManager::EndReloadAssembly
0x00007ff61399397d (Unity) MonoManager::ReloadAssembly
0x00007ff614129ea5 (Unity) ReloadAllUsedAssemblies
0x00007ff613e6e254 (Unity) Application::TickTimer
0x00007ff61426a561 (Unity) MainMessageLoop
0x00007ff61426e1f6 (Unity) WinMain
0x00007ff615dca0a2 (Unity) __scrt_common_main_seh
0x00007ffd08657c24 (KERNEL32) BaseThreadInitThunk
0x00007ffd0a26d4d1 (ntdll) RtlUserThreadStart

Alongside a few exceptions caused by UIElements/UI Toolkit and various packages that don’t deal with recompile during playmode. Sometimes, even the Unity UI components break, depending on their setup.

I haven’t investigated all cases, but I can tell that I’ve been trying to convince my team to make scripts recompile in playmode since 2014 but it never worked because after doing the groundwork, we end up blocked by some Unity system that doesn’t support it.

So, what is Unity’s stand on this? Is recompile during playmode supported or not? I actually don’t mind, if the option were removed because it was deemed too much trouble, but if it stays, I think Unity should put in the effort of supporting it with all of the official packages, at least with UI, PostProcessing, and the sort of common runtime features. :wink:

Yeah, it’s pretty maddening. Yes it is supported but no it is de-facto useless. From my experience with it, all variables are returned to their default state and since Start() does not get re-called, nor any other custom level setup you had going, pretty much with any Unity script written any common way that any of the millions of tutorials out there tell you do it, it just won’t work.

I only found out recently that I could turn this “feature” off and my workflow has been so much better ever since.

It’s definitely doable, but requires a lot of care for each variable:

using UnityEngine;

public class LastScriptStanding : MonoBehaviour
{
    // This will survive recompile because it is serializable.
    private float myNumber;

    // This will get lost.
    private Manager manager;
   
    private void OnEnable()
    {
        // But its possible to restore data in OnEnable.
        manager = new Manager();
    }

    private void Update()
    {
         myNumber = manager.Do(myNumber);
    }

    public class Manager
    {
        public float Do(float num)
        {
            return num + Time.deltaTime;
        }
    }
}

Kind of like with the new fast Enter Playmode behaviour. If static variables are not reset before starting the game, all scripts need to do it in Awake, OnEnable or Start and also make sure to unsubscribe from any static events in OnDisable or OnDestroy.

I usually just construct some stuff to let me fast-hot-quick test whatever I’m working on.

Usually I make it only appear #if UNITY_EDITOR and that gets me in and out.

Well I did full circle on the internet trying to find an answer to this also, including stumbling across this other post by you four years ago https://discussions.unity.com/t/615981

So in short, the answer is hot reloading is effectively redundant because Unity itself natively does not support it? Would this be the best approach for a new developer like me?

Even if you manage to hack your way with serializing everything, or writing hacky OnEnable events to capture the Hot Reload entry, which all add performance overhead to the final build, your still hoping any component Unity or third party your using doesnt die on the hot reload.

It seems this ‘feature’ has been in Unity for a long time, but never fully adopted. Now recently we have Scene/Domain reload features for play mode, I wonder if DOTS will eventually merge all this together.

For newcomers, I’d advise against hot reloading (script recompile or enter play mode without assembly reload), simply because it really doesn’t feel as robust or convenient to use as most other Unity features.

Personally, I also opened this new thread as a little reminder to Unity, that I’d still be interested in using these features, but they seem to not really commit to them. If I start prototyping in an empty project it starts off great, but after importing TextMeshPro, Cinemachine, or a couple of other packages, it all falls apart and I stop trying to make it work, so we never got to recompile or no-assembly-reload for my real company projects.

So the core problem is Script recompiling does not work when using Unity’s own components. As a newcomer I would like to design my projects in this way, start with good code design patterns that support this feature but it seems like Id hit a brick wall because of Unitys native component support for it.

Id too appreciate if someone from Unity could elaborate on why Unity supports this feature through preferences [Recompile & continue playing], when its native functionality is broken, and appears to have been broken since inception.

Are there any known issues with disabling domain and scene reload aside from needing to design your code to reset statics/static events? This is another design pattern I wish to adapt to gain the speed benefits.

I don’t have issuetracker IDs to quote, but my team had several issues with TextMeshPro und Cinemachine, which basically resulted in NullReferences being thrown if domain reload was disabled. We’ve reported some of them, but others are still on the TODO list.

Try it out on your end, but just a fair warning that you could end up investing a lot of time making your own code handle these situations gracefully and then end up not using it because of Unity or third-party code. I’m complaining about builtin/standard packages here, but let’s not even talk about the Asset Store or open source solutions. It feels like nobody is using hot reloading. Again, too bad, I’m a fan of the idea, but well.

If the Manager is derived from UnityEngine.Object, then it will not be lost.
Also, if Manager is NOT derived from UnityEngine.Object then it’s possible to preserve it by using the [Serializable] attribute (with caveats explained in the article below).

Here is a great article about Unity’s serialization and hot reloading:
https://gist.github.com/cobbpg/a74c8a5359554eb3daa5