Unity can’t serialize Dictionaries, so I figured I’d just use a list instead. Turns out Unity can’t handle polymorphism either (which is an absolute must for me).
The class I’m trying to work with is an ItemDatabase which holds a dictionary of item. Items are put in as different children (Sniper, Staff, Consumable, Armour, etc.) and also retrieved and cast.
I’ve managed to serialize this class using the system binary formatter.
My first question is: How can I get a filepath as decent as possible? I am now using
Application.dataPath + "/Resources/ItemDatabase.dbs"
to both load and save.
Now for my second, most important question:
Saving and loading this database works, so does using the data inside of the database. However, since I’ve saved the Database to D:/Unity/Assets…etc it won’t load when I actually make a build of the game.
How can I make sure the game knows where my database is located in a build?
Do you want / need to store it as file? Using the binary formatter doesn’t require you to store it as file. You could still use Unity’s serialization system but implement the (relatively new) ISerializationCallbackReceiver interface. That way Unity calls OnBeforeSerialize right before the object is going to be serialized and OnAfterDeserialize right after the object got deserialized. You can store your data in a simple string variable which can be serialized by Unity. Since OnBeforeSerialize is called before the object is serialized you can simply use the binary formatter to serialize your custom objects into a string and have the string serialized by Unity.
In OnAfterDeserialize you just do the reverse.
However if you want to use a file you have to distinguish between storing the data at edit time and using it at runtime. To store the file you have those options:
-
- Store it in a Resources folder in your project like you have it in your example above.
-
- Store it somewhere in your Assets folder as normal Asset.
-
- Store it outside of your project and ship the file seperately. The file could also be loaded from a webserver
To read the data at runtime it depends on the way you stored the file:
-
- If stored in a Resources folder you have to use Resources.Load to get a TextAsset instance based on the asset file name.
-
- If stored somewhere in your Assets folder you have to reference your file from another serialized object by adding a public serialized field of type “TextAsset”. Just assign your file to that variable and use the TextAsset in your code.
-
- If stored seperately you have to use either the WWW class, System.IO or any other appropriate class to read the data manually at runtime.
Some important notes:
- When storing the file inside the project (variant 1 or 2) the file extension has to be “.txt” even when it contains binary data.
- When loading the file from thr Resources folder you have to use the filename relative to the Resources folder. So if the file is right in the Resources folder you don’t need any path at all, just the file name. You also have to omit the file extension when using Resources.Load(). So just use the filename.
- When implementing the ISerializationCallbackReceiver interface you should be careful what you do in those two callbacks. Those are called from a background thread so most of the Unity API doesn’t work in those callbacks. Usual C# / .NET code is no problem.
- Keep in mind that Assets can’t be changed at runtime. Unity’s serialization system can only store data in the Editor. If you want / need to modify the data you have to store it in an external file.