Save for Unity Version V.1.0.8

Introduction

Save for Unity is a suite of programs that enables the saving and loading of just about any data used by a Unity project at run-time.

The system consists of a basic Core module for which add-on modules may be purchased to extend the functionality as required.

Alongside the Core module the Pro and Expert assets come with several add-on modules included. The Complete asset will be continually updated to include new add-on modules as they become available.
Note: The Pro, Expert and Complete assets do not include the Core asset, this is a free upgrade available after purchase and must be installed separately.

Save for Unity uses a custom binary serialization system for fast, efficient and secure data encoding. Optionally, you may add your own encryption method to the system if required. The serialized data is stored in a proprietory file format, any attempt to modify a file will result in it becoming unusable.

The serialization system stores all of the data by value whilst preserving references between objects with as little reliance on reflection as possible.

This version of the utility was written in C# with Unity .Net 4.7.1 libraries and tested using Unity 2020.3, 2021.3, 2022.3, 2023.2 and 6000.0 for Standalone, WebGL, Android and IOS but should function on all platforms supported by Unity.

Whilst every effort has been made to ensure the compatibility of Save for Unity with all Unity versions, the correct functioning of the software with Unity Alpha, Beta or Technical releases cannot be guaranteed.

Important Note: Due to breaking changes introduced by Unity in Versions 2022,2023 and 6000 the Save For Unity system is supplied as 4 package versions. One built for Unity 2020 and 2021, one built for Unity 2022 one built for Unity 2023 and one built for Unity 6. Please make sure you are using the correct package for your Unity version.

Please refer to the section Change Requests should you have a suggestion for a new add-on module or an enhancement to an existing one.

The code that makes up this utility is copyright SteveSmith.SoftWare 2022. Unless specifically stated in the code file or this documentation, no part of the system may be copied or modified. Neither may it be stored in such a way that would make it available to the public outside of the Unity Asset Store.

This documentation is available online at https://stevesmith.software. You will also find there the form for filing a bug report should it be necessary.

Steve Smith 2023.

Save for Unity Version 1.0.8 January 2025

Next ->



Main Assets

Save for Unity is available in 4 main assets, the basic Core asset and 3 bundles.

Core

The Core asset includes serialization/deserialization for the following objects:-

Unity Objects

GameObject
Transform

Non Unity Objects

C# classes and structs with the System.Serializable attribute

Refer to the Supported Data Types section for a full list of primitives and Unity structs supported.

<- Previous Next ->



Pro

The Pro asset extends the Core asset with the addition of

Unity Objects

Any class deriving from Monobehaviour

Add-On Modules

Graphics
Camera & Lights
Physics
Audio

Refer to the relevant add-on module section to see the objects handled by these add-ons.

Note: The Core asset must be installed separately

<- Previous Next ->



Expert

The Expert asset extends the Core asset with the addition of

Unity Objects

Any class deriving from Monobehaviour

Add-On Modules

Graphics
Camera & Lights
Physics
Audio
Events
UI including Text Mesh Pro
Animation
Navigation
Terrain

Refer to the relevant add-on module section to see the objects handled by these add-ons.

Note: The Core asset must be installed separately

<- Previous Next ->



Complete

The Complete asset extends the Core asset with the addition of

Unity Objects

Any class deriving from Monobehaviour

Add-On Modules

Graphics
Camera & Lights
Physics
Audio
Events
UI including Text Mesh Pro
Animation
Navigation
Terrain
Tile Maps
Joints and Hinges
Particles

Add-On Modules which require additional Unity packages

Mathematics
Splines (Unity 2022 and above)

Note: These add-on modules are supplied as .unitypackage files and must be installed manually


Refer to the relevant add-on module section to see the objects handled by these add-ons.

This asset will be continually updated with additional add-on modules as they become available.

Note: The Core asset must be installed separately

<- Previous Next ->



<- Previous Next ->



Save

Create an instance of this class to save data to a file

Namespace SSSoftware.Save

Class public class Save

Constructor


public Save(string fileName, Func<byte[], byte[]> encrypt = null, bool async=false, bool openOrCreate=false)

Description
Create an instance of the Save class

Parameters
fileName The name of the file to write to.
The file will be saved in the Application.persistentData folder. If fileName contains a folder name this will be a sub-folder of the persistent data folder. If the sub folder does not exist it will be created. If the file already exists it will be overwritten.
encrypt An optional method to perform data encryption
If specified this method will be called to encrypt the data. Refer to the Encryption section for more information
async Set to true to execute the save methods asynronously. Default false.
openOrCreate Set to true to open an existing file for updating. Default false, a new file will be created.

Example


using SSSoftware.Save;

Save save = new Save("mySaveFile.sav", myEncrypt);

byte[] myEncrypt(byte[] bytes)
{
   // Perform Encryption here
   return encryptedBytes;
}


<- Previous Next ->



Async Usage

Saving data asyncronously is as simple as setting the parameter in the constructor


Save save = new Save(saveFileName, async: true);



However it is recommended to put the code into a Coroutine.
This will give access to addirional functionality to allow better control :-

Progress - A value between 0 and 1 indicating the progress of the current method.
GetProgress - A callback passing the value of Progress
IsDone - A bool indicating when the current method is complete
UntilComplete - A Wait which becomes true when the current method is complete


    IEnumerator DoSave()
    {
        Save save = new Save(saveFileName, async: true);             // Open the Save file
        
        save.GetProgress = ShowProgress;                         // Assign a callback to show progress
        
        save.Scene(SceneManager.GetActiveScene());      // Save the complete Scene

        yield return save.UntilComplete;                               // Yield until the Save is completed

        /* Alternative option for waiting and showing progress
        while (!save.IsDone)
        {
            if (progressBar != null) progressBar.value = progress;
            yield return null;
        }
        */
    }

    void ShowProgress(float progress)
    {
        if (progressBar != null) progressBar.value = progress;
    }



NOTE: Because many Unity API calls may only be used when running on the main thread the async methods are also run on the main thread.
Those methods which may run on the thread pool have an additional parameter, mainThread


public void Object(object objects, bool keepOpen = false, bool mainThread=true)



This parameter can be set to false to use the thread pool although this should be used with caution.

Important: For WebGL builds mainThread should always be true.

See Save Async for full example code









<- Previous Next ->



Methods

Game Objects may be given the Tag 'NoSave'. Any Game Object with this tag will be ignored by the save system this will also include it's children.

