diff --git a/.github/workflows/toc.yml b/.github/workflows/toc.yml
new file mode 100644
index 0000000..c306eaf
--- /dev/null
+++ b/.github/workflows/toc.yml
@@ -0,0 +1,11 @@
+on: push
+name: TOC Generator
+jobs:
+ generateTOC:
+ name: TOC Generator
+ runs-on: ubuntu-latest
+ steps:
+ - uses: technote-space/toc-generator@v4
+ with:
+ FOLDING: true
+ TOC_TITLE: Details
diff --git a/Documentation/concept_01.png b/Documentation/concept_01.png
new file mode 100644
index 0000000..7e09730
Binary files /dev/null and b/Documentation/concept_01.png differ
diff --git a/Documentation/concept_02.png b/Documentation/concept_02.png
new file mode 100644
index 0000000..0a4819b
Binary files /dev/null and b/Documentation/concept_02.png differ
diff --git a/Documentation/setup_01.png b/Documentation/setup_01.png
new file mode 100644
index 0000000..e6b190f
Binary files /dev/null and b/Documentation/setup_01.png differ
diff --git a/README.md b/README.md
index 298927d..1eee97a 100644
--- a/README.md
+++ b/README.md
@@ -1,8 +1,43 @@
Addler
-Preloading, Pooling, Lifetime Management System for Unity Addressable Asset System.
+
+[](LICENSE.md)
+
+[日本語ドキュメント(Japanese Documents Available)](README_JA.md)
+
+Memory management system for Unity's Addressable Asset System.
+Provides lifetime management system for loaded resources, object pooling system, and preloading system.
+
+## Table of Contents
+
+
+
+
+Details
+
+- [Overview](#overview)
+- [Setup](#setup)
+ - [Requirement](#requirement)
+ - [Install](#install)
+- [Lifetime Binding](#lifetime-binding)
+ - [Bind to GameObject](#bind-to-gameobject)
+ - [Bind to non-GameObject](#bind-to-non-gameobject)
+- [Preloading](#preloading)
+ - [How to use Preloader](#how-to-use-preloader)
+ - [Use Preloader with Lifetime Binding](#use-preloader-with-lifetime-binding)
+ - [Limitations of Preloader](#limitations-of-preloader)
+- [Object Pooling](#object-pooling)
+ - [How to use Object Pooling](#how-to-use-object-pooling)
+ - [Use Object Pool with Lifetime Binding](#use-object-pool-with-lifetime-binding)
+- [Other](#other)
+ - [Disable Preloading / Object Pooling](#disable-preloading--object-pooling)
+ - [Use UniTask](#use-unitask)
+- [Licenses](#licenses)
+
+
+
## Overview
-In the Addressable Asset System, you must explicitly release loaded resources when they are no longer needed.
+In the Addressable Asset System, you need to explicitly release the loaded resources when they are no longer needed.
```cs
// Load.
@@ -13,9 +48,11 @@ await handle.Task;
Addressables.Release(handle);
```
-If you forget this, it will cause memory leaks and become a technical debt that will eventually lead to serious problems.
+If you forget to release, it can cause memory leaks and serious problems such as application crashes.
+However, such an implementation is easy to forget to release, and it is difficult to notice when you forget it.
-Addler simplifies memory management by binding resource lifetimes to GameObjects and other resources.
+**Addler** solves this problem by binding the lifetime of the loaded resource to a **GameObject**, for example, as follows.
+When the associated **GameObject** is destroyed, the resource is automatically released.
```cs
var fooObj = new GameObject();
@@ -25,215 +62,314 @@ var fooObj = new GameObject();
Addressables.LoadAssetAsync("BarPrefab").BindTo(fooObj);
```
-In the above code, the resource is released as soon as the `fooObj` is destroyed.
-
-Thus, you don't have to worry about forgetting to release it.
+In the above code, the resource is released as soon as the **fooObj** is destroyed.
-
+
-In addition, there is a preloader that preloads resources and get them synchronously, and also object pooling to reuse prefab instances.
+**Addler** also provides Preloading feature that preloads resources and gets them synchronously, and Object Pooling feature that pools prefab instances and uses them.
-
+
-Of course, these lifetimes can also be bound to GameObjects and other objects.
+Further, you can bind these lifetimes to **GameObjects** and so on to prevent forgetting to release them.
-In this way, Addler allows you to properly manage the lifetime of your Addressable Asset System resources.
+Thus, **Addler** is a library for proper memory management of resources in **Addressable***.
## Setup
-#### Requirement
-Unity 2019.3 or higher.
+### Requirement
+Unity 2020.3 or higher.
-#### Install
+### Install
1. Open the Package Manager from Window > Package Manager
2. "+" button > Add package from git URL
3. Enter the following
- * https://github.com/Haruma-K/Addler.git?path=/Packages/com.harumak.addler
+ - https://github.com/Haruma-K/Addler.git?path=/Assets/Addler
-
+
Or, open Packages/manifest.json and add the following to the dependencies block.
```json
{
- "dependencies": {
- "com.harumak.addler": "https://github.com/Haruma-K/Addler.git?path=/Packages/com.harumak.addler"
- }
+ "dependencies": {
+ "com.harumak.addler": "https://github.com/Haruma-K/Addler.git?path=/Assets/Addler"
+ }
}
```
If you want to set the target version, specify it like follow.
-* https://github.com/Haruma-K/Addler.git?path=/Packages/com.harumak.addler#0.1.0
-#### License
-This software is released under the MIT License.
-You are free to use it within the scope of the license.
-However, the following copyright and license notices are required for use.
-
-https://github.com/Haruma-K/Addler/blob/master/LICENSE.md
+- https://github.com/Haruma-K/Addler.git?path=/Assets/Addler#1.0.0
## Lifetime Binding
-To bind the lifetime of a resource loaded by Addressable, write `BindTo()` after `Addressables.LoadAsssetAsync()`.
+One of Addler's basic features is lifetime binding.
+This binds the lifetime of the resource to **GameObject** and so on, to release it automatically and reliably.
+
+### Bind to GameObject
+To bind the lifetime of the resource to **GameObject**, use the **BindTo** method as follows.
```cs
-// Load the asset and bind the handle's lifetime to the GameObject.
-var handle = Addressables.LoadAssetAsync("FooPrefab").BindTo(gameObject);
+// Load the resource and bind the lifetime to gameObject.
+var handle = Addressables
+ .LoadAssetAsync("FooPrefab")
+ .BindTo(gameObject);
await handle.Task;
var prefab = handle.Result;
-// Destroy the gameObject and release the bound handle.
+// Destroy gameObject and release the resource.
Destroy(gameObject);
```
-Now, the resource will be released as soon as the gameObject is destroyed.
-Note that lifetimes can also be bound to non-GameObject (see below).
+Now, the resource is released as soon as the gameObject is destroyed.
+
+### Bind to non-GameObject
+You can bind the lifetime to non-GameObject as well.
+To do so, create a class that implements `IReleaseEvent` interface and pass it to `BindTo` method.
+
+**Addler** provides the implementation of `IReleaseEvent` for the ParticleSystem.
+As the example of `IReleaseEvent` implementation, show it below.
+
+```cs
+using System;
+using Addler.Runtime.Core.LifetimeBinding;
+using UnityEngine;
+
+[RequireComponent(typeof(ParticleSystem))]
+public sealed class ParticleSystemBasedReleaseEvent : MonoBehaviour, IReleaseEvent // Implement IReleaseEvent
+{
+ [SerializeField] private ParticleSystem particle;
+ private bool _isAliveAtLastFrame;
+
+ private void Awake()
+ {
+ if (particle == null)
+ particle = GetComponent();
+ }
+
+ private void Reset()
+ {
+ particle = GetComponent();
+ }
+
+ private void LateUpdate()
+ {
+ var isAlive = particle.IsAlive(true);
+ if (_isAliveAtLastFrame && !isAlive)
+ ReleasedInternal?.Invoke();
+
+ _isAliveAtLastFrame = isAlive;
+ }
+
+ event Action IReleaseEvent.Dispatched
+ {
+ add => ReleasedInternal += value;
+ remove => ReleasedInternal -= value;
+ }
+
+ private event Action ReleasedInternal;
+}
+```
## Preloading
-Addressables only provides an API to load resources asynchronously.
+In Addressable Asset System, resources are loaded asynchronously.
```cs
-// Load asyncronously.
-var handle = Addressables.LoadAssetAsync("FooPrefab");
+// Asynchronous loading
+var handle = Addressables.LoadAssetAsync("fooPrefab");
await handle.Task;
```
-However, in reality, in most cases you will want to load resources in advance at the "Loading Screen" and load them synchronously during the game.
-The preloader does this.
+However, in some cases, you want to get pre-loaded resources synchronously.
+You can do this with preloader.
-#### How to use Preloader
-To use the preloader, instantiate the `AddressablesPreloader` class.
+### How to use Preloader
+The preloading feature is provided by the **Preloader** class.
+Below is an example of how to use it.
```cs
-// Create the preloader.
-var preloader = new AddressablesPreloader();
+using System;
+using System.Collections;
+using Addler.Runtime.Core.Preloading;
+using UnityEngine;
+
+public sealed class Example : MonoBehaviour
+{
+ private IEnumerator PreloadExample()
+ {
+ var preloader = new AddressablePreloader();
+
+ // Preload
+ {
+ var progress = new Progress(x => Debug.Log($"Progress: {x}"));
+
+ // Preload by address.
+ yield return preloader.PreloadKey("fooAddress", progress);
+
+ // You can also preload by label.
+ yield return preloader.PreloadKey("fooLabel", progress);
-// Preload resources.
-await preloader.PreloadAsync("FooPrefab", "BarPrefab");
+ // You can also preload multiple keys at once.
+ yield return preloader.PreloadKeys(new[] { "barAddress", "bazAddress" }, progress);
+ }
-// Get preloaded resourcdes synchronously.
-var fooPrefab = preloader.Get("FooPrefab");
-var barPrefab = preloader.Get("BarPrefab");
+ // Get the preloaded object.
+ {
+ // Get by address.
+ preloader.GetAsset("fooAddress");
-// Release all.
-preloader.Dispose();
+ // Get multiple assets by label.
+ preloader.GetAssets("fooLabel");
+ }
+
+ // Dispose the preloader and release all the assets.
+ preloader.Dispose();
+ }
+}
```
-You can preload a resource by passing its address to `AddressablesPreloader.PreloadAsync()`.
-And you can get the preloaded resources synchronously by `AddressablesPreloader.Get()` method.
+You can preload resources of the keys in the argument by calling `AddressablePreloader.PreloadKey()/PreloadKeys()`.
+And you can get the preloaded resources synchronously by `AddressablesPreloader.GetAsset()` method.
-When you are done using the preloader, call `AddressablesPool.Dispose()` to release all the resources.
+And all resources are released by `AddressablePreloader.Dispose()` method.
-#### Preloader Lifetime Binding
+### Use Preloader with Lifetime Binding
You can also bind the lifetime of the preloader.
```cs
-// Bind the lifetime of the preloader.
-var preloader = new AddressablesPreloader().BindTo(gameObject);
+// Bind the lifetime of the preloader to the GameObject.
+// When gameObject is destroyed, the preloader will be disposed and release all the assets.
+var preloader = new AddressablePreloader().BindTo(gameObject);
```
All resources will be released when the preloader lifetime expires.
+### Limitations of Preloader
+As a rule for preloading, the "key type specified at preloading" and the "key type specified when retrieving the preloaded resource" must match.
+
+For example, if label A, which contains the assets at address A, is specified at the time of preloading, label A must also be specified at the time of retrieving.
+It is not possible to specify address A.
+
+This is because, due to the specification of Addressable Asset System, there is no way to synchronously retrieve the key (Primary Key) pointed to by the address, label, or AssetReference.
+
+If you want to support this case, you can use [Synchronous Workflow](https://docs.unity3d.com/Packages/com.unity.addressables@1.21/manual/SynchronousAddressables.html) that is added in Addressable Asset System 1.17.1.
+However, this feature waits synchronously until all running **AsyncOperations** are finished, so be careful when using it.
+
## Object Pooling
-Unity games often use GameObjects instantiated from prefabs.
-However, instantiating and destroying is expensive, and if done too often, it can take time to process.
+Unity uses manu GAmeObjects instantiated from Prefabs.
+However, instantiating and destroying is expensive, so they often cause performance problems.
-Let's consider a case where many instances of the same prefab are created, like bullets.
-In such a case, we can reduce the processing load by using several instances created in advance.
+In cases where many instances of the same Prefab are created, such as bullets, it is possible to prevent performance degradation by creating a certain number of instances in advance and using them.
This is called object pooling.
-
+
-#### How to use Object Pooling
-To use the object pool, instantiate the `AddressablesPool` class.
+### How to use Object Pooling
+The preloading feature is provided by the `AddressablePool` class.
+Below is an example of how to use it.
```cs
-// Create the pool of the FooPrefab.
-var pool = new AddressablesPool("FooPrefab");
+using System;
+using System.Collections;
+using Addler.Runtime.Core.Pooling;
+using UnityEngine;
-// Create the instances.
-await pool.WarmupAsync(5);
+public sealed class Example : MonoBehaviour
+{
+ private IEnumerator PoolExample()
+ {
+ // Create a new pool with key of the GameObject.
+ var pool = new AddressablePool("fooPrefab");
-// Get the instance from the pool.
-var operation= pool.Use();
-var instance = operation.Object;
+ // Create instances in the pool.
+ var progress = new Progress(x => Debug.Log($"Progress: {x}"));
+ yield return pool.Warmup(5, progress);
-// Return the instance to the pool.
-operation.Dispose();
+ // Get an instance from the pool.
+ var pooledObject = pool.Use();
+ var instance = pooledObject.Instance;
-// Destroy and release all the instances.
-pool.Dispose();
+ // Return the instance to the pool.
+ pool.Return(pooledObject);
+ //pooledObject.Dispose(); // You can also return the instance by disposing the pooled object.
+
+ // Destroy the pool and release all instances.
+ pool.Dispose();
+ }
+}
```
-When you call `AddressablesPool.WarmupAsync()`, as many instances of prefab as you pass in the argument will be created.
-To get an instance from the pool, use the `AddressablesPool.Use()` method to get the `PooledObjectOperation`.
-You can get an instance from the `Object` property of this.
-To return the instance to the pool, call `PooledObjectOperation.Dispose()`.
+When you call `AddressablePool.WarmupAsync()`, as many instances of prefab as you pass in the argument will be created.
+To get an instance from the pool, use the `AddressablePool.Use()` method to get the `PooledObject`.
+You can get an instance from the `Instance` property of this.
+To return the instance to the pool, call `AddressablePool.Return()` or `PooledObject.Dispose()`.
-When the pool is no longer needed, dispose it with `AddressablesPool.Dispose()`.
-All instances will be destroyed and the resource will be released.
+When the pool is no longer needed, call `AddressablePool.Dispose()`.
+All instances will be destroyed and the resources will be released.
-#### Object Pool Lifetime Binding
-You can also bind the lifetime of the object pool and the lifetime of objects retrieved from the pool.
+### Use Object Pool with Lifetime Binding
+You can also bind the lifetime of the object pool and the lifetime of instances retrieved from it.
```cs
-// Bind the lifetime of the pool.
-var pool = new AddressablesPool("FooPrefab").BindTo(gameObject1);
-
-await pool.WarmupAsync(5);
+using System.Collections;
+using Addler.Runtime.Core.Pooling;
+using UnityEngine;
-// Bind the lifetime of the instance.
-// If the gameObject2 is destroyed, the instance will be returned to the pool.
-var instance = pool.Use().BindTo(gameObject2).Object;
+public sealed class Example : MonoBehaviour
+{
+ private IEnumerator PoolExample()
+ {
+ // Bind the lifetime of the pool to GameObject.
+ // If gameObject1 is destroyed, the pool will be disposed.
+ var pool = new AddressablePool("FooPrefab")
+ .BindTo(gameObject1);
+
+ yield return pool.Warmup(5);
+
+ // Bind the lifetime of the instance to GameObject.
+ // If gameObject2 is destroyed, the instance will be returned to the pool.
+ var instance = pool
+ .Use()
+ .BindTo(gameObject2)
+ .Instance;
+ }
+}
```
-When the lifetime of an object retrieved from the pool expires, it will be returned to the pool.
+When the lifetime of an instance expires, it will be returned to the pool.
When the lifetime of the object pool expires, all instances will be destroyed and released.
-## Bind to Non-GameObject
-You can also bind the lifetime to a non-GameObject.
-To bind it to a non-GameObject, create a class that implements IEventDispatcher and pass it to `BindTo()`.
+## Other
-Addler has a class for binding the lifetime to the end timing of ParticleSystem.
-As an example implementation of IEventDispatcher, this class is shown below.
+### Disable Preloading / Object Pooling
+If you do not use Preloading or Object Pooling, you can disable them and exclude them from the compilation.
+To disable them, set the following **Scripting Define Symbols** in the **Player Settings**.
-```cs
-using System;
-using UnityEngine;
+- **ADDLER_DISABLE_PRELOADING** : Disable Preloading.
+- **ADDLER_DISABLE_POOLING** : Disable Object Pooling.
-namespace Addler.Runtime.Foundation.EventDispatcher
-{
- [RequireComponent(typeof(ParticleSystem))]
- public class ParticleSystemFinishedEventDispatcher : MonoBehaviour, IEventDispatcher // Implement IEventDispatcher
- {
- private bool _isAliveAtLastFrame;
- private ParticleSystem _particleSystem;
+### Use UniTask
+In Preloading / Object Pooling, you can use coroutine to wait for the asynchronous operation.
+You can use UniTask too
- private void Awake()
- {
- _particleSystem = GetComponent();
- }
+1. Install [UniTask](https://github.com/Cysharp/UniTask).(There are several ways to install.)
+2. (Only if you install 1. not via Package Manager) Add `ADDLER_UNITASK_SUPPORT` to **Scripting Define Symbols** and restart Unity.
+3. Now you can use the **UniTask** version methods such as `AddressablePool.WarmupAsync`.
- private void LateUpdate()
- {
- var isAlive = _particleSystem.IsAlive(true);
- if (_isAliveAtLastFrame && !isAlive)
- {
- // Call OnDispatch when the ParticleSystem is finished.
- OnDispatch?.Invoke();
- }
-
- _isAliveAtLastFrame = isAlive;
- }
+## Licenses
+This software is released under the MIT License. You are free to use it within the scope of the license, but the following copyright and license notices must be displayed when using it.
- public event Action OnDispatch;
- }
-}
-```
+* [LICENSE.md](LICENSE.md)
+
+In addition, the table of contents of this document was created using the following software
+
+* [toc-generator](https://github.com/technote-space/toc-generator)
+
+See [Third Party Notices.md](Third%20Party%20Notices.md) for details on these licenses.
diff --git a/README_JA.md b/README_JA.md
new file mode 100644
index 0000000..28963a6
--- /dev/null
+++ b/README_JA.md
@@ -0,0 +1,381 @@
+Addler
+
+[](LICENSE.md)
+
+[English Documents Available(英語ドキュメント)](README.md)
+
+Unity の Addressable アセットシステムのためのメモリ管理システムです。
+ロードしたリソースのライフタイム管理、オブジェクトプーリング、プリローディング機能を提供します。
+
+## 目次
+
+
+
+
+
+詳細
+
+- [概要とコンセプト](#%E6%A6%82%E8%A6%81%E3%81%A8%E3%82%B3%E3%83%B3%E3%82%BB%E3%83%97%E3%83%88)
+- [セットアップ](#%E3%82%BB%E3%83%83%E3%83%88%E3%82%A2%E3%83%83%E3%83%97)
+ - [要件](#%E8%A6%81%E4%BB%B6)
+ - [インストール](#%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB)
+- [ライフタイムバインディング](#%E3%83%A9%E3%82%A4%E3%83%95%E3%82%BF%E3%82%A4%E3%83%A0%E3%83%90%E3%82%A4%E3%83%B3%E3%83%87%E3%82%A3%E3%83%B3%E3%82%B0)
+ - [GameObjectにバインディングする](#gameobject%E3%81%AB%E3%83%90%E3%82%A4%E3%83%B3%E3%83%87%E3%82%A3%E3%83%B3%E3%82%B0%E3%81%99%E3%82%8B)
+ - [GameObject以外にバインディングする](#gameobject%E4%BB%A5%E5%A4%96%E3%81%AB%E3%83%90%E3%82%A4%E3%83%B3%E3%83%87%E3%82%A3%E3%83%B3%E3%82%B0%E3%81%99%E3%82%8B)
+- [プリローディング](#%E3%83%97%E3%83%AA%E3%83%AD%E3%83%BC%E3%83%87%E3%82%A3%E3%83%B3%E3%82%B0)
+ - [プリローダの使い方](#%E3%83%97%E3%83%AA%E3%83%AD%E3%83%BC%E3%83%80%E3%81%AE%E4%BD%BF%E3%81%84%E6%96%B9)
+ - [プリローダのライフタイムをバインディングする](#%E3%83%97%E3%83%AA%E3%83%AD%E3%83%BC%E3%83%80%E3%81%AE%E3%83%A9%E3%82%A4%E3%83%95%E3%82%BF%E3%82%A4%E3%83%A0%E3%82%92%E3%83%90%E3%82%A4%E3%83%B3%E3%83%87%E3%82%A3%E3%83%B3%E3%82%B0%E3%81%99%E3%82%8B)
+ - [プリローディングの制約](#%E3%83%97%E3%83%AA%E3%83%AD%E3%83%BC%E3%83%87%E3%82%A3%E3%83%B3%E3%82%B0%E3%81%AE%E5%88%B6%E7%B4%84)
+- [オブジェクトプーリング](#%E3%82%AA%E3%83%96%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88%E3%83%97%E3%83%BC%E3%83%AA%E3%83%B3%E3%82%B0)
+ - [オブジェクトプーリングの使い方](#%E3%82%AA%E3%83%96%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88%E3%83%97%E3%83%BC%E3%83%AA%E3%83%B3%E3%82%B0%E3%81%AE%E4%BD%BF%E3%81%84%E6%96%B9)
+ - [オブジェクトプールのライフタイムをバインディングする](#%E3%82%AA%E3%83%96%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88%E3%83%97%E3%83%BC%E3%83%AB%E3%81%AE%E3%83%A9%E3%82%A4%E3%83%95%E3%82%BF%E3%82%A4%E3%83%A0%E3%82%92%E3%83%90%E3%82%A4%E3%83%B3%E3%83%87%E3%82%A3%E3%83%B3%E3%82%B0%E3%81%99%E3%82%8B)
+- [その他](#%E3%81%9D%E3%81%AE%E4%BB%96)
+ - [プリローディングやオブジェクトプーリングを無効化する](#%E3%83%97%E3%83%AA%E3%83%AD%E3%83%BC%E3%83%87%E3%82%A3%E3%83%B3%E3%82%B0%E3%82%84%E3%82%AA%E3%83%96%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88%E3%83%97%E3%83%BC%E3%83%AA%E3%83%B3%E3%82%B0%E3%82%92%E7%84%A1%E5%8A%B9%E5%8C%96%E3%81%99%E3%82%8B)
+ - [UniTaskを使う](#unitask%E3%82%92%E4%BD%BF%E3%81%86)
+- [ライセンス](#%E3%83%A9%E3%82%A4%E3%82%BB%E3%83%B3%E3%82%B9)
+
+
+
+
+## 概要とコンセプト
+Addressable アセットシステムでは、ロードしたリソースが不要になったら明示的に解放をする必要があります。
+
+```cs
+// ロードする
+var handle = Addressables.LoadAssetAsync("FooPrefab");
+await handle.Task;
+
+// ロードしたアセットを使用する
+var prefab = handle.Result;
+
+// 不要になったらリリースする
+Addressables.Release(handle);
+```
+
+これを忘れるとメモリリークの原因となり、アプリケーションのクラッシュなど深刻な問題に繋がります。
+しかしながら、上記のような実装では、解放を忘れやすく、また忘れた時に気づきづらいという問題があります。
+
+**Addler** ではこの問題に対応するため、以下のようにリソースのライフタイムを **GameObject** などに紐づけます。
+紐づけた **GameObject** が破棄されると、リソースが自動的に解放されます。
+
+```cs
+var fooObj = new GameObject();
+
+// fooObjにリソースのライフタイムを結びつける
+// fooObjがDestroyされると同時にリソースもリリースされる
+Addressables.LoadAssetAsync("BarPrefab").BindTo(fooObj);
+```
+
+上記のコードでは、`fooObj`が破棄されると同時にリソースが解放されます。
+こうしておけば解放を忘れる心配はありません。
+
+
+
+
+
+またリソースを事前にロードしておき同期的にそれを取得するプリロード機能や、Prefabのインスタンスをプーリングして使いまわすオブジェクトプーリング機能も実装しています。
+
+
+
+
+
+さらにこれらのライフタイムも **GameObject** などにバインドし、解放漏れを防ぐことができます。
+
+**Addler** はこのようにして **Addressable** におけるリソースのメモリを適切に管理するためのライブラリです。
+
+## セットアップ
+
+### 要件
+- Unity 2020.3 以上
+
+### インストール
+1. Window > Package ManagerからPackage Managerを開く
+2. 「+」ボタン > Add package from git URL
+3. 以下を入力してインストール
+ - https://github.com/Haruma-K/Addler.git?path=/Assets/Addler
+
+
+
+
+
+あるいはPackages/manifest.jsonを開き、dependenciesブロックに以下を追記します。
+
+```json
+{
+ "dependencies": {
+ "com.harumak.addler": "https://github.com/Haruma-K/Addler.git?path=/Assets/Addler"
+ }
+}
+```
+
+バージョンを指定したい場合には以下のように末尾にバージョンを指定します。
+
+- https://github.com/Haruma-K/Addler.git?path=/Assets/Addler#1.0.0
+
+## ライフタイムバインディング
+
+**Addler** の基本的な機能として、リソースのライフタイムを **GameObject** などと紐づけて、確実かつ自動的に解放処理を行うライフタイムバインディングがあります。
+
+### GameObjectにバインディングする
+**Addressable** で読み込んだリソースのライフタイムを **GameObject** と紐づけるには、以下のように`Addressables.LoadAsssetAsync()`の後ろに`BindTo()`と記述します。
+
+```cs
+// リソースをロードしてハンドルのライフタイムをgameObjectにバインドする
+var handle = Addressables
+ .LoadAssetAsync("FooPrefab")
+ .BindTo(gameObject);
+await handle.Task;
+var prefab = handle.Result;
+
+// gameObjectを破棄してハンドルをリリースする
+Destroy(gameObject);
+```
+
+これで、gameObjectが破棄されると同時にリソースが解放されます。
+
+### GameObject以外にバインディングする
+
+ライフタイムは **GameObject** 以外にバインドすることもできます。**GameObject** 以外にバインドするためには `IReleaseEvent` を実装したクラスを作成し、`BindTo()`にそれを渡します。
+
+**Addler** には **ParticleSystem** の終了タイミングにライフタイムをバインドするためのクラスを用意しています。`IReleaseEvent` の実装例として以下にこのクラスの実装を示します。
+
+```cs
+using System;
+using Addler.Runtime.Core.LifetimeBinding;
+using UnityEngine;
+
+[RequireComponent(typeof(ParticleSystem))]
+public sealed class ParticleSystemBasedReleaseEvent : MonoBehaviour, IReleaseEvent // Implement IReleaseEvent
+{
+ [SerializeField] private ParticleSystem particle;
+ private bool _isAliveAtLastFrame;
+
+ private void Awake()
+ {
+ if (particle == null)
+ particle = GetComponent();
+ }
+
+ private void Reset()
+ {
+ particle = GetComponent();
+ }
+
+ private void LateUpdate()
+ {
+ var isAlive = particle.IsAlive(true);
+ if (_isAliveAtLastFrame && !isAlive)
+ ReleasedInternal?.Invoke();
+
+ _isAliveAtLastFrame = isAlive;
+ }
+
+ event Action IReleaseEvent.Dispatched
+ {
+ add => ReleasedInternal += value;
+ remove => ReleasedInternal -= value;
+ }
+
+ private event Action ReleasedInternal;
+}
+```
+
+## プリローディング
+Addressables は基本的にリソースを非同期的にロードします。
+
+```cs
+// Asynchronous loading
+var handle = Addressables.LoadAssetAsync("fooPrefab");
+await handle.Task;
+```
+
+しかし実際には、いわゆるロード画面で事前にリソースをロードして、ゲーム中は同期的にリソースをロードしたいというケースがあります。
+プリローダはこのような処理を実現するための機能です。
+
+### プリローダの使い方
+プリロードは `AddressablePreloader` クラスにより行います。
+使い方は以下のコードの通りです。
+
+```cs
+using System;
+using System.Collections;
+using Addler.Runtime.Core.Preloading;
+using UnityEngine;
+
+public sealed class Example : MonoBehaviour
+{
+ private IEnumerator PreloadExample()
+ {
+ var preloader = new AddressablePreloader();
+
+ // Preload
+ {
+ var progress = new Progress(x => Debug.Log($"Progress: {x}"));
+
+ // Preload by address.
+ yield return preloader.PreloadKey("fooAddress", progress);
+
+ // You can also preload by label.
+ yield return preloader.PreloadKey("fooLabel", progress);
+
+ // You can also preload multiple keys at once.
+ yield return preloader.PreloadKeys(new[] { "barAddress", "bazAddress" }, progress);
+ }
+
+ // Get the preloaded object.
+ {
+ // Get by address.
+ preloader.GetAsset("fooAddress");
+
+ // Get multiple assets by label.
+ preloader.GetAssets("fooLabel");
+ }
+
+ // Dispose the preloader and release all the assets.
+ preloader.Dispose();
+ }
+}
+```
+
+`AddressablePreloader.PreloadKey()/PreloadKeys()`を呼ぶと引数に渡したキーが指すリソースを全てロードします。
+`AddressablesPreloader.GetAsset()` メソッドを使うとプリロードしたリソースを同期的に取得できます。
+
+プリローダを使用し終わったら`AddressablePool.Dispose()`を呼ぶことですべてのリソースがリリースされます。
+
+### プリローダのライフタイムをバインディングする
+プリローダのライフタイムをバインドすることもできます。
+
+```cs
+// Bind the lifetime of the preloader to the GameObject.
+// When gameObject is destroyed, the preloader will be disposed and release all the assets.
+var preloader = new AddressablePreloader().BindTo(gameObject);
+```
+
+プリローダのライフタイムが終了するとすべてのリソースがリリースされます。
+
+### プリローディングの制約
+
+プリローディングの制約として、「プリロード時に指定したキーの種類」と「プリロードされたリソースを取得する際に指定したキーの種類」が一致している必要があります。
+例えば、アドレスAのアセットを含むラベルAをプリロード時に指定した場合、取得時にもラベルAを指定する必要があります。
+アドレスAを指定して取得することはできません。
+
+これは、**Addressable** アセットシステムの仕様上、アドレスやラベル、**AssetReference** が指すリソースのキー (PrimaryKey) を同期的に取得する手段がないためです。
+
+もしこのようなケースに対応したい場合は **Addressables 1.17.1** からサポートされた [Synchronous Workflow](https://docs.unity3d.com/Packages/com.unity.addressables@1.21/manual/SynchronousAddressables.html) を使用することができます。
+ただしこれには実行中の全ての **AsyncOperation** が終わるまで同期的に待つという仕様上の制約があるため、使用する際には注意が必要です。
+
+## オブジェクトプーリング
+Unity のゲームでは Prefab をインスタンス化した GameObject が多数使われます。
+しかし Prefab のインスタンス生成や破棄にはコストがかかり、頻繁に行いすぎるとパフォーマンスの低下を招きます。
+
+例えば弾丸のように同じ Prefab のインスタンスを多数生成するようなケースでは、一定数のインスタンスをあらかじめ生成しておいてそれらを使いまわすことによりパフォーマンスの低下を防ぐことができます。
+これをオブジェクトプーリングと呼びます。
+
+
+
+
+
+**Addler** には Addressable アセットシステムでオブジェクトプーリングを扱うための機能が実装されています。
+
+### オブジェクトプーリングの使い方
+オブジェクトプールは`AddressablePool`クラスにより行います。
+使い方は以下のコードの通りです。
+
+```cs
+using System;
+using System.Collections;
+using Addler.Runtime.Core.Pooling;
+using UnityEngine;
+
+public sealed class Example : MonoBehaviour
+{
+ private IEnumerator PoolExample()
+ {
+ // Create a new pool with key of the GameObject.
+ var pool = new AddressablePool("fooPrefab");
+
+ // Create instances in the pool.
+ var progress = new Progress(x => Debug.Log($"Progress: {x}"));
+ yield return pool.Warmup(5, progress);
+
+ // Get an instance from the pool.
+ var pooledObject = pool.Use();
+ var instance = pooledObject.Instance;
+
+ // Return the instance to the pool.
+ pool.Return(pooledObject);
+ //pooledObject.Dispose(); // You can also return the instance by disposing the pooled object.
+
+ // Destroy the pool and release all instances.
+ pool.Dispose();
+ }
+}
+```
+
+`AddressablePool.Warmup()`を呼ぶと引数に渡した数だけ Prefab のインスタンスが生成されます。
+プールからインスタンスを取得するには`AddressablePool.Use()`メソッドで`PooledObject`を取得します。
+これの`Instance`プロパティからインスタンスを取得できます。
+`AddressablePool.Return` あるいは `PooledObject.Dispose()`メソッドを呼ぶとインスタンスがプールに戻ります。
+
+プールを使用し終わったら`AddressablePool.Dispose()`でプールを破棄してください。
+全てのインスタンスが破棄。解放されます。
+
+### オブジェクトプールのライフタイムをバインディングする
+オブジェクトプールや、プールから取得したオブジェクトのライフタイムをバインドすることもできます。
+
+```cs
+using System.Collections;
+using Addler.Runtime.Core.Pooling;
+using UnityEngine;
+
+public sealed class Example : MonoBehaviour
+{
+ private IEnumerator PoolExample()
+ {
+ // Bind the lifetime of the pool to GameObject.
+ // If gameObject1 is destroyed, the pool will be disposed.
+ var pool = new AddressablePool("FooPrefab")
+ .BindTo(gameObject1);
+
+ yield return pool.Warmup(5);
+
+ // Bind the lifetime of the instance to GameObject.
+ // If gameObject2 is destroyed, the instance will be returned to the pool.
+ var instance = pool
+ .Use()
+ .BindTo(gameObject2)
+ .Instance;
+ }
+}
+```
+
+プールから取得したオブジェクトのライフタイムが終了するとプールに返却され、オブジェクトプールのライフタイムが終了するとすべてのインスタンスが破棄・リリースされます。
+
+## その他
+
+### プリローディングやオブジェクトプーリングを無効化する
+**Addler** の機能のうち、プリローディングやオブジェクトプーリングを使用しない場合には、それらを無効化し、コンパイル対象から外すことができます。
+無効化は **Player Settings** から以下の **Scripting Define Symbols** を設定することで行います。
+
+- **ADDLER_DISABLE_PRELOADING** : プリローディングを無効化する
+- **ADDLER_DISABLE_POOLING** : オブジェクトプーリングを無効化する
+
+### UniTaskを使う
+プリローディングやオブジェクトプーリングでは、コルーチンを使って非同期処理を待機します。
+コルーチンの代わりにUniTaskを使いたい場合には以下の設定を行います。
+
+1. [UniTask](https://github.com/Cysharp/UniTask) をインストールする(複数のインストール方法があります)
+2. (Package Manager を経由しない方法で1.をインストールした場合のみ)**Scripting Define Symbols** に `ADDLER_UNITASK_SUPPORT` を追加して Unity を再起動する
+3. `AddressablePool.WarmupAsync`などコルーチンを使っていたメソッドの **UniTask** 版が **Async** という接尾辞と共に使用可能になります
+
+## ライセンス
+本ソフトウェアはMITライセンスで公開しています。
+ライセンスの範囲内で自由に使っていただけますが、使用の際は以下の著作権表示とライセンス表示が必須となります。
+
+* [LICENSE.md](LICENSE.md)
+
+また、本ドキュメントの目次は以下のソフトウェアを使用して作成されています。
+
+* [toc-generator](https://github.com/technote-space/toc-generator)
+
+toc-generatorのライセンスの詳細は [Third Party Notices.md](Third%20Party%20Notices.md) を参照してください。
diff --git a/Third Party Notices.md b/Third Party Notices.md
new file mode 100644
index 0000000..8f56c8b
--- /dev/null
+++ b/Third Party Notices.md
@@ -0,0 +1,26 @@
+The table of contents for README is created by the following software.
+---------
+
+toc-generator (https://github.com/technote-space/toc-generator)
+
+The MIT License (MIT)
+
+Copyright (c) 2019 Technote
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.