rn-gamekit 0.1.0 → 0.2.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 +68 -0
- package/README.md +95 -14
- package/lib/module/assets/defineAssets.js +28 -3
- package/lib/module/assets/defineAssets.js.map +1 -1
- package/lib/module/assets.js +11 -0
- package/lib/module/assets.js.map +1 -0
- package/lib/module/audio/createGameAudio.js +784 -0
- package/lib/module/audio/createGameAudio.js.map +1 -0
- package/lib/module/audio/errors.js +12 -0
- package/lib/module/audio/errors.js.map +1 -0
- package/lib/module/audio/index.js +5 -0
- package/lib/module/audio/index.js.map +1 -0
- package/lib/module/audio/resolver.js +37 -0
- package/lib/module/audio/resolver.js.map +1 -0
- package/lib/module/audio/types.js +4 -0
- package/lib/module/audio/types.js.map +1 -0
- package/lib/module/audio.js +9 -0
- package/lib/module/audio.js.map +1 -0
- package/lib/module/camera2d/bounds.js +59 -0
- package/lib/module/camera2d/bounds.js.map +1 -0
- package/lib/module/camera2d/extents.js +25 -0
- package/lib/module/camera2d/extents.js.map +1 -0
- package/lib/module/camera2d/follow.js +138 -0
- package/lib/module/camera2d/follow.js.map +1 -0
- package/lib/module/camera2d/index.js +20 -0
- package/lib/module/camera2d/index.js.map +1 -0
- package/lib/module/camera2d/interpolation.js +98 -0
- package/lib/module/camera2d/interpolation.js.map +1 -0
- package/lib/module/camera2d/shake.js +85 -0
- package/lib/module/camera2d/shake.js.map +1 -0
- package/lib/module/camera2d/transform.js +151 -0
- package/lib/module/camera2d/transform.js.map +1 -0
- package/lib/module/camera2d/types.js +4 -0
- package/lib/module/camera2d/types.js.map +1 -0
- package/lib/module/camera2d/validation.js +98 -0
- package/lib/module/camera2d/validation.js.map +1 -0
- package/lib/module/camera2d/visibility.js +138 -0
- package/lib/module/camera2d/visibility.js.map +1 -0
- package/lib/module/camera2d.js +9 -0
- package/lib/module/camera2d.js.map +1 -0
- package/lib/module/collision2d/colliders.js +266 -0
- package/lib/module/collision2d/colliders.js.map +1 -0
- package/lib/module/collision2d/debug.js +105 -0
- package/lib/module/collision2d/debug.js.map +1 -0
- package/lib/module/collision2d/filters.js +40 -0
- package/lib/module/collision2d/filters.js.map +1 -0
- package/lib/module/collision2d/index.js +12 -0
- package/lib/module/collision2d/index.js.map +1 -0
- package/lib/module/collision2d/intersections.js +67 -0
- package/lib/module/collision2d/intersections.js.map +1 -0
- package/lib/module/collision2d/manifolds.js +218 -0
- package/lib/module/collision2d/manifolds.js.map +1 -0
- package/lib/module/collision2d/segments.js +187 -0
- package/lib/module/collision2d/segments.js.map +1 -0
- package/lib/module/collision2d/spatialHash.js +167 -0
- package/lib/module/collision2d/spatialHash.js.map +1 -0
- package/lib/module/collision2d/sweeps.js +255 -0
- package/lib/module/collision2d/sweeps.js.map +1 -0
- package/lib/module/collision2d.js +9 -0
- package/lib/module/collision2d.js.map +1 -0
- package/lib/module/core/input/buttonPad.js +214 -0
- package/lib/module/core/input/buttonPad.js.map +1 -0
- package/lib/module/core/input/createInputBuffer.js +66 -14
- package/lib/module/core/input/createInputBuffer.js.map +1 -1
- package/lib/module/core/session/createGameSession.js +454 -50
- package/lib/module/core/session/createGameSession.js.map +1 -1
- package/lib/module/core/session/deepFreeze.js +92 -2
- package/lib/module/core/session/deepFreeze.js.map +1 -1
- package/lib/module/core/session/types.js +12 -0
- package/lib/module/core/session/types.js.map +1 -1
- package/lib/module/definition/defineGame.js +23 -0
- package/lib/module/definition/defineGame.js.map +1 -1
- package/lib/module/events/defineGameEvents.js +46 -0
- package/lib/module/events/defineGameEvents.js.map +1 -0
- package/lib/module/events/errors.js +16 -0
- package/lib/module/events/errors.js.map +1 -0
- package/lib/module/events/index.js +7 -0
- package/lib/module/events/index.js.map +1 -0
- package/lib/module/events/payload.js +219 -0
- package/lib/module/events/payload.js.map +1 -0
- package/lib/module/events/seed.js +33 -0
- package/lib/module/events/seed.js.map +1 -0
- package/lib/module/events/types.js +4 -0
- package/lib/module/events/types.js.map +1 -0
- package/lib/module/events.js +13 -0
- package/lib/module/events.js.map +1 -0
- package/lib/module/geometry/helpers.js +140 -0
- package/lib/module/geometry/helpers.js.map +1 -0
- package/lib/module/geometry/index.js +5 -0
- package/lib/module/geometry/index.js.map +1 -0
- package/lib/module/geometry/validation.js +104 -0
- package/lib/module/geometry/validation.js.map +1 -0
- package/lib/module/geometry.js +9 -0
- package/lib/module/geometry.js.map +1 -0
- package/lib/module/haptics/createGameHaptics.js +214 -0
- package/lib/module/haptics/createGameHaptics.js.map +1 -0
- package/lib/module/haptics/errors.js +12 -0
- package/lib/module/haptics/errors.js.map +1 -0
- package/lib/module/haptics/index.js +5 -0
- package/lib/module/haptics/index.js.map +1 -0
- package/lib/module/haptics/resolver.js +37 -0
- package/lib/module/haptics/resolver.js.map +1 -0
- package/lib/module/haptics/types.js +4 -0
- package/lib/module/haptics/types.js.map +1 -0
- package/lib/module/haptics.js +9 -0
- package/lib/module/haptics.js.map +1 -0
- package/lib/module/index.js +8 -1
- package/lib/module/index.js.map +1 -1
- package/lib/module/particles/createParticleSystem.js +481 -0
- package/lib/module/particles/createParticleSystem.js.map +1 -0
- package/lib/module/particles/defineParticleEffect.js +178 -0
- package/lib/module/particles/defineParticleEffect.js.map +1 -0
- package/lib/module/particles/errors.js +9 -0
- package/lib/module/particles/errors.js.map +1 -0
- package/lib/module/particles/index.js +8 -0
- package/lib/module/particles/index.js.map +1 -0
- package/lib/module/particles/sampling.js +121 -0
- package/lib/module/particles/sampling.js.map +1 -0
- package/lib/module/particles/types.js +4 -0
- package/lib/module/particles/types.js.map +1 -0
- package/lib/module/particles.js +4 -0
- package/lib/module/particles.js.map +1 -0
- package/lib/module/react/GameButtonPad.js +344 -0
- package/lib/module/react/GameButtonPad.js.map +1 -0
- package/lib/module/react/GamePointerInput.js +74 -16
- package/lib/module/react/GamePointerInput.js.map +1 -1
- package/lib/module/react/GameView.js +139 -60
- package/lib/module/react/GameView.js.map +1 -1
- package/lib/module/react/assets/createGameAssetStore.js +145 -95
- package/lib/module/react/assets/createGameAssetStore.js.map +1 -1
- package/lib/module/react/assets/useGameAssets.js +60 -35
- package/lib/module/react/assets/useGameAssets.js.map +1 -1
- package/lib/module/react/bindAppLifecycle.js +46 -17
- package/lib/module/react/bindAppLifecycle.js.map +1 -1
- package/lib/module/react/bindGameSession.js +13 -2
- package/lib/module/react/bindGameSession.js.map +1 -1
- package/lib/module/react/camera2d/GameLayer2D.js +50 -0
- package/lib/module/react/camera2d/GameLayer2D.js.map +1 -0
- package/lib/module/react/camera2d/defineGameCamera2D.js +30 -0
- package/lib/module/react/camera2d/defineGameCamera2D.js.map +1 -0
- package/lib/module/react/camera2d/usePresentedCameraBinding.js +177 -0
- package/lib/module/react/camera2d/usePresentedCameraBinding.js.map +1 -0
- package/lib/module/react/cleanupList.js +38 -0
- package/lib/module/react/cleanupList.js.map +1 -0
- package/lib/module/react/lifecycleSource.js +49 -0
- package/lib/module/react/lifecycleSource.js.map +1 -0
- package/lib/module/react/particles/ParticleView.js +308 -0
- package/lib/module/react/particles/ParticleView.js.map +1 -0
- package/lib/module/react/particles/culling.js +115 -0
- package/lib/module/react/particles/culling.js.map +1 -0
- package/lib/module/react/particles/index.js +7 -0
- package/lib/module/react/particles/index.js.map +1 -0
- package/lib/module/react/particles/spriteXForm.js +45 -0
- package/lib/module/react/particles/spriteXForm.js.map +1 -0
- package/lib/module/react/particles/useParticlePresentation.js +204 -0
- package/lib/module/react/particles/useParticlePresentation.js.map +1 -0
- package/lib/module/react/pointerBinding.js +55 -17
- package/lib/module/react/pointerBinding.js.map +1 -1
- package/lib/module/react/pointerCamera.js +28 -0
- package/lib/module/react/pointerCamera.js.map +1 -0
- package/lib/module/react/pointerCoalescer.js +16 -9
- package/lib/module/react/pointerCoalescer.js.map +1 -1
- package/lib/module/react/sprites/GameSprite.js +5 -17
- package/lib/module/react/sprites/GameSprite.js.map +1 -1
- package/lib/module/react/sprites/GameWorld2D.js +112 -9
- package/lib/module/react/sprites/GameWorld2D.js.map +1 -1
- package/lib/module/react/sprites/Sprite.js +48 -63
- package/lib/module/react/sprites/Sprite.js.map +1 -1
- package/lib/module/react/sprites/SpriteBatch.js +53 -28
- package/lib/module/react/sprites/SpriteBatch.js.map +1 -1
- package/lib/module/react/sprites/batchVisibility.js +58 -0
- package/lib/module/react/sprites/batchVisibility.js.map +1 -0
- package/lib/module/react/sprites/spriteSelection.js +103 -0
- package/lib/module/react/sprites/spriteSelection.js.map +1 -0
- package/lib/module/react/sprites/spriteTransform.js +46 -25
- package/lib/module/react/sprites/spriteTransform.js.map +1 -1
- package/lib/module/react/tilemap/TileMapLayer2D.js +217 -0
- package/lib/module/react/tilemap/TileMapLayer2D.js.map +1 -0
- package/lib/module/react/tilemap/tilePresentation.js +374 -0
- package/lib/module/react/tilemap/tilePresentation.js.map +1 -0
- package/lib/module/react/useGameSession.js +70 -0
- package/lib/module/react/useGameSession.js.map +1 -0
- package/lib/module/react/useGameSessionStatus.js +46 -0
- package/lib/module/react/useGameSessionStatus.js.map +1 -0
- package/lib/module/react/viewportBinding.js +5 -1
- package/lib/module/react/viewportBinding.js.map +1 -1
- package/lib/module/react.js +12 -1
- package/lib/module/react.js.map +1 -1
- package/lib/module/scene/defineScene.js +17 -0
- package/lib/module/scene/defineScene.js.map +1 -1
- package/lib/module/sprites/sampleSpriteClip.js +66 -6
- package/lib/module/sprites/sampleSpriteClip.js.map +1 -1
- package/lib/module/sprites/spriteAnimationState.js +10 -20
- package/lib/module/sprites/spriteAnimationState.js.map +1 -1
- package/lib/module/sprites.js +11 -0
- package/lib/module/sprites.js.map +1 -0
- package/lib/module/storage/adapters/asyncStorage.js +57 -0
- package/lib/module/storage/adapters/asyncStorage.js.map +1 -0
- package/lib/module/storage/adapters/memory.js +50 -0
- package/lib/module/storage/adapters/memory.js.map +1 -0
- package/lib/module/storage/errors.js +34 -0
- package/lib/module/storage/errors.js.map +1 -0
- package/lib/module/storage/index.js +11 -0
- package/lib/module/storage/index.js.map +1 -0
- package/lib/module/storage/schema.js +151 -0
- package/lib/module/storage/schema.js.map +1 -0
- package/lib/module/storage/serialization.js +249 -0
- package/lib/module/storage/serialization.js.map +1 -0
- package/lib/module/storage/store.js +387 -0
- package/lib/module/storage/store.js.map +1 -0
- package/lib/module/storage/types.js +16 -0
- package/lib/module/storage/types.js.map +1 -0
- package/lib/module/storage/validation.js +111 -0
- package/lib/module/storage/validation.js.map +1 -0
- package/lib/module/storage.js +4 -0
- package/lib/module/storage.js.map +1 -0
- package/lib/module/testing.js +4 -0
- package/lib/module/testing.js.map +1 -1
- package/lib/module/tilemap/chunkStats.js +27 -0
- package/lib/module/tilemap/chunkStats.js.map +1 -0
- package/lib/module/tilemap/definitions.js +308 -0
- package/lib/module/tilemap/definitions.js.map +1 -0
- package/lib/module/tilemap/errors.js +13 -0
- package/lib/module/tilemap/errors.js.map +1 -0
- package/lib/module/tilemap/index.js +10 -0
- package/lib/module/tilemap/index.js.map +1 -0
- package/lib/module/tilemap/movement.js +379 -0
- package/lib/module/tilemap/movement.js.map +1 -0
- package/lib/module/tilemap/queries.js +114 -0
- package/lib/module/tilemap/queries.js.map +1 -0
- package/lib/module/tilemap/tiledAdapter.js +141 -0
- package/lib/module/tilemap/tiledAdapter.js.map +1 -0
- package/lib/module/tilemap/types.js +4 -0
- package/lib/module/tilemap/types.js.map +1 -0
- package/lib/module/tilemap.js +4 -0
- package/lib/module/tilemap.js.map +1 -0
- package/lib/typescript/src/assets/defineAssets.d.ts +1 -1
- package/lib/typescript/src/assets/defineAssets.d.ts.map +1 -1
- package/lib/typescript/src/assets.d.ts +11 -0
- package/lib/typescript/src/assets.d.ts.map +1 -0
- package/lib/typescript/src/audio/createGameAudio.d.ts +5 -0
- package/lib/typescript/src/audio/createGameAudio.d.ts.map +1 -0
- package/lib/typescript/src/audio/errors.d.ts +6 -0
- package/lib/typescript/src/audio/errors.d.ts.map +1 -0
- package/lib/typescript/src/audio/index.d.ts +4 -0
- package/lib/typescript/src/audio/index.d.ts.map +1 -0
- package/lib/typescript/src/audio/resolver.d.ts +44 -0
- package/lib/typescript/src/audio/resolver.d.ts.map +1 -0
- package/lib/typescript/src/audio/types.d.ts +42 -0
- package/lib/typescript/src/audio/types.d.ts.map +1 -0
- package/lib/typescript/src/audio.d.ts +8 -0
- package/lib/typescript/src/audio.d.ts.map +1 -0
- package/lib/typescript/src/camera2d/bounds.d.ts +25 -0
- package/lib/typescript/src/camera2d/bounds.d.ts.map +1 -0
- package/lib/typescript/src/camera2d/extents.d.ts +17 -0
- package/lib/typescript/src/camera2d/extents.d.ts.map +1 -0
- package/lib/typescript/src/camera2d/follow.d.ts +24 -0
- package/lib/typescript/src/camera2d/follow.d.ts.map +1 -0
- package/lib/typescript/src/camera2d/index.d.ts +19 -0
- package/lib/typescript/src/camera2d/index.d.ts.map +1 -0
- package/lib/typescript/src/camera2d/interpolation.d.ts +17 -0
- package/lib/typescript/src/camera2d/interpolation.d.ts.map +1 -0
- package/lib/typescript/src/camera2d/shake.d.ts +20 -0
- package/lib/typescript/src/camera2d/shake.d.ts.map +1 -0
- package/lib/typescript/src/camera2d/transform.d.ts +44 -0
- package/lib/typescript/src/camera2d/transform.d.ts.map +1 -0
- package/lib/typescript/src/camera2d/types.d.ts +74 -0
- package/lib/typescript/src/camera2d/types.d.ts.map +1 -0
- package/lib/typescript/src/camera2d/validation.d.ts +30 -0
- package/lib/typescript/src/camera2d/validation.d.ts.map +1 -0
- package/lib/typescript/src/camera2d/visibility.d.ts +47 -0
- package/lib/typescript/src/camera2d/visibility.d.ts.map +1 -0
- package/lib/typescript/src/camera2d.d.ts +7 -0
- package/lib/typescript/src/camera2d.d.ts.map +1 -0
- package/lib/typescript/src/collision2d/colliders.d.ts +120 -0
- package/lib/typescript/src/collision2d/colliders.d.ts.map +1 -0
- package/lib/typescript/src/collision2d/debug.d.ts +67 -0
- package/lib/typescript/src/collision2d/debug.d.ts.map +1 -0
- package/lib/typescript/src/collision2d/filters.d.ts +28 -0
- package/lib/typescript/src/collision2d/filters.d.ts.map +1 -0
- package/lib/typescript/src/collision2d/index.d.ts +17 -0
- package/lib/typescript/src/collision2d/index.d.ts.map +1 -0
- package/lib/typescript/src/collision2d/intersections.d.ts +24 -0
- package/lib/typescript/src/collision2d/intersections.d.ts.map +1 -0
- package/lib/typescript/src/collision2d/manifolds.d.ts +39 -0
- package/lib/typescript/src/collision2d/manifolds.d.ts.map +1 -0
- package/lib/typescript/src/collision2d/segments.d.ts +24 -0
- package/lib/typescript/src/collision2d/segments.d.ts.map +1 -0
- package/lib/typescript/src/collision2d/spatialHash.d.ts +50 -0
- package/lib/typescript/src/collision2d/spatialHash.d.ts.map +1 -0
- package/lib/typescript/src/collision2d/sweeps.d.ts +60 -0
- package/lib/typescript/src/collision2d/sweeps.d.ts.map +1 -0
- package/lib/typescript/src/collision2d.d.ts +7 -0
- package/lib/typescript/src/collision2d.d.ts.map +1 -0
- package/lib/typescript/src/core/input/buttonPad.d.ts +59 -0
- package/lib/typescript/src/core/input/buttonPad.d.ts.map +1 -0
- package/lib/typescript/src/core/input/createInputBuffer.d.ts +1 -1
- package/lib/typescript/src/core/input/createInputBuffer.d.ts.map +1 -1
- package/lib/typescript/src/core/input/types.d.ts +7 -0
- package/lib/typescript/src/core/input/types.d.ts.map +1 -1
- package/lib/typescript/src/core/session/createGameSession.d.ts +4 -2
- package/lib/typescript/src/core/session/createGameSession.d.ts.map +1 -1
- package/lib/typescript/src/core/session/deepFreeze.d.ts +21 -1
- package/lib/typescript/src/core/session/deepFreeze.d.ts.map +1 -1
- package/lib/typescript/src/core/session/diagnostics.d.ts +2 -0
- package/lib/typescript/src/core/session/diagnostics.d.ts.map +1 -1
- package/lib/typescript/src/core/session/types.d.ts +69 -4
- package/lib/typescript/src/core/session/types.d.ts.map +1 -1
- package/lib/typescript/src/definition/defineGame.d.ts +12 -1
- package/lib/typescript/src/definition/defineGame.d.ts.map +1 -1
- package/lib/typescript/src/definition/types.d.ts +10 -1
- package/lib/typescript/src/definition/types.d.ts.map +1 -1
- package/lib/typescript/src/events/defineGameEvents.d.ts +26 -0
- package/lib/typescript/src/events/defineGameEvents.d.ts.map +1 -0
- package/lib/typescript/src/events/errors.d.ts +12 -0
- package/lib/typescript/src/events/errors.d.ts.map +1 -0
- package/lib/typescript/src/events/index.d.ts +6 -0
- package/lib/typescript/src/events/index.d.ts.map +1 -0
- package/lib/typescript/src/events/payload.d.ts +21 -0
- package/lib/typescript/src/events/payload.d.ts.map +1 -0
- package/lib/typescript/src/events/seed.d.ts +3 -0
- package/lib/typescript/src/events/seed.d.ts.map +1 -0
- package/lib/typescript/src/events/types.d.ts +42 -0
- package/lib/typescript/src/events/types.d.ts.map +1 -0
- package/lib/typescript/src/events.d.ts +12 -0
- package/lib/typescript/src/events.d.ts.map +1 -0
- package/lib/typescript/src/geometry/helpers.d.ts +35 -0
- package/lib/typescript/src/geometry/helpers.d.ts.map +1 -0
- package/lib/typescript/src/geometry/index.d.ts +4 -0
- package/lib/typescript/src/geometry/index.d.ts.map +1 -0
- package/lib/typescript/src/geometry/types.d.ts +49 -0
- package/lib/typescript/src/geometry/types.d.ts.map +1 -1
- package/lib/typescript/src/geometry/validation.d.ts +44 -0
- package/lib/typescript/src/geometry/validation.d.ts.map +1 -0
- package/lib/typescript/src/geometry.d.ts +7 -0
- package/lib/typescript/src/geometry.d.ts.map +1 -0
- package/lib/typescript/src/haptics/createGameHaptics.d.ts +3 -0
- package/lib/typescript/src/haptics/createGameHaptics.d.ts.map +1 -0
- package/lib/typescript/src/haptics/errors.d.ts +6 -0
- package/lib/typescript/src/haptics/errors.d.ts.map +1 -0
- package/lib/typescript/src/haptics/index.d.ts +4 -0
- package/lib/typescript/src/haptics/index.d.ts.map +1 -0
- package/lib/typescript/src/haptics/resolver.d.ts +22 -0
- package/lib/typescript/src/haptics/resolver.d.ts.map +1 -0
- package/lib/typescript/src/haptics/types.d.ts +37 -0
- package/lib/typescript/src/haptics/types.d.ts.map +1 -0
- package/lib/typescript/src/haptics.d.ts +8 -0
- package/lib/typescript/src/haptics.d.ts.map +1 -0
- package/lib/typescript/src/index.d.ts +10 -2
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/lib/typescript/src/particles/createParticleSystem.d.ts +5 -0
- package/lib/typescript/src/particles/createParticleSystem.d.ts.map +1 -0
- package/lib/typescript/src/particles/defineParticleEffect.d.ts +3 -0
- package/lib/typescript/src/particles/defineParticleEffect.d.ts.map +1 -0
- package/lib/typescript/src/particles/errors.d.ts +5 -0
- package/lib/typescript/src/particles/errors.d.ts.map +1 -0
- package/lib/typescript/src/particles/index.d.ts +6 -0
- package/lib/typescript/src/particles/index.d.ts.map +1 -0
- package/lib/typescript/src/particles/sampling.d.ts +54 -0
- package/lib/typescript/src/particles/sampling.d.ts.map +1 -0
- package/lib/typescript/src/particles/types.d.ts +292 -0
- package/lib/typescript/src/particles/types.d.ts.map +1 -0
- package/lib/typescript/src/particles.d.ts +2 -0
- package/lib/typescript/src/particles.d.ts.map +1 -0
- package/lib/typescript/src/react/GameButtonPad.d.ts +84 -0
- package/lib/typescript/src/react/GameButtonPad.d.ts.map +1 -0
- package/lib/typescript/src/react/GamePointerInput.d.ts.map +1 -1
- package/lib/typescript/src/react/GameView.d.ts +27 -1
- package/lib/typescript/src/react/GameView.d.ts.map +1 -1
- package/lib/typescript/src/react/assets/createGameAssetStore.d.ts.map +1 -1
- package/lib/typescript/src/react/assets/useGameAssets.d.ts.map +1 -1
- package/lib/typescript/src/react/bindAppLifecycle.d.ts +7 -1
- package/lib/typescript/src/react/bindAppLifecycle.d.ts.map +1 -1
- package/lib/typescript/src/react/bindGameSession.d.ts.map +1 -1
- package/lib/typescript/src/react/camera2d/GameLayer2D.d.ts +24 -0
- package/lib/typescript/src/react/camera2d/GameLayer2D.d.ts.map +1 -0
- package/lib/typescript/src/react/camera2d/defineGameCamera2D.d.ts +44 -0
- package/lib/typescript/src/react/camera2d/defineGameCamera2D.d.ts.map +1 -0
- package/lib/typescript/src/react/camera2d/usePresentedCameraBinding.d.ts +22 -0
- package/lib/typescript/src/react/camera2d/usePresentedCameraBinding.d.ts.map +1 -0
- package/lib/typescript/src/react/cleanupList.d.ts +21 -0
- package/lib/typescript/src/react/cleanupList.d.ts.map +1 -0
- package/lib/typescript/src/react/instrumentation.d.ts +33 -3
- package/lib/typescript/src/react/instrumentation.d.ts.map +1 -1
- package/lib/typescript/src/react/lifecycleSource.d.ts +21 -0
- package/lib/typescript/src/react/lifecycleSource.d.ts.map +1 -0
- package/lib/typescript/src/react/particles/ParticleView.d.ts +65 -0
- package/lib/typescript/src/react/particles/ParticleView.d.ts.map +1 -0
- package/lib/typescript/src/react/particles/culling.d.ts +70 -0
- package/lib/typescript/src/react/particles/culling.d.ts.map +1 -0
- package/lib/typescript/src/react/particles/index.d.ts +7 -0
- package/lib/typescript/src/react/particles/index.d.ts.map +1 -0
- package/lib/typescript/src/react/particles/spriteXForm.d.ts +28 -0
- package/lib/typescript/src/react/particles/spriteXForm.d.ts.map +1 -0
- package/lib/typescript/src/react/particles/useParticlePresentation.d.ts +48 -0
- package/lib/typescript/src/react/particles/useParticlePresentation.d.ts.map +1 -0
- package/lib/typescript/src/react/pointerBinding.d.ts +38 -8
- package/lib/typescript/src/react/pointerBinding.d.ts.map +1 -1
- package/lib/typescript/src/react/pointerCamera.d.ts +20 -0
- package/lib/typescript/src/react/pointerCamera.d.ts.map +1 -0
- package/lib/typescript/src/react/pointerCoalescer.d.ts +17 -1
- package/lib/typescript/src/react/pointerCoalescer.d.ts.map +1 -1
- package/lib/typescript/src/react/sprites/GameSprite.d.ts +3 -10
- package/lib/typescript/src/react/sprites/GameSprite.d.ts.map +1 -1
- package/lib/typescript/src/react/sprites/GameWorld2D.d.ts +51 -6
- package/lib/typescript/src/react/sprites/GameWorld2D.d.ts.map +1 -1
- package/lib/typescript/src/react/sprites/Sprite.d.ts.map +1 -1
- package/lib/typescript/src/react/sprites/SpriteBatch.d.ts +22 -1
- package/lib/typescript/src/react/sprites/SpriteBatch.d.ts.map +1 -1
- package/lib/typescript/src/react/sprites/batchVisibility.d.ts +28 -0
- package/lib/typescript/src/react/sprites/batchVisibility.d.ts.map +1 -0
- package/lib/typescript/src/react/sprites/spriteSelection.d.ts +58 -0
- package/lib/typescript/src/react/sprites/spriteSelection.d.ts.map +1 -0
- package/lib/typescript/src/react/sprites/spriteTransform.d.ts +27 -12
- package/lib/typescript/src/react/sprites/spriteTransform.d.ts.map +1 -1
- package/lib/typescript/src/react/tilemap/TileMapLayer2D.d.ts +69 -0
- package/lib/typescript/src/react/tilemap/TileMapLayer2D.d.ts.map +1 -0
- package/lib/typescript/src/react/tilemap/tilePresentation.d.ts +217 -0
- package/lib/typescript/src/react/tilemap/tilePresentation.d.ts.map +1 -0
- package/lib/typescript/src/react/useGameSession.d.ts +48 -0
- package/lib/typescript/src/react/useGameSession.d.ts.map +1 -0
- package/lib/typescript/src/react/useGameSessionStatus.d.ts +23 -0
- package/lib/typescript/src/react/useGameSessionStatus.d.ts.map +1 -0
- package/lib/typescript/src/react/viewportBinding.d.ts +5 -1
- package/lib/typescript/src/react/viewportBinding.d.ts.map +1 -1
- package/lib/typescript/src/react.d.ts +18 -1
- package/lib/typescript/src/react.d.ts.map +1 -1
- package/lib/typescript/src/scene/defineScene.d.ts +22 -2
- package/lib/typescript/src/scene/defineScene.d.ts.map +1 -1
- package/lib/typescript/src/scene/types.d.ts +24 -4
- package/lib/typescript/src/scene/types.d.ts.map +1 -1
- package/lib/typescript/src/sprites/sampleSpriteClip.d.ts +26 -2
- package/lib/typescript/src/sprites/sampleSpriteClip.d.ts.map +1 -1
- package/lib/typescript/src/sprites/spriteAnimationState.d.ts +6 -7
- package/lib/typescript/src/sprites/spriteAnimationState.d.ts.map +1 -1
- package/lib/typescript/src/sprites.d.ts +10 -0
- package/lib/typescript/src/sprites.d.ts.map +1 -0
- package/lib/typescript/src/storage/adapters/asyncStorage.d.ts +18 -0
- package/lib/typescript/src/storage/adapters/asyncStorage.d.ts.map +1 -0
- package/lib/typescript/src/storage/adapters/memory.d.ts +16 -0
- package/lib/typescript/src/storage/adapters/memory.d.ts.map +1 -0
- package/lib/typescript/src/storage/errors.d.ts +37 -0
- package/lib/typescript/src/storage/errors.d.ts.map +1 -0
- package/lib/typescript/src/storage/index.d.ts +11 -0
- package/lib/typescript/src/storage/index.d.ts.map +1 -0
- package/lib/typescript/src/storage/schema.d.ts +22 -0
- package/lib/typescript/src/storage/schema.d.ts.map +1 -0
- package/lib/typescript/src/storage/serialization.d.ts +23 -0
- package/lib/typescript/src/storage/serialization.d.ts.map +1 -0
- package/lib/typescript/src/storage/store.d.ts +3 -0
- package/lib/typescript/src/storage/store.d.ts.map +1 -0
- package/lib/typescript/src/storage/types.d.ts +69 -0
- package/lib/typescript/src/storage/types.d.ts.map +1 -0
- package/lib/typescript/src/storage/validation.d.ts +24 -0
- package/lib/typescript/src/storage/validation.d.ts.map +1 -0
- package/lib/typescript/src/storage.d.ts +2 -0
- package/lib/typescript/src/storage.d.ts.map +1 -0
- package/lib/typescript/src/testing.d.ts +1 -0
- package/lib/typescript/src/testing.d.ts.map +1 -1
- package/lib/typescript/src/tilemap/chunkStats.d.ts +14 -0
- package/lib/typescript/src/tilemap/chunkStats.d.ts.map +1 -0
- package/lib/typescript/src/tilemap/definitions.d.ts +38 -0
- package/lib/typescript/src/tilemap/definitions.d.ts.map +1 -0
- package/lib/typescript/src/tilemap/errors.d.ts +7 -0
- package/lib/typescript/src/tilemap/errors.d.ts.map +1 -0
- package/lib/typescript/src/tilemap/index.d.ts +8 -0
- package/lib/typescript/src/tilemap/index.d.ts.map +1 -0
- package/lib/typescript/src/tilemap/movement.d.ts +52 -0
- package/lib/typescript/src/tilemap/movement.d.ts.map +1 -0
- package/lib/typescript/src/tilemap/queries.d.ts +21 -0
- package/lib/typescript/src/tilemap/queries.d.ts.map +1 -0
- package/lib/typescript/src/tilemap/tiledAdapter.d.ts +32 -0
- package/lib/typescript/src/tilemap/tiledAdapter.d.ts.map +1 -0
- package/lib/typescript/src/tilemap/types.d.ts +127 -0
- package/lib/typescript/src/tilemap/types.d.ts.map +1 -0
- package/lib/typescript/src/tilemap.d.ts +2 -0
- package/lib/typescript/src/tilemap.d.ts.map +1 -0
- package/package.json +94 -4
- package/src/assets/defineAssets.ts +31 -5
- package/src/assets.ts +27 -0
- package/src/audio/createGameAudio.ts +749 -0
- package/src/audio/errors.ts +12 -0
- package/src/audio/index.ts +9 -0
- package/src/audio/resolver.ts +74 -0
- package/src/audio/types.ts +47 -0
- package/src/audio.ts +13 -0
- package/src/camera2d/bounds.ts +69 -0
- package/src/camera2d/extents.ts +25 -0
- package/src/camera2d/follow.ts +165 -0
- package/src/camera2d/index.ts +29 -0
- package/src/camera2d/interpolation.ts +113 -0
- package/src/camera2d/shake.ts +90 -0
- package/src/camera2d/transform.ts +148 -0
- package/src/camera2d/types.ts +73 -0
- package/src/camera2d/validation.ts +126 -0
- package/src/camera2d/visibility.ts +181 -0
- package/src/camera2d.ts +6 -0
- package/src/collision2d/colliders.ts +292 -0
- package/src/collision2d/debug.ts +133 -0
- package/src/collision2d/filters.ts +48 -0
- package/src/collision2d/index.ts +74 -0
- package/src/collision2d/intersections.ts +82 -0
- package/src/collision2d/manifolds.ts +191 -0
- package/src/collision2d/segments.ts +176 -0
- package/src/collision2d/spatialHash.ts +211 -0
- package/src/collision2d/sweeps.ts +269 -0
- package/src/collision2d.ts +6 -0
- package/src/core/input/buttonPad.ts +235 -0
- package/src/core/input/createInputBuffer.ts +95 -14
- package/src/core/input/types.ts +7 -0
- package/src/core/session/createGameSession.ts +480 -53
- package/src/core/session/deepFreeze.ts +104 -3
- package/src/core/session/diagnostics.ts +2 -0
- package/src/core/session/types.ts +77 -4
- package/src/definition/defineGame.ts +61 -3
- package/src/definition/types.ts +10 -0
- package/src/events/defineGameEvents.ts +46 -0
- package/src/events/errors.ts +14 -0
- package/src/events/index.ts +14 -0
- package/src/events/payload.ts +234 -0
- package/src/events/seed.ts +33 -0
- package/src/events/types.ts +53 -0
- package/src/events.ts +20 -0
- package/src/geometry/helpers.ts +136 -0
- package/src/geometry/index.ts +14 -0
- package/src/geometry/types.ts +54 -0
- package/src/geometry/validation.ts +131 -0
- package/src/geometry.ts +6 -0
- package/src/haptics/createGameHaptics.ts +214 -0
- package/src/haptics/errors.ts +12 -0
- package/src/haptics/index.ts +3 -0
- package/src/haptics/resolver.ts +58 -0
- package/src/haptics/types.ts +48 -0
- package/src/haptics.ts +7 -0
- package/src/index.ts +37 -1
- package/src/particles/createParticleSystem.ts +505 -0
- package/src/particles/defineParticleEffect.ts +164 -0
- package/src/particles/errors.ts +6 -0
- package/src/particles/index.ts +5 -0
- package/src/particles/sampling.ts +141 -0
- package/src/particles/types.ts +327 -0
- package/src/particles.ts +1 -0
- package/src/react/GameButtonPad.tsx +436 -0
- package/src/react/GamePointerInput.tsx +73 -8
- package/src/react/GameView.tsx +160 -61
- package/src/react/assets/createGameAssetStore.ts +140 -107
- package/src/react/assets/useGameAssets.ts +63 -31
- package/src/react/bindAppLifecycle.ts +55 -19
- package/src/react/bindGameSession.ts +12 -2
- package/src/react/camera2d/GameLayer2D.tsx +43 -0
- package/src/react/camera2d/defineGameCamera2D.ts +59 -0
- package/src/react/camera2d/usePresentedCameraBinding.ts +185 -0
- package/src/react/cleanupList.ts +48 -0
- package/src/react/instrumentation.ts +31 -3
- package/src/react/lifecycleSource.ts +58 -0
- package/src/react/particles/ParticleView.tsx +358 -0
- package/src/react/particles/culling.ts +145 -0
- package/src/react/particles/index.ts +6 -0
- package/src/react/particles/spriteXForm.ts +72 -0
- package/src/react/particles/useParticlePresentation.ts +261 -0
- package/src/react/pointerBinding.ts +74 -16
- package/src/react/pointerCamera.ts +33 -0
- package/src/react/pointerCoalescer.ts +36 -10
- package/src/react/sprites/GameSprite.tsx +4 -33
- package/src/react/sprites/GameWorld2D.tsx +113 -7
- package/src/react/sprites/Sprite.tsx +51 -72
- package/src/react/sprites/SpriteBatch.tsx +74 -22
- package/src/react/sprites/batchVisibility.ts +76 -0
- package/src/react/sprites/spriteSelection.ts +133 -0
- package/src/react/sprites/spriteTransform.ts +46 -26
- package/src/react/tilemap/TileMapLayer2D.tsx +274 -0
- package/src/react/tilemap/tilePresentation.ts +491 -0
- package/src/react/useGameSession.ts +90 -0
- package/src/react/useGameSessionStatus.ts +53 -0
- package/src/react/viewportBinding.ts +5 -1
- package/src/react.ts +18 -1
- package/src/scene/defineScene.ts +47 -5
- package/src/scene/types.ts +37 -3
- package/src/sprites/sampleSpriteClip.ts +82 -14
- package/src/sprites/spriteAnimationState.ts +29 -25
- package/src/sprites.ts +22 -0
- package/src/storage/adapters/asyncStorage.ts +77 -0
- package/src/storage/adapters/memory.ts +58 -0
- package/src/storage/errors.ts +88 -0
- package/src/storage/index.ts +18 -0
- package/src/storage/schema.ts +147 -0
- package/src/storage/serialization.ts +248 -0
- package/src/storage/store.ts +380 -0
- package/src/storage/types.ts +76 -0
- package/src/storage/validation.ts +102 -0
- package/src/storage.ts +1 -0
- package/src/testing.ts +4 -0
- package/src/tilemap/chunkStats.ts +24 -0
- package/src/tilemap/definitions.ts +327 -0
- package/src/tilemap/errors.ts +11 -0
- package/src/tilemap/index.ts +10 -0
- package/src/tilemap/movement.ts +368 -0
- package/src/tilemap/queries.ts +136 -0
- package/src/tilemap/tiledAdapter.ts +165 -0
- package/src/tilemap/types.ts +119 -0
- package/src/tilemap.ts +1 -0
|
@@ -4,7 +4,47 @@ import { createAnimationFrameDriver } from "../frameDriver.js";
|
|
|
4
4
|
import { createInputBuffer } from "../input/createInputBuffer.js";
|
|
5
5
|
import { GameSessionDisposedError, GameSessionLifecycleError } from "./types.js";
|
|
6
6
|
import { createDeepFreeze } from "./deepFreeze.js";
|
|
7
|
+
import { GameEventError } from "../../events/errors.js";
|
|
8
|
+
import { cloneAndValidatePayload } from "../../events/payload.js";
|
|
7
9
|
const DEFAULT_FIXED_STEP_MS = 1000 / 60;
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* A captured failure: an explicit boolean record so an arbitrary thrown
|
|
13
|
+
* value (including `undefined`) is never confused with "no failure".
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
const NO_FAILURE = {
|
|
17
|
+
failed: false
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
/** Run a closure and capture its thrown value, whatever its type. */
|
|
21
|
+
function captureFailure(run) {
|
|
22
|
+
try {
|
|
23
|
+
run();
|
|
24
|
+
return NO_FAILURE;
|
|
25
|
+
} catch (error) {
|
|
26
|
+
return {
|
|
27
|
+
failed: true,
|
|
28
|
+
value: error
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/** Surface a captured failure, throwing `undefined` if that was the value. */
|
|
34
|
+
function throwFailure(record) {
|
|
35
|
+
if (record.failed) {
|
|
36
|
+
throw record.value;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Immutably compose two failures into one lossless error: an AggregateError
|
|
42
|
+
* with a stable message and ordered `errors`. Neither thrown value is
|
|
43
|
+
* mutated or wrapped away.
|
|
44
|
+
*/
|
|
45
|
+
function composeFailures(first, second) {
|
|
46
|
+
return new AggregateError([first, second], 'Lifecycle operation failed with multiple errors');
|
|
47
|
+
}
|
|
8
48
|
const DEFAULT_MAX_CATCH_UP_STEPS = 5;
|
|
9
49
|
function now() {
|
|
10
50
|
return typeof performance !== 'undefined' ? performance.now() : 0;
|
|
@@ -47,6 +87,34 @@ export function createGameSessionWithDriver(definition, options) {
|
|
|
47
87
|
if (!(maxFrameDeltaMs > 0) || !Number.isFinite(maxFrameDeltaMs)) {
|
|
48
88
|
throw new RangeError('maxFrameDeltaMs must be a finite positive number');
|
|
49
89
|
}
|
|
90
|
+
|
|
91
|
+
// T13: event definitions and per-scene emit declarations.
|
|
92
|
+
const eventDefs = definition.events;
|
|
93
|
+
const hasEvents = eventDefs !== undefined && eventDefs !== null;
|
|
94
|
+
const allowedEventNames = hasEvents ? new Set(Object.keys(eventDefs)) : new Set();
|
|
95
|
+
const allowedEmitsByScene = new Map();
|
|
96
|
+
// Validate per-scene emits are declared events and that the scene's `events` reference matches the game's.
|
|
97
|
+
for (const [name, scene] of Object.entries(definition.scenes)) {
|
|
98
|
+
const erased = scene;
|
|
99
|
+
const emits = erased.emits ?? [];
|
|
100
|
+
for (const ev of emits) {
|
|
101
|
+
if (!allowedEventNames.has(ev)) {
|
|
102
|
+
throw new Error(`Scene "${name}" declares unknown event "${ev}"`);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
allowedEmitsByScene.set(name, new Set(emits));
|
|
106
|
+
// Runtime identity check for the branded event definitions.
|
|
107
|
+
if (erased.events !== undefined) {
|
|
108
|
+
if (!hasEvents) {
|
|
109
|
+
throw new Error(`Scene "${name}" is bound to events but the game has no events map`);
|
|
110
|
+
}
|
|
111
|
+
if (erased.events !== eventDefs) {
|
|
112
|
+
throw new Error(`Scene "${name}" is bound to a different events object than the game. Pass the same defineGameEvents() result to both defineScene({ events }) and defineGame({ events }).`);
|
|
113
|
+
}
|
|
114
|
+
} else if (emits.length > 0) {
|
|
115
|
+
throw new Error(`Scene "${name}" declares emits but is not bound to the game's events. Pass \`events\` to defineScene.`);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
50
118
|
const erasedSceneMap = {};
|
|
51
119
|
for (const [name, scene] of Object.entries(definition.scenes)) {
|
|
52
120
|
const erased = scene;
|
|
@@ -74,16 +142,24 @@ export function createGameSessionWithDriver(definition, options) {
|
|
|
74
142
|
try {
|
|
75
143
|
initialSnapshot = deepFreeze(initialDefinition.snapshot({
|
|
76
144
|
state: initialState
|
|
77
|
-
})
|
|
145
|
+
}), {
|
|
146
|
+
scene: initialSceneName
|
|
147
|
+
});
|
|
78
148
|
} catch (error) {
|
|
79
|
-
|
|
149
|
+
// GS-SCENE-02: the cleanup failure must not replace the snapshot
|
|
150
|
+
// failure — compose losslessly in a stable order instead.
|
|
151
|
+
const cleanupFailure = captureFailure(() => initialDefinition.dispose?.(initialState));
|
|
152
|
+
if (cleanupFailure.failed) {
|
|
153
|
+
throw composeFailures(error, cleanupFailure.value);
|
|
154
|
+
}
|
|
80
155
|
throw error;
|
|
81
156
|
}
|
|
82
157
|
let activeScene = {
|
|
83
158
|
name: initialSceneName,
|
|
84
159
|
definition: initialDefinition,
|
|
85
160
|
state: initialState,
|
|
86
|
-
sceneTick: 0
|
|
161
|
+
sceneTick: 0,
|
|
162
|
+
disposalAttempted: false
|
|
87
163
|
};
|
|
88
164
|
let sceneName = initialSceneName;
|
|
89
165
|
let currentSnapshot = initialSnapshot;
|
|
@@ -95,6 +171,12 @@ export function createGameSessionWithDriver(definition, options) {
|
|
|
95
171
|
let accumulatorMs = 0;
|
|
96
172
|
let tick = 0;
|
|
97
173
|
let pendingTransition;
|
|
174
|
+
/**
|
|
175
|
+
* Set when an outgoing scene disposal throws: the retained scene is
|
|
176
|
+
* explicitly non-resumable — `start()` refuses to update it until a
|
|
177
|
+
* transition or restart replaces it. Cleared on every successful install.
|
|
178
|
+
*/
|
|
179
|
+
let sceneFaulted = false;
|
|
98
180
|
let hardCutPending = false;
|
|
99
181
|
let publishedThisCallback = false;
|
|
100
182
|
let updateInProgress = false;
|
|
@@ -110,13 +192,138 @@ export function createGameSessionWithDriver(definition, options) {
|
|
|
110
192
|
stepMs: fixedStepMs
|
|
111
193
|
});
|
|
112
194
|
const listeners = new Set();
|
|
195
|
+
const statusListeners = new Set();
|
|
196
|
+
let deliveringStatus = false;
|
|
197
|
+
const queuedStatuses = [];
|
|
198
|
+
let releaseStatusListeners = false;
|
|
199
|
+
|
|
200
|
+
// T13: per-session event listeners.
|
|
201
|
+
const eventListeners = new Map();
|
|
202
|
+
|
|
203
|
+
// Centralized, non-recursive error sink for game event listeners.
|
|
204
|
+
// A failing reporter must not pause the session or escape into the fixed-step loop.
|
|
205
|
+
const reportGameEventListenerError = (name, error) => {
|
|
206
|
+
try {
|
|
207
|
+
console.error(`Game event listener for "${name}" threw:`, error);
|
|
208
|
+
} catch {
|
|
209
|
+
// Swallow reporter failures — the session must remain running and siblings must still run.
|
|
210
|
+
}
|
|
211
|
+
};
|
|
212
|
+
const deliverEvents = envelopes => {
|
|
213
|
+
// Snapshot per tick: a listener added during this tick's delivery receives
|
|
214
|
+
// only later ticks, and a removal prevents only future ticks.
|
|
215
|
+
const snapshots = new Map();
|
|
216
|
+
for (const env of envelopes) {
|
|
217
|
+
if (!snapshots.has(env.name)) {
|
|
218
|
+
const set = eventListeners.get(env.name);
|
|
219
|
+
snapshots.set(env.name, set ? [...set] : []);
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
for (const envelope of envelopes) {
|
|
223
|
+
const snapshot = snapshots.get(envelope.name) ?? [];
|
|
224
|
+
for (const listener of snapshot) {
|
|
225
|
+
let result;
|
|
226
|
+
try {
|
|
227
|
+
result = listener(envelope);
|
|
228
|
+
} catch (error) {
|
|
229
|
+
reportGameEventListenerError(envelope.name, error);
|
|
230
|
+
continue;
|
|
231
|
+
}
|
|
232
|
+
if (result !== null && typeof result === 'object' && typeof result.then === 'function') {
|
|
233
|
+
result.catch(error => {
|
|
234
|
+
reportGameEventListenerError(envelope.name, error);
|
|
235
|
+
});
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
};
|
|
240
|
+
const NO_EVENT_EMITTER = Object.freeze({
|
|
241
|
+
emit() {
|
|
242
|
+
throw new GameEventError('This game has no events or this scene does not emit any events');
|
|
243
|
+
}
|
|
244
|
+
});
|
|
245
|
+
|
|
246
|
+
// Deliver one transition pass to a snapshot. A throwing listener never
|
|
247
|
+
// aborts the pass: the remaining snapshot listeners still run, and the
|
|
248
|
+
// first failure is rethrown once every queued transition has been
|
|
249
|
+
// delivered (the transition itself is already authoritative).
|
|
250
|
+
const deliverStatusPass = current => {
|
|
251
|
+
let firstFailure = NO_FAILURE;
|
|
252
|
+
for (const listener of [...statusListeners]) {
|
|
253
|
+
try {
|
|
254
|
+
listener(current);
|
|
255
|
+
} catch (error) {
|
|
256
|
+
if (!firstFailure.failed) {
|
|
257
|
+
firstFailure = {
|
|
258
|
+
failed: true,
|
|
259
|
+
value: error
|
|
260
|
+
};
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
return firstFailure;
|
|
265
|
+
};
|
|
266
|
+
const notifyStatus = () => {
|
|
267
|
+
if (deliveringStatus) {
|
|
268
|
+
// Re-entrant transition from inside a listener: queue it so every
|
|
269
|
+
// listener observes complete states, never a half-applied transition.
|
|
270
|
+
queuedStatuses.push(status);
|
|
271
|
+
return;
|
|
272
|
+
}
|
|
273
|
+
deliveringStatus = true;
|
|
274
|
+
let firstFailure = NO_FAILURE;
|
|
275
|
+
try {
|
|
276
|
+
const passFailure = deliverStatusPass(status);
|
|
277
|
+
if (!firstFailure.failed) {
|
|
278
|
+
firstFailure = passFailure;
|
|
279
|
+
}
|
|
280
|
+
while (queuedStatuses.length > 0) {
|
|
281
|
+
const queued = queuedStatuses.shift();
|
|
282
|
+
const queuedFailure = deliverStatusPass(queued);
|
|
283
|
+
if (!firstFailure.failed) {
|
|
284
|
+
firstFailure = queuedFailure;
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
} finally {
|
|
288
|
+
deliveringStatus = false;
|
|
289
|
+
if (releaseStatusListeners) {
|
|
290
|
+
releaseStatusListeners = false;
|
|
291
|
+
statusListeners.clear();
|
|
292
|
+
diagnostics?.onStatusListenerCount?.(statusListeners.size);
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
throwFailure(firstFailure);
|
|
296
|
+
};
|
|
297
|
+
|
|
298
|
+
// Status becomes authoritative only after the command's scheduling and
|
|
299
|
+
// input side effects are safe; listeners then observe the committed value.
|
|
300
|
+
const setStatus = next => {
|
|
301
|
+
if (status === next) {
|
|
302
|
+
return;
|
|
303
|
+
}
|
|
304
|
+
status = next;
|
|
305
|
+
notifyStatus();
|
|
306
|
+
};
|
|
307
|
+
|
|
308
|
+
// Error-path pause: complete the transition and notify, but never let a
|
|
309
|
+
// status-listener failure mask the original error that caused the pause.
|
|
310
|
+
const pauseAndRethrow = original => {
|
|
311
|
+
try {
|
|
312
|
+
pauseInternal();
|
|
313
|
+
} catch {
|
|
314
|
+
// The original error is the actionable one; listeners were notified.
|
|
315
|
+
}
|
|
316
|
+
throw original;
|
|
317
|
+
};
|
|
113
318
|
const assertLive = () => {
|
|
114
319
|
if (status === 'disposed') {
|
|
115
320
|
throw new GameSessionDisposedError();
|
|
116
321
|
}
|
|
117
322
|
};
|
|
118
323
|
const isDisposed = () => status === 'disposed';
|
|
119
|
-
|
|
324
|
+
// T10.4: gameplay input is rejected at the shared boundary while paused
|
|
325
|
+
// (before the queue and before the accepted-input diagnostics).
|
|
326
|
+
const inputBuffer = createInputBuffer(definition.input, assertLive, () => status === 'paused');
|
|
120
327
|
|
|
121
328
|
// Simulation commits are the only presentation updates (T5): a commit
|
|
122
329
|
// happens on the initial baseline, after every presentation callback that
|
|
@@ -152,7 +359,6 @@ export function createGameSessionWithDriver(definition, options) {
|
|
|
152
359
|
if (status !== 'running') {
|
|
153
360
|
return;
|
|
154
361
|
}
|
|
155
|
-
status = 'paused';
|
|
156
362
|
generation += 1;
|
|
157
363
|
if (frameHandle !== undefined) {
|
|
158
364
|
options.frameDriver.cancelFrame(frameHandle);
|
|
@@ -161,16 +367,29 @@ export function createGameSessionWithDriver(definition, options) {
|
|
|
161
367
|
previousTimestampMs = undefined;
|
|
162
368
|
accumulatorMs = 0;
|
|
163
369
|
inputBuffer.reset();
|
|
370
|
+
setStatus('paused');
|
|
164
371
|
};
|
|
165
372
|
const commitOrPause = () => {
|
|
166
373
|
try {
|
|
167
374
|
commit();
|
|
168
375
|
} catch (error) {
|
|
169
|
-
|
|
170
|
-
throw error;
|
|
376
|
+
pauseAndRethrow(error);
|
|
171
377
|
}
|
|
172
378
|
};
|
|
173
379
|
|
|
380
|
+
/**
|
|
381
|
+
* Dispose one scene instance exactly once. The attempt flag is set before
|
|
382
|
+
* user cleanup runs, so a throwing disposer is never retried for this
|
|
383
|
+
* instance — by transition retries or by session disposal.
|
|
384
|
+
*/
|
|
385
|
+
const disposeSceneInstance = (scene, state) => {
|
|
386
|
+
if (scene.disposalAttempted) {
|
|
387
|
+
return;
|
|
388
|
+
}
|
|
389
|
+
scene.disposalAttempted = true;
|
|
390
|
+
scene.definition.dispose?.(state);
|
|
391
|
+
};
|
|
392
|
+
|
|
174
393
|
/**
|
|
175
394
|
* Transition to `targetName` following the deterministic ordering:
|
|
176
395
|
* prepare the target -> dispose the outgoing scene exactly once -> advance
|
|
@@ -198,7 +417,9 @@ export function createGameSessionWithDriver(definition, options) {
|
|
|
198
417
|
targetCreated = true;
|
|
199
418
|
targetSnapshot = deepFreeze(targetDefinition.snapshot({
|
|
200
419
|
state: targetState
|
|
201
|
-
})
|
|
420
|
+
}), {
|
|
421
|
+
scene: targetName
|
|
422
|
+
});
|
|
202
423
|
} catch (error) {
|
|
203
424
|
if (targetCreated) {
|
|
204
425
|
try {
|
|
@@ -210,15 +431,17 @@ export function createGameSessionWithDriver(definition, options) {
|
|
|
210
431
|
throw error;
|
|
211
432
|
}
|
|
212
433
|
try {
|
|
213
|
-
activeScene
|
|
434
|
+
disposeSceneInstance(activeScene, outgoingFinalState);
|
|
214
435
|
} catch (error) {
|
|
215
|
-
// The outgoing scene's dispose already ran (possibly partially) and
|
|
216
|
-
//
|
|
436
|
+
// The outgoing scene's dispose already ran (possibly partially) and
|
|
437
|
+
// is never retried; the old scene remains active but explicitly
|
|
438
|
+
// faulted. The prepared target is still cleaned up, and a failing
|
|
439
|
+
// target cleanup composes losslessly with the outgoing failure.
|
|
440
|
+
sceneFaulted = true;
|
|
217
441
|
if (targetCreated) {
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
// Best effort.
|
|
442
|
+
const targetFailure = captureFailure(() => targetDefinition.dispose?.(targetState));
|
|
443
|
+
if (targetFailure.failed) {
|
|
444
|
+
throw composeFailures(error, targetFailure.value);
|
|
222
445
|
}
|
|
223
446
|
}
|
|
224
447
|
throw error;
|
|
@@ -230,8 +453,10 @@ export function createGameSessionWithDriver(definition, options) {
|
|
|
230
453
|
name: targetName,
|
|
231
454
|
definition: targetDefinition,
|
|
232
455
|
state: targetState,
|
|
233
|
-
sceneTick: 0
|
|
456
|
+
sceneTick: 0,
|
|
457
|
+
disposalAttempted: false
|
|
234
458
|
};
|
|
459
|
+
sceneFaulted = false;
|
|
235
460
|
sceneName = targetName;
|
|
236
461
|
currentSnapshot = targetSnapshot;
|
|
237
462
|
previousSnapshot = targetSnapshot;
|
|
@@ -290,6 +515,30 @@ export function createGameSessionWithDriver(definition, options) {
|
|
|
290
515
|
}
|
|
291
516
|
});
|
|
292
517
|
};
|
|
518
|
+
|
|
519
|
+
// One scheduler-failure policy for successor scheduling (GS-SESSION-02).
|
|
520
|
+
// The initial `start()` path keeps its own restore-previous-status policy
|
|
521
|
+
// because no running state was ever published there. On failure: clear the
|
|
522
|
+
// handle, invalidate the generation so late callbacks are no-ops,
|
|
523
|
+
// neutralize input via the pause path, and publish paused while preserving
|
|
524
|
+
// the scheduling error — a throwing status listener composes with it
|
|
525
|
+
// instead of masking it. Never retries automatically.
|
|
526
|
+
const failScheduling = error => {
|
|
527
|
+
frameHandle = undefined;
|
|
528
|
+
try {
|
|
529
|
+
pauseInternal();
|
|
530
|
+
} catch (statusError) {
|
|
531
|
+
throw composeFailures(error, statusError);
|
|
532
|
+
}
|
|
533
|
+
throw error;
|
|
534
|
+
};
|
|
535
|
+
const scheduleSuccessor = activeGeneration => {
|
|
536
|
+
try {
|
|
537
|
+
schedule(activeGeneration);
|
|
538
|
+
} catch (error) {
|
|
539
|
+
failScheduling(error);
|
|
540
|
+
}
|
|
541
|
+
};
|
|
293
542
|
const schedule = activeGeneration => {
|
|
294
543
|
frameHandle = options.frameDriver.requestFrame(timestampMs => {
|
|
295
544
|
if (status !== 'running' || generation !== activeGeneration) {
|
|
@@ -301,16 +550,17 @@ export function createGameSessionWithDriver(definition, options) {
|
|
|
301
550
|
diagnostics.onDisplayCallback();
|
|
302
551
|
}
|
|
303
552
|
|
|
304
|
-
// A pending external transition commits at the next
|
|
305
|
-
// without advancing
|
|
553
|
+
// A pending external transition commits at the next frame-driver
|
|
554
|
+
// callback — a zero-step callback may carry it — without advancing
|
|
555
|
+
// simulation tick/time. The target scene first updates at the next
|
|
556
|
+
// due fixed step; accumulated timing debt is preserved.
|
|
306
557
|
if (pendingTransition !== undefined) {
|
|
307
558
|
const pending = pendingTransition;
|
|
308
559
|
pendingTransition = undefined;
|
|
309
560
|
try {
|
|
310
561
|
commitTransition(pending, activeScene.state, undefined);
|
|
311
562
|
} catch (error) {
|
|
312
|
-
|
|
313
|
-
throw error;
|
|
563
|
+
pauseAndRethrow(error);
|
|
314
564
|
}
|
|
315
565
|
commitOrPause();
|
|
316
566
|
if (status !== 'running' || generation !== activeGeneration) {
|
|
@@ -323,7 +573,7 @@ export function createGameSessionWithDriver(definition, options) {
|
|
|
323
573
|
commitOrPause();
|
|
324
574
|
}
|
|
325
575
|
if (status === 'running' && generation === activeGeneration) {
|
|
326
|
-
|
|
576
|
+
scheduleSuccessor(activeGeneration);
|
|
327
577
|
}
|
|
328
578
|
return;
|
|
329
579
|
}
|
|
@@ -338,6 +588,39 @@ export function createGameSessionWithDriver(definition, options) {
|
|
|
338
588
|
stepsRan = true;
|
|
339
589
|
const nextTick = tick + 1;
|
|
340
590
|
const nextSceneTick = activeScene.sceneTick + 1;
|
|
591
|
+
const sceneNameForTick = activeScene.name;
|
|
592
|
+
const allowedEmits = allowedEmitsByScene.get(sceneNameForTick) ?? new Set();
|
|
593
|
+
|
|
594
|
+
// T13: per-tick transactional emitter.
|
|
595
|
+
let stagedThisTick = [];
|
|
596
|
+
let ordinal = 0;
|
|
597
|
+
let emitterInvalidated = false;
|
|
598
|
+
const emitter = hasEvents ? {
|
|
599
|
+
emit(name, payload) {
|
|
600
|
+
if (emitterInvalidated) {
|
|
601
|
+
throw new GameEventError('Game event emitter is only valid during its owning scene update');
|
|
602
|
+
}
|
|
603
|
+
if (!allowedEventNames.has(name)) {
|
|
604
|
+
throw new GameEventError(`Event "${name}" is not declared by this game`);
|
|
605
|
+
}
|
|
606
|
+
if (!allowedEmits.has(name)) {
|
|
607
|
+
throw new GameEventError(`Scene "${sceneNameForTick}" cannot emit event "${name}" (missing from its emits list)`);
|
|
608
|
+
}
|
|
609
|
+
const cloned = cloneAndValidatePayload(payload, name, 'payload');
|
|
610
|
+
const envelope = Object.freeze({
|
|
611
|
+
name,
|
|
612
|
+
payload: cloned,
|
|
613
|
+
tick: nextTick,
|
|
614
|
+
scene: sceneNameForTick,
|
|
615
|
+
sceneTick: nextSceneTick,
|
|
616
|
+
ordinal: ordinal++
|
|
617
|
+
});
|
|
618
|
+
stagedThisTick.push(envelope);
|
|
619
|
+
}
|
|
620
|
+
} : NO_EVENT_EMITTER;
|
|
621
|
+
if (hasEvents) {
|
|
622
|
+
Object.freeze(emitter);
|
|
623
|
+
}
|
|
341
624
|
const sampleStart = diagnostics === undefined ? 0 : now();
|
|
342
625
|
const input = inputBuffer.sample();
|
|
343
626
|
if (diagnostics !== undefined) {
|
|
@@ -347,16 +630,30 @@ export function createGameSessionWithDriver(definition, options) {
|
|
|
347
630
|
activeUpdateScope = scope;
|
|
348
631
|
updateInProgress = true;
|
|
349
632
|
const updateStart = diagnostics === undefined ? 0 : now();
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
633
|
+
let nextState;
|
|
634
|
+
try {
|
|
635
|
+
nextState = freezeObject(
|
|
636
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
637
|
+
activeScene.definition.update({
|
|
638
|
+
state: activeScene.state,
|
|
639
|
+
input,
|
|
640
|
+
transition: makeTransitionController(scope),
|
|
641
|
+
events: emitter,
|
|
642
|
+
tick: nextTick,
|
|
643
|
+
sceneTick: nextSceneTick,
|
|
644
|
+
deltaSeconds: fixedStepMs / 1000,
|
|
645
|
+
elapsedSeconds: nextTick * fixedStepMs / 1000,
|
|
646
|
+
sceneElapsedSeconds: nextSceneTick * fixedStepMs / 1000
|
|
647
|
+
}));
|
|
648
|
+
} catch (error) {
|
|
649
|
+
// Update failed: discard staged events, invalidate emitter.
|
|
650
|
+
stagedThisTick = [];
|
|
651
|
+
emitterInvalidated = true;
|
|
652
|
+
activeUpdateScope = undefined;
|
|
653
|
+
updateInProgress = false;
|
|
654
|
+
throw error;
|
|
655
|
+
}
|
|
656
|
+
emitterInvalidated = true;
|
|
360
657
|
activeUpdateScope = undefined;
|
|
361
658
|
updateInProgress = false;
|
|
362
659
|
if (diagnostics !== undefined) {
|
|
@@ -370,7 +667,17 @@ export function createGameSessionWithDriver(definition, options) {
|
|
|
370
667
|
// A transition requested during update commits after this update
|
|
371
668
|
// completes successfully. The update consumed one fixed step; the
|
|
372
669
|
// hard-cut frame publishes at the end of this presentation callback.
|
|
373
|
-
|
|
670
|
+
try {
|
|
671
|
+
commitTransition(intent, nextState, nextTick, true);
|
|
672
|
+
} catch (error) {
|
|
673
|
+
// Transition preparation/disposal failed: discard staged events.
|
|
674
|
+
stagedThisTick = [];
|
|
675
|
+
throw error;
|
|
676
|
+
}
|
|
677
|
+
// Successful transition tick: staged events commit with source tick/scene.
|
|
678
|
+
if (stagedThisTick.length > 0) {
|
|
679
|
+
deliverEvents(stagedThisTick);
|
|
680
|
+
}
|
|
374
681
|
accumulatorMs = Math.max(0, accumulatorMs - fixedStepMs);
|
|
375
682
|
// F4: the transition consumed one fixed step; report it as such
|
|
376
683
|
// and never as a zero-step callback (zero-step fires only when
|
|
@@ -381,14 +688,29 @@ export function createGameSessionWithDriver(definition, options) {
|
|
|
381
688
|
break;
|
|
382
689
|
}
|
|
383
690
|
const snapshotStart = diagnostics === undefined ? 0 : now();
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
691
|
+
let rawSnapshot;
|
|
692
|
+
try {
|
|
693
|
+
rawSnapshot = activeScene.definition.snapshot({
|
|
694
|
+
state: nextState
|
|
695
|
+
});
|
|
696
|
+
} catch (error) {
|
|
697
|
+
stagedThisTick = [];
|
|
698
|
+
throw error;
|
|
699
|
+
}
|
|
387
700
|
if (diagnostics !== undefined) {
|
|
388
701
|
diagnostics.onSnapshot(now() - snapshotStart);
|
|
389
702
|
}
|
|
390
703
|
const freezeStart = diagnostics === undefined ? 0 : now();
|
|
391
|
-
|
|
704
|
+
let nextSnapshot;
|
|
705
|
+
try {
|
|
706
|
+
nextSnapshot = deepFreeze(rawSnapshot, {
|
|
707
|
+
scene: sceneNameForTick,
|
|
708
|
+
tick: nextTick
|
|
709
|
+
});
|
|
710
|
+
} catch (error) {
|
|
711
|
+
stagedThisTick = [];
|
|
712
|
+
throw error;
|
|
713
|
+
}
|
|
392
714
|
if (diagnostics !== undefined) {
|
|
393
715
|
diagnostics.onDeepFreeze(now() - freezeStart);
|
|
394
716
|
}
|
|
@@ -400,6 +722,10 @@ export function createGameSessionWithDriver(definition, options) {
|
|
|
400
722
|
previousSnapshot = currentSnapshot;
|
|
401
723
|
currentSnapshot = nextSnapshot;
|
|
402
724
|
tick = nextTick;
|
|
725
|
+
// Successful tick: deliver staged events in tick order, then emission order.
|
|
726
|
+
if (stagedThisTick.length > 0) {
|
|
727
|
+
deliverEvents(stagedThisTick);
|
|
728
|
+
}
|
|
403
729
|
accumulatorMs = Math.max(0, accumulatorMs - fixedStepMs);
|
|
404
730
|
catchUpSteps += 1;
|
|
405
731
|
if (diagnostics !== undefined) {
|
|
@@ -412,8 +738,7 @@ export function createGameSessionWithDriver(definition, options) {
|
|
|
412
738
|
} catch (error) {
|
|
413
739
|
activeUpdateScope = undefined;
|
|
414
740
|
updateInProgress = false;
|
|
415
|
-
|
|
416
|
-
throw error;
|
|
741
|
+
pauseAndRethrow(error);
|
|
417
742
|
}
|
|
418
743
|
if (catchUpSteps === maxCatchUpSteps && accumulatorMs >= fixedStepMs) {
|
|
419
744
|
const droppedSteps = Math.floor(accumulatorMs / fixedStepMs);
|
|
@@ -435,7 +760,7 @@ export function createGameSessionWithDriver(definition, options) {
|
|
|
435
760
|
commitOrPause();
|
|
436
761
|
}
|
|
437
762
|
if (status === 'running' && generation === activeGeneration) {
|
|
438
|
-
|
|
763
|
+
scheduleSuccessor(activeGeneration);
|
|
439
764
|
}
|
|
440
765
|
});
|
|
441
766
|
};
|
|
@@ -453,21 +778,41 @@ export function createGameSessionWithDriver(definition, options) {
|
|
|
453
778
|
if (status === 'running') {
|
|
454
779
|
return;
|
|
455
780
|
}
|
|
456
|
-
|
|
781
|
+
if (sceneFaulted) {
|
|
782
|
+
throw new GameSessionLifecycleError('The active scene failed disposal and is explicitly non-resumable: ' + 'replace it with setScene() or restartScene() before start(), or dispose the session.');
|
|
783
|
+
}
|
|
784
|
+
const previous = status;
|
|
457
785
|
previousTimestampMs = undefined;
|
|
458
786
|
accumulatorMs = 0;
|
|
459
787
|
const activeGeneration = ++generation;
|
|
460
|
-
|
|
788
|
+
try {
|
|
789
|
+
schedule(activeGeneration);
|
|
790
|
+
} catch (error) {
|
|
791
|
+
// Do not publish `running` when scheduling could not be established.
|
|
792
|
+
status = previous;
|
|
793
|
+
throw error;
|
|
794
|
+
}
|
|
795
|
+
setStatus('running');
|
|
461
796
|
},
|
|
462
797
|
pause() {
|
|
463
798
|
assertLive();
|
|
464
|
-
pauseInternal();
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
799
|
+
const pauseFailure = captureFailure(() => pauseInternal());
|
|
800
|
+
// The command must complete: a pending external transition is resolved
|
|
801
|
+
// at the pause boundary even when a status listener threw, so a later
|
|
802
|
+
// start() can never commit a stale transition on an unexpected frame.
|
|
803
|
+
const transitionFailure = captureFailure(() => {
|
|
804
|
+
if (pendingTransition !== undefined) {
|
|
805
|
+
const pending = pendingTransition;
|
|
806
|
+
pendingTransition = undefined;
|
|
807
|
+
commitTransition(pending, activeScene.state, undefined);
|
|
808
|
+
commitOrPause();
|
|
809
|
+
}
|
|
810
|
+
});
|
|
811
|
+
if (pauseFailure.failed && transitionFailure.failed) {
|
|
812
|
+
throw composeFailures(pauseFailure.value, transitionFailure.value);
|
|
470
813
|
}
|
|
814
|
+
throwFailure(pauseFailure);
|
|
815
|
+
throwFailure(transitionFailure);
|
|
471
816
|
},
|
|
472
817
|
setScene(name) {
|
|
473
818
|
assertLive();
|
|
@@ -518,14 +863,29 @@ export function createGameSessionWithDriver(definition, options) {
|
|
|
518
863
|
options.frameDriver.cancelFrame(frameHandle);
|
|
519
864
|
frameHandle = undefined;
|
|
520
865
|
}
|
|
521
|
-
status = 'disposed';
|
|
522
866
|
generation += 1;
|
|
523
867
|
previousTimestampMs = undefined;
|
|
524
868
|
accumulatorMs = 0;
|
|
525
869
|
pendingTransition = undefined;
|
|
526
870
|
inputBuffer.reset();
|
|
527
|
-
|
|
528
|
-
|
|
871
|
+
eventListeners.clear();
|
|
872
|
+
// Terminal cleanup is unconditional: `disposed` is delivered to the
|
|
873
|
+
// full listener snapshot (including the re-entrant queued pass), then
|
|
874
|
+
// every listener and the scene are released exactly once even when a
|
|
875
|
+
// status listener throws. The release flag is set BEFORE the
|
|
876
|
+
// notification so notifyStatus's finally performs the clear; for the
|
|
877
|
+
// re-entrant path the clear happens after the queued pass drains.
|
|
878
|
+
releaseStatusListeners = true;
|
|
879
|
+
const notificationFailure = captureFailure(() => setStatus('disposed'));
|
|
880
|
+
const cleanupFailure = captureFailure(() => {
|
|
881
|
+
listeners.clear();
|
|
882
|
+
disposeSceneInstance(activeScene, activeScene.state);
|
|
883
|
+
});
|
|
884
|
+
if (notificationFailure.failed && cleanupFailure.failed) {
|
|
885
|
+
throw composeFailures(notificationFailure.value, cleanupFailure.value);
|
|
886
|
+
}
|
|
887
|
+
throwFailure(notificationFailure);
|
|
888
|
+
throwFailure(cleanupFailure);
|
|
529
889
|
},
|
|
530
890
|
getRenderFrame() {
|
|
531
891
|
const alpha = commitFrame.hardCut ? 0 : Math.max(0, Math.min(accumulatorMs / fixedStepMs, 1 - Number.EPSILON));
|
|
@@ -547,6 +907,50 @@ export function createGameSessionWithDriver(definition, options) {
|
|
|
547
907
|
listeners.delete(listener);
|
|
548
908
|
}
|
|
549
909
|
});
|
|
910
|
+
},
|
|
911
|
+
addStatusListener(listener) {
|
|
912
|
+
assertLive();
|
|
913
|
+
statusListeners.add(listener);
|
|
914
|
+
diagnostics?.onStatusListenerCount?.(statusListeners.size);
|
|
915
|
+
let removed = false;
|
|
916
|
+
return Object.freeze({
|
|
917
|
+
remove() {
|
|
918
|
+
if (removed) {
|
|
919
|
+
return;
|
|
920
|
+
}
|
|
921
|
+
removed = true;
|
|
922
|
+
statusListeners.delete(listener);
|
|
923
|
+
diagnostics?.onStatusListenerCount?.(statusListeners.size);
|
|
924
|
+
}
|
|
925
|
+
});
|
|
926
|
+
},
|
|
927
|
+
addGameEventListener: (name, listener) => {
|
|
928
|
+
assertLive();
|
|
929
|
+
if (!hasEvents || !allowedEventNames.has(name)) {
|
|
930
|
+
throw new GameEventError(`Event "${String(name)}" is not declared by this game`);
|
|
931
|
+
}
|
|
932
|
+
let set = eventListeners.get(name);
|
|
933
|
+
if (set === undefined) {
|
|
934
|
+
set = new Set();
|
|
935
|
+
eventListeners.set(name, set);
|
|
936
|
+
}
|
|
937
|
+
set.add(listener);
|
|
938
|
+
let removed = false;
|
|
939
|
+
return Object.freeze({
|
|
940
|
+
remove() {
|
|
941
|
+
if (removed) {
|
|
942
|
+
return;
|
|
943
|
+
}
|
|
944
|
+
removed = true;
|
|
945
|
+
const existing = eventListeners.get(name);
|
|
946
|
+
if (existing) {
|
|
947
|
+
existing.delete(listener);
|
|
948
|
+
if (existing.size === 0) {
|
|
949
|
+
eventListeners.delete(name);
|
|
950
|
+
}
|
|
951
|
+
}
|
|
952
|
+
}
|
|
953
|
+
});
|
|
550
954
|
}
|
|
551
955
|
};
|
|
552
956
|
return Object.freeze(session);
|