GameObject

The GameObject methods will save all of the GameObjects, their Components and Children


void GameObject(GameObject gameObject, bool keepOpen)

Description
Save a single GameObject

Parameters
gameObject The GameObject to save
keepOpen False to close the file on exit. True to keep the file open to add more data. Default: False

Return values
none

Example


            Save save = new Save("mySave");
            save.GameObject(gameObject);



void GameObject(List<GameObject> gameObjects, bool keepOpen)

Description
Save a list of GameObjects

Parameters
gameObjects The list of GameObjects to save
keepOpen False to close the file on exit. True to keep the file open to add more data. Default: False

Return values
none

Example


            List<GameObject> gameObjects = new List<GameObject>();
            // Fill the list

            Save save = new Save("mySave");
            save.GameObject(gameObjects);



void GameObject(GameObject[] gameObjects, bool keepOpen)

Description
Save an array of GameObjects

Parameters
gameObjects The array of GameObjects to save
keepOpen False to close the file on exit. True to keep the file open to add more data. Default: False

Return values
none

Example


            GameObject[] gameObjects = new GameObject[10];
            // Fill the array

            Save save = new Save("mySave");
            save.GameObject(gameObjects);



<- Previous Next ->



Component

The Component methods will save any object which inherits from Unity Component.


void Component(Component component, bool keepOpen)

Description
Save a single component

Parameters
component The component to save
keepOpen False to close the file on exit. True to keep the file open to add more data. Default: False

Return values
none

Example


            Save save = new Save("mySave");
            save.Component(GetComponent<Rigidbody>());



void Component(List<Component> components, bool keepOpen)

Description
Save a list of components

Parameters
components The list of comonents to save
keepOpen False to close the file on exit. True to keep the file open to add more data. Default: False

Return values
none

Example


            List<Collider> colliders = new List<Collider>();
            GetComponents(colliders);

            Save save = new Save("mySave");
            save.Component(colliders);



void Component(Component[] components, bool keepOpen)

Description
Save an array of components

Parameters
components The array of components to save
keepOpen False to close the file on exit. True to keep the file open to add more data. Default: False

Return values
none

Example


            Collider[] colliders = GetComponents<Collider>();

            Save save = new Save("mySave");
            save.Component(colliders);



<- Previous Next ->



Object

The Object methods will save any serializable object which does not inherit from a Unity object.


void Object(object objects, bool keepOpen, bool mainThread)

Description
Save a single serializable object

Parameters
objects The object to save
keepOpen False to close the file on exit. True to keep the file open to add more data. Default: False
mainThread True to run on the main thread. False to run on the thread pool. Default: True
Only applies when async:true

Return values
none

Example


            MyClass myClass = new MyClass();
            Save save = new Save("mySave");
            save.Object(myClass);



void Object(List<object> objects, bool keepOpen, bool mainThread)

Description
Save a list of serializable objects

Parameters
objects The list of objects to save
keepOpen False to close the file on exit. True to keep the file open to add more data. Default: False
mainThread True to run on the main thread. False to run on the thread pool. Default: True
Only applies when async:true

Return values
none

Example


            List<MyClass> myClasses = new List<MyClass>();
            // Fill list

            Save save = new Save("mySave");
            save.Object(myClasses);



void Object(object[] objects, bool keepOpen, bool mainThread)

Description
Save an array of serializable objects

Parameters
objects The array of objects to save
keepOpen False to close the file on exit. True to keep the file open to add more data. Default: False
mainThread True to run on the main thread. False to run on the thread pool. Default: True
Only applies when async:true

Return values
none

Example


            MyClass[] myClasses = new MyClass[10];
            // Fill array

            Save save = new Save("mySave");
            save.Object(myClasses);



<- Previous Next ->



Scene


void Scene(Scene scene, bool keepOpen, bool saveStatic)

Description
This method will save the complete contents of a scene

Parameters
scene The scene to save
keepOpen False to close the file on exit. True to keep the file open to add more data. Default: False
saveStatic False to ignore root game objects marked as Static. True to save those game objects. Default: False

Return values
none

Example


using SSSoftware.Save;
using UnityEngine.SceneManagement;

Scene scene = SceneManager.GetActiveScene();
Save save = new Save("mySave");
save.Scene(scene);


<- Previous Next ->



KeyValue

The KeyValue methods will save any serializable object value with a string key.
The enables a functionality similar to that of Unity PlayerPrefs.


void KeyValue(string key, object value, bool keepOpen, bool mainThread)

Description
Save a single key value pair

Parameters
key The key to save under
value The object to save
keepOpen False to close the file on exit. True to keep the file open to add more data. Default: False
mainThread True to run on the main thread. False to run on the thread pool. Default: True
Only applies when async:true

Return values
none

Example


            MyClass myClass = new MyClass();
            Save save = new Save("mySave");
            save.KeyValue("myclass", myClass, true);
            save.KeyValue("position", transform.position, true);
            save.KeyValue("rotation", transform.rotation, true);
            save.KeyValue("scale", transform.localScale);



void KeyValue(KeyValuePair<string, object> keyValuePair, bool keepOpen, bool mainThread)

Description
Save a single key value pair

Parameters
keyValuePair The KeyValuePair to save
keepOpen False to close the file on exit. True to keep the file open to add more data. Default: False
mainThread True to run on the main thread. False to run on the thread pool. Default: True
Only applies when async:true

Return values
none

Example


            KeyValuePair<string,object> kvp = new();
            kvp.Key = "key";
            kvp.Value = new MyClass();

            Save save = new Save("mySave");
            save.KeyValue(kvp);


            Save save = new Save("mySave");
            foreach (KeyValuePair<string, MyClass> kvp in myDictionary) {
               if (kvp.Value != null) {
                   save.KeyValue(kvp, true);
               }
            }
            save.Close();



void KeyValue(IDictionary<string, object> dictionary, bool keepOpen, bool mainThread)
void KeyValue<T>(IDictionary<string, T> dictionary, bool keepOpen, bool mainThread)

Description
Save a dictionary of key value pairs

Parameters
dictionary The dictionary of objects to save. Can be any collection that implements the IDictionary interface.
Use the generic signature for a collection of fixed type
keepOpen False to close the file on exit. True to keep the file open to add more data. Default: False
mainThread True to run on the main thread. False to run on the thread pool. Default: True
Only applies when async:true

Return values
none

