Search Unity

  1. We are migrating the Unity Forums to Unity Discussions. On July 12, the Unity Forums will become read-only.

    Please, do not make any changes to your username or email addresses at id.unity.com during this transition time.

    It's still possible to reply to existing private message conversations during the migration, but any new replies you post will be missing after the main migration is complete. We'll do our best to migrate these messages in a follow-up step.

    On July 15, Unity Discussions will become read-only until July 18, when the new design and the migrated forum contents will go live.


    Read our full announcement for more information and let us know if you have any questions.

Question UnityEngine.Object in an ScriptableObject is empty in WebGL build

Discussion in 'Web' started by trnq1ll0, Jul 24, 2023.

  1. trnq1ll0

    trnq1ll0

    Joined:
    Aug 30, 2019
    Posts:
    53
    Hi, I am encountering a problem in a WebGL build.


    A WorkPlanController (singleton MonoBehaviour) defining in a subclass the member "data" as the reference to the struct:

    Code (CSharp):
    1.  
    2. public class WorkPlanController : Singleton<WorkPlanController>
    3. {
    4.     public class WorkPlanModule
    5.     {
    6.          public ModuleData data;
    7.     }
    8. }
    9.  
    I have an ScriptableObject (accessed via Singleton) containing a list of modules and every module holds a struct of data:

    The ScriptableObject:
    Code (CSharp):
    1.  
    2. public class WorkplanData : SingletonScriptableObject<WorkplanData>
    3. {
    4.     public WorkPlanController.WorkPlanModule[] module = null;
    5. }
    6.  

    Code (CSharp):
    1.  
    2. [Serializable]
    3. public struct ModuleData
    4. {
    5.     public string name;
    6.     public string description;
    7.     public UnityEngine.Object processFile;   <<== problem
    8. }
    9.  

    At runtime I'am accessing the data via

    Code (CSharp):
    1.            
    2. foreach (var module in WorkPlanController.Instance.data.module)
    3. {
    4.     //throw exception in WebGL because module.data.processFile == null
    5.    string processPath = $"Processes/{module.data.processFile.name}";
    6. }
    7.  
    In the Editor it works very well, file pathes and files can be read without a problem. But in the WebGL build the reference to the GameEngine.Object module.data.processFile is null.

    I don't know if relevant, but the source files put in to processFile resides in Assets/StreamingAssets/

    Would be great if someone can shed some light on the problem.
    Thanks
     
  2. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    39,571
    Look at your singletons. Chances are if you picked them up from some random website then they are broken and require some silly "must be in scene" or "must be loaded" step first, which suddenly imposes these massive irritations upon you like knowing their load order, enforcing a good load order, etc.

    Here are the ONLY forms of a singleton I use in Unity because they have been engineered to consider Unity's full object lifecycle. Because of this they have the important advantage that they never require dragging and dropping random stuff into random scenes, and they also work. :)

    Simple Singleton (UnitySingleton):

    Some super-simple Singleton examples to take and modify:

    Simple Unity3D Singleton (no predefined data):

    https://gist.github.com/kurtdekker/775bb97614047072f7004d6fb9ccce30

    Unity3D Singleton with a Prefab (or a ScriptableObject) used for predefined data:

    https://gist.github.com/kurtdekker/2f07be6f6a844cf82110fc42a774a625

    These are pure-code solutions, DO NOT put anything into any scene, just access it via .Instance!

    The above solutions can be modified to additively load a scene instead, BUT scenes do not load until end of frame, which means your static factory cannot return the instance that will be in the to-be-loaded scene. This is a minor limitation that is simple to work around.

    If it is a GameManager, when the game is over, make a function in that singleton that Destroys itself so the next time you access it you get a fresh one, something like:

    Code (csharp):
    1. public void DestroyThyself()
    2. {
    3.    Destroy(gameObject);
    4.    Instance = null;    // because destroy doesn't happen until end of frame
    5. }
    There are also lots of Youtube tutorials on the concepts involved in making a suitable GameManager, which obviously depends a lot on what your game might need.

    OR just make a custom ScriptableObject that has the shared fields you want for the duration of many scenes, and drag references to that one ScriptableObject instance into everything that needs it. It scales up to a certain point.

    And finally there's always just a simple "static locator" pattern you can use on MonoBehaviour-derived classes, just to give global access to them during their lifecycle.

    WARNING: this does NOT control their uniqueness.

    WARNING: this does NOT control their lifecycle.

    Code (csharp):
    1. public static MyClass Instance { get; private set; }
    2.  
    3. void OnEnable()
    4. {
    5.   Instance = this;
    6. }
    7. void OnDisable()
    8. {
    9.   Instance = null;     // keep everybody honest when we're not around
    10. }
    Anyone can get at it via
    MyClass.Instance.
    , but only while it exists.
     
  3. trnq1ll0

    trnq1ll0

    Joined:
    Aug 30, 2019
    Posts:
    53
    Thank you Kurt for your super rich answer.

    We make heavy use of Addressables and small scenes that will be un/loaded all the time, so we have slightly bigger Singletons with types, thread lock and unicon glitter (and maybe some bugs, to be honest) and also not like yours with the implementation of the Unity lifecycle methods.

    But this time I think that these are not the problem, because other fields than the module.data.processFile are accessible like module.data.name only it itself is not. Therefore I think that the problem lies elsewhere.

    Would you agree with that?
    Thanks
     
    Last edited: Jul 25, 2023
  4. trnq1ll0

    trnq1ll0

    Joined:
    Aug 30, 2019
    Posts:
    53
    Problem still unsolved... if anyone has any suggestion please let me know :)