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
20 changes: 20 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,22 @@ 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.10.0] - 2024-11-13

**New**:
- Added *UniTask* dependency to enable WebGL platform support

**Changed**:
- Updated *IUiService* async methods to use *UniTask* instead of *Task* for better performance and WebGL compatibility

## [0.9.1] - 2024-11-04

**Fixed**:
- Fixed the issue that would crash *NonDrawingView* if the *GameObject* would be missing a *CanvasRenderer*

## [0.9.0] - 2024-11-01

***New**:
- Added *GetUi<T>* method to the *IUiService*. It requests the *UiPresenter* by directly using generic T
- Added *IsVisible<T>* method to the *IUiService*. It requests the visibility state of *UiPresenter*
- Added IReadOnlyList property *VisiblePresenters* to the *IUiService* to allow external entities to access the list of visible *UiPresenter*
Expand All @@ -20,6 +29,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.

## [0.8.0] - 2024-10-29

***New**:
- Added new *PresenterDelayerBase*, *AnimationDelayer* and *TimeDelayer* to support presenters that open/close with a delay
- Added new *DelayUiPresenter* to interact with *PresenterDelayerBase* implementations and allow presenters to open/close with a delay
- Improved performance of *UiService*
Expand All @@ -41,13 +51,15 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.

## [0.7.1] - 2021-05-03

***New**:
- Added the possibility for *SafeAreaHelpersView* to maintain the View in the same position if not placed outside of the safe area

**Fixed**:
- Fixed the duplicated memory issue when loading the same *UiPresenter* multiple times at the same time before when of them is finished

## [0.7.0] - 2021-03-12

***New**:
- Added *NonDrawingView* to have an Image without a renderer to not add additional draw calls.
- Added *SafeAreaHelperView* to add the possibility for the *RectTransform* to adjust himself to the screen notches
- Added *AnimatedUiPresenter* to play animation on enter or closing
Expand All @@ -61,10 +73,12 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.

## [0.6.1] - 2020-09-24

**Fixed**:
- Updated dependency packages

## [0.6.0] - 2020-09-24

***New**:
- Added the possibility for the *IUiService* to allow to open/close already opened/closed *UiPresenters*, and throw an exception if not.
- Added the visible property to UiPresenter of its current visual status Added *IUiServiceInit* to give a new contract interface for the *UiService" initialisation

Expand All @@ -75,6 +89,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.

## [0.5.0] - 2020-07-13

***New**:
- Added *UiAssetLoader* to load Ui assets to memory

**Changed**:
Expand All @@ -88,19 +103,23 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.

## [0.3.2] - 2020-04-18

**Changed**:
- Moved interface *IUiService* to a separate file to improve the code readability

## [0.3.1] - 2020-02-15

**Changed**:
- Updated dependency packages

## [0.3.0] - 2020-02-11

***New**:
- Added new *UiPresenterData* class for the case where the *UiPresenter* needs to be initialized with a default data value
- Added new *OnInitialize* method that is invoked after the *UiPresenter* is initialized

## [0.2.1] - 2020-02-09

***New**:
- Added the possibility to open the ui after adding or loading it to the *UiService*
- Added the possibility to get the canvas reference object based on the given layer
- Added the possibility to remove and unload the *UiPresenter* by only passing it's reference
Expand All @@ -110,6 +129,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.

## [0.2.0] - 2020-01-19

***New**:
- Added easy selection of the *UiConfigs.asset* file. Just go to *Tools > Select UiConfigs.asset*. If the *UiConfigs.asset* does not exist, it will create a new one in the Assets folder
- Added the protected *Close()* method to directly allow to close the *UiPresenter* from the *UiPresenter* object file without needing to call the *UiService*. Also now is possible to close an Ui in the service by referencing the object directly without needing to reference the object type by calling *CloseUi<T>(T presenter)*
- Now the *UnloadUi* & *UnloadUiSet* properly unloads the ui from memory and removes it from the service
Expand Down
3 changes: 2 additions & 1 deletion Runtime/GameLovers.UiService.asmdef
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
"rootNamespace": "",
"references": [
"GUID:84651a3751eca9349aac36a66bba901b",
"GUID:9e24947de15b9834991c9d8411ea37cf"
"GUID:9e24947de15b9834991c9d8411ea37cf",
"GUID:f51ebe6a0ceec4240a699833d6309b23"
],
"includePlatforms": [],
"excludePlatforms": [],
Expand Down
15 changes: 8 additions & 7 deletions Runtime/IUiService.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using Cysharp.Threading.Tasks;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
Expand Down Expand Up @@ -111,7 +112,7 @@ public interface IUiService
/// <param name="openAfter">Whether to open the UI after loading.</param>
/// <returns>A task that completes with the loaded UI.</returns>
/// <exception cref="KeyNotFoundException">Thrown if the service does not contain a UI configuration for the specified type.</exception>
async Task<T> LoadUiAsync<T>(bool openAfter = false) where T : UiPresenter => (await LoadUiAsync(typeof(T), openAfter)) as T;
async UniTask<T> LoadUiAsync<T>(bool openAfter = false) where T : UiPresenter => (await LoadUiAsync(typeof(T), openAfter)) as T;

