ScriptableObject Pro Version V.1.0.0

Introduction

ScriptableObject Pro is a utility that enables the saving and loading of Unity ScriptableObjects at runtime.
This means that changes to the ScriptableObject data will be persisted across runs thus enabling a save/load scenario whilst using Unity Scriptable Object technology.

Please refer to the section Quick Start to see the steps necessary to quickly upgrade a Unity ScriptableObject to ScriptableObject Pro

This version of the utility was written in C# with Unity .Net 4.7.1 libraries and tested using Unity 2020.3 and 2021.3 for Standalone, WebGL, Andriod and IOS but should function on all platforms supported by Unity.
Whilst every effort has been made to ensure the compatibility of ScriptableObject Pro with all Unity versions, the correct functioning of the software with Unity Alpha, Beta or Technical releases cannot be guaranteed.

Please refer to the section Change Requests should you have a serializable field which ScriptableObject Pro cannot handle.

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 2022.

Next ->



Quick Start

Unity Scriptable Object


using UnityEngine;

[CreateAssetMenu (fileName="New MySO", menuName="My SO ")]
public class MySO : ScriptableObject
{
	public Vector3[] waypoints;
	public Vector3 currPosition;
	public int nextWayPoint = 1;
	public float currLerp = 0f;
	public Material currMat;
}


ScriptableObject Pro


using UnityEngine;
[CreateAssetMenu(fileName = "New MySO", menuName = "My SO")]
[SSSoftware.Attributes.Mutable]
public class MySO : SSSoftware.SOPro.ScriptableObject
{
	public Vector3[] waypoints;
	public Vector3 currPosition;
	public int nextWayPoint = 1;
	public float currLerp=0.0f;
	public Material currMat;
}

1) Change - The inheritance of the class
public class MySO : ScriptableObject
becomes
public class MySO : SSSoftware.SOPro.ScriptableObject
This switches the class from UnityEngine.ScriptableObject to SOPro.ScriptableObject

2) Add - [SSSoftware.Attributes.Mutable] - Above the class definiton. This makes all public, serializable fields in the class mutable.

3) If your ScriptableObject implements the OnEnable method it MUST call the ScriptableObject Pro OnEnable as it's FIRST action


	private void OnEnable()
	{
		// Your code here
	}
Before



	private new void OnEnable()
	{
		base.OnEnable();

		// Your code here
	}
After
Note: The new keyword is also added to the method signature to surpress the compiler warning



NOTE: This is the minimum required to upgrade from a Unity ScriptableObject to ScriptableObject Pro.
Your usage of mutable ScriptableObjects can be made more efficient by following the complete documentation.



<- Previous Next ->



ScriptableObject

The class from which all ScriptableObject Pro classes should inherit.

Namspace SSSoftware.SOPro

Class public class ScriptableObject

Overview

All ScriptableObject Pro objects must implement 2 things

1) Inherit from SSSoftware.SOPro.ScriptableObject
2) Apply the [SSSoftware.Attributes.Mutable] attribute. See Attributes for more information on SOPro Attribute usage.

This will enable the default save behaviour of ScriptableObject Pro. Refer to AutoSaveOff and AutoSaveOn for more information.

At runtime ScriptableObject Pro creates a save file in the Application.persistentDataPath folder for your target platform.
Note: To Reset the ScriptableObject to it's original build values this file may be deleted.

ScriptableObject Pro uses a custom, copyrighted file format. Any attempt to modiy a ScriptableObject Pro file outside of this utility will render it inoperable.

The ScriptableObject Pro Anti-Cheat system offers 2 methods of automatically dealing with tampered files ResetOnError and QuitOnError if you do not use these then your application should cater for the fact that should the save file have been tampered with an Exception will be thrown.
Refer to Exceptions and OnEnable for more details.

<- Previous Next ->



Constructors

As with Unity ScriptableObjects ScriptableObject Pro classes can NOT be constructed using the new keyword.

