Getting Adressables adress of an asset at runtime

I am trying to create runtime object serialization and I came across the issue that if I have AudioSource with AudioClip asset attached, I can’t save this in some kind of file (like using JSON serialization), nor I can’t really load it after. I saw Addressables as a solution, and yeah, I can load asset using it’s path, but I cant save the asset. In runtime you can’t get a path of an asset, and there’s no constant properties of an asset (like GUID) that you can get at the runtime, so I can map this thing to an asset path in editor to use it at runtime.
Can someone either tell me that no, it’s not possible at all, or there is a way to save asset\it’s path to a file and then load it both in runtime?

Addressable isn’t a save game solution. Making an addressable reference requires the GUID, which can only be found at editor time.

Addressables is for content delivery, not save games, as Spiney points out.

You can save which audio clip it was.

If it was user-generated audio (as opposed to just a sound already in your game), you would need to save whatever the user generated and recreate the audio at load time.

You can load it based on what you saved.

Load/Save steps:

An excellent discussion of loading/saving in Unity3D by Xarbrough:

And another excellent set of notes and considerations by karliss_coldwild:

Loading/Saving ScriptableObjects by a proxy identifier such as name:

When loading, you can never re-create a MonoBehaviour or ScriptableObject instance directly from JSON. Save data needs to be all entirely plain C# data with no Unity objects in it.

The reason is they are hybrid C# and native engine objects, and when the JSON package calls new to make one, it cannot make the native engine portion of the object, so you end up with a defective “dead” Unity object.

Instead you must first create the MonoBehaviour using AddComponent() on a GameObject instance, or use ScriptableObject.CreateInstance() to make your SO, then use the appropriate JSON “populate object” call to fill in its public fields.

If you want to use PlayerPrefs to save your game, it’s always better to use a JSON-based wrapper such as this one I forked from a fellow named Brett M Johnson on github:

Do not use the binary formatter/serializer: it is insecure, it cannot be made secure, and it makes debugging very difficult, plus it actually will NOT prevent people from modifying your save data on their computers.

A good summary / survey of the problem space:

One day we will be able to get an asset’s GUID at runtime and it will make all our save game systems so much simpler.

@spiney199, yeah, I know that it is not a solution, but I believed it could be possible to integrate Adressables as loading part of the system, seems like there’s not much left for the saving part

Oh, what a response! I will definitely take a look at the stuff you have mentioned, thank you!
By the way, I was able to do most of the stuff needed for my saveload system using reflections, and it worked perfectly. I also made a kind of a “demand” system, as I call it, that saves instanceID of an unity object in the scene and after loading all the objects I use it to assign them back to proper fields and properties. But yeah, sadly this trick doesn’t work with assets.
And about preventing people from modifying data, it’s part of our company philosophy, we don’t see much problem here. Like, if the person got their hands on the game, it’s fully theirs, they can break it how much as they want to. We should just make the main game bearable without person accidentally breaking the game, everything that people can think of and know this is not intended for the main game, it’s their way of having fun!

Not sure what you mean by a ‘demand system’ but InstanceID’s are not stable between runtime sessions. They are not suitable to be used for save game systems.

@spiney199
It works like this: due to instanceID changing every scene run, I have to store it manually. When I save an unity object, I save it’s instanceID, and for every field/property in it that is an unity object and is not an asset I save instanceID (as custom class Demand with three fields: instanceID of what is object demanding, instanceID of who is demanding, MemberInfo fieldThatIsDemanding) of object, that this field/property is linked to. I do that for every object that I know needs to be saved. Then, when I load the objects (using custom class with three fields: type, data of its fields/properties and intstanceID that it had when you have saved), I put them in a list (again, like a custom class: UnityEngine.Object loadedObject and its instanceID, that it had when saving). Then, when you assign the data to an Unity Object, you put all the Demand classes in the list to an another list for later. When you are done and instanced all the objects you have needed, you just go through the demands list and for every Demand, you get the instanceID of the demanding object, and find it in the list of instanced objects (because it currently has a different instanceID, but in this list we have it like it was during saving), do the same to find what is it demanding and assign it to the field, saved into Demand that you are looking at.

I use instanceID and not create my own ID for an object because InstanceID is already perfect: it’s already contained in every Unity Object, so it’s easy to save, and its unique for every Unity Object!
It may be a little unoptimised, I know, but this is the best I have come up with, and it works perfectly in both editor and build!.. Before the field contains a link to an asset and not an UnitEngine.Object on the scene… But I think it is really cool and I haven’t found something like this, though I maybe searched for not long enough time

That doesn’t sound like it would work at all. If the InstanceID’s have changed, then you have no way to marry the data from when it was saved to what object you need to assign the data to when loading.

Like I said, InstanceID’s should not be used for any save system. That is not what they are meant for whatsoever.

It also just sounds like you created your own long-winded serialization system, though to save the data of UnityEngine.Objects. Which is something I advise against doing.

And do you need to be saving all this data? Like why do you have to save every bit of data of a rigidbody? It sounds unnecessary.

