Manage save games in Unity without pain using NDatabase

By | Development | No Comments

As developers, we all know that save games are an important aspect to most of our games, even more so on mobile where the game can be disrupted at any time.

But how could we solve this issue? How can we store our game data in a performant and easy way without the major limitations that Unitys PlayerPrefs put on our titles?

Today, I want to introduce you to NDatabase!

NDatabase is an easy to use data storage solution.

NDatabase is written purely in C# without native code (like SQLite), making it capable of going to all Unitys platforms that can handle file operations.

Prerequirements

Before we get started, we need to ensure that we have everything ready.

For simplicity we will use the precompiled library.

You can download the ‘Download for .net 3.5′ version from https://ndatabase.codeplex.com.

After you downloaded it, extract the files content and move it into your projects Assets/Plugins folder.

Thats already all you need to start saving and loading your game data.

Define what you want to store

For this introduction, we will store data for an endless runner:

  • the current player position
  • the current score
  • the remaining lives
  • the inventory (a list of names)

We will store this information in a simple, lightweight data object that we can easily pass around as required.

We will not attempt to save a whole MonoBehavior or GameObject.

MonoBehavior and GameObject are very heavy weight objects.

Attempting to save them severly limits the complexity of the data you can store performantly.

The classes

NDatabase makes it very easy to store data.

All it requires is classes with data to store and it will handle it invisibly.

This is for example the case for object, float, int, string, bool or arrays, lists and dictionaries of these.

In our case, we want to store an array of floats for the position, two ints for score and lives as well as a list of strings for the inventory.

If we put this all together, this results in the following class:

PlayerData.cs
public class PlayerData {
    public float[] PositionData;
    public int Score;
    public int Lives;
    public List Inventory = new List ();


    /// 
    /// Gets or sets the position array
    /// 
    /// The position.
    public Vector3 Position {
        get {
            if (PositionData == null) {
                return Vector3.zero;
            }
            Vector3 result;
            for (int i = 0; i < 3; i++) {
                result [i] = PositionData [i];
            }
            return result;
        }
        set{
            PositionData = new float[3]{ value.x, value.y, value.z };
        }
    }
}

To focus on the specific NDatabase operations in the remaining post, I also want to provide the sources of the Player class you can find in the download. The Player class manages the PlayerData including the loading and saving of the data.

Player.cs
public class Player : MonoBehaviour
{
    private string _savegamePath;
    private IOdb _dataStorage;
    public PlayerData Data { get; private set; }

    private void Awake ()
    {
        _savegamePath = Application.persistentDataPath + "/savegame";
        LoadFirstSavegame ();
    }

    private void LoadFirstSavegame ()
    {
        _dataStorage = OdbFactory.Open (_savegamePath);

        Data = _dataStorage.QueryAndExecute ().GetFirst ();
        if (Data == null) {
            Data = new PlayerData ();
        } else {
            transform.position = Data.Position;
        }
    }

    private void OnApplicationPause (bool pause)
    {
        if (pause) {
            SavePlayerData ();
        } else {
            if (_dataStorage == null || _dataStorage.IsClosed ()) {
                LoadFirstSavegame ();
            }
        }
    }

    private void OnApplicationQuit ()
    {
        if (_dataStorage != null) {
            SavePlayerData ();
            _dataStorage.Dispose ();
        }
    }

    private void SavePlayerData ()
    {
        Data.Position = transform.position;
        _dataStorage.Store (Data);
        _dataStorage.Commit ();
    }
}

Creating the data storage

NDatabase makes creating the data storage as simple as it can be. All you need is a single line of code:

IOdb _dataStorage = OdbFactory.Open (savegamePath);

If you keep this reference stored on your player or a global manager, you can access the data at any time.

Saving your game the easy way

To prepare a new object to be stored, all we need to do is call

_dataStorage.Store (theObject);

This though will not yet write the data to disk. We need to finalize the changes to have them written to disk calling

_dataStorage.Commit();

In our case, we would like to update the existing save game instead of creating more and more entries in the database.

NDatabase makes this very easy, you simply need to store a previously fetched object.

As we assigned the latest player data to Data in the call to LoadFirstSavegame, all we need to do is update above Store call to

_dataStorage.Store (Data);