Unitys [CreateAssetMenu] attribute may be applied to the derived class for asset creation.

For creation of ScriptableObject assets using Unity Editor code please refer to Unity ScriptableObject.CreateInstance documentation.

Note: ScriptableObjects cannot be created at runtime.

<- Previous Next ->



Fields

All of the public serializable fields of your ScriptableObject are exposed in the Unity Editor and UnityEngine exactly as a Unity ScriptableObject would be.

private or non serrializable fileds are accesible through code.

ScriptableObject Pro enables the serialization and mutability of several data types that Unity ScriptableObjects do not. Please refer to C# Data types and Unity Data types for more information.

In addition to this there are 2 fields unique to ScriptableObject Pro

int id A unique identifier for this ScriptableObject asset
long dateUpdated The date/Time the Scriptable object was last created/updated

These fields are not visible in the Unity Editor Inspector, they are assigned automatically by the utility and must NOT be changed by your code.

<- Previous Next ->



Properties

These additional properties are defined by ScriptableObject Pro

Path

Path

string Path

This property returns the full path and file name of the underlying save file for the ScriptableObject

Example Usage


	File.Delete(MySoPro.Path);

This will delete the underlying save file and reset the ScriptableObject to it's build values on next application run.





<- Previous Next ->



<- Previous Next ->



Methods

The following are the public methods which can be called by user code to control the functioning of ScriptableObject Pro. Other, undocumented, public methods are for internal use only and should NOT be called by user code.

AutoSaveOff


void AutoSaveOff()

Description
By default the state of a ScriptableObject Pro class will be saved automatically when the application quits or looses focus. A call to AutoSaveOff will disable this behaviour and it is then the responsibility of user code to call Save to save the state.

Parameters
none

Return values
none

Example


MySOPro.AutoSaveOff(); // Disable the default save behaviour

MySOPro.AutoSaveOff(); // Cancel a previous timed Autosave


<- Previous Next ->



AutoSaveOn


void AutoSaveOn(float time)

Description
This method activates the default saving of objects and, alternatively, adds a timed save

Parameters
time The time interval in seconds at which saves are to be performed. Optional when restoring default behaviour

Return values
none

Example


	MySOPro.AutoSaveOn(); // Enable default save behaviour (On Exit or Lost Focus)

	MySOPro.AutoSaveOn(0.5f); // Autosave MySOPro every half second


<- Previous Next ->



OnEnable

The OnEnable method is automatically called by Unity when your application starts.

If you have implemented the OnEnable method in your ScriptableObject then it MUST call the ScriptableObject Pro OnEnable as it's FIRST action


	private void OnEnable()
	{
		// Your code here
	}
Before



	private new void OnEnable()
	{
		base.OnEnable();

		// Your code here
	}
After
Note: The new keyword is also added to the method signature to surpress the compiler warning


This is also a good place to check if a ScriptableObject Pro file has been tampered with


	private new void OnEnable()
	{
		try
		{
			base.OnEnable();
		}
		catch (System.IO.FileLoadException)
		{
			Debug.Log("The ScriptableObject Pro file has been modified");

			// This is the same as the [QuitOnError] attribute
			Application.Quit();

			// OR

			// This is the same as the [ResetOnError] attribute
			// Delete the modified file which will reset the ScriptableObject to it's build state
			System.IO.File.Delete(Path);

			// Reload Original ScriptableObject
			base.OnEnable();
		}

		// Your code here
	}





<- Previous Next ->



Save


void Save()

Description
This method will Save the current state of the ScriptableObject Pro class.
If AutoSaveOff has been used then this method MUST be called in order to save the state.

Parameters
none

Return values
none

Example


	 MySOPro.Save(); // Save the current state of MySOPro


<- Previous Next ->



<- Previous Next ->



Attributes

Attributes applicable to ScriptableObject Pro classes

Namespace SSSoftware.Attributes

Immutable

Attribute

Example usage

