{"id":14961006,"url":"https://github.com/gilzoide/unity-update-manager","last_synced_at":"2025-10-08T20:10:43.801Z","repository":{"id":65824785,"uuid":"600753225","full_name":"gilzoide/unity-update-manager","owner":"gilzoide","description":"Simple to use Update Manager pattern for Unity + Jobified Update for MonoBehaviours and pure C# classes alike","archived":false,"fork":false,"pushed_at":"2024-12-11T21:48:03.000Z","size":16587,"stargazers_count":162,"open_issues_count":1,"forks_count":16,"subscribers_count":4,"default_branch":"main","last_synced_at":"2025-05-25T13:05:36.353Z","etag":null,"topics":["job-system","jobs","unity","unity3d","update","update-manager","upm","upm-package"],"latest_commit_sha":null,"homepage":"","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"unlicense","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/gilzoide.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":".github/FUNDING.yml","license":null,"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},"funding":{"github":["gilzoide"],"patreon":null,"open_collective":null,"ko_fi":"gilzoide","tidelift":null,"community_bridge":null,"liberapay":"gilzoide","issuehunt":null,"otechie":null,"lfx_crowdfunding":null,"custom":null}},"created_at":"2023-02-12T13:55:07.000Z","updated_at":"2025-05-25T07:30:38.000Z","dependencies_parsed_at":"2023-06-12T17:02:56.379Z","dependency_job_id":"345d050a-32b4-463f-9bbf-d4857908e67c","html_url":"https://github.com/gilzoide/unity-update-manager","commit_stats":{"total_commits":143,"total_committers":1,"mean_commits":143.0,"dds":0.0,"last_synced_commit":"701d573069928cf2754aadc2b50f173d26946a40"},"previous_names":[],"tags_count":14,"template":false,"template_full_name":null,"purl":"pkg:github/gilzoide/unity-update-manager","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gilzoide%2Funity-update-manager","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gilzoide%2Funity-update-manager/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gilzoide%2Funity-update-manager/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gilzoide%2Funity-update-manager/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/gilzoide","download_url":"https://codeload.github.com/gilzoide/unity-update-manager/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gilzoide%2Funity-update-manager/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":279000680,"owners_count":26082818,"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","status":"online","status_checked_at":"2025-10-08T02:00:06.501Z","response_time":56,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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":["job-system","jobs","unity","unity3d","update","update-manager","upm","upm-package"],"created_at":"2024-09-24T13:23:37.635Z","updated_at":"2025-10-08T20:10:43.742Z","avatar_url":"https://github.com/gilzoide.png","language":"C#","readme":"# Update Manager\n[![openupm](https://img.shields.io/npm/v/com.gilzoide.update-manager?label=openupm\u0026registry_uri=https://package.openupm.com)](https://openupm.com/packages/com.gilzoide.update-manager/)\n\nSimple to use Update Manager pattern for Unity + Jobified Update for `MonoBehaviour`s and pure C# classes alike.\n\nUsing these may improve your game's CPU usage when there are thousands of objects updating every frame.\n\nMore info on Update Manager vs traditional Update: https://github.com/Menyus777/Game-engine-specific-optimization-techniques-for-Unity\n\n\n## Features\n- Use `UpdateManager` to call objects' `ManagedUpdate`, `ManagedLateUpdate` or `ManagedFixedUpdate` method, bypassing Unity's native \u003c-\u003e C# interop\n- Both `MonoBehaviour` and pure C# classes are supported, just implement `IUpdatable`, `ILateUpdatable` and/or `IFixedUpdatable` interface and register the object to be updated using its `RegisterInManager` extension method.\n  \n  Remember to unregister the objects with `UnregisterInManager` when necessary.\n- Inherit `AManagedBehaviour` to automatically register/unregister MonoBehaviours in `UpdateManager` in their `OnEnable`/`OnDisable` messages.\n  The class still needs to implement the `IUpdatable`, `ILateUpdatable` and/or `IFixedUpdatable` interfaces for any managed update methods to be run.\n- Supports profiler markers for managed update methods by adding the `UPDATE_MANAGER_ENABLE_PROFILER_MARKERS` scripting symbol to the project\n\nJob System:\n- Use `UpdateJobManager\u003cMyIUpdateJobStruct\u003e` to run jobs every frame using Unity's Job system\n- Use `UpdateTransformJobManager\u003cMyIUpdateTransformJobStruct\u003e` to run jobs with `TransformAccess` every frame using Unity's Job system, so you can change your objects' transforms from jobs\n- Both `MonoBehaviour` and pure C# classes are supported, just implement `IJobUpdatable\u003cMyIUpdateJobStruct\u003e` or `ITransformJobUpdatable\u003cMyIUpdateTransformJobStruct\u003e` interface and register the object to be updated using the `RegisterInManager` extension method.\n  \n  Remember to unregister the objects with `UnregisterInManager` when necessary.\n- Inherit `AJobBehaviour\u003cMyIUpdateTransformJobStruct\u003e` to automatically register/unregister MonoBehaviours for update jobs in their `OnEnable`/`OnDisable` messages\n- Burst compilation is enabled when you implement `IBurstUpdateJob\u003cBurstUpdateJob\u003cMyJobStruct\u003e\u003e` instead of `IUpdateJob` in your job struct type.\n  The same is true for `IBurstUpdateTransformJob\u003cBurstUpdateTransformJob\u003cMyJobStruct\u003e\u003e` vs `IUpdateTransformJob`.\n- Job data may be modified from within jobs and fetched anytime.\n  This package uses double buffering to let you read values even while jobs are running and modifying data.\n- `UpdateJobTime` class with information from Unity's `Time` class that you can access from within jobs (`deltaTime`, `time`, etc...)\n- Configurable job batch size using `[JobBatchSize(...)]` attribute in job structs.\n  This is ignored in read-write transform jobs.\n- Add dependencies between managed jobs using `[DependsOn(typeof(MyJobDependency1), ...)]`.\n  \n  For now, no dependency cycle detection is performed, so job runners may get deadlocked if you misuse it.\n\n\n## Caveats\n- `UpdateManager` doesn't have the concept of script execution order like Unity MonoBehaviours, so don't rely on execution order.\n- Read-write transform jobs are only parallelized if the objects live in hierarchies with different root objects.\n  This is a limitation of Unity's job system.\n\n  Read-only transform jobs, marked by the `[ReadOnlyTransformAccess]` attribute, don't have this restriction.\n- Although native container fields (`NativeArray`, `NativeList`...) are supported in managed jobs, the thread safety system provided by Unity is not applied to them.\n  Use them with care!\n\n\n## How to install\nThis package is available on the [openupm registry](https://openupm.com/) and can be installed using the [openupm-cli](https://github.com/openupm/openupm-cli):\n\n```\nopenupm add com.gilzoide.update-manager\n```\n\nOtherwise, you can install directly using the [Unity Package Manager](https://docs.unity3d.com/Manual/upm-ui-giturl.html)\nwith the following URL:\n\n```\nhttps://github.com/gilzoide/unity-update-manager.git#1.5.3\n```\n\nOr you can clone this repository or download a snapshot of it directly inside your project's `Assets` or `Packages` folder.\n\n\n## How to use\n### `UpdateManager` + `MonoBehaviour`\n```cs\nusing Gilzoide.UpdateManager;\nusing UnityEngine;\n\npublic class MyManagedUpdatableBehaviour : AManagedBehaviour, IUpdatable, ILateUpdatable, IFixedUpdatable\n{\n    public void ManagedUpdate()\n    {\n        Debug.Log(\"Called every frame, alongside other scripts' Update message\");\n    }\n\n    public void ManagedLateUpdate()\n    {\n        Debug.Log(\"Also called every frame, alongside other scripts' LateUpdate message\");\n    }\n\n    public void ManagedFixedUpdate()\n    {\n        Debug.Log(\"Also called every frame, alongside other scripts' FixedUpdate message\");\n    }\n}\n```\n\n### `UpdateManager` with pure C# class\n```cs\nusing Gilzoide.UpdateManager;\nusing UnityEngine;\n\npublic class MyUpdatable : IUpdatable, ILateUpdatable, IFixedUpdatable\n{\n    public void ManagedUpdate()\n    {\n        Debug.Log(\"Called every frame, alongside other scripts' Update message\");\n    }\n\n    public void ManagedLateUpdate()\n    {\n        Debug.Log(\"Also called every frame, alongside other scripts' LateUpdate message\");\n    }\n\n    public void ManagedFixedUpdate()\n    {\n        Debug.Log(\"Also called every frame, alongside other scripts' FixedUpdate message\");\n    }\n\n    // call this when you want Updates to start running\n    public void StartUpdating()\n    {\n        this.RegisterInManager();\n        // ^ alias for `UpdateManager.Instance.Register(this)`\n    }\n\n    // call this when necessary to stop the updates\n    public void StopUpdating()\n    {\n        this.UnregisterInManager();\n        // ^ alias for `UpdateManager.Instance.Unregister(this)`\n    }\n}\n```\n\n### `UpdateTransformJobManager` + `MonoBehaviour`\n```cs\nusing System.Collections;\nusing Gilzoide.UpdateManager.Jobs;\nusing UnityEngine;\nusing UnityEngine.Jobs;\n\n// 1. Create the Job struct\n//\n// Note: Implement `IBurstUpdateTransformJob\u003cBurstUpdateTransformJob\u003cMoveJob\u003e\u003e`\n// instead if you want Burst to compile the job\npublic struct MoveJob : IUpdateTransformJob\n{\n    public Vector3 Direction;\n    public float Speed;\n    public bool SomethingHappened;\n\n    public void Execute(TransformAccess transform)\n    {\n        Debug.Log(\"This will be called every frame using Unity's Job system\");\n        // This runs outside of the Main Thread, so\n        // we need to use `UpdateJobTime` instead of `Time`\n        float deltaTime = UpdateJobTime.deltaTime;\n        // You can modify the Transform in jobs!\n        transform.localPosition += Direction * Speed * deltaTime;\n        // You can modify the struct's value and fetch them later!\n        SomethingHappened = true;\n    }\n}\n\n// 2. Create the job-updated behaviour\npublic class MyJobifiedBehaviour : AJobBehaviour\u003cMoveJob\u003e\n{\n    // set the parameters in Unity's Inspector\n    public Vector3 Direction;\n    public float Speed;\n\n    // (optional) Set the data passed to the first job run\n    public override MoveJob InitialJobData =\u003e new MoveJob\n    {\n        Direction = Direction,\n        Speed = Speed,\n    };\n\n    IEnumerator Start()\n    {\n        // wait a frame to see if something happened\n        yield return null;\n        // use the `JobData` property to fetch the current data\n        MoveJob currentData = JobData;\n        // should print \"Something happened: true\"\n        Debug.Log(\"Something happened: \" + currentData.SomethingHappened);\n    }\n}\n```\n\n### `UpdateJobManager` + pure C# class\n```cs\nusing Gilzoide.UpdateManager.Jobs;\nusing UnityEngine;\n\n// 1. Create the Job struct\n//\n// Note: Implement `IBurstUpdateJob\u003cBurstUpdateJob\u003cMoveJob\u003e\u003e`\n// instead if you want Burst to compile the job\npublic struct CountJob : IUpdateJob\n{\n    public int Count;\n\n    public void Execute()\n    {\n        Debug.Log(\"This will be called every frame using Unity's Job system\");\n        Count++;\n    }\n}\n\n// 2. Create the job-updated class\npublic class MyJobifiedBehaviour : IJobUpdatable\u003cCountJob\u003e\n{\n    // Set the data passed to the first job run\n    public CountJob InitialJobData =\u003e default;\n\n    // call this when you want Updates to start running\n    public void StartUpdating()\n    {\n        this.RegisterInManager();\n        // ^ alias for `UpdateJobManager\u003cCountJob\u003e.Instance.Register(this)`\n    }\n\n    // call this when necessary to stop the updates\n    public void StopUpdating()\n    {\n        this.UnregisterInManager();\n        // ^ alias for `UpdateJobManager\u003cCountJob\u003e.Instance.Unregister(this)`\n    }\n\n    // fetch current data using `this.GetJobData`\n    public int CurrentCount =\u003e this.GetJobData().Count;\n}\n```\n\n\n## Benchmarks\n1. Test with 2000 spinning cubes running at 30 FPS in a Xiaomi Redmi 4X Android device.\n   - Plain Update: 12\\~13ms updating, 8\\~10ms spare in frame\n   - Update Manager: 7\\~8ms updating, 12\\~15ms spare in frame\n   - Fully parallelized transform job: \\~2ms updating, 18\\~20ms spare in frame\n   ![](Extras~/demo.gif)\n2. 1000 spinning game objects running in an automated performace testing running in a M1 Macbook Pro\n   - Plain Update: \\~1.01ms updating\n   - Update Manager: \\~0.91ms updating\n   - Fully parallelized transform job: \\~0.60ms updating\n   ![](Extras~/performance-testing.png)","funding_links":["https://github.com/sponsors/gilzoide","https://ko-fi.com/gilzoide","https://liberapay.com/gilzoide"],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgilzoide%2Funity-update-manager","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgilzoide%2Funity-update-manager","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgilzoide%2Funity-update-manager/lists"}