Saving and Loading Games in Unity with Json.NET

As I expected game persistence turned out to be a bit of beast and has taken up all of my development time for the past 2 weeks. The result is not perfect and in retrospect I would have designed for persistence earlier. Nevertheless here are a few tips and ideas that may help you on your projects:

Not Persisting MonoBehaviours

The decision to move all game state out of MonoBehaviour classes was the right one when it came to persistence. I don’t have to worry about Unity’s inner workings. I persist and load my own entity classes, and inject them into MonoBehaviours which in turn instantiate all the needed graphics and UI. I had to do some minor tweaks to these components but for the most part, it just worked.

Persistence and Dependency Injection

I’m using Zenject for dependency injection so the persistence had to fit into that. After several false starts, I ended up with something like this:

Saving:

  • All top level objects, like Product, Company, and Finances have a persistence model associated with them (ProductPersistModel, CompanyPersistModel, etc), and a corresponding IPersister implementation.
  • When saving, we resolve all top-level objects from the container, create their persistence models using IPersisters, and put them in a final GameSave object. The majority of this is automated with the use of the container and marker interfaces so we don’t have to explicitly instantiate any classes.
  • Finally the GameSave object is serialized to a file using Json.NET.

Loading:

  • We load the GameSave object from file.
  • All persistence model objects are registered with container during initialization.
  • The persistence models are (optionally) injected into the constructor of the relevant class. So ProductPersistModel is injected into Product which can use it to hydrate itself.
  • The rest of the game is initialized per normal.

Now it might seem overkill to have specialized persistence classes. However it does prevent me from having to sprinkle the [JsonIgnore] and other persistence specific code everywhere. Do keep in mind that the persistence model only exists for the top level objects (aggregate roots) and not any “inner classes”. For those I fully serialize and deserialize them, which bring me to my next point.

Serializing Child Entities

As I mentioned, only the aggregate roots have a special persistence model and are resolved from the container. Other, inner classes are persisted fully and instantiated using Json.NET. That means there are certain restrictions on these which I actually consider to be good (DDD) coding practice anyway:

  • Any dependencies (like services) should not be passed to the constructor and stored in a member variable. Instead the entity should either inform outer objects via events, or dependencies should be passed to the methods that need them. For example the Feature class informs its parent (Product) when it has completed using an event called FeatureCompleted rather than explicitly holding an instance of Product.
  • I use a custom ContractResolver to get Json.NET to serialize all private and public fields and properties. It looks something like this:

public class GameContractResolver : CamelCasePropertyNamesContractResolver
{
  protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
  {
    var property = base.CreateProperty(member, memberSerialization);
    property.Readable = true;
    property.Writable = true;

    return property;
  }

  protected override List<MemberInfo> GetSerializableMembers(Type objectType)
  {
    const BindingFlags bindingFlags = BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public;
    var properties = objectType.GetProperties(bindingFlags).Where(p => p.CanWrite);
    var fields = objectType.GetFields(bindingFlags)
      .Where(f => !f.GetCustomAttributes(typeof(CompilerGeneratedAttribute), false).Any())
      .Where(f => !typeof(Delegate).IsAssignableFrom(f.FieldType));

    var allMembers = properties.Cast<MemberInfo>().Union(fields.Cast<MemberInfo>()).ToList();
    return allMembers;
  }
}

Types and References in Json

I have enabled 2 features in Json.NET that greatly simplify persistence. Under normal circumstances where you are using Json for communication between two systems this would be code smell and not advisable. However here I’m just using it for persistence and so it’s less of an issue:

  • TypeNameHandling.Auto – This option adds a $type property to all Json objects that have an ambiguous type (ie interfaces and generics) so that during desensitization the engine knows what type to instantiate. The downside of course, is that if a type gets renamed or moved you’ll have trouble.
  • PreserveReferencesHandling.Objects – This is an awesome little option. I was originally going to implement it myself before finding out about it. In short when this is enabled if a particular object is referenced from multiple places (which will invariably happen), Json.NET will serialize it once with a $id property and for all other references simply uses $ref property to refer to that instance. So during deserilization you won’t get two instances of something that is only meant to have one instance.
  • ReferenceLoopHandling.Serialize – This goes hand in hand with the previous option, essentially allowing you to serialize a circular dependency (which while might indicate poor design, is sometimes unavoidable).

Dealing with Database Items

Like any game some assets like text, images, definitions, etc. are loaded into the game from a data store (in my case files). For these it made sense not to persist them with the rest of the game but rather load them again from the database. This way any updates to those assets would be correctly applied to a game that was previously saved.

Doing this is easy enough with Json.NET. I created a new interface to be put on any database class, called IDataStoreItemWithId which contains an Id property. I then implemented a JsonConverter class that uses the database to save/load such objects:


public class DataStoreItemConverter : JsonConverter
{
  readonly IDataStore _dataStore;

  public DataStoreItemConverter(IDataStore dataStore)
  {
    _dataStore = dataStore;
  }

  public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
  {
    var item = (IDataStoreItemWithId) value;

    var jObj = new JObject { { "id", item.Id } };
    jObj.WriteTo(writer);
  }

  public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
  {
    var jObj = JToken.ReadFrom(reader);
    return _dataStore.GetById(objectType, jObj.Value<string>("id"));
  }

  public override bool CanConvert(Type objectType)
  {
    return objectType.GetInterfaces().Any(i => i == typeof(IDataStoreItemWithId));
  }
}

What’s Next

I still have a bunch more to do on persistence but I think at this point I have hit all the pain points and now it’s just a mechanical process of getting everything into the persistence pipeline and tested. There is probably another week of that left to do.

I have also been moving forward on the art front with some exciting new progress, but that’s a topic for another post…

Art Inspiration for Startup Freak

86df8932589513-568bc2a51ef90

Over the past 9 months, as I have been working on the game, I have always had the eventual art style in the back of my mind, trying to decide on a look and feel that might be appropriate. I have looked around many different sites like DeviantArt, and GameArtisans but ultimately found Behance to be the best source of inspiration for the type of art that I think would look good in the game. For better or worse a good portion of indie game developers and artists, at least those doing 2D PC games, are focused on pixel art which is something I have tried to stay away from.

Anyway in this post I’m going to share a few of the images and artists I have been inspired by. But before that, here is a quick update of what I have been working on as of late:

Continue reading

A Short Update

I haven’t made a whole lot of progress on the game in the past week or two, mostly because I have been focusing on putting together a presentation and workshop on neural networks, and how to use R to play around with training one. Machine learning has been a side interest for a long while so it’s good to exercise those muscles every now and then.

Back on Startup Freak, I have spent a bit of time completing the UI for leveling and upgrading the servers and network topology. As I had mentioned before, I am now in cleanup and tuning phase and thinking very hard about how to procure art for the game.

That is all.

Pre-Alpha Feedback

backlog

In the past 2 weeks a number of people, mostly friends and colleagues but also some complete strangers, have played the Startup Freak pre-alpha and have given me feedback. This was great in and of itself, but what has absolutely floored me is the length and detail of the feedback. I have had people write entire documents for me, have lengthy chats, and send me exact screenshots of the issues they are running into.

I’m still waiting for a few more, but so far a couple of themes have emerged which have really given me direction. Here they are: Continue reading

Alpha Release is Very Close!

Just a short update: I have been working very hard to get a build ready to put in front of people. All of the late effort has been around bug fixes and balancing so that you can play the game for a reasonable amount of time (mind you there is still no win condition). I have also added some temporary tutorial / help text to guide players, until I figure out something more elegant for walking the players through the game. I am very close and will have something ready by the end of the coming week.

Continue reading