Skip to content

Player Saved Data

ISavedData

ISavedData has the basic foundation for saving and loading any content. This interface includes the signatures for methods such as Load, Save, Delete and Reset.

ICloudSavedData

Any interface that inherits from ICloudSavedData will be using the Beamable Serializer to save data as unstructured JSON.

Beamable Serializer

Beamable stores Player Saved Data, and the Beamable Serializer is responsible for the stored data.

BaseSavedData

This abstract class provides the basic functionality and its abstract methods must be overridden by each class that extends from it. This base class also provides implementations for Load, Save, Delete and Reset. As a result, any class related to ISavedData can extend from the BaseSavedData class and use these implementations.

Note

Abstract method Deserialize() should be implemented by each class that extends from BaseSavedData.

Examples

An example for this is UserSavedData

How to Extend

user_saved_data_relationship

The above diagram shows one of the potential ways of implementing a concrete player saved data class. Each class implements the corresponding interface by inheriting from its base class and implementing the additional members needed.

The following is a code example for extending from the existing StageSavedData class. A new Serialized Field _hasClaimedAscensionRewards is introduced in this example. This implementation enables us to track whether the player has claimed the ascension rewards yet. As a result, it prevents the player from claiming the same reward multiple times if they do not finish the ascension sequence.

Step 1

Create the new class by extending from any necessary classes. Create constructors, and any new fields you want to introduce.

Note

Notice how the class is Serializable, and any new fields we add are also SerializedField.

    [Serializable]
    public class NewStageSavedData : StageSavedData
    {
        [SerializeField]
        protected bool _hasClaimedAscensionRewards;
        public bool hasClaimedAscensionRewards => _hasClaimedAscensionRewards;

        protected NewStageSavedData()
        {
            //Empty
        }

        protected NewStageSavedData(string savedId, int numGoalSlots) : base(savedId, numGoalSlots)
        {
            //Empty
        }
    }    

Step 2

Implement the Deserialize method as each class is required to have their own version.

Note

Deserialize is overridden in the NewStageSavedData class and it also keeps track of the new serialized field.

status: True indicates that there is data to be deserialized.

protected override bool Deserialize(out ISavedData savedData)
{
      NewStageSavedData deserialized = new NewStageSavedData();

      bool status = _serializer.Deserialize(_savedId, ref deserialized);
      if (status)
      {
                _hasStarted = deserialized.hasStarted;
                _hasClaimedAscensionRewards = deserialized.hasClaimedAscensionRewards;
      }

      savedData = deserialized;
      return status;
}

Step 3

Update the new serialized field where necessary, this step might require to override methods such as Reset, or introduce new methods like ClaimAscensionRewards.

Note

Notice how Reset keeps updates the new serialized field and call the base method.

public override void Reset()
{
    _hasClaimedAscensionRewards = false;
    base.Reset();
}
public virtual void ClaimAscensionRewards()
{
     _hasClaimedAscensionRewards = true;
     Save();
}

The following is the final version:

    [Serializable]
    public class NewStageSavedData : StageSavedData
    {
        [SerializeField]
        protected bool _hasClaimedAscensionRewards;
        public bool hasClaimedAscensionRewards => _hasClaimedAscensionRewards;

        protected NewStageSavedData()
        {
            //Empty
        }

        protected NewStageSavedData(string savedId, int numGoalSlots) : base(savedId, numGoalSlots)
        {
            //Empty
        }

        protected override bool Deserialize(out ISavedData savedData)
        {
            NewStageSavedData deserialized = new NewStageSavedData();

            bool status = _serializer.Deserialize(_savedId, ref deserialized);
            if (status)
            {
                _hasStarted = deserialized.hasStarted;
                _hasClaimedAscensionRewards = deserialized.hasClaimedAscensionRewards;
            }

            savedData = deserialized;
            return status;
        }

        public override void Reset()
        {
            _hasClaimedAscensionRewards = false;
            base.Reset();
        }

        public virtual void ClaimAscensionRewards()
        {
            _hasClaimedAscensionRewards = true;
            Save();
        }

    }