From 11d86d63d78df718e385bd92ae639c4bc8db20a5 Mon Sep 17 00:00:00 2001 From: Edvinas Date: Mon, 16 Oct 2023 22:22:55 +0300 Subject: [PATCH] Expose serializer, add more tests, update docs, add more async capabilities, add streaming assets loaidng, rename args --- .../com.chark.game-management/CHANGELOG.md | 12 + .../Runtime/Assets/IResourceLoader.cs | 23 +- .../Runtime/Assets/ResourceLoader.cs | 61 ++++- .../Runtime/GameManager.External.cs | 116 +++++++--- .../Runtime/GameManager.cs | 31 ++- .../Runtime/Serialization.meta | 3 + .../Serialization/DefaultSerializer.cs | 115 +++++++++ .../Serialization/DefaultSerializer.cs.meta | 3 + .../Runtime/Serialization/ISerializer.cs | 17 ++ .../Runtime/Serialization/ISerializer.cs.meta | 3 + .../Runtime/Storage/DefaultGameStorage.cs | 37 --- .../Runtime/Storage/DefaultStorage.cs | 39 ++++ ...Storage.cs.meta => DefaultStorage.cs.meta} | 2 +- .../Runtime/Storage/EditorPrefsGameStorage.cs | 35 --- .../Runtime/Storage/EditorPrefsStorage.cs | 37 +++ ...age.cs.meta => EditorPrefsStorage.cs.meta} | 2 +- .../Runtime/Storage/FileGameStorage.cs | 50 ---- .../Runtime/Storage/FileStorage.cs | 51 ++++ ...ameStorage.cs.meta => FileStorage.cs.meta} | 2 +- .../Runtime/Storage/GameStorage.cs | 219 ------------------ .../Runtime/Storage/IGameStorage.cs | 36 --- .../Runtime/Storage/IStorage.cs | 52 +++++ ...{IGameStorage.cs.meta => IStorage.cs.meta} | 2 +- .../Runtime/Storage/PlayerPrefsGameStorage.cs | 29 --- .../Runtime/Storage/PlayerPrefsStorage.cs | 30 +++ ...age.cs.meta => PlayerPrefsStorage.cs.meta} | 2 +- .../Runtime/Storage/Storage.cs | 148 ++++++++++++ .../{GameStorage.cs.meta => Storage.cs.meta} | 2 +- .../Tests/Editor/DefaultSerializerTest.cs | 119 ++++++++++ .../Editor/DefaultSerializerTest.cs.meta | 3 + ...orageTest.cs => EditorPrefsStorageTest.cs} | 9 +- ...cs.meta => EditorPrefsStorageTest.cs.meta} | 2 +- ...orageTest.cs => PlayerPrefsStorageTest.cs} | 9 +- ...cs.meta => PlayerPrefsStorageTest.cs.meta} | 2 +- .../{GameStorageTest.cs => StorageTest.cs} | 6 +- ...torageTest.cs.meta => StorageTest.cs.meta} | 2 +- 36 files changed, 831 insertions(+), 480 deletions(-) create mode 100644 Packages/com.chark.game-management/Runtime/Serialization.meta create mode 100644 Packages/com.chark.game-management/Runtime/Serialization/DefaultSerializer.cs create mode 100644 Packages/com.chark.game-management/Runtime/Serialization/DefaultSerializer.cs.meta create mode 100644 Packages/com.chark.game-management/Runtime/Serialization/ISerializer.cs create mode 100644 Packages/com.chark.game-management/Runtime/Serialization/ISerializer.cs.meta delete mode 100644 Packages/com.chark.game-management/Runtime/Storage/DefaultGameStorage.cs create mode 100644 Packages/com.chark.game-management/Runtime/Storage/DefaultStorage.cs rename Packages/com.chark.game-management/Runtime/Storage/{DefaultGameStorage.cs.meta => DefaultStorage.cs.meta} (54%) delete mode 100644 Packages/com.chark.game-management/Runtime/Storage/EditorPrefsGameStorage.cs create mode 100644 Packages/com.chark.game-management/Runtime/Storage/EditorPrefsStorage.cs rename Packages/com.chark.game-management/Runtime/Storage/{EditorPrefsGameStorage.cs.meta => EditorPrefsStorage.cs.meta} (54%) delete mode 100644 Packages/com.chark.game-management/Runtime/Storage/FileGameStorage.cs create mode 100644 Packages/com.chark.game-management/Runtime/Storage/FileStorage.cs rename Packages/com.chark.game-management/Runtime/Storage/{FileGameStorage.cs.meta => FileStorage.cs.meta} (54%) delete mode 100644 Packages/com.chark.game-management/Runtime/Storage/GameStorage.cs delete mode 100644 Packages/com.chark.game-management/Runtime/Storage/IGameStorage.cs create mode 100644 Packages/com.chark.game-management/Runtime/Storage/IStorage.cs rename Packages/com.chark.game-management/Runtime/Storage/{IGameStorage.cs.meta => IStorage.cs.meta} (54%) delete mode 100644 Packages/com.chark.game-management/Runtime/Storage/PlayerPrefsGameStorage.cs create mode 100644 Packages/com.chark.game-management/Runtime/Storage/PlayerPrefsStorage.cs rename Packages/com.chark.game-management/Runtime/Storage/{PlayerPrefsGameStorage.cs.meta => PlayerPrefsStorage.cs.meta} (54%) create mode 100644 Packages/com.chark.game-management/Runtime/Storage/Storage.cs rename Packages/com.chark.game-management/Runtime/Storage/{GameStorage.cs.meta => Storage.cs.meta} (54%) create mode 100644 Packages/com.chark.game-management/Tests/Editor/DefaultSerializerTest.cs create mode 100644 Packages/com.chark.game-management/Tests/Editor/DefaultSerializerTest.cs.meta rename Packages/com.chark.game-management/Tests/Editor/{EditorPrefsGameStorageTest.cs => EditorPrefsStorageTest.cs} (64%) rename Packages/com.chark.game-management/Tests/Editor/{EditorPrefsGameStorageTest.cs.meta => EditorPrefsStorageTest.cs.meta} (54%) rename Packages/com.chark.game-management/Tests/Editor/{PlayerPrefsGameStorageTest.cs => PlayerPrefsStorageTest.cs} (64%) rename Packages/com.chark.game-management/Tests/Editor/{PlayerPrefsGameStorageTest.cs.meta => PlayerPrefsStorageTest.cs.meta} (54%) rename Packages/com.chark.game-management/Tests/Editor/{GameStorageTest.cs => StorageTest.cs} (97%) rename Packages/com.chark.game-management/Tests/Editor/{GameStorageTest.cs.meta => StorageTest.cs.meta} (54%) diff --git a/Packages/com.chark.game-management/CHANGELOG.md b/Packages/com.chark.game-management/CHANGELOG.md index 1aacae3..8a8f071 100644 --- a/Packages/com.chark.game-management/CHANGELOG.md +++ b/Packages/com.chark.game-management/CHANGELOG.md @@ -7,6 +7,18 @@ adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [v0.0.3](https://github.com/chark/game-management/compare/v0.0.2...v0.0.3) - 2023-XX-XX +### Added + +- `ISerializer` with `GameManager.TryDeserializeValue` and `GameManager.TrySerializeValue` methods, this can be used to serialize and deserialize data using internal `GameManager` serialization utilities. +- `GameManager.DeleteRuntimeValueAsync` which can be used to delete data asynchronously. +- `GameManager.GetResourceAsync` which can be used to retrieve resources from StreamingAssets directory. + +### Changed + +- Renamed `IResourceLoader` methods to use `Get*` prefix instead of `Load*` so its more consistent with other methods. +- Renamed `IGameStorage` to `IStorage`. +- Cancellation tokens can now be used in async methods. + ### Fixed - `GameStorage.GetValueAsync` not switching back to main thread when no value is found. diff --git a/Packages/com.chark.game-management/Runtime/Assets/IResourceLoader.cs b/Packages/com.chark.game-management/Runtime/Assets/IResourceLoader.cs index f89aa34..7e74274 100644 --- a/Packages/com.chark.game-management/Runtime/Assets/IResourceLoader.cs +++ b/Packages/com.chark.game-management/Runtime/Assets/IResourceLoader.cs @@ -1,4 +1,6 @@ using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; using UnityEngine; namespace CHARK.GameManagement.Assets @@ -6,13 +8,26 @@ namespace CHARK.GameManagement.Assets public interface IResourceLoader { /// - /// Resources loaded from given . + /// Enumerable of resources retrieved from given . /// - public IEnumerable LoadResources(string path = null) where TResource : Object; + public IEnumerable GetResources(string path = null) + where TResource : Object; /// - /// Resource loaded from given . + /// true if is retrieved from given + /// or false otherwise. /// - public TResource LoadResource(string path) where TResource : Object; + public bool TryGetResource(string path, out TResource resource) + where TResource : Object; + + /// + /// Asset loaded asynchronously from given . + ///

+ /// Note, is relative to StreamingAssets directory. + /// + public Task GetResourceAsync( + string path, + CancellationToken cancellationToken = default + ); } } diff --git a/Packages/com.chark.game-management/Runtime/Assets/ResourceLoader.cs b/Packages/com.chark.game-management/Runtime/Assets/ResourceLoader.cs index 10b8d2c..c099220 100644 --- a/Packages/com.chark.game-management/Runtime/Assets/ResourceLoader.cs +++ b/Packages/com.chark.game-management/Runtime/Assets/ResourceLoader.cs @@ -1,5 +1,8 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; +using System.IO; +using System.Threading; +using System.Threading.Tasks; +using CHARK.GameManagement.Serialization; using UnityEngine; using Object = UnityEngine.Object; @@ -7,7 +10,14 @@ namespace CHARK.GameManagement.Assets { internal sealed class ResourceLoader : IResourceLoader { - public IEnumerable LoadResources(string path = null) where TResource : Object + private readonly ISerializer serializer; + + public ResourceLoader(ISerializer serializer) + { + this.serializer = serializer; + } + + public IEnumerable GetResources(string path = null) where TResource : Object { if (string.IsNullOrWhiteSpace(path)) { @@ -17,20 +27,53 @@ public IEnumerable LoadResources(string path = null) where return Resources.LoadAll(path); } - public TResource LoadResource(string path) where TResource : Object + public bool TryGetResource(string path, out TResource resource) where TResource : Object { if (string.IsNullOrWhiteSpace(path)) { - throw new ArgumentException($"{nameof(path)} must not be empty or null"); + resource = default; + return false; + } + + var loadedResource = Resources.Load(path); + if (loadedResource) + { + resource = loadedResource; + return true; } - var resource = Resources.Load(path); - if (resource) + resource = default; + return false; + } + + public async Task GetResourceAsync( + string path, + CancellationToken cancellationToken + ) + { + var actualPath = Path.Combine(Application.streamingAssetsPath, path); + +#if UNITY_ANDROID + var request = UnityEngine.Networking.UnityWebRequest.Get(actualPath); + var operation = request.SendWebRequest(); + + await Cysharp.Threading.Tasks.UnityAsyncExtensions.ToUniTask( + operation, + cancellationToken: cancellationToken + ); + + var handler = request.downloadHandler; + var content = handler.text; +#else + var content = await File.ReadAllTextAsync(actualPath, cancellationToken); +#endif + + if (serializer.TryDeserializeValue(content, out var value)) { - return resource; + return value; } - throw new Exception($"Resource at path \"{path}\" could not be loaded"); + return default; } } } diff --git a/Packages/com.chark.game-management/Runtime/GameManager.External.cs b/Packages/com.chark.game-management/Runtime/GameManager.External.cs index 6e78c0e..b4af54f 100644 --- a/Packages/com.chark.game-management/Runtime/GameManager.External.cs +++ b/Packages/com.chark.game-management/Runtime/GameManager.External.cs @@ -10,114 +10,138 @@ namespace CHARK.GameManagement public abstract partial class GameManager { /// - /// Resources of type loaded via at + /// Resources of type from at /// given . /// - public static IEnumerable LoadResources(string path = null) where TResource : Object + public static IEnumerable GetResources(string path = null) where TResource : Object { var gameManager = GetGameManager(); var resourceLoader = gameManager.resourceLoader; - return resourceLoader.LoadResources(path); + return resourceLoader.GetResources(path); } /// - /// Resource of type loaded via at - /// given . If resource can't be loaded an - /// is thrown. + /// true if resource of type is retrieved from + /// at given or false otherwise. /// - public static TResource LoadResource(string path) where TResource : Object + public static bool TryGetResource(string path, out TResource resource) where TResource : Object { var gameManager = GetGameManager(); var resourceLoader = gameManager.resourceLoader; - return resourceLoader.LoadResource(path); + return resourceLoader.TryGetResource(path, out resource); } /// - /// Value retrieved from at given + /// Task containing a resource of type retrieved from + /// at given or default if + /// value could not be retrieved. + /// + public static Task GetResourceAsync(string path) + { + var gameManager = GetGameManager(); + var resourceLoader = gameManager.resourceLoader; + + return resourceLoader.GetResourceAsync(path); + } + + /// + /// Value retrieved from at given /// asynchronously or default if no value is could be retrieved. /// - public static Task GetRuntimeValueAsync(string key) + public static Task GetRuntimeValueAsync(string path) { var gameManager = GetGameManager(); var runtimeStorage = gameManager.runtimeStorage; - return runtimeStorage.GetValueAsync(key); + return runtimeStorage.GetValueAsync(path); } /// - /// true if is retrieved by given + /// true if is retrieved by given /// from . /// - public static bool TryGetRuntimeValue(string key, out TValue value) + public static bool TryGetRuntimeValue(string path, out TValue value) { var gameManager = GetGameManager(); var runtimeStorage = gameManager.runtimeStorage; - return runtimeStorage.TryGetValue(key, out value); + return runtimeStorage.TryGetValue(path, out value); } ///

- /// Persist a by given asynchronously to + /// Persist a by given asynchronously to /// . /// - public static Task SetRuntimeValueAsync(string key, TValue value) + public static Task SetRuntimeValueAsync(string path, TValue value) { var gameManager = GetGameManager(); var runtimeStorage = gameManager.runtimeStorage; - return runtimeStorage.SetValueAsync(key, value); + return runtimeStorage.SetValueAsync(path, value); } /// - /// Persist a by given to + /// Persist a by given to /// . /// - public static void SetRuntimeValue(string key, TValue value) + public static void SetRuntimeValue(string path, TValue value) { var gameManager = GetGameManager(); var runtimeStorage = gameManager.runtimeStorage; - runtimeStorage.SetValue(key, value); + runtimeStorage.SetValue(path, value); } - // TODO: add async variant! /// - /// Delete persisted value at given . + /// Delete persisted value at given + /// asynchronously from . /// - public static void DeleteRuntimeValue(string key) + public static Task DeleteRuntimeValueAsync(string path) { var gameManager = GetGameManager(); var runtimeStorage = gameManager.runtimeStorage; - runtimeStorage.DeleteValue(key); + return runtimeStorage.DeleteValueAsync(path); + } + + /// + /// Delete persisted value at given + /// from . + /// + public static void DeleteRuntimeValue(string path) + { + var gameManager = GetGameManager(); + var runtimeStorage = gameManager.runtimeStorage; + + runtimeStorage.DeleteValue(path); } /// - /// true if is retrieved by given + /// true if is retrieved by given /// from . /// - public static bool TryGetEditorValue(string key, out TValue value) + public static bool TryGetEditorValue(string path, out TValue value) { - return EditorStorage.TryGetValue(key, out value); + return EditorStorage.TryGetValue(path, out value); } /// - /// Persist a by given to + /// Persist a by given to /// . /// - public static void SetEditorValue(string key, TValue value) + public static void SetEditorValue(string path, TValue value) { - EditorStorage.SetValue(key, value); + EditorStorage.SetValue(path, value); } /// - /// Delete persisted value at given . + /// Delete persisted value at given . /// - public static void DeleteEditorValue(string key) + public static void DeleteEditorValue(string path) { - EditorStorage.DeleteValue(key); + EditorStorage.DeleteValue(path); } /// @@ -189,5 +213,31 @@ public static void RemoveListener(Action listener) messageBus.RemoveListener(listener); } + + /// + /// true if is deserialized to + /// using successfully or + /// false otherwise. + /// + public static bool TryDeserializeValue(string serializedValue, out TValue deserializedValue) + { + var gameManager = GetGameManager(); + var serializer = gameManager.serializer; + + return serializer.TryDeserializeValue(serializedValue, out deserializedValue); + } + + /// + /// true if is serialized to + /// using successfully or + /// false otherwise. + /// + public static bool TrySerializeValue(TValue deserializedValue, out string serializedValue) + { + var gameManager = GetGameManager(); + var serializer = gameManager.serializer; + + return serializer.TrySerializeValue(deserializedValue, out serializedValue); + } } } diff --git a/Packages/com.chark.game-management/Runtime/GameManager.cs b/Packages/com.chark.game-management/Runtime/GameManager.cs index 63011b1..b8c85eb 100644 --- a/Packages/com.chark.game-management/Runtime/GameManager.cs +++ b/Packages/com.chark.game-management/Runtime/GameManager.cs @@ -2,6 +2,7 @@ using CHARK.GameManagement.Assets; using CHARK.GameManagement.Entities; using CHARK.GameManagement.Messaging; +using CHARK.GameManagement.Serialization; using CHARK.GameManagement.Settings; using CHARK.GameManagement.Storage; using CHARK.GameManagement.Systems; @@ -15,9 +16,9 @@ public abstract partial class GameManager : MonoBehaviour { private static GameManager currentGameManager; - private static readonly IGameStorage EditorStorage = + private static readonly IStorage EditorStorage = #if UNITY_EDITOR - new EditorPrefsGameStorage($"{nameof(GameManager)}."); + new EditorPrefsStorage(DefaultSerializer.Instance, $"{nameof(GameManager)}."); #else DefaultGameStorage.Instance; #endif @@ -26,7 +27,8 @@ public abstract partial class GameManager : MonoBehaviour private bool isSystemsInitialized; - private IGameStorage runtimeStorage; + private ISerializer serializer; + private IStorage runtimeStorage; private IResourceLoader resourceLoader; private IEntityManager entityManager; private IMessageBus messageBus; @@ -144,12 +146,24 @@ protected void RemoveSystem(ISystem system) } /// - /// New instance. + /// New instance. /// - protected virtual IGameStorage CreateRuntimeGameStorage() + protected virtual ISerializer CreateSerializer() + { + return DefaultSerializer.Instance; + } + + /// + /// New instance. + /// + protected virtual IStorage CreateRuntimeStorage() { var keyPrefix = $"{GetGameManagerName()}."; - return new FileGameStorage(keyPrefix, Application.persistentDataPath); + return new FileStorage( + serializer: serializer, + persistentDataPath: Application.persistentDataPath, + pathPrefix: keyPrefix + ); } /// @@ -157,7 +171,7 @@ protected virtual IGameStorage CreateRuntimeGameStorage() /// protected virtual IResourceLoader CreateResourceLoader() { - return new ResourceLoader(); + return new ResourceLoader(serializer); } /// @@ -189,7 +203,8 @@ private void InitializeGameManager() private void InitializeCore() { name = GetGameManagerName(); - runtimeStorage = CreateRuntimeGameStorage(); + serializer = CreateSerializer(); + runtimeStorage = CreateRuntimeStorage(); resourceLoader = CreateResourceLoader(); entityManager = CreateEntityManager(); messageBus = CreateMessageBus(); diff --git a/Packages/com.chark.game-management/Runtime/Serialization.meta b/Packages/com.chark.game-management/Runtime/Serialization.meta new file mode 100644 index 0000000..47ccbff --- /dev/null +++ b/Packages/com.chark.game-management/Runtime/Serialization.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 293eddc0b735441490b10f43b47b7669 +timeCreated: 1697453804 \ No newline at end of file diff --git a/Packages/com.chark.game-management/Runtime/Serialization/DefaultSerializer.cs b/Packages/com.chark.game-management/Runtime/Serialization/DefaultSerializer.cs new file mode 100644 index 0000000..c502ed4 --- /dev/null +++ b/Packages/com.chark.game-management/Runtime/Serialization/DefaultSerializer.cs @@ -0,0 +1,115 @@ +using System; +using System.ComponentModel; +using Newtonsoft.Json; +using Newtonsoft.Json.Serialization; +using UnityEngine; + +namespace CHARK.GameManagement.Serialization +{ + internal class DefaultSerializer : ISerializer + { + internal static DefaultSerializer Instance { get; } = new(); + + private readonly JsonSerializerSettings serializerSettings; + + private DefaultSerializer() + { + serializerSettings = CreateDefaultSerializerSettings(); + } + + public bool TryDeserializeValue(string serializedValue, out TValue deserializedValue) + { + if (TryDeserializeConverterValue(serializedValue, out TValue converterValue)) + { + deserializedValue = converterValue; + return true; + } + + deserializedValue = default; + + try + { + var jsonValue = JsonConvert.DeserializeObject(serializedValue); + if (jsonValue == null) + { + return false; + } + + deserializedValue = jsonValue; + return true; + } + catch (Exception exception) + { + Debug.LogException(exception); + return false; + } + } + + public bool TrySerializeValue(TValue deserializedValue, out string serializedJson) + { + serializedJson = default; + + var valueType = typeof(TValue); + if (valueType.IsPrimitive || valueType == typeof(string)) + { + var valueString = deserializedValue.ToString(); + serializedJson = valueString; + return true; + } + + try + { + var valueJson = JsonConvert.SerializeObject(deserializedValue, serializerSettings); + if (string.IsNullOrWhiteSpace(valueJson)) + { + return false; + } + + serializedJson = valueJson; + return true; + } + catch (Exception exception) + { + Debug.LogException(exception); + throw; + } + } + + private static bool TryDeserializeConverterValue(string json, out TValue deserializedValue) + { + deserializedValue = default; + + var valueType = typeof(TValue); + if (valueType.IsPrimitive == false && valueType != typeof(string)) + { + return false; + } + + try + { + var converter = TypeDescriptor.GetConverter(valueType); + var converterValue = (TValue)converter.ConvertFrom(json); + if (converterValue == null) + { + return false; + } + + deserializedValue = converterValue; + return true; + } + catch (Exception exception) + { + Debug.LogException(exception); + return false; + } + } + + private static JsonSerializerSettings CreateDefaultSerializerSettings() + { + return new JsonSerializerSettings + { + ContractResolver = new CamelCasePropertyNamesContractResolver(), + }; + } + } +} diff --git a/Packages/com.chark.game-management/Runtime/Serialization/DefaultSerializer.cs.meta b/Packages/com.chark.game-management/Runtime/Serialization/DefaultSerializer.cs.meta new file mode 100644 index 0000000..2b89c88 --- /dev/null +++ b/Packages/com.chark.game-management/Runtime/Serialization/DefaultSerializer.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: e1c75eb72bcb49c4a401a96fa63207b2 +timeCreated: 1697453883 \ No newline at end of file diff --git a/Packages/com.chark.game-management/Runtime/Serialization/ISerializer.cs b/Packages/com.chark.game-management/Runtime/Serialization/ISerializer.cs new file mode 100644 index 0000000..6a9c811 --- /dev/null +++ b/Packages/com.chark.game-management/Runtime/Serialization/ISerializer.cs @@ -0,0 +1,17 @@ +namespace CHARK.GameManagement.Serialization +{ + public interface ISerializer + { + /// + /// true if is retrieved from + /// or false otherwise. + /// + public bool TryDeserializeValue(string serializedValue, out TValue deserializedValue); + + /// + /// true if is retrieved from + /// or false otherwise. + /// + public bool TrySerializeValue(TValue deserializedValue, out string serializedValue); + } +} diff --git a/Packages/com.chark.game-management/Runtime/Serialization/ISerializer.cs.meta b/Packages/com.chark.game-management/Runtime/Serialization/ISerializer.cs.meta new file mode 100644 index 0000000..ae11d13 --- /dev/null +++ b/Packages/com.chark.game-management/Runtime/Serialization/ISerializer.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 3a26923754bd4b72bf58a94c8b65ffd7 +timeCreated: 1697453811 \ No newline at end of file diff --git a/Packages/com.chark.game-management/Runtime/Storage/DefaultGameStorage.cs b/Packages/com.chark.game-management/Runtime/Storage/DefaultGameStorage.cs deleted file mode 100644 index 3efbb52..0000000 --- a/Packages/com.chark.game-management/Runtime/Storage/DefaultGameStorage.cs +++ /dev/null @@ -1,37 +0,0 @@ -namespace CHARK.GameManagement.Storage -{ - /// - /// Game storage which does nothing (placeholder). - /// - internal sealed class DefaultGameStorage : GameStorage - { - public static DefaultGameStorage Instance { get; } = new DefaultGameStorage(); - - private DefaultGameStorage() : base(default) - { - } - - public override bool TryGetValue(string key, out TValue value) - { - value = default; - return false; - } - - public override void SetValue(string key, TValue value) - { - } - - protected override string GetString(string key) - { - return default; - } - - protected override void SetString(string key, string value) - { - } - - protected override void DeleteKey(string key) - { - } - } -} diff --git a/Packages/com.chark.game-management/Runtime/Storage/DefaultStorage.cs b/Packages/com.chark.game-management/Runtime/Storage/DefaultStorage.cs new file mode 100644 index 0000000..2d312d6 --- /dev/null +++ b/Packages/com.chark.game-management/Runtime/Storage/DefaultStorage.cs @@ -0,0 +1,39 @@ +using CHARK.GameManagement.Serialization; + +namespace CHARK.GameManagement.Storage +{ + /// + /// Game storage which does nothing (placeholder). + /// + internal sealed class DefaultStorage : Storage + { + public static DefaultStorage Instance { get; } = new(); + + private DefaultStorage() : base(DefaultSerializer.Instance, default) + { + } + + public override bool TryGetValue(string path, out TValue value) + { + value = default; + return false; + } + + public override void SetValue(string path, TValue value) + { + } + + protected override string GetString(string path) + { + return default; + } + + protected override void SetString(string path, string value) + { + } + + protected override void Delete(string path) + { + } + } +} diff --git a/Packages/com.chark.game-management/Runtime/Storage/DefaultGameStorage.cs.meta b/Packages/com.chark.game-management/Runtime/Storage/DefaultStorage.cs.meta similarity index 54% rename from Packages/com.chark.game-management/Runtime/Storage/DefaultGameStorage.cs.meta rename to Packages/com.chark.game-management/Runtime/Storage/DefaultStorage.cs.meta index e11b18d..2e763e5 100644 --- a/Packages/com.chark.game-management/Runtime/Storage/DefaultGameStorage.cs.meta +++ b/Packages/com.chark.game-management/Runtime/Storage/DefaultStorage.cs.meta @@ -1,3 +1,3 @@ fileFormatVersion: 2 -guid: 31ce34677dfc433fa18370eef1d451c2 +guid: ce724dba3e44b704380f4b972c5d202d timeCreated: 1669928210 \ No newline at end of file diff --git a/Packages/com.chark.game-management/Runtime/Storage/EditorPrefsGameStorage.cs b/Packages/com.chark.game-management/Runtime/Storage/EditorPrefsGameStorage.cs deleted file mode 100644 index 6f843d7..0000000 --- a/Packages/com.chark.game-management/Runtime/Storage/EditorPrefsGameStorage.cs +++ /dev/null @@ -1,35 +0,0 @@ -namespace CHARK.GameManagement.Storage -{ - /// - /// Game storage which stores values in . - /// - internal sealed class EditorPrefsGameStorage : GameStorage - { - public EditorPrefsGameStorage(string keyPrefix = "") : base(keyPrefix) - { - } - - protected override string GetString(string key) - { -#if UNITY_EDITOR - return UnityEditor.EditorPrefs.GetString(key); -#else - return default; -#endif - } - - protected override void SetString(string key, string value) - { -#if UNITY_EDITOR - UnityEditor.EditorPrefs.SetString(key, value); -#endif - } - - protected override void DeleteKey(string key) - { -#if UNITY_EDITOR - UnityEditor.EditorPrefs.DeleteKey(key); -#endif - } - } -} diff --git a/Packages/com.chark.game-management/Runtime/Storage/EditorPrefsStorage.cs b/Packages/com.chark.game-management/Runtime/Storage/EditorPrefsStorage.cs new file mode 100644 index 0000000..4a8b003 --- /dev/null +++ b/Packages/com.chark.game-management/Runtime/Storage/EditorPrefsStorage.cs @@ -0,0 +1,37 @@ +using CHARK.GameManagement.Serialization; + +namespace CHARK.GameManagement.Storage +{ + /// + /// Game storage which stores values in . + /// + internal sealed class EditorPrefsStorage : Storage + { + public EditorPrefsStorage(ISerializer serializer, string keyPrefix = "") : base(serializer, keyPrefix) + { + } + + protected override string GetString(string path) + { +#if UNITY_EDITOR + return UnityEditor.EditorPrefs.GetString(path); +#else + return default; +#endif + } + + protected override void SetString(string path, string value) + { +#if UNITY_EDITOR + UnityEditor.EditorPrefs.SetString(path, value); +#endif + } + + protected override void Delete(string path) + { +#if UNITY_EDITOR + UnityEditor.EditorPrefs.DeleteKey(path); +#endif + } + } +} diff --git a/Packages/com.chark.game-management/Runtime/Storage/EditorPrefsGameStorage.cs.meta b/Packages/com.chark.game-management/Runtime/Storage/EditorPrefsStorage.cs.meta similarity index 54% rename from Packages/com.chark.game-management/Runtime/Storage/EditorPrefsGameStorage.cs.meta rename to Packages/com.chark.game-management/Runtime/Storage/EditorPrefsStorage.cs.meta index e09cda0..ee940dd 100644 --- a/Packages/com.chark.game-management/Runtime/Storage/EditorPrefsGameStorage.cs.meta +++ b/Packages/com.chark.game-management/Runtime/Storage/EditorPrefsStorage.cs.meta @@ -1,3 +1,3 @@ fileFormatVersion: 2 -guid: 3df6529c17164ab68ceb29ac9dfb116a +guid: 3795b11e96151c5438282149a64c9e21 timeCreated: 1669925611 \ No newline at end of file diff --git a/Packages/com.chark.game-management/Runtime/Storage/FileGameStorage.cs b/Packages/com.chark.game-management/Runtime/Storage/FileGameStorage.cs deleted file mode 100644 index db238fd..0000000 --- a/Packages/com.chark.game-management/Runtime/Storage/FileGameStorage.cs +++ /dev/null @@ -1,50 +0,0 @@ -using System.IO; - -namespace CHARK.GameManagement.Storage -{ - internal sealed class FileGameStorage : GameStorage - { - private readonly string persistentDataPath; - - public FileGameStorage(string persistentDataPath, string keyPrefix = "") : base(keyPrefix) - { - this.persistentDataPath = persistentDataPath; - } - - protected override string GetString(string key) - { - var path = GetFilePath(key); - if (File.Exists(path) == false) - { - return default; - } - - return File.ReadAllText(path); - } - - protected override void SetString(string key, string value) - { - var path = GetFilePath(key); - File.WriteAllText(path, value); - } - - protected override void DeleteKey(string key) - { - var path = GetFilePath(key); - if (File.Exists(path) == false) - { - return; - } - - File.Delete(path); - } - - private string GetFilePath(string key) - { - var fileName = $"{key}.json"; - var path = Path.Combine(persistentDataPath, fileName); - - return path; - } - } -} diff --git a/Packages/com.chark.game-management/Runtime/Storage/FileStorage.cs b/Packages/com.chark.game-management/Runtime/Storage/FileStorage.cs new file mode 100644 index 0000000..7474b3a --- /dev/null +++ b/Packages/com.chark.game-management/Runtime/Storage/FileStorage.cs @@ -0,0 +1,51 @@ +using System.IO; +using CHARK.GameManagement.Serialization; + +namespace CHARK.GameManagement.Storage +{ + internal sealed class FileStorage : Storage + { + private readonly string persistentDataPath; + + public FileStorage(ISerializer serializer, string persistentDataPath, string pathPrefix = "") : base(serializer, pathPrefix) + { + this.persistentDataPath = persistentDataPath; + } + + protected override string GetString(string path) + { + var actualPath = GetFilePath(path); + if (File.Exists(actualPath) == false) + { + return default; + } + + return File.ReadAllText(actualPath); + } + + protected override void SetString(string path, string value) + { + var actualPath = GetFilePath(path); + File.WriteAllText(actualPath, value); + } + + protected override void Delete(string path) + { + var actualPath = GetFilePath(path); + if (File.Exists(actualPath) == false) + { + return; + } + + File.Delete(actualPath); + } + + private string GetFilePath(string path) + { + var fileName = $"{path}.json"; + var actualPath = Path.Combine(persistentDataPath, fileName); + + return actualPath; + } + } +} diff --git a/Packages/com.chark.game-management/Runtime/Storage/FileGameStorage.cs.meta b/Packages/com.chark.game-management/Runtime/Storage/FileStorage.cs.meta similarity index 54% rename from Packages/com.chark.game-management/Runtime/Storage/FileGameStorage.cs.meta rename to Packages/com.chark.game-management/Runtime/Storage/FileStorage.cs.meta index 59920a6..f2d41e0 100644 --- a/Packages/com.chark.game-management/Runtime/Storage/FileGameStorage.cs.meta +++ b/Packages/com.chark.game-management/Runtime/Storage/FileStorage.cs.meta @@ -1,3 +1,3 @@ fileFormatVersion: 2 -guid: adee4469de0f4d7cb145558833da4d23 +guid: 153e72cf9cea8144e8bffc11797d7e46 timeCreated: 1670271717 \ No newline at end of file diff --git a/Packages/com.chark.game-management/Runtime/Storage/GameStorage.cs b/Packages/com.chark.game-management/Runtime/Storage/GameStorage.cs deleted file mode 100644 index e6e9dda..0000000 --- a/Packages/com.chark.game-management/Runtime/Storage/GameStorage.cs +++ /dev/null @@ -1,219 +0,0 @@ -using System; -using System.ComponentModel; -using System.Threading.Tasks; -using Cysharp.Threading.Tasks; -using Newtonsoft.Json; -using Newtonsoft.Json.Serialization; -using UnityEngine; - -namespace CHARK.GameManagement.Storage -{ - internal abstract class GameStorage : IGameStorage - { - private readonly JsonSerializerSettings jsonSerializerSettings; - private readonly string keyPrefix; - - protected GameStorage(string keyPrefix) : this(keyPrefix, CreateDefaultSerializerSettings()) - { - } - - protected GameStorage(string keyPrefix, JsonSerializerSettings jsonSerializerSettings) - { - this.keyPrefix = keyPrefix; - this.jsonSerializerSettings = jsonSerializerSettings; - } - - public async Task GetValueAsync(string key) - { - await UniTask.SwitchToThreadPool(); - - if (TryGetValue(key, out var value)) - { - await UniTask.SwitchToMainThread(); - - return value; - } - - await UniTask.SwitchToMainThread(); - - return default; - } - - public virtual bool TryGetValue(string key, out TValue value) - { - value = default; - - if (TryGetFormattedKey(key, out var formattedKey) == false) - { - return false; - } - - var stringValue = GetString(formattedKey); - if (string.IsNullOrWhiteSpace(stringValue)) - { - return false; - } - - if (TryDeserializeConverterValue(stringValue, out TValue converterValue)) - { - value = converterValue; - return true; - } - - if (TryDeserializeJsonValue(stringValue, out TValue jsonValue)) - { - value = jsonValue; - return true; - } - - return true; - } - - public async Task SetValueAsync(string key, TValue value) - { - await UniTask.SwitchToThreadPool(); - SetValue(key, value); - await UniTask.SwitchToMainThread(); - } - - public virtual void SetValue(string key, TValue value) - { - if (TryGetFormattedKey(key, out var formattedKey) == false) - { - return; - } - - if (TrySerializeValue(value, out var stringValue) == false) - { - return; - } - - SetString(formattedKey, stringValue); - } - - public void DeleteValue(string key) - { - if (TryGetFormattedKey(key, out var formattedKey)) - { - DeleteKey(formattedKey); - } - } - - /// - /// String retrieved using given . - /// - protected abstract string GetString(string key); - - /// - /// Store a at given . - /// - protected abstract void SetString(string key, string value); - - /// - /// Delete value at given . - /// - protected abstract void DeleteKey(string key); - - private bool TryGetFormattedKey(string key, out string formattedKey) - { - formattedKey = default; - - if (string.IsNullOrWhiteSpace(key)) - { - return false; - } - - formattedKey = keyPrefix + key; - return true; - } - - private static bool TryDeserializeConverterValue(string json, out TValue deserializedValue) - { - deserializedValue = default; - - var valueType = typeof(TValue); - if (valueType.IsPrimitive == false && valueType != typeof(string)) - { - return false; - } - - try - { - var converter = TypeDescriptor.GetConverter(valueType); - var converterValue = (TValue)converter.ConvertFrom(json); - if (converterValue == null) - { - return false; - } - - deserializedValue = converterValue; - return true; - } - catch (Exception exception) - { - Debug.LogException(exception); - return false; - } - } - - private bool TryDeserializeJsonValue(string json, out TValue deserializedValue) - { - deserializedValue = default; - - try - { - var jsonValue = JsonConvert.DeserializeObject(json, jsonSerializerSettings); - if (jsonValue == null) - { - return false; - } - - deserializedValue = jsonValue; - return true; - } - catch (Exception exception) - { - Debug.LogException(exception); - return false; - } - } - - private bool TrySerializeValue(TValue value, out string serializedJson) - { - serializedJson = default; - - var valueType = typeof(TValue); - if (valueType.IsPrimitive || valueType == typeof(string)) - { - var valueString = value.ToString(); - serializedJson = valueString; - return true; - } - - try - { - var valueJson = JsonConvert.SerializeObject(value, jsonSerializerSettings); - if (string.IsNullOrWhiteSpace(valueJson)) - { - return false; - } - - serializedJson = valueJson; - return true; - } - catch (Exception exception) - { - Debug.LogException(exception); - throw; - } - } - - private static JsonSerializerSettings CreateDefaultSerializerSettings() - { - return new JsonSerializerSettings - { - ContractResolver = new CamelCasePropertyNamesContractResolver() - }; - } - } -} diff --git a/Packages/com.chark.game-management/Runtime/Storage/IGameStorage.cs b/Packages/com.chark.game-management/Runtime/Storage/IGameStorage.cs deleted file mode 100644 index 5880daf..0000000 --- a/Packages/com.chark.game-management/Runtime/Storage/IGameStorage.cs +++ /dev/null @@ -1,36 +0,0 @@ -using System.Threading.Tasks; - -namespace CHARK.GameManagement.Storage -{ - /// - /// Persistent storage/config repository. - /// - public interface IGameStorage - { - /// - /// Value from persistent game storage asynchronously or default if no value is - /// could be retrieved. - /// - public Task GetValueAsync(string key); - - /// - /// Get a value from persistent game storage. - /// - public bool TryGetValue(string key, out TValue value); - - /// - /// Save a value to persistent game storage asynchronously. - /// - public Task SetValueAsync(string key, TValue value); - - /// - /// Save a value to persistent game storage. - /// - public void SetValue(string key, TValue value); - - /// - /// Delete value at given key. - /// - public void DeleteValue(string key); - } -} diff --git a/Packages/com.chark.game-management/Runtime/Storage/IStorage.cs b/Packages/com.chark.game-management/Runtime/Storage/IStorage.cs new file mode 100644 index 0000000..06b9778 --- /dev/null +++ b/Packages/com.chark.game-management/Runtime/Storage/IStorage.cs @@ -0,0 +1,52 @@ +using System.Threading; +using System.Threading.Tasks; + +namespace CHARK.GameManagement.Storage +{ + /// + /// Persistent storage/config repository. + /// + public interface IStorage + { + /// + /// Value from persistent game storage asynchronously or default if no value is + /// could be retrieved. + /// + public Task GetValueAsync( + string path, + CancellationToken cancellationToken = default + ); + + /// + /// Get a value from persistent game storage. + /// + public bool TryGetValue(string path, out TValue value); + + /// + /// Save a value to persistent game storage asynchronously. + /// + public Task SetValueAsync( + string path, + TValue value, + CancellationToken cancellationToken = default + ); + + /// + /// Save a value to persistent game storage. + /// + public void SetValue(string path, TValue value); + + /// + /// Delete value at given asynchronously. + /// + public Task DeleteValueAsync( + string path, + CancellationToken cancellationToken = default + ); + + /// + /// Delete value at given . + /// + public void DeleteValue(string path); + } +} diff --git a/Packages/com.chark.game-management/Runtime/Storage/IGameStorage.cs.meta b/Packages/com.chark.game-management/Runtime/Storage/IStorage.cs.meta similarity index 54% rename from Packages/com.chark.game-management/Runtime/Storage/IGameStorage.cs.meta rename to Packages/com.chark.game-management/Runtime/Storage/IStorage.cs.meta index 55c341e..f197056 100644 --- a/Packages/com.chark.game-management/Runtime/Storage/IGameStorage.cs.meta +++ b/Packages/com.chark.game-management/Runtime/Storage/IStorage.cs.meta @@ -1,3 +1,3 @@ fileFormatVersion: 2 -guid: 375fb5d7cc45456e81be7de326b35c08 +guid: 63cf4c2156065ce498a83c99e0e73f55 timeCreated: 1669919582 \ No newline at end of file diff --git a/Packages/com.chark.game-management/Runtime/Storage/PlayerPrefsGameStorage.cs b/Packages/com.chark.game-management/Runtime/Storage/PlayerPrefsGameStorage.cs deleted file mode 100644 index 1dd1d8b..0000000 --- a/Packages/com.chark.game-management/Runtime/Storage/PlayerPrefsGameStorage.cs +++ /dev/null @@ -1,29 +0,0 @@ -using UnityEngine; - -namespace CHARK.GameManagement.Storage -{ - /// - /// Game storage which stores values in . - /// - internal sealed class PlayerPrefsGameStorage : GameStorage - { - public PlayerPrefsGameStorage(string keyPrefix = "") : base(keyPrefix) - { - } - - protected override string GetString(string key) - { - return PlayerPrefs.GetString(key); - } - - protected override void SetString(string key, string value) - { - PlayerPrefs.SetString(key, value); - } - - protected override void DeleteKey(string key) - { - PlayerPrefs.DeleteKey(key); - } - } -} diff --git a/Packages/com.chark.game-management/Runtime/Storage/PlayerPrefsStorage.cs b/Packages/com.chark.game-management/Runtime/Storage/PlayerPrefsStorage.cs new file mode 100644 index 0000000..376516b --- /dev/null +++ b/Packages/com.chark.game-management/Runtime/Storage/PlayerPrefsStorage.cs @@ -0,0 +1,30 @@ +using CHARK.GameManagement.Serialization; +using UnityEngine; + +namespace CHARK.GameManagement.Storage +{ + /// + /// Game storage which stores values in . + /// + internal sealed class PlayerPrefsStorage : Storage + { + public PlayerPrefsStorage(ISerializer serializer, string pathPrefix = "") : base(serializer, pathPrefix) + { + } + + protected override string GetString(string path) + { + return PlayerPrefs.GetString(path); + } + + protected override void SetString(string path, string value) + { + PlayerPrefs.SetString(path, value); + } + + protected override void Delete(string path) + { + PlayerPrefs.DeleteKey(path); + } + } +} diff --git a/Packages/com.chark.game-management/Runtime/Storage/PlayerPrefsGameStorage.cs.meta b/Packages/com.chark.game-management/Runtime/Storage/PlayerPrefsStorage.cs.meta similarity index 54% rename from Packages/com.chark.game-management/Runtime/Storage/PlayerPrefsGameStorage.cs.meta rename to Packages/com.chark.game-management/Runtime/Storage/PlayerPrefsStorage.cs.meta index 709d90f..18941be 100644 --- a/Packages/com.chark.game-management/Runtime/Storage/PlayerPrefsGameStorage.cs.meta +++ b/Packages/com.chark.game-management/Runtime/Storage/PlayerPrefsStorage.cs.meta @@ -1,3 +1,3 @@ fileFormatVersion: 2 -guid: 3bd652a013914f44959f0d3180367bd2 +guid: ca7aedef44f0f4245aaa77fc97f64c43 timeCreated: 1669925549 \ No newline at end of file diff --git a/Packages/com.chark.game-management/Runtime/Storage/Storage.cs b/Packages/com.chark.game-management/Runtime/Storage/Storage.cs new file mode 100644 index 0000000..b7c3627 --- /dev/null +++ b/Packages/com.chark.game-management/Runtime/Storage/Storage.cs @@ -0,0 +1,148 @@ +using System.Threading; +using System.Threading.Tasks; +using CHARK.GameManagement.Serialization; +using Cysharp.Threading.Tasks; + +namespace CHARK.GameManagement.Storage +{ + internal abstract class Storage : IStorage + { + private readonly ISerializer serializer; + private readonly string pathPrefix; + + protected Storage(ISerializer serializer, string pathPrefix) + { + this.serializer = serializer; + this.pathPrefix = pathPrefix; + } + + public async Task GetValueAsync( + string path, + CancellationToken cancellationToken + ) + { + await UniTask.SwitchToThreadPool(); + + try + { + if (TryGetValue(path, out var value)) + { + return value; + } + } + finally + { + await UniTask.SwitchToMainThread(cancellationToken); + } + + return default; + } + + public virtual bool TryGetValue(string path, out TValue value) + { + value = default; + + if (TryGetFormattedPath(path, out var formattedPath) == false) + { + return false; + } + + var stringValue = GetString(formattedPath); + if (string.IsNullOrWhiteSpace(stringValue)) + { + return false; + } + + if (serializer.TryDeserializeValue(stringValue, out TValue deserializedValue)) + { + value = deserializedValue; + return true; + } + + return true; + } + + public async Task SetValueAsync( + string path, + TValue value, + CancellationToken cancellationToken + ) + { + await UniTask.SwitchToThreadPool(); + + try + { + SetValue(path, value); + } + finally + { + await UniTask.SwitchToMainThread(cancellationToken); + } + } + + public virtual void SetValue(string path, TValue value) + { + if (TryGetFormattedPath(path, out var formattedPath) == false) + { + return; + } + + if (serializer.TrySerializeValue(value, out var serializedValue) == false) + { + return; + } + + SetString(formattedPath, serializedValue); + } + + public async Task DeleteValueAsync(string path, CancellationToken cancellationToken) + { + await UniTask.SwitchToThreadPool(); + + try + { + Delete(path); + } + finally + { + await UniTask.SwitchToMainThread(cancellationToken); + } + } + + public void DeleteValue(string path) + { + if (TryGetFormattedPath(path, out var formattedPath)) + { + Delete(formattedPath); + } + } + + /// + /// String retrieved using given . + /// + protected abstract string GetString(string path); + + /// + /// Store a at given . + /// + protected abstract void SetString(string path, string value); + + /// + /// Delete value at given . + /// + protected abstract void Delete(string path); + + private bool TryGetFormattedPath(string path, out string formattedPath) + { + formattedPath = default; + + if (string.IsNullOrWhiteSpace(path)) + { + return false; + } + + formattedPath = pathPrefix + path; + return true; + } + } +} diff --git a/Packages/com.chark.game-management/Runtime/Storage/GameStorage.cs.meta b/Packages/com.chark.game-management/Runtime/Storage/Storage.cs.meta similarity index 54% rename from Packages/com.chark.game-management/Runtime/Storage/GameStorage.cs.meta rename to Packages/com.chark.game-management/Runtime/Storage/Storage.cs.meta index 710aaf9..d4cbf81 100644 --- a/Packages/com.chark.game-management/Runtime/Storage/GameStorage.cs.meta +++ b/Packages/com.chark.game-management/Runtime/Storage/Storage.cs.meta @@ -1,3 +1,3 @@ fileFormatVersion: 2 -guid: ea91cadd8a0c4a14b19e67360efea6bf +guid: 2bff78b09def57040bc3ed7af6a9ae3c timeCreated: 1669919761 \ No newline at end of file diff --git a/Packages/com.chark.game-management/Tests/Editor/DefaultSerializerTest.cs b/Packages/com.chark.game-management/Tests/Editor/DefaultSerializerTest.cs new file mode 100644 index 0000000..10c9f5f --- /dev/null +++ b/Packages/com.chark.game-management/Tests/Editor/DefaultSerializerTest.cs @@ -0,0 +1,119 @@ +using CHARK.GameManagement.Serialization; +using Newtonsoft.Json; +using NUnit.Framework; + +namespace CHARK.GameManagement.Tests.Editor +{ + internal sealed class DefaultSerializerTest + { + private readonly ISerializer serializer = DefaultSerializer.Instance; + + [Test] + public void ShouldSerializeString() + { + // Given + const string value = "hello"; + + // When + if (serializer.TrySerializeValue(value, out var actualValue) == false) + { + Assert.Fail("Could not serialize string"); + } + + // Then + Assert.AreEqual("hello", actualValue); + } + + [Test] + public void ShouldSerializeInt() + { + // Given + const int value = 123; + + // When + if (serializer.TrySerializeValue(value, out var actualValue) == false) + { + Assert.Fail("Could not serialize int"); + } + + // Then + Assert.AreEqual("123", actualValue); + } + + [Test] + public void ShouldSerializeClass() + { + // Given + var value = new TestClass("hello"); + + // When + if (serializer.TrySerializeValue(value, out var actualValue) == false) + { + Assert.Fail("Could not serialize class"); + } + + // Then + Assert.AreEqual("{\"value\":\"hello\"}", actualValue); + } + + [Test] + public void ShouldDeserializeString() + { + // Given + const string value = "hello"; + + // When + if (serializer.TryDeserializeValue(value, out var actualValue) == false) + { + Assert.Fail("Could not deserialize string"); + } + + // Then + Assert.AreEqual("hello", actualValue); + } + + [Test] + public void ShouldDeserializeInt() + { + // Given + const string value = "123"; + + // When + if (serializer.TryDeserializeValue(value, out var actualValue) == false) + { + Assert.Fail("Could not deserialize int"); + } + + // Then + Assert.AreEqual(123, actualValue); + } + + [Test] + public void ShouldDeserializeClass() + { + // Given + var value = "{\"value\":\"hello\"}"; + + // When + if (serializer.TryDeserializeValue(value, out var actualValue) == false) + { + Assert.Fail("Could not serialize class"); + } + + // Then + Assert.AreEqual("hello", actualValue.Value); + } + + private class TestClass + { + [JsonProperty] + public string Value { get; } + + [JsonConstructor] + public TestClass(string value) + { + Value = value; + } + } + } +} diff --git a/Packages/com.chark.game-management/Tests/Editor/DefaultSerializerTest.cs.meta b/Packages/com.chark.game-management/Tests/Editor/DefaultSerializerTest.cs.meta new file mode 100644 index 0000000..b1793be --- /dev/null +++ b/Packages/com.chark.game-management/Tests/Editor/DefaultSerializerTest.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 56598dd986db4c328249429fad7aa11f +timeCreated: 1697482165 \ No newline at end of file diff --git a/Packages/com.chark.game-management/Tests/Editor/EditorPrefsGameStorageTest.cs b/Packages/com.chark.game-management/Tests/Editor/EditorPrefsStorageTest.cs similarity index 64% rename from Packages/com.chark.game-management/Tests/Editor/EditorPrefsGameStorageTest.cs rename to Packages/com.chark.game-management/Tests/Editor/EditorPrefsStorageTest.cs index 1339e0b..83cbbfc 100644 --- a/Packages/com.chark.game-management/Tests/Editor/EditorPrefsGameStorageTest.cs +++ b/Packages/com.chark.game-management/Tests/Editor/EditorPrefsStorageTest.cs @@ -1,13 +1,14 @@ -using CHARK.GameManagement.Storage; +using CHARK.GameManagement.Serialization; +using CHARK.GameManagement.Storage; using UnityEditor; namespace CHARK.GameManagement.Tests.Editor { - internal sealed class EditorPrefsGameStorageTest : GameStorageTest + internal sealed class EditorPrefsStorageTest : StorageTest { - protected override IGameStorage CreateStorage() + protected override IStorage CreateStorage() { - return new EditorPrefsGameStorage(); + return new EditorPrefsStorage(DefaultSerializer.Instance); } protected override string GetString(string key) diff --git a/Packages/com.chark.game-management/Tests/Editor/EditorPrefsGameStorageTest.cs.meta b/Packages/com.chark.game-management/Tests/Editor/EditorPrefsStorageTest.cs.meta similarity index 54% rename from Packages/com.chark.game-management/Tests/Editor/EditorPrefsGameStorageTest.cs.meta rename to Packages/com.chark.game-management/Tests/Editor/EditorPrefsStorageTest.cs.meta index 2bd5415..733cb6a 100644 --- a/Packages/com.chark.game-management/Tests/Editor/EditorPrefsGameStorageTest.cs.meta +++ b/Packages/com.chark.game-management/Tests/Editor/EditorPrefsStorageTest.cs.meta @@ -1,3 +1,3 @@ fileFormatVersion: 2 -guid: 43a0363377e54882ad5aa7514c99a3e9 +guid: 2368299ec355e784089fd85a2f2624a5 timeCreated: 1669924783 \ No newline at end of file diff --git a/Packages/com.chark.game-management/Tests/Editor/PlayerPrefsGameStorageTest.cs b/Packages/com.chark.game-management/Tests/Editor/PlayerPrefsStorageTest.cs similarity index 64% rename from Packages/com.chark.game-management/Tests/Editor/PlayerPrefsGameStorageTest.cs rename to Packages/com.chark.game-management/Tests/Editor/PlayerPrefsStorageTest.cs index f368aa3..977ac6b 100644 --- a/Packages/com.chark.game-management/Tests/Editor/PlayerPrefsGameStorageTest.cs +++ b/Packages/com.chark.game-management/Tests/Editor/PlayerPrefsStorageTest.cs @@ -1,13 +1,14 @@ -using CHARK.GameManagement.Storage; +using CHARK.GameManagement.Serialization; +using CHARK.GameManagement.Storage; using UnityEngine; namespace CHARK.GameManagement.Tests.Editor { - internal sealed class PlayerPrefsGameStorageTest : GameStorageTest + internal sealed class PlayerPrefsStorageTest : StorageTest { - protected override IGameStorage CreateStorage() + protected override IStorage CreateStorage() { - return new PlayerPrefsGameStorage(); + return new PlayerPrefsStorage(DefaultSerializer.Instance); } protected override string GetString(string key) diff --git a/Packages/com.chark.game-management/Tests/Editor/PlayerPrefsGameStorageTest.cs.meta b/Packages/com.chark.game-management/Tests/Editor/PlayerPrefsStorageTest.cs.meta similarity index 54% rename from Packages/com.chark.game-management/Tests/Editor/PlayerPrefsGameStorageTest.cs.meta rename to Packages/com.chark.game-management/Tests/Editor/PlayerPrefsStorageTest.cs.meta index 32ed0ae..50e9f62 100644 --- a/Packages/com.chark.game-management/Tests/Editor/PlayerPrefsGameStorageTest.cs.meta +++ b/Packages/com.chark.game-management/Tests/Editor/PlayerPrefsStorageTest.cs.meta @@ -1,3 +1,3 @@ fileFormatVersion: 2 -guid: 79ddf9e1bf7c4a8dab7a9a635b247d1c +guid: dae3f11f888aa314394e2513084cbbd5 timeCreated: 1669922570 \ No newline at end of file diff --git a/Packages/com.chark.game-management/Tests/Editor/GameStorageTest.cs b/Packages/com.chark.game-management/Tests/Editor/StorageTest.cs similarity index 97% rename from Packages/com.chark.game-management/Tests/Editor/GameStorageTest.cs rename to Packages/com.chark.game-management/Tests/Editor/StorageTest.cs index c5f4c3b..a41aa7c 100644 --- a/Packages/com.chark.game-management/Tests/Editor/GameStorageTest.cs +++ b/Packages/com.chark.game-management/Tests/Editor/StorageTest.cs @@ -6,7 +6,7 @@ namespace CHARK.GameManagement.Tests.Editor { - internal abstract class GameStorageTest + internal abstract class StorageTest { private static readonly JsonSerializerSettings SerializerSettings = new() { @@ -15,7 +15,7 @@ internal abstract class GameStorageTest private string Key => GetType().Name; - private IGameStorage storage; + private IStorage storage; [SetUp] public void SetUp() @@ -147,7 +147,7 @@ public void ShouldSetObjectValue() /// /// New storage instance. /// - protected abstract IGameStorage CreateStorage(); + protected abstract IStorage CreateStorage(); /// /// Raw json value retrieved by given . diff --git a/Packages/com.chark.game-management/Tests/Editor/GameStorageTest.cs.meta b/Packages/com.chark.game-management/Tests/Editor/StorageTest.cs.meta similarity index 54% rename from Packages/com.chark.game-management/Tests/Editor/GameStorageTest.cs.meta rename to Packages/com.chark.game-management/Tests/Editor/StorageTest.cs.meta index e909ecd..a4966bc 100644 --- a/Packages/com.chark.game-management/Tests/Editor/GameStorageTest.cs.meta +++ b/Packages/com.chark.game-management/Tests/Editor/StorageTest.cs.meta @@ -1,3 +1,3 @@ fileFormatVersion: 2 -guid: 5e33c627119c4b06a548b9e3ef9242b6 +guid: 84adec182f69dc3449510989d0ddb724 timeCreated: 1670270154 \ No newline at end of file