Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,17 @@ All notable changes to this package will be documented in this file.
The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html)

## [0.5.0] - 2020-07-13

- Added *UiAssetLoader* to load Ui assets to memory

**Changed**:
- Removed the *UiService* dependency from the *com.gamelovers.assetLoader*

## [0.4.0] - 2020-07-13

**Changed**:
- Removed the *UiService* dependency from the *Addressables*
- Removed the *UiService* dependency from the *com.unity.addressables*
- Modified the *UiService* to be testable and injectable into other systems

## [0.3.2] - 2020-04-18
Expand Down
5 changes: 2 additions & 3 deletions Runtime/GameLovers.UiService.asmdef
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
{
"name": "UiService",
"name": "GameLovers.UiService",
"references": [
"GUID:84651a3751eca9349aac36a66bba901b",
"GUID:9e24947de15b9834991c9d8411ea37cf",
"GUID:ebfc05ee5a737f94d8b07099524dab77"
"GUID:9e24947de15b9834991c9d8411ea37cf"
],
"includePlatforms": [],
"excludePlatforms": [],
Expand Down
62 changes: 62 additions & 0 deletions Runtime/UiAssetLoader.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
using System.Threading.Tasks;
using UnityEngine;
using UnityEngine.AddressableAssets;
using UnityEngine.ResourceManagement.AsyncOperations;
using UnityEngine.ResourceManagement.ResourceProviders;

// ReSharper disable CheckNamespace

namespace GameLovers.UiService
{
/// <summary>
/// This interface allows to wrap the asset loading scheme into the UI memory
/// </summary>
public interface IUiAssetLoader
{
/// <summary>
/// Loads and instantiates the prefab in the given <paramref name="path"/> with the given <paramref name="parent"/>
/// and the given <paramref name="instantiateInWorldSpace"/> to preserve the instance transform relative to world
/// space or relative to the parent.
/// To help the execution of this method is recommended to request the asset path from an <seealso cref="AddressableConfig"/>.
/// This method can be controlled in an async method and returns the prefab instantiated
/// </summary>
Task<GameObject> InstantiatePrefabAsync(string path, Transform parent, bool instantiateInWorldSpace);

/// <summary>
/// Unloads the given <paramref name="asset"/> from the game memory.
/// If <typeparamref name="T"/> is of <seealso cref="GameObject"/> type, then will also destroy it
/// </summary>
void UnloadAsset<T>(T asset);
}

/// <inheritdoc />
public class UiAssetLoader : IUiAssetLoader
{
/// <inheritdoc />
public async Task<GameObject> InstantiatePrefabAsync(string path, Transform parent, bool instantiateInWorldSpace)
{
var operation = Addressables.InstantiateAsync(path, new InstantiationParameters(parent, instantiateInWorldSpace));

await operation.Task;

if (operation.Status != AsyncOperationStatus.Succeeded)
{
throw operation.OperationException;
}

return operation.Result;
}

/// <inheritdoc />
public void UnloadAsset<T>(T asset)
{
Addressables.Release(asset);

var gameObject = asset as GameObject;
if (gameObject != null)
{
UnityEngine.Object.Destroy(gameObject);
}
}
}
}
3 changes: 3 additions & 0 deletions Runtime/UiAssetLoader.cs.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

18 changes: 0 additions & 18 deletions Runtime/UiConfig.cs

This file was deleted.

3 changes: 0 additions & 3 deletions Runtime/UiConfig.cs.meta

This file was deleted.

14 changes: 13 additions & 1 deletion Runtime/UiConfigs.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,19 @@
namespace GameLovers.UiService
{
/// <summary>
/// Scriptable Object tool to import the <seealso cref="UiConfig"/> & <seealso cref="UiSetConfig"/> to be used in the <see cref="IUiService"/>
/// Represents a configuration of an <seealso cref="UiPresenter"/> with all it's important data
/// The Id is the int representation of the UI generated by the UiIdsGenerator code generator
/// </summary>
[Serializable]
public struct UiConfig
{
public string AddressableAddress;
public int Layer;
public Type UiType;
}

/// <summary>
/// ScriptableObject tool to import the <seealso cref="UiConfig"/> & <seealso cref="UiSetConfig"/> to be used in the <see cref="IUiService"/>
/// </summary>
[CreateAssetMenu(fileName = "UiConfigs", menuName = "ScriptableObjects/Configs/UiConfigs")]
public class UiConfigs : ScriptableObject
Expand Down
7 changes: 3 additions & 4 deletions Runtime/UiPresenter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -60,17 +60,16 @@ internal void InternalClose()
}

/// <summary>
/// Tags the <see cref="UiPresenter"/> as a <see cref="UiPresenterData{T}"/> to allow definning a specific state when
/// opening it via the <see cref="UiService"/>
/// Tags the <see cref="UiPresenter"/> as a <see cref="UiPresenterData{T}"/> to allow defining a specific state when
/// opening the UI via the <see cref="UiService"/>
/// </summary>
public interface IUiPresenterData {}

/// <inheritdoc cref="UiPresenter"/>
/// <remarks>
/// Extends the <see cref="UiPresenter"/> behaviour with defined data of type <typeparamref name="T"/>
/// </remarks>
public abstract class UiPresenterData<T> : UiPresenter, IUiPresenterData
where T : struct
public abstract class UiPresenterData<T> : UiPresenter, IUiPresenterData where T : struct
{
/// <summary>
/// The Ui data defined when opened via the <see cref="UiService"/>
Expand Down
44 changes: 38 additions & 6 deletions Runtime/UiService.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using GameLovers.AssetLoader;
using UnityEngine;

// ReSharper disable CheckNamespace
Expand All @@ -11,21 +12,25 @@ namespace GameLovers.UiService
/// <inheritdoc />
public class UiService : IUiService
{
private readonly IAssetLoader _assetLoader;
private readonly IUiAssetLoader _assetLoader;
private readonly IDictionary<Type, UiReference> _uiViews = new Dictionary<Type, UiReference>();
private readonly IDictionary<Type, UiConfig> _uiConfigs = new Dictionary<Type, UiConfig>();
private readonly IDictionary<int, UiSetConfig> _uiSets = new Dictionary<int, UiSetConfig>();
private readonly IList<Type> _visibleUiList = new List<Type>();
private readonly IList<Canvas> _layers = new List<Canvas>();

public UiService(IAssetLoader assetLoader)
public UiService(IUiAssetLoader assetLoader)
{
_assetLoader = assetLoader;
}

/// <summary>
/// Initialize the service with the proper <paramref name="configs"/>
/// Initialize the service with <paramref name="configs"/> that define the game's UI
/// </summary>
/// <remarks>
/// To help configure the game's UI you need to create a UiConfigs Scriptable object by:
/// - Right Click on the Project View > Create > ScriptableObjects > Configs > UiConfigs
/// </remarks>
/// <exception cref="ArgumentException">
/// Thrown if any of the <see cref="UiConfig"/> in the given <paramref name="configs"/> is duplicated
/// </exception>
Expand Down Expand Up @@ -145,7 +150,7 @@ public async Task<UiPresenter> LoadUiAsync(Type type, bool openAfter = false)
throw new KeyNotFoundException($"The UiConfig of type {type} was not added to the service. Call {nameof(AddUiConfig)} first");
}

var gameObject = await _assetLoader.InstantiatePrefabAsync(config.AddressableAddress);
var gameObject = await _assetLoader.InstantiatePrefabAsync(config.AddressableAddress, null, true);
var uiPresenter = gameObject.GetComponent<UiPresenter>();

gameObject.SetActive(false);
Expand Down Expand Up @@ -372,7 +377,7 @@ public Task<Task<UiPresenter>>[] LoadUiSetAsync(int setId)
uiTasks.Add(LoadUiAsync(set.UiConfigsType[i]));
}

return AssetLoaderUtils.Interleaved(uiTasks);
return Interleaved(uiTasks);
}

