The UserData class, which is available as open-source and specifically designed for use in Unity®, serves as a versatile and generic solution. The primary objective of this class is to facilitate seamless and dependable Input/Output operations within Unity®, ensuring consistency and reliability across various platforms, irrespective of the inherent differences or peculiarities associated with each platform. This user-friendly class streamlines the complexities of handling Input/Output tasks, providing a straightforward yet robust mechanism that developers can employ to interact with data consistently, regardless of the specific Unity® platform they are targeting.
- Windows
- Linux
- Mac
- Android
- iOS
- WebGL
- Console
- VR
- Unity 2017 or later
In the Editor, you can access the Package Manager window through: Window > Package Manager, than:
- Open the add menu in the Package Manager's toolbar.
- The options for adding packages appear. Add package from git URL button.
- Select Add package from git URL from the add menu. A text box and an Add button appear.
- Enter a valid Git URL in the text box and click Add.
Enter the following git URL:
https://github.com/benedekmeszaros/unity-hextools-userdata.git
Implementation | Description |
---|---|
UserData<T>(string) |
Initializes a new instance of the UserData class that is empty. |
UserData<T>(string, T) |
Initializes a new instance of the UserData with a provided value. |
Implementation | Type | Description |
---|---|---|
Value |
T |
Gets the current value of the data. |
Name |
string |
Gets the file name of the file without extension. |
Extension |
string |
Gets the file extension. |
Exists |
bool |
Checks if the file exists. |
RelativePath |
string |
Gets the relative path of the file. |
AbsolutePath |
string |
Gets the absolute path of the file. |
Implementation | Return type | Description |
---|---|---|
Save() |
void |
Save the current value to the file. If the file does not exist, create a new one. Each file is stored within the directory specified by Application.persistentDataPath . |
Overwrite(T) |
void |
Overwrites the current value with the specified value and saves it. If the file does not exist, create a new one. |
Load() |
T |
Loads the value from the file. |
Read() |
void |
Loads the value from the file. |
Unload() |
void |
Unloads the current value, setting it to the default value of T. |
Remove() |
bool |
Delete the file from the disk. |
Modify(Action<T>) |
void |
Modifies the current value using the provided action and saves it. |
Modify(Func<T, bool>) |
bool |
Modifies the current value using the provided action. Saves the value if the action returns true. |
GetHashCode() |
int |
Serves as the default hash function. |
Equals(object) |
bool |
Determines whether the specified object is equal to the current object. |
ToString() |
string |
Returns the full path of the corresponding file. |
UserData provides asynchronous versions of each heavy I/O operations:
Implementation | Return type | Description |
---|---|---|
SaveAsync() |
Task |
Save the current value to the file asynchronously. |
SaveAsync(Action) |
void |
Save the current value to the file asynchronously. |
OverwriteAsync(T) |
Task |
Overwrites the current value with the specified value and saves it asynchronously. |
OverwriteAsync(T, Action) |
void |
Overwrites the current value with the specified value and saves it asynchronously. |
ReadAsync() |
Task<T> |
Loads the value from the file asynchronously. |
ReadAsync(Action<T>) |
void |
Loads the value from the file asynchronously. |
LoadAsync() |
Task<T> |
Loads the value from the file asynchronously. |
LoadAsync(Action<T>) |
void |
Loads the value from the file asynchronously. |
ModifyAsync(Action<T>) |
Task |
Modifies the current value using the provided action and saves it asynchronously. |
ModifyAsync(Action<T>, Action) |
Task |
Modifies the current value using the provided action and saves it asynchronously. |
ModifyAsync(Func<T, bool>) |
Task<bool> |
Modifies the current value using the provided action asynchronously. Saves the value if the action returns true. |
ModifyAsync(Func<T, bool>, Action<bool>) |
void |
Modifies the current value using the provided action asynchronously. Saves the value if the action returns true. |
By default this class using the built in JsonUtility
for serialization.
Implementation | Return type | Description |
---|---|---|
Deserialize(byte[]) |
T |
Convert the given byte[] to object. |
Serialize(T) |
byte[] |
Convert the given object to byte[] . |
- Value types
- String
- Array
- Generic list
- Serializable classes
- Serializable structs
UserData has its own property drawer for visual debugging directly in the Inspector, which support deep serialization. Make sure to give SerializeField
attribute to the desired field or make it public
, otherwise the editor won't display it.
[SerializeField] private UserData<Progress> progressData;
Make sure to provide a valid relative path for the given instance.
Enter Play mode
to have access the following utility controlls:
- Create/Save
- Read
- Delete
The subsequent utilization of the Progress
class, in conjunction with the ProgressTracer
class, will be employed for purposes of demonstration.
[System.Serializable]
public class Progress
{
public int coins;
public float highScore;
}
Create a new instance, then load its content. If the target file does not exist, the object keeps its initial value.
using HexTools.Persistence;
public class ProgressTracer : MonoBehaviour
{
private UserData<Progress> progressData = new UserData<Progress>("saved/progress.json", new Progress());
void Awake()
{
// Load the content
progressData.Read();
}
}
Periodic modifications may be preserved by invoking the Save()
function. For a more resilient approach, users have the option to employ the Modify(...)
function along with a lambda expression.
Basic approach:
public void AddCoins(int coins)
{
Progress p = progressData.Value;
p.coins += coins;
progressData.Save();
}
Using the unconditional Modify
function:
public void AddCoins(int coins)
{
progressData.Modify(p => p.coins += coins);
}
Using the conditional Modify
function:
public bool UpdateHighScore(float score)
{
// Saving occurs exclusively when the provided anonymous function returns a true value.
return progressData.Modify(p =>
{
bool update = p.highScore < score;
if (update)
p.highScore = score;
return update;
});
}
public void LoadProgress()
{
progressData.Read();
//or
progressData.Load();
}
public void ResetProgress()
{
progressData.Overwrite(new Progress());
}
public bool RemoveProgress()
{
//Returns true if the file is successfuly deleted.
return progressData.Remove();
}
public void SaveProgress()
{
progressData.SaveAsync(() => {
print("Game saved!");
});
}
// or
public IEnumerator SaveProgress()
{
yield return progressData.SaveAsync();
print("Game saved!");
}
public void LoadProgress()
{
progressData.LoadAsync(p => {
print("Progress loaded!");
});
}
// or
public IEnumerator LoadProgress()
{
var task = progressData.LoadAsync();
yield return task;
Progress p = task.Result;
print("Progress loaded!");
}