Example


            Dictionary<string, object> myDict = new();
            Dictionary<string, MyClass> myClassDict = new();

            Save save = new Save("mySave");
            save.KeyValue(myDict,true);
            save.KeyValue<MyClass>(myClassDict);



<- Previous Next ->



Close

Closes an open Save file. Close should be called if the Save keepOpen option has been used


void Close()

Description
Close the Save file

Parameters
None

Return values
None

Example



Save save = new Save("mySave");
save.Scene(scene,true);
save.Close();


<- Previous Next ->



Delete

Static method to Delete an existing Save file


static bool Delete(string fileName)

Description
Delete the file if it exists

Parameters
fileName The name of the file to delete

Return values
true The file was deleted
false The file was not found

Example


bool deleted = Save.Delete("myFile.sav");
if (deleted) Debug.Log("File Deleted");


<- Previous Next ->



Exists

Static method to check for the existance of a Save file


static bool Exists(string fileName)

Description
Check the file exists in the persistent data folder

Parameters
fileName The name of the file to check

Return values
true The file exists
false The file was not found

Example


bool exists = Save.Exists("myFile.sav");
if (exists) Debug.Log("File Exists");


<- Previous Next ->



<- Previous Next ->



Properties

Trace

static bool Trace

Set this to true to get a verbose log of the actions taken by the system.

<- Previous Next ->



Progress

float Progress

returns a value between 0 and 1 indicating the progress of the current operation


      public Slider progressBar;

        while (!save.IsDone)
        {
            if (progressBar != null) progressBar.value = progress;
            yield return null;
        }



See Async Usage for detailed example

<- Previous Next ->



GetProgress

Action GetProgress

Set a callback to give access to the progress


    public Slider progressBar;

    save.GetProgress = ShowProgress;

    void ShowProgress(float progress)
    {
        if (progressBar != null) progressBar.value = progress;
    }

progress will contain a value between 0 and 1



See Async Usage for detailed example

<- Previous Next ->



IsDone

bool IsDone

return a boolean which can be used in a Coroutine


        while (!save.IsDone)
        {
            yield return null;
        }



See Async Usage for detailed example

<- Previous Next ->



UntilComplete

WaitUntil UntilComplete

return a WaitUntil which can be used in a Coroutine


	 yield return save.UntilComplete;



See Async Usage for detailed example

<- Previous Next ->



<- Previous Next ->



<- Previous Next ->



Load

Create an instance of this class to load data from a file

Namespace SSSoftware.Save

Class public class Load

Constructor


public Load(string fileName, Func<byte[], byte[]> decrypt = null, async=false)

Description
Create an instance of the Load class

Parameters
fileName The name of the file to read from.
The file should be located in Application.persistentData folder or a specified sub-folder. If the file does not exist an exception will be thrown
decrypt An optional method to perform data decryption
If specified this method will be called to decrypt the data. Refer to the Encryption section for more information
async Set to true to execute the load methods asynronously. Default false.

Example


using SSSoftware.Save;

Load load = new Load("mySaveFile.sav", myDecrypt);

byte[] myDecrypt(byte[] bytes)
{
   // Perform Decryption here
   return decryptedBytes;
}


<- Previous Next ->



Async Usage

Load data asyncronously is as simple as setting the parameter in the constructor


Load load = new Load(saveFileName, async: true);



However it is recommended to put the code into a Coroutine.
This will give access to addirional functionality to allow better control :-

Progress - A value between 0 and 1 indicating the progress of the current method.
GetProgress - A callback passing the value of Progress
IsDone - A bool indicating when the current method is complete
UntilComplete - A Wait which becomes true when the current method is complete


IEnumerator DoLoad()
    {
        Load load = new Load(saveFileName, async: true);        // Open the Load file

        load.GetProgress = ShowProgress;                              // Assign a callback to display progress
        
        Scene scene = SceneManager.GetActiveScene();    // Get the active Scene
        load.Scene(scene);                                                    // Load the file into the Scene
        
        yield return load.UntilComplete;                                 // Wait until the Load is complete

        /* Alternative oprion to wait and show progress
        while (!load.IsDone)
        {
            if (progressBar != null) progressBar.value = progress;
            yield return null;
        }
        */

        load.Close();                                   // Close the Load file

    }

    void ShowProgress(float progress)
    {
        if (progressBar != null) progressBar.value = progress;
    }



NOTE: Because many Unity API calls may only be used when running on the main thread the async methods are also run on the main thread.
Those methods which may run on the thread pool have an additional parameter, mainThread


public List<object> Object(bool mainThread = true)



This parameter can be set to false to use the thread pool although this should be used with caution.

Important: For WebGL builds mainThread should always be true.

See Load Async for full example code

<- Previous Next ->



Methods

GameObject

The GameObject method will load the GameObject, it's Components and all of it's children


GameObject GameObject(string name, bool includeChildren, GameObject parent, bool updateExisting)

Description
Load a single GameObject by name

Parameters
name The name of the GameObject to Load
includeChildren Load child game objects. Default is true
parent If specified the loaded game object will be parented to this. Default no parenting
updateExisting Set to true to update an existing Game Object if it exists. Default false

Return values
GameObject The Loaded GameObject

Example


            Load load = new Load("mySave");
            GameObject go = load.GameObject("myGameObject");
            loadf.Close();



List<GameObject> GameObject(GameObject parent, bool updateExisting)

Description
Load all of the GameObjects into the active scene

Parameters
parent if specified the loaded gameobjects will be parented to this. Defaulf no parenting
updateExisting Set to true to update existing Game Objects if they exist. Default false

Return values
List<GameObject> The list of Loaded GameObjects

Example


            Load load = new Load("mySave");
            List<GameObject> gameObjects = load.GameObject();
            load.Close();


<- Previous Next ->



Component

The Component method will load the components in the file and add them to the Game Object specified


List<Component> Component(GameObject gameObject)

Description
Loads all of the components and return them as a list

Parameters
gameObject The game object to add the components to

Return values
List<Component> A list of the loaded components

Example


            Load load = new Load("mySave");
            List<Component> components = load.Component(gameObject);
            load.Close();



List<Component> Component(GameObject gameObject, Type type)

Description
Loads all of the components of the specified Type and return them as a list

Parameters
gameObject The game object to add the components to
type The Type of the components to load

Return values
List<Component> A list of the loaded components

Example


 Load load = new Load("mySave");
 List<Component> components = load.Component(gameObject, typeof(Collider));
 load.Close();



