#
🛠️ Pref Types
Unity’s built-in PlayerPrefs
and EditorPrefs
are limited to just three data types: int
, float
, and string
. That works for simple use cases — but as your project grows, that limitation quickly becomes painful.
EazyPrefs expands on this with a wide range of built-in types, giving you the ability to store data like Vector3
, Color
, DateTime
, enums, even complex objects — all without needing to manually serialize or deserialize anything.
On top of that, EazyPrefs is fully extensible. You can define your own pref types, with custom serialization, validation, and helper methods, tailored to your project’s needs.
#
🧰 Supported Built-in Types
Out of the box, EazyPrefs supports the following pref types:
int
,uint
,float
,double
,short
,ushort
,long
,ulong
,bool
,string
,char
,byte
Enum<T>
DateTime
,TimeSpan
Vector2
,Vector2Int
,Vector3
,Vector3Int
,Vector4
,Quaternion
Color
JSONObj<T>
— for storing complex classes and collections
You can use Arrays, Lists, Dictionaries or any other collections you want, using the JSONObjPref<T>
pref type.
You can use these with either PlayerPrefs or EditorPrefs, and they work with both static and instance-based access.
#
♻️ How It Works
Internally, all EazyPrefs types extend a common Pref<T>
base class. However, Most advanced types use the StringBasedPref<T>
class — which adds support for encryption, compression, and is based on string serialization.
For structured data (e.g. classes, dictionaries), EazyPrefs uses JSONObjPref<T>
, which wraps around StringBasedPref<T>
and uses JSON.NET for serialization.
#
✨ Creating Your Own Pref Type
EazyPrefs supports custom pref types of any class. Assume we have a class UserData
we want to turn into a pref type
[Serializable]
public class UserData
{
public string name;
public int coins;
public Difficulty selectedDifficulty;
}
public enum Difficulty
{
Easy,
Medium,
Hard
}
Make sure to always use the [Serializable]
attribute on classes you use with EazyPrefs.
There are two recommended ways to implement a custom pref type:
#
Option 1: Extend JSONObjPref<T>
Use this if you want a custom strongly-typed wrapper around a class or struct, and you're fine using built-in JSON serialization.
[PrefTypeName("UserData")]
[PrefTypeSerializationAlias("UserData")]
public class UserDataPref : JSONObjPref<UserData>
{
public UserDataPref(IPrefStorageSource source) : base(source) { }
// Optional: Add custom methods, logic, or defaults here
}
This avoids repeating new JSONObjPref<UserData>(...)
everywhere and keeps your codebase cleaner.
#
Option 2: Extend StringBasedPref<T>
Use this if you want full control over serialization, for performance, optimization, or compatibility with a non-JSON format.
[PrefTypeName("UserData")]
[PrefTypeSerializationAlias("UserData")]
public class UserDataPref : StringBasedPref<UserData>
{
public UserDataPref(IPrefStorageSource source) : base(source) { }
protected override string ConvertValueToString(UserData value)
{
// Store as a delimited string: name|coins|difficulty
return $"{value.name}|{value.coins}|{(int)value.selectedDifficulty}";
}
protected override UserData ConvertStringToValue(string valueStr)
{
var parts = valueStr.Split('|');
return new UserData
{
name = parts[0],
coins = int.Parse(parts[1]),
selectedDifficulty = (Difficulty)int.Parse(parts[2])
};
}
}
This is the preferred approach if you want to optimize how data is stored and retrieved — for example, using delimited strings instead of JSON, or storing binary-like formats as Base64.
#
📝 What Do These Methods Do?
When creating a custom StringBasedPref<T>
, you're responsible for defining how the value is converted to/from a string. This is done by implementing two required methods:
ConvertValueToString(TValue value)
This method should convert your data into a string representation. This string will then be optionally compressed, encrypted, and stored.ConvertStringToValue(string valueStr)
This method takes the stored string (after it has been decrypted and decompressed, if applicable) and turns it back into the object you're working with.
Use these methods to define how your type is represented internally — whether it’s JSON, a CSV-style string, XML, or something else entirely.
#
🏷️ PrefTypeName Attribute
When creating your own custom pref types, you can optionally decorate the class with a PrefTypeName
attribute:
[PrefTypeName("UserData")]
public class UserDataPref : JSONObjPref<UserData>
{
public UserDataPref(IPrefStorageSource source) : base(source) { }
}
This attribute provides a friendlier, cleaner name for your pref type, which is especially useful in the EazyPrefs Editor UI. If the attribute is not used, EazyPrefs will fall back to using the full type name (e.g., UserDataPref
), which might be unnecessarily verbose or less readable in some cases.
Make sure not to have more than one pref classes share the same name, as it might lead to unexpected behaviour, or some prefs classes being ignored
#
🏷️ PrefTypeSerializationAlias Attribute
When a pref is saved, EazyPrefs includes metadata about the pref's type so that it can be properly identified and rendered in the editor later.
By default, this type info uses the full assembly-qualified class name — which can be long, hard to read, and brittle if the class is ever renamed or moved.
To solve this, you can use the PrefTypeSerializationAliasAttribute
to assign a short and stable alias to your pref class:
[PrefTypeSerializationAlias("UserData")]
public class UserDataPref : JSONObjPref<UserData>
{
public UserDataPref(IPrefStorageSource source) : base(source) { }
}
This alias will be stored with the pref metadata instead of the full type name.
Make sure not to have more than one pref classes share the same alias, as it might lead to unexpected behaviour, or some prefs classes being correctly read/written.
💡 Why Use It?
- Makes the serialized data shorter and more human-readable
- Prevents issues if you rename or move your pref class
- Ensures the editor can always recognize and draw the pref correctly, as long as the alias stays the same
Using a serialization alias is the recommended approach when creating custom pref types — especially if you're shipping tools, plugins, or working in larger codebases.
If you change the alias after a pref has been saved, the editor will no longer be able to associate it with the correct drawer or type. Always treat aliases as stable identifiers.
Avoid renaming pref classes without a serialization alias
If you rename or move a pref class and haven't assigned a stable serialization alias, the editor may no longer recognize the pref type.
This can result in fallback visuals, incorrect drawers, or warnings in the editor.
Accessing the pref from code will still work, since it relies only on the key — but the editor experience may break.
To prevent this, you should:
- Use the
PrefTypeSerializationAlias
attribute to assign a stable alias to your pref class (recommended) - Keep the alias consistent even if the class name changes
- Avoid depending on the full class name as an identifier
#
Using the new pref
With both options, you can now use your custom pref type like this:
var source = new PlayerPrefStorageSource("UserData");
var userDataPref = new UserDataPref(source);
// We create a temporary UserData object for demonstration purposes.
// You could just pass your own reference directly (if you have one)
var userData = new UserData
{
name = "Alex",
coins = 200,
selectedDifficulty = Difficulty.Medium
}
// Set the value
userDataPref.SetValue(userData);
// Use this when you want to retrieve the last stored value.
UserData data = userDataPref.GetValue();
Use JSONObjPref
#
🌱 Overriding the Default Value
Another virtual method you can override in both StringBasedPref<T>
and JSONObjPref<T>
is:
public virtual TValue GetDefaultValue() => default;
This method defines the fallback value returned when:
- The pref is not yet set
- The stored data is corrupted
- Deserialization fails
- You explicitly reset the pref
By default, this returns the standard .NET default for your type (null
for reference types). You can override it to return something more meaningful to your use case.
public override UserData GetDefaultValue()
{
return new UserData
{
name = "Guest",
coins = 0,
selectedDifficulty = Difficulty.Easy
};
}
#
🔧 Advanced: Custom JSON Converters
You can also optionally override the GetJSONConverter()
method:
protected override JsonConverter<UserData> GetJSONConverter()
{
return new MyCustomUserDataConverter();
}
This allows you to plug in a custom JsonConverter<T>
for full control over how your type is serialized and deserialized through JSON.NET. This is also useful for value types that cannot be correctly serialized/deserialized by default (like some Unity types like Color
)
You can override this in either JSONObjPref<T>
or your own StringBasedPref<T>
implementation — useful if you're mixing default serialization with something more custom.