/// <inheritdoc />
Expand Down Expand Up @@ -473,6 +478,33 @@ private UiReference GetReference(Type type)
return uiReference;
}

private Task<Task<T>>[] Interleaved<T>(IEnumerable<Task<T>> tasks)
{
var inputTasks = tasks.ToList();
var buckets = new TaskCompletionSource<Task<T>>[inputTasks.Count];
var results = new Task<Task<T>>[buckets.Length];
var nextTaskIndex = -1;

for (var i = 0; i < buckets.Length; i++)
{
buckets[i] = new TaskCompletionSource<Task<T>>();
results[i] = buckets[i].Task;
}

foreach (var inputTask in inputTasks)
{
inputTask.ContinueWith(Continuation, CancellationToken.None, TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default);
}

return results;

// Local function
void Continuation(Task<T> completed)
{
buckets[Interlocked.Increment(ref nextTaskIndex)].TrySetResult(completed);
}
}

private struct UiReference
{
public Type UiType;
Expand Down
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
{
"name": "com.gamelovers.uiservice",
"displayName": "UiService",
"version": "0.3.2",
"version": "0.5.0",
"unity": "2019.3",
"description": "This package provides a service to help manage an Unity's, game UI.\nIt allows to open, close, load, unload and request any Ui Configured in the game.\nThe package provides a Ui Set that allows to group a set of Ui Presenters to help load, open and close multiple Uis at the same time.\n\nTo help configure the game's UI you need to create a UiConfigs Scriptable object by:\n- Right Click on the Project View > Create > ScriptableObjects > Configs > UiConfigs",
"dependencies": {
"com.gamelovers.assetloader": "0.3.0"
"com.unity.addressables": "1.8.4"
},
"type": "library",
"hideInEditor": false
Expand Down