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

(Solved, but unhappy)ScriptableObject.Awake never execute

Discussion in 'Documentation' started by PJRM, Aug 16, 2017.

  1. PJRM

    PJRM

    Joined:
    Mar 4, 2013
    Posts:
    303
    Hello!
    On ScriptableObject.Awake documentation, It says:
    But the problem is that this function is never called! I'm using 2017.1.
    Is there something wrong?
    None of these work:
    Code (CSharp):
    1. void Awake() {
    2.    Debug.Log("Test!");
    3. }
    Code (CSharp):
    1. private void Awake() {
    2.    Debug.Log("Test!");
    3. }
    Code (CSharp):
    1. public void Awake() {
    2.    Debug.Log("Test!");
    3. }
    Code (CSharp):
    1. protected void Awake() {
    2.    Debug.Log("Test!");
    3. }
    So, someone manage to make it work??? I need this soooo badly to avoid making any "jerry-rig" code.
     
  2. PJRM

    PJRM

    Joined:
    Mar 4, 2013
    Posts:
    303
    Oh well... I created a report: https://fogbugz.unity3d.com/default.asp?943003_3rnv3sufsjhjjeff

    Since I'm not able to use Awake function on ScriptableObjects, I had to create an Init() function and now I have to call Init() everytime on the Awake gameobject, runing a foreach fr every ScriptableObject attached and I do the same for every other ScriptableObject that it is attached inside my others ScriptableObjects.

    Really not a good way to do the coding on this scripts. Bad! Very bad!
    I'm open to suggestions, solutions, whatever... This is giving me a nervous tic, everytime I have to call this Init function.
     
  3. PJRM

    PJRM

    Joined:
    Mar 4, 2013
    Posts:
    303
    So. I got an answer from Unity about the report.
    I have to test it and IMHO, Devs: Take a kind look at this!

    The scripts are simple:
    Code (CSharp):
    1. using UnityEngine;
    2.  
    3. namespace Game.Test {
    4.    public class Test : MonoBehaviour {
    5.       public TestSO testing;
    6.    }
    7. }
    Code (CSharp):
    1. using UnityEngine;
    2.  
    3. namespace Game.Test {
    4.    public class TestSO : ScriptableObject {
    5.       protected virtual void Awake() { }
    6.    }
    7. }
    Code (CSharp):
    1. using UnityEngine;
    2.  
    3. namespace Game.Test {
    4.    [CreateAssetMenu (menuName = "Test/Testing ScriptableObject")]
    5.    public class TestChildSO : TestSO {
    6.       protected override void Awake () {
    7.          base.Awake ();
    8.          Debug.Log("Testing");
    9.       }
    10.    }
    11. }
    Observation: I created the ScriptableObject file on an folder and attached to the slot on the gameObject in inspector.
    I thought it required the Awake function on the base class, but when I run, it doesn't work! So...
    Since the first test didn't work I add some code to the Test class:
    Code (CSharp):
    1. private void Awake() {
    2.    testing = (TestSO) ScriptableObject.CreateInstance(typeof(TestChildSO));
    3. }
    And it work!
    Conclusion: In my point of view, this method should be renamed to OnCreated. Why is that: Simple, the Awake does not run if a GameObject is on the scene, but only if a script creates the ScriptableObject!

    When a Object is Awakening, ( if the ScriptableObject have the same method and the documentation says that it works similar way as MonoBehaviour, ) then the ScriptableObjects must execute Awake too! Otherwise it's purpose lacks meaning! It is an OnCreated execution! More logic and coherence. Remember: this is my point of view and my argument!
     
  4. Wdarkfenix

    Wdarkfenix

    Joined:
    Feb 3, 2013
    Posts:
    5
    Thank you for posting this. It explains a lot and I agree with you, it should be called OnCreate() Instead. Maybe is some inheritance shenanigans.
     
  5. Pablomon

    Pablomon

    Joined:
    Mar 9, 2015
    Posts:
    40
    Totally agree.
    Thanks for posting.
     
    PJRM likes this.
  6. illinar

    illinar

    Joined:
    Apr 6, 2011
    Posts:
    857
    Just discovered this. Wasted some time on it.
     
  7. cdytoby

    cdytoby

    Joined:
    Nov 19, 2014
    Posts:
    181
    I just have this problem and found this post. Thanks for saving my time.
     
    SolidAlloy likes this.
  8. DungDajHjep

    DungDajHjep

    Joined:
    Mar 25, 2015
    Posts:
    163
    try OnEnable Instead ?
     
  9. cdytoby

    cdytoby

    Joined:
    Nov 19, 2014
    Posts:
    181
    OnEnable will be executed when Editor is not in playmode and an instance is assigned to a gameobject's script's parameter. So, this is not good.
     
  10. LaneFox

    LaneFox

    Joined:
    Jun 29, 2011
    Posts:
    7,380
    The documentation is incorrect here, it's an ambiguous and misleading statement.

    But for consistency Awake() is plenty clear. Both Mobobehaviors and ScriptableObjects must have an instance alive and running in a scene in order to get their built-in calls. It's already known how Awake() works - only fired once when the object is instanced - so why bother creating a new built in call that is executed exactly the same?
     
    Ryiah, Zethros and hippocoder like this.
  11. DungDajHjep

    DungDajHjep

    Joined:
    Mar 25, 2015
    Posts:
    163
    Hi all, scriptable call Awake when my game open on android device , but when Editor play, it's not trigger ??? im so confuse -_-
     
  12. cdytoby

    cdytoby

    Joined:
    Nov 19, 2014
    Posts:
    181
    I decided to load the scriptableObjects asset from Resources. But I don't know if this single asset contains 1000 different references (gameobjects, sprites, etc), will it affect performance?
     
    OliverGrack likes this.
  13. DungDajHjep

    DungDajHjep

    Joined:
    Mar 25, 2015
    Posts:
    163
    [QUOTE = "cdytoby, post: 3476517, member: 722742"] Tôi quyết định tải nội dung scriptableObjects từ Tài nguyên. Nhưng tôi không biết liệu tài sản đơn này có chứa 1000 tham chiếu khác nhau (gameobject, sprites, v.v.), nó có ảnh hưởng đến hiệu suất không? [/ QUOTE]
    no, i make a test
    https://forum.unity.com/threads/res...object-is-load-and-unload-from-memory.555358/
     
    Last edited: Sep 22, 2018
  14. vimutti

    vimutti

    Joined:
    Nov 22, 2017
    Posts:
    5
    I tested it. Look like the editor version is act different from the built version. In editor version, Awake will not be called by created scriptable. But in built version, it will be called. I assume that the built version will re-create all scriptable every time we start game so all Awake will be called.
     
  15. PJRM

    PJRM

    Joined:
    Mar 4, 2013
    Posts:
    303
    The main issue here that i wrote about it, is because of the statement on documentation.
    Please make sure you ready well my 3rd post, because it explain well. The Awake only run on scriptableobject when created, not loaded. To me this never make sense to be called Awake. On build version, the awake is called because the engine need to create the scriptableobjects to be ready.

    It's a OnCreated method. Not Awake method.
    I don't know how to explain better. I even give example script above to show whether this is true or not! On my Statecontroller i even created a Setup method which i call it everytime i load the script, because i need some settings to be set before update starts.
     
    Gabahulk and swingingtom like this.
  16. Pablomon

    Pablomon

    Joined:
    Mar 9, 2015
    Posts:
    40
    This is my workaround.

    1. Create a derived class from scriptable object with functions for the callbacks ( OnAwake() ), I called it monoscriptableObject.
    2. Create a scriptable object with a list that references the new monoscriptableObjects that need normal monobehaviours callbacks, I called it MonoCallBacks.
    3. Create a monobehaviour with a reference to the list in point 2 that calls those functions when their callbacks are called. ie. OnEnable() { foreach mso in list { mso .OnEnableCallBack() }}
    4. Have an instance in your scene of MonoCallBacks.

    It's a bit of a hassle, but works for me.
     
    Last edited: Jun 12, 2018
  17. GetBrinxed

    GetBrinxed

    Joined:
    Feb 21, 2018
    Posts:
    12
    Not quite.
    I've debugged this to death and back because I was wondering the same thing.

    There are 3 different cases that will cause a ScriptableObject to call Awake()

    1 - When it's created. (Editor Only)
    2 - When a scene which contains an object that references the asset is loaded.
    3 - When the asset is first selected in the project window IF Awake() hasn't already been called. (Editor Only)

    Please correct me if I'm wrong, but in all the tests I've done, I've found this to be the consistent behaviour.
     
    hellobody likes this.
  18. GetBrinxed

    GetBrinxed

    Joined:
    Feb 21, 2018
    Posts:
    12
    I forgot that SOs can be created at runtime, so point 1 should happen in editor and out of editor.
     
  19. Pablomon

    Pablomon

    Joined:
    Mar 9, 2015
    Posts:
    40
    Exactly what I found.
    OnAwake is an unfortunate name. Unity Devs?
     
  20. GetBrinxed

    GetBrinxed

    Joined:
    Feb 21, 2018
    Posts:
    12
    JaisyKo, ZombieTFK and CyrilGhys like this.
  21. DungDajHjep

    DungDajHjep

    Joined:
    Mar 25, 2015
    Posts:
    163
  22. mazenn25

    mazenn25

    Joined:
    Sep 23, 2018
    Posts:
    2
    I'm open to suggestions, solutions, whatever.
    This is giving me a nervous tic, everytime I have to call this Init function.
     
  23. Josiah_Kunz

    Josiah_Kunz

    Joined:
    Jun 8, 2017
    Posts:
    9
    You can use
    [InitializeOnLoad]
    in tandem with
    OnEnable
    :

    Code (CSharp):
    1. [InitializeOnLoad]
    2. public class Test : ScriptableObject {
    3.  
    4.      void OnEnable () {
    5.            Debug.Log ("Unity editor has just started up!");
    6.      }
    7.  
    8. }
    Now the method is called whenever the ScriptableObject is created and whenever Unity is launched.
     
  24. illinar

    illinar

    Joined:
    Apr 6, 2011
    Posts:
    857
    I'm running into this frustrating issue again. Can anyone please give a TLDR of why on earth they don't run Awake and OnEnable when everyone expects them to? (When the same methods are executed on GameObject instances)
     
    Last edited: Apr 28, 2019
  25. PJRM

    PJRM

    Joined:
    Mar 4, 2013
    Posts:
    303
    This issue is so old.
    The solution is to create your own Awake event. The Awake on ScriptableObjects happen only when it is loaded into scene and not when it is playing for the first time.

    I don't know if this is still this way now a days, but if it is, then use a boolean variable to tell when it is the first time your script is running. If its the first time, then you invoke your own "Awake" event. This will solve your issue.
    Hope it helps.
     
  26. Lurking-Ninja

    Lurking-Ninja

    Joined:
    Jan 20, 2015
    Posts:
    9,760
    I use something like this:
    Code (CSharp):
    1. using UnityEngine;
    2. #if UNITY_EDITOR
    3. using UnityEditor;
    4. #endif
    5.  
    6.     [InitializeOnLoad]
    7.     public abstract class ManagedObject : ScriptableObject
    8.     {
    9.         abstract protected void OnBegin();
    10.         abstract protected void OnEnd();
    11.  
    12. #if UNITY_EDITOR
    13.         protected void OnEnable()
    14.         {
    15.             EditorApplication.playModeStateChanged += OnPlayStateChange;
    16.         }
    17.  
    18.         protected void OnDisable()
    19.         {
    20.             EditorApplication.playModeStateChanged -= OnPlayStateChange;
    21.         }
    22.  
    23.         void OnPlayStateChange(PlayModeStateChange state)
    24.         {
    25.             if(state == PlayModeStateChange.EnteredPlayMode)
    26.             {
    27.                 OnBegin();
    28.             }
    29.             else if(state == PlayModeStateChange.ExitingPlayMode)
    30.             {
    31.                 OnEnd();
    32.             }
    33.         }
    34. #else
    35.         protected void OnEnable()
    36.         {
    37.             OnBegin();
    38.         }
    39.  
    40.         protected void OnDisable()
    41.         {
    42.             OnEnd();
    43.         }
    44. #endif
    45.     }
    46.  
    And when you inherit from it, you implement the OnBegin and OnEnd methods. It runs on starting unity editor, on entering/exiting playmode and on starting your built application.
     
  27. John_Leorid

    John_Leorid

    Joined:
    Nov 5, 2012
    Posts:
    612
    Guys, I've found the solution - it works exactly as I need it for my SO-BulletPool:

    Code (CSharp):
    1. private void OnEnable()
    2. {
    3. SceneManager.sceneLoaded -= OnSceneLoaded;
    4. SceneManager.sceneLoaded += OnSceneLoaded;
    5. }
    6. void OnSceneLoaded(Scene scene, LoadSceneMode mode)
    7. {
    8. InitializePool();
    9. }
    10.  
    11. public void InitializePool()
    12. {
    13. Debug.Log("Initialize Pool");
    14. // do stuff
    15. }
    16. }
     
    micha_dev, abcjjy and luvjung1e like this.
  28. illinar

    illinar

    Joined:
    Apr 6, 2011
    Posts:
    857
    By the way, I was talking about OnEnable and Awake being executed when Play mode is activated. Since they don't execute it makes OnEnable and Awake completely unusable because they don't work during testing. So there is no good solution for that as far as I remember.
     
  29. chambino

    chambino

    Joined:
    Jun 4, 2018
    Posts:
    12
    Looks like they've closed the ticket without discussing that Awake should be called when object is not instantiated from scripts. Has anyone created something else, or brought this to devs attention?
     
  30. netlander

    netlander

    Joined:
    Nov 22, 2011
    Posts:
    28
    Unbelievable!
     
    Circool likes this.
  31. Hullabu

    Hullabu

    Joined:
    Oct 23, 2014
    Posts:
    18
    The developers don't give a S***. Bugs have existed for years and nobody care. They are only have time to develop a new features for promotion...
     
    crowmaster, SolidAlloy and ModLunar like this.
  32. Jorhoto

    Jorhoto

    Joined:
    May 7, 2019
    Posts:
    99
    I just added an interface (lets call it: IInitializable) to the scriptableobjects requiring a special initialization that I call from a gameobject in my scene when needed.

    Edit: The problem I see with this approach is that you lose the Lazy Initialization factor.
     
    Last edited: Dec 24, 2019
  33. nyonge

    nyonge

    Joined:
    Jul 11, 2013
    Posts:
    49
    Loosely inspired by what @Lurking-Ninja wrote above.

    Here's a simple check for OnEnable to run only in editor. It uses isPlayingOrWillChangePlaymode. I use it to call a function that's also called by Awake, so either way it runs on start (OnEnable in Editor, Awake in build)

    Code (CSharp):
    1. using UnityEngine;
    2.  
    3. public class myScriptableObject:ScriptableObject {
    4.    
    5.     private void OnEnable() {
    6.         #if UNITY_EDITOR
    7.         // use platform dependent compilation so it only exists in editor, otherwise it'll break the build
    8.         if (UnityEditor.EditorApplication.isPlayingOrWillChangePlaymode)
    9.             myStartFunction ();
    10.         #endif
    11.     }
    12.    
    13.     private void Awake() {
    14.         myStartFunction ();
    15.     }
    16. }
    The other solutions here are good, but this is just a lot quicker - no need to make custom interfaces or listen to events or whatever. Hope it helps!
     
  34. AntonPetrov

    AntonPetrov

    Joined:
    Dec 27, 2013
    Posts:
    56
    Documentation says "Awake is called as the ScriptableObject script starts." but no one told you that SO script starts when you hit Play in the editor :)

    Scriptable objects are instantiated in edit mode (as all other referenced assets) and not re-instantiated or reloaded when you start playing in the editor, this allows fast start without loading everything every time.

    So documentation is true, while your expectations are false. Sorry.

    P.S. I was blocked by this feature too and I do understand your pain.
     
  35. bobbaluba

    bobbaluba

    Joined:
    Feb 27, 2013
    Posts:
    81
    Seems like this solution doesn't work if experimental enter play mode is enabled :/
     
  36. the_Simian

    the_Simian

    Joined:
    Mar 13, 2011
    Posts:
    37
    I came across this problem as well, and I was in a situation where I needed some data to basically be calculated from the static data in the SerializeableObject. like @bobbaluba I was experiencing problems with experimental play mode.

    In production, I just needed things to be calculated once, and that's fine. In the editor I needed some data to be recalculated every play.

    Here is what I worked out:

    Code (CSharp):
    1.  
    2. public class DataBagWithCalculatedFields : ScriptableObject
    3. {
    4.     private string calculatedFieldNeedsResetOnPlay;
    5.  
    6.     private void Awake()
    7.     {
    8.         InitialiationMethods();
    9.     }
    10.  
    11.     private void OnEnable()
    12.     {
    13.         EditorApplication.playModeStateChanged += PlayStateChanged;
    14.         InitialiationMethods();
    15.     }
    16.  
    17.     void PlayStateChanged(PlayModeStateChange state)
    18.     {
    19.         if (state == PlayModeStateChange.EnteredPlayMode)
    20.         {
    21.             InitialiationMethods();
    22.         }
    23.     }
    24.  
    25.     void InitialiationMethods()
    26.     {
    27.         calculatedFieldNeedsResetOnPlay = "do work here.";
    28.     }
    29. }
    30.  
    Edit: Looks like this is very similar to @Lurking-Ninja 's approach it seems
     
    Unifikation and bobbaluba like this.
  37. bourriquet

    bourriquet

    Joined:
    Jul 17, 2012
    Posts:
    180
    Scumbag Dev: "Everyone misunderstands my documentation => everyone has a problem"
     
  38. Ziplock9000

    Ziplock9000

    Joined:
    Jan 26, 2016
    Posts:
    360
    Yes, this is an issue. I need an event that triggers when a new instance of an SO is created via the editor menu so I can assign it a unique Id.
    All of the other methods to do this via OnValidate, OnBeforeSerialise all feel hacky and don't work well or execute more than needed (which is once in the whole lifecycle of the SO)
     
  39. DragonCoder

    DragonCoder

    Joined:
    Jul 3, 2015
    Posts:
    1,406
    As someone just starting out with scriptable obejcts, I have to agree:
    Calling this method "OnCreate" instead of Awake or at very least make it way more obvious in the documentation that we should not assume its Awake to act like for regular Gameobjects (called upon pressing the start button) would have avoided some confusion.
    I do understand now why that assumption is wrong, but it's just counter intuitive on first sight.
     
  40. a436t4ataf

    a436t4ataf

    Joined:
    May 19, 2013
    Posts:
    1,861
    No, you only read half the paragraph. The other half says:

    "This happens as the game is launched and is similar to MonoBehavior.Awake."

    But it does NOT happen 'as the game is launched' -- as has been extensively documented in this thread.
     
    Unifikation likes this.
  41. a436t4ataf

    a436t4ataf

    Joined:
    May 19, 2013
    Posts:
    1,861
    This is still incorrectly documented - Unity teams seem to hate writing docs so much that they won't even lift a finger to correct broken docs.

    It is still broken in all versions of Unity (just tested from 2019.1 through 2020.3.LTS)

    4.5 years.
     
  42. _TheFuture_

    _TheFuture_

    Joined:
    Mar 11, 2016
    Posts:
    4
    In my experience, all "event methods" (OnEnable, Awake, ...) on Scriptable Objects (SO) are only reliably called, when an instance of an SO is referenced by an active scene component. Just creating an instance is not enough.

    It is particularly confusing in the editor. One can e.g. create an instance of an SO in the project's assets and it will look like OnEnable, Awake, ... is being called as you'd expect it. But as soon as you're building and running the game outside the editor, these methods will not be called whatsoever anymore if the SO instance wasn't assigned to an active scene object or loaded by a script in another way, but just exists in the assets.

    Furthermore I couldn't find out when the editor decides to load or re-load an SO instance that only exists in the assets. Even the scripts provided by @Lurking-Ninja and @nyonge simply did not execute some of the times I entered / left playmode.

    It gives the impression that the creation of SO instances is cached by some conditions. This has been very inconsistent and unreliable in my experience. I've had more issues than use of SOs so far.
     
    Unifikation and PJRM like this.
  43. Baste

    Baste

    Joined:
    Jan 24, 2013
    Posts:
    6,172
    ScriptableObjects are great! Don't actually try to use them like GameObjects, though. I don't know why there is an Awake method, but just don't use it.

    A ScriptableObject is a generic data container. That's it. Don't give it messages. Don't give it behaviour.
     
    PJRM and DragonCoder like this.
  44. a436t4ataf

    a436t4ataf

    Joined:
    May 19, 2013
    Posts:
    1,861
    Wat. Core piece of Unity has a bug, but it's OK because you don't have to use Unity - write your game in Unreal instead, and this bug goes away!

    Most of us using SO's for things beyond 'generic data container' are doing so because it is the only way in Unity to do such things. Also ... SO's are one of the worst (if not the very worst) ways to store data in Unity, should never be / have been used for that.
     
    Unifikation and _TheFuture_ like this.
  45. DragonCoder

    DragonCoder

    Joined:
    Jul 3, 2015
    Posts:
    1,406
    The whole "Awake" issue could have been avoided by giving that event a different name, oh well. Now it's too late sadly since it'd break backwards compatibility.
    However if you do want a real awake method that executes on every game launch or scene load, that's not that hard to achieve.

    I wrote a simple class that inherits from ScriptableObject like "ScriptableWithInit" and allows for an Init() method (you could also name it CustomAwake, SceneStart or something similar).
    Then there's a manager class which is a monobehavior and just has a srializable list of those ScriptableWithInit.

    Now all SOs that shall have an init method inherit from ScriptableWithInit and in my scene I have an object with the manager class and I add every new SO to its list.

    Finally in that managers regular Awake method is a simple loop that calls the Init() method for all the SO.

    Probably you could even do this smarter and actually use the real Awake method of SOs so they add themselves to the list automatically.

    That's how you work around problems like those :)
     
  46. a436t4ataf

    a436t4ataf

    Joined:
    May 19, 2013
    Posts:
    1,861
    Surely it's the opposite: the only 100% safe usage of SO I've found - that doesn't suffer data-loss, scene-corruption, project-corruption bugs in ANY version of Unity, that never gets leaked - is as a "behaviour" holder.

    SO's are perfect as a way of dynamically loading/unloading code, and including links from one SO to another (one code module referencing/delegating to other code modules). This one thing they get correct always (as far as I can tell). I have some projects now with upwards of 15,000 lines of code that are managed this way - they exist in SO's not in MB's, and are easy to manage in Unity.

    ...or did I miss an "/s" on the quoted post ? :)
     
    Unifikation likes this.
  47. DragonCoder

    DragonCoder

    Joined:
    Jul 3, 2015
    Posts:
    1,406
    @a436t4ataf
    What do you mean by loading/unloading code? Could you please elaborate the benefits/usecase of that? Have trouble imagining what you mean but it sounds interesting.
    Are you using the SOs as an alternative to what Unity calls packages but just for code?
     
  48. a436t4ataf

    a436t4ataf

    Joined:
    May 19, 2013
    Posts:
    1,861
    SO's are a bunch of code. If an SO implements a c# interface, it can be drag/drop replaced in the Editor with a different SO instance that provides the same interface but different implementation. Any editor-user can do this, requires no code-editing - lets non-tech people mix-and-match large code modules, scripts, etc.
     
    Unifikation likes this.
  49. DragonCoder

    DragonCoder

    Joined:
    Jul 3, 2015
    Posts:
    1,406
    I see! Interesting approach.
    Think normally you are supposed to use Monobehaviors for that purpose. Unity is built around the components system with them after all. But I see the potential advantages. Using SOs even with code can result in a neat architecture for certain usecases.
     
  50. a436t4ataf

    a436t4ataf

    Joined:
    May 19, 2013
    Posts:
    1,861
    MB's cannot do this. You can approximate it, at a lower level of quality, with multiple ways it can go wrong (because you cannot drag/drop MB's, you've never been able to in any version of Unity) ... and MB's have the problem of multiple instances ... they can't exist without a Transform ... etc etc. All those problems vanish / don't exist if you use SO's. SO's can be fairly thought of as "the Asset version of an MB". For code that's exactly what you want: an asset, not a gameobject.
     
    Unifikation likes this.