Hi, Recently I’ve been refactoring some of my ScriptableObject classes and faced some problems.
Here’s an example -
Let’s say I made a scriptableobject named ‘Item’.
public class Item : ScriptableObject
{
public enum Type { Potion, Weapon, Armor }
public Type type;
public int price;
public Vector2 position;
public int restore_amount;
public int damage;
public int defense;
}
After making 100 items, I decide to seperate Item class into ‘Potion’, ‘Weapon’, ‘Armor’.
public class Potion: Item
{
public int restore_amount;
}
public class Weapon: Item
{
public int damage;
}
public class Armor: Item
{
public int defense;
}
Data migration is not a problem here, I can just write a script that reads all the ‘Item’ type resources and recreate ScriptableObjects by types. The real problem is reference.
During the development, plenty of Scene’s gameobjects & Other ScriptableObjects already referenced Item scriptableobject.
So, If I delete and replace old item scriptableobjects into newly refactored Potion/Weapon/Armor scriptableobjects, Every references will be lost. It’ll be pain in the ass if I manually replace all the lost references.
This example is a simplified version of the problem I’m facing now, but you’ll get the point. How can I resolve this reference problem? Any suggestion will be really helpful. Thank you!
Have you tried simply selecting the new script on the scriptable objects? I have a feeling this may work and you won’t lose your serialised data. You may be able to multi-select them and do it easily?
ScriptableObjects, like other UnityEngine.Objects, are stored by reference to their GUID. The GUID is stored in the .meta file of the ScriptableObject. This is hackable - you can simply rewrite the GUIDs of files to swap which item is referenced in scenes.
Say you have an old Item SO, and want to replace it with a Potion SO. Simply open the .meta file of the Item, save the GUID, create the Potion, delete the Item, and overwrite the Potion’s GUID with the old Item GUID. You can do this from editor scripts, though there’s no API to do this directly, so you have to edit the .meta file as text. I’m also pretty sure you’ll have to reimport the asset after you’ve done the switcheroo.
Thank you @Baste , GUID edit seems to be a solution. I simply Copy & Pasted Original scriptableobjects’ meta files and it works.
Some comments for other guys who see this thread in the future - If you’re working with a game that requires complex & frequently changing data structure, I recommend you to manage most of your datas in text files like json / xml / etc then parse & save them into scriptableobjects with script. I think this way is a much more flexible way to respond to your frequent data structure changes. I’ll choose this way in my future projects.
Yes I do this in a couple of our puzzles games. Json file describing puzzles is exported from external tool and in Unity I import and create a ScriptableObject.
I know this is old, but I thought I’d add it anyway in case anyone finds it useful.
A simple solution I used in a smaller project (less custom editors to add the base reference to) was to create my own ScriptableObject / MonoBehaviour base class and switch my heirarchies to inherit from that. I gave it a Copy/Paste button in the inspector. Then just used JsonUtility to serialize to a static string and back again.
@GarlicDipping hey, I am trying to replace scriptable object file in my project. I wanted to ask you How did you do it.
Did you just Copy and Replace the meta files and noting else. Please guide me as soon as possible.
I’m not sure about what kind of problem you’re facing, but if you mean you want to replace SO asset named ‘A’ to other asset ‘B’, and want to maintain other assets not to lose its reference to ‘A’, then simply replace asset ‘A’ to ‘B’ in your System explorer. (I mean, don’t touch .meta files!)
This will make unity editor NOT change .meta file of asset ‘A’, and reference will not be lost. Which means asset ‘A’ will smoothly change to asset ‘B’.
Hello @GarlicDipping I’m from the future and I’m doing exactly what you said here:
The problem I got is also losing the references whenever I use ScriptableObject.CreateInstance while deserializing data (whenever I load data, new instances are created with same names but not keeping references and hidden). Although messing with the InstanceID seems tempting, those IDs are not persistent. I’m convinced to welcome ScriptableObjects in my code, but I need a secure way to load and save data from external files directly using scripts and not messing with the editor. Could you please explain how did you solve it?
In case it helps, what I’m trying to do is loading and saving my game config in a json using ScriptableObjects, so I can mod it or enter new data without having to rebuild (similar to what @andymads said above). I had some problems with ScriptableObjects List and de/serializing polymorphism, so I followed @Dextozz tips here https://forum.unity.com/threads/saving-a-list-of-scriptable-objects-to-json.856783/#post-6007802 and also used this Newtonsoft.json package https://github.com/jilleJr/Newtonsoft.Json-for-Unity instead of Unity’s. My main issue is keeping references of ScriptableObjects with json files and in a persistent way, but maybe I’m not in the right path. Thanks.
Hey @danbg . As far as I’m aware there’s no way to serialize / deserialize references at runtime. I think serializing a reference converts it to an instance ID integer value which is not persistent between runs of the game.
For something like saving game config, I’d recommend splitting your SOs into player-facing ones that don’t use references, and then editor / dev specific ones that do. I’d do that even if serialization works as you’re essentially exposing the reference to the player in a text file anyway - it would be really easy for them to break things.
One simple way to do this is to group all your config info inside a [Serializable] class inside the SO, and serialize / deserialize that. Eg:
public class MySettings : ScriptableObject
{
[SerializeField] private MySettingsConfig m_Config = null;
// Reference type serialized fields here
[Serializable]
class MySettingsConfig
{
// value type serialized fields in here
}
public void Save()
{
var json = string ToJson(m_Config);
// Write to disk
}
public void Load()
{
// Read from disk
JsonUtility.FromJsonOverwrite(json, m_Config);
}
}
Hi @YondernautsGames thanks for replying. But if I do that, am I not just reusing a singleton pattern? Would I need to reference in each ScriptableObject to this single config ScriptableObject, or the other way around, have a lot of ScriptableObjects around and reference to them in my config ScriptableObject? If I don’t reference anything why should I use ScriptableObjects then? I could have everything in “MySettingsConfig” but how do I connect that to all the ScriptableObjects in my project?
For example, I have a ScriptableObject for some vars, like health or time, and some complex ones for levels. My GameObject and scripts are connected to them in Editor (that’s the power of SCriptableObjects, isn’t it), and my main config ScriptableObject is also referencing them to be able to save and load them. I build, and then in beta testing we found that we should change the time and do some other minor tweaks, or create a whole new level. Instead of building again, someone just edit the file, reload the file, and that should be it.
Not really, as long as the data you want user facing is value types. Each one of those “MySettings” SOs (or behaviours for that matter) can have its own config. However, if you’re doing things like level layout with SOs and you want to reference items in the scene, then you’d need a different solution. Unity really isn’t that friendly for this side of things and you essentially need to give each item its own unique persistent ID (harder than it sounds to automate, but not that bad to do manually) and use that to rebuild references at runtime (you store references by ID, not directly). You can hide that behind an ISerializationCallbackReceiver to make it a little easier to work with if you like, but it’s still a complex thing to implement. If you’re talking about referencing and placing prefabs then you can also look at the new unity addressables system for a bit more of an off-the shelf solution, or the odin serializer (as used in the odin inspector & serializer asset) is a good open source solution: https://github.com/TeamSirenix/odin-serializer
@YondernautsGames I guess I could just reference values, but in that case I still don’t understand how to do it.
For example, if I have a time value for UI animations in my scenes, with ScriptableObjects I just reference to it directly and just it, I don’t want to reference to the whole config. But if I load the config data, that reference is lost. Should I create a persistent ID for each variable like that? That sounds like madness…
I don’t mind using Odin Serializer if I can save/load json data (there is more stuff going on in my project, using Node.js and Pyhton, so I need a universal way to manage data), but I’d rather not use Odin Inspector. But in that case, is Odin Serializer going to keep the references? Newtonsoft.json is serializing and deserializing data already, but references are the main issue.
Addressable ScriptableObject seems a good solution, but then I wonder if I should KISS just with singletons.
KISS is usually a good idea for sure if you can do that.
Per object, not per variable. I mean it’s kinda case by case depending on what you’re doing. If you’re saying that each variable like that is its own scriptable object which is shared by the UI objects then yes, using persistent IDs for every one gets very complicated.
Wow! This just saved me a TON of time. Thank you. Had no idea there was debug mode in the inspector. And it supports multi-object editing so it makes it super easy to switch scriptable types on the fly. Thank you so much.