Serializable Class On ScriptableObject Null when loaded from AssetBundle
For modularity reasons we build our game code to a dll. The assets are build to asset bundles from scene and we load these dynamically.
We're having a specific issue where instances of an editor-created (serialized) non-monobehaviour C# class are lost when building to dll. The instanced are however stored on a ScriptableObject which is available in our AssetBundle. It seems like the instances that are defined in the inspector window and visible in the raw scriptableobject file are not being correctly instantiated in our dll build. Running from within the editor while using dll scripts still works, but a standalone Windows build results in null references (the instances do not exist). The class itself does exist inside the dll build, because we can print a static string from it.
The ScriptableObject which stores the list of the SerializeAble Class (PathTile.cs)
[CreateAssetMenu(menuName = "KnuffelGame/KnuffelPath")]
public class KnuffelPath : ScriptableObject
{
[SerializeField]
private List<PathTile> tiles;
private float cleanedPercentage;
private bool isFinalPath;
public List<PathTile> Tiles
{
get
{
return tiles;
}
set
{
tiles = value;
}
}
}
The Serializable Class
[System.Serializable]
public class PathTile
{
[System.Serializable]
public enum Direction
{
Up,
Left,
Down,
Right
}
[SerializeField]
private Vector2 tileCords;
[SerializeField]
private Direction direction;
public Vector2 TileCords
{
get
{
return tileCords;
}
}
public Direction TileDirection
{
get
{
return direction;
}
}
}
And an image of where we create the PathTiles in the editor
Below is the saved ScriptableObject which has this list stored in text, this ScriptableObject is referenced in the scene and also available in the build, since we can debug it. This is the ScriptableObject that is visible in the image above.
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!114 &11400000
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInternal: {fileID: 0}
m_GameObject: {fileID: 0}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: a4a21c2da3d5300449d25802ea791b03, type: 3}
m_Name: Path02
m_EditorClassIdentifier:
tiles:
- tileCords: {x: 1, y: 2}
direction: 3
- tileCords: {x: 1, y: 3}
direction: 3
- tileCords: {x: 1, y: 4}
direction: 3
- tileCords: {x: 2, y: 4}
direction: 2
- tileCords: {x: 3, y: 4}
direction: 2
- tileCords: {x: 4, y: 4}
direction: 2
- tileCords: {x: 4, y: 5}
direction: 3
- tileCords: {x: 4, y: 6}
direction: 3
- tileCords: {x: 4, y: 7}
direction: 3
- tileCords: {x: 4, y: 8}
direction: 0
- tileCords: {x: 3, y: 8}
direction: 0
But for some reason the list of Tiles does not get created, it ends up without items. We tried building the scriptableobjects to a non-streamed AssetBundle and load these separately but faced the same problem.
There are a few things unclear. When you say you build your game code to a dll, that's nothing new, that always happens. So the question is, do you do anything "special" with your dlls? Are the dlls somewhere inside the Assets folder when you build your game? Are the two relevant classes ($$anonymous$$nuffelPath and PathTile) in the same dll? Are the dlls loaded manually / dynamically through code or are they just part of your project? What's the exact reason why you build your own seperate dll? $$anonymous$$odularity is greatest if you just keep the source files when building the game. Do you exchange / update code after the build? It's possible that Unity builds internal metadata for the serializable classes which might be missing if you exchange code after the build.
Do you use Unity's AssemblyDefinition files or do you build your dlls completely manually / externally? If you build them manually, what .NET version do those dlls have.
Let me try and answer your questions. Thanks for taking the time for this.
What's the exact reason why you build your own seperate dll? -We are actually building a platform for different 'games'. Not everyone will have all games, so the games should be buildable separately. We have a 'core' dll where all platform specific software is in. All separate 'games' are made up of 2 parts. An asset bundle, created from Unity. And a dll that's built outside Unity, which references our core dll. We use the original scripts to develop the 'games' in. Once we are ready to build it, we have a separate .NET (3.5) Assembly project that we build and with a tool from the Asset Store we switch all Asset references in Unity from the original C# scripts to those of the dll. After switching, we create the assetbundles for the game. This process is working for all our 'games' except for one, in which the problem described above occurs. We suspect it might be a Unity bug where the references in the dll's are not propagating correctly when they are referencing each other.
On runtime we load the dll dynamically, which is placed in the '$$anonymous$$anaged folder'. After that we load the assetbundle, which is placed in Strea$$anonymous$$gAssets. As I said, this works for all other games. When testing in the editor, we either run from the original scripts, or after we use the DLLSwitcher, we use the dll's which we place in the Plugins folder.
Are the two relevant classes ($$anonymous$$nuffelPath and PathTile) in the same dll? - Yes Are the dlls loaded manually / dynamically through code or are they just part of your project? - Dynamically in build, Part of project in Editor
Do you exchange / update code after the build? - We will rebuild games dll's and anssetbundles once the core dll is changed
Do you use Unity's AssemblyDefinition files or do you build your dlls completely manually / externally? If you build them manually, what .NET version do those dlls have. - Externally. .NET 3.5
I hope this helps. We encountered issues with this process a month ago, which turned out to be a Unity issue solved in 2018.3.7, so perhaps it is related.
Answer by Brust94 · May 03, 2019 at 05:54 AM
Hello @TimonSpringlab ,
I got a similar issue writing some serialized classes for my game and loading them at runtime using AssetBundles. I finally got this working by using simple fields instead of properties (without getter and setter).
Here's an example :
[Serializable]
public class MySerializableClass
{
public Vector2Int aPosition; // without { get; set; }
public GameObject aGameObject; // without { get; set; }
}
Answer by bmeijer · May 17, 2019 at 09:48 AM
@TimonSpringlab Did you manage to find a fix for this?
Adding a .dll to the project with the name of the games' .dll and building the entire project with that dll included seems to work for now. It seems like the fact that a dll is present in a build changes the file: globalgamemanagers to include the serialized classes.
Your answer
Follow this Question
Related Questions
Scriptable Object issues when inside .dll 1 Answer
Serialize a list of class containing ScriptableObject assets 0 Answers
[SOLVED] ScriptableObject generic list makes all derived instances to base type when serializing 1 Answer
ScriptableObject not Serializing? 0 Answers
Deserialize an outside object in Unity 0 Answers