Reputation: 7
Consider the following setup:
using System;
class Shelf : ScriptableObject // << IS A SCRIPTABLE OBJECT
{
[SerializeField] List<Jars> jars = new();
public AddUniqueJar(Type typeOfJar)
{
//need to add a new object of type typeOfJar to jars. I currently do something like this:
sentences.Add((Jar)Activator.CreateInstance(typeOfJar));
EditorUtility.SetDirty(this);
AssetDatabase.SaveAssets();
AssetDatabase.Refresh();
}
}
[Serializable]
abstract class Jar// << NOT A SCRIPTABLE OBJECT
[Serializable]
class JamJar:Jar{}
[Serializable]
class PickleJar:Jar{}
[Serializable]
class MoneyJar:Jar{}
I'd have imagined this would all be fine -, when the editor adds to the list the listview shows my new entry - but the next time my code compiles or restart a session my object loses the data for what is stored in the jars
List and the ListView that queries it reports it as an empty list.
How do I get my method to add a new object of this type to the list while also serializing and maintaining that information between sessions?
Upvotes: 0
Views: 93
Reputation: 90630
This isn't going to work this way!
The Serializer doesn't serialize custom abstract
types - seems to be missing in the documentation though to be fair.
Anyway, even if the serializer would serialize abstract
types then it still only sees and knows the type Jar
-> it would anyway only serialize the values of a Jar
and trying to deserialize into instances of Jar
.
I think closest you will come to your use case would be to indeed convert those to ScriptableObject
and have
class Shelf : ScriptableObject
{
[SerializeField] List<Jar> jars = new();
public void AddUniqueJar<T>() where T : Jar
{
var newjar = ScriptableObject.CreateInstance<T>();
newJar.name = $"New {typeof(T).Name}";
jars.Add(newjar);
AssetDatabase.AddObjectToAsset(newjar, this);
EditorUtility.SetDirty(this);
AssetDatabase.SaveAssetIfDirty(this);
AssetDatabase.Refresh();
}
}
abstract class Jar : ScriptableObject { }
class JamJar : Jar { }
class PickleJar : Jar { }
class MoneyJar : Jar { }
To directly store those within the same asset.
Little demo:
[CreateAssetMenu]
public class Shelf : ScriptableObject
{
[SerializeField] List<Jar> jars = new();
public void AddUniqueJar<T>() where T : Jar
{
var newJar = CreateInstance<T>();
newJar.name = $"New {typeof(T).Name}";
jars.Add(newJar);
AssetDatabase.AddObjectToAsset(newJar, this);
EditorUtility.SetDirty(this);
AssetDatabase.SaveAssetIfDirty(this);
AssetDatabase.Refresh();
}
[ContextMenu(nameof(AddMoneyJar))]
private void AddMoneyJar()
{
AddUniqueJar<MoneyJar>();
}
[ContextMenu(nameof(AddPickleJar))]
private void AddPickleJar()
{
AddUniqueJar<PickleJar>();
}
[ContextMenu(nameof(AddJamJar))]
private void AddJamJar()
{
AddUniqueJar<JamJar>();
}
}
Personally I would even rather save those as separate assets so you can easily maintain, remove them etc.
Or alternatively if it is really only about having different instance types you could also just instead serialize a list of an enum
or type name and then rather on runtime create the instances of those accordingly.
Upvotes: 1
Reputation: 4591
The reason the Jar classes are not serializing is because Jar is abstract.
After removing the abstract keyword, all classes are serializing like usual.
You should remove the EditorUtility and AssetDatabase code from the scriptable object, as it is not needed for this serialization to occur.
Upvotes: 0