Skip to content

Commit

Permalink
v1.0.0-preview candidate
Browse files Browse the repository at this point in the history
Added:
- Switching between an asynchronous model `.Net` / `UniTask`
- Complete Coroutine base operations for addressables management
- Complete UniTask base operations for addressables management
  • Loading branch information
inc8877 committed Sep 3, 2021
1 parent e211326 commit 5b5a360
Show file tree
Hide file tree
Showing 12 changed files with 348 additions and 96 deletions.
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
# Changelog

# v1.0.0-preview

### Added

- Switching between an asynchronous model `.Net` / `UniTask`
- Complete Coroutine base operations for addressables management
- Complete UniTask base operations for addressables management

## v0.1.2

### Fixed
Expand Down
8 changes: 8 additions & 0 deletions Editor.meta

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

78 changes: 78 additions & 0 deletions Editor/UseUniTaskAsyncModel.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
using System.Collections.Generic;
using UnityEditor;

namespace AddressablesMasterDevelopment.Editor
{
internal static class UseUniTaskAsyncModel
{
private const string uniTaskSymbol = "USE_UNITASK";


[MenuItem("Tools/Addressables Master/UniTask/On")]
internal static void IncludeToSymbols()
{
if (DefineActivity())
{
EditorUtility.DisplayDialog("UniTask is supported",
"UniTask is already used", "OK");
}
else
{
if (EditorUtility.DisplayDialog("Use UniTask Async Model?",
"If UniTask support is enabled then all asynchronous code will use the UniTask async operations", "Yes", "No"))
{
DefineSymbols(true);
}
}
}
[MenuItem("Tools/Addressables Master/UniTask/Off")]
internal static void ExcludeFromSymbols()
{
if (!DefineActivity())
{
EditorUtility.DisplayDialog("UniTask support is already turned off",
"The .NET default async model is used", "OK");
}
else
{
if (EditorUtility.DisplayDialog("Disable UniTask support?",
"This action will cause the use of the standard .NET async model", "Yes", "No"))
{
DefineSymbols(false);
}
}
}

private static bool DefineActivity()
{
BuildTargetGroup currentTarget = EditorUserBuildSettings.selectedBuildTargetGroup;

List<string> scriptingSymbols =
new List<string>(PlayerSettings.GetScriptingDefineSymbolsForGroup(currentTarget).Split(';'));

return scriptingSymbols.Contains(uniTaskSymbol);
}

private static void DefineSymbols(bool state)
{
BuildTargetGroup currentTarget = EditorUserBuildSettings.selectedBuildTargetGroup;

List<string> scriptingSymbols =
new List<string>(PlayerSettings.GetScriptingDefineSymbolsForGroup(currentTarget).Split(';'));

if (state)
{
if (!scriptingSymbols.Contains(uniTaskSymbol)) scriptingSymbols.Add(uniTaskSymbol);
else return;
}
else
{
if (scriptingSymbols.Contains(uniTaskSymbol)) scriptingSymbols.Remove(uniTaskSymbol);
else return;
}

string finalScriptingSymbols = string.Join(";", scriptingSymbols.ToArray());
PlayerSettings.SetScriptingDefineSymbolsForGroup(currentTarget, finalScriptingSymbols);
}
}
}
3 changes: 3 additions & 0 deletions Editor/UseUniTaskAsyncModel.cs.meta

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

16 changes: 16 additions & 0 deletions Editor/inc8877.AddressablesMaster.Editor.asmdef
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"name": "inc8877.AddressablesMaster.Editor",
"rootNamespace": "",
"references": [],
"includePlatforms": [
"Editor"
],
"excludePlatforms": [],
"allowUnsafeCode": false,
"overrideReferences": false,
"precompiledReferences": [],
"autoReferenced": true,
"defineConstraints": [],
"versionDefines": [],
"noEngineReferences": false
}
7 changes: 7 additions & 0 deletions Editor/inc8877.AddressablesMaster.Editor.asmdef.meta

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

