# 🛠️ 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 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
}

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])
        };
    }
}

# 📝 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.

# 🏷️ 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.

💡 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 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();

# 🌱 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.

JSON.NET docs on JsonConverter
https://www.newtonsoft.com/json/help/html/CustomJsonConverterGeneric.htm