Bro, do you even save?

Yesterday I made a post in the Asset Store section about a tool I’ve been working on that helps you make saved games:


http://forum.unity3d.com/threads/recorder-serialization-seeking-testers.314568/

(No, keep reading. This post isn’t an ad, really.)

It does something I consider useful: makes it easy to save and and load data that’s stored in your MonoBehaviour-based scripts. It basically lets you treat MonoBehaviours as if they were Serializable, which lets you store your game data in a more natural way.

So, the post was bumped out of the first page within a few hours, as sometimes happens. While thinking about why (to see if it could be improved), I figured I might’ve overestimated the number of people who actually care about adding a Save/Load feature to their games.

So that’s what this post is about. How many of you actually care about adding Saving/Loading to your games? And if you do, is there an existing approach that does the job so well you don’t really worry about it?

Much obliged for any info. I’m curious about how you people do things.

  • Orion

Player Pref’s are great for prototypes and smaller games, I generally use them in prototyping. Until the save / load system becomes an actual problem I wouldn’t consider building one or replacing it. So there might not be an immediate need.

Stick it out, you only posted it yesterday. Come back in a week and see if it has caught any traction…

2 Likes

“Generic statement and praise about JSON” -People

Any details about how the data is stored?

@ I like to roll a new saving structure and parsing system for every project I have that involves saving :smile:

Working with strings is fun!

1 Like

Your data is still written in JSON, Xml, Binary, etc. You JSON soldiers- keep doing your thing. :slight_smile:

The tool isn’t a new serialization format. Instead, well…I can’t say it any better than the copy text I wrote earlier :stuck_out_tongue: :


Basically, Recorder Serialization works by inheriting your script from a ‘Recorder’ class. This lets you add ‘Read’ and ‘Write’ methods to your scripts. Here’s an example:

using UnityEngine;
using System.Collections;
using RecorderSerialization;

public class ExampleLight : Recorder
{
    private bool lightIsOn = false;

    // toggle the light on/off
    public void ToggleLight()
    {
        lightIsOn = !lightIsOn;
        SetDirty("LightToggled");
    }

    // called when this ExampleLight's data is saved, if "LightToggled" is dirty
    [Serializer("LightToggled")]
    void OnSaveLight()
    {
        // save the light's 'on' state
        SaveValue("lightIsOn", lightIsOn);
    }

    // called when this ExampleLight's data is saved, if "LightToggled" is dirty
    [Deserializer("LightToggled")]
    void OnLoadLight(int version)
    {
        // load the light's 'on' state
        if(!TryLoadValue<bool>("lightIsOn", out lightIsOn))
        {
            Debug.LogError("lightIsOn was not loaded.");
        }
    }
}

Using these, you can save any data you’d like from inside those scripts, plus data from built in Unity Components like Transforms, RigidBodies, Animators, etc. The actual values are stored as key/value pairs. These Read/Write methods can also be called conditionally, so you’re not saving every field/property of your objects every time you make a save- only what’s changed.

There are some frilly extras as well, like the ability to save and load Object references, and the option to reinstantiate prefabs on load. Also save-versioning, for backwards compatibility with older saves.

When it’s time to save, you call a ‘SaveData’ property on your object. This will bundle everything that needs to be saved into a surrogate object, which you can serialize. When you deserialize that object later, it will automatically find the object that created it in your game, and use it to load back it’s saved data.

Ok, so it does a pretty significant thing…

… and it fell off the front page of a busy forum quickly:

My guess is that not enough people are making decisions about how to handle non-trivial game saves for large projects on an hourly basis. I wouldn’t jump to the conclusion that nobody’s interested based on just a few hours.

If I need this I design it in up-front and make sure I’ve got a clear delineation between data the needs to be saved and data that doesn’t. Once that’s done I don’t think I’d feel the need for some fancy generic system to handle it for me. Having said that, I’m a professional software developer with nearly a decade of experience - probably not your target market.

2 Likes

I will need a saving game solution. I’ve kind of been glancing at a few of them for over a year now. And I’m not a professional developer, just a hobbyist. That being said, I keep my eye out for things, but only purchase assets or systems when I absolutely need them, or I’m at that stage in my game where I’m ready to implement a given system.

Your system might be great for me, I don’t know. I’m not at that stage in my game yet though – but I will need a “save game” system in the near future. And by near I mean between now and 3 years from now lol.

