{"id":13662374,"url":"https://github.com/Haruma-K/Addler","last_synced_at":"2025-04-25T10:31:01.564Z","repository":{"id":42457287,"uuid":"336805853","full_name":"Haruma-K/Addler","owner":"Haruma-K","description":"Memory management system for Unity's Addressable Asset System. Provides lifetime management system for loaded resources, object pooling system, and preloading system.","archived":false,"fork":false,"pushed_at":"2024-02-03T09:13:11.000Z","size":6779,"stargazers_count":265,"open_issues_count":0,"forks_count":21,"subscribers_count":6,"default_branch":"master","last_synced_at":"2024-11-09T18:03:34.769Z","etag":null,"topics":["addressable","addressables","objectpooling","preloading","unity"],"latest_commit_sha":null,"homepage":"","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Haruma-K.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-02-07T14:24:29.000Z","updated_at":"2024-10-17T14:28:53.000Z","dependencies_parsed_at":"2024-08-02T05:13:30.987Z","dependency_job_id":"412be510-6ce2-4527-8eba-277d0d0220c9","html_url":"https://github.com/Haruma-K/Addler","commit_stats":null,"previous_names":[],"tags_count":2,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Haruma-K%2FAddler","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Haruma-K%2FAddler/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Haruma-K%2FAddler/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Haruma-K%2FAddler/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Haruma-K","download_url":"https://codeload.github.com/Haruma-K/Addler/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":223996554,"owners_count":17238327,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["addressable","addressables","objectpooling","preloading","unity"],"created_at":"2024-08-02T05:01:56.934Z","updated_at":"2024-11-10T18:30:16.111Z","avatar_url":"https://github.com/Haruma-K.png","language":"C#","readme":"\u003ch1 align=\"center\"\u003eAddler\u003c/h1\u003e\n\n[![license](https://img.shields.io/badge/LICENSE-MIT-green.svg)](LICENSE.md)\n\n[日本語ドキュメント(Japanese Documents Available)](README_JA.md)\n\nMemory management system for Unity's Addressable Asset System.\nProvides lifetime management system for loaded resources, object pooling system, and preloading system.\n\n## Table of Contents\n\n\u003c!-- START doctoc generated TOC please keep comment here to allow auto update --\u003e\n\u003c!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE --\u003e\n\u003cdetails\u003e\n\u003csummary\u003eDetails\u003c/summary\u003e\n\n- [Overview](#overview)\n- [Setup](#setup)\n  - [Requirement](#requirement)\n  - [Install](#install)\n- [Lifetime Binding](#lifetime-binding)\n  - [Bind to GameObject](#bind-to-gameobject)\n  - [Bind to non-GameObject](#bind-to-non-gameobject)\n- [Preloading](#preloading)\n  - [How to use Preloader](#how-to-use-preloader)\n  - [Use Preloader with Lifetime Binding](#use-preloader-with-lifetime-binding)\n  - [Limitations of Preloader](#limitations-of-preloader)\n- [Object Pooling](#object-pooling)\n  - [How to use Object Pooling](#how-to-use-object-pooling)\n  - [Use Object Pool with Lifetime Binding](#use-object-pool-with-lifetime-binding)\n- [Other](#other)\n  - [Disable Preloading / Object Pooling](#disable-preloading--object-pooling)\n  - [Use UniTask](#use-unitask)\n- [Licenses](#licenses)\n\n\u003c/details\u003e\n\u003c!-- END doctoc generated TOC please keep comment here to allow auto update --\u003e\n\n## Overview\nIn the Addressable Asset System, you need to explicitly release the loaded resources when they are no longer needed.\n\n```cs\n// Load.\nvar handle = Addressables.LoadAssetAsync\u003cGameObject\u003e(\"FooPrefab\");\nawait handle.Task;\n\n// Release.\nAddressables.Release(handle);\n```\n\nIf you forget to release, it can cause memory leaks and serious problems such as application crashes.\nHowever, such an implementation is easy to forget to release, and it is difficult to notice when you forget it.\n\n**Addler** solves this problem by binding the lifetime of the loaded resource to a **GameObject**, for example, as follows.\nWhen the associated **GameObject** is destroyed, the resource is automatically released.\n\n```cs\nvar fooObj = new GameObject();\n\n// Load and bind the lifetime of the resource to fooObj.\n// The asset will be released at the same time the fooObj is destroyed.\nAddressables.LoadAssetAsync\u003cGameObject\u003e(\"BarPrefab\").BindTo(fooObj);\n```\n\nIn the above code, the resource is released as soon as the **fooObj** is destroyed.\n\n\u003cp align=\"center\"\u003e\n  \u003cimg width=80% src=\"Documentation/concept_01.png\" alt=\"Lifetime Binding\"\u003e\n\u003c/p\u003e\n\n**Addler** also provides Preloading feature that preloads resources and gets them synchronously, and Object Pooling feature that pools prefab instances and uses them.\n\n\u003cp align=\"center\"\u003e\n  \u003cimg width=80% src=\"Documentation/concept_02.png\" alt=\"Pooling\"\u003e\n\u003c/p\u003e\n\nFurther, you can bind these lifetimes to **GameObjects** and so on to prevent forgetting to release them.\n\nThus, **Addler** is a library for proper memory management of resources in **Addressable***.\n\n## Setup\n\n### Requirement\n* Unity 2020.3 or higher.\n* Addressables is installed.\n\n### Install\n1. Open the Package Manager from Window \u003e Package Manager\n2. \"+\" button \u003e Add package from git URL\n3. Enter the following\n   - https://github.com/Haruma-K/Addler.git?path=/Assets/Addler\n\n\u003cp align=\"center\"\u003e\n  \u003cimg width=50% src=\"Documentation/setup_01.png\" alt=\"Package Manager\"\u003e\n\u003c/p\u003e\n\nOr, open Packages/manifest.json and add the following to the dependencies block.\n\n```json\n{\n   \"dependencies\": {\n      \"com.harumak.addler\": \"https://github.com/Haruma-K/Addler.git?path=/Assets/Addler\"\n   }\n}\n```\n\nIf you want to set the target version, specify it like follow.\n\n- https://github.com/Haruma-K/Addler.git?path=/Assets/Addler#1.0.0\n\n## Lifetime Binding\nOne of Addler's basic features is lifetime binding.\nThis binds the lifetime of the resource to **GameObject** and so on, to release it automatically and reliably.\n\n### Bind to GameObject\nTo bind the lifetime of the resource to **GameObject**, use the **BindTo** method as follows.\n\n```cs\n// Load the resource and bind the lifetime to gameObject.\nvar handle = Addressables\n    .LoadAssetAsync\u003cGameObject\u003e(\"FooPrefab\")\n    .BindTo(gameObject);\nawait handle.Task;\nvar prefab = handle.Result;\n\n// Destroy gameObject and release the resource.\nDestroy(gameObject);\n```\n\nNow, the resource is released as soon as the gameObject is destroyed.\n\n### Bind to non-GameObject\nYou can bind the lifetime to non-GameObject as well.\nTo do so, create a class that implements `IReleaseEvent` interface and pass it to `BindTo` method.\n\n**Addler** provides the implementation of `IReleaseEvent` for the ParticleSystem.\nAs the example of `IReleaseEvent` implementation, show it below.\n\n```cs\nusing System;\nusing Addler.Runtime.Core.LifetimeBinding;\nusing UnityEngine;\n\n[RequireComponent(typeof(ParticleSystem))]\npublic sealed class ParticleSystemBasedReleaseEvent : MonoBehaviour, IReleaseEvent // Implement IReleaseEvent\n{\n    [SerializeField] private ParticleSystem particle;\n    private bool _isAliveAtLastFrame;\n\n    private void Awake()\n    {\n        if (particle == null)\n            particle = GetComponent\u003cParticleSystem\u003e();\n    }\n\n    private void Reset()\n    {\n        particle = GetComponent\u003cParticleSystem\u003e();\n    }\n\n    private void LateUpdate()\n    {\n        var isAlive = particle.IsAlive(true);\n        if (_isAliveAtLastFrame \u0026\u0026 !isAlive)\n            ReleasedInternal?.Invoke();\n\n        _isAliveAtLastFrame = isAlive;\n    }\n    \n    event Action IReleaseEvent.Dispatched\n    {\n        add =\u003e ReleasedInternal += value;\n        remove =\u003e ReleasedInternal -= value;\n    }\n\n    private event Action ReleasedInternal;\n}\n```\n\n## Preloading\nIn Addressable Asset System, resources are loaded asynchronously.\n\n```cs\n// Asynchronous loading\nvar handle = Addressables.LoadAssetAsync\u003cGameObject\u003e(\"fooPrefab\");\nawait handle.Task;\n```\n\nHowever, in some cases, you want to get pre-loaded resources synchronously.\nYou can do this with preloader.\n\n### How to use Preloader\nThe preloading feature is provided by the **Preloader** class.\nBelow is an example of how to use it.\n\n```cs\nusing System;\nusing System.Collections;\nusing Addler.Runtime.Core.Preloading;\nusing UnityEngine;\n\npublic sealed class Example : MonoBehaviour\n{\n    private IEnumerator PreloadExample()\n    {\n        var preloader = new AddressablePreloader();\n\n        // Preload\n        {\n            var progress = new Progress\u003cfloat\u003e(x =\u003e Debug.Log($\"Progress: {x}\"));\n            \n            // Preload by address.\n            yield return preloader.PreloadKey\u003cGameObject\u003e(\"fooAddress\", progress);\n\n            // You can also preload by label.\n            yield return preloader.PreloadKey\u003cGameObject\u003e(\"fooLabel\", progress);\n\n            // You can also preload multiple keys at once.\n            yield return preloader.PreloadKeys\u003cGameObject\u003e(new[] { \"barAddress\", \"bazAddress\" }, progress);\n        }\n\n        // Get the preloaded object.\n        {\n            // Get by address.\n            preloader.GetAsset\u003cGameObject\u003e(\"fooAddress\");\n\n            // Get multiple assets by label.\n            preloader.GetAssets\u003cGameObject\u003e(\"fooLabel\");\n        }\n        \n        // Dispose the preloader and release all the assets.\n        preloader.Dispose();\n    }\n}\n```\n\nYou can preload resources of the keys in the argument by calling `AddressablePreloader.PreloadKey()/PreloadKeys()`.\nAnd you can get the preloaded resources synchronously by `AddressablesPreloader.GetAsset()` method.\n\nAnd all resources are released by `AddressablePreloader.Dispose()` method.\n\n### Use Preloader with Lifetime Binding\nYou can also bind the lifetime of the preloader.\n\n```cs\n// Bind the lifetime of the preloader to the GameObject.\n// When gameObject is destroyed, the preloader will be disposed and release all the assets.\nvar preloader = new AddressablePreloader().BindTo(gameObject);\n```\n\nAll resources will be released when the preloader lifetime expires.\n\n### Limitations of Preloader\nAs a rule for preloading, the \"key type specified at preloading\" and the \"key type specified when retrieving the preloaded resource\" must match.\n\nFor 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.\nIt is not possible to specify address A.\n\nThis 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.\n\nIf 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.\nHowever, this feature waits synchronously until all running **AsyncOperations** are finished, so be careful when using it.\n\n## Object Pooling\nUnity uses manu GAmeObjects instantiated from Prefabs.\nHowever, instantiating and destroying is expensive, so they often cause performance problems.\n\nIn 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.\nThis is called object pooling.\n\n\u003cp align=\"center\"\u003e\n  \u003cimg width=80% src=\"Documentation/concept_02.png\" alt=\"Pooling\"\u003e\n\u003c/p\u003e\n\n### How to use Object Pooling\nThe preloading feature is provided by the `AddressablePool` class.\nBelow is an example of how to use it.\n\n```cs\nusing System;\nusing System.Collections;\nusing Addler.Runtime.Core.Pooling;\nusing UnityEngine;\n\npublic sealed class Example : MonoBehaviour\n{\n    private IEnumerator PoolExample()\n    {\n        // Create a new pool with key of the GameObject.\n        var pool = new AddressablePool(\"fooPrefab\");\n\n        // Create instances in the pool.\n        var progress = new Progress\u003cfloat\u003e(x =\u003e Debug.Log($\"Progress: {x}\"));\n        yield return pool.Warmup(5, progress);\n\n        // Get an instance from the pool.\n        var pooledObject = pool.Use();\n        var instance = pooledObject.Instance;\n\n        // Return the instance to the pool.\n        pool.Return(pooledObject);\n        //pooledObject.Dispose(); // You can also return the instance by disposing the pooled object.\n\n        // Destroy the pool and release all instances.\n        pool.Dispose();\n    }\n}\n```\n\nWhen you call `AddressablePool.WarmupAsync()`, as many instances of prefab as you pass in the argument will be created.\nTo get an instance from the pool, use the `AddressablePool.Use()` method to get the `PooledObject`.\nYou can get an instance from the `Instance` property of this.\nTo return the instance to the pool, call `AddressablePool.Return()` or `PooledObject.Dispose()`.\n\nWhen the pool is no longer needed, call `AddressablePool.Dispose()`.\nAll instances will be destroyed and the resources will be released.\n\n### Use Object Pool with Lifetime Binding\nYou can also bind the lifetime of the object pool and the lifetime of instances retrieved from it.\n\n```cs\nusing System.Collections;\nusing Addler.Runtime.Core.Pooling;\nusing UnityEngine;\n\npublic sealed class Example : MonoBehaviour\n{\n    private IEnumerator PoolExample()\n    {\n        // Bind the lifetime of the pool to GameObject.\n        // If gameObject1 is destroyed, the pool will be disposed.\n        var pool = new AddressablePool(\"FooPrefab\")\n            .BindTo(gameObject1);\n\n        yield return pool.Warmup(5);\n\n        // Bind the lifetime of the instance to GameObject.\n        // If gameObject2 is destroyed, the instance will be returned to the pool.\n        var instance = pool\n            .Use()\n            .BindTo(gameObject2)\n            .Instance;\n    }\n}\n```\n\nWhen the lifetime of an instance expires, it will be returned to the pool.\nWhen the lifetime of the object pool expires, all instances will be destroyed and released.\n\n## Other\n\n### Disable Preloading / Object Pooling\nIf you do not use Preloading or Object Pooling, you can disable them and exclude them from the compilation.\nTo disable them, set the following **Scripting Define Symbols** in the **Player Settings**.\n\n- **ADDLER_DISABLE_PRELOADING** : Disable Preloading.\n- **ADDLER_DISABLE_POOLING** : Disable Object Pooling.\n\n### Use UniTask\nIn Preloading / Object Pooling, you can use coroutine to wait for the asynchronous operation.\nYou can use UniTask too \n\n1. Install [UniTask](https://github.com/Cysharp/UniTask).（There are several ways to install.）\n2. (Only if you install 1. not via Package Manager) Add `ADDLER_UNITASK_SUPPORT` to **Scripting Define Symbols** and restart Unity.\n3. Now you can use the **UniTask** version methods such as `AddressablePool.WarmupAsync`.\n\n## Licenses\nThis 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.\n\n* [LICENSE.md](LICENSE.md)\n\nIn addition, the table of contents of this document was created using the following software\n\n* [toc-generator](https://github.com/technote-space/toc-generator)\n\nSee [Third Party Notices.md](Third%20Party%20Notices.md) for details on these licenses.\n","funding_links":[],"categories":["Unity","C\\#"],"sub_categories":["Lua"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FHaruma-K%2FAddler","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FHaruma-K%2FAddler","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FHaruma-K%2FAddler/lists"}