/// <summary>
/// Loads the UI of the specified type asynchronously.
Expand All @@ -122,7 +123,7 @@ public interface IUiService
/// <param name="openAfter">Whether to open the UI after loading.</param>
/// <returns>A task that completes with the loaded UI.</returns>
/// <exception cref="KeyNotFoundException">Thrown if the service does not contain a UI configuration for the specified type.</exception>
Task<UiPresenter> LoadUiAsync(Type type, bool openAfter = false);
UniTask<UiPresenter> LoadUiAsync(Type type, bool openAfter = false);

/// <summary>
/// Loads all UI presenters from the specified UI set asynchronously.
Expand All @@ -132,7 +133,7 @@ public interface IUiService
/// <param name="setId">The ID of the UI set to load from.</param>
/// <returns>An array of tasks that complete with each loaded UI.</returns>
/// <exception cref="KeyNotFoundException">Thrown if the service does not contain a UI set with the specified ID.</exception>
Task<Task<UiPresenter>>[] LoadUiSetAsync(int setId);
IList<UniTask<UiPresenter>> LoadUiSetAsync(int setId);

/// <summary>
/// Unloads the UI of the specified type.
Expand Down Expand Up @@ -168,14 +169,14 @@ public interface IUiService
/// </summary>
/// <typeparam name="T">The type of UI presenter to open.</typeparam>
/// <returns>A task that completes when the UI presenter is opened.</returns>
async Task<T> OpenUiAsync<T>() where T : UiPresenter => (await OpenUiAsync(typeof(T))) as T;
async UniTask<T> OpenUiAsync<T>() where T : UiPresenter => (await OpenUiAsync(typeof(T))) as T;

/// <summary>
/// Opens a UI presenter asynchronously, loading its assets if necessary.
/// </summary>
/// <param name="type">The type of UI presenter to open.</param>
/// <returns>A task that completes when the UI presenter is opened.</returns>
Task<UiPresenter> OpenUiAsync(Type type);
UniTask<UiPresenter> OpenUiAsync(Type type);

/// <summary>
/// Opens a UI presenter asynchronously, loading its assets if necessary, and sets its initial data.
Expand All @@ -184,7 +185,7 @@ public interface IUiService
/// <typeparam name="TData">The type of initial data to set.</typeparam>
/// <param name="initialData">The initial data to set.</param>
/// <returns>A task that completes when the UI presenter is opened.</returns>
async Task<T> OpenUiAsync<T, TData>(TData initialData)
async UniTask<T> OpenUiAsync<T, TData>(TData initialData)
where T : class, IUiPresenterData
where TData : struct => await OpenUiAsync(typeof(T), initialData) as T;

Expand All @@ -194,7 +195,7 @@ async Task<T> OpenUiAsync<T, TData>(TData initialData)
/// <param name="type">The type of UI presenter to open.</param>
/// <param name="initialData">The initial data to set.</param>
/// <returns>A task that completes when the UI presenter is opened.</returns>
Task<UiPresenter> OpenUiAsync<TData>(Type type, TData initialData) where TData : struct;
UniTask<UiPresenter> OpenUiAsync<TData>(Type type, TData initialData) where TData : struct;

/// <summary>
/// Closes a UI presenter and optionally destroys its assets.
Expand Down
7 changes: 3 additions & 4 deletions Runtime/UiAssetLoader.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using System.IO;
using System.Threading.Tasks;
using Cysharp.Threading.Tasks;
using UnityEngine;
using UnityEngine.AddressableAssets;
using UnityEngine.ResourceManagement.AsyncOperations;
Expand All @@ -20,7 +19,7 @@ public interface IUiAssetLoader
/// <param name="config">The UI configuration to instantiate.</param>
/// <param name="parent">The parent transform to instantiate the prefab under.</param>
/// <returns>A task that completes with the instantiated prefab game object.</returns>
Task<GameObject> InstantiatePrefab(UiConfig config, Transform parent);
UniTask<GameObject> InstantiatePrefab(UiConfig config, Transform parent);

