Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

Feedback Is "Recompile during Playmode" supported or not?

Discussion in 'Editor & General Support' started by Xarbrough, Feb 12, 2021.

  1. Xarbrough

    Xarbrough

    Joined:
    Dec 11, 2014
    Posts:
    1,184
    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:

    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<SerializableManagedRefBackupGenerator>
    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. ;)
     
  2. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,756
    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.
     
    Walter_Hulsebos likes this.
  3. PraetorBlue

    PraetorBlue

    Joined:
    Dec 13, 2012
    Posts:
    7,722
    I only found out recently that I could turn this "feature" off and my workflow has been so much better ever since.
     
  4. Xarbrough

    Xarbrough

    Joined:
    Dec 11, 2014
    Posts:
    1,184
    It's definitely doable, but requires a lot of care for each variable:

    Code (CSharp):
    1. using UnityEngine;
    2.  
    3. public class LastScriptStanding : MonoBehaviour
    4. {
    5.     // This will survive recompile because it is serializable.
    6.     private float myNumber;
    7.  
    8.     // This will get lost.
    9.     private Manager manager;
    10.    
    11.     private void OnEnable()
    12.     {
    13.         // But its possible to restore data in OnEnable.
    14.         manager = new Manager();
    15.     }
    16.  
    17.     private void Update()
    18.     {
    19.          myNumber = manager.Do(myNumber);
    20.     }
    21.  
    22.     public class Manager
    23.     {
    24.         public float Do(float num)
    25.         {
    26.             return num + Time.deltaTime;
    27.         }
    28.     }
    29. }
    30.  
    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.
     
  5. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,756
    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.
     
  6. timfrombriz

    timfrombriz

    Joined:
    Jun 23, 2014
    Posts:
    30
    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://forum.unity.com/threads/wri...es-a-recompile-feasible-and-practical.384840/

    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.
     
    Xarbrough likes this.
  7. Xarbrough

    Xarbrough

    Joined:
    Dec 11, 2014
    Posts:
    1,184
    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.
     
  8. timfrombriz

    timfrombriz

    Joined:
    Jun 23, 2014
    Posts:
    30
    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.
     
    Last edited: Mar 22, 2021
  9. timfrombriz

    timfrombriz

    Joined:
    Jun 23, 2014
    Posts:
    30
    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.
     
  10. Xarbrough

    Xarbrough

    Joined:
    Dec 11, 2014
    Posts:
    1,184
    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.
     
  11. KyryloKuzyk

    KyryloKuzyk

    Joined:
    Nov 4, 2013
    Posts:
    1,070
    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
     
    Last edited: May 7, 2022
    Tymianek and Elapotp like this.