List<T> Component<T>(GameObject gameObject)

Description
Loads all of the components of the specified Type and return them as a list

Parameters
gameObject The game object to add the components to

Return values
List<T> A list of the loaded components

Example


            Load load = new Load("mySave");
            List<Collider> colliders = load.Component<Collider>(gameObject);
            load.Close();



<- Previous Next ->



Object

The Object methods will load the serializable objects in the file.


List<object> Object(bool mainThread)

Description
Loads all of the serializable objects and return them as a list

Parameters
mainThread True to run on the main thread. False to run on the thread pool. Default: True
Only applies when async:true

Return values
List<object> A list of the loaded objects

Example


            Load load = new Load("mySave");
            List<object> objects = load.Object();
            load.Close();



List<object> Object(Type type, bool mainThread)

Description
Loads all of the serializable objects of the specified Type and return them as a list

Parameters
type The Type of the objects to load
mainThread True to run on the main thread. False to run on the thread pool. Default: True
Only applies when async:true

Return values
List<object> A list of the loaded objects

Example


            Load load = new Load("mySave");
            List<object> objects = load.Object(typeof(MyClass));
            load.Close();



List<T> Object<T>(bool mainThread)

Description
Loads all of the serializable objects of the specified Type and return them as a list

Parameters
mainThread True to run on the main thread. False to run on the thread pool. Default: True
Only applies when async:true

Return values
List<T> A list of the loaded objects

Example


            Load load = new Load("mySave");
            List<MyClass> objects = load.Object<MyClass>();
            load.Close();



<- Previous Next ->



Scene


void Scene(Scene scene, bool updateExisting)

Description
This method will load the saved data into the scene

Parameters
scene The scene to load into
updateExisting Set to true to update existing Game Objects if they exist. Default false

Return values
none

Example


using SSSoftware.Save;
using UnityEngine.SceneManagement;

Scene scene = SceneManager.GetActiveScene();
Load load = new Load("mySave");
load.Scene(scene);
load.Close();

<- Previous Next ->



KeyValue

The KeyValue methods will load the key values in the file using a string key.


object KeyValue(string key, bool mainThread)
T KeyValue<T>(string key, bool mainThread)

Description
Loads a value as an object or by type

Parameters
key The string key of the keyvaluepair to load
mainThread True to run on the main thread. False to run on the thread pool. Default: True
Only applies when async:true

Return values
object The value from the keyvaluepair
T The value from the keyvaluepair as Type T

Example


            Load load = new Load("mySave");
            object value = load.KeyValue("myKey");
            MyClass myClass = load.KeyValue<MyClass>("myClass");
            load.Close();



Dictionary<string, object> KeyValue(bool mainThread)
Dictionary<string, T> KeyValue<T>(bool mainThread)

Description
Loads all of the key value pairs and returns them as a dictionary of objects or Types

Parameters
mainThread True to run on the main thread. False to run on the thread pool. Default: True
Only applies when async:true

Return values
Dictionary<string, object> A dictionary of the loaded objects
Dictionary<string, T> A dictionary of the loaded objects cast to Type T

Example


            Load load = new Load("mySave");
            Dictionary<string, object> myDict = load.KeyValue();
            Dictionary<string, MyClass> myClassDict = load.KeyValue<MyClass>();
            load.Close();


<- Previous Next ->



Update

The Update method allows for references in NONE saved objects to be updated to reference loaded objects


void Update(Object component)
void Update(Object[] components)
void Update(List<Object> components)

Description
Update references in the supplied Component(s)

Parameters
component(s) The Component(s) to be updated

Return values
None

Example


public MyComponent myComponent;
...
Load load = new Load("mySave");
List<GameObject> gos = load.GameObject();
load.Update(myComponent);
load.Close();


<- Previous Next ->



Close

The Close method Closes the open Load file. Close must be called before the file can be used in another Save.


void Close()

Description
Close the Load file

Parameters
None

Return values
None

Example


Load load = new Load("mySave");
load.Scene(scene);
load.Close();


<- Previous Next ->



Exists

Static method to check for the existance of a Save file


static bool Exists(string fileName)

Description
Check the file exists in the persistent data folder

Parameters
fileName The name of the file to check

Return values
true The file exists
false The file was not found

Example


bool exists = Load.Exists("myFile.sav");
if (exists) Debug.Log("File Exists");


<- Previous Next ->



<- Previous Next ->



Interfaces

ILoad

Whilst every effort has been made to restore references between objects on Load it may not always be possible to do so. The ILoad interface may be added to a Monobehaviour class to provide a callback once loading is complete in order for that class to fix any missing references or carry out any other kind of re-initialization processes.


void OnLoadComplete()

Description
Called by the Load class once all loading of data is completed

Parameters
none

Return values
none

Example


using UnityEngine;
using SSSoftware.Save;

public class NewBehaviourScript : MonoBehaviour, ILoad
{
    public GameObject target;

    public void OnLoadComplete()
	{
		target = GameObject.Find("Target");
	}
}


<- Previous Next ->



<- Previous Next ->



Properties

Trace

static bool Trace

Set this to true to get a verbose log of the actions taken by the system.

<- Previous Next ->



Progress

float Progress

returns a value between 0 and 1 indicating the progress of the current operation


      public Slider progressBar;

        while (!load.IsDone)
        {
            if (progressBar != null) progressBar.value = progress;
            yield return null;
        }



See Async Usage for detailed example

<- Previous Next ->



GetProgress

Action GetProgress

Set a callback to give access to the progress


     public Slider progressBar;

     load.GetProgress = ShowProgress;

    void ShowProgress(float progress)
    {
        if (progressBar != null) progressBar.value = progress;
    }

progress will contain a value between 0 and 1



See Async Usage for detailed example

<- Previous Next ->



IsDone

bool IsDone

return a booleanl which can be used in a Coroutine


        while (!load.IsDone)
        {
            yield return null;
        }



See Async Usage for detailed example

<- Previous Next ->



UntilComplete

WaitUntil UntilComplete

return a WaitUntil which can be used in a Coroutine


	 yield return load.UntilComplete;



See Async Usage for detailed example

<- Previous Next ->



<- Previous Next ->



<- Previous Next ->



AutoSave

AutoSave is a No Code oprion for using the Save system.
AutoSave is a Monobehaviour component which can be added to any game object. A prefab can be found in the Examples package.



