rn-gamekit 0.1.0 → 0.2.1
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 +75 -0
- package/README.md +97 -16
- 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 +100 -10
- 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
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
import { GameEventError } from './errors';
|
|
2
|
+
|
|
3
|
+
const MAX_PAYLOAD_NODES = 512;
|
|
4
|
+
const MAX_PAYLOAD_DEPTH = 10;
|
|
5
|
+
const MAX_PAYLOAD_STRING_LENGTH = 4096;
|
|
6
|
+
const MAX_PAYLOAD_ARRAY_LENGTH = 256;
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Validate, clone, and deeply freeze a payload.
|
|
10
|
+
*
|
|
11
|
+
* Accepted: finite numbers, strings, booleans, `null`, `undefined` (as an
|
|
12
|
+
* optional property value), arrays, and plain records (`Object.prototype`
|
|
13
|
+
* or `Object.create(null)`). Rejected: functions, symbols, bigints,
|
|
14
|
+
* promises/thenables, sparse arrays, class instances, unsafe prototypes,
|
|
15
|
+
* native handles, React elements (`$$typeof`), cycles, accessors,
|
|
16
|
+
* non-enumerable properties, and non-finite numbers. Errors are reported
|
|
17
|
+
* with `Event "<name>" payload invalid at <path>`.
|
|
18
|
+
*
|
|
19
|
+
* The clone is frozen deeply so callers cannot mutate the staged envelope.
|
|
20
|
+
*/
|
|
21
|
+
export function cloneAndValidatePayload(
|
|
22
|
+
payload: unknown,
|
|
23
|
+
eventName: string,
|
|
24
|
+
basePath = 'payload',
|
|
25
|
+
): unknown {
|
|
26
|
+
let nodeCount = 0;
|
|
27
|
+
// Ancestry set — only the current recursion stack, not the entire visited graph.
|
|
28
|
+
// Shared acyclic references are allowed; true cycles are rejected.
|
|
29
|
+
const ancestry = new WeakSet<object>();
|
|
30
|
+
|
|
31
|
+
const fail = (path: string, reason: string): never => {
|
|
32
|
+
throw new GameEventError(`Event "${eventName}" payload invalid at ${path}: ${reason}`);
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
const isPlainRecord = (value: object): boolean => {
|
|
36
|
+
const proto = Object.getPrototypeOf(value);
|
|
37
|
+
return proto === Object.prototype || proto === null;
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
const isReactElement = (value: object): boolean => {
|
|
41
|
+
// Use descriptor to avoid invoking a getter for $$typeof.
|
|
42
|
+
const desc = Object.getOwnPropertyDescriptor(value, '$$typeof' as unknown as string);
|
|
43
|
+
if (desc !== undefined) {
|
|
44
|
+
return true;
|
|
45
|
+
}
|
|
46
|
+
// Also check prototype chain via `in` without invoking getter? `in` can invoke proxy traps but not getters.
|
|
47
|
+
// For safety, also check `Object.prototype.hasOwnProperty` on the object and its prototype chain via `in`.
|
|
48
|
+
// If the object has a getter for $$typeof on its prototype, `in` will not invoke it, but `'$$typeof' in value` will still
|
|
49
|
+
// check presence without invoking. We use `in` as a fallback that does not execute the getter.
|
|
50
|
+
return '$$typeof' in (value as Record<string, unknown>);
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
const clone = (value: unknown, path: string, depth: number): unknown => {
|
|
54
|
+
if (depth > MAX_PAYLOAD_DEPTH) {
|
|
55
|
+
fail(path, `exceeds maximum depth of ${MAX_PAYLOAD_DEPTH}`);
|
|
56
|
+
}
|
|
57
|
+
nodeCount += 1;
|
|
58
|
+
if (nodeCount > MAX_PAYLOAD_NODES) {
|
|
59
|
+
fail(path, `exceeds maximum payload size of ${MAX_PAYLOAD_NODES} nodes`);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
if (value === null || value === undefined) {
|
|
63
|
+
return value;
|
|
64
|
+
}
|
|
65
|
+
const type = typeof value;
|
|
66
|
+
if (type === 'string') {
|
|
67
|
+
const str = value as string;
|
|
68
|
+
if (str.length > MAX_PAYLOAD_STRING_LENGTH) {
|
|
69
|
+
fail(path, `string exceeds maximum length of ${MAX_PAYLOAD_STRING_LENGTH}`);
|
|
70
|
+
}
|
|
71
|
+
return str;
|
|
72
|
+
}
|
|
73
|
+
if (type === 'boolean') {
|
|
74
|
+
return value;
|
|
75
|
+
}
|
|
76
|
+
if (type === 'number') {
|
|
77
|
+
const num = value as number;
|
|
78
|
+
if (!Number.isFinite(num)) {
|
|
79
|
+
fail(path, 'number must be finite');
|
|
80
|
+
}
|
|
81
|
+
return num;
|
|
82
|
+
}
|
|
83
|
+
if (type === 'bigint') {
|
|
84
|
+
fail(path, 'bigint is not a supported payload type');
|
|
85
|
+
}
|
|
86
|
+
if (type === 'symbol') {
|
|
87
|
+
fail(path, 'symbol is not a supported payload type');
|
|
88
|
+
}
|
|
89
|
+
if (type === 'function') {
|
|
90
|
+
fail(path, 'function is not a supported payload type');
|
|
91
|
+
}
|
|
92
|
+
if (type !== 'object') {
|
|
93
|
+
fail(path, `unsupported payload type "${type}"`);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
const obj = value as object;
|
|
97
|
+
if (ancestry.has(obj)) {
|
|
98
|
+
fail(path, 'cycle detected in payload');
|
|
99
|
+
}
|
|
100
|
+
ancestry.add(obj);
|
|
101
|
+
|
|
102
|
+
// Use try/finally to ensure ancestry is cleaned even when we throw.
|
|
103
|
+
try {
|
|
104
|
+
// GS-EVENT-03: thenables are rejected without invoking any user code.
|
|
105
|
+
// Only safe operations run here (instanceof, getPrototypeOf, own
|
|
106
|
+
// descriptors). A Promise fails with its useful path; every other
|
|
107
|
+
// non-plain object fails at the array/record branches below — the
|
|
108
|
+
// preliminary inherited `.then` read that could execute a getter is
|
|
109
|
+
// gone. Own `then` functions are rejected later as function values.
|
|
110
|
+
if (obj instanceof Promise) {
|
|
111
|
+
fail(path, 'promise/thenable is not a supported payload type');
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
if (isReactElement(obj)) {
|
|
115
|
+
fail(path, 'React element is not a supported payload type');
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
if (Array.isArray(obj)) {
|
|
119
|
+
const arr = obj as unknown[];
|
|
120
|
+
if (Object.getPrototypeOf(arr) !== Array.prototype) {
|
|
121
|
+
fail(path, 'array subclass is not a supported payload type');
|
|
122
|
+
}
|
|
123
|
+
if (arr.length > MAX_PAYLOAD_ARRAY_LENGTH) {
|
|
124
|
+
fail(path, `array exceeds maximum length of ${MAX_PAYLOAD_ARRAY_LENGTH}`);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// Use descriptors to avoid invoking getters and to detect sparse holes.
|
|
128
|
+
const descs = Object.getOwnPropertyDescriptors(arr);
|
|
129
|
+
// Sparse check: every index < length must have an own descriptor.
|
|
130
|
+
for (let index = 0; index < arr.length; index += 1) {
|
|
131
|
+
const key = String(index);
|
|
132
|
+
if (!(key in descs)) {
|
|
133
|
+
fail(`${path}[${index}]`, 'sparse array holes are not supported');
|
|
134
|
+
}
|
|
135
|
+
const d = descs[key]!;
|
|
136
|
+
if (d.get !== undefined || d.set !== undefined) {
|
|
137
|
+
fail(`${path}[${index}]`, 'accessor property is not supported');
|
|
138
|
+
}
|
|
139
|
+
if (d.enumerable === false) {
|
|
140
|
+
fail(`${path}[${index}]`, 'non-enumerable property is not supported');
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// Clone indices via descriptors to avoid getter invocation.
|
|
145
|
+
const cloned: unknown[] = new Array(arr.length);
|
|
146
|
+
for (let index = 0; index < arr.length; index += 1) {
|
|
147
|
+
const key = String(index);
|
|
148
|
+
const d = descs[key]!;
|
|
149
|
+
cloned[index] = clone(d.value, `${path}[${index}]`, depth + 1);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// Check for non-index own properties (including symbols).
|
|
153
|
+
for (const key of Reflect.ownKeys(descs) as (string | symbol)[]) {
|
|
154
|
+
if (typeof key === 'symbol') {
|
|
155
|
+
fail(`${path}[Symbol(${String(key).slice(7, -1)})]`, 'symbol-keyed property is not supported');
|
|
156
|
+
}
|
|
157
|
+
const k = key as string;
|
|
158
|
+
if (k === 'length') {
|
|
159
|
+
continue;
|
|
160
|
+
}
|
|
161
|
+
// Indices already handled.
|
|
162
|
+
if (/^(0|[1-9]\d*)$/.test(k)) {
|
|
163
|
+
const idx = Number(k);
|
|
164
|
+
if (idx < arr.length && String(idx) === k) {
|
|
165
|
+
continue;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
if (k === '__proto__' || k === 'constructor' || k === 'prototype') {
|
|
169
|
+
fail(`${path}.${k}`, 'unsafe prototype key is not supported');
|
|
170
|
+
}
|
|
171
|
+
const d = descs[k]!;
|
|
172
|
+
if (d.get !== undefined || d.set !== undefined) {
|
|
173
|
+
fail(`${path}.${k}`, 'accessor property is not supported');
|
|
174
|
+
}
|
|
175
|
+
if (d.enumerable === false) {
|
|
176
|
+
fail(`${path}.${k}`, 'non-enumerable property is not supported');
|
|
177
|
+
}
|
|
178
|
+
fail(`${path}.${k}`, 'array extra property is not a supported payload member');
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
Object.freeze(cloned);
|
|
182
|
+
return cloned;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
// Plain record
|
|
186
|
+
if (!isPlainRecord(obj)) {
|
|
187
|
+
fail(path, 'only plain records and arrays are supported (class instance, Map, Set, Date, etc. are rejected)');
|
|
188
|
+
}
|
|
189
|
+
const proto = Object.getPrototypeOf(obj);
|
|
190
|
+
|
|
191
|
+
const descs = Object.getOwnPropertyDescriptors(obj);
|
|
192
|
+
// Check for symbol keys and unsafe keys, and validate descriptors.
|
|
193
|
+
for (const key of Reflect.ownKeys(descs) as (string | symbol)[]) {
|
|
194
|
+
if (typeof key === 'symbol') {
|
|
195
|
+
fail(`${path}[Symbol(${String(key).slice(7, -1)})]`, 'symbol-keyed property is not supported');
|
|
196
|
+
}
|
|
197
|
+
const k = key as string;
|
|
198
|
+
if (k === '__proto__' || k === 'constructor' || k === 'prototype') {
|
|
199
|
+
fail(`${path}.${k}`, 'unsafe prototype key is not supported');
|
|
200
|
+
}
|
|
201
|
+
const d = descs[k]!;
|
|
202
|
+
if (d.get !== undefined || d.set !== undefined) {
|
|
203
|
+
fail(`${path}.${k}`, 'accessor property is not supported');
|
|
204
|
+
}
|
|
205
|
+
if (d.enumerable === false) {
|
|
206
|
+
fail(`${path}.${k}`, 'non-enumerable property is not supported');
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
const cloned: Record<string, unknown> = proto === null ? Object.create(null) : {};
|
|
211
|
+
for (const key of Object.keys(descs)) {
|
|
212
|
+
// `Object.keys` already filters to enumerable string keys, but we have already validated
|
|
213
|
+
// via `getOwnPropertyDescriptors` that all own keys are enumerable data properties.
|
|
214
|
+
// Use descriptor value without invoking getter (we already checked it's a data descriptor).
|
|
215
|
+
const d = descs[key]!;
|
|
216
|
+
cloned[key] = clone(d.value, `${path}.${key}`, depth + 1);
|
|
217
|
+
}
|
|
218
|
+
Object.freeze(cloned);
|
|
219
|
+
return cloned;
|
|
220
|
+
} finally {
|
|
221
|
+
ancestry.delete(obj);
|
|
222
|
+
}
|
|
223
|
+
};
|
|
224
|
+
|
|
225
|
+
const result = clone(payload, basePath, 0);
|
|
226
|
+
return result;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
export const PAYLOAD_LIMITS = {
|
|
230
|
+
MAX_PAYLOAD_NODES,
|
|
231
|
+
MAX_PAYLOAD_DEPTH,
|
|
232
|
+
MAX_PAYLOAD_STRING_LENGTH,
|
|
233
|
+
MAX_PAYLOAD_ARRAY_LENGTH,
|
|
234
|
+
} as const;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { AnyGameEventEnvelope } from './types';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Derive a deterministic seed from a committed event envelope.
|
|
5
|
+
*
|
|
6
|
+
* The seed is stable within a session and across replays because it
|
|
7
|
+
* depends only on the envelope's identity `(tick, ordinal)` and name,
|
|
8
|
+
* never on wall time, React renders, or display frames.
|
|
9
|
+
*
|
|
10
|
+
* `seedGameEvent` is suitable for seeding seeded visual effects,
|
|
11
|
+
* particles, or audio variations that must replay identically.
|
|
12
|
+
*/
|
|
13
|
+
function hashString(value: string): number {
|
|
14
|
+
let hash = 2166136261;
|
|
15
|
+
for (let index = 0; index < value.length; index += 1) {
|
|
16
|
+
hash ^= value.charCodeAt(index);
|
|
17
|
+
hash = Math.imul(hash, 16777619);
|
|
18
|
+
}
|
|
19
|
+
return hash >>> 0;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export function seedGameEvent(event: AnyGameEventEnvelope): number {
|
|
23
|
+
const nameHash = hashString(event.name);
|
|
24
|
+
// Deterministic mixing of tick, ordinal, and name hash — the documented
|
|
25
|
+
// stable identity (tick, ordinal, name). sceneTick is intentionally
|
|
26
|
+
// excluded; it is presentation-local and would make the seed disagree
|
|
27
|
+
// with its contract.
|
|
28
|
+
let seed = 17;
|
|
29
|
+
seed = Math.imul(seed, 31) + event.tick;
|
|
30
|
+
seed = Math.imul(seed, 31) + event.ordinal;
|
|
31
|
+
seed = Math.imul(seed, 31) + nameHash;
|
|
32
|
+
return seed >>> 0;
|
|
33
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import type { DeepReadonly } from '../core/session/types';
|
|
2
|
+
|
|
3
|
+
declare const EventDefsBrand: unique symbol;
|
|
4
|
+
|
|
5
|
+
/** A type-witness descriptor for one game event's payload. */
|
|
6
|
+
export interface GameEventDescriptor<TPayload> {
|
|
7
|
+
/** @internal Payload witness — no runtime value. */
|
|
8
|
+
readonly __payload?: TPayload;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/** A map from event name to its payload type. */
|
|
12
|
+
export type GameEventMap = Record<string, unknown>;
|
|
13
|
+
|
|
14
|
+
/** A map from event name to its descriptor (the authored declaration). */
|
|
15
|
+
export type GameEventDefinitions<TMap extends GameEventMap> = {
|
|
16
|
+
readonly [K in keyof TMap]: GameEventDescriptor<TMap[K]>;
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
/** Branded event definitions — nominal identity for scene/game binding. */
|
|
20
|
+
export type BrandedGameEventDefs<T extends Record<string, GameEventDescriptor<unknown>>> = T & {
|
|
21
|
+
readonly [EventDefsBrand]?: T;
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
/** Infer the payload map from a descriptor map. */
|
|
25
|
+
export type InferGameEventMap<TDefs extends Record<string, GameEventDescriptor<unknown>>> = {
|
|
26
|
+
[K in keyof TDefs as K extends string ? K : never]: TDefs[K] extends GameEventDescriptor<infer P> ? P : never;
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
/** One committed event envelope. Identity is `(tick, ordinal)` within a session. */
|
|
30
|
+
export interface GameEventEnvelope<TName extends string, TPayload> {
|
|
31
|
+
readonly name: TName;
|
|
32
|
+
readonly payload: DeepReadonly<TPayload>;
|
|
33
|
+
readonly tick: number;
|
|
34
|
+
readonly scene: string;
|
|
35
|
+
readonly sceneTick: number;
|
|
36
|
+
readonly ordinal: number;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/** Type-erased envelope for storage and delivery. */
|
|
40
|
+
export type AnyGameEventEnvelope = GameEventEnvelope<string, unknown>;
|
|
41
|
+
|
|
42
|
+
/** An emitter scoped to one fixed tick and one scene. */
|
|
43
|
+
export interface GameEventEmitter<TMap extends GameEventMap> {
|
|
44
|
+
emit<TName extends keyof TMap & string>(name: TName, payload: TMap[TName]): void;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/** Listener for one event name. May be sync or async; rejections are observed without awaiting. */
|
|
48
|
+
export type GameEventListener<TPayload> = (
|
|
49
|
+
event: GameEventEnvelope<string, TPayload>,
|
|
50
|
+
) => void | Promise<void>;
|
|
51
|
+
|
|
52
|
+
/** Infer the listener payload for a given game definition's event map. */
|
|
53
|
+
export type GameEventPayloadFor<TMap extends GameEventMap, TName extends keyof TMap & string> = TMap[TName];
|
package/src/events.ts
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Subpath entry for `rn-gamekit/events`.
|
|
3
|
+
*
|
|
4
|
+
* Typed event definitions, envelopes, payload limits, seeding, and errors.
|
|
5
|
+
* Does not expose internal validation helpers or effect consumers.
|
|
6
|
+
*/
|
|
7
|
+
export { GameEventError } from './events/errors';
|
|
8
|
+
export { defineGameEvents, gameEvent } from './events/defineGameEvents';
|
|
9
|
+
export { seedGameEvent } from './events/seed';
|
|
10
|
+
export { PAYLOAD_LIMITS } from './events/payload';
|
|
11
|
+
export type {
|
|
12
|
+
AnyGameEventEnvelope,
|
|
13
|
+
GameEventDefinitions,
|
|
14
|
+
GameEventDescriptor,
|
|
15
|
+
GameEventEmitter,
|
|
16
|
+
GameEventEnvelope,
|
|
17
|
+
GameEventListener,
|
|
18
|
+
GameEventMap,
|
|
19
|
+
InferGameEventMap,
|
|
20
|
+
} from './events/types';
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure geometry helpers (T11.1): AABB centers, translation, expansion, and
|
|
3
|
+
* union, plus vector arithmetic. All functions validate their inputs,
|
|
4
|
+
* preserve them untouched, and return fresh immutable values.
|
|
5
|
+
*/
|
|
6
|
+
import type { Aabb2D, Point2D, Vector2D } from './types';
|
|
7
|
+
import {
|
|
8
|
+
assertValidAabb2D,
|
|
9
|
+
assertValidPoint2D,
|
|
10
|
+
assertValidVector2D,
|
|
11
|
+
GeometryError,
|
|
12
|
+
} from './validation';
|
|
13
|
+
|
|
14
|
+
/** Center of an AABB. */
|
|
15
|
+
export function aabbCenter2D(aabb: Aabb2D): Point2D {
|
|
16
|
+
assertValidAabb2D(aabb);
|
|
17
|
+
return Object.freeze({
|
|
18
|
+
x: aabb.x + aabb.width / 2,
|
|
19
|
+
y: aabb.y + aabb.height / 2,
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/** Translate an AABB by a delta vector, returning a new AABB. */
|
|
24
|
+
export function translateAabb2D(aabb: Aabb2D, delta: Vector2D): Aabb2D {
|
|
25
|
+
assertValidAabb2D(aabb);
|
|
26
|
+
assertValidVector2D(delta, 'delta');
|
|
27
|
+
return Object.freeze({
|
|
28
|
+
x: aabb.x + delta.x,
|
|
29
|
+
y: aabb.y + delta.y,
|
|
30
|
+
width: aabb.width,
|
|
31
|
+
height: aabb.height,
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Expand an AABB symmetrically (or per-axis) by the given amounts.
|
|
37
|
+
*
|
|
38
|
+
* A negative inset shrinks the AABB. The expanded result keeps the same
|
|
39
|
+
* width/height semantics; `inset` is the margin added on each side.
|
|
40
|
+
*/
|
|
41
|
+
export function expandAabb2D(aabb: Aabb2D, inset: number | Vector2D): Aabb2D {
|
|
42
|
+
assertValidAabb2D(aabb);
|
|
43
|
+
const x = typeof inset === 'number' ? inset : inset.x;
|
|
44
|
+
const y = typeof inset === 'number' ? inset : inset.y;
|
|
45
|
+
assertFiniteInset(x, 'inset.x');
|
|
46
|
+
assertFiniteInset(y, 'inset.y');
|
|
47
|
+
const expanded = Object.freeze({
|
|
48
|
+
x: aabb.x - x,
|
|
49
|
+
y: aabb.y - y,
|
|
50
|
+
width: aabb.width + x * 2,
|
|
51
|
+
height: aabb.height + y * 2,
|
|
52
|
+
});
|
|
53
|
+
// A negative inset may legitimately shrink the shape, but never into a
|
|
54
|
+
// malformed (negative-size) result.
|
|
55
|
+
assertValidAabb2D(expanded, 'expanded');
|
|
56
|
+
return expanded;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function assertFiniteInset(value: number, field: string): void {
|
|
60
|
+
if (!Number.isFinite(value)) {
|
|
61
|
+
throw new GeometryError(
|
|
62
|
+
'GEOMETRY_INVALID_NUMBER',
|
|
63
|
+
field,
|
|
64
|
+
`expected a finite inset, got ${String(value)}`,
|
|
65
|
+
);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/** The smallest AABB containing both inputs (bounding union). */
|
|
70
|
+
export function unionAabb2D(first: Aabb2D, second: Aabb2D): Aabb2D {
|
|
71
|
+
assertValidAabb2D(first, 'first');
|
|
72
|
+
assertValidAabb2D(second, 'second');
|
|
73
|
+
const minX = Math.min(first.x, second.x);
|
|
74
|
+
const minY = Math.min(first.y, second.y);
|
|
75
|
+
const maxX = Math.max(first.x + first.width, second.x + second.width);
|
|
76
|
+
const maxY = Math.max(first.y + first.height, second.y + second.height);
|
|
77
|
+
return Object.freeze({
|
|
78
|
+
x: minX,
|
|
79
|
+
y: minY,
|
|
80
|
+
width: maxX - minX,
|
|
81
|
+
height: maxY - minY,
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/** Component-wise vector addition. */
|
|
86
|
+
export function addVector2D(first: Vector2D, second: Vector2D): Vector2D {
|
|
87
|
+
assertValidVector2D(first, 'first');
|
|
88
|
+
assertValidVector2D(second, 'second');
|
|
89
|
+
return Object.freeze({ x: first.x + second.x, y: first.y + second.y });
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/** Component-wise vector subtraction (`first - second`). */
|
|
93
|
+
export function subtractVector2D(first: Vector2D, second: Vector2D): Vector2D {
|
|
94
|
+
assertValidVector2D(first, 'first');
|
|
95
|
+
assertValidVector2D(second, 'second');
|
|
96
|
+
return Object.freeze({ x: first.x - second.x, y: first.y - second.y });
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/** Scale a vector by a finite scalar. */
|
|
100
|
+
export function scaleVector2D(vector: Vector2D, scalar: number): Vector2D {
|
|
101
|
+
assertValidVector2D(vector);
|
|
102
|
+
if (!Number.isFinite(scalar)) {
|
|
103
|
+
throw new GeometryError(
|
|
104
|
+
'GEOMETRY_INVALID_NUMBER',
|
|
105
|
+
'scalar',
|
|
106
|
+
`expected a finite number, got ${String(scalar)}`,
|
|
107
|
+
);
|
|
108
|
+
}
|
|
109
|
+
return Object.freeze({ x: vector.x * scalar, y: vector.y * scalar });
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/** Euclidean length of a vector. */
|
|
113
|
+
export function lengthVector2D(vector: Vector2D): number {
|
|
114
|
+
assertValidVector2D(vector);
|
|
115
|
+
return Math.hypot(vector.x, vector.y);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Normalize a vector to unit length. The zero vector is returned unchanged
|
|
120
|
+
* (never NaN); callers that need a fallback direction choose it explicitly.
|
|
121
|
+
*/
|
|
122
|
+
export function normalizeVector2D(vector: Vector2D): Vector2D {
|
|
123
|
+
assertValidVector2D(vector);
|
|
124
|
+
const length = Math.hypot(vector.x, vector.y);
|
|
125
|
+
if (length === 0) {
|
|
126
|
+
return Object.freeze({ x: 0, y: 0 });
|
|
127
|
+
}
|
|
128
|
+
return Object.freeze({ x: vector.x / length, y: vector.y / length });
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/** Euclidean distance between two points. */
|
|
132
|
+
export function distancePoint2D(first: Point2D, second: Point2D): number {
|
|
133
|
+
assertValidPoint2D(first, 'first');
|
|
134
|
+
assertValidPoint2D(second, 'second');
|
|
135
|
+
return Math.hypot(second.x - first.x, second.y - first.y);
|
|
136
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export type { Aabb2D, Circle2D, Point2D, Segment2D, Vector2D } from './types';
|
|
2
|
+
export { GeometryError, type GeometryErrorCode } from './validation';
|
|
3
|
+
export {
|
|
4
|
+
aabbCenter2D,
|
|
5
|
+
addVector2D,
|
|
6
|
+
distancePoint2D,
|
|
7
|
+
expandAabb2D,
|
|
8
|
+
lengthVector2D,
|
|
9
|
+
normalizeVector2D,
|
|
10
|
+
scaleVector2D,
|
|
11
|
+
subtractVector2D,
|
|
12
|
+
translateAabb2D,
|
|
13
|
+
unionAabb2D,
|
|
14
|
+
} from './helpers';
|
package/src/geometry/types.ts
CHANGED
|
@@ -1,3 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Canonical 2D geometry values (T11.1).
|
|
3
|
+
*
|
|
4
|
+
* All shapes are immutable plain data in Gamekit's logical world
|
|
5
|
+
* coordinates (positive x right, positive y down). `Aabb2D.x/y` identify the
|
|
6
|
+
* minimum/top-left corner. Width, height, and radius are finite and
|
|
7
|
+
* nonnegative; malformed values throw `GeometryError` at the public
|
|
8
|
+
* operation boundary and never masquerade as "no collision".
|
|
9
|
+
*/
|
|
10
|
+
|
|
1
11
|
/** A plain 2D point in logical/world or surface coordinate space. */
|
|
2
12
|
export interface Point2D {
|
|
3
13
|
/** Horizontal coordinate. */
|
|
@@ -5,3 +15,47 @@ export interface Point2D {
|
|
|
5
15
|
/** Vertical coordinate. */
|
|
6
16
|
readonly y: number;
|
|
7
17
|
}
|
|
18
|
+
|
|
19
|
+
/** A plain 2D vector (translation, displacement, or direction). */
|
|
20
|
+
export interface Vector2D {
|
|
21
|
+
/** Horizontal component. */
|
|
22
|
+
readonly x: number;
|
|
23
|
+
/** Vertical component. */
|
|
24
|
+
readonly y: number;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* An axis-aligned rectangle in logical world units.
|
|
29
|
+
*
|
|
30
|
+
* `x`/`y` are the top-left corner (the minimum corner in Gamekit's
|
|
31
|
+
* positive-down convention). Shape-compatible with the viewport `Rect`
|
|
32
|
+
* type: any `Rect` is also a valid `Aabb2D` by shape, and vice versa.
|
|
33
|
+
*/
|
|
34
|
+
export interface Aabb2D {
|
|
35
|
+
/** Left edge. */
|
|
36
|
+
readonly x: number;
|
|
37
|
+
/** Top edge. */
|
|
38
|
+
readonly y: number;
|
|
39
|
+
/** Width, finite and nonnegative. */
|
|
40
|
+
readonly width: number;
|
|
41
|
+
/** Height, finite and nonnegative. */
|
|
42
|
+
readonly height: number;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/** A circle in logical world units. */
|
|
46
|
+
export interface Circle2D {
|
|
47
|
+
/** Center x. */
|
|
48
|
+
readonly x: number;
|
|
49
|
+
/** Center y. */
|
|
50
|
+
readonly y: number;
|
|
51
|
+
/** Radius, finite and nonnegative. */
|
|
52
|
+
readonly radius: number;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/** A directed segment (ray-style query input). */
|
|
56
|
+
export interface Segment2D {
|
|
57
|
+
/** Segment start point. */
|
|
58
|
+
readonly start: Point2D;
|
|
59
|
+
/** Segment end point. */
|
|
60
|
+
readonly end: Point2D;
|
|
61
|
+
}
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Geometry validation and structured errors (T11.1).
|
|
3
|
+
*
|
|
4
|
+
* Mirrors the package's structured-error style (`GameAssetError`): a stable
|
|
5
|
+
* machine-readable code plus the offending field. Validation happens at
|
|
6
|
+
* public operation boundaries; helpers never coerce or reorder malformed
|
|
7
|
+
* values into valid shapes.
|
|
8
|
+
*
|
|
9
|
+
* Numeric policy (GS-GEOMETRY-01): validators require the declared
|
|
10
|
+
* structural shape (a null/array/scalar argument fails with
|
|
11
|
+
* GEOMETRY_INVALID_SHAPE, never a TypeError) and finite components within
|
|
12
|
+
* ordinary game-world magnitudes. Derived-value overflow from extreme
|
|
13
|
+
* finite inputs is out of contract: helpers do not re-validate results,
|
|
14
|
+
* and zero-length normalization of an overflowing length stays a zero
|
|
15
|
+
* vector by the existing defined behavior.
|
|
16
|
+
*/
|
|
17
|
+
import type { Aabb2D, Circle2D, Point2D, Segment2D, Vector2D } from './types';
|
|
18
|
+
|
|
19
|
+
/** Stable error codes for geometry and collision input. */
|
|
20
|
+
export type GeometryErrorCode =
|
|
21
|
+
| 'GEOMETRY_INVALID_NUMBER'
|
|
22
|
+
| 'GEOMETRY_INVALID_SIZE'
|
|
23
|
+
| 'GEOMETRY_INVALID_BITS'
|
|
24
|
+
| 'GEOMETRY_INVALID_SEGMENT'
|
|
25
|
+
| 'GEOMETRY_INVALID_SHAPE'
|
|
26
|
+
| 'GEOMETRY_DUPLICATE_ID'
|
|
27
|
+
| 'GEOMETRY_SPATIAL_INDEX_RANGE';
|
|
28
|
+
|
|
29
|
+
/** A structured geometry or collision input failure. */
|
|
30
|
+
export class GeometryError extends Error {
|
|
31
|
+
/** Stable machine-readable code. */
|
|
32
|
+
readonly code: GeometryErrorCode;
|
|
33
|
+
/** Field path within the value that caused the failure. */
|
|
34
|
+
readonly field: string;
|
|
35
|
+
|
|
36
|
+
constructor(code: GeometryErrorCode, field: string, message: string) {
|
|
37
|
+
super(`${code} at ${field}: ${message}`);
|
|
38
|
+
this.name = 'GeometryError';
|
|
39
|
+
this.code = code;
|
|
40
|
+
this.field = field;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/** Assert a finite number (rejects NaN and ±Infinity). */
|
|
45
|
+
export function assertFiniteNumber(value: number, field: string): void {
|
|
46
|
+
if (!Number.isFinite(value)) {
|
|
47
|
+
throw new GeometryError(
|
|
48
|
+
'GEOMETRY_INVALID_NUMBER',
|
|
49
|
+
field,
|
|
50
|
+
`expected a finite number, got ${String(value)}`,
|
|
51
|
+
);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/** Assert a finite, nonnegative size (width, height, radius). */
|
|
56
|
+
export function assertNonnegativeSize(value: number, field: string): void {
|
|
57
|
+
assertFiniteNumber(value, field);
|
|
58
|
+
if (value < 0) {
|
|
59
|
+
throw new GeometryError(
|
|
60
|
+
'GEOMETRY_INVALID_SIZE',
|
|
61
|
+
field,
|
|
62
|
+
`expected a nonnegative size, got ${value}`,
|
|
63
|
+
);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/** Assert an unsigned 32-bit integer (collision filters and bit masks). */
|
|
68
|
+
export function assertUnsigned32Bits(value: number, field: string): void {
|
|
69
|
+
if (!Number.isInteger(value) || value < 0 || value > 0xffffffff) {
|
|
70
|
+
throw new GeometryError(
|
|
71
|
+
'GEOMETRY_INVALID_BITS',
|
|
72
|
+
field,
|
|
73
|
+
`expected an unsigned 32-bit integer, got ${String(value)}`,
|
|
74
|
+
);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/** Assert a value is a plain record before reading fields (GS-GEOMETRY-01). */
|
|
79
|
+
function assertRecordShape(value: unknown, name: string): asserts value is Record<string, unknown> {
|
|
80
|
+
if (value === null || typeof value !== 'object' || Array.isArray(value)) {
|
|
81
|
+
throw new GeometryError(
|
|
82
|
+
'GEOMETRY_INVALID_SHAPE',
|
|
83
|
+
name,
|
|
84
|
+
`expected an object with numeric fields, got ${Array.isArray(value) ? 'an array' : String(value)}`,
|
|
85
|
+
);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/** Validate a point or vector component pair. */
|
|
90
|
+
export function assertValidPoint2D(point: Point2D, name = 'point'): void {
|
|
91
|
+
assertRecordShape(point, name);
|
|
92
|
+
assertFiniteNumber(point.x, `${name}.x`);
|
|
93
|
+
assertFiniteNumber(point.y, `${name}.y`);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/** Validate a vector (same shape as a point, distinct naming). */
|
|
97
|
+
export function assertValidVector2D(vector: Vector2D, name = 'vector'): void {
|
|
98
|
+
assertRecordShape(vector, name);
|
|
99
|
+
assertFiniteNumber(vector.x, `${name}.x`);
|
|
100
|
+
assertFiniteNumber(vector.y, `${name}.y`);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/** Validate an AABB: finite corner, finite nonnegative size. */
|
|
104
|
+
export function assertValidAabb2D(aabb: Aabb2D, name = 'aabb'): void {
|
|
105
|
+
assertRecordShape(aabb, name);
|
|
106
|
+
assertFiniteNumber(aabb.x, `${name}.x`);
|
|
107
|
+
assertFiniteNumber(aabb.y, `${name}.y`);
|
|
108
|
+
assertNonnegativeSize(aabb.width, `${name}.width`);
|
|
109
|
+
assertNonnegativeSize(aabb.height, `${name}.height`);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/** Validate a circle: finite center, finite nonnegative radius. */
|
|
113
|
+
export function assertValidCircle2D(circle: Circle2D, name = 'circle'): void {
|
|
114
|
+
assertRecordShape(circle, name);
|
|
115
|
+
assertFiniteNumber(circle.x, `${name}.x`);
|
|
116
|
+
assertFiniteNumber(circle.y, `${name}.y`);
|
|
117
|
+
assertNonnegativeSize(circle.radius, `${name}.radius`);
|
|
118
|
+
}
|
|
119
|
+
/** Validate a segment: finite endpoints that are not both degenerate checks. */
|
|
120
|
+
export function assertValidSegment2D(segment: Segment2D, name = 'segment'): void {
|
|
121
|
+
assertRecordShape(segment, name);
|
|
122
|
+
assertValidPoint2D(segment.start, `${name}.start`);
|
|
123
|
+
assertValidPoint2D(segment.end, `${name}.end`);
|
|
124
|
+
if (segment.start.x === segment.end.x && segment.start.y === segment.end.y) {
|
|
125
|
+
throw new GeometryError(
|
|
126
|
+
'GEOMETRY_INVALID_SEGMENT',
|
|
127
|
+
name,
|
|
128
|
+
'expected distinct endpoints, got a zero-length segment',
|
|
129
|
+
);
|
|
130
|
+
}
|
|
131
|
+
}
|