@angrypenguin Thanks. You make a good point there- a lot of developers who will actually take a project past the prototype stage are used to rolling their own serialization features. And I’m like that too- it would take a lot for me to actually adopt someone else’s code for a large part of my game- I just like writing those systems myself.

So, just out of curiosity, let’s say you’re at the start of a new project, and you haven’t designed anything for serialization yet. What would it take to make you consider using something like this? What would you be worried about/turned off by?

You’re right, I’m not bummed that my thread got bumped. I see how me bringing up in the OP could have sounded like whining. So to set the record straight, that wasn’t intentional. Thanks for the feedback. :slight_smile:

@Velo222 Thanks for the info. Let me know if you’d ever like to take this solution for a spin. And since you’ve been shopping around for a while, I’d be curious to hear what features you’d like to see in a saving solution/have seen in the ones you’ve considered.

I went with a somewhat unconventional method of saving/loading on my current game, which is using a SQLite database. So far it’s working great. I use an asset called SimpleSQL that lets you do LINQ-like queries. It’s all rather straightforward and civilized. There are down sides (like any solution to anything), but I dig it.

It’d be overkill for a lot of games, but for a game with RPG elements, like for storing many inventory items that can be owned by any number of entities, it’s a pretty sweet solution.

I initially tried a free generic serialization solution on the Asset Store, but could never get it to work. I could see a more bullet-proof asset being rather useful for most games, though I imagine there are already a ton of those?

1 Like

In the interest of helping your market research, here’s why I would not be your target audience: While I’m fine with trusting someone else’s code for quite a few things, there is no way I would trust someone else’s code for saving important game data. You screw up player save data and they will be breaking out the torches and pitchforks and heading to your house. No way am I going to risk saving on anything but code I know down to the last detail.

Okay. So maybe I know more about saving client data than saving game data, but the principle is the same. Because I’ve had to make adjustments to pretty much every piece of Asset Store code I have bought, I just don’t see myself ever trusting any Asset Store code for mission critical things like saving. (This is not a knock on the Asset Store. It is just that an Asset Store save system won’t have the testing and engineering behind it as, say, one of the major database systems. Thousands of people use those every day, so I feel I can trust them within their known limits.)

3 Likes

That is an excellent set of arguments, Socrates, an excellent set of arguments…

Tell you what- I care much more about sharing this approach than making any money off of this asset. I’m promoting this because I think it’s a smart way to work, and I’d love to contribute something that might being a good solution for someone.

I’m considering putting it on the Asset Store, mainly so there would be an official version that could be tracked and updated. But you’re right- there would be a specific type of stank associated with that, even (especially?) if it was free. Trouble is, posting it online for free somewhere else might have an amateurish connotation that would turn some folks away. And it’s slightly too complex to post on a repo like Github- and at least have people easily make sense of it.

I’m going to spend some time thinking about the best way to do this. Thanks again.

It’d have to fit in with that stage of design, not be an overkill/clunky/everything-including-the-kitchen-sink approach, and it’d have to be clear that the person who made it was more experienced in this area than I am (and at least as experienced in general).

The thing is, as long as you design it in up front I can’t see what a fancy 3rd party solution can do for me that built in .NET functionality wouldn’t. (That could of course be because I haven’t done any mammoth custom saving of my own. And I’ll admit, I have run into issues with the built in DataContractSerializer…)

2 Likes

The rhetoric I picked up from 4 years of college in both CS and IT courses is that you shouldn’t reinvent the wheel. If your solution is easy to use and reasonably efficient, then people may opt to use that instead of write their own. I would suggest maybe having a video of using it for very complex project but also very basic projects so you reach out to a broad range of people.

Not everyone is going to love dealing with strings like some of us do :stuck_out_tongue:

1 Like

Go explicit or go home. :stuck_out_tongue: Using string (or int, etc.) keys to name fields for serialization can save so much hassle is you ever need to add, remove, or change data. It adds a level of security and future-proofing, which is why every major serialization format supports it (Xml, JSON, soap, binary, protocol buffers, etc.).

It’s only my opinion, but I’d rather spend a little time being explicit about how stuff gets saved, rather than hand my fate to a system that attempts to automatically serialize stuff in mysterious ways. :slight_smile:

If I didn’t know exactly how my game’s serialization was happening, I would never feel comfortable asking players to use it.

1 Like