Loading the game made simple

Loading your save game is straight forward.

To get all stored PlayerData object, the simplest way is to call

var result = _dataStorage.QueryAndExecute ();

For the start, we will focus on getting the first PlayerData object, assuming there will only be one at any time.

This is done through the call to GetFirst:

Data = result.GetFirst();

Using Data, you can now restore the players position, score, lives and inventory by reassigning them to the appropriate objects.

Lookout

With the knowledge we now have we can already handle complex save game data sets through the ease of NDatabase. But we are still limited to the amount of data we can store in realtime as writing a lot of data takes time.

In the next article of this series, we will present you with different strategies to challenge the current limits in realtime save game sizes.

We will continue our coverage on NDatabase in future blog posts, covering NDatabase more indepth, showing you how to optimize your queries beyond the simple call, use indices to accelerate accesses even further and leveraging the In Memory database capabilities of NDatabase to manage large, complex data sets during runtime.

If you currently have a challenge with your save game handling that you want us to cover, let us know through the comments!

Learn how to kickstart your unity multiplayer games

By | Development, Mobile Development, multiplayer, photon, unity game engine, Unity3D | No Comments

Unity Multiplayer Games

Alan R. Stagner - Unity Multiplayer Games

… are no easy thing to create, so I’m glad that I recently got offered the opportunity to write a review on Alan R. Stagners book Unity Multiplayer Games

After working with Unity professionally for over 6 years and working in the multiplayer and networking field since the 90’s, this was an offer I couldn’t deny, especially as there are only very few good to learn about networking in Unity.

The book tackles the challenge in an easy to grasp and well structured way by investing the first 5 chapters to introduce different options for the multiplayer networking itself before introducing crucial core aspects that ensure a smooth multiplayer experience through interpolation and prediction of movement as well as server side hit detection to prevent easy cheating.

 

Unity Networking

The books first chapter covers Unity Networking and it is one of the rare exception in this area by covering all relevant aspects including level prefixes and the required steps to setup an own Master Server and Facilitator.
This allows the reader to create a production usable environment within half an hour upon which they can build in the future.

 

ExitGames Photon

After Unity Networking, the book dedicates chapter 2 and 3 to the two distinct technologies offered by ExitGames.
Starting out with Photon Cloud (PUN) and then followed by the Photon Server, the reader is lead through to the required steps to create a multiuser chat with friendslist and a simple, fun multiuser star collection game.

 

Player.IO

Following Photon, the book covers the Player.IO technology, guiding the user through the steps to get an application running through creating one with them.
Warning: I consider the chapter troublesome as it advertises the service.
I worked with Player.IO professionally and its a neat API but I need to warn developers and recommend not using it after working with it for over a year.
The service has not only serious problems with reliability, the staff also does not inform (paying) users about existing issues and downtimes even when asked.
Not being able to create any rooms at all for hours has been a long standing,  common issue, which prevents your game from working at all as the service is built completely around rooms (all game logic has to be put in rooms).
It often even takes weeks to solve crucial things, like paying for your plan at all (https://playerio.com/forum/viewtopic.php?f=29&t=35442) …
Should you aim for asyncronous multiplayer games, go with a service like Parse or PubNub instead.
If you want realtime multiplayer games and player persistance, then using Photon Cloud and their newly added webhook support, in combination with a Parse-PubNub-like service (or your own webservice), is a great way to go.

PubNub

PubNub is the 4th technology covered by the book and its probably the only truely different one.
The author does a great job introducing its concept to the reader to build a small but representative chat application to get the user in touch with the service and expand upon it in their projects.

 

Interpolation, Prediction and Server-side Hit Detection

The chapters cover solid base knowledge for smooth multiplayer games and are not only a must read, they are also a must know.

What leaves a somewhat sour taste after reading this chapter is the missing citication of the real authors of the interpolation code, which is Unity Technology, more specifically its code offered for years freely through the Networking Example package provided to unity users since Unity 1.x

 

Conclusion

All in all the book is highly recommendable to readers interested in learning the core knowledge required to create realtime unity multiplayer games using Unity Networking, ExitGames Photon, Photon Cloud or PubNub covering the crucial aspects related to basic authorative network architectures, movement interpolation, further things to add and problems that regarding cheating.