diff --git a/.BinaryPrefs/ProjectSettings/ProjectSettings.asset b/.BinaryPrefs/ProjectSettings/ProjectSettings.asset
index 6cc1934..e0783dd 100644
--- a/.BinaryPrefs/ProjectSettings/ProjectSettings.asset
+++ b/.BinaryPrefs/ProjectSettings/ProjectSettings.asset
@@ -54,7 +54,7 @@ PlayerSettings:
mipStripping: 0
numberOfMipsStripped: 0
numberOfMipsStrippedPerMipmapLimitGroup: {}
- m_StackTraceTypes: 000000000000000000000000000000000000000001000000
+ m_StackTraceTypes: 010000000100000001000000010000000100000001000000
iosShowActivityIndicatorOnLoading: -1
androidShowActivityIndicatorOnLoading: -1
iosUseCustomAppBackgroundBehavior: 0
diff --git a/Runtime/BinaryPrefs.cs b/Runtime/BinaryPrefs.cs
new file mode 100644
index 0000000..fa8a298
--- /dev/null
+++ b/Runtime/BinaryPrefs.cs
@@ -0,0 +1,153 @@
+using System.IO;
+using UnityEngine;
+
+namespace Appegy.Storage
+{
+ public static class BinaryPrefs
+ {
+ private static readonly BinaryStorage _storage = BinaryStorage
+ .Construct(Path.Combine(Application.persistentDataPath, PackageInfo.Name, "player_prefs.bin"))
+ .AddPrimitiveTypes()
+ .EnableAutoSaveOnChange()
+ .SetMissingKeyBehaviour(MissingKeyBehavior.ReturnDefaultValueOnly)
+ .SetTypeMismatchBehaviour(TypeMismatchBehaviour.OverrideValueAndType)
+ .Build();
+
+ ///
+ /// Sets the value of the preference identified by the given key.
+ ///
+ /// The key to set the value for.
+ /// The value to set.
+ public static void SetInt(string key, int value)
+ {
+ _storage.Set(key, value);
+ }
+
+ ///
+ /// Returns the value corresponding to key in the preference file if it exists.
+ /// If the key is not found in the current storage, it checks PlayerPrefs.
+ ///
+ /// The key to retrieve the value for.
+ /// The default value to return if the key does not exist.
+ /// The value corresponding to key.
+ public static int GetInt(string key, int defaultValue = 0)
+ {
+ if (_storage.Has(key))
+ {
+ return _storage.Get(key, defaultValue);
+ }
+
+ if (PlayerPrefs.HasKey(key))
+ {
+ var value = PlayerPrefs.GetInt(key, defaultValue);
+ _storage.Set(key, value);
+ return value;
+ }
+
+ return defaultValue;
+ }
+
+ ///
+ /// Sets the value of the preference identified by the given key.
+ ///
+ /// The key to set the value for.
+ /// The value to set.
+ public static void SetFloat(string key, float value)
+ {
+ _storage.Set(key, value);
+ }
+
+ ///
+ /// Returns the value corresponding to key in the preference file if it exists.
+ /// If the key is not found in the current storage, it checks PlayerPrefs.
+ ///
+ /// The key to retrieve the value for.
+ /// The default value to return if the key does not exist.
+ /// The value corresponding to key.
+ public static float GetFloat(string key, float defaultValue = 0f)
+ {
+ if (_storage.Has(key))
+ {
+ return _storage.Get(key, defaultValue);
+ }
+
+ if (PlayerPrefs.HasKey(key))
+ {
+ var value = PlayerPrefs.GetFloat(key, defaultValue);
+ _storage.Set(key, value);
+ return value;
+ }
+
+ return defaultValue;
+ }
+
+ ///
+ /// Sets the value of the preference identified by the given key.
+ ///
+ /// The key to set the value for.
+ /// The value to set.
+ public static void SetString(string key, string value)
+ {
+ _storage.Set(key, value);
+ }
+
+ ///
+ /// Returns the value corresponding to key in the preference file if it exists.
+ /// If the key is not found in the current storage, it checks PlayerPrefs.
+ ///
+ /// The key to retrieve the value for.
+ /// The default value to return if the key does not exist.
+ /// The value corresponding to key.
+ public static string GetString(string key, string defaultValue = "")
+ {
+ if (_storage.Has(key))
+ {
+ return _storage.Get(key, defaultValue);
+ }
+
+ if (PlayerPrefs.HasKey(key))
+ {
+ var value = PlayerPrefs.GetString(key, defaultValue);
+ _storage.Set(key, value);
+ return value;
+ }
+
+ return defaultValue;
+ }
+
+ ///
+ /// Returns true if the key exists in the preference file.
+ ///
+ /// The key to check for existence.
+ /// True if the key exists; otherwise, false.
+ public static bool HasKey(string key)
+ {
+ return _storage.Has(key) || PlayerPrefs.HasKey(key);
+ }
+
+ ///
+ /// Removes the given key from the preference file.
+ ///
+ /// The key to remove.
+ public static void DeleteKey(string key)
+ {
+ _storage.Remove(key);
+ }
+
+ ///
+ /// Removes all keys and values from the preference file.
+ ///
+ public static void DeleteAll()
+ {
+ _storage.RemoveAll();
+ }
+
+ ///
+ /// Writes all modified preferences to disk.
+ ///
+ public static void Save()
+ {
+ _storage.Save();
+ }
+ }
+}
\ No newline at end of file
diff --git a/Runtime/BinaryPrefs.cs.meta b/Runtime/BinaryPrefs.cs.meta
new file mode 100644
index 0000000..3588755
--- /dev/null
+++ b/Runtime/BinaryPrefs.cs.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: 6aa0713cf5824cd5acef4288973e8500
+timeCreated: 1718807205
\ No newline at end of file
diff --git a/Tests/BinaryPrefsTests.cs b/Tests/BinaryPrefsTests.cs
new file mode 100644
index 0000000..1f58c39
--- /dev/null
+++ b/Tests/BinaryPrefsTests.cs
@@ -0,0 +1,289 @@
+using FluentAssertions;
+using NUnit.Framework;
+using UnityEngine;
+
+namespace Appegy.Storage
+{
+ [TestFixture]
+ public class BinaryPrefsIntTests
+ {
+ [SetUp, TearDown]
+ public void SetUp()
+ {
+ // Clear PlayerPrefs and BinaryPrefs before each test
+ PlayerPrefs.DeleteAll();
+ BinaryPrefs.DeleteAll();
+ }
+
+ #region Integer
+
+ [Test]
+ public void SetInt_ShouldStoreValueInBinaryStorage()
+ {
+ // Arrange
+ var key = "key";
+ var value = 42;
+
+ // Act
+ BinaryPrefs.SetInt(key, value);
+
+ // Assert
+ BinaryPrefs.GetInt(key).Should().Be(value);
+ }
+
+ [Test]
+ public void GetInt_ShouldReturnDefaultValueIfKeyNotFound()
+ {
+ // Arrange
+ var key = "unknownKey";
+ var defaultValue = 10;
+
+ // Act
+ var result = BinaryPrefs.GetInt(key, defaultValue);
+
+ // Assert
+ result.Should().Be(defaultValue);
+ }
+
+ [Test]
+ public void GetInt_ShouldReturnValueFromPlayerPrefsIfNotInBinaryStorage()
+ {
+ // Arrange
+ var key = "key";
+ var playerPrefsValue = 100;
+
+ // Store value in PlayerPrefs only
+ PlayerPrefs.SetInt(key, playerPrefsValue);
+
+ // Act
+ var result = BinaryPrefs.GetInt(key);
+
+ // Assert
+ result.Should().Be(playerPrefsValue);
+
+ // Verify that the value is now stored in BinaryStorage
+ BinaryPrefs.GetInt(key).Should().Be(playerPrefsValue);
+ }
+
+ [Test]
+ public void GetInt_ShouldReturnDefaultValueIfKeyNotFoundInBothStorages()
+ {
+ // Arrange
+ var key = "nonExistentKey";
+ var defaultValue = 20;
+
+ // Act
+ var result = BinaryPrefs.GetInt(key, defaultValue);
+
+ // Assert
+ result.Should().Be(defaultValue);
+ }
+
+ [Test]
+ public void SetInt_ShouldOverrideExistingValueInBinaryStorage()
+ {
+ // Arrange
+ var key = "key";
+ var initialValue = 42;
+ var newValue = 84;
+
+ // Store initial value
+ BinaryPrefs.SetInt(key, initialValue);
+
+ // Act
+ BinaryPrefs.SetInt(key, newValue);
+
+ // Assert
+ BinaryPrefs.GetInt(key).Should().Be(newValue);
+ }
+
+ #endregion
+
+ #region Float
+
+ [Test]
+ public void SetFloat_ShouldStoreValueInBinaryStorage()
+ {
+ // Arrange
+ var key = "key";
+ var value = 42f;
+
+ // Act
+ BinaryPrefs.SetFloat(key, value);
+
+ // Assert
+ BinaryPrefs.GetFloat(key).Should().Be(value);
+ }
+
+ [Test]
+ public void GetFloat_ShouldReturnDefaultValueIfKeyNotFound()
+ {
+ // Arrange
+ var key = "unknownKey";
+ var defaultValue = 10f;
+
+ // Act
+ var result = BinaryPrefs.GetFloat(key, defaultValue);
+
+ // Assert
+ result.Should().Be(defaultValue);
+ }
+
+ [Test]
+ public void GetFloat_ShouldReturnValueFromPlayerPrefsIfNotInBinaryStorage()
+ {
+ // Arrange
+ var key = "key";
+ var playerPrefsValue = 100f;
+
+ // Store value in PlayerPrefs only
+ PlayerPrefs.SetFloat(key, playerPrefsValue);
+
+ // Act
+ var result = BinaryPrefs.GetFloat(key);
+
+ // Assert
+ result.Should().Be(playerPrefsValue);
+
+ // Verify that the value is now stored in BinaryStorage
+ BinaryPrefs.GetFloat(key).Should().Be(playerPrefsValue);
+ }
+
+ [Test]
+ public void GetFloat_ShouldReturnDefaultValueIfKeyNotFoundInBothStorages()
+ {
+ // Arrange
+ var key = "nonExistentKey";
+ var defaultValue = 20f;
+
+ // Act
+ var result = BinaryPrefs.GetFloat(key, defaultValue);
+
+ // Assert
+ result.Should().Be(defaultValue);
+ }
+
+ [Test]
+ public void SetFloat_ShouldOverrideExistingValueInBinaryStorage()
+ {
+ // Arrange
+ var key = "key";
+ var initialValue = 42f;
+ var newValue = 84f;
+
+ // Store initial value
+ BinaryPrefs.SetFloat(key, initialValue);
+
+ // Act
+ BinaryPrefs.SetFloat(key, newValue);
+
+ // Assert
+ BinaryPrefs.GetFloat(key).Should().Be(newValue);
+ }
+
+ #endregion
+
+ #region String
+
+ [Test]
+ public void SetString_ShouldStoreValueInBinaryStorage()
+ {
+ // Arrange
+ var key = "key";
+ var value = "42";
+
+ // Act
+ BinaryPrefs.SetString(key, value);
+
+ // Assert
+ BinaryPrefs.GetString(key).Should().Be(value);
+ }
+
+ [Test]
+ public void GetString_ShouldReturnDefaultValueIfKeyNotFound()
+ {
+ // Arrange
+ var key = "unknownKey";
+ var defaultValue = "10";
+
+ // Act
+ var result = BinaryPrefs.GetString(key, defaultValue);
+
+ // Assert
+ result.Should().Be(defaultValue);
+ }
+
+ [Test]
+ public void GetString_ShouldReturnValueFromPlayerPrefsIfNotInBinaryStorage()
+ {
+ // Arrange
+ var key = "key";
+ var playerPrefsValue = "100";
+
+ // Store value in PlayerPrefs only
+ PlayerPrefs.SetString(key, playerPrefsValue);
+
+ // Act
+ var result = BinaryPrefs.GetString(key);
+
+ // Assert
+ result.Should().Be(playerPrefsValue);
+
+ // Verify that the value is now stored in BinaryStorage
+ BinaryPrefs.GetString(key).Should().Be(playerPrefsValue);
+ }
+
+ [Test]
+ public void GetString_ShouldReturnDefaultValueIfKeyNotFoundInBothStorages()
+ {
+ // Arrange
+ var key = "nonExistentKey";
+ var defaultValue = "20";
+
+ // Act
+ var result = BinaryPrefs.GetString(key, defaultValue);
+
+ // Assert
+ result.Should().Be(defaultValue);
+ }
+
+ [Test]
+ public void SetString_ShouldOverrideExistingValueInBinaryStorage()
+ {
+ // Arrange
+ var key = "key";
+ var initialValue = "42";
+ var newValue = "84";
+
+ // Store initial value
+ BinaryPrefs.SetString(key, initialValue);
+
+ // Act
+ BinaryPrefs.SetString(key, newValue);
+
+ // Assert
+ BinaryPrefs.GetString(key).Should().Be(newValue);
+ }
+
+ #endregion
+
+ #region Edges
+
+ [Test]
+ public void SetInt_GetFloat_ShouldReturnCorrectInt()
+ {
+ // Arrange
+ var key = "key";
+ var value = 42;
+
+ // Act
+ PlayerPrefs.SetInt(key, value);
+ PlayerPrefs.SetFloat(key, value);
+
+ // Assert
+ BinaryPrefs.GetFloat(key).Should().Be(value);
+ }
+
+ #endregion
+ }
+}
\ No newline at end of file
diff --git a/Tests/BinaryPrefsTests.cs.meta b/Tests/BinaryPrefsTests.cs.meta
new file mode 100644
index 0000000..0f6a260
--- /dev/null
+++ b/Tests/BinaryPrefsTests.cs.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: e14b5abec5094cdc82b51f6861f43f94
+timeCreated: 1723741900
\ No newline at end of file