@orionburcham if you offer a way to encrypt / secure this data and possibly easily make the serialization be sent to a web server or have a choice of local directory, you’ll have a lot more to offer. Storing and parsing is pretty simple, but there are a lot of developers with the “play my way or go away” mindset (like the devs at diablo 3). If you can make the saved files unreadable outside of the game then I’m pretty sure more ‘serious’ developers will be interested.

I do my best to have an external, plain text document that my users can ‘mod’ and corrupt to their heart’s content.

1 Like

hmm…Aha! Ok, I think we’re actually talking about different things.

When I said:

I meant this kind of thing (this example uses the ISerializable interface- unrelated to my product):

[Serializable]
public class MyItemType : ISerializable
{
    // The value to serialize.
    private string myText;

    // Implement this method to serialize data. The method is called
    // on serialization.
    public void GetObjectData(SerializationInfo info, StreamingContext context)
    {
        // Use the AddValue method to specify serialized values.
        info.AddValue("myText", myText, typeof(string));

    }

    // The special constructor is used to deserialize values.
    public MyItemType(SerializationInfo info, StreamingContext context)
    {
        // Reset the property value using the GetValue method.
        myText = (string) info.GetValue("myText", typeof(string));
    }
}

Take a look at the last line of code inside of GetObjectData(). The name string property is being serialized as a key value pair with the string key “myText”.

That’s different from the serialization format, which determines how human-readable the end result file is. If the above example was serialized to a binary format, it wouldn’t be human readable at all (and could be further encrypted however the developer might like). But in code, on the authoring side, the values would still be saved/loaded as string/value pairs.

The main benefit is that it avoids the serializer trying to load values based on the name of the field, or by the order the fields appears in the class, or by alphabetical order, etc. All of these can end up breaking save files if you end up adding or changing data, which can be painful to fix.

So, apologies for being pedantic there. That’s what I was was saying in my last comment.

Here’s an example of the above class done the same way using a DataContract model. Same concept- the field are being saving using explicit string keys:

[DataContract]
public class MyItemType : ISerializable
{
    // The value to serialize.
    [DataMember(Name = "MyText")]
    private string myText;
}

There’s high demand for reliable, effortless save systems.

The Dialogue System has a general-purpose save/load subsystem. Its core purpose is to save the Dialogue System’s state (who you’ve talked to, what you’ve said, what quests are active, etc.), but you can also tie other data into it. Since the Dialogue System includes integration packages for frameworks like UFPS and ORK, it was easy enough to provide out of the box saving and loading for them. Saves and loads just use a big string that the developer has to save somewhere such as PlayerPrefs or a local disk file, so I wouldn’t call it 100% comprehensive, although it does most of the hard work for you.

Even so, to my surprise some people buy the Dialogue System primarily for the save/load subsystem. I think this hints at a big need for a plugin that you can just drop into an existing framework like UFPS and get a complete save system without having to fiddle with any scripts.

They may, but it’s competing with stuff already built into .NET as well. My question would be, as an experienced programmer who’s (presumably) going to do this right from the start, what does this solution do for me that built-in .NET serialisation does not?

On that note, this…

… is a great point - not everyone designs every project from the ground up, so a drop-in solution that “just works” could absolutely have value there.

I buy game frameworks from the same author and their frameworks include gave save/restore functionality already.

Likewise, it depends on the developer/hobbiest - are they out to become experts at the current technical systems and their hobby is essentially learning more of those things and relearning the systems as they are obsoleted (I’m a developer and systems administrator and I’m used to doing that already) or, like me, will they try to minimize the learning as much of the technical things as possible and learn to create games as simply as possible.

Both have their merits but the 1st is liable to write or want to write their own game save/load system and the 2nd is liable to use as few assets and packages that get the job done. So a package like yours is strictly for those that truly have commercial aspirations and that don’t want their staff writing such software for each game but want the same technique used every time.

Now, when & if I get to expanding the functionality of those frameworks I bought it may be better to expand the author’s included system or if it gets to be too non-optimal, look at another system.

There is no shortage of game save systems already in the asset store though.

My [questionable] understanding of this topic was that some degree of serialization could be done for objects that could previously not be serialized with simple .Net calls.

Especially in the Unity community, haha.

Just goes to show the skill level of developers entering the game development community. Not necessarily a good or bad thing, but still interesting. Parsing and string manipulation was touched briefly in high school, CS100 and CS280. Are people getting into this field also this new to programming?

Could be quite the tutoring opportunity on the job forums here.