Skip to content

Commit

Permalink
Expose serializer, add more tests, update docs, add more async capabi…
Browse files Browse the repository at this point in the history
…lities, add streaming assets loaidng, rename args
  • Loading branch information
Edvinas01 committed Oct 16, 2023
1 parent 328c3e2 commit 11d86d6
Show file tree
Hide file tree
Showing 36 changed files with 831 additions and 480 deletions.
12 changes: 12 additions & 0 deletions Packages/com.chark.game-management/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,33 @@
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using UnityEngine;

namespace CHARK.GameManagement.Assets
{
public interface IResourceLoader
{
/// <returns>
/// Resources loaded from given <paramref name="path"/>.
/// Enumerable of resources retrieved from given <paramref name="path"/>.
/// </returns>
public IEnumerable<TResource> LoadResources<TResource>(string path = null) where TResource : Object;
public IEnumerable<TResource> GetResources<TResource>(string path = null)
where TResource : Object;

/// <returns>
/// Resource loaded from given <paramref name="path"/>.
/// <c>true</c> if <paramref name="resource"/> is retrieved from given
/// <paramref name="path"/> or <c>false</c> otherwise.
/// </returns>
public TResource LoadResource<TResource>(string path) where TResource : Object;
public bool TryGetResource<TResource>(string path, out TResource resource)
where TResource : Object;

/// <returns>
/// Asset loaded asynchronously from given <paramref name="path"/>.
/// <p/>
/// <b>Note</b>, <paramref name="path"/> is relative to StreamingAssets directory.
/// </returns>
public Task<TResource> GetResourceAsync<TResource>(
string path,
CancellationToken cancellationToken = default
);
}
}
Original file line number Diff line number Diff line change
@@ -1,13 +1,23 @@
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;

namespace CHARK.GameManagement.Assets
{
internal sealed class ResourceLoader : IResourceLoader
{
public IEnumerable<TResource> LoadResources<TResource>(string path = null) where TResource : Object
private readonly ISerializer serializer;

public ResourceLoader(ISerializer serializer)
{
this.serializer = serializer;
}

public IEnumerable<TResource> GetResources<TResource>(string path = null) where TResource : Object
{
if (string.IsNullOrWhiteSpace(path))
{
Expand All @@ -17,20 +27,53 @@ public IEnumerable<TResource> LoadResources<TResource>(string path = null) where
return Resources.LoadAll<TResource>(path);
}

public TResource LoadResource<TResource>(string path) where TResource : Object
public bool TryGetResource<TResource>(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<TResource>(path);
if (loadedResource)
{
resource = loadedResource;
return true;
}

var resource = Resources.Load<TResource>(path);
if (resource)
resource = default;
return false;
}

public async Task<TResource> GetResourceAsync<TResource>(
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<TResource>(content, out var value))
{
return resource;
return value;
}

throw new Exception($"Resource at path \"{path}\" could not be loaded");
return default;
}
}
}
116 changes: 83 additions & 33 deletions Packages/com.chark.game-management/Runtime/GameManager.External.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,114 +10,138 @@ namespace CHARK.GameManagement
public abstract partial class GameManager
{
/// <returns>
/// Resources of type <see cref="TResource"/> loaded via <see cref="resourceLoader"/> at
/// Resources of type <see cref="TResource"/> from <see cref="resourceLoader"/> at
/// given <paramref name="path"/>.
/// </returns>
public static IEnumerable<TResource> LoadResources<TResource>(string path = null) where TResource : Object
public static IEnumerable<TResource> GetResources<TResource>(string path = null) where TResource : Object
{
var gameManager = GetGameManager();
var resourceLoader = gameManager.resourceLoader;

return resourceLoader.LoadResources<TResource>(path);
return resourceLoader.GetResources<TResource>(path);
}

/// <returns>
/// Resource of type <see cref="TResource"/> loaded via <see cref="resourceLoader"/> at
/// given <paramref name="path"/>. If resource can't be loaded an <see cref="System.Exception"/>
/// is thrown.
/// <c>true</c> if resource of type <see cref="TResource"/> is retrieved from
/// <see cref="resourceLoader"/> at given <paramref name="path"/> or <c>false</c> otherwise.
/// </returns>
public static TResource LoadResource<TResource>(string path) where TResource : Object
public static bool TryGetResource<TResource>(string path, out TResource resource) where TResource : Object
{
var gameManager = GetGameManager();
var resourceLoader = gameManager.resourceLoader;

return resourceLoader.LoadResource<TResource>(path);
return resourceLoader.TryGetResource(path, out resource);
}

/// <returns>
/// Value retrieved from <see cref="runtimeStorage"/> at given <paramref name="key"/>
/// Task containing a resource of type <see cref="TResource"/> retrieved from
/// <see cref="resourceLoader"/> at given <paramref name="path"/> or <c>default</c> if
/// value could not be retrieved.
/// </returns>
public static Task<TResource> GetResourceAsync<TResource>(string path)
{
var gameManager = GetGameManager();
var resourceLoader = gameManager.resourceLoader;

return resourceLoader.GetResourceAsync<TResource>(path);
}

/// <returns>
/// Value retrieved from <see cref="runtimeStorage"/> at given <paramref name="path"/>
/// asynchronously or <c>default</c> if no value is could be retrieved.
/// </returns>
public static Task<TValue> GetRuntimeValueAsync<TValue>(string key)
public static Task<TValue> GetRuntimeValueAsync<TValue>(string path)
{
var gameManager = GetGameManager();
var runtimeStorage = gameManager.runtimeStorage;

return runtimeStorage.GetValueAsync<TValue>(key);
return runtimeStorage.GetValueAsync<TValue>(path);
}

/// <returns>
/// <c>true</c> if <paramref name="value"/> is retrieved by given <paramref name="key"/>
/// <c>true</c> if <paramref name="value"/> is retrieved by given <paramref name="path"/>
/// from <see cref="runtimeStorage"/>.
/// </returns>
public static bool TryGetRuntimeValue<TValue>(string key, out TValue value)
public static bool TryGetRuntimeValue<TValue>(string path, out TValue value)
{
var gameManager = GetGameManager();
var runtimeStorage = gameManager.runtimeStorage;

return runtimeStorage.TryGetValue(key, out value);
return runtimeStorage.TryGetValue(path, out value);
}

/// <summary>
/// Persist a <paramref name="value"/> by given <paramref name="key"/> asynchronously to
/// Persist a <paramref name="value"/> by given <paramref name="path"/> asynchronously to
/// <see cref="runtimeStorage"/>.
/// </summary>
public static Task SetRuntimeValueAsync<TValue>(string key, TValue value)
public static Task SetRuntimeValueAsync<TValue>(string path, TValue value)
{
var gameManager = GetGameManager();
var runtimeStorage = gameManager.runtimeStorage;

return runtimeStorage.SetValueAsync(key, value);
return runtimeStorage.SetValueAsync(path, value);
}

/// <summary>
/// Persist a <paramref name="value"/> by given <paramref name="key"/> to
/// Persist a <paramref name="value"/> by given <paramref name="path"/> to
/// <see cref="runtimeStorage"/>.
/// </summary>
public static void SetRuntimeValue<TValue>(string key, TValue value)
public static void SetRuntimeValue<TValue>(string path, TValue value)
{
var gameManager = GetGameManager();
var runtimeStorage = gameManager.runtimeStorage;

runtimeStorage.SetValue(key, value);
runtimeStorage.SetValue(path, value);
}

// TODO: add async variant!
/// <summary>
/// Delete persisted <see cref="runtimeStorage"/> value at given <paramref name="key"/>.
/// Delete persisted <see cref="runtimeStorage"/> value at given <paramref name="path"/>
/// asynchronously from <see cref="runtimeStorage"/>.
/// </summary>
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);
}