144 changes: 108 additions & 36 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,12 @@ If you find this project useful, star it, I will be grateful!
- [Install via OpenUPM](#install-via-openupm)
- [Install via Git URL](#install-via-git-url)
- [How to use](#how-to-use)
- [Sync](#sync)
- [Examples](#examples)
- [Async](#async)
- [Examples](#examples-1)
- [Intro](#intro)
- [Short examples](#short-examples)
- [Lifetime managment](#lifetime-managment)
- [Addressables Extensions](#addressables-extensions)
- [Examples](#examples-2)
- [Examples](#examples-3)
- [Management operations](#management-operations)
- [Short examples](#short-examples-1)
- [Credits](#credits)

## Roadmap
Expand Down Expand Up @@ -58,7 +56,9 @@ Open `Packages/manifest.json` with your favorite text editor. Add the following

## How to use

Plugin nampespace first.
### Intro

Plug in namespace first.

```c#
using AddressablesMaster;
Expand All @@ -70,24 +70,30 @@ All basic features for asset management are available along the following path:
ManageAddressables.[SOME_COMMAND];
```

The `AddressablesMaster` implements the ability to manage assets in several ways, synchronously, asynchronously and coroutines.
Below is a list of operations that are available in each control model:

> Important! The use of an asynchronous model depends on the presence of `UniTask` in the project, if it does not exist in the project, then the `.NET` async system is used by default, if the project has `UniTask`, then it is used.
- Initialize
- LoadLocations
- LoadAsset
- LoadScene
- UnloadScene
- Instantiate
- InstantiateWithAutoRelease

No matter which management model you use, each has basic control operations with its own unique implementation. For example this is how initialization looks like on each model:
If you are using the `UniTask` in a project and want to use it in an asynchronous control model, then connect it by following the path `Tools > Addressables Master > UniTask > On`.
`.NET` asynchronous operating model is used by default.
> Carefully! If you switch the asynchronous model, all existing code will be invalidated as each model has its own implementation.
```c#
ManageAddressables.InitializeSync();
ManageAddressables.InitializeAsync();
StartCoroutine(ManageAddressables.InitializeCoroutine());
```
### Short examples

For all examples we will use the following data:
For examples we will take some data:

```c#
public string keyOfAddressablesFigure;
public AssetReferenceGameObject figureAssetRefGO;
public AssetReferenceMaterial assetReferenceMaterial;
// Some data for examples
public string startupSound;
public AssetReferenceGameObject props;
public AssetReferenceMaterial material;
public AudioSource audioSource;

[Serializable]
public class AssetReferenceMaterial : AssetReferenceT<Material>
Expand All @@ -96,35 +102,45 @@ public class AssetReferenceMaterial : AssetReferenceT<Material>
}
```

### Sync
`Sync`

When using a synchronous operation script, in response to a command output that has a return value, you will receive a value of the type specified in the signature of the operation being called, this seems obvious, but for example, by calling the same operation using the asynchronous model, you will get a custom type similar to an `AsyncOperationHandle`.
```c#
audioSource.PlayOneShot(ManageAddressables.LoadAssetSync<AudioClip>(startupSound));

var _material = ManageAddressables.LoadAssetSync(material);

ManageAddressables.InstantiateSync(props).GetComponent<MeshRenderer>().material = _material;
```

#### Examples
`Async .NET`

```c#
ManageAddressables.InstantiateSync(keyOfAddressablesFigure).transform.position = Vector3.back;
ManageAddressables.InstantiateSync(figureAssetRefGO);
Debug.Log(ManageAddressables.LoadAssetSync(assetReferenceMaterial).color.a);
ManageAddressables.LoadAssetAsync(material, _material => ManageAddressables.InstantiateAsync(props,
onCompletion: _go => _go.GetComponent<MeshRenderer>().material = _material));
```

### Async
`Async UniTask`

When using a synchronous operation script, in response to a command output that has a return value, you will get a `Task` that contains as a result a custom class named `OperationResult` with several fields, `Succeeded` and `Value`. You can process this data in accordance with the logic of your project.
```c#
ManageAddressables.LoadAssetAsync(material).ContinueWith(result =>
ManageAddressables.InstantiateAsync(props).ContinueWith(x =>
x.Value.GetComponent<MeshRenderer>().material = result));
```

#### Examples
`Coroutine`

```c#
ManageAddressables.InstantiateAsync(figureAssetRefGO, onCompletion: (go =>
{
ManageAddressables.LoadAssetAsync(assetReferenceMaterial, material => go.GetComponent<MeshRenderer>().material = material);
}));
StartCoroutine(ManageAddressables.LoadAssetCoroutine(material, (key1, result1) =>
StartCoroutine(ManageAddressables.InstantiateCoroutine(props,
onSucceeded: (key2, result2) => result2.GetComponent<MeshRenderer>().material = result1))));
```

### Lifetime managment

When you load an addressable asset, you should release it as soon as you don't need it anymore, forgetting to do this can lead to many bad processes at runtime. Using the `Addressables Master` you can bind a release to the `GameoObject` that will do it for you automatically as soon as it is destroyed.

The `Addressables Master` has two ways to manage the release of objects, the first is to use [methods of extending the basic operations](#addressables-extensions) of the Addressables, the second is to use separate methods of life management.

#### Addressables Extensions

If you need to use standard operations for working with addressables assets, then you can use the extensions.
Expand All @@ -141,7 +157,7 @@ public static async Task<AsyncOperationHandle<T>> AddAutoRelease<T>(this AsyncOp
public static async Task<AsyncOperationHandle<GameObject>> AddReleaseOnDestroy(this AsyncOperationHandle<GameObject> operationHandle)
```

##### Examples
Examples:

```c#
GameObject go = new GameObject("Temp");
Expand All @@ -151,19 +167,75 @@ assetReferenceMaterial.LoadAssetAsync().AddAutoRelease(go);
figureAssetRefGO.InstantiateAsync().AddReleaseOnDestroy();
```

#### Management operations

`Sync`

```c#
public static GameObject InstantiateSyncWithAutoRelease(AssetReference assetReference, Transform parent = null, bool inWorldSpace = false)
public static GameObject InstantiateSyncWithAutoRelease(string key, Transform parent = null,
bool inWorldSpace = false)
```

`Async`
```c#
public static GameObject InstantiateSyncWithAutoRelease(AssetReference assetReference, Transform parent = null,
bool inWorldSpace = false)
```

`Async .NET`

```c#
public static async Task<GameObject> InstantiateAsyncWithAutoRelease(string key, Transform parent = null,
bool inWorldSpace = false, Action<GameObject> onCompletion = null)
```

```c#
public static async Task<GameObject> InstantiateAsyncWithAutoRelease(AssetReference assetReference, Transform parent = null, bool inWorldSpace = false)
```

#### Examples
`Async UniTask`

```c#
public static async UniTask<GameObject> InstantiateAsyncWithAutoRelease(string key, Transform parent = null,
bool inWorldSpace = false, Action<GameObject> onCompletion = null)
```

```c#
public static async UniTask<GameObject> InstantiateAsyncWithAutoRelease(AssetReference assetReference,
Transform parent = null, bool inWorldSpace = false, Action<GameObject> onCompletion = null)
```

`Coroutine`

```c#
public static IEnumerator InstantiateWithAutoReleaseCoroutine(string key, Transform parent = null,
bool inWorldSpace = false, bool trackHandle = true, Action<string, GameObject> onSucceeded = null,
Action<string> onFailed = null)
```

```c#
public static IEnumerator InstantiateWithAutoReleaseCoroutine(AssetReference reference, Transform parent = null,
bool inWorldSpace = false, Action<string, GameObject> onSucceeded = null, Action<string> onFailed = null)
```

`Methods not tied to a specific management model`

```c#
public static void AddAutoReleaseAssetTrigger(string key, GameObject targetGO)
```

```c#
public static void AddAutoReleaseAssetTrigger(AssetReference assetReference, GameObject targetGO)
```

```c#
public static void AddAutoReleaseInstanceTrigger(string key, GameObject targetGO)
```

```c#
public static void AddAutoReleaseInstanceTrigger(AssetReference assetReference, GameObject targetGO)
```

#### Short examples

```c#
ManageAddressables.InstantiateSyncWithAutoRelease(figureAssetRefGO);
Expand Down
17 changes: 8 additions & 9 deletions Runtime/ManageAddressables.Async.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#if !ADDRESSABLES_UNITASK
#if !USE_UNITASK

using System;
using System.Runtime.CompilerServices;
Expand Down Expand Up @@ -123,14 +123,6 @@ public static async Task<OperationResult<T>> LoadAssetAsync<T>(AssetReferenceT<T
}
}

private static async Task ActivateAsync(SceneInstance scene, int priority)
{
var operation = scene.ActivateAsync();
operation.priority = priority;

await operation;
}

public static async Task<OperationResult<SceneInstance>> LoadSceneAsync(string key,
LoadSceneMode loadMode = LoadSceneMode.Single,
bool activateOnLoad = true,
Expand Down Expand Up @@ -320,7 +312,14 @@ public static async Task<GameObject> InstantiateAsyncWithAutoRelease(

return instantiatedGO;
}

private static async Task ActivateAsync(SceneInstance scene, int priority)
{
var operation = scene.ActivateAsync();
operation.priority = priority;

await operation;
}
}

internal static partial class AsyncOperationExtensions
Expand Down
Loading

0 comments on commit 5b5a360

Please sign in to comment.