1. AutoSave Inspector


Is Active Select to activate the script
Save As Enter a file name to save as. Optionally select the toggle for asyncronous saving
Save When Which events should the save react to?
-- On Enable Select to save when the script is enabled
-- On Pause Select to save on Pause
-- On Destroy Select to save when the gameobuject is destroyed
-- On Disable Select to save when the gameobject is disabled
-- On Exit Select to save on application exit/quit. Note: For Android this is also on losing focus
Save What Select from either GameObjects or Components to save
Drag and Drop the objects to save

<- Previous Next ->



AutoLoad

AutoLoad is a No Code oprion for using the Save system.
AutoLoad is a Monobehaviour component which can be added to any game object.A prefab can be found in the Examples package.



2. AutoLoad Inspector


Is Active Select to activate the script
Load From Enter a file name to load from. Optionally select the toggle for asyncronous loading
Load When Which events should the load react to?
-- On Awake Load when the object is Instantiated
-- On Enable Load when the script is enabled
-- On Focus Load when the applcation gains focus
-- On Start Load when the script starts
-- On Pause Load when the application un pauses
Load What Select from either GameObjects or Components to load
Load Into Select either a Gameobject to use as parent or to add the components to

<- Previous Next ->



ISerializationCallbackReceiver

The ISerializationCallbackReceiver is an interface implemented by Unity and exposes 2 methods :-

public void OnBeforeSerialize() { }

and

public void OnAfterDeserialize() { }

These methods allow for manual processing of data immediately before and after serialization.

Save for Unity will also call these methods during its serialization/deserialization procesasing.

Please refer to the Unity documentation for more information

ISerializationCallbackReceiver

<- Previous Next ->



Encryption

Due to the propriatory nature of the Save for Unity file format and serializer and the fact that encrypting and decrypting data is an intensive task this system does not include an encryption module.

However, hooks have been provided in the constructors of the Save and Load classes to allow the user to define their own encryption routines if required.

As a part of the Save finalization process a byte array will be passed to an encryption method written by the user and that method should return a byte array of that encrypted data which will then by written to the save file.

As a part of the Load initialization process the encrypted byte array will be passed to a decryption method written by the user and that method should return a byte array of that decrypted data. This data is then used to load the file.

It is the responsibility of the encryption and decryption methods provided by the user to ensure that the decrypted data matches exactly with the data passed for encryption.

Once a save file has been saved with encrypted data it will be impossible to use that file without the corresponding decryption method.


<- Previous Next ->



Optimization

The Optimization module uses a Roslyn Source Analyzer to remove the reliance of Reflection for data serialization.

This can be done in 2 ways.

1) Use the Optimization Utility.
Firstly enter Play mode in the Unity Editor.
Ensure that your Save code has been executed.
Exit Play mode
The utility can then be accessed via the Unity menu Tools->Save for Unity->Manage Optimization

The optimization utility evaluates which scripts are suitable for optimization and offers the option to optimise them.
It also shows which add-on modules are not in use and offers the option to remove therm.



3. Manage Optimization


a) Select the scripts to optimize using the toggles
b) Click 'Apply chages'

Note: Deselecting the toggle will revert the script changes.

2) Modifying code manually by:-
a) Adding the [SSSoftware.Attributes.SaveForUnity] attribute to the class
b) Adding the partial keyword to the class declaration

This can be done for Monobehaviours and plain C# classes and structs


[System.Serializable]
[SSSoftware.Attributes.SaveForUnity]
public partial class MyClass {
    public int x;
 }

Example code



In both cases this will result in a generated partial class which can be viewed via your IDE



4. Generated code


Note: In the unlikely event that the generated partial class produces compile errors please report this via one of the support channels and revert the changes.

The second section of the Optimization Utility identifies which add-on modules are installed and which are in use by your save system.

The unused modules can be safely removed by clicking on 'Remove Unused Add-Ons'. This will close the utility and delete the add-on modules from your project.

To undo this action you can re-import the Save for Unity asset into your project.

<- Previous Next ->



Add-On Modules

The Add-on modules are NOT stand alone assets. You must use them in combination with one of the main Save for Unity assets.

Animation

The Animation module provides support for the following objects

UnityEngine.Animation
UnityEngine.AnimationClip
UnityEngine.Animator
UnityEngine.AnimationCurve
UnityEngine.Animations.AimConstraint
UnityEngine.Animations.AnimationClipPlayable
UnityEngine.Animations.AnimationLayerMixerPlayable
UnityEngine.Animations.AnimationMixerPlayable
UnityEngine.Animations.AnimationPlayableOutput
UnityEngine.Animations.AnimationScriptPlayable
UnityEngine.Animations.AnimatorControllerPlayable
UnityEngine.Animations.LookAtConstraint
UnityEngine.Animations.ConstraintSource
UnityEngine.Animations.MuscleHandle
UnityEngine.Animations.ParentConstraint
UnityEngine.Animations.PositionConstraint
UnityEngine.Animations.PropertySceneHandle
UnityEngine.Animations.PropertyStreamHandle
UnityEngine.Animations.RotationConstraint
UnityEngine.Animations.ScaleConstraint
UnityEngine.Animations.TransformSceneHandle
UnityEngine.Animations.TransformStreamHandle
UnityEngine.Avatar
UnityEngine.Gadient
UnityEngine.GadientAlphaKey
UnityEngine.GadientColorKey

<- Previous Next ->



Audio

The Audio module provides support for the following objects

UnityEngine.AudioClip,
UnityEngine.AudioSource,
UnityEngine.Audio.AudioMixer,
UnityEngine.Audio.AudioMixerGroup,
UnityEngine.Audio.AudioClipPlayable,
UnityEngine.Audio.AudioMixerPlayable,
UnityEngine.Audio.AudioMixerSnapshot,
UnityEngine.Audio.AudioMixerUpdateMode,
UnityEngine.Audio.AudioPlayableOutput,
UnityEngine.AudioBehaviour,
UnityEngine.AudioChorusFilter,
UnityEngine.AudioConfiguration,
UnityEngine.AudioDistortionFilter,
UnityEngine.AudioEchoFilter,
UnityEngine.AudioHighPassFilter,
UnityEngine.AudioLowPassFilter,
UnityEngine.AudioReverbFilter,
UnityEngine.AudioReverbZone,

<- Previous Next ->



Camera & Light

The Camera module provides support for the following objects

