Skip to content

Instantly share code, notes, and snippets.

@CharlieHess
Created June 6, 2023 17:21
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save CharlieHess/92f18b9dbb2723fcc8a0fe76df18744e to your computer and use it in GitHub Desktop.
Save CharlieHess/92f18b9dbb2723fcc8a0fe76df18744e to your computer and use it in GitHub Desktop.
Flexible serialization using SOs and DTOs
[Serializable]
[JsonObject(MemberSerialization.OptIn)]
public class Item {
[JsonProperty]
public string Id;
// ... other stuff
/// <summary>
/// This only needs to be implemented for *mutable* serialized properties.
/// Properties that already exist on the ScriptableObject will be cloned
/// during deserialization and are never persisted.
/// </summary>
public virtual void PopulateFromJson(JObject json) {
}
}
[CreateAssetMenu(fileName = "Item", menuName = "Scriptable Objects/Items/Item")]
public class ItemAsset : ScriptableObject, IItemAsset {
// ... all your properties
public virtual Item CreateItem() {
return new Item {
// copy properties from the SO into the instance
};
}
}
using System;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Zenject;
/// <summary>
/// Items by default only serialize their ID, which we can map to a scriptable
/// object in the ItemRegistry. Any mutable properties beyond that template
/// must be deserialized in Item.PopulateFromJson.
/// </summary>
public class ItemConverter : JsonConverter<Item> {
[Inject] protected readonly ItemRegistry _itemRegistry;
public override bool CanWrite => false;
public override Item ReadJson(
JsonReader reader,
Type objectType,
Item existingValue,
bool hasExistingValue,
JsonSerializer serializer
) {
var json = JObject.Load(reader);
var id = json["Id"].Value<string>();
var newItem = _itemRegistry[id].CreateItem();
newItem.PopulateFromJson(json);
return newItem;
}
public override void WriteJson(JsonWriter writer, Item value, JsonSerializer serializer) {
throw new NotImplementedException();
}
}
/// <summary>
/// A collection of all ItemAsset ScriptableObjects, keyed by their ID, which is also their filename.
/// </summary>
public class ItemRegistry {
protected Dictionary<string, ItemAsset> _registry;
public ItemAsset this[string id] => _registry.GetValueOrDefault(id);
// I use Zenject to populate this singleton, but you can just as easily use Resources.Load
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment