How to get the instance of a ScriptableObject

I’m trying to make an Inventory system similar to the one from Skyrim and I have just finished item equipping. I have tried to make it so that if the player tries to equip an item that is already equip it de-euips. I have made that functionality by detecting if the item that is equip is the same as the item you are trying to equip (Using ==) it will de-equip that item. I am using ScriptableObjects with [CreateAssetMenu()] as the base class of my items. This way I have a template for my items and they are all .asset. The downside to this is that all of the items are considered the same, so if I try and equip a different copy of the same equipment .asset it de-equips the item. Is there a way I can save a unique instance id in my item class so I differentiate copies of the same template?

EDIT: Sorry, maybe I was misleading. I mean If I instantiate multiple instances of the same .asset, I need some way to differentiate between those objects, not just between different .assets from the same script.

Perhaps you can fetch a get only integer ID using the GetHashCode function using the hash of the asset and class name in the OnValidate magic method as such …

public int UniqueID { get; private set; }
private override void OnValidate()
{
    int assetNameHash = name.GetHashCode();
    int typeHash = typeof(type).GetHashCode();
    int uniqueID = assetNameHash ^ typeHash;
    if(Mathf.Approximate(this.UniqueID, uniqueID) == false) return;
    UniqueID = uniqueID;
}

That being said, it won’t immediately update when you alter the name of the asset, so you may have to
the data to force a validation in order to correct the ID.

Might not be the best solution, but it’s a solution.

You can find instance of ScriptableObject this way:


#if UNITY_EDITOR
        public static ExampleData Load() {
            string[] guids = UnityEditor.AssetDatabase.FindAssets("t:ExampleData");
            if (guids.Length == 0)
            {
                return ScriptableObject.CreateInstance!!
            }
            else
            {
                string path = UnityEditor.AssetDatabase.GUIDToAssetPath(guids[0]);
                return UnityEditor.AssetDatabase.LoadAssetAtPath<ExampleData>(path);
            }
        }
#endif

Editing: “return ScriptableObject.CreateInstance()” is not this before ‘()’ ExampleData in <> same thing LoadAssetAtPath!!(path);
But this code works only in Editor because this code is Editor code so it is inside in the ‘#if UNITY_EDITOR’.

I think you shouldn’t use ScriptableObject for this
because you can’t save the information inside ScriptableObject in the Build. You need to use a save system for this.
You can use like this:


public class TPP_DB
    {
        static string dataPath;

        public static void Save(System.Object _saveObject)
        {
            if(_saveObject == null) return;

            BinaryFormatter bf = new BinaryFormatter();
            if(dataPath == null)
            {
                GetDirectory();
            }
            FileStream file = null;
            if(!File.Exists(dataPath + "/Save/db.sav"))
            {
                file = File.Create(dataPath + "/Save/db.sav");
            }
            else
            {
                file = File.Open(dataPath + "/Save/db.sav", FileMode.Open);
            }
            if(file != null)
            {
                bf.Serialize(file, _saveObject);
                file.Close();
            }
        }
        public static TPP_Data Load()
        {
            if(dataPath == null)
            {
                GetDirectory();
            }
            if(dataPath != null)
            {
                if(File.Exists(dataPath + "/Save/db.sav"))
                {
                    BinaryFormatter bf = new BinaryFormatter();
                    FileStream file = File.Open(dataPath + "/Save/db.sav", FileMode.Open);
                    TPP_Data loadedData = (TPP_Data)bf.Deserialize(file);
                    file.Close();
                    return loadedData;
                }
                else
                {
                    return null;
                }
            }
            else
            {
                return null;
            }
        }
        static void GetDirectory()
        {
            string[] paths = Directory.GetDirectories(Application.dataPath, "TerrainPathPainter", System.IO.SearchOption.TopDirectoryOnly);
            if(paths.Length > 0)
            {
                dataPath = paths[0];
                dataPath = dataPath.Replace('\\', '/');
                dataPath = dataPath.Substring(dataPath.IndexOf("Assets"));
            }
        }
    }

Hey, I found this thread

It solved my problem. After I did the solution I could just compare the two objects with an == operator.