AudioListener
Camera
Light
Flare

Note: The Light class may cause problems in a build when using URP or HDRP. It is recommended that it not be used in this situation.

<- Previous Next ->



Events

The Events module provides support for all objects deriving from UnityEngine.Events.Event

This add-on module is included in the UI add-on miodule

<- Previous Next ->



Graphics

The Graphics module provides support for the following objects

Material
Mesh
MeshFilter
MeshRenderer
Shader
Sprite
Texture
Texture2D
SkinnedMeshRenderer
SpriteRenderer
RenderTexture
RenderTextureDescriptor
LOD
LODGroup

Note: For Texture assets to be serialized including the image data they must be flagged as Read/Write in their inspector

<- Previous Next ->



Joints

The Joints module provides support for the following objects

3D

CharacterJoint
ConfigurableJoint
FixedJoint
HingeJoint
SpringJoint

2D

DistanceJoint2D
FixedJoint2D
FrictionJoint2D
HingeJoint2D
RelitiveJoint2D
SliderJoint2D
SpringJoint2D
TargetJoint2D
WheelJoint2D


<- Previous Next ->



Mathematics

The Mathematics module provides support for the Unity Mathematics package which must be installed first

The following structs are supported

float2
float3
float4
int2
int3
int4
double2
double3
double4
uint2
uint3
uint4
bool2
bool3
bool4
half
half2
half3
half4
quaternion
float4x4


<- Previous Next ->



Monobehaviours

The Monobehaviour module give support for any class which derives from UnityEngine.Monobehaviour

<- Previous Next ->



Navigation

The Navigation module provides support for the following objects

NavMeshAgent
NavMeshData
NavMeshHit
NavMeshObstacle
OcclusionArea
PositionAsUV1

<- Previous Next ->



Particles

The Particles module provides support for the following objects