Just store the data you need into a regular C# class, and write that data to disk with one of the many existing serialization libraries.

Okay, I will look into more solutions, if you really think that this is a bad idea, however it does really work.
I just use instanceID as a way to mark and then find the object, not like I am assigning it or something like this, I know this would break so much stuff, if it will work at all. I can make custom ID system that will do just that, but it simply will be longer, since I can’t directly inject it to the object to refer to it later.
And I do really need to save all objects data (at least for several cases), because my game is somewhat a physics sandbox, and for most of the development (3 out of 3.5 years) I was told that we wouldn’t need a complex saveload system, so game’s architecture is not really suitable for making custom save and load methods for everything we have in it, though it is possible, my system checks for flags for custom saving and loading in the class. So for now I have stuck to the all-serializing save method, and for it to fully work I just need a way to get any type of identificator of assets linked to fields to get them when loading.
I think I can share you some of my code later, if you want to take a look

I’m just not understanding how you match up the data saved under one InstanceID with a different instance of the (potentially) same object with a different InstanceID. Are you simply using the its index position in the data? That can also potentially be unsafe if the length or order of the list ever changes on the loading side.

Though honestly if I was making a physics sandbox game I would have everything handled by a custom data structure and simply use the game object hierarchy for visualisation (which is all it should ever be used for). Should the need for save-anywhere save games come up, then you can make sure all the data is safe to serialize and simply save all that.

Ultimately you will always need some kind of custom ID system for complex save systems. Unity doesn’t provide the tools built in to do so.

When I instance the object during loading it surely has a different instanceID, but when I save it, I save not only it’s properties, I also save it’s instance id. When I load, I have and array of class exemplars that contain: type, data, instanceID. Firstly I instantiate the object with type, then I assign it’s data (save it’s demands for later) and then I add it to a list as a custom class with two fields: thing that I have instanced, instanceID from that class with type, data and instanceID (or you can use dictionary if you want to). This is how I link new instanced object with InstanceID that it had during saving, I can then find it by this “old” instanceID by using List.Find

Sorry, there’s a language issue going on here as I don’t quite understand what your English is trying to say.

But almost sounds like the InstanceID is irrelevant? If you’re just going to use the data to generate an object, then why does the InstanceID matter at all?

Or are you only using it to reestablish Unity object references on said component? That also wouldn’t work either, as there will be different InstanceID’s in both sessions, giving you no way to match up one with another. Namely you can’t actually use that InstanceID to locate the same object, as in all likelihood the same object will have a completely different InstanceID.

It just doesn’t make any sense whatsoever.

@spiney199
Sorry for bad English, it’s not my native language :sweat_smile:

I made a diagram so I hope it will be easer to understand

Everything that is left of Save Data node is saving process, everything that is right of it is a loading process

Right, that sort of makes sense but doesn’t explain how you might, for example, restore a reference to something like the PhysicsMaterial of a rigidbody. This system would only allow you to restore references to object that you are also creating at the same time. And you naturally cannot just willy-nilly make instances of UnityEngine.Object types without knowing whether to use a constructor or a specific factory method.

Also using System.Object is incredibly unsafe and I highly suggest that you do not publish a game that does so. It allows anyone to share save files that can be malicious, and your serializer will happily deserialise things it shouldn’t and cause bad actors to do who knows what with anyone’s computer.

Unless your serializer allows you to filter specific types, and you are willing to maintain what types are safe or not, you should only use types specific to your project, or known safe concrete types. Avoid common base types like IEnumerator<T>, etc, too.

  1. Yes, this is exactly the issue, I can’t restore references to the assets, this is exactly why I created this post, to see if anyone knows how to do it if it is possible.
  2. Of course I cant just create instance of Unity Object, I simplified some of the stuff in the diagramm, in the code there’s several steps in determing how to properly instantiate it.
  3. About System.Object, this does make sence, I should have investigated this first, thank you for telling me this! As I understood, I should make system more strict so it allows only certain needed type of data to prevent unsafe deserialization, right?

Yes this is part why I’m saying InstanceID’s aren’t suitable for save games.

It is like I said here:

Okay, so now the question is what is the best way to save links to assets and then loading them back, so I can base custom ID system on it

The best way is the way that fits the needs for your project.

But it will generally always involve:

  • Some way to uniquely identify assets
  • Look up tables for said assets
  • An API that can accept a unique ID and use that to return said asset

For built in types that you can’t provide unique IDs for, you can wrap these in a custom scriptable object.

Then your save data either uses the ID’s in lieu of direct references, or you can use your serializer to substitute direct references for these IDs, or you can write an ‘indirect reference’ object: an object that encapsulates an ID, and can be used to retrieve and cache the referenced asset.

Would be worth reminding your project managers that a save system isn’t something you shoehorn in late into production. Especially for the kind of game you’re working on, it should have been planned for from day zero.

It’s a common limitation in Unity. At runtime, assets like AudioClips lack persistent identifiers. Addressables can load them, but saving a reference requires creating a custom mapping in the editor beforehand.