[SSSoftware.Attributes.Immutable]
public int myInt;

using SSSoftware.Attributes;

[Immutable]
public int myInt;


The Immutable attribute can only be applied at field level.

The Immutable attribute means that ScriptableObjectPro will not serialize the field and so changes will not persist.
Using this attribute can offer significant performance improvements when a ScriptableObject contains a mixture of immutable and mutables fields.

Please refer to Immutable Fields for example usage

<- Previous Next ->



Mutable

Attribute

Example usage

[SSSoftware.Attributes.Mutable]
public int myInt;

using SSSoftware.Attributes;
[Mutable]
public class mySOPro : SSSoftware.SOPro.ScriptableObject


Using the Mutable attribute allows ScriptableObject Pro to save and load changes to the data at runtime.

The Mutable attribute can be applied at class or field level.

If this attribute is applied at class level then all public serializable fields in the class will also be mutable.

If the attribute is NOT applied at class level then only those fields to which the [Mutable] attribute is applied will be serialized. A ScriptableObject Pro derived class must have at least one [Mutable] field.

Unlike other serializers, applying the [Mutable] attribute to non public fields will also enable the field to be sertialized.

Please refer to Mutable Class and Mutables Fields for example usage

<- Previous Next ->



PersistAcrossBuilds

Attribute

Example usage

[SSSoftware.Attributes.PersistAcrossBuilds]
public class mySOPro : SSSoftware.SOPro.ScriptableObject

using SSSoftware.Attributes;
[PersistAcrossBuilds]
public class mySOPro : SSSoftware.SOPro.ScriptableObject


Using the PersistAcrossBuilds attribute will stop the system from overwriting the saved data when a new build of the application is run for the first time.
Important This attribute should NOT be used when ANY change has been made to the ScriptableObject data structure.

Note: ScriptableObjects which contain UnityObjects can become unstable when this attribute is applied. Refer to Persist Unity Objects for an example workaround to this.

<- Previous Next ->



ResetOnError

Attribute

Example usage

[SSSoftware.Attributes.ResetOnError]
public class mySOPro : SSSoftware.SOPro.ScriptableObject

using SSSoftware.Attributes;
[ResetOnError]
public class mySOPro : SSSoftware.SOPro.ScriptableObject

Applying this attribute to a ScriptableObject Pro class will cause the ScriptableObject to be reset to it's original build values if the ScriptableObject Pro file has been modified in any way.
This attribute can be applied to automatically enforce the anti-cheat protection without affecting game play.

If neither this or the QuitOnError attribute are applied you are responsible for catching and handling errors.

<- Previous Next ->



QuitOnError

Attribute

Example usage

[SSSoftware.Attributes.QuitOnError]
public class mySOPro : SSSoftware.SOPro.ScriptableObject

using SSSoftware.Attributes;
[QuitOnError]
public class mySOPro : SSSoftware.SOPro.ScriptableObject

Applying this attribute to ANY ScriptableObject Pro class will force the application to Quit is the ScriptableObject Pro file has been modified in any way.

This attribute should be applied with caution because once it has fired the only way that the application can be run again is by manually deleting the modified ScriptableObject Pro file from the Application.persistentDataPath folder.

If neither this or the ResetOnError attribute are applied you are responsible for catching and handling errors.

<- Previous Next ->



<- Previous Next ->



Exceptions

Exceptions are thrown only when it is impossible for the system to recover.

In the case of the run time exceptions it is strongly recommended that these be caught and a call to Application.Quit() be made.
Refer to OnEnable for an example of how to implement this.

ArgumentNullException
This exception may be thrown when the ScriptableObject Pro files are being created. It is an indication that no mutable fields were found in a class.

FileNotFoundException
This exception will be thrown when the system is unable to save the state of an object. It is possibly a permissions or file size problem.

FileLoadException
This exception will be thrown when a ScriptableObject Pro file has been tampered with.
Refer to the ResetOnError and QuitOnError attributes for possibile remedial actions.
This exception may also be thrown when trying to load a file to a ScriptableObject with a modified data structure.

