rn-gamekit 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +18 -0
- package/LICENSE +21 -0
- package/README.md +131 -0
- package/lib/module/assets/defineAssets.js +48 -0
- package/lib/module/assets/defineAssets.js.map +1 -0
- package/lib/module/assets/errors.js +38 -0
- package/lib/module/assets/errors.js.map +1 -0
- package/lib/module/assets/types.js +2 -0
- package/lib/module/assets/types.js.map +1 -0
- package/lib/module/assets/validation.js +99 -0
- package/lib/module/assets/validation.js.map +1 -0
- package/lib/module/core/frameDriver.js +20 -0
- package/lib/module/core/frameDriver.js.map +1 -0
- package/lib/module/core/input/createInputBuffer.js +296 -0
- package/lib/module/core/input/createInputBuffer.js.map +1 -0
- package/lib/module/core/input/types.js +4 -0
- package/lib/module/core/input/types.js.map +1 -0
- package/lib/module/core/session/createGameSession.js +554 -0
- package/lib/module/core/session/createGameSession.js.map +1 -0
- package/lib/module/core/session/deepFreeze.js +155 -0
- package/lib/module/core/session/deepFreeze.js.map +1 -0
- package/lib/module/core/session/diagnostics.js +2 -0
- package/lib/module/core/session/diagnostics.js.map +1 -0
- package/lib/module/core/session/types.js +43 -0
- package/lib/module/core/session/types.js.map +1 -0
- package/lib/module/definition/defineGame.js +57 -0
- package/lib/module/definition/defineGame.js.map +1 -0
- package/lib/module/definition/types.js +4 -0
- package/lib/module/definition/types.js.map +1 -0
- package/lib/module/geometry/types.js +2 -0
- package/lib/module/geometry/types.js.map +1 -0
- package/lib/module/index.js +12 -0
- package/lib/module/index.js.map +1 -0
- package/lib/module/package.json +1 -0
- package/lib/module/react/GamePointerInput.js +385 -0
- package/lib/module/react/GamePointerInput.js.map +1 -0
- package/lib/module/react/GameView.js +223 -0
- package/lib/module/react/GameView.js.map +1 -0
- package/lib/module/react/alphaClock.js +42 -0
- package/lib/module/react/alphaClock.js.map +1 -0
- package/lib/module/react/assets/createGameAssetStore.js +358 -0
- package/lib/module/react/assets/createGameAssetStore.js.map +1 -0
- package/lib/module/react/assets/decodeSkiaImage.js +54 -0
- package/lib/module/react/assets/decodeSkiaImage.js.map +1 -0
- package/lib/module/react/assets/errors.js +10 -0
- package/lib/module/react/assets/errors.js.map +1 -0
- package/lib/module/react/assets/useGameAssets.js +160 -0
- package/lib/module/react/assets/useGameAssets.js.map +1 -0
- package/lib/module/react/bindAppLifecycle.js +58 -0
- package/lib/module/react/bindAppLifecycle.js.map +1 -0
- package/lib/module/react/bindGameSession.js +37 -0
- package/lib/module/react/bindGameSession.js.map +1 -0
- package/lib/module/react/gestureLifecycle.js +68 -0
- package/lib/module/react/gestureLifecycle.js.map +1 -0
- package/lib/module/react/instrumentation.js +4 -0
- package/lib/module/react/instrumentation.js.map +1 -0
- package/lib/module/react/pointerBinding.js +196 -0
- package/lib/module/react/pointerBinding.js.map +1 -0
- package/lib/module/react/pointerCoalescer.js +224 -0
- package/lib/module/react/pointerCoalescer.js.map +1 -0
- package/lib/module/react/pointerContainment.js +27 -0
- package/lib/module/react/pointerContainment.js.map +1 -0
- package/lib/module/react/sprites/GameSprite.js +116 -0
- package/lib/module/react/sprites/GameSprite.js.map +1 -0
- package/lib/module/react/sprites/GameWorld2D.js +44 -0
- package/lib/module/react/sprites/GameWorld2D.js.map +1 -0
- package/lib/module/react/sprites/Sprite.js +147 -0
- package/lib/module/react/sprites/Sprite.js.map +1 -0
- package/lib/module/react/sprites/SpriteBatch.js +173 -0
- package/lib/module/react/sprites/SpriteBatch.js.map +1 -0
- package/lib/module/react/sprites/spriteBatchPolicy.js +25 -0
- package/lib/module/react/sprites/spriteBatchPolicy.js.map +1 -0
- package/lib/module/react/sprites/spriteTransform.js +135 -0
- package/lib/module/react/sprites/spriteTransform.js.map +1 -0
- package/lib/module/react/viewportBinding.js +101 -0
- package/lib/module/react/viewportBinding.js.map +1 -0
- package/lib/module/react.js +13 -0
- package/lib/module/react.js.map +1 -0
- package/lib/module/scene/defineScene.js +29 -0
- package/lib/module/scene/defineScene.js.map +1 -0
- package/lib/module/scene/types.js +4 -0
- package/lib/module/scene/types.js.map +1 -0
- package/lib/module/sprites/sampleSpriteClip.js +50 -0
- package/lib/module/sprites/sampleSpriteClip.js.map +1 -0
- package/lib/module/sprites/spriteAnimationState.js +165 -0
- package/lib/module/sprites/spriteAnimationState.js.map +1 -0
- package/lib/module/testing.js +57 -0
- package/lib/module/testing.js.map +1 -0
- package/lib/module/viewport2d/index.js +4 -0
- package/lib/module/viewport2d/index.js.map +1 -0
- package/lib/module/viewport2d/math.js +129 -0
- package/lib/module/viewport2d/math.js.map +1 -0
- package/lib/module/viewport2d/types.js +2 -0
- package/lib/module/viewport2d/types.js.map +1 -0
- package/lib/typescript/package.json +1 -0
- package/lib/typescript/src/assets/defineAssets.d.ts +20 -0
- package/lib/typescript/src/assets/defineAssets.d.ts.map +1 -0
- package/lib/typescript/src/assets/errors.d.ts +20 -0
- package/lib/typescript/src/assets/errors.d.ts.map +1 -0
- package/lib/typescript/src/assets/types.d.ts +138 -0
- package/lib/typescript/src/assets/types.d.ts.map +1 -0
- package/lib/typescript/src/assets/validation.d.ts +15 -0
- package/lib/typescript/src/assets/validation.d.ts.map +1 -0
- package/lib/typescript/src/core/frameDriver.d.ts +12 -0
- package/lib/typescript/src/core/frameDriver.d.ts.map +1 -0
- package/lib/typescript/src/core/input/createInputBuffer.d.ts +12 -0
- package/lib/typescript/src/core/input/createInputBuffer.d.ts.map +1 -0
- package/lib/typescript/src/core/input/types.d.ts +64 -0
- package/lib/typescript/src/core/input/types.d.ts.map +1 -0
- package/lib/typescript/src/core/session/createGameSession.d.ts +18 -0
- package/lib/typescript/src/core/session/createGameSession.d.ts.map +1 -0
- package/lib/typescript/src/core/session/deepFreeze.d.ts +27 -0
- package/lib/typescript/src/core/session/deepFreeze.d.ts.map +1 -0
- package/lib/typescript/src/core/session/diagnostics.d.ts +36 -0
- package/lib/typescript/src/core/session/diagnostics.d.ts.map +1 -0
- package/lib/typescript/src/core/session/types.d.ts +104 -0
- package/lib/typescript/src/core/session/types.d.ts.map +1 -0
- package/lib/typescript/src/definition/defineGame.d.ts +66 -0
- package/lib/typescript/src/definition/defineGame.d.ts.map +1 -0
- package/lib/typescript/src/definition/types.d.ts +56 -0
- package/lib/typescript/src/definition/types.d.ts.map +1 -0
- package/lib/typescript/src/geometry/types.d.ts +8 -0
- package/lib/typescript/src/geometry/types.d.ts.map +1 -0
- package/lib/typescript/src/index.d.ts +18 -0
- package/lib/typescript/src/index.d.ts.map +1 -0
- package/lib/typescript/src/react/GamePointerInput.d.ts +37 -0
- package/lib/typescript/src/react/GamePointerInput.d.ts.map +1 -0
- package/lib/typescript/src/react/GameView.d.ts +61 -0
- package/lib/typescript/src/react/GameView.d.ts.map +1 -0
- package/lib/typescript/src/react/alphaClock.d.ts +29 -0
- package/lib/typescript/src/react/alphaClock.d.ts.map +1 -0
- package/lib/typescript/src/react/assets/createGameAssetStore.d.ts +33 -0
- package/lib/typescript/src/react/assets/createGameAssetStore.d.ts.map +1 -0
- package/lib/typescript/src/react/assets/decodeSkiaImage.d.ts +12 -0
- package/lib/typescript/src/react/assets/decodeSkiaImage.d.ts.map +1 -0
- package/lib/typescript/src/react/assets/errors.d.ts +8 -0
- package/lib/typescript/src/react/assets/errors.d.ts.map +1 -0
- package/lib/typescript/src/react/assets/useGameAssets.d.ts +35 -0
- package/lib/typescript/src/react/assets/useGameAssets.d.ts.map +1 -0
- package/lib/typescript/src/react/bindAppLifecycle.d.ts +32 -0
- package/lib/typescript/src/react/bindAppLifecycle.d.ts.map +1 -0
- package/lib/typescript/src/react/bindGameSession.d.ts +14 -0
- package/lib/typescript/src/react/bindGameSession.d.ts.map +1 -0
- package/lib/typescript/src/react/gestureLifecycle.d.ts +37 -0
- package/lib/typescript/src/react/gestureLifecycle.d.ts.map +1 -0
- package/lib/typescript/src/react/instrumentation.d.ts +47 -0
- package/lib/typescript/src/react/instrumentation.d.ts.map +1 -0
- package/lib/typescript/src/react/pointerBinding.d.ts +104 -0
- package/lib/typescript/src/react/pointerBinding.d.ts.map +1 -0
- package/lib/typescript/src/react/pointerCoalescer.d.ts +106 -0
- package/lib/typescript/src/react/pointerCoalescer.d.ts.map +1 -0
- package/lib/typescript/src/react/pointerContainment.d.ts +12 -0
- package/lib/typescript/src/react/pointerContainment.d.ts.map +1 -0
- package/lib/typescript/src/react/sprites/GameSprite.d.ts +75 -0
- package/lib/typescript/src/react/sprites/GameSprite.d.ts.map +1 -0
- package/lib/typescript/src/react/sprites/GameWorld2D.d.ts +29 -0
- package/lib/typescript/src/react/sprites/GameWorld2D.d.ts.map +1 -0
- package/lib/typescript/src/react/sprites/Sprite.d.ts +43 -0
- package/lib/typescript/src/react/sprites/Sprite.d.ts.map +1 -0
- package/lib/typescript/src/react/sprites/SpriteBatch.d.ts +41 -0
- package/lib/typescript/src/react/sprites/SpriteBatch.d.ts.map +1 -0
- package/lib/typescript/src/react/sprites/spriteBatchPolicy.d.ts +10 -0
- package/lib/typescript/src/react/sprites/spriteBatchPolicy.d.ts.map +1 -0
- package/lib/typescript/src/react/sprites/spriteTransform.d.ts +86 -0
- package/lib/typescript/src/react/sprites/spriteTransform.d.ts.map +1 -0
- package/lib/typescript/src/react/viewportBinding.d.ts +42 -0
- package/lib/typescript/src/react/viewportBinding.d.ts.map +1 -0
- package/lib/typescript/src/react.d.ts +20 -0
- package/lib/typescript/src/react.d.ts.map +1 -0
- package/lib/typescript/src/scene/defineScene.d.ts +26 -0
- package/lib/typescript/src/scene/defineScene.d.ts.map +1 -0
- package/lib/typescript/src/scene/types.d.ts +71 -0
- package/lib/typescript/src/scene/types.d.ts.map +1 -0
- package/lib/typescript/src/sprites/sampleSpriteClip.d.ts +24 -0
- package/lib/typescript/src/sprites/sampleSpriteClip.d.ts.map +1 -0
- package/lib/typescript/src/sprites/spriteAnimationState.d.ts +45 -0
- package/lib/typescript/src/sprites/spriteAnimationState.d.ts.map +1 -0
- package/lib/typescript/src/testing.d.ts +28 -0
- package/lib/typescript/src/testing.d.ts.map +1 -0
- package/lib/typescript/src/viewport2d/index.d.ts +3 -0
- package/lib/typescript/src/viewport2d/index.d.ts.map +1 -0
- package/lib/typescript/src/viewport2d/math.d.ts +25 -0
- package/lib/typescript/src/viewport2d/math.d.ts.map +1 -0
- package/lib/typescript/src/viewport2d/types.d.ts +59 -0
- package/lib/typescript/src/viewport2d/types.d.ts.map +1 -0
- package/package.json +120 -0
- package/src/assets/defineAssets.ts +62 -0
- package/src/assets/errors.ts +64 -0
- package/src/assets/types.ts +164 -0
- package/src/assets/validation.ts +158 -0
- package/src/core/frameDriver.ts +31 -0
- package/src/core/input/createInputBuffer.ts +337 -0
- package/src/core/input/types.ts +67 -0
- package/src/core/session/createGameSession.ts +652 -0
- package/src/core/session/deepFreeze.ts +158 -0
- package/src/core/session/diagnostics.ts +35 -0
- package/src/core/session/types.ts +122 -0
- package/src/definition/defineGame.ts +94 -0
- package/src/definition/types.ts +67 -0
- package/src/geometry/types.ts +7 -0
- package/src/index.ts +84 -0
- package/src/react/GamePointerInput.tsx +478 -0
- package/src/react/GameView.tsx +317 -0
- package/src/react/alphaClock.ts +59 -0
- package/src/react/assets/createGameAssetStore.ts +459 -0
- package/src/react/assets/decodeSkiaImage.ts +64 -0
- package/src/react/assets/errors.ts +7 -0
- package/src/react/assets/useGameAssets.ts +171 -0
- package/src/react/bindAppLifecycle.ts +79 -0
- package/src/react/bindGameSession.ts +41 -0
- package/src/react/gestureLifecycle.ts +73 -0
- package/src/react/instrumentation.ts +54 -0
- package/src/react/pointerBinding.ts +226 -0
- package/src/react/pointerCoalescer.ts +234 -0
- package/src/react/pointerContainment.ts +23 -0
- package/src/react/sprites/GameSprite.tsx +192 -0
- package/src/react/sprites/GameWorld2D.tsx +46 -0
- package/src/react/sprites/Sprite.tsx +194 -0
- package/src/react/sprites/SpriteBatch.tsx +219 -0
- package/src/react/sprites/spriteBatchPolicy.ts +21 -0
- package/src/react/sprites/spriteTransform.ts +163 -0
- package/src/react/viewportBinding.ts +104 -0
- package/src/react.ts +37 -0
- package/src/scene/defineScene.ts +38 -0
- package/src/scene/types.ts +79 -0
- package/src/sprites/sampleSpriteClip.ts +51 -0
- package/src/sprites/spriteAnimationState.ts +176 -0
- package/src/testing.ts +61 -0
- package/src/viewport2d/index.ts +7 -0
- package/src/viewport2d/math.ts +134 -0
- package/src/viewport2d/types.ts +63 -0
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* UI-owned alpha clock (T5).
|
|
5
|
+
*
|
|
6
|
+
* Pure, worklet-safe presentation clock: `alpha` advances from UI frame
|
|
7
|
+
* deltas against the simulation step duration and resets to zero whenever a
|
|
8
|
+
* newer commit arrives. It never extrapolates past the current snapshot
|
|
9
|
+
* (clamped at 1, then held) and ignores stale or duplicate commits so a
|
|
10
|
+
* delayed write cannot reset presentation backward.
|
|
11
|
+
*
|
|
12
|
+
* The `epoch` guards session replacement: a new GameView binding carries a
|
|
13
|
+
* fresh epoch, so a replacement session whose revision restarts at zero is
|
|
14
|
+
* still accepted, while a delayed write from an old epoch is ignored.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
/** Advance the clock by one UI frame; returns the next alpha state. */
|
|
18
|
+
export function advanceAlpha(previous, commit, frameDeltaMs) {
|
|
19
|
+
'worklet';
|
|
20
|
+
|
|
21
|
+
if (commit.epoch > previous.epoch || commit.epoch === previous.epoch && commit.revision > previous.revision) {
|
|
22
|
+
return {
|
|
23
|
+
epoch: commit.epoch,
|
|
24
|
+
revision: commit.revision,
|
|
25
|
+
alpha: 0
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
if (commit.epoch < previous.epoch || commit.epoch === previous.epoch && commit.revision < previous.revision) {
|
|
29
|
+
return previous; // A stale write is ignored entirely, alpha preserved.
|
|
30
|
+
}
|
|
31
|
+
if (previous.alpha >= 1) {
|
|
32
|
+
return previous; // Clamp at 1: hold, never extrapolate.
|
|
33
|
+
}
|
|
34
|
+
const delta = Math.max(0, frameDeltaMs) / commit.stepMs;
|
|
35
|
+
const next = previous.alpha + delta;
|
|
36
|
+
return {
|
|
37
|
+
epoch: previous.epoch,
|
|
38
|
+
revision: previous.revision,
|
|
39
|
+
alpha: next >= 1 ? 1 : next
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=alphaClock.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["advanceAlpha","previous","commit","frameDeltaMs","epoch","revision","alpha","delta","Math","max","stepMs","next"],"sourceRoot":"../../../src","sources":["react/alphaClock.ts"],"mappings":";;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAiBA;AACA,OAAO,SAASA,YAAYA,CAC1BC,QAAyB,EACzBC,MAAwB,EACxBC,YAAoB,EACH;EACjB,SAAS;;EACT,IACED,MAAM,CAACE,KAAK,GAAGH,QAAQ,CAACG,KAAK,IAC5BF,MAAM,CAACE,KAAK,KAAKH,QAAQ,CAACG,KAAK,IAAIF,MAAM,CAACG,QAAQ,GAAGJ,QAAQ,CAACI,QAAS,EACxE;IACA,OAAO;MAAED,KAAK,EAAEF,MAAM,CAACE,KAAK;MAAEC,QAAQ,EAAEH,MAAM,CAACG,QAAQ;MAAEC,KAAK,EAAE;IAAE,CAAC;EACrE;EACA,IACEJ,MAAM,CAACE,KAAK,GAAGH,QAAQ,CAACG,KAAK,IAC5BF,MAAM,CAACE,KAAK,KAAKH,QAAQ,CAACG,KAAK,IAAIF,MAAM,CAACG,QAAQ,GAAGJ,QAAQ,CAACI,QAAS,EACxE;IACA,OAAOJ,QAAQ,CAAC,CAAC;EACnB;EACA,IAAIA,QAAQ,CAACK,KAAK,IAAI,CAAC,EAAE;IACvB,OAAOL,QAAQ,CAAC,CAAC;EACnB;EACA,MAAMM,KAAK,GAAGC,IAAI,CAACC,GAAG,CAAC,CAAC,EAAEN,YAAY,CAAC,GAAGD,MAAM,CAACQ,MAAM;EACvD,MAAMC,IAAI,GAAGV,QAAQ,CAACK,KAAK,GAAGC,KAAK;EACnC,OAAO;IACLH,KAAK,EAAEH,QAAQ,CAACG,KAAK;IACrBC,QAAQ,EAAEJ,QAAQ,CAACI,QAAQ;IAC3BC,KAAK,EAAEK,IAAI,IAAI,CAAC,GAAG,CAAC,GAAGA;EACzB,CAAC;AACH","ignoreList":[]}
|
|
@@ -0,0 +1,358 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Asset store core (T7.4).
|
|
5
|
+
*
|
|
6
|
+
* The explicit owner of the decoded-image cache. Source resolution and
|
|
7
|
+
* image decoding are injected so the ownership logic is unit-testable with
|
|
8
|
+
* fakes and never imports native modules itself.
|
|
9
|
+
*
|
|
10
|
+
* Ownership rules:
|
|
11
|
+
* - An explicitly created store owns cache/native entries.
|
|
12
|
+
* - `acquire` resolves only with a complete usable lease.
|
|
13
|
+
* - Reference counts keep a shared source alive across leases; the native
|
|
14
|
+
* handle is disposed exactly once when the final lease releases it.
|
|
15
|
+
* - A failed/abandoned attempt releases every handle it acquired; entries
|
|
16
|
+
* still leased elsewhere are preserved.
|
|
17
|
+
* - Attempts carry an epoch token: stale completion after retry/unmount is
|
|
18
|
+
* ignored and can never double-dispose.
|
|
19
|
+
* - `AbortSignal` detaches an imperative caller immediately; late results
|
|
20
|
+
* from the underlying work are ignored.
|
|
21
|
+
* - Progress is monotonic and counts requested logical resources (a
|
|
22
|
+
* deduplicated source still counts once per logical descriptor).
|
|
23
|
+
* - The store rejects acquisitions after disposal; disposal is idempotent.
|
|
24
|
+
*/
|
|
25
|
+
import { GameAssetError } from "../../assets/errors.js";
|
|
26
|
+
import { validateFrameRect } from "../../assets/validation.js";
|
|
27
|
+
import { GameAssetError as AssetStoreError } from "../../assets/errors.js";
|
|
28
|
+
|
|
29
|
+
/** Opaque decoded-image handle (Skia's SkImage satisfies this structurally). */
|
|
30
|
+
|
|
31
|
+
/** Injected source resolution and decode pipelines. */
|
|
32
|
+
|
|
33
|
+
/** Acquisition options for `acquire`. */
|
|
34
|
+
|
|
35
|
+
/** One idempotent ownership token: release() is safe to call repeatedly and
|
|
36
|
+
* disposes the native handle when it is the final reference (RF5). */
|
|
37
|
+
|
|
38
|
+
/** One logical (group, asset) identity inside a manifest. */
|
|
39
|
+
|
|
40
|
+
function logicalAssetsOf(manifest) {
|
|
41
|
+
const result = [];
|
|
42
|
+
for (const [group, assets] of Object.entries(manifest)) {
|
|
43
|
+
for (const [name, descriptor] of Object.entries(assets)) {
|
|
44
|
+
result.push({
|
|
45
|
+
key: `${group}/${name}`,
|
|
46
|
+
group,
|
|
47
|
+
name,
|
|
48
|
+
descriptor: descriptor
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
return result;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/** Validate a sprite sheet's frames against decoded dimensions. */
|
|
56
|
+
function validateFrames(path, frames, width, height) {
|
|
57
|
+
for (const [name, rect] of Object.entries(frames)) {
|
|
58
|
+
validateFrameRect(path, name, rect);
|
|
59
|
+
if (rect.x + rect.width > width || rect.y + rect.height > height) {
|
|
60
|
+
throw new GameAssetError('ASSET_FRAME_OUT_OF_BOUNDS', [...path, name], `frame ${JSON.stringify(name)} (${rect.x},${rect.y} ${rect.width}x${rect.height}) exceeds the decoded image ${width}x${height}`);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
export function createGameAssetStoreCore(manifest, pipelines) {
|
|
65
|
+
const groups = new Set(Object.keys(manifest));
|
|
66
|
+
const logical = logicalAssetsOf(manifest);
|
|
67
|
+
const byKey = new Map(logical.map(asset => [asset.key, asset]));
|
|
68
|
+
const resources = new Map();
|
|
69
|
+
let disposed = false;
|
|
70
|
+
let nextAttemptToken = 1;
|
|
71
|
+
/** Per-attempt ownership is explicit: the attempt object is passed through
|
|
72
|
+
* every resolve/decode/validate operation; no shared singleton (R4). */
|
|
73
|
+
|
|
74
|
+
function assertLive() {
|
|
75
|
+
if (disposed) {
|
|
76
|
+
throw new AssetStoreError('ASSET_STORE_DISPOSED', [], 'asset store is disposed');
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/** Race a promise with the abort signal; the listener is removed on
|
|
81
|
+
* resolve, reject, and abort (RF5). */
|
|
82
|
+
function raceWithAbort(promise, signal) {
|
|
83
|
+
if (signal === undefined) {
|
|
84
|
+
return promise;
|
|
85
|
+
}
|
|
86
|
+
return new Promise((resolve, reject) => {
|
|
87
|
+
const onAbort = () => {
|
|
88
|
+
reject(new AssetStoreError('ASSET_ABORTED', [], 'asset acquisition aborted'));
|
|
89
|
+
};
|
|
90
|
+
signal.addEventListener('abort', onAbort, {
|
|
91
|
+
once: true
|
|
92
|
+
});
|
|
93
|
+
promise.then(value => {
|
|
94
|
+
signal.removeEventListener('abort', onAbort);
|
|
95
|
+
resolve(value);
|
|
96
|
+
}, error => {
|
|
97
|
+
signal.removeEventListener('abort', onAbort);
|
|
98
|
+
reject(error);
|
|
99
|
+
});
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/** Drop one reference held by a caller that never recorded a logical key. */
|
|
104
|
+
function dropResourceRef(uri) {
|
|
105
|
+
const entry = resources.get(uri);
|
|
106
|
+
if (entry === undefined) {
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
entry.refCount -= 1;
|
|
110
|
+
if (entry.refCount <= 0) {
|
|
111
|
+
if (entry.handle !== undefined) {
|
|
112
|
+
entry.handle.dispose();
|
|
113
|
+
}
|
|
114
|
+
resources.delete(uri);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Begin one owned reference to a resource. Every waiter — cache miss,
|
|
120
|
+
* in-flight share, or completed cache hit — goes through this single
|
|
121
|
+
* accounting path and receives an idempotent release closure (RF5). The
|
|
122
|
+
* caller must either commit the ref to the attempt or call release()
|
|
123
|
+
* exactly once; the final release disposes the native handle.
|
|
124
|
+
*/
|
|
125
|
+
function beginResourceRef(uri) {
|
|
126
|
+
const existing = resources.get(uri);
|
|
127
|
+
let entry;
|
|
128
|
+
if (existing !== undefined && existing.handle !== undefined) {
|
|
129
|
+
// Completed cache hit.
|
|
130
|
+
entry = existing;
|
|
131
|
+
entry.refCount += 1;
|
|
132
|
+
const handle = existing.handle;
|
|
133
|
+
return {
|
|
134
|
+
release: () => dropResourceRef(uri),
|
|
135
|
+
ready: async () => handle
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
if (existing !== undefined && existing.inFlight !== undefined) {
|
|
139
|
+
// Shared in-flight decode.
|
|
140
|
+
entry = existing;
|
|
141
|
+
entry.refCount += 1;
|
|
142
|
+
const shared = existing.inFlight;
|
|
143
|
+
return {
|
|
144
|
+
release: () => dropResourceRef(uri),
|
|
145
|
+
ready: async () => shared
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
// Cache miss: this waiter starts the decode.
|
|
149
|
+
entry = {
|
|
150
|
+
uri,
|
|
151
|
+
handle: undefined,
|
|
152
|
+
inFlight: undefined,
|
|
153
|
+
logicalKeys: new Set(),
|
|
154
|
+
refCount: 1
|
|
155
|
+
};
|
|
156
|
+
resources.set(uri, entry);
|
|
157
|
+
const promise = (async () => {
|
|
158
|
+
const handle = await pipelines.decode(uri);
|
|
159
|
+
// A late completion must never resurrect a disposed store or an entry
|
|
160
|
+
// whose last waiter aborted while the decode was in flight.
|
|
161
|
+
if (disposed || entry.refCount <= 0) {
|
|
162
|
+
handle.dispose();
|
|
163
|
+
if (entry.refCount <= 0) {
|
|
164
|
+
resources.delete(uri);
|
|
165
|
+
}
|
|
166
|
+
throw new AssetStoreError('ASSET_ABORTED', [], 'asset acquisition aborted');
|
|
167
|
+
}
|
|
168
|
+
entry.handle = handle;
|
|
169
|
+
return handle;
|
|
170
|
+
})();
|
|
171
|
+
entry.inFlight = promise;
|
|
172
|
+
void promise.then(() => {
|
|
173
|
+
entry.inFlight = undefined;
|
|
174
|
+
}, () => {
|
|
175
|
+
entry.inFlight = undefined;
|
|
176
|
+
});
|
|
177
|
+
return {
|
|
178
|
+
release: () => dropResourceRef(uri),
|
|
179
|
+
ready: async () => promise
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
async function acquireOne(asset, attempt, signal) {
|
|
183
|
+
const uri = await raceWithAbort(pipelines.resolve(asset.descriptor.source), signal);
|
|
184
|
+
// RF5: the reference token exists before any cancellable await; abort
|
|
185
|
+
// can never leave a positive reference behind.
|
|
186
|
+
const ref = beginResourceRef(uri);
|
|
187
|
+
try {
|
|
188
|
+
const handle = await raceWithAbort(ref.ready(), signal);
|
|
189
|
+
attempt.acquired.push(ref);
|
|
190
|
+
const entry = resources.get(uri);
|
|
191
|
+
if (entry !== undefined) {
|
|
192
|
+
entry.logicalKeys.add(asset.key);
|
|
193
|
+
}
|
|
194
|
+
if (asset.descriptor.kind === 'sprite-sheet') {
|
|
195
|
+
validateFrames([asset.group, asset.name, 'frames'], asset.descriptor.frames, handle.width(), handle.height());
|
|
196
|
+
}
|
|
197
|
+
} catch (error) {
|
|
198
|
+
// Every failure, abort, and stale completion releases this waiter's
|
|
199
|
+
// reference exactly once; surviving owners keep theirs.
|
|
200
|
+
ref.release();
|
|
201
|
+
throw error;
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
const acquire = async options => {
|
|
205
|
+
assertLive();
|
|
206
|
+
const {
|
|
207
|
+
signal
|
|
208
|
+
} = options;
|
|
209
|
+
const throwIfAborted = () => {
|
|
210
|
+
if (signal?.aborted === true) {
|
|
211
|
+
throw new AssetStoreError('ASSET_ABORTED', [], 'asset acquisition aborted');
|
|
212
|
+
}
|
|
213
|
+
};
|
|
214
|
+
throwIfAborted();
|
|
215
|
+
|
|
216
|
+
// RF5: normalize groups at the public boundary (dedupe) and use the
|
|
217
|
+
// same list for the progress total and acquisition.
|
|
218
|
+
const groupsNormalized = [...new Set(options.groups)];
|
|
219
|
+
const requested = [];
|
|
220
|
+
for (const group of groupsNormalized) {
|
|
221
|
+
if (!groups.has(group)) {
|
|
222
|
+
throw new GameAssetError('ASSET_UNKNOWN_GROUP', [group], `unknown asset group ${JSON.stringify(group)}`);
|
|
223
|
+
}
|
|
224
|
+
for (const asset of logical) {
|
|
225
|
+
if (asset.group === group) {
|
|
226
|
+
requested.push(asset);
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
if (requested.length === 0) {
|
|
231
|
+
// Empty group set resolves immediately with progress 1 and no resources.
|
|
232
|
+
options.onProgress?.(1);
|
|
233
|
+
return createLease(new Map(), () => undefined);
|
|
234
|
+
}
|
|
235
|
+
const token = nextAttemptToken;
|
|
236
|
+
nextAttemptToken += 1;
|
|
237
|
+
const attempt = {
|
|
238
|
+
token,
|
|
239
|
+
acquired: []
|
|
240
|
+
};
|
|
241
|
+
const loaded = new Map();
|
|
242
|
+
try {
|
|
243
|
+
let completed = 0;
|
|
244
|
+
const total = requested.length;
|
|
245
|
+
for (const asset of requested) {
|
|
246
|
+
throwIfAborted();
|
|
247
|
+
await acquireOne(asset, attempt, signal);
|
|
248
|
+
loaded.set(asset.key, asset.key);
|
|
249
|
+
completed += 1;
|
|
250
|
+
options.onProgress?.(completed / total);
|
|
251
|
+
}
|
|
252
|
+
return createLease(loaded, () => {
|
|
253
|
+
for (const ref of attempt.acquired) {
|
|
254
|
+
ref.release();
|
|
255
|
+
}
|
|
256
|
+
});
|
|
257
|
+
} catch (error) {
|
|
258
|
+
// Release every reference this attempt acquired exactly once; entries
|
|
259
|
+
// still leased by a previous lease keep their references.
|
|
260
|
+
for (const ref of attempt.acquired) {
|
|
261
|
+
ref.release();
|
|
262
|
+
}
|
|
263
|
+
throw error;
|
|
264
|
+
}
|
|
265
|
+
};
|
|
266
|
+
function createLease(loadedKeys, onDispose) {
|
|
267
|
+
let leaseDisposed = false;
|
|
268
|
+
const loaded = new Map();
|
|
269
|
+
for (const key of loadedKeys.keys()) {
|
|
270
|
+
const asset = byKey.get(key);
|
|
271
|
+
if (asset !== undefined) {
|
|
272
|
+
loaded.set(key, asset);
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
const assets = {
|
|
276
|
+
manifest,
|
|
277
|
+
get: descriptor => {
|
|
278
|
+
assertLive();
|
|
279
|
+
if (leaseDisposed) {
|
|
280
|
+
throw new AssetStoreError('ASSET_STORE_DISPOSED', [], 'lease is disposed');
|
|
281
|
+
}
|
|
282
|
+
const entry = findLoadedFor(descriptor, loaded);
|
|
283
|
+
if (entry === undefined) {
|
|
284
|
+
// R9: v1 lookup is descriptor-reference membership — the exact
|
|
285
|
+
// descriptor object the manifest declared — not a nominal manifest
|
|
286
|
+
// identity. Identically shaped manifests share the structural type,
|
|
287
|
+
// so the type layer cannot distinguish them; the runtime reference
|
|
288
|
+
// check is the guarantee.
|
|
289
|
+
throw new GameAssetError('ASSET_UNKNOWN_ASSET', [], 'descriptor is not a reference declared by this manifest and group selection');
|
|
290
|
+
}
|
|
291
|
+
return entry;
|
|
292
|
+
}
|
|
293
|
+
};
|
|
294
|
+
return {
|
|
295
|
+
assets,
|
|
296
|
+
dispose: () => {
|
|
297
|
+
if (leaseDisposed) {
|
|
298
|
+
return;
|
|
299
|
+
}
|
|
300
|
+
leaseDisposed = true;
|
|
301
|
+
onDispose();
|
|
302
|
+
}
|
|
303
|
+
};
|
|
304
|
+
}
|
|
305
|
+
function findLoadedFor(descriptor, loaded) {
|
|
306
|
+
for (const asset of loaded.values()) {
|
|
307
|
+
if (asset.descriptor === descriptor) {
|
|
308
|
+
const entry = entryFor(asset.key);
|
|
309
|
+
const handle = entry?.handle;
|
|
310
|
+
const width = handle?.width() ?? 0;
|
|
311
|
+
const height = handle?.height() ?? 0;
|
|
312
|
+
if (asset.descriptor.kind === 'image') {
|
|
313
|
+
return {
|
|
314
|
+
descriptor: asset.descriptor,
|
|
315
|
+
width,
|
|
316
|
+
height,
|
|
317
|
+
image: handle
|
|
318
|
+
};
|
|
319
|
+
}
|
|
320
|
+
return {
|
|
321
|
+
descriptor: asset.descriptor,
|
|
322
|
+
frames: asset.descriptor.frames,
|
|
323
|
+
width,
|
|
324
|
+
height,
|
|
325
|
+
image: handle
|
|
326
|
+
};
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
return undefined;
|
|
330
|
+
}
|
|
331
|
+
function entryFor(logicalKey) {
|
|
332
|
+
for (const entry of resources.values()) {
|
|
333
|
+
if (entry.logicalKeys.has(logicalKey)) {
|
|
334
|
+
return entry;
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
return undefined;
|
|
338
|
+
}
|
|
339
|
+
return {
|
|
340
|
+
acquire,
|
|
341
|
+
dispose: () => {
|
|
342
|
+
if (disposed) {
|
|
343
|
+
return;
|
|
344
|
+
}
|
|
345
|
+
disposed = true;
|
|
346
|
+
// Drop entries with no live lease; leased entries stay until their
|
|
347
|
+
// lease releases them (their refCount keeps them alive).
|
|
348
|
+
for (const [uri, entry] of resources) {
|
|
349
|
+
if (entry.refCount <= 0 && entry.handle !== undefined) {
|
|
350
|
+
entry.handle.dispose();
|
|
351
|
+
resources.delete(uri);
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
},
|
|
355
|
+
isDisposed: () => disposed
|
|
356
|
+
};
|
|
357
|
+
}
|
|
358
|
+
//# sourceMappingURL=createGameAssetStore.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["GameAssetError","validateFrameRect","AssetStoreError","logicalAssetsOf","manifest","result","group","assets","Object","entries","name","descriptor","push","key","validateFrames","path","frames","width","height","rect","x","y","JSON","stringify","createGameAssetStoreCore","pipelines","groups","Set","keys","logical","byKey","Map","map","asset","resources","disposed","nextAttemptToken","assertLive","raceWithAbort","promise","signal","undefined","Promise","resolve","reject","onAbort","addEventListener","once","then","value","removeEventListener","error","dropResourceRef","uri","entry","get","refCount","handle","dispose","delete","beginResourceRef","existing","release","ready","inFlight","shared","logicalKeys","set","decode","acquireOne","attempt","source","ref","acquired","add","kind","acquire","options","throwIfAborted","aborted","groupsNormalized","requested","has","length","onProgress","createLease","token","loaded","completed","total","loadedKeys","onDispose","leaseDisposed","findLoadedFor","values","entryFor","image","logicalKey","isDisposed"],"sourceRoot":"../../../../src","sources":["react/assets/createGameAssetStore.ts"],"mappings":"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","ignoreList":[]}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Default Expo/Skia asset pipelines (T7.4).
|
|
5
|
+
*
|
|
6
|
+
* Exact primitives used (verified against the installed types, Skia 2.11.0
|
|
7
|
+
* and expo-asset SDK 57):
|
|
8
|
+
* - `Asset.fromModule(source)` -> `await asset.downloadAsync()` ->
|
|
9
|
+
* `asset.localUri ?? asset.uri` (canonical local URI; static module
|
|
10
|
+
* handles only);
|
|
11
|
+
* - `Skia.Data.fromURI(uri)` -> `SkData` (disposed as soon as the image is
|
|
12
|
+
* created — `SkImage.MakeImageFromEncoded` copies the encoded bytes);
|
|
13
|
+
* - `Skia.Image.MakeImageFromEncoded(data)` -> `SkImage | null` (null is a
|
|
14
|
+
* structured load failure, never a ready resource).
|
|
15
|
+
*/
|
|
16
|
+
import { Asset } from 'expo-asset';
|
|
17
|
+
import { Skia } from '@shopify/react-native-skia';
|
|
18
|
+
import { GameAssetError } from "../../assets/errors.js";
|
|
19
|
+
import { createGameAssetStoreCore } from "./createGameAssetStore.js";
|
|
20
|
+
const resolvePipeline = async source => {
|
|
21
|
+
const asset = Asset.fromModule(source);
|
|
22
|
+
try {
|
|
23
|
+
await asset.downloadAsync();
|
|
24
|
+
} catch (error) {
|
|
25
|
+
throw new GameAssetError('ASSET_RESOLVE_FAILED', [], `failed to resolve static asset module ${source}: ${error instanceof Error ? error.message : String(error)}`);
|
|
26
|
+
}
|
|
27
|
+
return asset.localUri ?? asset.uri;
|
|
28
|
+
};
|
|
29
|
+
const decodePipeline = async uri => {
|
|
30
|
+
const data = await Skia.Data.fromURI(uri);
|
|
31
|
+
try {
|
|
32
|
+
const image = Skia.Image.MakeImageFromEncoded(data);
|
|
33
|
+
if (image === null) {
|
|
34
|
+
throw new GameAssetError('ASSET_DECODE_FAILED', [], `decoding ${uri} produced no image`);
|
|
35
|
+
}
|
|
36
|
+
return image;
|
|
37
|
+
} finally {
|
|
38
|
+
data.dispose();
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Create the explicit asset-store owner for a manifest using the default
|
|
44
|
+
* Expo/Skia pipelines. Callers dispose the lease then the store in
|
|
45
|
+
* `finally`.
|
|
46
|
+
*/
|
|
47
|
+
export function createGameAssetStore(manifest) {
|
|
48
|
+
// The return type keeps the manifest generic so leases stay typed.
|
|
49
|
+
return createGameAssetStoreCore(manifest, {
|
|
50
|
+
resolve: resolvePipeline,
|
|
51
|
+
decode: decodePipeline
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
//# sourceMappingURL=decodeSkiaImage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["Asset","Skia","GameAssetError","createGameAssetStoreCore","resolvePipeline","source","asset","fromModule","downloadAsync","error","Error","message","String","localUri","uri","decodePipeline","data","Data","fromURI","image","Image","MakeImageFromEncoded","dispose","createGameAssetStore","manifest","resolve","decode"],"sourceRoot":"../../../../src","sources":["react/assets/decodeSkiaImage.ts"],"mappings":";;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAASA,KAAK,QAAQ,YAAY;AAClC,SAASC,IAAI,QAAQ,4BAA4B;AAEjD,SAASC,cAAc,QAAQ,wBAAqB;AAEpD,SACEC,wBAAwB,QAEnB,2BAAwB;AAE/B,MAAMC,eAAe,GAAG,MAAOC,MAAc,IAAsB;EACjE,MAAMC,KAAK,GAAGN,KAAK,CAACO,UAAU,CAACF,MAAM,CAAC;EACtC,IAAI;IACF,MAAMC,KAAK,CAACE,aAAa,CAAC,CAAC;EAC7B,CAAC,CAAC,OAAOC,KAAK,EAAE;IACd,MAAM,IAAIP,cAAc,CACtB,sBAAsB,EACtB,EAAE,EACF,yCAAyCG,MAAM,KAAKI,KAAK,YAAYC,KAAK,GAAGD,KAAK,CAACE,OAAO,GAAGC,MAAM,CAACH,KAAK,CAAC,EAC5G,CAAC;EACH;EACA,OAAOH,KAAK,CAACO,QAAQ,IAAIP,KAAK,CAACQ,GAAG;AACpC,CAAC;AAED,MAAMC,cAAc,GAAG,MAAOD,GAAW,IAAiC;EACxE,MAAME,IAAI,GAAG,MAAMf,IAAI,CAACgB,IAAI,CAACC,OAAO,CAACJ,GAAG,CAAC;EACzC,IAAI;IACF,MAAMK,KAAK,GAAGlB,IAAI,CAACmB,KAAK,CAACC,oBAAoB,CAACL,IAAI,CAAC;IACnD,IAAIG,KAAK,KAAK,IAAI,EAAE;MAClB,MAAM,IAAIjB,cAAc,CAAC,qBAAqB,EAAE,EAAE,EAAE,YAAYY,GAAG,oBAAoB,CAAC;IAC1F;IACA,OAAOK,KAAK;EACd,CAAC,SAAS;IACRH,IAAI,CAACM,OAAO,CAAC,CAAC;EAChB;AACF,CAAC;;AAED;AACA;AACA;AACA;AACA;AACA,OAAO,SAASC,oBAAoBA,CAClCC,QAAmB,EACnB;EACA;EACA,OAAOrB,wBAAwB,CAACqB,QAAQ,EAAE;IACxCC,OAAO,EAAErB,eAAe;IACxBsB,MAAM,EAAEX;EACV,CAAC,CAAC;AACJ","ignoreList":[]}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Asset store errors (T7.4).
|
|
5
|
+
*
|
|
6
|
+
* The store adds no error codes of its own: every failure is a structured
|
|
7
|
+
* `GameAssetError` with a stable code and field path.
|
|
8
|
+
*/
|
|
9
|
+
export { GameAssetError } from "../../assets/errors.js";
|
|
10
|
+
//# sourceMappingURL=errors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["GameAssetError"],"sourceRoot":"../../../../src","sources":["react/assets/errors.ts"],"mappings":";;AAAA;AACA;AACA;AACA;AACA;AACA;AACA,SAASA,cAAc,QAAQ,wBAAqB","ignoreList":[]}
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* `useGameAssets` — the React loading adapter (T7.5).
|
|
5
|
+
*
|
|
6
|
+
* The hook creates and owns one asset store and lease for the requested
|
|
7
|
+
* groups; the caller must not dispose the returned ready value manually.
|
|
8
|
+
*
|
|
9
|
+
* Contract:
|
|
10
|
+
* - `{ status: 'loading'; progress }` — progress in [0, 1], monotonic;
|
|
11
|
+
* - `{ status: 'error'; error; retry }` — structured error + stable retry;
|
|
12
|
+
* - `{ status: 'ready'; assets }` — the complete lease, typed to the
|
|
13
|
+
* manifest.
|
|
14
|
+
*
|
|
15
|
+
* Lifecycle:
|
|
16
|
+
* - The requested group list is normalized (sorted) so a recreated
|
|
17
|
+
* equivalent array does not reload.
|
|
18
|
+
* - Retry starts a new attempt; late completion from an older attempt can
|
|
19
|
+
* never replace the new state.
|
|
20
|
+
* - Unmount invalidates the attempt, releases the lease, and disposes the
|
|
21
|
+
* store — hook-owned resources are released exactly once.
|
|
22
|
+
*/
|
|
23
|
+
import { useCallback, useEffect, useRef, useState } from 'react';
|
|
24
|
+
import { GameAssetError } from "../../assets/errors.js";
|
|
25
|
+
|
|
26
|
+
/** The store surface the hook needs, kept generic over the manifest. */
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Default store factory using the Expo/Skia pipelines. The wiring module is
|
|
30
|
+
* required lazily so the hook's import graph stays headless (tests inject
|
|
31
|
+
* their own factory and never touch the native side).
|
|
32
|
+
*/
|
|
33
|
+
function defaultStoreFactory(manifest) {
|
|
34
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
35
|
+
const {
|
|
36
|
+
createGameAssetStore
|
|
37
|
+
} = require('./decodeSkiaImage');
|
|
38
|
+
return createGameAssetStore(manifest);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/** The discriminated loading state machine. Every state carries the
|
|
42
|
+
* normalized request key (RF7) so a rendered request that differs from the
|
|
43
|
+
* state's request can never expose a stale lease. */
|
|
44
|
+
|
|
45
|
+
/** Deduplicate and sort groups so equivalent reordered/duplicated arrays
|
|
46
|
+
* map to one key and one acquisition (R6). */
|
|
47
|
+
export function dedupeGroups(groups) {
|
|
48
|
+
return [...new Set(groups)].sort();
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/** Order-independent group key: equivalent arrays map to one key. */
|
|
52
|
+
export function stableGroupsKey(groups) {
|
|
53
|
+
return dedupeGroups(groups).join('\u0000');
|
|
54
|
+
}
|
|
55
|
+
export function useGameAssets(manifest, options, storeFactory) {
|
|
56
|
+
const groupsKey = stableGroupsKey(options.groups);
|
|
57
|
+
const [attempt, setAttempt] = useState(0);
|
|
58
|
+
const [state, setState] = useState({
|
|
59
|
+
status: 'loading',
|
|
60
|
+
progress: 0,
|
|
61
|
+
retry: () => undefined,
|
|
62
|
+
requestKey: groupsKey
|
|
63
|
+
});
|
|
64
|
+
const storeRef = useRef(undefined);
|
|
65
|
+
const leaseRef = useRef(undefined);
|
|
66
|
+
const retry = useCallback(() => {
|
|
67
|
+
// R6: one user action starts exactly one new attempt; the same function
|
|
68
|
+
// identity is exposed in loading and error states.
|
|
69
|
+
setAttempt(current => current + 1);
|
|
70
|
+
}, []);
|
|
71
|
+
|
|
72
|
+
// Ref mirror of the attempt so stale-effect completions are rejected
|
|
73
|
+
// after a retry re-renders with a higher attempt.
|
|
74
|
+
const attemptRef = useRef(attempt);
|
|
75
|
+
attemptRef.current = attempt;
|
|
76
|
+
|
|
77
|
+
// RF7: if the rendered request differs from the state's request, expose
|
|
78
|
+
// loading synchronously instead of the previous ready lease — the old
|
|
79
|
+
// lease is disposed by the effect cleanup, so no consumer can observe it
|
|
80
|
+
// under the new request.
|
|
81
|
+
if (state.requestKey !== groupsKey && state.status === 'ready') {
|
|
82
|
+
return {
|
|
83
|
+
status: 'loading',
|
|
84
|
+
progress: 0,
|
|
85
|
+
retry,
|
|
86
|
+
requestKey: groupsKey
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
useEffect(() => {
|
|
90
|
+
const store = (storeFactory ?? defaultStoreFactory)(manifest);
|
|
91
|
+
storeRef.current = store;
|
|
92
|
+
let disposed = false;
|
|
93
|
+
const attemptAtStart = attempt;
|
|
94
|
+
const isCurrent = () => attemptRef.current === attemptAtStart;
|
|
95
|
+
const setIfCurrent = updater => {
|
|
96
|
+
if (!disposed && isCurrent()) {
|
|
97
|
+
setState(updater);
|
|
98
|
+
}
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
// R6: every attempt owns an AbortController; aborting detaches the
|
|
102
|
+
// caller and rejects late progress/ready/error from older configs.
|
|
103
|
+
const controller = new AbortController();
|
|
104
|
+
setState({
|
|
105
|
+
status: 'loading',
|
|
106
|
+
progress: 0,
|
|
107
|
+
retry: retry,
|
|
108
|
+
requestKey: groupsKey
|
|
109
|
+
});
|
|
110
|
+
store.acquire({
|
|
111
|
+
groups: dedupeGroups(options.groups),
|
|
112
|
+
signal: controller.signal,
|
|
113
|
+
onProgress: progress => {
|
|
114
|
+
setIfCurrent(previous => previous.status === 'loading' ? {
|
|
115
|
+
...previous,
|
|
116
|
+
progress
|
|
117
|
+
} : previous);
|
|
118
|
+
}
|
|
119
|
+
}).then(lease => {
|
|
120
|
+
if (disposed || !isCurrent()) {
|
|
121
|
+
// Stale completion (retry/unmount): release immediately.
|
|
122
|
+
lease.dispose();
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
leaseRef.current?.dispose();
|
|
126
|
+
leaseRef.current = lease;
|
|
127
|
+
setState({
|
|
128
|
+
status: 'ready',
|
|
129
|
+
assets: lease.assets,
|
|
130
|
+
requestKey: groupsKey
|
|
131
|
+
});
|
|
132
|
+
}).catch(error => {
|
|
133
|
+
if (disposed || !isCurrent()) {
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
const structured = error instanceof GameAssetError ? error : new GameAssetError('ASSET_DECODE_FAILED', [], error instanceof Error ? error.message : String(error));
|
|
137
|
+
setState({
|
|
138
|
+
status: 'error',
|
|
139
|
+
error: structured,
|
|
140
|
+
retry,
|
|
141
|
+
requestKey: groupsKey
|
|
142
|
+
});
|
|
143
|
+
});
|
|
144
|
+
return () => {
|
|
145
|
+
disposed = true;
|
|
146
|
+
// R6: abort before releasing so no late completion can touch state or
|
|
147
|
+
// resources, then release the lease and store exactly once.
|
|
148
|
+
controller.abort();
|
|
149
|
+
leaseRef.current?.dispose();
|
|
150
|
+
leaseRef.current = undefined;
|
|
151
|
+
storeRef.current = undefined;
|
|
152
|
+
store.dispose();
|
|
153
|
+
};
|
|
154
|
+
// The groups key is order-independent, so a recreated equivalent array
|
|
155
|
+
// does not reload; the attempt state drives retries. The store factory
|
|
156
|
+
// is the internal test seam and must be stable across renders.
|
|
157
|
+
}, [attempt, groupsKey, manifest, storeFactory]);
|
|
158
|
+
return state;
|
|
159
|
+
}
|
|
160
|
+
//# sourceMappingURL=useGameAssets.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["useCallback","useEffect","useRef","useState","GameAssetError","defaultStoreFactory","manifest","createGameAssetStore","require","dedupeGroups","groups","Set","sort","stableGroupsKey","join","useGameAssets","options","storeFactory","groupsKey","attempt","setAttempt","state","setState","status","progress","retry","undefined","requestKey","storeRef","leaseRef","current","attemptRef","store","disposed","attemptAtStart","isCurrent","setIfCurrent","updater","controller","AbortController","acquire","signal","onProgress","previous","then","lease","dispose","assets","catch","error","structured","Error","message","String","abort"],"sourceRoot":"../../../../src","sources":["react/assets/useGameAssets.ts"],"mappings":"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","ignoreList":[]}
|