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
|
@@ -0,0 +1,436 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Multitouch button pad (T20).
|
|
3
|
+
*
|
|
4
|
+
* The React surface over the headless button-pad controller
|
|
5
|
+
* (`core/input/buttonPad`): compose any number of {@link GameButton} zones
|
|
6
|
+
* inside a {@link GameButtonPad}; every active pointer is mapped to the zone
|
|
7
|
+
* it covers and press/release edges flow into the session's declared button
|
|
8
|
+
* actions. Unlike RN `Pressable`, simultaneous fingers on different buttons
|
|
9
|
+
* all register — hold left/right and jump at the same time.
|
|
10
|
+
*
|
|
11
|
+
* Semantics carried over from the reference implementation:
|
|
12
|
+
* - Release edges ALWAYS fire on touch up/cancel, so edge-triggered actions
|
|
13
|
+
* (a jump pulse) re-arm for the next press.
|
|
14
|
+
* - A finger sliding between zones reassigns: release + press.
|
|
15
|
+
* - Unmount releases every held action; no input outlives the pad.
|
|
16
|
+
*
|
|
17
|
+
* GS-INPUT-03: zones measure into pad coordinates (never parent-relative),
|
|
18
|
+
* every mounted zone has an owner identity with idempotent cleanup, and
|
|
19
|
+
* terminal cleanup never touches a disposed session.
|
|
20
|
+
* GS-INPUT-04: one invalidation policy — pause, session replacement, and
|
|
21
|
+
* unmount bump an ownership generation stamped onto every scheduled RN
|
|
22
|
+
* callback; stale callbacks die at ingress, pad ownership clears, and a
|
|
23
|
+
* fresh down is required before moves can acquire again.
|
|
24
|
+
*/
|
|
25
|
+
import {
|
|
26
|
+
createContext,
|
|
27
|
+
useCallback,
|
|
28
|
+
useContext,
|
|
29
|
+
useEffect,
|
|
30
|
+
useMemo,
|
|
31
|
+
useRef,
|
|
32
|
+
type ReactNode,
|
|
33
|
+
} from 'react';
|
|
34
|
+
import { findNodeHandle, StyleSheet, View } from 'react-native';
|
|
35
|
+
import { GestureDetector, useManualGesture, type ManualGestureConfig } from 'react-native-gesture-handler';
|
|
36
|
+
import { useSharedValue } from 'react-native-reanimated';
|
|
37
|
+
import { scheduleOnRN } from 'react-native-worklets';
|
|
38
|
+
import type { StyleProp, ViewStyle } from 'react-native';
|
|
39
|
+
|
|
40
|
+
import { createButtonPadController } from '../core/input/buttonPad';
|
|
41
|
+
import type { InputMap } from '../definition/types';
|
|
42
|
+
import type { SceneMap } from '../definition/types';
|
|
43
|
+
import type { GameSession } from '../core/session/types';
|
|
44
|
+
|
|
45
|
+
/** Declared button action names of an input map. */
|
|
46
|
+
export type ButtonActionName<TInput extends InputMap> = {
|
|
47
|
+
[TName in Extract<keyof TInput, string>]: TInput[TName] extends { readonly type: 'button' }
|
|
48
|
+
? TName
|
|
49
|
+
: never;
|
|
50
|
+
}[Extract<keyof TInput, string>];
|
|
51
|
+
|
|
52
|
+
interface ButtonPadContextValue {
|
|
53
|
+
/**
|
|
54
|
+
* Register/refresh a zone rect with its owner node. Provisional rects
|
|
55
|
+
* come from layout events; pad-space measurement overwrites them.
|
|
56
|
+
*/
|
|
57
|
+
readonly setZone: (
|
|
58
|
+
action: string,
|
|
59
|
+
x: number,
|
|
60
|
+
y: number,
|
|
61
|
+
width: number,
|
|
62
|
+
height: number,
|
|
63
|
+
node: unknown,
|
|
64
|
+
) => void;
|
|
65
|
+
/**
|
|
66
|
+
* Authoritatively measure a zone into pad coordinates. No-op when native
|
|
67
|
+
* nodes are unavailable (the provisional layout registration stands).
|
|
68
|
+
*/
|
|
69
|
+
readonly measureZone: (action: string, node: unknown) => void;
|
|
70
|
+
/** Remove a zone (button unmounted or action replaced). */
|
|
71
|
+
readonly removeZone: (action: string, node: unknown) => void;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const ButtonPadContext = createContext<ButtonPadContextValue | null>(null);
|
|
75
|
+
|
|
76
|
+
function useButtonPadContext(): ButtonPadContextValue {
|
|
77
|
+
const context = useContext(ButtonPadContext);
|
|
78
|
+
if (context === null) {
|
|
79
|
+
throw new Error('GameButton must be rendered inside a GameButtonPad');
|
|
80
|
+
}
|
|
81
|
+
return context;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
export interface GameButtonPadProps<TScenes extends SceneMap, TInput extends InputMap> {
|
|
85
|
+
/** The session whose input buffer receives button presses. */
|
|
86
|
+
readonly game: GameSession<TScenes, TInput>;
|
|
87
|
+
/** One or more {@link GameButton} zones (any layout). */
|
|
88
|
+
readonly children?: ReactNode;
|
|
89
|
+
/**
|
|
90
|
+
* Container style layered over the default full-surface overlay. The pad
|
|
91
|
+
* never draws and never blocks touches outside mounted GameButtons.
|
|
92
|
+
*/
|
|
93
|
+
readonly style?: StyleProp<ViewStyle>;
|
|
94
|
+
/** Extra hit area around every zone, in dp. Default 0. */
|
|
95
|
+
readonly hitSlop?: number;
|
|
96
|
+
/** Test id for the pad container. */
|
|
97
|
+
readonly testID?: string;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/** A host node measurable against the pad container. */
|
|
101
|
+
interface MeasurableNode {
|
|
102
|
+
measureLayout(
|
|
103
|
+
relativeTo: unknown,
|
|
104
|
+
onSuccess: (x: number, y: number, width: number, height: number) => void,
|
|
105
|
+
onFail: () => void,
|
|
106
|
+
): void;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Map simultaneous multitouch zones onto declared button actions.
|
|
111
|
+
*
|
|
112
|
+
* The pad is an INVISIBLE FULL-SURFACE OVERLAY: it draws nothing and its
|
|
113
|
+
* empty areas let touches pass through (`pointerEvents="box-none"`), so you
|
|
114
|
+
* can render whatever React children you like underneath and position each
|
|
115
|
+
* {@link GameButton} anywhere on screen — flex rows, corners, one thumb-zone
|
|
116
|
+
* per side — with ordinary styles. Only the measured bounds of mounted
|
|
117
|
+
* {@link GameButton} components capture touches; every other point falls
|
|
118
|
+
* through to the content below.
|
|
119
|
+
*/
|
|
120
|
+
export function GameButtonPad<TScenes extends SceneMap, TInput extends InputMap>({
|
|
121
|
+
game,
|
|
122
|
+
children,
|
|
123
|
+
style,
|
|
124
|
+
hitSlop = 0,
|
|
125
|
+
testID,
|
|
126
|
+
}: GameButtonPadProps<TScenes, TInput>) {
|
|
127
|
+
const input = game.input as unknown as {
|
|
128
|
+
press: (action: string) => void;
|
|
129
|
+
release: (action: string) => void;
|
|
130
|
+
};
|
|
131
|
+
const padRef = useRef<View | null>(null);
|
|
132
|
+
// The zone context must stay identical across session replacements:
|
|
133
|
+
// zones belong to mounted buttons, not to sessions, so a game change
|
|
134
|
+
// must never tear down and re-register them (no layout event would
|
|
135
|
+
// restore them). Session/input reads below always use the live values.
|
|
136
|
+
const sessionRef = useRef({ game, input });
|
|
137
|
+
sessionRef.current = { game, input };
|
|
138
|
+
|
|
139
|
+
// Stable across renders: RNGH 3 re-registers gesture callbacks when the
|
|
140
|
+
// config identity changes (same discipline as GamePointerInput).
|
|
141
|
+
const controllerRef = useRef<ReturnType<typeof createButtonPadController> | null>(null);
|
|
142
|
+
if (controllerRef.current === null) {
|
|
143
|
+
controllerRef.current = createButtonPadController({ hitSlop });
|
|
144
|
+
}
|
|
145
|
+
// GS-INPUT-03: owner identity per mounted zone. A second mounted button
|
|
146
|
+
// claiming the same action is a contract violation; re-registration by
|
|
147
|
+
// the owning node (re-layout, re-measure) is idempotent.
|
|
148
|
+
const ownersRef = useRef(new Map<string, unknown>());
|
|
149
|
+
// GS-INPUT-04: ownership generation — bumped on pause, session
|
|
150
|
+
// replacement, and unmount; stamped onto every scheduled RN callback and
|
|
151
|
+
// checked at ingress so stale callbacks die instead of pressing a dead
|
|
152
|
+
// session or a replaced binding.
|
|
153
|
+
const generationRef = useRef(1);
|
|
154
|
+
const generationSV = useSharedValue(1);
|
|
155
|
+
|
|
156
|
+
const liveInput = useCallback((): {
|
|
157
|
+
press: (action: string) => void;
|
|
158
|
+
release: (action: string) => void;
|
|
159
|
+
} | null => {
|
|
160
|
+
// GS-INPUT-03: terminal cleanup never touches a disposed session.
|
|
161
|
+
if (game.status === 'disposed') {
|
|
162
|
+
return null;
|
|
163
|
+
}
|
|
164
|
+
return input;
|
|
165
|
+
}, [game, input]);
|
|
166
|
+
|
|
167
|
+
const registerZone = useCallback(
|
|
168
|
+
(action: string, rect: { x: number; y: number; width: number; height: number }, node: unknown) => {
|
|
169
|
+
const owners = ownersRef.current;
|
|
170
|
+
const owner = owners.get(action);
|
|
171
|
+
if (owner !== undefined && owner !== node) {
|
|
172
|
+
throw new Error(
|
|
173
|
+
`GameButton action "${action}" is already registered by another mounted button. Use one button per action.`,
|
|
174
|
+
);
|
|
175
|
+
}
|
|
176
|
+
owners.set(action, node);
|
|
177
|
+
controllerRef.current?.setZone(action, rect);
|
|
178
|
+
},
|
|
179
|
+
[],
|
|
180
|
+
);
|
|
181
|
+
|
|
182
|
+
const context = useMemo<ButtonPadContextValue>(
|
|
183
|
+
() => ({
|
|
184
|
+
setZone: (action, x, y, width, height, node) => {
|
|
185
|
+
registerZone(action, { x, y, width, height }, node);
|
|
186
|
+
},
|
|
187
|
+
measureZone: (action, node) => {
|
|
188
|
+
const owners = ownersRef.current;
|
|
189
|
+
if (owners.has(action) && owners.get(action) !== node) {
|
|
190
|
+
throw new Error(
|
|
191
|
+
`GameButton action "${action}" is already registered by another mounted button. Use one button per action.`,
|
|
192
|
+
);
|
|
193
|
+
}
|
|
194
|
+
const measurable = node as MeasurableNode | null;
|
|
195
|
+
const padNode = padRef.current === null ? null : findNodeHandle(padRef.current);
|
|
196
|
+
if (measurable === null || typeof measurable.measureLayout !== 'function' || padNode === null) {
|
|
197
|
+
return;
|
|
198
|
+
}
|
|
199
|
+
measurable.measureLayout(
|
|
200
|
+
padNode,
|
|
201
|
+
(x, y, width, height) => {
|
|
202
|
+
// The button may have unmounted or been replaced while the
|
|
203
|
+
// native measurement was in flight: never resurrect a zone.
|
|
204
|
+
if (ownersRef.current.get(action) !== node) {
|
|
205
|
+
return;
|
|
206
|
+
}
|
|
207
|
+
registerZone(action, { x, y, width, height }, node);
|
|
208
|
+
},
|
|
209
|
+
() => {},
|
|
210
|
+
);
|
|
211
|
+
},
|
|
212
|
+
removeZone: (action, node) => {
|
|
213
|
+
if (ownersRef.current.get(action) !== node) {
|
|
214
|
+
return;
|
|
215
|
+
}
|
|
216
|
+
ownersRef.current.delete(action);
|
|
217
|
+
const released = controllerRef.current?.removeZone(action) ?? [];
|
|
218
|
+
const live = sessionRef.current;
|
|
219
|
+
if (live.game.status === 'disposed') {
|
|
220
|
+
return;
|
|
221
|
+
}
|
|
222
|
+
for (const actionReleased of released) {
|
|
223
|
+
live.input.release(actionReleased);
|
|
224
|
+
}
|
|
225
|
+
},
|
|
226
|
+
}),
|
|
227
|
+
[registerZone],
|
|
228
|
+
);
|
|
229
|
+
|
|
230
|
+
// GS-INPUT-04: one invalidation policy — pause, session replacement, and
|
|
231
|
+
// unmount bump the generation and clear pad ownership, so stale scheduled
|
|
232
|
+
// callbacks die at ingress and a fresh down is required after resume.
|
|
233
|
+
const invalidateOwnership = useCallback(() => {
|
|
234
|
+
generationRef.current += 1;
|
|
235
|
+
generationSV.value = generationRef.current;
|
|
236
|
+
controllerRef.current?.invalidateOwnership();
|
|
237
|
+
}, [generationSV]);
|
|
238
|
+
|
|
239
|
+
useEffect(() => {
|
|
240
|
+
invalidateOwnership();
|
|
241
|
+
if (game.status === 'disposed') {
|
|
242
|
+
return;
|
|
243
|
+
}
|
|
244
|
+
const subscription = game.addStatusListener((status) => {
|
|
245
|
+
if (status === 'paused') {
|
|
246
|
+
invalidateOwnership();
|
|
247
|
+
}
|
|
248
|
+
});
|
|
249
|
+
return () => {
|
|
250
|
+
subscription.remove();
|
|
251
|
+
};
|
|
252
|
+
}, [game, invalidateOwnership]);
|
|
253
|
+
|
|
254
|
+
useEffect(() => {
|
|
255
|
+
const controller = controllerRef.current;
|
|
256
|
+
return () => {
|
|
257
|
+
// Release held actions on the owning session first (unless it is
|
|
258
|
+
// already disposed), then invalidate so late callbacks die.
|
|
259
|
+
if (game.status !== 'disposed') {
|
|
260
|
+
for (const action of controller?.releaseAll() ?? []) {
|
|
261
|
+
input.release(action);
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
invalidateOwnership();
|
|
265
|
+
};
|
|
266
|
+
}, [game, input, invalidateOwnership]);
|
|
267
|
+
|
|
268
|
+
// JS-side handlers — called from the UI worklet via scheduleOnRN with the
|
|
269
|
+
// scheduling generation first. Stale generations die here, before the
|
|
270
|
+
// controller sees them.
|
|
271
|
+
const onDownJS = useCallback(
|
|
272
|
+
(generation: number, event: { allTouches: readonly { id: number; x: number; y: number }[] }) => {
|
|
273
|
+
if (generation !== generationRef.current) {
|
|
274
|
+
return;
|
|
275
|
+
}
|
|
276
|
+
const live = liveInput();
|
|
277
|
+
if (live === null) {
|
|
278
|
+
return;
|
|
279
|
+
}
|
|
280
|
+
const diff = controllerRef.current?.touchesDown(event.allTouches) ?? { pressed: [], released: [] };
|
|
281
|
+
for (const action of diff.released) live.release(action);
|
|
282
|
+
for (const action of diff.pressed) live.press(action);
|
|
283
|
+
},
|
|
284
|
+
[liveInput],
|
|
285
|
+
);
|
|
286
|
+
const onMoveJS = useCallback(
|
|
287
|
+
(generation: number, event: { allTouches: readonly { id: number; x: number; y: number }[] }) => {
|
|
288
|
+
if (generation !== generationRef.current) {
|
|
289
|
+
return;
|
|
290
|
+
}
|
|
291
|
+
const live = liveInput();
|
|
292
|
+
if (live === null) {
|
|
293
|
+
return;
|
|
294
|
+
}
|
|
295
|
+
const diff = controllerRef.current?.touchesMove(event.allTouches) ?? { pressed: [], released: [] };
|
|
296
|
+
for (const action of diff.released) live.release(action);
|
|
297
|
+
for (const action of diff.pressed) live.press(action);
|
|
298
|
+
},
|
|
299
|
+
[liveInput],
|
|
300
|
+
);
|
|
301
|
+
const onUpJS = useCallback(
|
|
302
|
+
(generation: number, event: { changedTouches: readonly { id: number; x: number; y: number }[] }) => {
|
|
303
|
+
if (generation !== generationRef.current) {
|
|
304
|
+
return;
|
|
305
|
+
}
|
|
306
|
+
const live = liveInput();
|
|
307
|
+
if (live === null) {
|
|
308
|
+
return;
|
|
309
|
+
}
|
|
310
|
+
const diff = controllerRef.current?.touchesUp(event.changedTouches) ?? { pressed: [], released: [] };
|
|
311
|
+
for (const action of diff.released) live.release(action);
|
|
312
|
+
},
|
|
313
|
+
[liveInput],
|
|
314
|
+
);
|
|
315
|
+
const onCancelJS = useCallback(
|
|
316
|
+
(generation: number, event: { changedTouches: readonly { id: number; x: number; y: number }[] }) => {
|
|
317
|
+
if (generation !== generationRef.current) {
|
|
318
|
+
return;
|
|
319
|
+
}
|
|
320
|
+
const live = liveInput();
|
|
321
|
+
if (live === null) {
|
|
322
|
+
return;
|
|
323
|
+
}
|
|
324
|
+
const diff = controllerRef.current?.touchesCancel(event.changedTouches) ?? { pressed: [], released: [] };
|
|
325
|
+
for (const action of diff.released) live.release(action);
|
|
326
|
+
},
|
|
327
|
+
[liveInput],
|
|
328
|
+
);
|
|
329
|
+
|
|
330
|
+
type ManualTouchHandler = NonNullable<ManualGestureConfig['onTouchesDown']>;
|
|
331
|
+
const handleTouchesDown = useCallback<ManualTouchHandler>(
|
|
332
|
+
(event) => {
|
|
333
|
+
'worklet';
|
|
334
|
+
scheduleOnRN(onDownJS, generationSV.value, event as never);
|
|
335
|
+
},
|
|
336
|
+
[onDownJS, generationSV],
|
|
337
|
+
);
|
|
338
|
+
const handleTouchesMove = useCallback<ManualTouchHandler>(
|
|
339
|
+
(event) => {
|
|
340
|
+
'worklet';
|
|
341
|
+
scheduleOnRN(onMoveJS, generationSV.value, event as never);
|
|
342
|
+
},
|
|
343
|
+
[onMoveJS, generationSV],
|
|
344
|
+
);
|
|
345
|
+
const handleTouchesUp = useCallback<ManualTouchHandler>(
|
|
346
|
+
(event) => {
|
|
347
|
+
'worklet';
|
|
348
|
+
scheduleOnRN(onUpJS, generationSV.value, event as never);
|
|
349
|
+
},
|
|
350
|
+
[onUpJS, generationSV],
|
|
351
|
+
);
|
|
352
|
+
const handleTouchesCancel = useCallback<ManualTouchHandler>(
|
|
353
|
+
(event) => {
|
|
354
|
+
'worklet';
|
|
355
|
+
scheduleOnRN(onCancelJS, generationSV.value, event as never);
|
|
356
|
+
},
|
|
357
|
+
[onCancelJS, generationSV],
|
|
358
|
+
);
|
|
359
|
+
|
|
360
|
+
const gestureConfig = useMemo<ManualGestureConfig>(
|
|
361
|
+
() => ({
|
|
362
|
+
shouldCancelWhenOutside: false,
|
|
363
|
+
onTouchesDown: handleTouchesDown,
|
|
364
|
+
onTouchesMove: handleTouchesMove,
|
|
365
|
+
onTouchesUp: handleTouchesUp,
|
|
366
|
+
onTouchesCancel: handleTouchesCancel,
|
|
367
|
+
}),
|
|
368
|
+
[handleTouchesCancel, handleTouchesDown, handleTouchesMove, handleTouchesUp],
|
|
369
|
+
);
|
|
370
|
+
const gesture = useManualGesture(gestureConfig);
|
|
371
|
+
|
|
372
|
+
// When a style is provided the caller owns the layout (e.g. an
|
|
373
|
+
// absolutely-positioned bottom row). Otherwise default to a full-surface
|
|
374
|
+
// invisible overlay so buttons can be placed anywhere via their own
|
|
375
|
+
// styles. Using a fallback instead of [absoluteFill, style] avoids the
|
|
376
|
+
// "tall pad" bug where merging top:0 from absoluteFill with a bottom-
|
|
377
|
+
// anchored row stretches the container to full height and vertically
|
|
378
|
+
// centers its children in the middle of the screen.
|
|
379
|
+
return (
|
|
380
|
+
<GestureDetector gesture={gesture}>
|
|
381
|
+
<View
|
|
382
|
+
ref={padRef as never}
|
|
383
|
+
pointerEvents="box-none"
|
|
384
|
+
style={style ?? StyleSheet.absoluteFill}
|
|
385
|
+
testID={testID}
|
|
386
|
+
>
|
|
387
|
+
<ButtonPadContext.Provider value={context}>{children}</ButtonPadContext.Provider>
|
|
388
|
+
</View>
|
|
389
|
+
</GestureDetector>
|
|
390
|
+
);
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
export interface GameButtonProps {
|
|
394
|
+
/** The declared button action this zone presses. */
|
|
395
|
+
readonly action: string;
|
|
396
|
+
/** Zone content (label, icon, art). */
|
|
397
|
+
readonly children?: ReactNode;
|
|
398
|
+
/** Zone layout + presentation styles. */
|
|
399
|
+
readonly style?: StyleProp<ViewStyle>;
|
|
400
|
+
/** Test id for end-to-end tests. */
|
|
401
|
+
readonly testID?: string;
|
|
402
|
+
/** Accessibility role announced to the OS. */
|
|
403
|
+
readonly accessibilityRole?: 'button';
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
/**
|
|
407
|
+
* One touch zone of the pad. Layout it however you like; its measured
|
|
408
|
+
* bounds become the multitouch hit area for `action`, in pad coordinates.
|
|
409
|
+
*
|
|
410
|
+
* GS-INPUT-03: the zone registers on layout (provisional, parent-relative)
|
|
411
|
+
* and re-resolves into pad space through native measurement whenever
|
|
412
|
+
* available; unmount and action replacement release the zone exactly once.
|
|
413
|
+
*/
|
|
414
|
+
export function GameButton({ action, children, style, testID, accessibilityRole }: GameButtonProps) {
|
|
415
|
+
const context = useButtonPadContext();
|
|
416
|
+
const nodeRef = useRef<View | null>(null);
|
|
417
|
+
useEffect(() => {
|
|
418
|
+
context.measureZone(action, nodeRef.current);
|
|
419
|
+
return () => context.removeZone(action, nodeRef.current);
|
|
420
|
+
}, [context, action]);
|
|
421
|
+
return (
|
|
422
|
+
<View
|
|
423
|
+
ref={nodeRef as never}
|
|
424
|
+
style={style}
|
|
425
|
+
testID={testID}
|
|
426
|
+
accessibilityRole={accessibilityRole}
|
|
427
|
+
onLayout={(event) => {
|
|
428
|
+
const layout = event.nativeEvent.layout;
|
|
429
|
+
context.setZone(action, layout.x, layout.y, layout.width, layout.height, nodeRef.current);
|
|
430
|
+
context.measureZone(action, nodeRef.current);
|
|
431
|
+
}}
|
|
432
|
+
>
|
|
433
|
+
{children}
|
|
434
|
+
</View>
|
|
435
|
+
);
|
|
436
|
+
}
|
|
@@ -9,9 +9,10 @@ import {
|
|
|
9
9
|
import { useFrameCallback, useSharedValue, type SharedValue } from 'react-native-reanimated';
|
|
10
10
|
import { scheduleOnRN } from 'react-native-worklets';
|
|
11
11
|
|
|
12
|
+
import type { CameraCut2D } from '../camera2d';
|
|
12
13
|
import type { InputMap, PointerInputAction, SceneMap } from '../definition/types';
|
|
13
14
|
import type { GameSession } from '../core/session/types';
|
|
14
|
-
import { GameViewportContext } from './GameView';
|
|
15
|
+
import { GameCameraContext, GameViewportContext } from './GameView';
|
|
15
16
|
import {
|
|
16
17
|
canBeginPrimaryPointer,
|
|
17
18
|
cancelOnActiveFinalize,
|
|
@@ -29,6 +30,7 @@ import {
|
|
|
29
30
|
type PointerCoalescerInput,
|
|
30
31
|
type PointerCoalescerState,
|
|
31
32
|
} from './pointerCoalescer';
|
|
33
|
+
import { packetCameraFor, type PointerCameraCapture2D } from './pointerCamera';
|
|
32
34
|
import { PointerBinding, type PointerPacket } from './pointerBinding';
|
|
33
35
|
|
|
34
36
|
/** Declared pointer action names of an input map. */
|
|
@@ -78,6 +80,7 @@ function TrailingFlushSampler({
|
|
|
78
80
|
layoutEpoch,
|
|
79
81
|
forwardSeq,
|
|
80
82
|
generation,
|
|
83
|
+
camera,
|
|
81
84
|
}: {
|
|
82
85
|
readonly coalescerState: SharedValue<PointerCoalescerState>;
|
|
83
86
|
readonly forwardEventOnJS: (packet: PointerPacket) => void;
|
|
@@ -85,6 +88,8 @@ function TrailingFlushSampler({
|
|
|
85
88
|
readonly layoutEpoch: SharedValue<number>;
|
|
86
89
|
readonly forwardSeq: SharedValue<number>;
|
|
87
90
|
readonly generation: number;
|
|
91
|
+
/** The presented camera shared value, sampled at flush time (T12-F4). */
|
|
92
|
+
readonly camera: SharedValue<CameraCut2D | undefined> | undefined;
|
|
88
93
|
}) {
|
|
89
94
|
// F2 acceptance: report the sampler's mounted lifecycle so the lab can
|
|
90
95
|
// prove no idle frame callback survives pointer exit, replacement, or
|
|
@@ -116,6 +121,10 @@ function TrailingFlushSampler({
|
|
|
116
121
|
layoutEpoch: layoutEpoch.value,
|
|
117
122
|
seq: forwardSeq.value,
|
|
118
123
|
atMs: Date.now(),
|
|
124
|
+
// The deferred move carries the stamp captured at ITS native
|
|
125
|
+
// sample (T12-RF3, T12-SF1) — never the flush-time camera, and a
|
|
126
|
+
// captured undefined stays undefined.
|
|
127
|
+
camera: packetCameraFor(forwarded, camera?.value),
|
|
119
128
|
});
|
|
120
129
|
}
|
|
121
130
|
});
|
|
@@ -150,6 +159,11 @@ export function GamePointerInput<TScenes extends SceneMap, TInput extends InputM
|
|
|
150
159
|
if (viewportContext === null) {
|
|
151
160
|
throw new Error('GamePointerInput must be rendered inside a GameView');
|
|
152
161
|
}
|
|
162
|
+
// T12.4: the adapter discovers the presented camera from the mounted
|
|
163
|
+
// surface (never a repeated prop), so renderer and input share the same
|
|
164
|
+
// generation. Games without a camera get the exact current viewport path.
|
|
165
|
+
const cameraContext = useContext(GameCameraContext);
|
|
166
|
+
const presentedCamera = cameraContext?.presented;
|
|
153
167
|
const viewportShared = viewportContext.viewport;
|
|
154
168
|
const maxMoveIntervalMs = game.getRenderFrame().stepMs;
|
|
155
169
|
const coalescerState = useSharedValue<PointerCoalescerState>(() =>
|
|
@@ -163,9 +177,19 @@ export function GamePointerInput<TScenes extends SceneMap, TInput extends InputM
|
|
|
163
177
|
// stamp packets with that same generation, so the packet producer and
|
|
164
178
|
// consumer agree by construction — no post-commit synchronization.
|
|
165
179
|
const binding = useMemo(
|
|
166
|
-
() =>
|
|
180
|
+
() =>
|
|
181
|
+
new PointerBinding(
|
|
182
|
+
action,
|
|
183
|
+
game.input,
|
|
184
|
+
() => viewportBinding.resolved,
|
|
185
|
+
nextBindingGeneration++,
|
|
186
|
+
),
|
|
167
187
|
[action, game, viewportBinding],
|
|
168
188
|
);
|
|
189
|
+
// T12-F4: the presented camera is sampled at EVENT TIME inside the touch
|
|
190
|
+
// worklets and stamped onto every packet; the binding inverts through
|
|
191
|
+
// that stamp, never a later JS-side read.
|
|
192
|
+
const cameraShared = presentedCamera;
|
|
169
193
|
const generation = binding.generation;
|
|
170
194
|
// F6/F3: the layout epoch is adapter-owned (ref + UI mirror), bumped only
|
|
171
195
|
// on layout revisions and unmount; it never resets, so replacement cannot
|
|
@@ -197,7 +221,33 @@ export function GamePointerInput<TScenes extends SceneMap, TInput extends InputM
|
|
|
197
221
|
[generation],
|
|
198
222
|
);
|
|
199
223
|
|
|
200
|
-
//
|
|
224
|
+
// T10.4: the pause transition clears the UI-side coalescer queue for the
|
|
225
|
+
// active stream (the core input buffer already cancelled ownership), so a
|
|
226
|
+
// pre-pause pointer can never flush stale moves after resume. The gesture
|
|
227
|
+
// itself is not remounted and its key does not change.
|
|
228
|
+
// GS-INPUT-04: pause also advances the packet epoch (queued pre-pause
|
|
229
|
+
// packets die at RN ingress) and clears the React sampler mirror, so the
|
|
230
|
+
// trailing sampler unmounts even when no coalescer event ever arrives to
|
|
231
|
+
// finalize it. A fresh down is required after resume.
|
|
232
|
+
useEffect(() => {
|
|
233
|
+
if (game.status === 'disposed') {
|
|
234
|
+
return;
|
|
235
|
+
}
|
|
236
|
+
const subscription = game.addStatusListener((status) => {
|
|
237
|
+
if (status === 'paused') {
|
|
238
|
+
coalescerState.value = createPointerCoalescerState(maxMoveIntervalMs);
|
|
239
|
+
bumpLayoutEpoch();
|
|
240
|
+
setSamplerState((previous) =>
|
|
241
|
+
reduceSamplerMirrorState(generation, previous, { generation, active: false }),
|
|
242
|
+
);
|
|
243
|
+
}
|
|
244
|
+
});
|
|
245
|
+
return () => {
|
|
246
|
+
subscription.remove();
|
|
247
|
+
};
|
|
248
|
+
}, [bumpLayoutEpoch, coalescerState, game, generation, maxMoveIntervalMs]);
|
|
249
|
+
|
|
250
|
+
// F2 review: `autostart` is only consulted at creation (changing it later
|
|
201
251
|
// re-registers but never activates) and `setActive` from an effect proved
|
|
202
252
|
// unreliable in this stack, so the sampler is a conditionally mounted
|
|
203
253
|
// component (see TrailingFlushSampler): it mounts with autostart active
|
|
@@ -213,10 +263,14 @@ export function GamePointerInput<TScenes extends SceneMap, TInput extends InputM
|
|
|
213
263
|
// layout die here, before the binding sees them.
|
|
214
264
|
if (packet.layoutEpoch !== layoutEpochRef.current) {
|
|
215
265
|
instrumentation?.onDispatchResult?.(packet.seq, packet.atMs, false);
|
|
266
|
+
instrumentation?.onDispatchRejected?.('layout-epoch', packet.seq, packet.atMs);
|
|
216
267
|
return;
|
|
217
268
|
}
|
|
218
269
|
const accepted = binding.dispatch(packet);
|
|
219
270
|
instrumentation?.onDispatchResult?.(packet.seq, packet.atMs, accepted);
|
|
271
|
+
if (!accepted) {
|
|
272
|
+
instrumentation?.onDispatchRejected?.('binding', packet.seq, packet.atMs);
|
|
273
|
+
}
|
|
220
274
|
},
|
|
221
275
|
[binding, instrumentation],
|
|
222
276
|
);
|
|
@@ -261,6 +315,7 @@ export function GamePointerInput<TScenes extends SceneMap, TInput extends InputM
|
|
|
261
315
|
layoutEpoch: layoutEpoch.value,
|
|
262
316
|
seq: forwardSeq.value,
|
|
263
317
|
atMs: Date.now(),
|
|
318
|
+
camera: cameraShared?.value,
|
|
264
319
|
});
|
|
265
320
|
}
|
|
266
321
|
const nextActive = samplerMirrorFromBatch(batch);
|
|
@@ -269,7 +324,7 @@ export function GamePointerInput<TScenes extends SceneMap, TInput extends InputM
|
|
|
269
324
|
}
|
|
270
325
|
GestureStateManager.activate(event.handlerTag);
|
|
271
326
|
},
|
|
272
|
-
[coalescerState, forwardEventOnJS, generation, instrumentation, layoutEpoch, reportSamplerState, viewportShared],
|
|
327
|
+
[cameraShared, coalescerState, forwardEventOnJS, generation, instrumentation, layoutEpoch, reportSamplerState, viewportShared],
|
|
273
328
|
);
|
|
274
329
|
|
|
275
330
|
const handleTouchesMove = useCallback<ManualTouchHandler>(
|
|
@@ -283,6 +338,7 @@ export function GamePointerInput<TScenes extends SceneMap, TInput extends InputM
|
|
|
283
338
|
x: touch.x,
|
|
284
339
|
y: touch.y,
|
|
285
340
|
nowMs: Date.now(),
|
|
341
|
+
stamp: { captured: true, value: cameraShared?.value } satisfies PointerCameraCapture2D,
|
|
286
342
|
});
|
|
287
343
|
for (const forwarded of batch) {
|
|
288
344
|
instrumentation?.onForwarded?.(
|
|
@@ -297,11 +353,12 @@ export function GamePointerInput<TScenes extends SceneMap, TInput extends InputM
|
|
|
297
353
|
layoutEpoch: layoutEpoch.value,
|
|
298
354
|
seq: forwardSeq.value,
|
|
299
355
|
atMs: Date.now(),
|
|
356
|
+
camera: packetCameraFor(forwarded, cameraShared?.value),
|
|
300
357
|
});
|
|
301
358
|
}
|
|
302
359
|
}
|
|
303
360
|
},
|
|
304
|
-
[coalescerState, forwardEventOnJS, generation, instrumentation, layoutEpoch],
|
|
361
|
+
[cameraShared, coalescerState, forwardEventOnJS, generation, instrumentation, layoutEpoch],
|
|
305
362
|
);
|
|
306
363
|
|
|
307
364
|
const handleTouchesUp = useCallback<ManualTouchHandler>(
|
|
@@ -330,6 +387,7 @@ export function GamePointerInput<TScenes extends SceneMap, TInput extends InputM
|
|
|
330
387
|
layoutEpoch: layoutEpoch.value,
|
|
331
388
|
seq: forwardSeq.value,
|
|
332
389
|
atMs: Date.now(),
|
|
390
|
+
camera: packetCameraFor(forwarded, cameraShared?.value),
|
|
333
391
|
});
|
|
334
392
|
}
|
|
335
393
|
const mirror = samplerMirrorFromBatch(batch);
|
|
@@ -344,7 +402,7 @@ export function GamePointerInput<TScenes extends SceneMap, TInput extends InputM
|
|
|
344
402
|
GestureStateManager.deactivate(event.handlerTag);
|
|
345
403
|
}
|
|
346
404
|
},
|
|
347
|
-
[coalescerState, forwardEventOnJS, generation, instrumentation, layoutEpoch, reportSamplerState],
|
|
405
|
+
[cameraShared, coalescerState, forwardEventOnJS, generation, instrumentation, layoutEpoch, reportSamplerState],
|
|
348
406
|
);
|
|
349
407
|
|
|
350
408
|
const handleTouchesCancel = useCallback<ManualTouchHandler>(
|
|
@@ -364,6 +422,7 @@ export function GamePointerInput<TScenes extends SceneMap, TInput extends InputM
|
|
|
364
422
|
layoutEpoch: layoutEpoch.value,
|
|
365
423
|
seq: forwardSeq.value,
|
|
366
424
|
atMs: Date.now(),
|
|
425
|
+
camera: cameraShared?.value,
|
|
367
426
|
});
|
|
368
427
|
}
|
|
369
428
|
const nextActive = samplerMirrorFromBatch(batch);
|
|
@@ -371,7 +430,7 @@ export function GamePointerInput<TScenes extends SceneMap, TInput extends InputM
|
|
|
371
430
|
scheduleOnRN(reportSamplerState, { generation, active: nextActive });
|
|
372
431
|
}
|
|
373
432
|
},
|
|
374
|
-
[coalescerState, forwardEventOnJS, generation, instrumentation, layoutEpoch, reportSamplerState],
|
|
433
|
+
[cameraShared, coalescerState, forwardEventOnJS, generation, instrumentation, layoutEpoch, reportSamplerState],
|
|
375
434
|
);
|
|
376
435
|
|
|
377
436
|
const handleFinalize = useCallback<ManualFinalizeHandler>(
|
|
@@ -394,6 +453,7 @@ export function GamePointerInput<TScenes extends SceneMap, TInput extends InputM
|
|
|
394
453
|
layoutEpoch: layoutEpoch.value,
|
|
395
454
|
seq: forwardSeq.value,
|
|
396
455
|
atMs: Date.now(),
|
|
456
|
+
camera: cameraShared?.value,
|
|
397
457
|
});
|
|
398
458
|
}
|
|
399
459
|
const nextActive = samplerMirrorFromBatch(batch);
|
|
@@ -441,8 +501,12 @@ export function GamePointerInput<TScenes extends SceneMap, TInput extends InputM
|
|
|
441
501
|
// flight become harmless no-ops, neutralize old input ownership exactly
|
|
442
502
|
// once, reset the coalescer, remove the old sampler (generation
|
|
443
503
|
// mismatch makes it inactive by construction), and dispose the binding.
|
|
504
|
+
// The mirror reset bails out when already inactive so cleanup never
|
|
505
|
+
// schedules redundant renders (GS-INPUT-04).
|
|
444
506
|
bumpLayoutEpoch();
|
|
445
|
-
setSamplerState(
|
|
507
|
+
setSamplerState((previous) =>
|
|
508
|
+
previous.active ? { generation: -1, active: false } : previous,
|
|
509
|
+
);
|
|
446
510
|
if (game.status !== 'disposed') {
|
|
447
511
|
binding.cancel();
|
|
448
512
|
}
|
|
@@ -470,6 +534,7 @@ export function GamePointerInput<TScenes extends SceneMap, TInput extends InputM
|
|
|
470
534
|
layoutEpoch={layoutEpoch}
|
|
471
535
|
forwardSeq={forwardSeq}
|
|
472
536
|
generation={generation}
|
|
537
|
+
camera={cameraShared}
|
|
473
538
|
/>
|
|
474
539
|
) : null}
|
|
475
540
|
</View>
|