ArgumentOutOfRangeException
This exception will be thrown when trying to load a file created with an incompatible version of ScriptableObject Pro.

<- Previous Next ->



<- Previous Next ->



Testing

In order to test the correct functioning of ScriptableObject Pro at run time but without having to make a build of your project 2 menu options are available at

Tools->ScriptableObject Pro

Enable in Play Mode

Disable in Play Mode

Enable in Play Mode

Unity menu option

Tools->ScriptableObject Pro->Enable in Play Mode

This option turns ON the ScriptableObject Pro utility when entering Play Mode in the Unity Editor.

Additional debugging information will be shown in the Unity Console.

Note: In order to test data persistence in Editor Play Mode the ScriptableObject must implement the [PersistAcrossBuilds] attribute.

<- Previous Next ->



Disable in Play Mode

Unity menu option

Tools->ScriptableObject Pro->Disable in Play Mode

This option turns OFF the ScriptableObject Pro utility when entering Play Mode in the Unity Editor.


<- Previous Next ->



<- Previous Next ->



Example Code

Here I will publish code to illustrate the various usages of ScriptableObject Pro.

This code is copyright SteveSmith.Software 2022. But may be used as is or in a modified form under the MIT License.

No warranty of useability or support will be applicable for the use of code derived from these examples.

Mutable Class

Apply the [Mutable] attribute to a class.

All of the serializable fields in the class will become mutable


using System;
using UnityEngine;

using SSSoftware.Attributes;

[CreateAssetMenu(fileName = "New MySO", menuName = "MySO")]
[Mutable]
public class MySO : SSSoftware.SOPro.ScriptableObject
{
	public Vector3[] waypoints;
	public Vector3 currPosition;
}



<- Previous Next ->



Mutable Fields

Apply the [Mutable] attribute to a field.

Only those fields with the attribute will be mutable


using System;
using UnityEngine;

using SSSoftware.Attributes;

[CreateAssetMenu(fileName = "New MySO", menuName = "MySO")]
public class MySO : SSSoftware.SOPro.ScriptableObject
{
     public Vector3[] waypoints;
     [Mutable]
     public Vector3 currPosition;
}


In this example changes to currPosition will be persisted. Changes to waypoints will NOT persist.

<- Previous Next ->



Immutable Fields

Apply the [Mutable] attribute to a class.or to fields
Apply the [Immutable] attribute to fields to be ignored


using System;
using UnityEngine;

using SSSoftware.Attributes;

[CreateAssetMenu(fileName = "New MySO", menuName = "MySO")]
[Mutable]
public class MySO : SSSoftware.SOPro.ScriptableObject
{
     [Immutable]
     public Vector3[] waypoints;
     public Vector3 currPosition;
}



using System;
using UnityEngine;

using SSSoftware.Attributes;

[CreateAssetMenu(fileName = "New MySO", menuName = "MySO")]
public class MySO : SSSoftware.SOPro.ScriptableObject
{
     [Immutable]
     public Vector3[] waypoints;
     [Mutable]
     public Vector3 currPosition;
}


In these examples changes to currPosition will be persisted. Changes to waypoints will NOT persist.



<- Previous Next ->



User defined Save


using System;
using UnityEngine;

using SSSoftware.Attributes;

[CreateAssetMenu(fileName = "New MySO", menuName = "MySO")]
[Mutable]
public class MySO : SSSoftware.SOPro.ScriptableObject
{
	public Vector3 currPosition;
}




using UnityEngine;

public class MyScript : MonoBehaviour
{
	public MySO so;

	void Start()
	{
		transform.localPosition = so.currPosition;
		so.AutoSaveOff(); // Do not autosave
	}

	void Update()
	{
		so.currPosition = transform.position;
		so.Save(); // Save every Update
	}

