Search Unity

Scriptable Object onEnable being called even on unused SOs

Discussion in 'Editor & General Support' started by RyanH20, Apr 18, 2021.

  1. RyanH20

    RyanH20

    Joined:
    Jun 8, 2020
    Posts:
    23
    The page on scriptable objects says the OnEnable method is called when the scriptable object is loaded. I saw in another thread a long description of how they work (although it was from a few years ago now) but the jist of it seemed to be that for the most part, onEnable is only called on scriptable objects that are referenced by monobehaviors, which is exactly what I want, however, I wanted to test it. I have an Inventory class that inherits from ScriptableObject and I wanted to check that it only got 1 OnEnable even if it was attached to multiple monobehaviors, which it did but I also got OnEnable calls from a testInventory SO that isn't attached to anything. Just to make sure, I created a testInventory2 and pressed play and I got an OnEnable call from that one too.
     
  2. SOs haven't been changed for years, so what you have read in those threads are true.
    The thing is, SOs behave differently in the Editor and in the build. Okay, this isn't really true, but you perceive that way.
    Why is that? Because you expect SOs not to be loaded in the editor when you hit the play button.
    In reality, when you edit an object in the editor it gets loaded into memory and won't be unloaded just because you hit the play button.
    This means when you get the OnEnabled call in the editor it will be once, when you create the SO (or when the project/SO gets loaded, unpredictible).
    In the build your SO gets loaded when it is needed. When something gets initialized and reference it or when you load it manually.
    In reality the rules are consistent, but the circumstances in the editor and in the build aren't.
     
    CiroContns likes this.
  3. RyanH20

    RyanH20

    Joined:
    Jun 8, 2020
    Posts:
    23
    Yeah, I managed to get past the issue of SOs getting enabled that aren't being used at all - it seems like it happens every time the scripts get recompiled, I hadn't noticed and cleared the messages.
    I think what I was trying to do just isn't going to work though. I had the bright idea that all my scriptable objects that should be saved would register themselves (previously they had to be in a resources folder and then I'd use resources.loadAll to find them) when they were enabled so the save system would just run through them all and capture the save data but they get enabled in the editor so that caused issues, so then I made it only do that if Application.isPlaying but I found that when I pressed play the playerInventory got enabled before Application.isPlaying was true. So I think I'll just bin this idea and go back to Resources.LoadAll
     
  4. What you can do is build a base class upon SO which calls a custom initialization. I do this:
    Code (CSharp):
    1. using System;
    2. #if UNITY_EDITOR
    3. using UnityEditor;
    4. #endif
    5. using UnityEngine;
    6.  
    7. namespace LurkingNinja.Managers
    8. {
    9.     public abstract class ManagedScriptableObject : ScriptableObject
    10.     {
    11.         protected abstract void OnBegin();
    12.         protected abstract void OnEnd();
    13.  
    14. #if UNITY_EDITOR
    15.         protected void OnEnable() => EditorApplication.playModeStateChanged += OnPlayStateChange;
    16.         protected void OnDisable() => EditorApplication.playModeStateChanged -= OnPlayStateChange;
    17.  
    18.         private void OnPlayStateChange(PlayModeStateChange state)
    19.         {
    20.             switch (state)
    21.             {
    22.                 case PlayModeStateChange.EnteredPlayMode:
    23.                     OnBegin();
    24.                     break;
    25.                 case PlayModeStateChange.ExitingPlayMode:
    26.                     OnEnd();
    27.                     break;
    28.                 case PlayModeStateChange.EnteredEditMode:
    29.                     break;
    30.                 case PlayModeStateChange.ExitingEditMode:
    31.                     break;
    32.                 default:
    33.                     throw new ArgumentOutOfRangeException(nameof(state), state, null);
    34.             }
    35.         }
    36. #else
    37.         protected void OnEnable() => OnBegin();
    38.         protected void OnDisable() => OnEnd();
    39. #endif
    40.     }
    41. }
    The
    OnBegin
    and
    OnEnd
    are the ones I can implement so it is called when the application starts / exits or when I hit the play button (start/stop).
     
    kyuskoj and Alex_Galvez like this.