From aefa5af48585ee3aa514df934f57686be3e56e8e Mon Sep 17 00:00:00 2001 From: waynemwashuma <94756970+waynemwashuma@users.noreply.github.com> Date: Mon, 29 Sep 2025 08:32:00 +0300 Subject: [PATCH 1/7] Remove `HandleProvider` --- src/asset/core/asset.js | 9 +-------- src/asset/plugins/asset.js | 1 - 2 files changed, 1 insertion(+), 9 deletions(-) diff --git a/src/asset/core/asset.js b/src/asset/core/asset.js index 33eeaef7..caa294ce 100644 --- a/src/asset/core/asset.js +++ b/src/asset/core/asset.js @@ -300,11 +300,4 @@ export class AssetEntry { this.asset = asset this.refCount = 0 } -} - -/** - * @template T - * @callback HandleProvider - * @param {number} id - * @returns {Handle} - */ \ No newline at end of file +} \ No newline at end of file diff --git a/src/asset/plugins/asset.js b/src/asset/plugins/asset.js index ba6cf9c0..80ab977f 100644 --- a/src/asset/plugins/asset.js +++ b/src/asset/plugins/asset.js @@ -1,5 +1,4 @@ /** @import { Constructor } from '../../reflect/index.js' */ -/** @import { HandleProvider } from '../core/index.js' */ import { App, AppSchedule, Plugin } from '../../app/index.js' import { EventPlugin } from '../../event/index.js' From 5fcee6d70a4d3d5a8657616904f4c035fb5f024f Mon Sep 17 00:00:00 2001 From: waynemwashuma <94756970+waynemwashuma@users.noreply.github.com> Date: Mon, 29 Sep 2025 08:32:00 +0300 Subject: [PATCH 2/7] Add `Assets.getEntryByAssetId` --- src/asset/core/asset.js | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/src/asset/core/asset.js b/src/asset/core/asset.js index caa294ce..ba3e08ed 100644 --- a/src/asset/core/asset.js +++ b/src/asset/core/asset.js @@ -125,6 +125,31 @@ export class Assets { return this.assets.get(index) } + /** + * @param {AssetId} assetId + * @returns {AssetEntry | undefined} + */ + getEntryByAssetId(assetId) { + const [index, generation] = unpackFrom64Int(assetId) + + return this.getEntryInternal(index, generation) + } + + /** + * @private + * @param {number} index + * @param {number} generation + */ + getEntryInternal(index, generation) { + const entry = this.assets.get(index) + + if (!entry) return undefined + + if (entry.generation !== generation) return undefined + + return entry + } + /** * @param {Handle} handle * @returns {T | undefined} From 6d1a20c03130e1d00fc991efd121f38313ab21bf Mon Sep 17 00:00:00 2001 From: waynemwashuma <94756970+waynemwashuma@users.noreply.github.com> Date: Mon, 29 Sep 2025 08:35:00 +0300 Subject: [PATCH 3/7] Add `Handle.generation` --- src/asset/core/asset.js | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/src/asset/core/asset.js b/src/asset/core/asset.js index ba3e08ed..6d825531 100644 --- a/src/asset/core/asset.js +++ b/src/asset/core/asset.js @@ -268,16 +268,24 @@ export class Handle { index /** - * @param {Assets} assets - * @param {number} index + * @readonly + * @type {number} + */ + generation = 0 + + /** + * @param {Assets} assets + * @param {number} index + * @param {number} generation */ - constructor(assets, index) { + constructor(assets, index, generation) { this.index = index + this.generation = generation this.assets = assets const entry = assets.getEntry(this) - if (entry) { + if (entry && entry.generation === generation) { entry.refCount += 1 } } @@ -286,13 +294,13 @@ export class Handle { * @returns {AssetId} */ id() { - return /** @type {AssetId}*/ (this.index) + return /** @type {AssetId}*/ (packInto64Int(this.index, this.generation)) } clone() { - const { assets, index } = this + const { assets, index, generation } = this - return new Handle(assets, index) + return new Handle(assets, index, generation) } drop() { From f47ab54ea81fd1f7d18ab9d35f90b1a3a2059105 Mon Sep 17 00:00:00 2001 From: waynemwashuma <94756970+waynemwashuma@users.noreply.github.com> Date: Mon, 29 Sep 2025 08:35:00 +0300 Subject: [PATCH 4/7] Add `AssetEntry.generation` --- src/asset/core/asset.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/asset/core/asset.js b/src/asset/core/asset.js index 6d825531..1e74bf44 100644 --- a/src/asset/core/asset.js +++ b/src/asset/core/asset.js @@ -324,13 +324,17 @@ export class AssetEntry { /** * @type {number} */ - refCount + refCount = 0 + + /** + * @type {number} + */ + generation = 0 /** * @param {T} asset */ constructor(asset) { this.asset = asset - this.refCount = 0 } } \ No newline at end of file From 60c9f376f4eebeaa87ffc95b70196571ffa973ce Mon Sep 17 00:00:00 2001 From: waynemwashuma <94756970+waynemwashuma@users.noreply.github.com> Date: Mon, 29 Sep 2025 08:35:00 +0300 Subject: [PATCH 5/7] Implement generational refcounting on `Assets` --- src/asset/core/asset.js | 39 +++++++++++++++++++++++++-------------- 1 file changed, 25 insertions(+), 14 deletions(-) diff --git a/src/asset/core/asset.js b/src/asset/core/asset.js index 1e74bf44..41b9a581 100644 --- a/src/asset/core/asset.js +++ b/src/asset/core/asset.js @@ -1,5 +1,6 @@ /** @import {AssetId} from '../types/index.js' */ /** @import {Constructor} from '../../reflect/index.js'*/ +import { packInto64Int, unpackFrom64Int } from '../../algorithms/index.js' import { DenseList } from '../../datastructures/index.js' import { AssetAdded, AssetDropped, AssetEvent, AssetModified } from '../events/assets.js' @@ -43,12 +44,10 @@ export class Assets { * @returns {Handle} */ add(asset) { - const id = this.assets.reserve() - - this.assets.set(id, new AssetEntry(asset)) - - const handle = new Handle(this, id) + const handle = this.reserve() + const entry = this.getEntry(handle) + entry.asset = asset this.events.push(new AssetAdded(this.type, handle.id())) return handle @@ -79,7 +78,7 @@ export class Assets { * @param {T} asset */ setUsingAssetId(assetId, asset) { - const entry = this.assets.get(assetId) + const entry = this.getEntryByAssetId(assetId) if (!entry) return @@ -120,9 +119,9 @@ export class Assets { * @returns {AssetEntry | undefined} */ getEntry(handle) { - const { index } = handle + const { index, generation } = handle - return this.assets.get(index) + return this.getEntryInternal(index, generation) } /** @@ -179,11 +178,11 @@ export class Assets { * @returns {T | undefined} */ getByAssetId(id) { - const entry = this.assets.get(id) + const entry = this.getEntryByAssetId(id) if (!entry) return undefined - return this.assets.get(id).asset + return entry.asset } /** @@ -225,7 +224,9 @@ export class Assets { * @param {AssetId} assetId */ upgrade(assetId) { - return new Handle(this, assetId) + const [index, generation] = unpackFrom64Int(assetId) + + return new Handle(this, index, generation) } /** @@ -233,11 +234,21 @@ export class Assets { * */ reserve() { - const id = this.assets.reserve() + const index = this.assets.reserve() + const entry = this.assets.get(index) + + if (entry) { + entry.generation += 1 + + return new Handle(this, index, entry.generation) + } + + const newEntry = new AssetEntry(undefined) - this.assets.set(id, new AssetEntry(undefined)) + newEntry.generation += 1 + this.assets.set(index, newEntry) - return new Handle(this, id) + return new Handle(this, index, newEntry.generation) } } From ef3d6c9f34cdae9a1dcfacad337581748cd1e55f Mon Sep 17 00:00:00 2001 From: waynemwashuma <94756970+waynemwashuma@users.noreply.github.com> Date: Mon, 29 Sep 2025 08:35:00 +0300 Subject: [PATCH 6/7] Update asset and handle tests --- src/asset/tests/asset.test.js | 14 ++++++------- src/asset/tests/handle.test.js | 38 ++++++++++++++++++++++++++++++++++ 2 files changed, 44 insertions(+), 8 deletions(-) diff --git a/src/asset/tests/asset.test.js b/src/asset/tests/asset.test.js index 42c53377..f9986e53 100644 --- a/src/asset/tests/asset.test.js +++ b/src/asset/tests/asset.test.js @@ -54,7 +54,7 @@ describe("Testing `Assets`", () => { test('`Assets.get` returns undefined on invalid handle', () => { const assets = new Assets(String) - const handle = new Handle(assets,0) + const handle = new Handle(assets,0, 1) const actual = assets.get(handle) strictEqual(actual, undefined) @@ -182,7 +182,7 @@ describe("Testing `Assets`", () => { test('`Assets.getByAssetId` returns undefined on invalid assetid', () => { const assets = new Assets(String) - const handle = new Handle(assets,0).id() + const handle = new Handle(assets,0, 1).id() const actual = assets.getByAssetId(handle) strictEqual(actual, undefined) @@ -252,13 +252,11 @@ describe("Testing `Assets`", () => { test('Assets provides the right events when asset is added/modified using uuid', () => { const assets = new Assets(String) const asset = "Wima engine" - const uuid1 = "124-ufy7f-yrffu-67ftcgh" - const uuid2 = "1243f-ufy7f-eggfu-6cghjeha46" - const handle1 = assets.setWithUUID(uuid1,asset) - const handle2 = assets.setWithUUID(uuid2,asset) - assets.setWithUUID(uuid1,asset) - assets.setWithUUID(uuid2,asset) + const handle1 = assets.add(asset) + const handle2 = assets.add(asset) + assets.set(handle1,asset) + assets.set(handle2,asset) const events = assets.flushEvents() deepStrictEqual(events[0], new AssetAdded(String, handle1.id())) diff --git a/src/asset/tests/handle.test.js b/src/asset/tests/handle.test.js index aa35bdde..26472940 100644 --- a/src/asset/tests/handle.test.js +++ b/src/asset/tests/handle.test.js @@ -140,4 +140,42 @@ describe('Testing `Handle`',()=>{ deepStrictEqual(actual, asset) }) + + test('`Handle` generation starts at one (case 1).', () => { + const assets = new Assets(String) + const asset = "Wima engine" + + const handle = assets.add(asset) + + deepStrictEqual(handle.generation, 1) + }) + + test('`Handle` generation starts at one (case 2).', () => { + const assets = new Assets(String) + const asset = "Wima engine" + + const handle1 = assets.add(asset) + const handle2 = assets.add(asset) + + deepStrictEqual(handle1.generation, 1) + deepStrictEqual(handle2.generation, 1) + }) + + test('Recycled `Handle`s have incremented generation.', () => { + const assets = new Assets(String) + const asset = "Wima engine" + + const handle1 = assets.add(asset) + handle1.drop() + const handle2 = assets.add(asset) + handle2.drop() + const handle3 = assets.add(asset) + + deepStrictEqual(handle1.index, 0) + deepStrictEqual(handle1.generation, 1) + deepStrictEqual(handle2.index, 0) + deepStrictEqual(handle2.generation, 2) + deepStrictEqual(handle3.index, 0) + deepStrictEqual(handle3.generation, 3) + }) }) \ No newline at end of file From 21d17efc4aa2973d1d4e1df2c94326781e31aea4 Mon Sep 17 00:00:00 2001 From: waynemwashuma <94756970+waynemwashuma@users.noreply.github.com> Date: Mon, 29 Sep 2025 08:35:00 +0300 Subject: [PATCH 7/7] Update affected modules --- src/animation/components/player.js | 3 ++- src/animation/systems/index.js | 7 +++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/animation/components/player.js b/src/animation/components/player.js index d530e097..09bdcb2e 100644 --- a/src/animation/components/player.js +++ b/src/animation/components/player.js @@ -1,4 +1,5 @@ /** @import { PlaybackSettings } from '../core/index.js'*/ +/** @import { AssetId } from '../../asset/index.js'*/ import { Handle } from '../../asset/index.js' import { Playback } from '../core/index.js' import { AnimationClip } from '../assets/index.js' @@ -6,7 +7,7 @@ import { AnimationClip } from '../assets/index.js' export class AnimationPlayer { /** - * @type {Map} + * @type {Map} */ animations = new Map() diff --git a/src/animation/systems/index.js b/src/animation/systems/index.js index 827fd175..9ea621da 100644 --- a/src/animation/systems/index.js +++ b/src/animation/systems/index.js @@ -1,4 +1,3 @@ -import { Handle } from '../../asset/index.js' import { Entity, Query, World } from '../../ecs/index.js' import { VirtualClock } from '../../time/index.js' import { AnimationPlayer, AnimationTarget } from '../components/index.js' @@ -33,9 +32,9 @@ export function applyAnimations(world) { const [player] = play - player.animations.forEach((playback, handleid) => { - const handle = new Handle(clips, handleid) - const clip = clips.get(handle) + player.animations.forEach((playback, assetId) => { + + const clip = clips.getByAssetId(assetId) const tracks = clip.getTracks(target.id) if (!tracks) return