	void OnApplicationQuit()
	{
		so.currPosition = transform.position;
		so.Save(); // Save On Exit
	}
}



<- Previous Next ->



AutoSave


using System;
using UnityEngine;

using SSSoftware.Attributes;

[CreateAssetMenu(fileName = "New MySO", menuName = "MySO")]
[Mutable]
public class MySO : SSSoftware.SOPro.ScriptableObject
{
	public Vector3 currPosition;
}




using UnityEngine;

public class MyScript : MonoBehaviour
{
	public MySO so;

	void Start()
	{
		transform.localPosition = so.currPosition;
		so.AutoSaveOn(0.5f); // Autosave every half second and On Exit
	}

	void Update()
	{
		so.currPosition = transform.position;
	}
}



<- Previous Next ->



Persist Unity Objects

Persisting UnityObjects across builds could cause instability in the ScriptableObject save file.

Using an index into an array of objects stored on a MonoBehaviour will mitigate this potential problem.

Before (May NOT Persist across builds)


using System;
using UnityEngine;

using SSSoftware.Attributes;

[CreateAssetMenu(fileName = "New MySO", menuName = "MySO")]
[Mutable]
[PersistAcrossBuilds]
public class MySO : SSSoftware.SOPro.ScriptableObject
{
	public Material currMat;
}



using UnityEngine;

public class MyScript : MonoBehaviour
{
	public MySO so;

	void Start()
	{
		if (so.currMat != null)
		{
			MeshRenderer mr = GetComponent();
			mr.material = so.currMat;
		}
	}
}



After (Will persist across builds)


using System;
using UnityEngine;

using SSSoftware.Attributes;

[CreateAssetMenu(fileName = "New MySO", menuName = "MySO")]
[Mutable]
[PersistAcrossBuilds]
public class MySO : SSSoftware.SOPro.ScriptableObject
{
	public int currMat;
}



using UnityEngine;

public class MyScript : MonoBehaviour
{
	public MySO so;
	public Material[] materials;

	void Start()
	{
		MeshRenderer mr = GetComponent();
		mr.material = materials[so.currMat];
	}
}



<- Previous Next ->



<- Previous Next ->



Supported Datatypes

ScriptableObject Pro supports many C# and Unity data types.

Some data types not supported by Unity ScriptableObjects are supported by Scriptableobjects Pro as mutable data.

C# Data types

The following C# data types are supported by ScriptableObject Pro

Primitive Data Types

byte
sbyte
char
ushort
short
uint
int
ulong
long
decimal
float
double
string

C# Classes

User defined classes must have the [Serializable] attribute.
Classes must have either the [Mutable] attribute or one or more fields with the [Mutable] attribute in the class

DateTime

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

List<T> where T is a C# primitive type

Dictionary<T1,T2> where T1 and T2 are C# primitive types

To have these data types extended please refer to Change Requests

<- Previous Next ->



Unity Data types

The following Unity data types are supported by ScriptableObject Pro

Vector2
Vector2Int
Vector3
Vector3Int
Vector4
Quaternion
Color
Color32
Rect
Rectint

The utility also supports

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

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

To have these data types extended please refer to Change Requests


<- Previous Next ->



Unity Objects

Scriptable Object Pro can save and load any object that derives from UnityEngine.Object with the following proviso.

The utility does NOT serialize the actual object but holds a reference into the Unity Resources database.

Therefore all Unity Objects that need to be saved/loaded MUST be present in the Unity Resources database at the time of project build.
So GameObjects which are prefabs or present in a scene can be saved. GameObjects which are instantiated at runtime can not.

Note: Usage of the PersistAcrossBuilds attribute can cause instability in the ScriptableObject when UnityEngine Objects are used. Refer to Persist Unity Objects for an example of a workaround.

<- 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: SOPro@SteveSmith.Software

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

<- Previous Next ->



Change Requests

ScriptableObject Pro 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 SOPro@SteveSmith.Software with your request

<- Previous



<- Previous Next ->