Search Unity

  1. Unity Asset Manager is now available in public beta. Try it out now and join the conversation here in the forums.
    Dismiss Notice

Insanely Fast Enter-to-Play mode

Discussion in '2019.3 Beta' started by chrisk, Jun 27, 2019.

  1. chrisk

    chrisk

    Joined:
    Jan 23, 2009
    Posts:
    704
    The Fast Enter-to-Play mode is probably the most exciting feature in years and it will probably save months of waiting time during the project development cycle on our team.

    It should've been the part of the Unity from the beginning but I'm still happy that Unity finally recognizes.
    Unity routinely is asking for feedback but it really makes me sick whenever I hear them.
    It's not like we didn't give Unity enough feedbacks but Unity does not listen and take actions from the user's perspective.

    It's late nonetheless it's a good start and I hope it continues.

    The doc ( https://docs.google.com/document/d/...j-Pd9M71Uz9dc-dg4/edit#heading=h.2gazcsgmxkub ) is really good explaining how thing will change. However, it still lacks explaining how to work around it. If there is one asset causing a problem, this feature will not be usable, therefore I would like Unity to help the asset developers to adopt the new way of entering the play mode as fast/easily as possible. Having some use-cases where it can cause problems and how to work around it would be useful. And in order to do that, it will help to have a new API/Attributes, such as InitializeOnPlayToEnter(and perhaps ExitOnPlayToEnter) and etc.

    This is the best thing ever happened in a long time and I can't wait until 2019.3 releases. It can immediately save many hours, but adopting the new style will take a while, therefore we need to move as soon as we can.

    I really hope this feature still be part of 2019.2 preview package. It will make the adoption 3-4 months earlier. This is still an optional preview that won't break if not opt-in, right? Yeah, it will require some core changes but if users do not opt-in, just make the code path to take the old. I don't think it's that hard and I don't see any harm doing it.

    I'll really appreciate in advance and it will make me think twice about Unity if you can push it. Look how many canceled project or delayed projects we had in the past? Can you please make it something to happen earlier just for once?

    Cheers!
     
    Last edited: Jun 28, 2019
    CodeRonnie, Immu, aschtronaut and 3 others like this.
  2. alexeyzakharov likes this.
  3. alexeyzakharov

    alexeyzakharov

    Joined:
    Jul 2, 2014
    Posts:
    508
    Thank you for taking time to read and the suggestions! I'll add examples with issues to the doc.

    We've been considering and are still considering adding an attribute. Having
    [InitializeOnEnteredPlayMode]
    which executes method
    static void MyPlaymodeSetup(EnterPlayModeOptions options)
    totally makes sense.
    However, as mentioned above we already have https://docs.unity3d.com/ScriptReference/EditorApplication-playModeStateChanged.html event which can be used to clear the state. In some cases is has to be used in combination with other APIs which makes detection not simple (at all). Partially it is because PlayModeStateChange.EnteredPlayMode is fired too late after 2 updates when game code is technically already in playmode. I would rather fix this behavior first - we are looking if it is safe - and if not add an attribute.
     
    firstuser, Alverik, Havokki and 3 others like this.
  4. Peter77

    Peter77

    QA Jesus

    Joined:
    Jun 12, 2013
    Posts:
    6,620
    In this case, the boiler-plate code would be more right?

    Rather than being able to just do:
    Code (CSharp):
    1. class Cat : MonoBehaviour
    2. {
    3.     static int s_TotalMeows;
    4.    
    5.     [InitializeOnEnteredPlayMode]
    6.     static void OnEnteredPlayMode()
    7.     {
    8.         s_TotalMeows = 0;
    9.     }
    10. }
    We would need to have something like:
    Code (CSharp):
    1. class Cat : MonoBehaviour
    2. {
    3.     static int s_TotalMeows;
    4.  
    5. #if UNITY_EDITOR
    6.     static void OnEnteredPlayMode(UnityEditor.PlayModeStateChange value)
    7.     {
    8.         if (value == UnityEditor.PlayModeStateChange.ExitingEditMode)
    9.         {
    10.             s_TotalMeows = 0;
    11.         }
    12.     }
    13.  
    14.     [UnityEditor.InitializeOnLoadMethod]
    15.     static void RegisterCallback()
    16.     {
    17.         UnityEditor.EditorApplication.playModeStateChanged += OnEnteredPlayMode;
    18.     }
    19. #endif
    20. }
    Would I also need to unregister the playModeStateChanged callback with this new feature?
     
  5. Prodigga

    Prodigga

    Joined:
    Apr 13, 2011
    Posts:
    1,123
    I noticed according to the document the scene reset does not re-deserialise the objects in the scene. It just invokes awake and on enable. Consider the scenario where I have an object in my scene that has a behaviour that references another object. I hit play, and while the game is running I change the reference on that behaviour to a 3rd game object. When I hit stop, my behaviour isn't "reset"? IE it'll be referencing the 3rd object? Am I understanding this right?
     
  6. brunocoimbra

    brunocoimbra

    Joined:
    Sep 2, 2015
    Posts:
    679
    If I understood correctly, when stopping it will still reset, as it backups the scene before playing, what does not occurs is a reload when entering play mode, so if you change a field of an object while in edit mode (for example, using the ExecuteInEditMode attribute) this field will not reset automatically when entering play mode.
     
    alexeyzakharov likes this.
  7. Baste

    Baste

    Joined:
    Jan 24, 2013
    Posts:
    6,338
    When you say that you "backup current scenes" - what does that mean? If none of the current scenes are dirty, this should take zero time, since they can be loaded from file, right?
     
    alexeyzakharov likes this.
  8. Hyp-X

    Hyp-X

    Joined:
    Jun 24, 2015
    Posts:
    438
    I submitted a bug: (Case 1168733) Fast Enter Playmode compatibility issue

    The issue is that the default values can change in some circumstances.
    This is happening in playmode only scripts so this is not an issue of something remaining from editor mode user code.

    Here's a test script:

    Code (CSharp):
    1. using UnityEngine;
    2.  
    3. public class PlayModeTest : MonoBehaviour
    4. {
    5.     private Vector3[] testVector;
    6.  
    7.     private void Start()
    8.     {
    9.         if (testVector == null)
    10.             Debug.Log("Start: testVector is null");
    11.         else
    12.             Debug.Log("Start: testVector is not null");
    13.     }
    14. }
    15.  
    If you trigger a recompile, THEN enter playmode it will report the variable as not null.
    Subsequent playmode entries, or if you manually reload the scene than the variable will be null.

    Found it in real production code - was quite unexpected even after reading the entire doc.
     
  9. brunocoimbra

    brunocoimbra

    Joined:
    Sep 2, 2015
    Posts:
    679
    Not sure if the reply was to me, but if yes, I meant exactly that, as scenes with modifications needs to be backed up. If is doesn't have modification it will not take "zero time" as it still requires to load from file, but it should be back to a "before play mode" state.
     
  10. alexeyzakharov

    alexeyzakharov

    Joined:
    Jul 2, 2014
    Posts:
    508
    Thanks for the bug!
    It is more likely scene reset fault when we soft reset alive scene objects. Could you please enable normal scene reload as a workaround.
     
  11. alexeyzakharov

    alexeyzakharov

    Joined:
    Jul 2, 2014
    Posts:
    508
    InitializeOnLoadMethod is called only with the domain reload, so no, there is no need to unregister because there will be no second registration for the domain lifetime.
    But yes, I like personally attributes way - less boilerplate code - I'll add it.
     
    brunocoimbra and Peter77 like this.
  12. alexeyzakharov

    alexeyzakharov

    Joined:
    Jul 2, 2014
    Posts:
    508
    When you exit playmode the scene is destroyed and reloaded from the backup, so you get unaltered scene state which was before you hit play. The exit playmode behavior stays exactly the same.
     
    radiantboy and brunocoimbra like this.
  13. alexeyzakharov

    alexeyzakharov

    Joined:
    Jul 2, 2014
    Posts:
    508
    Yes, you are right. If scene is not dirty backup is pointing to the original scene file.
    (I'll add it to the doc, thanks for pointing this out)
     
  14. alexeyzakharov

    alexeyzakharov

    Joined:
    Jul 2, 2014
    Posts:
    508
    Would you use such boilerplate to catch EnterPlaymode and do reset or other Editor work for game code?
    Code (CSharp):
    1.  
    2. using UnityEngine;
    3. #if UNITY_EDITOR
    4. using UnityEditor;
    5. #endif // UNITY_EDITOR
    6. public class InitializeOnEnterPlayModeScript : MonoBehaviour
    7. {
    8.     public static int GameStaticValue = 42;
    9. #if UNITY_EDITOR
    10.     [InitializeOnEnterPlayMode]
    11.     static void InitializeOnEnterPlayModeGameMethod(EnterPlayModeOptions options)
    12.     {
    13.         if (!options.HasFlag(EnterPlayModeOptions.DisableDomainReload))
    14.             return;
    15.         GameStaticValue = 42;
    16.     }
    17. #endif // UNITY_EDITOR
    18. }
     
    lacas8282 likes this.
  15. Baste

    Baste

    Joined:
    Jan 24, 2013
    Posts:
    6,338
    In that case you don't want the editor code to be different from the play mode code. We'd need an attribute that fires either when we enter play mode, or when the build is launched.

    In your example, and in @Peter77's, having that code in builds would be harmless. For something like a must-be-initialized-at-startup-singleton, it's necessary for the code to run in builds.

    I think the #if boilerplate should be reserved for instances where you need different things to happen from builds to play mode.
     
  16. Peter77

    Peter77

    QA Jesus

    Joined:
    Jun 12, 2013
    Posts:
    6,620
    I think the initialization code is often the same, whether you press play in the editor or if you actually start a player. At least in my code base. Thus I would prefer if we can use the same initialization method in both cases, to avoid having different initialization behaviour.

    I think of something along the lines:
    Code (CSharp):
    1. public class InitializeOnEnterPlayModeScript : MonoBehaviour
    2. {
    3.     public static int GameStaticValue;
    4.  
    5.     [RuntimeInitializeOnLoadMethod]
    6.     [UnityEngine.InitializeOnEnterPlayMode]
    7.     static void InitializeOnEnterPlayModeGameMethod()
    8.     {
    9.         GameStaticValue = 42;
    10.     }
    11. }
     
  17. alexeyzakharov

    alexeyzakharov

    Joined:
    Jul 2, 2014
    Posts:
    508
    Thanks for the replies!
    Yes, agree. For this we have
    RuntimeInitializeOnLoadMethod
    attribute which is executed both in the Player and Editor during the scene load and doesn't depend on domain reload happened or not.
    And now that @Peter77 mentioned it in the example I understand that there is no need to use InitializeOnEnterPlayMode for game scripts and thus complement
    RuntimeInitializeOnLoadMethod
    with
    InitializeOnEnterPlayMode
    attribute as it is called anyway. (Although
    [RuntimeInitializeOnLoadMethod([URL='https://docs.unity3d.com/ScriptReference/RuntimeInitializeLoadType.BeforeSceneLoad.html']RuntimeInitializeLoadType.BeforeSceneLoad[/URL])]
    should be used to make sure init happens before any Awake or OnEnable of game scripts).
    I shouldn't have used #if probably, sorry for confusion - that was a copy paste from a test script :)

    The main reason for
    InitializeOnEnterPlayMode
    to exist is to provide a better entry point for resetting Editor scripts.
    During Enter Play Mode there is a specific order in which magic callbacks are called for Editor scripts. And there is no way to reset singletons before the first Update happens due to
    EditorApplication.playModeStateChanged
    callback being called after the second Update - you basically need to use boilerplate in a form of Editor script with the lowest order index.
    There is
    InitializeOnLoad
    attribute which does custom initialization for the Editor code, unfortunately we can't use it in the path without domain reload as it breaks scripting state in 100% of cases we looked at.
    InitializeOnEnterPlayMode
    could be used to compliment
    InitializeOnLoad
    . However it is flexibility vs usability question (and somewhat performance) :)
    Option 1:
    Code (CSharp):
    1. public class MayEditorClass :
    2. {
    3.     public static int StaticValue;
    4.     [InitializeOnLoadMethod]
    5.     static void MyInitializeOnLoadMethod()
    6.     {
    7.         StaticValue = 42;
    8.     }
    9.     [InitializeOnEnterPlayMode]
    10.     static void MyInitializeOnEnterPlayModeMethod(EnterPlayModeOptions options)
    11.     {
    12.         if (options.HasFlag(EnterPlayModeOptions.DisableDomainReload))
    13.             MyInitializeOnLoadMethod();
    14.     }
    15. }
    Option 2:
    Code (CSharp):
    1. public class MayEditorClass :
    2. {
    3.     public static int StaticValue;
    4.  
    5.     [InitializeOnLoadMethod]
    6.     [InitializeOnEnterPlayMode]
    7.     static void MyInitializeMethod()
    8.     {
    9.         StaticValue = 42;
    10.     }
    11. }
    In the last example InitializeOnLoadMethod is called after domain reload, so if we choose it we have to make sure that a set of methods marked with InitializeOnLoadMethod is not called during processing of InitializeOnEnterPlayMode methods to be able to use InitializeOnEnterPlayMode universally for any Play Mode configuration.
     
  18. AlkisFortuneFish

    AlkisFortuneFish

    Joined:
    Apr 26, 2013
    Posts:
    973
    Been trying this out and found Addressables throwing a bit of a wobbly with it. Submitted a bug report with a repro, as well as a thread here.
     
  19. chrisk

    chrisk

    Joined:
    Jan 23, 2009
    Posts:
    704
    I'm still waiting for 2019.3 to release asap to push other asset developers but I'm getting a bit worried.

    Since my wish wasn't granted (i.g., release this mode with 2019.2 as a preview so that we can test early on), I expect Unity will do thorough testing that all of Unity packages work out-of-box when it's released in 2019.3, so that Unity itself is not the problem for the adoption.
    I hope it's not too much to ask and I would be very disappointed if Unity packages themselves are not working properly.
     
    andreiagmu likes this.
  20. Hyp-X

    Hyp-X

    Joined:
    Jun 24, 2015
    Posts:
    438
    I got a reply from QA that
    Now let me be clear:
    - I know why the issue appears.
    - I know how to work around it, so I don't need more help on that
    - I think the behavior is anything but expected.
    - It will cause a lot of headaches and random bugs for a lot of developers
    - Most people will not understand why it is happening and will see it as random failure.

    So in this case I filed the bug to be helpful, not just for ourselves.

    Just so you know, the generic workaround that WE found is:
    If you have a
    private
    or
    internal
    field, that is a reference type (arrays, List<>, or a class marked [Serializable]), starting from 2019.3 you should mark them [NonSerialized]
    Otherwise you might see seemingly random issues, that didn't happen in previous Unity versions.
     
  21. Baste

    Baste

    Joined:
    Jan 24, 2013
    Posts:
    6,338
    When you get an "our developers have decided that this behaviour is expected" reply, it seems like 9 times out of 10 it's QA not understanding your issue, and passing on a really bad explanation to the devs.

    Even if it is expected, at least insist that they properly document it. It's pretty annoying that every time I get back a "is expected" reply, I have to nag them to at least write that down somewhere, as it's not very useful to us end-users if something's expected if that's a secret.
     
  22. AlkisFortuneFish

    AlkisFortuneFish

    Joined:
    Apr 26, 2013
    Posts:
    973
    The only way what is described there is to be "expected" is if they inverted their understanding of what the problem is, something being non-null the second time around.
     
  23. alexeyzakharov

    alexeyzakharov

    Joined:
    Jul 2, 2014
    Posts:
    508
    I looked at the issue as well and think that resolution notes describe the reason very well.
    Basically this happens due to domain reload serializing list/array references as empty arrays. And thus keeping same objects alive on enter playmode keeps same field values which are non-null anymore.

    I've tired to reconstruct the C# class instances, but that led to necessity of restoring values of other serialized fields which can be done only by reading those from a backup and defeats the purpose of "soft" reset of already loaded scene.
    So in my opinion the right fix would be to fix unexpected null->empty array conversion during domain reload. And that is quite risky to do - from overall stability perspective change in settled behavior to accommodate experimental feature needs is no go.

    For now I can only consider the following scenarios 1) update domain reload serialization behavior for arrays/lists if the feature is on, 2) if skipping scene reload uncovers other fundamental issues remove it.
     
    SugoiDev and brunocoimbra like this.
  24. alexeyzakharov

    alexeyzakharov

    Joined:
    Jul 2, 2014
    Posts:
    508
    Did you also get a resolution notes with the QA reply? If not there might be some process issue - the developer wrote why and it is displayed on issuestracker.
    I really appreciate reporting the issue you've found and for now I've mentioned it in the forum post and it will appear in manuals soonish.
     
  25. AlkisFortuneFish

    AlkisFortuneFish

    Joined:
    Apr 26, 2013
    Posts:
    973
    Yeah, but this seems to have an extra bit that is rather unexpected:

    * Reload the domain
    * Restores array as non-null
    * Enter play mode
    * Array is not null
    * Exit play mode
    * Enter play mode
    * Array is null

    What is unexpected here is the inconsistency.

    From doing a lot of editor tooling, I fully expect private arrays to be serialized and deserialized on assembly reload, hence them being non-null after reload, but what is setting the array instance to null on exiting and re-entering play mode with scene reload and assembly reload off?
     
    TextusGames and alexeyzakharov like this.
  26. rastlin

    rastlin

    Joined:
    Jun 5, 2017
    Posts:
    127
    Please stop advocating for more static classes/methods, this is really bad design.

    If you want to take advantage of this feature, you should construct your dependency tree on Awake() of a single entry point to your game, this way once you hit enter play mode, your dependency tree will be re-generated.
     
    alexeyzakharov likes this.
  27. alexeyzakharov

    alexeyzakharov

    Joined:
    Jul 2, 2014
    Posts:
    508
    On exiting play mode we load scene from backup and that is what restoring the GO/components state.
    Scene load (non additive) consist of:
    1. Destroy current scene GO - C# script instances are destroyed.
    2. Read scene from disk.
    3. Create new C# script instances for MB/SO - ctor is called here.
    4. Deserialize fields.
    5. OnValidate, Awake, OnEnable,....
    #3 is what "fixes" the default script values.
    Yes, this is unexpected for game scripts. However, it was always the case for editor scripts which have to mitigate null->empty array conversion after domain reload in OnEnable or other ways. Perhaps, as @rastlin said if you have another init entry point based on OnEnable/Awake the soft scene reset option should work.
     
  28. Peter77

    Peter77

    QA Jesus

    Joined:
    Jun 12, 2013
    Posts:
    6,620
    I think that's not the issue he is describing. The problem is that the null->empty array conversion does not work the second time you enter playmode, in which case it stays null rather than being converted to an empty array.
     
  29. AlkisFortuneFish

    AlkisFortuneFish

    Joined:
    Apr 26, 2013
    Posts:
    973
    Ah, I see. Yeah, I can see the issue.
     
    alexeyzakharov likes this.
  30. snacktime

    snacktime

    Joined:
    Apr 15, 2013
    Posts:
    3,356
    It would be nice if Unity provided a utility that abstracts initialization/destruction that could be used for code that is used both in and out of Unity and also handles cases like native plugins. It's rather involved to do this correctly and professional teams almost always have shared dll's and likely a few native plugins also.

    This is something that any sane team will do. The docs (and blog post) on this feature are just horrible IMO. Like RuntimeInitializeLoadType.SubsystemRegistration we have no documentation on exactly what that is or where it fires. Then you have an example of RuntimeInitializeOnLoadMethod coupled with Application.quitting. So basically two approaches you could use reset on quit or on initialization. You guys should provide one correct way to handle the flow here with no ambiguity.

    That Unity is pushing this feature pretty hard without providing a sane api for it, is a bit frustrating.
     
  31. TextusGames

    TextusGames

    Joined:
    Dec 8, 2016
    Posts:
    429
    Just tried this feature. Only thing i was need to change is resetting some static variables and events with static method with [RuntimeInitializeOnLoadMethod(beforeSubsistemRegistration)]. And everething seems to work great, enter play mode time is just instant less then 0.5 sec.
     
    Last edited: Jan 10, 2020
  32. julian-moschuering

    julian-moschuering

    Joined:
    Apr 15, 2014
    Posts:
    529
    Another potential candidate for the new play mode options: Don't Garbage Collect Assets. This takes up to 1 second in our project and the development machines don't really need this, at least not on each play switch / load scene call.
    And it takes additional time when the assets get reloaded.
     
    Last edited: Jan 9, 2020
    joshcamas and alexeyzakharov like this.
  33. Tortuap

    Tortuap

    Joined:
    Dec 4, 2013
    Posts:
    137
    @alexeyzakharov, we still have issues with the use of [InitializeOnEnterPlayMode] : as it is not executed once entered Play Mode as [InitializeOnLoadMethod] is, but before it, method calls such as DontDestroyOnLoad are rejected.
    Is it possible to get this fixed ? Or do you see a possible workaround for this ?
     
  34. alexeyzakharov

    alexeyzakharov

    Joined:
    Jul 2, 2014
    Posts:
    508
    What is your usage? Are you doing editor-specific logic update and need to know the actual playmode settings? [RuntimeInitializeOnLoadMethod] is executed after both - would it work?
     
  35. Tortuap

    Tortuap

    Joined:
    Dec 4, 2013
    Posts:
    137
    @alexeyzakharov Yes [RuntimeInitializeOnLoadMethod] will do the trick for me. Thank you.
     
    Last edited: Apr 21, 2020
    alexeyzakharov likes this.
  36. brunocoimbra

    brunocoimbra

    Joined:
    Sep 2, 2015
    Posts:
    679
    Which Unity version are you using? In 2019.3.9 the [RuntimeInitializeOnLoadMethod] is always called.
    upload_2020-4-21_13-11-53.png

    EDIT: just realized you edited your comment when I was replying :rolleyes:
     
    alexeyzakharov likes this.
  37. oscarAbraham

    oscarAbraham

    Joined:
    Jan 7, 2013
    Posts:
    431
    Hi, I really love all the time and mental stability saved by this feature. I have no problem with setting private fields OnEnable/Awake; I think it is very reasonable and I've probably always done it anyway. I have a problem with something related to it though: OnEnable is not called for ScriptableObjects when entering PlayMode. The weirdest thing is that OnDisable does get called when exiting Play Mode, but just once. I realize this is a consequence of SOs not being reconstructed by the Domain Reload, but MonoBehaviours do get their initialization calls, isn't it to be expected that the initialization of SOs is also simulated?

    I imagine a counterargument would probably be that SOs are supposed to be permanent and only get their callbacks when they are created. I'd say that OnEnable gets normally called every time we enter PlayMode and that getting those callbacks with this feature would just make things seem more normal, flow easier. It think it shouldn't break anything for anyone, because the code that would be executed in that moment is already accounted for and even expected by the programmers.

    Or, if this is expected behaviour, could we get a suggestion on the best way to handle this difference that can be very striking? I saw the excellent examples for managing the expected behaviour of static fields and events and I've tried to infer from it what to do, but I'm not sure of what would be the best thing, or even if anything should be done about it. Is one supposed to use the InitializeOnEnteredPlayMode attribute to manually initialize all the SOs that require it? I would really really appreciate any suggestions from anyone. Thank you very much. I hope you all have a very nice day.
     
  38. Baste

    Baste

    Joined:
    Jan 24, 2013
    Posts:
    6,338
    Which ScriptableObjects should get OnEnable callbacks, though? Not every single one in your project, right? Many might not be required for the level you're on, so enabling them doesn't sound like the best idea...
     
    oscarAbraham likes this.
  39. oscarAbraham

    oscarAbraham

    Joined:
    Jan 7, 2013
    Posts:
    431
    Well, at least in Unity 2019.3 all the SOs stored in assets get their OnEnable Called when the domain reloads. I'd expect that if an SO is brought into existence, their OnEnable should be called in that moment. I think that would actually be the most expected moment to be called. Wouldn't you agree with that? It seems to be the way it works, and it seems to be the reason its not being called when there is no Domain Reload. So then, this might be more controversial, I think Unity should try to simulate the creation of all the SOs that already exist when hitting play without Domain Reload, just as MBs are. Because entering play mode should kind of simulate the game being executed from scratch.

    I have no problems with using OnEnable to initialize private fields of SOs because I wouldn't expect to be able to use it to react to state changes made at runtime. Just as I wouldn't put code to react to state changes in OnEnable or Awake in MBs. I think this kinds of methods are to be understood as substitutes for constructor methods. I think that it's pretty natural to think of SOs stored in assets in the project as existing right from the beginning of the game, so I'd expect to be expected to initialize them at the beginning of the game.

    I think I kind of see why you say it's not the best idea to enable SOs that are not being used. I think I disagree a little, though. In part, I disagree because it'd be kind of hard to detect when an unused SO gets referenced dynamically. In part, I disagree because (please forgive me for repeating myself) OnEnable methods are like substitutes for constructors and constructors are called the moment an object is brought into existence.
     
    Last edited: Apr 28, 2020
  40. Baste

    Baste

    Joined:
    Jan 24, 2013
    Posts:
    6,338
    Well, the whole point of skipping domain reload - the only point - is for the editor to do less so we can iterate faster. I really don't want a whole extra code-path that does a bunch of things that slows me down again,
     
  41. oscarAbraham

    oscarAbraham

    Joined:
    Jan 7, 2013
    Posts:
    431
    But, running the initialization methods on SOs that already exist wouldn't be very expensive, wouldn't it? Specially if you're not using those calls anyway. Those calls are already made on all MBs and Components, and there are a lot more (Awake, Start and OnEnable) there. And they usually do a lot more with their initialization calls. Maybe it is even the same code path anyway, because SOs are said to be the same as MBs internally. Calling the initialization method for SOs should be far from comparable to reloading the whole domain. I mean, it would bring a lot more consistency, and I don't see why it would slow things down in a way that is significant.

    Edit.
    Also, if it is not to be done that way. Wouldn't it be better if we got some official ideas on how to manually replicate the way things behave with Domain Reloading, just as we got them for static fields and events? Because, right now, without an official word on this, I'm not even sure if this is something that I should fix myself or if it's an unintended effect that is going to be fixed by Unity.
     
    Last edited: Apr 28, 2020
    toya-vesta and alexeyzakharov like this.
  42. CPlusSharp22

    CPlusSharp22

    Joined:
    Dec 1, 2012
    Posts:
    111
    I complete agree with this.
    Plus on large projects with multiple assemblies/plugins and a ton of code, identifying and figuring out ways to clear/reset statics is mind boggling!
     
    firstuser likes this.
  43. oscarAbraham

    oscarAbraham

    Joined:
    Jan 7, 2013
    Posts:
    431
    Hi, it's me again, I'm sorry to bother. I was just refactoring my solution to the problem I have with SOs ctor not being called, and I realized: if the garbage collector ran after C# instances are destroyed, shouldn't that make the SO objects that where used be unloaded too? And that way the SOs in use would be loaded again when step 3 happens, which would call their initialization methods? I know it's probably not important in the great scheme of things, but it's really constantly getting in my way? Is there any way I can get a hook or an event between step 1 and 2, to try unloading the SOs there?
     
  44. firstuser

    firstuser

    Joined:
    May 5, 2016
    Posts:
    147
    Very exciting feature, would make a major impact on productivity across the board.

    I think we can discuss endlessly how to configure it manually but..
    ultimately I don't think this will be a useful feature until there is an "auto-magic" way to use it without broad changes to existing codebase.

    It's unrealistic to maintain changes in dozens of third party assets across projects

    It's also unrealistic to expect everyone to update their assets (see UPM progress for example), maybe a couple of the newest will over time but even that can be easily a 3+ years transition.

    The main thing I'd like to know from Unity is if this is on the horizon or if it's technically impossible so that we can make decisions asap about how to move forward.
     
    toya-vesta likes this.
  45. herra_lehtiniemi

    herra_lehtiniemi

    Joined:
    Feb 12, 2017
    Posts:
    133
    At which point in this process is EditorApplicationPlaymodeChanged for PlayModeStateChange.EnteredEditMode triggered? I tried use this in the following scenario:
    -My application works in Editor mode, but I have a component that requires going to Play mode for a while
    -I set a boolean and enter Play mode - the component sees from the boolean that it needs to run
    -When it's finished, it needs to deliver a message back to Editor mode that it did the job and won't trigger again if I would enter play mode manually again.
    -> I made this component set a callback to for EnterEditMode and set a boolean to false on the callback, like this:
    Code (CSharp):
    1.     private void _ResetRecording(PlayModeStateChange newPlayMode) {
    2.         Debug.Log("ResetRecording called.");
    3.         if (newPlayMode == PlayModeStateChange.EnteredEditMode) {
    4.             Debug.Log("ResetRecording triggered, current value is " + _shouldStartRecording);
    5.             _shouldStartRecording = false;
    6.             EditorApplication.playModeStateChanged -= _ResetRecording;
    7.         }
    8.     }
    However, when I'm back in editor mode, _shouldStartRecording is still true.

    At which point is EnteredEditMode triggered? It seems this is done before deserialization? If so, is there anything that's executed AFTER everything else is done? I noticed you mentioned [InitializeOnEnterPlayMode], but I couldn't find a similar [InitializeOnEnterEditMode].
     
  46. Tortuap

    Tortuap

    Joined:
    Dec 4, 2013
    Posts:
    137
    firstuser likes this.
  47. herra_lehtiniemi

    herra_lehtiniemi

    Joined:
    Feb 12, 2017
    Posts:
    133
  48. Peter77

    Peter77

    QA Jesus

    Joined:
    Jun 12, 2013
    Posts:
    6,620
    Hey Alex :)

    Any chance you could add an
    order
    argument to
    RuntimeInitializeOnLoadMethod
    , just like the
    DefaultExecutionOrder
    attribute has?

    I often end up having things depending on a specific initialization order and RuntimeInitializeOnLoadMethod makes it a bit hard at the moment. It does support a few loadType's, but it's unclear/undocumented in what order they are called. It's also not as easy to grasp than just having an
    order
    argument.

    Code (CSharp):
    1. [RuntimeInitializeOnLoadMethod(-10)]
    2. static void A()
    3. {
    4.     Debug.Log("A");
    5. }
    6.  
    7. [RuntimeInitializeOnLoadMethod(0)]
    8. static void B()
    9. {
    10.     Debug.Log("B");
    11. }
    12.  
    13. [RuntimeInitializeOnLoadMethod(10)]
    14. static void C()
    15. {
    16.     Debug.Log("C");
    17. }
    The code above should be executed in order from lowest to highest. The output should be:
    Code (CSharp):
    1. A
    2. B
    3. C

    An useful bonus-feature, in case it's not supported yet. If two methods use the same order, for example:
    Code (CSharp):
    1. [RuntimeInitializeOnLoadMethod]
    2. static void A()
    3. {
    4.     Debug.Log("A");
    5. }
    6.  
    7. [RuntimeInitializeOnLoadMethod]
    8. static void B()
    9. {
    10.     Debug.Log("B");
    11. }
    To make things deterministic, it could use the full type + method name (you most likely have a better idea) to sort callbacks within the same order value, to make sure that callbacks with the same order don't get fired in random order.

    Any thoughts?
     
    SugoiDev, AlkisFortuneFish and Wokky like this.
  49. Peter77

    Peter77

    QA Jesus

    Joined:
    Jun 12, 2013
    Posts:
    6,620
    Perhaps it's useful for someone: The order in what
    RuntimeInitializeOnLoadMethod
    is called, at least in the editor, is as followed (1=called first, 5=called last):
    1. SubsystemRegistration
    2. AfterAssembliesLoaded
    3. BeforeSplashScreen
    4. BeforeSceneLoad
    5. NoArgument
    6. AfterSceneLoad
    I'm not sure whether the default is AfterSceneLoad when you don't specify any
    RuntimeInitializeLoadType
    . In this case, the order of
    NoArgument
    and
    AfterSceneLoad
    can be random.
    Code (CSharp):
    1.  
    2. [RuntimeInitializeOnLoadMethod]
    3. static void NoArgument() { Debug.Log("NoArgument"); }
    4.  
    5. [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)]
    6. static void BeforeSceneLoad() { Debug.Log("BeforeSceneLoad"); }
    7.  
    8. [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.AfterAssembliesLoaded)]
    9. static void AfterAssembliesLoaded() { Debug.Log("AfterAssembliesLoaded"); }
    10.  
    11. [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.AfterSceneLoad)]
    12. static void AfterSceneLoad() { Debug.Log("AfterSceneLoad"); }
    13.  
    14. [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSplashScreen)]
    15. static void BeforeSplashScreen() { Debug.Log("BeforeSplashScreen"); }
    16.  
    17. [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)]
    18. static void SubsystemRegistration() { Debug.Log("SubsystemRegistration"); }
    I use
    AfterAssembliesLoaded
    to reset static fields.
     
    Last edited: Jul 22, 2022
  50. Peter77

    Peter77

    QA Jesus

    Joined:
    Jun 12, 2013
    Posts:
    6,620
    I updated the post right above this one and added the "NoArgument" information.
     
    AlkisFortuneFish likes this.