/// <summary>
/// Delete persisted <see cref="runtimeStorage"/> value at given <paramref name="path"/>
/// from <see cref="runtimeStorage"/>.
/// </summary>
public static void DeleteRuntimeValue(string path)
{
var gameManager = GetGameManager();
var runtimeStorage = gameManager.runtimeStorage;

runtimeStorage.DeleteValue(path);
}

/// <returns>
/// <c>true</c> if <paramref name="value"/> is retrieved by given <paramref name="key"/>
/// <c>true</c> if <paramref name="value"/> is retrieved by given <paramref name="path"/>
/// from <see cref="EditorStorage"/>.
/// </returns>
public static bool TryGetEditorValue<TValue>(string key, out TValue value)
public static bool TryGetEditorValue<TValue>(string path, out TValue value)
{
return EditorStorage.TryGetValue(key, out value);
return EditorStorage.TryGetValue(path, out value);
}

/// <summary>
/// Persist a <paramref name="value"/> by given <paramref name="key"/> to
/// Persist a <paramref name="value"/> by given <paramref name="path"/> to
/// <see cref="EditorStorage"/>.
/// </summary>
public static void SetEditorValue<TValue>(string key, TValue value)
public static void SetEditorValue<TValue>(string path, TValue value)
{
EditorStorage.SetValue(key, value);
EditorStorage.SetValue(path, value);
}

/// <summary>
/// Delete persisted <see cref="EditorStorage"/> value at given <paramref name="key"/>.
/// Delete persisted <see cref="EditorStorage"/> value at given <paramref name="path"/>.
/// </summary>
public static void DeleteEditorValue(string key)
public static void DeleteEditorValue(string path)
{
EditorStorage.DeleteValue(key);
EditorStorage.DeleteValue(path);
}

/// <returns>
Expand Down Expand Up @@ -189,5 +213,31 @@ public static void RemoveListener<TMessage>(Action<TMessage> listener)

messageBus.RemoveListener(listener);
}

/// <returns>
/// <c>true</c> if <paramref name="serializedValue"/> is deserialized to
/// <paramref name="deserializedValue"/> using <see cref="serializer"/> successfully or
/// <c>false</c> otherwise.
/// </returns>
public static bool TryDeserializeValue<TValue>(string serializedValue, out TValue deserializedValue)
{
var gameManager = GetGameManager();
var serializer = gameManager.serializer;

return serializer.TryDeserializeValue(serializedValue, out deserializedValue);
}

/// <returns>
/// <c>true</c> if <paramref name="deserializedValue"/> is serialized to
/// <paramref name="serializedValue"/> using <see cref="serializer"/> successfully or
/// <c>false</c> otherwise.
/// </returns>
public static bool TrySerializeValue<TValue>(TValue deserializedValue, out string serializedValue)
{
var gameManager = GetGameManager();
var serializer = gameManager.serializer;

return serializer.TrySerializeValue(deserializedValue, out serializedValue);
}
}
}
Loading

0 comments on commit 11d86d6

Please sign in to comment.