Question: How to go about serializing asset references?
I understand this is a very hard problem because Unity doesn't give access to much at runtime.
What I'd really really like to do, is serialize to disk an object, which contains references to a bunch of Unity assets (mostly prefabs but also FullInspector SharedInstances), and for those references to be hooked up again on deserialization.
My use case is save games; many game objects (plain C# classes for me) have a bunch of state, but also store references to config classes which are loaded from assets. I don't want to save out copies of these assets - I want to reload them from the asset.
If Unity provided an asset database, and GUIDs on objects at runtime, that would be perfect.
Have you given this any thought, and if so did you come to any conclusions?
Create this database yourself, make a scriptable object and in editor write a script that collects all your assets into it, or something similar if you are using asset bundles. After that write and fs converter that would serialize the ids of assets in your database, and on deserialization would convert it back to asset by looking them up.
Oh I should have updated this issue! I found a way to do this.
What I'm doing is building an object <-> ID mapping deterministically, by traversing my config assets (which ultimately reference every asset in the game) using reflection, embedding fixed IDs in some assets which I control, and generating IDs by hashing paths from the last fixed ID, for assets I don't control (e.g. prefabs, anims). Since this is deterministic, I can generate it on each run of the game and it'll all work out. Cycles etc. have to be considered carefully, of course!
I then added the ability for fsCyclicReferenceManager to pre-populate its _marked and objectIds fields from this mapping, so when serialization encounters one of these externally stored objects, it serializes out a reference to it, and conversely on deserialization, it will fix up the reference to the object. Again, this works because of the deterministic way IDs are generated.
I should note that the IDs I generate are all negative, so there are no clashes with fsCyclicReferenceManager's generation of IDs, which are all positive :)
I should also note that this is particularly nice since I generate IDs for inner parts of assets too - so if I have a ScriptableObject for a 'Character' and that stores a list of Items (which themselves aren't ScriptableObjects, just serialized classes), then they get IDs too, and my game code can safely store references to them... as long as the path to them doesn't change between save and load, as that will change the IDs!
I'm using this in production at Two Point, on Two Point Hospital. We have tens of thousands of asset IDs generated this way, and with some careful optimisation, I have the asset ID mapping getting generated in something like 0.2 seconds, which I do once at startup.
I hope this helps somebody! Some day I plan to release the code or write an article since I think it's something that's quite useful to do, no matter what the serializer used, but I've got to concentrate on shipping the game first :)
Thanks for update!
Your approach sounds pretty interesting. Hope you get the change to publish something on it in the future!
I've been planning a major refactor of FullSerializer by using some ideas from Utf8Json, but it's hard to find the time (same as you: shipping comes first!).