UnityEngine.ParticleSystem.Burst
UnityEngine.ParticleSystem.ColliderData
UnityEngine.ParticleSystem.CollisionModule
UnityEngine.ParticleSystem.ColorBySpeedModule
UnityEngine.ParticleSystem.ColorOverLifetimeModule
UnityEngine.ParticleSystem.EmissionModule
UnityEngine.ParticleSystem.EmitParams
UnityEngine.ParticleSystem.ExternalForcesModule
UnityEngine.ParticleSystem.ForceOverLifetimeModule
UnityEngine.ParticleSystem.InheritVelocityModule
UnityEngine.ParticleSystem.LifetimeByEmitterSpeedModule
UnityEngine.ParticleSystem.LightsModule
UnityEngine.ParticleSystem.LimitVelocityOverLifetimeModule
UnityEngine.ParticleSystem.MainModule
UnityEngine.ParticleSystem.MinMaxCurve
UnityEngine.ParticleSystem.MinMaxGradient
UnityEngine.ParticleSystem.NoiseModule
UnityEngine.ParticleSystem.Particle
UnityEngine.ParticleSystem
(UnityEngine.ParticleSystem.PlaybackState
UnityEngine.ParticleSystem.RotationBySpeedModule
UnityEngine.ParticleSystem.RotationOverLifetimeModule
UnityEngine.ParticleSystem.ShapeModule
UnityEngine.ParticleSystem.SizeBySpeedModule
UnityEngine.ParticleSystem.TextureSheetAnimationModule
UnityEngine.ParticleSystem.TrailModule
UnityEngine.ParticleSystem.Trails
UnityEngine.ParticleSystem.TriggerModule
UnityEngine.ParticleSystem.VelocityOverLifetimeModule
UnityEngine.ParticleSystem.SizeOverLifetimeModule
UnityEngine.ParticleSystem.SubEmittersModule
UnityEngine.ParticleSystem.CustomDataModule

<- Previous Next ->



Physics

The Physics module provides support for the following objects

3D

BoxCollider
CapsuleCollider
MeshCollider
PhysicMaterial (PhysicsMaterial for Unity 6)
PhysicsRaycaster
Rigidbody
SphereCollider
WheelCollider
CharacterController

2D

BoxCollider2D
CapsuleCollider2D
CircleCollider2D
CompositeCollider2D
EdgeCollider2D
PhysicsMaterial2D
Physics2DRaycaster
PolygonCollider2D
Rigidbody2D

<- Previous Next ->



Splines

The Splines module provides support for the Unity Splines package which must be installed first

The following classes/structs are supported


BezierCurve
BezierKnot
Spline
SplineAnimate
SplineContainer
SplineData

Note: this module is NOT available for Unity versions 2020 and 2021

<- Previous Next ->



Terrain

The Terrain module provides support for the following objects

DetailPrototype
Terrain
TerrainCollider
TerrainData
TerrainLayer
TreeInstance
TreePrototype

<- Previous Next ->



Tile Maps

The Tiles module provides support for the following objects

Tile
TileAnimationData
TileData
Tilemap
TilemapCollider2D
TilemapRenderer
Grid

<- Previous Next ->



UI

The UI module provides support for the following objects

IMGUI

Button
Canvas
CanvasRenderer
CanvasScaler
CharacterInfo
ColorBlock
Dropdown
EventSystem
Font
FontData
GraphicRaycaster
Image
Inputfield
Mask
Navigation
OptionData
OptionSataList
RawImage
RectTransform
Scrollbar
ScrollRect
Slider
SppriteState
StandaloneInputModule
Text
Toggle
UIVertex
CanvasGroup

TMP

TextMeshProUGUI
TMP_ColorGradient
TMP_Dropdown
TMP_Inputfield
TMP_Sprite
TMP_Style
TMP_StyleSheet
TMP_Text
TextMeshPro
VertexGradient

This module also includes the Events add-on module

<- Previous Next ->



<- Previous Next ->



Example Code

A demonstration project with explanation can be found at Save for Unity Demonstration Project

Save for Unity provides several example code files. These are supplied as a .unitypackage which can be found in

Save4Unity/Editor/Examples.

All of the code is supplied under the standard Asset Store EULA and is free to be used as required.

C# Objects

Save and Load C# Objects

Save


using System.Collections.Generic;
using UnityEngine;

namespace SSSoftware.Save
{
    public class SaveObjects : MonoBehaviour            // Add to an empty Game Object
    {
                                                        // The objects to save
        public List<int> stats = new List<int>();
        public Dictionary<int, string> names = new Dictionary<int, string>();
        public PlayerData playerData = new PlayerData();

        public string saveFileName;                     // File name to Save to

        void OnEnable()                                 // Enable to Save
        {
            Save save = new Save(saveFileName);         // Open the Save file

            // Save the objects and keep the file open

            save.Object(stats, true);      
            save.Object(names, true);
            save.Object(playerData, true);

            save.Close();                               // Close the Save file
        }
    }

    [System.Serializable]
    public class PlayerData
    {
        public string name = "Steve";
        public Vector3 position;
        public Quaternion rotation;
    }
}




5. Save Objects


<- Previous Next ->



Load


using System.Collections.Generic;
using UnityEngine;

namespace SSSoftware.Save
{
    public class LoadObjects : MonoBehaviour                    //Add to an empty GameObject
    {
                                                                // The objects to be loaded
        public List<int> stats;
        public Dictionary<int, string> names;
        public PlayerData playerData;

        public string saveFileName;                             // File name to Load from

        void OnEnable()                                         // Enable to Load
        {
            if (Load.Exists(saveFileName))                      // Check the Load file exists
            {
                Load load = new Load(saveFileName);             // Open the Load file
                List<object> loadedObjects = load.Object();     // Load the objects

               // Put the loaded objects into their variables
               // Note: The objects are loaded in the same order as they were saved

                stats = loadedObjects[0] as List<int>;
                names = loadedObjects[2] as Dictionary<int,string>;
                playerData = loadedObjects[3] as PlayerData;

                load.Close();                                   // Close the Load file
            }
        }
    }
}




6. Load Objects

<- Previous Next ->



<- Previous Next ->



MonoBehaviours

Save and Load Monobehaviours or other Components

Save


using UnityEngine;

namespace SSSoftware.Save
{
    public class SaveMonoBehaviour : MonoBehaviour     // Add to a Game Object
    {
        public MonoBehaviour script;                   // The Monobehaviour to Save
        public string saveFileName;                    // The file name to Save to

        void OnEnable()                                //Enable to Save
        {
            Save save = new Save(saveFileName);        // Open the Save file
            save.Component(script);                    // Save the Monobehaviour
        }
    }
}




7. Save MonoBehaviour

<- Previous Next ->



Load


using UnityEngine;

namespace SSSoftware.Save
{
    public class LoadMonoBehaviour : MonoBehaviour           // Add to a Game Object
    {
        public string saveFileName;                          // The file name to load from

        void OnEnable()                                      // Enable to Load
        {
            if (Load.Exists(saveFileName))                   // Check the load file exists
            {
                Load load = new Load(saveFileName);          // Open the Load file
                load.Component(gameObject);                  // Load the Component onto Game Object
                load.Close();                                // Close the Load file
            }
        }
    }
}




8. Load MonoBehaviour

<- Previous Next ->



<- Previous Next ->



Game Object

Save and Load a Game Object

Save




using UnityEngine;

namespace SSSoftware.Save
{
    public class SaveGameObject : MonoBehaviour     // Add to an empty Game Object
    {
        public GameObject player;                   // The Game Object to Save
        public string saveFileName;                 // The file name to Save to

        void OnEnable()                             //Enable to Save
        {
            Save save = new Save(saveFileName);     // Open the Save file
            save.GameObject(player);                // Save the Game Object and it's children
        }
    }
}



9. Save Game Object

<- Previous Next ->



Load


using UnityEngine;

namespace SSSoftware.Save
{
    public class LoadGameObject : MonoBehaviour                         // Add to an empty Game Object
    {
        public string playerName;                                       // The name of the Game Object
        public bool includeChildren;                                    // Load child Game Objects
        public string saveFileName;                                     // The file name to load from

        public GameObject player;                                       // GameOject to Load into

        void OnEnable()                                                 // Enable to Load
        {
            if (Load.Exists(saveFileName))                              // Check the load file exists
            {
                Load load = new Load(saveFileName);                     // Open the Load file
                player = load.GameObject(playerName, includeChildren);  // Load the Game Object
                load.Close();                                           // Close the Load file
            }
        }
    }
}




10. Load GameObject

<- Previous Next ->



<- Previous Next ->



Game Objects

Save and Load multiple Game Objects

Save


using System.Collections.Generic;
using UnityEngine;

namespace SSSoftware.Save
{
    public class SaveGameObjects : MonoBehaviour        // Add to an empty Game Object
    {
        public List<GameObject> enemies;                // The Lisy of GameObjects to Save
        public string saveFileName;                     // The file name to Save to

        void OnEnable()                                 //Enable to Save
        {
            if (enemies.Count > 0)                      // Are there objects to Save?
            {
                Save save = new Save(saveFileName);     // Open the Save file
                save.GameObject(enemies);               // Save the Game Objects
            }
            else
            {
                Save.Delete(saveFileName);              // Delete old Save file
            }
        }
    }
}




11. Save GameObjects

<- Previous Next ->



Load



using System.Collections.Generic;
using UnityEngine;

namespace SSSoftware.Save
{
    public class LoadGameObjects : MonoBehaviour        // Add to an empty Game Object
    {

        public GameObject parent;                       // Optional GameObject to parent to
        public List<GameObject> enemies;                // List of loaded Game Objects
        public string saveFileName;                     // The file name to load from

        void OnEnable()                                 // Enable to Load
        {
            if (Load.Exists(saveFileName))              // Check the load file exists
            {
                Load load = new Load(saveFileName);     // Open the Load file
                enemies = load.GameObject(parent);      // Load the Game Objects
                load.Close();                           // Close the Load file
            }
        }
    }
}




12. Load Game Objects

<- Previous Next ->



<- Previous Next ->



Scene

Save and Load a complete scene

Save



using UnityEngine;
using UnityEngine.SceneManagement;

namespace SSSoftware.Save
{
    public class SaveScene : MonoBehaviour                  // Add to an empty Game Object. Tag as NoSave
    {
        public string saveFileName;                         // File name to Save to

        void OnEnable()                                     // Enable to Save
        {
            Save save = new Save(saveFileName);             // Open the Save file
            save.Scene(SceneManager.GetActiveScene());      // Save the complete Scene
        }
    }
}




13. Save Scene

<- Previous Next ->



Load



using UnityEngine;
using UnityEngine.SceneManagement;

namespace SSSoftware.Save
{
    public class LoadScene : MonoBehaviour                      //Add to an empty GameObject
    {
        public string saveFileName;                             // File name to Load from

        void OnEnable()                                         // Enable to Load
        {
            if (Load.Exists(saveFileName))                      // Check the Load file exists
            {
                Load load = new Load(saveFileName);             // Open the Load file
                Scene scene = SceneManager.GetActiveScene();    // Get the active Scene
                load.Scene(scene);                              // Load the file into the Scene
                load.Close();                                   // Close the Load file
            }
        }
    }
}




14. Load Scene

<- Previous Next ->



<- Previous Next ->



Key Values

Save and Load using Key/Value pairs

Save


using UnityEngine;

namespace SSSoftware.Save
{
    public class SaveKeyValue : MonoBehaviour            // Add to an empty Game Object
    {
        // The values to save
        public string fullName = "Steve Smith";
        public Vector3 position;
        public Quaternion rotation;

        public string saveFileName;                     // File name to Save to

        void OnEnable()                                 // Enable to Save
        {
            Save save = new Save(saveFileName);         // Open the Save file

            // Save the values by key and keep the file open

            save.KeyValue("name", fullName, true);
            save.KeyValue("position", position, true);
            save.KeyValue("rotation", rotation, true);

            save.Close();                               // Close the Save file
        }
    }
}



<- Previous Next ->



Load


using System.Collections.Generic;
using UnityEngine;

namespace SSSoftware.Save
{
    public class LoadKeyValue : MonoBehaviour                    //Add to an empty GameObject
    {
        // The key value to be loaded
        public Dictionary<string, object> keyValues;

        public string saveFileName;                             // File name to Load from

        void OnEnable()                                         // Enable to Load
        {
            if (Load.Exists(saveFileName))                      // Check the Load file exists
            {
                Load load = new Load(saveFileName);             // Open the Load file
                keyValues = load.KeyValue();                    // Load the values
                load.Close();                                   // Close the Load file
            }
        }
    }
}




<- Previous Next ->



<- Previous Next ->



Save Async


using System.Collections;
using UnityEngine;
using UnityEngine.SceneManagement;
using SSSoftware.Save;
using UnityEngine.UI;

public class SaveAsync : MonoBehaviour
{
    public string saveFileName;                         // File name to Save to

    public Slider progressBar;

    public void OnClick()
    {
        StartCoroutine(DoSave());
    }

    IEnumerator DoSave()
    {
        Save save = new Save(saveFileName, async: true);             // Open the Save file
        
        save.GetProgress = ShowProgress;
        
        save.Scene(SceneManager.GetActiveScene());      // Save the complete Scene

        yield return save.UntilComplete;

        /*
        while (!save.IsDone)
        {
            if (progressBar != null) progressBar.value = progress;
            yield return null;
        }
        */
    }

    void ShowProgress(float progress)
    {
        if (progressBar != null) progressBar.value = progress;
    }
}



<- Previous Next ->



Load Async


using System.Collections;
using UnityEngine;
using UnityEngine.SceneManagement;
using SSSoftware.Save;
using UnityEngine.UI;

public class LoadAsync : MonoBehaviour
{
    public string saveFileName;                             // File name to Load from

    public Slider progressBar;

    public void OnClick()
    {
        if (Load.Exists(saveFileName))                      // Check the Load file exists
        {
            StartCoroutine(DoLoad());
        }
    }

    IEnumerator DoLoad()
    {
        Load load = new Load(saveFileName, async: true);        // Open the Load file

        load.GetProgress = ShowProgress;
        
        Scene scene = SceneManager.GetActiveScene();    // Get the active Scene
        load.Scene(scene);                              // Load the file into the Scene
        
        yield return load.UntilComplete;

        /*
        while (!load.IsDone)
        {
            if (progressBar != null) progressBar.value = progress;
            yield return null;
        }
        */

        load.Close();                                   // Close the Load file

    }

    void ShowProgress(float progress)
    {
        if (progressBar != null) progressBar.value = progress;
    }
}



<- Previous Next ->



<- Previous Next ->



Supported Data Types

The following supported data type are included in all Save For Unity versions

C# Data types

The following C# data types are supported by Save for Unity

Primitive Data Types

byte
sbyte
char
ushort
short
uint
int
ulong
long
decimal
float
double
string
intptr
uintptr
bool
dbnull
biginteger

C# Classes and Structs

DateTime
TimeSpan
Action
KeyValuePair where T is a C# primitive type or serializable class/struct
User defined classes and structs must have the [Serializable] attribute.

.Net Collections

Array<T> where T is a C# primitive type or serializable class/struct
This includes
Array[] with any number of ranks
and jagged arrays, Array[][], of any depth

IList<T> where T is a C# primitive type or serializable class/struct

IDictionary<T1,T2> where T1 and T2 are C# primitive types or serializable class/struct

Queue<T> where T is a C# primitive type or serializable class/struct
Stack<T> where T is a C# primitive type or serializable class/struct
Hashset<T> where T is a C# primitive type or serializable class/struct

To have these data types extended please refer to Change Requests

<- Previous Next ->



Unity Data types

The following Unity data types are supported by Save for Unity

Vector2
Vector2Int
Vector3
Vector3Int
Vector4
Quaternion
Color
Color32
Rect
Rectint
Matrix4x4
Bounds
BoundsInt
BoneWeight
BoneWeight1
KeyFrame

The utility also supports

Array where T is one of the above.
This includes
Array[]
Array[,]
Array[,,]
And jagged arrays, Array[][] of any depth

List<T> where T is one of the above

Dictionary<T1,T2> where T1 and/or T2 are one of the above or C# primitive types

NativeArray<T> where T is one of the above or a C# primitive type

Queue<T> where T is one of the above
Stack<T> where T is one of the above
Hashset<T> where T is one of the above

The collections also support T where T is one of the Unity classes/string supported by the add on modules

To have these data types extended please refer to Change Requests

<- Previous Next ->



<- Previous Next ->



Additional Information

Support

Support can only be offered to users using Unity LTS versions

Please contact SteveSmith.Software via one of the following channels

To file a Bug Report: SteveSmith.Software Choose the Contact tab and login as guest

Email: Support@SteveSmith.Software

Discord: Join our discord channel at SteveSmith.Software on discord

<- Previous Next ->



Change Requests

Save for Unity aims to be the ultimate serializer/deserialzer for Unity projects.

Any request for additional data type implementation or support will be treated as a matter of urgency

Please email Support@SteveSmith.Software with your request

<- Previous



<- Previous Next ->