Search Unity

ScriptableObject inheritance and reference.

Discussion in 'Scripting' started by jister, Nov 18, 2019.

  1. jister

    jister

    Joined:
    Oct 9, 2009
    Posts:
    1,749
    So i have a ScriptableObject "GameMode" that has a base and it's child implements some references to other ScriptableObjects "Databases". Then there is one more SO "SceneSettings" That has a reference to the "GameMode" one. Now if i make that "GameMode" reference (which is of type Base), point to an Instance of the child version (with the databases) then i get this error in my build (not in editor):
    Code (CSharp):
    1. A scripted object (script unknown or not yet loaded) has a different serialization layout when loading. (Read 52 bytes but expected 56 bytes)
    2. Did you #ifdef UNITY_EDITOR a section of your serialized properties in any of your scripts?
    3. UnityEngine.Resources:Load(String, Type)
    4. UnityEngine.Resources:Load(String) (at C:\buildslave\unity\build\Runtime\Export\Resources\Resources.bindings.cs:51)
    and no i don't have any properties with #ifdef UNITY_EDITOR
     
  2. palex-nx

    palex-nx

    Joined:
    Jul 23, 2018
    Posts:
    1,748
    Unity do not support class hierarchies with scriptable objects when you reference them as base types. It either needs an exact type or deserialization will fail.
     
  3. Owen-Reynolds

    Owen-Reynolds

    Joined:
    Feb 15, 2012
    Posts:
    1,998
    But there shouldn't be any deserialization. Didn't the OP first create every ScriptableObject needed, by clicking the menu? They're all side-by-side in Assets, which properly saves and loads them all, right? In the problem area, "public GameModeBaseClass g;", wasn't that filled in by dragging over another ScriptableObject? That should be no problem.

    If you could somehow create a subclassOfGameMode that wasn't in Assets, and the only way to find it was your "public GameModeBaseClass g;" pointer, meaning it needed to be serialized along with you, then it would be a problem. But is that even possible?
     
  4. jister

    jister

    Joined:
    Oct 9, 2009
    Posts:
    1,749
    Can you confirm this? I don't see anything in the documents stating SO's don't support inheritance...


    All gameModes are Assets created during editor time, same for scenesettings...
     
  5. palex-nx

    palex-nx

    Joined:
    Jul 23, 2018
    Posts:
    1,748
    I believe this message

    Code (CSharp):
    1. A scripted object (script unknown or not yet loaded) has a different serialization layout when loading. (Read 52 bytes but expected 56 bytes)
    pops up when unity tries to deserialize an object, but target type and object has different sizes, no?
     
  6. Owen-Reynolds

    Owen-Reynolds

    Joined:
    Feb 15, 2012
    Posts:
    1,998
    Yikes! Searching for that phrase "has a different serialization layout" looks like it's a catch-all error whenever just about anything is wrong.
     
  7. jister

    jister

    Joined:
    Oct 9, 2009
    Posts:
    1,749
    so maybe better to post the relevant code:
    GameModeBase:
    Code (CSharp):
    1. [CreateAssetMenu(fileName = "GameMode", menuName = "ScriptableObjects/GameModes/New GameModeBase", order = 1)]
    2. public class GameModeBase : ScriptableObject
    3. {
    4.     public PlayerController playerControllerPrefab;
    5.     public Pawn pawnPrefab;
    6.     public HUDBase HUDPrefab;
    7.  
    8.     public PlayerController PlayerController { get { return m_playerController; } }
    9.  
    10.     private PlayerController m_playerController;
    11. }
    Child of base:
    Code (CSharp):
    1. [CreateAssetMenu(fileName = "GameMode", menuName = "ScriptableObjects/GameModes/New GameModeGame", order = 1)]
    2. public class GameModeGame : GameModeBase
    3. {
    4.     [Header("Booking System")]
    5.     public BookingsSO bookingsSO;
    6.     public GroupsSO groupsSO;
    7.     public GuestsSO guestsSO;
    8.     public EthnicityDB ethnicityDB;
    9.     public ThemeRequirementSO themeRequirementSO;
    10.  
    11.     [Header("Items And Structures")]
    12.     public BuildingDB buildingDB;
    13.     public PlaceableDB placeableDB;
    14.     public PropDB propDB;
    15.     public BuildingDB vehicleDB;
    16.  
    17.     [Header("Characters")]
    18.     public ToolDataSO toolDataSO;
    19.  
    20.     public ResortManager ResortManager { get; private set; }
    21.     public Calendar Calendar { get; private set; }
    22. }
    The Scriptable object holding reference to a gamemode as base:
    (This gets generated at editor time when you create or save a new scene, It's saved to the resource folder and gets loaded from there at runtime when we load a scene)
    Code (CSharp):
    1. public class SceneSettings : ScriptableObject
    2. {
    3.     public Scene scene;
    4.     public string scenePath;
    5.     public GameModeBase gameMode;
    6.  
    7.     public ShadowmaskMode shadowMaskMode = ShadowmaskMode.DistanceShadowmask;
    8.     public ShadowQuality shadows = ShadowQuality.All;
    9.     public ShadowResolution shadowResolution = ShadowResolution.High;
    10.     public ShadowProjection shadowProjection = ShadowProjection.StableFit;
    11.     public float shadowDistance = 150f;
    12.     public float shadowNearPlaneOffset = 3f;
    13.     public int shadowCascades = 4;
    14. }
    the line the error points to:
    Code (CSharp):
    1.  sceneSettings = Resources.Load<SceneSettings>("SceneSettings/"+SceneManager.GetActiveScene().name+"SceneSettings");
     
  8. palex-nx

    palex-nx

    Joined:
    Jul 23, 2018
    Posts:
    1,748
    Try using interface IGameMode instead of base class.
     
  9. jister

    jister

    Joined:
    Oct 9, 2009
    Posts:
    1,749
    I still need it to be a scriptable object...
     
  10. Suddoha

    Suddoha

    Joined:
    Nov 9, 2013
    Posts:
    2,824
    It definitely does work with ScriptableObjects, just like it works with components and other UnityEngine.Objects.
    This serialization layout error message is caused by other issues, e.g. scripts and assemblies that - for some reason - have not been updated properly, so that the deserialized version doesn't match the expected layout.
     
  11. Owen-Reynolds

    Owen-Reynolds

    Joined:
    Feb 15, 2012
    Posts:
    1,998
    Wait, Resources.Load? I thought people liked ScriptableObject since an Inspector slot can always be used to find them. In this case you're trying to find the SceneSettings for the current scene. Seems like some master object could have them all as an array: SceneSettings[] AllSceneSettings;.

    I don't think Resources.Load is the problem, or a problem. It just seems odd there.
     
  12. jister

    jister

    Joined:
    Oct 9, 2009
    Posts:
    1,749
    yes, the reason for Resources here was because the scriptable object "SceneSettings" gets auto generated and i wanted to spare extra drag and drop action which maybe get forgotten by designers...

    I found that i don't get the error when i put a base class version off GameModeBase in the gameMode field in SceneSettings:
    Code (CSharp):
    1. public GameModeBase gameMode;
    so my initial thought was that the extra fields implemented in GameModeGame (child) are causing the extra unexpected size. but then shouldn't it be more then 4 bytes?
    there are 12 references to objects, so on a 64bit machine thats: 768 bit = 96 bytes, is that correct?
    in C++ a virtual void adds size to a class, I have 1 virtual void in the class but I'm not sure if its the same in C#?
     
  13. Antistone

    Antistone

    Joined:
    Feb 22, 2014
    Posts:
    2,836
    The serialized size of an object won't necessarily be the same as its size in RAM when running.

    But you're right, 4 bytes difference sounds far too small to be the difference between a GameModeBase and a GameModeGame. I would guess it's not the GameModeGame object itself that's having trouble, but some other object that is being accessed indirectly, such as one of the many other classes that it includes references to. (Which means you actually need to scrutinize the source code for all of those sub-objects, too, not just the GameModeGame itself.)



    Wild speculation:

    When you make a build, Unity tries to automatically exclude assets that it doesn't think are being used in your build (for efficiency), except for scripts and anything inside a Resources folder.

    Instances of ScriptableObjects are assets.

    Is there any possibility that some scriptable object you are referencing (directly or indirectly) is being excluded from the build because of Unity not being able to figure out that it's being used? Your SceneSettings asset is presumably in Resources, but are ALL related scriptable objects also in Resources? (One would think that being referenced from something inside a Resources folder ought to be enough to keep it in the build, but I've never tested that.)
     
  14. jister

    jister

    Joined:
    Oct 9, 2009
    Posts:
    1,749
    Thanks for the suggestions! Will try it with putting all SO's in resources, just to be sure.
    But my guess is its ok, since if i drag in base instead of child, i don't get the erorr...
     
  15. Muhammad_Taha

    Muhammad_Taha

    Joined:
    Jun 21, 2015
    Posts:
    22
    I fixed it by commenting the line and full block of Unity Editor.
    Code (CSharp):
    1. #if UNITY_EDITOR
    2.     [Multiline, SerializeField] private string DeveloperDescription = "";
    3. #endif