/// <summary>
/// Unloads the given <paramref name="asset"/> from the game memory
Expand All @@ -32,7 +31,7 @@ public interface IUiAssetLoader
public class UiAssetLoader : IUiAssetLoader
{
/// <inheritdoc />
public async Task<GameObject> InstantiatePrefab(UiConfig config, Transform parent)
public async UniTask<GameObject> InstantiatePrefab(UiConfig config, Transform parent)
{
var operation = Addressables.InstantiateAsync(config.AddressableAddress, new InstantiationParameters(parent, false));

Expand Down
2 changes: 1 addition & 1 deletion Runtime/UiConfigs.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ public struct UiConfig
/// 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
public class UiConfigs : ScriptableObject//, IConfigsContainer<UiConfig>
{
[SerializeField] private string _loadingSpinnerType;
[SerializeField]
Expand Down
42 changes: 8 additions & 34 deletions Runtime/UiService.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using Cysharp.Threading.Tasks;
using System;
using System.Collections.Generic;
using System.Linq;
Expand Down Expand Up @@ -154,7 +155,7 @@ public List<UiPresenter> RemoveUiSet(int setId)
}

/// <inheritdoc />
public async Task<UiPresenter> LoadUiAsync(Type type, bool openAfter = false)
public async UniTask<UiPresenter> LoadUiAsync(Type type, bool openAfter = false)
{
if (!_uiConfigs.TryGetValue(type, out var config))
{
Expand Down Expand Up @@ -190,9 +191,9 @@ public async Task<UiPresenter> LoadUiAsync(Type type, bool openAfter = false)
}

/// <inheritdoc />
public Task<Task<UiPresenter>>[] LoadUiSetAsync(int setId)
public IList<UniTask<UiPresenter>> LoadUiSetAsync(int setId)
{
var uiTasks = new List<Task<UiPresenter>>();
var uiTasks = new List<UniTask<UiPresenter>>();

if (_uiSets.TryGetValue(setId, out var set))
{
Expand All @@ -207,7 +208,7 @@ public Task<Task<UiPresenter>>[] LoadUiSetAsync(int setId)
}
}

return Interleaved(uiTasks);
return uiTasks;
}

/// <inheritdoc />
Expand Down Expand Up @@ -235,7 +236,7 @@ public void UnloadUiSet(int setId)
}

/// <inheritdoc />
public async Task<UiPresenter> OpenUiAsync(Type type)
public async UniTask<UiPresenter> OpenUiAsync(Type type)
{
var ui = await GetOrLoadUiAsync(type);

Expand All @@ -245,7 +246,7 @@ public async Task<UiPresenter> OpenUiAsync(Type type)
}

/// <inheritdoc />
public async Task<UiPresenter> OpenUiAsync<TData>(Type type, TData initialData) where TData : struct
public async UniTask<UiPresenter> OpenUiAsync<TData>(Type type, TData initialData) where TData : struct
{
var ui = await GetOrLoadUiAsync(type);
var uiPresenterData = ui as UiPresenterData<TData>;
Expand Down Expand Up @@ -333,7 +334,7 @@ private void OpenUi(Type type)
_visibleUiList.Add(type);
}

private async Task<UiPresenter> GetOrLoadUiAsync(Type type)
private async UniTask<UiPresenter> GetOrLoadUiAsync(Type type)
{
if (!_uiPresenters.TryGetValue(type, out var ui))
{
Expand Down Expand Up @@ -364,32 +365,5 @@ private void CloseLoadingSpinner()

CloseUi(_loadingSpinnerType);
}

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);
}
}
}
}
5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,13 @@
"name": "com.gamelovers.uiservice",
"displayName": "UiService",
"author": "Miguel Tomas",
"version": "0.9.1",
"version": "0.10.0",
"unity": "2022.3",
"license": "MIT",
"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.unity.addressables": "1.22.0"
"com.unity.addressables": "1.22.0",
"com.cysharp.unitask": "2.5.10"
},
"type": "library",
"hideInEditor": false
Expand Down