@jgengine/core 0.10.0 → 0.11.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.
Files changed (607) hide show
  1. package/CHANGELOG.md +13 -2
  2. package/LICENSE +203 -661
  3. package/README.md +1 -1
  4. package/dist/ai/crowd.d.ts +55 -0
  5. package/dist/ai/crowd.js +114 -0
  6. package/dist/ai/flock.d.ts +5 -2
  7. package/dist/ai/flock.js +5 -2
  8. package/dist/ai/groupAssist.d.ts +1 -0
  9. package/dist/ai/groupAssist.js +1 -0
  10. package/dist/ai/heatSystem.d.ts +76 -0
  11. package/dist/ai/heatSystem.js +97 -0
  12. package/dist/ai/interestScheduler.d.ts +107 -0
  13. package/dist/ai/interestScheduler.js +118 -0
  14. package/dist/ai/jobBoard.d.ts +1 -0
  15. package/dist/ai/jobBoard.js +1 -0
  16. package/dist/ai/laneSelect.d.ts +5 -2
  17. package/dist/ai/laneSelect.js +5 -2
  18. package/dist/ai/mobBrain.d.ts +1 -0
  19. package/dist/ai/mobBrain.js +1 -0
  20. package/dist/ai/spawnDirector.d.ts +7 -2
  21. package/dist/ai/spawnDirector.js +18 -15
  22. package/dist/ai/spawnPoint.d.ts +3 -1
  23. package/dist/ai/spawnPoint.js +3 -1
  24. package/dist/ai/targetAcquisition.d.ts +84 -0
  25. package/dist/ai/targetAcquisition.js +92 -0
  26. package/dist/anim/easing.d.ts +19 -0
  27. package/dist/anim/easing.js +19 -0
  28. package/dist/anim/oscillator.d.ts +12 -0
  29. package/dist/anim/oscillator.js +25 -0
  30. package/dist/area/areaEffectField.d.ts +127 -0
  31. package/dist/area/areaEffectField.js +175 -0
  32. package/dist/area/stackPolicy.d.ts +47 -0
  33. package/dist/area/stackPolicy.js +99 -0
  34. package/dist/authoring.d.ts +1 -0
  35. package/dist/authoring.js +1 -0
  36. package/dist/board/laneBoard.d.ts +13 -0
  37. package/dist/board/laneBoard.js +13 -0
  38. package/dist/board/timelineBoard.d.ts +10 -0
  39. package/dist/board/timelineBoard.js +10 -0
  40. package/dist/combat/abilityKit.d.ts +18 -0
  41. package/dist/combat/abilityKit.js +24 -9
  42. package/dist/combat/animationState.d.ts +5 -0
  43. package/dist/combat/animationState.js +5 -0
  44. package/dist/combat/breakMeters.d.ts +10 -0
  45. package/dist/combat/breakMeters.js +10 -0
  46. package/dist/combat/castRunner.d.ts +5 -0
  47. package/dist/combat/castRunner.js +5 -0
  48. package/dist/combat/comboPoints.d.ts +5 -0
  49. package/dist/combat/comboPoints.js +5 -0
  50. package/dist/combat/comboString.d.ts +5 -0
  51. package/dist/combat/comboString.js +5 -0
  52. package/dist/combat/damageInterceptors.d.ts +192 -0
  53. package/dist/combat/damageInterceptors.js +251 -0
  54. package/dist/combat/damageMatchup.d.ts +68 -0
  55. package/dist/combat/damageMatchup.js +42 -0
  56. package/dist/combat/damageResolution.d.ts +63 -0
  57. package/dist/combat/damageResolution.js +50 -0
  58. package/dist/combat/death.d.ts +7 -1
  59. package/dist/combat/death.js +5 -0
  60. package/dist/combat/deathReason.d.ts +14 -0
  61. package/dist/combat/deathReason.js +1 -0
  62. package/dist/combat/defensiveWindow.d.ts +5 -0
  63. package/dist/combat/defensiveWindow.js +5 -0
  64. package/dist/combat/dotField.d.ts +5 -1
  65. package/dist/combat/dotField.js +5 -1
  66. package/dist/combat/downed.d.ts +5 -0
  67. package/dist/combat/downed.js +5 -0
  68. package/dist/combat/effects.d.ts +5 -0
  69. package/dist/combat/effects.js +5 -0
  70. package/dist/combat/encounterSequence.d.ts +258 -0
  71. package/dist/combat/encounterSequence.js +426 -0
  72. package/dist/combat/hitReaction.d.ts +57 -1
  73. package/dist/combat/hitReaction.js +45 -5
  74. package/dist/combat/magazine.d.ts +54 -0
  75. package/dist/combat/magazine.js +96 -0
  76. package/dist/combat/projectiles.d.ts +5 -0
  77. package/dist/combat/projectiles.js +32 -14
  78. package/dist/combat/receivedDamage.d.ts +117 -0
  79. package/dist/combat/receivedDamage.js +92 -0
  80. package/dist/combat/regenShield.d.ts +5 -1
  81. package/dist/combat/regenShield.js +5 -1
  82. package/dist/combat/renderCues.d.ts +51 -0
  83. package/dist/combat/renderCues.js +44 -0
  84. package/dist/combat/resourcePool.d.ts +5 -0
  85. package/dist/combat/resourcePool.js +5 -0
  86. package/dist/combat/rewardAllocation.d.ts +121 -0
  87. package/dist/combat/rewardAllocation.js +251 -0
  88. package/dist/combat/shotOrigin.d.ts +18 -1
  89. package/dist/combat/shotOrigin.js +39 -0
  90. package/dist/combat/statusApplication.d.ts +96 -0
  91. package/dist/combat/statusApplication.js +81 -0
  92. package/dist/combat/telegraph.d.ts +11 -2
  93. package/dist/combat/telegraph.js +11 -2
  94. package/dist/combat/thresholdCrossings.d.ts +85 -0
  95. package/dist/combat/thresholdCrossings.js +116 -0
  96. package/dist/combat.d.ts +34 -0
  97. package/dist/combat.js +34 -0
  98. package/dist/commands/commandRegistry.d.ts +11 -0
  99. package/dist/commands/commandRegistry.js +9 -2
  100. package/dist/crafting/crop.d.ts +18 -0
  101. package/dist/crafting/crop.js +18 -0
  102. package/dist/crafting/production.d.ts +5 -0
  103. package/dist/crafting/production.js +5 -0
  104. package/dist/devtools/rewriteTunables.d.ts +17 -0
  105. package/dist/devtools/rewriteTunables.js +276 -0
  106. package/dist/devtools/saveEndpoint.d.ts +46 -0
  107. package/dist/devtools/saveEndpoint.js +48 -0
  108. package/dist/devtools/transformTunables.d.ts +3 -0
  109. package/dist/devtools/transformTunables.js +3 -0
  110. package/dist/devtools/tunableSchema.d.ts +31 -0
  111. package/dist/devtools/tunableSchema.js +31 -0
  112. package/dist/economy/currency.d.ts +12 -1
  113. package/dist/economy/currency.js +12 -1
  114. package/dist/economy/listingBook.d.ts +91 -0
  115. package/dist/economy/listingBook.js +144 -0
  116. package/dist/economy/resourceLedger.d.ts +222 -0
  117. package/dist/economy/resourceLedger.js +353 -0
  118. package/dist/economy/sharedWallet.d.ts +14 -0
  119. package/dist/economy/sharedWallet.js +14 -0
  120. package/dist/economy/techTree.d.ts +12 -0
  121. package/dist/economy/techTree.js +12 -0
  122. package/dist/economy/wallet.d.ts +26 -2
  123. package/dist/economy/wallet.js +35 -6
  124. package/dist/editor/commands.d.ts +190 -7
  125. package/dist/editor/commands.js +727 -55
  126. package/dist/editor/document.d.ts +159 -13
  127. package/dist/editor/document.js +750 -19
  128. package/dist/editor/grid.d.ts +229 -0
  129. package/dist/editor/grid.js +366 -0
  130. package/dist/editor/gridAdapters.d.ts +80 -0
  131. package/dist/editor/gridAdapters.js +134 -0
  132. package/dist/editor/index.d.ts +73 -6
  133. package/dist/editor/index.js +6 -2
  134. package/dist/editor/liveSync.d.ts +127 -0
  135. package/dist/editor/liveSync.js +249 -0
  136. package/dist/editor/runtimeInspector.d.ts +88 -0
  137. package/dist/editor/runtimeInspector.js +239 -0
  138. package/dist/editor/types.d.ts +107 -1
  139. package/dist/faction/reputation.d.ts +5 -0
  140. package/dist/faction/reputation.js +5 -0
  141. package/dist/format/distance.d.ts +17 -0
  142. package/dist/format/distance.js +18 -0
  143. package/dist/format/duration.d.ts +27 -0
  144. package/dist/format/duration.js +45 -0
  145. package/dist/format/speed.d.ts +17 -0
  146. package/dist/format/speed.js +25 -0
  147. package/dist/game/connectedPlayers.d.ts +6 -4
  148. package/dist/game/connectedPlayers.js +2 -2
  149. package/dist/game/cosmetics.d.ts +9 -0
  150. package/dist/game/cosmetics.js +16 -0
  151. package/dist/game/defineGame.d.ts +100 -2
  152. package/dist/game/defineGame.js +39 -2
  153. package/dist/game/defineSystem.d.ts +88 -0
  154. package/dist/game/defineSystem.js +45 -0
  155. package/dist/game/dialogue.d.ts +33 -0
  156. package/dist/game/dialogue.js +21 -0
  157. package/dist/game/events.d.ts +35 -13
  158. package/dist/game/events.js +5 -0
  159. package/dist/game/feed.d.ts +33 -0
  160. package/dist/game/feed.js +35 -2
  161. package/dist/game/gamePhase.d.ts +11 -0
  162. package/dist/game/gamePhase.js +16 -0
  163. package/dist/game/leaderboard.d.ts +5 -0
  164. package/dist/game/leaderboard.js +5 -0
  165. package/dist/game/loadout.d.ts +5 -0
  166. package/dist/game/loadout.js +5 -0
  167. package/dist/game/lootFilter.d.ts +2 -0
  168. package/dist/game/lootFilter.js +2 -0
  169. package/dist/game/lootPipeline.d.ts +164 -0
  170. package/dist/game/lootPipeline.js +216 -0
  171. package/dist/game/lootTable.d.ts +19 -2
  172. package/dist/game/lootTable.js +15 -5
  173. package/dist/game/objectives.d.ts +43 -0
  174. package/dist/game/objectives.js +36 -0
  175. package/dist/game/paramLayers.d.ts +148 -0
  176. package/dist/game/paramLayers.js +185 -0
  177. package/dist/game/ping.d.ts +5 -0
  178. package/dist/game/ping.js +5 -0
  179. package/dist/game/playableGame.d.ts +92 -7
  180. package/dist/game/quest.d.ts +8 -0
  181. package/dist/game/quest.js +29 -0
  182. package/dist/game/race.d.ts +141 -0
  183. package/dist/game/race.js +169 -0
  184. package/dist/game/recordBook.d.ts +3 -1
  185. package/dist/game/recordBook.js +4 -1
  186. package/dist/game/ruleSelection.d.ts +75 -0
  187. package/dist/game/ruleSelection.js +127 -0
  188. package/dist/game/runDraft.d.ts +5 -0
  189. package/dist/game/runDraft.js +5 -0
  190. package/dist/game/saveStore.d.ts +111 -0
  191. package/dist/game/saveStore.js +312 -0
  192. package/dist/game/snapshotHistory.d.ts +67 -0
  193. package/dist/game/snapshotHistory.js +95 -0
  194. package/dist/game/social.d.ts +38 -1
  195. package/dist/game/social.js +71 -0
  196. package/dist/game/spawnPoints.d.ts +5 -0
  197. package/dist/game/spawnPoints.js +5 -0
  198. package/dist/game/systemRuntime.d.ts +50 -0
  199. package/dist/game/systemRuntime.js +157 -0
  200. package/dist/game/systemSchedule.d.ts +72 -0
  201. package/dist/game/systemSchedule.js +242 -0
  202. package/dist/game/toasts.d.ts +43 -0
  203. package/dist/game/toasts.js +44 -0
  204. package/dist/game/trade.d.ts +10 -0
  205. package/dist/game/trade.js +10 -0
  206. package/dist/game/unlocks.d.ts +8 -0
  207. package/dist/game/unlocks.js +16 -0
  208. package/dist/game/vfxInstance.d.ts +138 -0
  209. package/dist/game/vfxInstance.js +96 -0
  210. package/dist/game/worldItem.d.ts +17 -4
  211. package/dist/game/worldItem.js +17 -4
  212. package/dist/gameplay.d.ts +91 -0
  213. package/dist/gameplay.js +91 -0
  214. package/dist/index.d.ts +5 -14
  215. package/dist/index.js +5 -14
  216. package/dist/input/actionBindings.d.ts +23 -6
  217. package/dist/input/actionBindings.js +23 -6
  218. package/dist/input/axisInput.d.ts +7 -2
  219. package/dist/input/axisInput.js +7 -2
  220. package/dist/input/controlGroups.d.ts +67 -0
  221. package/dist/input/controlGroups.js +41 -0
  222. package/dist/input/touchScheme.d.ts +82 -6
  223. package/dist/input/touchScheme.js +123 -10
  224. package/dist/interaction/lockpick.d.ts +61 -0
  225. package/dist/interaction/lockpick.js +168 -0
  226. package/dist/interaction/proximityPrompt.d.ts +2 -0
  227. package/dist/interaction/proximityPrompt.js +2 -0
  228. package/dist/interaction/qte.d.ts +5 -0
  229. package/dist/interaction/qte.js +5 -0
  230. package/dist/interaction/skillCheck.d.ts +5 -0
  231. package/dist/interaction/skillCheck.js +5 -0
  232. package/dist/inventory/inventoryModel.d.ts +12 -0
  233. package/dist/inventory/inventoryModel.js +12 -0
  234. package/dist/inventory/shapedGrid.d.ts +16 -0
  235. package/dist/inventory/shapedGrid.js +16 -0
  236. package/dist/inventory/slotModel.d.ts +10 -0
  237. package/dist/inventory/slotModel.js +10 -0
  238. package/dist/item/durability.d.ts +5 -0
  239. package/dist/item/durability.js +5 -0
  240. package/dist/item/itemIdentity.d.ts +171 -0
  241. package/dist/item/itemIdentity.js +138 -0
  242. package/dist/item/itemInstanceRegistry.d.ts +32 -0
  243. package/dist/item/itemInstanceRegistry.js +34 -0
  244. package/dist/item/itemgen.d.ts +163 -0
  245. package/dist/item/itemgen.js +151 -0
  246. package/dist/item/modularItem.d.ts +5 -0
  247. package/dist/item/modularItem.js +5 -0
  248. package/dist/item/use.d.ts +5 -0
  249. package/dist/item/use.js +5 -0
  250. package/dist/item/useBehavior.d.ts +142 -0
  251. package/dist/item/useBehavior.js +105 -0
  252. package/dist/item/weapon.d.ts +5 -0
  253. package/dist/item/weapon.js +5 -0
  254. package/dist/math/scalar.d.ts +25 -0
  255. package/dist/math/scalar.js +47 -0
  256. package/dist/meta/changelog.d.ts +4 -1
  257. package/dist/meta/changelog.js +16 -2
  258. package/dist/movement/avoidance.d.ts +45 -0
  259. package/dist/movement/avoidance.js +123 -0
  260. package/dist/movement/cameraRig.d.ts +8 -0
  261. package/dist/movement/cameraRig.js +8 -0
  262. package/dist/movement/dash.d.ts +11 -0
  263. package/dist/movement/dash.js +11 -0
  264. package/dist/movement/formation.d.ts +135 -0
  265. package/dist/movement/formation.js +194 -0
  266. package/dist/movement/glideModel.d.ts +5 -0
  267. package/dist/movement/glideModel.js +5 -0
  268. package/dist/movement/grappleSwing.d.ts +5 -0
  269. package/dist/movement/grappleSwing.js +5 -0
  270. package/dist/movement/leaderTrail.d.ts +5 -0
  271. package/dist/movement/leaderTrail.js +5 -0
  272. package/dist/movement/movementModel.d.ts +35 -8
  273. package/dist/movement/movementModel.js +42 -14
  274. package/dist/movement/playerMovement.js +65 -10
  275. package/dist/movement/poseState.d.ts +13 -0
  276. package/dist/movement/poseState.js +16 -0
  277. package/dist/movement/steering.d.ts +8 -0
  278. package/dist/movement/steering.js +18 -0
  279. package/dist/multiplayer/combatSnapshot.d.ts +3 -0
  280. package/dist/multiplayer/combatSnapshot.js +3 -0
  281. package/dist/multiplayer/lagCompensation.d.ts +5 -0
  282. package/dist/multiplayer/lagCompensation.js +5 -0
  283. package/dist/multiplayer/presenceModel.d.ts +9 -1
  284. package/dist/multiplayer/presenceModel.js +9 -1
  285. package/dist/multiplayer/simultaneousCommit.d.ts +3 -0
  286. package/dist/multiplayer/simultaneousCommit.js +3 -0
  287. package/dist/multiplayer.d.ts +11 -0
  288. package/dist/multiplayer.js +11 -0
  289. package/dist/nav/pathFollow.d.ts +57 -0
  290. package/dist/nav/pathFollow.js +109 -0
  291. package/dist/orders/orderKinds.d.ts +156 -0
  292. package/dist/orders/orderKinds.js +197 -0
  293. package/dist/orders/orderQueue.d.ts +208 -0
  294. package/dist/orders/orderQueue.js +211 -0
  295. package/dist/physics/drivableVehicle.d.ts +29 -0
  296. package/dist/physics/drivableVehicle.js +16 -0
  297. package/dist/physics/kinematicVehicle.d.ts +21 -1
  298. package/dist/physics/kinematicVehicle.js +23 -8
  299. package/dist/physics/physicsWorld.d.ts +24 -12
  300. package/dist/physics/physicsWorld.js +11 -5
  301. package/dist/physics/radialImpulse.d.ts +25 -0
  302. package/dist/physics/radialImpulse.js +27 -0
  303. package/dist/procedural.d.ts +3 -0
  304. package/dist/procedural.js +3 -0
  305. package/dist/progression/statGraph.d.ts +116 -0
  306. package/dist/progression/statGraph.js +318 -0
  307. package/dist/puzzle/cellGrid.d.ts +9 -0
  308. package/dist/puzzle/cellGrid.js +9 -0
  309. package/dist/puzzle/fallingPiece.d.ts +9 -0
  310. package/dist/puzzle/fallingPiece.js +9 -0
  311. package/dist/puzzle/nonogram.d.ts +39 -0
  312. package/dist/puzzle/nonogram.js +136 -0
  313. package/dist/random/nameGen.d.ts +5 -0
  314. package/dist/random/nameGen.js +5 -0
  315. package/dist/random/pick.d.ts +8 -0
  316. package/dist/random/pick.js +31 -0
  317. package/dist/random/rng.d.ts +22 -0
  318. package/dist/random/rng.js +28 -8
  319. package/dist/random/seedLink.d.ts +4 -0
  320. package/dist/random/seedLink.js +4 -0
  321. package/dist/relation/keyedValues.d.ts +54 -0
  322. package/dist/relation/keyedValues.js +115 -0
  323. package/dist/relation/thresholds.d.ts +62 -0
  324. package/dist/relation/thresholds.js +62 -0
  325. package/dist/render/color.d.ts +12 -0
  326. package/dist/render/color.js +26 -0
  327. package/dist/render/lookPreset.d.ts +41 -0
  328. package/dist/render/lookPreset.js +29 -0
  329. package/dist/render/postProcessing.d.ts +20 -0
  330. package/dist/render/postProcessing.js +21 -1
  331. package/dist/rules/predicate.d.ts +53 -0
  332. package/dist/rules/predicate.js +64 -0
  333. package/dist/rules/ruleEffects.d.ts +38 -0
  334. package/dist/rules/ruleEffects.js +37 -0
  335. package/dist/rules/triggeredRules.d.ts +160 -0
  336. package/dist/rules/triggeredRules.js +241 -0
  337. package/dist/runtime/adapter.d.ts +42 -3
  338. package/dist/runtime/adapter.js +44 -1
  339. package/dist/runtime/cameraDirector.d.ts +1 -0
  340. package/dist/runtime/cameraDirector.js +1 -0
  341. package/dist/runtime/commandRunner.d.ts +1 -0
  342. package/dist/runtime/commandRunner.js +1 -0
  343. package/dist/runtime/context/combatFx.d.ts +23 -0
  344. package/dist/runtime/context/combatFx.js +161 -0
  345. package/dist/runtime/context/registries.d.ts +13 -0
  346. package/dist/runtime/context/registries.js +84 -0
  347. package/dist/runtime/context/worldItems.d.ts +21 -0
  348. package/dist/runtime/context/worldItems.js +37 -0
  349. package/dist/runtime/descriptors/baseline.d.ts +48 -0
  350. package/dist/runtime/descriptors/baseline.js +134 -0
  351. package/dist/runtime/descriptors/features.d.ts +74 -0
  352. package/dist/runtime/descriptors/features.js +281 -0
  353. package/dist/runtime/gameContext.d.ts +114 -13
  354. package/dist/runtime/gameContext.js +303 -395
  355. package/dist/runtime/gameRuntime.d.ts +1 -0
  356. package/dist/runtime/gameRuntime.js +1 -0
  357. package/dist/runtime/headlessRunner.d.ts +60 -0
  358. package/dist/runtime/headlessRunner.js +44 -0
  359. package/dist/runtime/hostPersistence.d.ts +12 -0
  360. package/dist/runtime/hostPersistence.js +12 -0
  361. package/dist/runtime/hostedGameRunner.d.ts +8 -3
  362. package/dist/runtime/hostedGameRunner.js +26 -3
  363. package/dist/runtime/hostedWorldSession.d.ts +12 -4
  364. package/dist/runtime/hostedWorldSession.js +11 -4
  365. package/dist/runtime/inputSnapshot.d.ts +8 -3
  366. package/dist/runtime/inputSnapshot.js +6 -2
  367. package/dist/runtime/motionIntents.d.ts +11 -2
  368. package/dist/runtime/motionIntents.js +16 -2
  369. package/dist/runtime/perContext.d.ts +15 -0
  370. package/dist/runtime/perContext.js +21 -0
  371. package/dist/runtime/runtimeSave.d.ts +79 -0
  372. package/dist/runtime/runtimeSave.js +105 -0
  373. package/dist/runtime/save.d.ts +4 -0
  374. package/dist/runtime/save.js +4 -0
  375. package/dist/runtime/snapshot.d.ts +7 -0
  376. package/dist/runtime/snapshot.js +7 -0
  377. package/dist/runtime/visibility.d.ts +2 -1
  378. package/dist/runtime/visibility.js +2 -1
  379. package/dist/runtime/worldChannel.d.ts +7 -3
  380. package/dist/runtime/worldChannel.js +51 -6
  381. package/dist/runtime/worldMirror.d.ts +14 -2
  382. package/dist/runtime/worldMirror.js +15 -2
  383. package/dist/runtime/worldProjection.d.ts +47 -0
  384. package/dist/runtime/worldProjection.js +52 -0
  385. package/dist/runtime/worldReplication.d.ts +30 -7
  386. package/dist/runtime/worldReplication.js +41 -9
  387. package/dist/runtime/worldSnapshot.d.ts +30 -3
  388. package/dist/runtime/worldSnapshot.js +20 -5
  389. package/dist/scene/assetCatalog.d.ts +21 -0
  390. package/dist/scene/assetCatalog.js +4 -0
  391. package/dist/scene/assetDiagnostics.d.ts +69 -0
  392. package/dist/scene/assetDiagnostics.js +110 -0
  393. package/dist/scene/assetGenerator.d.ts +65 -0
  394. package/dist/scene/assetGenerator.js +64 -0
  395. package/dist/scene/assetSpace.d.ts +137 -0
  396. package/dist/scene/assetSpace.js +259 -0
  397. package/dist/scene/authoredTriggers.d.ts +169 -0
  398. package/dist/scene/authoredTriggers.js +340 -0
  399. package/dist/scene/behaviorRuntime.d.ts +75 -0
  400. package/dist/scene/behaviorRuntime.js +217 -0
  401. package/dist/scene/behaviors.d.ts +14 -2
  402. package/dist/scene/behaviors.js +7 -2
  403. package/dist/scene/bodyBind.d.ts +60 -0
  404. package/dist/scene/bodyBind.js +51 -0
  405. package/dist/scene/builtinSceneKinds.d.ts +5 -0
  406. package/dist/scene/builtinSceneKinds.js +62 -0
  407. package/dist/scene/colliders.d.ts +13 -1
  408. package/dist/scene/colliders.js +37 -1
  409. package/dist/scene/entityStats.d.ts +11 -2
  410. package/dist/scene/entityStats.js +11 -2
  411. package/dist/scene/entityStore.d.ts +12 -1
  412. package/dist/scene/entityStore.js +15 -0
  413. package/dist/scene/facing.d.ts +18 -0
  414. package/dist/scene/facing.js +26 -0
  415. package/dist/scene/modelSockets.d.ts +33 -0
  416. package/dist/scene/modelSockets.js +29 -0
  417. package/dist/scene/objectQuery.d.ts +2 -0
  418. package/dist/scene/objectQuery.js +2 -0
  419. package/dist/scene/objectStore.d.ts +4 -0
  420. package/dist/scene/objectStore.js +6 -0
  421. package/dist/scene/possession.d.ts +8 -0
  422. package/dist/scene/possession.js +14 -0
  423. package/dist/scene/roster.d.ts +3 -0
  424. package/dist/scene/roster.js +12 -0
  425. package/dist/scene/sceneKinds.d.ts +240 -0
  426. package/dist/scene/sceneKinds.js +214 -0
  427. package/dist/scene/sceneOwnership.d.ts +169 -0
  428. package/dist/scene/sceneOwnership.js +179 -0
  429. package/dist/scene/selectionBookmarks.d.ts +93 -0
  430. package/dist/scene/selectionBookmarks.js +122 -0
  431. package/dist/scene/vehicleSeat.d.ts +68 -0
  432. package/dist/scene/vehicleSeat.js +59 -0
  433. package/dist/sensor/concealment.d.ts +3 -0
  434. package/dist/sensor/concealment.js +3 -0
  435. package/dist/sensor/freezeMonitor.d.ts +1 -0
  436. package/dist/sensor/freezeMonitor.js +1 -0
  437. package/dist/sensor/frustumSensor.d.ts +7 -3
  438. package/dist/sensor/frustumSensor.js +7 -3
  439. package/dist/sensor/hiddenStateProbe.d.ts +5 -2
  440. package/dist/sensor/hiddenStateProbe.js +5 -2
  441. package/dist/sensor/recordingBuffer.d.ts +2 -1
  442. package/dist/sensor/recordingBuffer.js +2 -1
  443. package/dist/sensor/replayLoop.d.ts +6 -2
  444. package/dist/sensor/replayLoop.js +6 -2
  445. package/dist/sensor/revealQuery.d.ts +2 -1
  446. package/dist/sensor/revealQuery.js +2 -1
  447. package/dist/sensor/visionCone.d.ts +10 -3
  448. package/dist/sensor/visionCone.js +10 -3
  449. package/dist/session/contestedChannel.d.ts +1 -0
  450. package/dist/session/contestedChannel.js +1 -0
  451. package/dist/session/extraction.d.ts +1 -0
  452. package/dist/session/extraction.js +1 -0
  453. package/dist/session/roles.d.ts +6 -0
  454. package/dist/session/roles.js +6 -0
  455. package/dist/session/roundState.d.ts +8 -0
  456. package/dist/session/roundState.js +2 -0
  457. package/dist/settings/settingsModel.d.ts +1 -0
  458. package/dist/settings/settingsModel.js +1 -0
  459. package/dist/stats/accumulatorMeter.d.ts +6 -0
  460. package/dist/stats/accumulatorMeter.js +6 -0
  461. package/dist/stats/eventMeter.d.ts +5 -0
  462. package/dist/stats/eventMeter.js +5 -0
  463. package/dist/stats/rollCheck.d.ts +5 -0
  464. package/dist/stats/rollCheck.js +5 -0
  465. package/dist/stats/statModifiers.d.ts +5 -0
  466. package/dist/stats/statModifiers.js +5 -0
  467. package/dist/store/defineKeyedStore.d.ts +38 -0
  468. package/dist/store/defineKeyedStore.js +42 -0
  469. package/dist/store/defineStore.d.ts +33 -0
  470. package/dist/store/defineStore.js +35 -0
  471. package/dist/store/observableKeyedStore.d.ts +5 -0
  472. package/dist/store/observableKeyedStore.js +34 -2
  473. package/dist/survival/decayMeter.d.ts +55 -0
  474. package/dist/survival/decayMeter.js +130 -55
  475. package/dist/survival/moodle.d.ts +2 -0
  476. package/dist/survival/regionHealth.d.ts +6 -0
  477. package/dist/survival/regionHealth.js +5 -0
  478. package/dist/tactics/fallingGrid.d.ts +4 -2
  479. package/dist/tactics/fallingGrid.js +4 -2
  480. package/dist/tactics/predictiveQuery.d.ts +3 -0
  481. package/dist/tactics/predictiveQuery.js +3 -0
  482. package/dist/tactics/snapshot.d.ts +2 -0
  483. package/dist/tactics/snapshot.js +2 -0
  484. package/dist/tactics/surface.d.ts +1 -0
  485. package/dist/tactics/surface.js +1 -0
  486. package/dist/tactics/tacticalGrid.d.ts +1 -0
  487. package/dist/tactics/tacticalGrid.js +1 -0
  488. package/dist/time/beatClock.d.ts +14 -4
  489. package/dist/time/beatClock.js +14 -4
  490. package/dist/time/calendarClock.d.ts +3 -0
  491. package/dist/time/calendarClock.js +3 -0
  492. package/dist/time/idleProgress.d.ts +4 -0
  493. package/dist/time/idleProgress.js +4 -0
  494. package/dist/time/simClock.d.ts +2 -0
  495. package/dist/time/simClock.js +20 -5
  496. package/dist/ui/actionModel.d.ts +110 -0
  497. package/dist/ui/actionModel.js +159 -0
  498. package/dist/ui/gameLayout.d.ts +30 -11
  499. package/dist/ui/gameLayout.js +30 -11
  500. package/dist/ui/hudDocument.d.ts +114 -0
  501. package/dist/ui/hudDocument.js +220 -0
  502. package/dist/ui/hudLayout.d.ts +33 -1
  503. package/dist/ui/hudLayout.js +204 -17
  504. package/dist/ui/selectionModel.d.ts +92 -0
  505. package/dist/ui/selectionModel.js +88 -0
  506. package/dist/ui/tooltipModel.d.ts +63 -0
  507. package/dist/ui/tooltipModel.js +82 -0
  508. package/dist/ui.d.ts +15 -0
  509. package/dist/ui.js +15 -0
  510. package/dist/visibility/bounds.d.ts +8 -1
  511. package/dist/visibility/bounds.js +8 -1
  512. package/dist/visibility/frustum.d.ts +12 -3
  513. package/dist/visibility/frustum.js +12 -3
  514. package/dist/work/jobQueue.d.ts +201 -0
  515. package/dist/work/jobQueue.js +253 -0
  516. package/dist/work/unitTraining.d.ts +58 -0
  517. package/dist/work/unitTraining.js +52 -0
  518. package/dist/world/authoredObjects.d.ts +58 -0
  519. package/dist/world/authoredObjects.js +69 -0
  520. package/dist/world/buildingGenerator.d.ts +18 -0
  521. package/dist/world/buildingGenerator.js +62 -0
  522. package/dist/world/buildings.d.ts +5 -0
  523. package/dist/world/buildings.js +5 -0
  524. package/dist/world/catenary.d.ts +22 -0
  525. package/dist/world/catenary.js +69 -0
  526. package/dist/world/features.d.ts +115 -7
  527. package/dist/world/features.js +56 -5
  528. package/dist/world/footprintGrid.d.ts +59 -0
  529. package/dist/world/footprintGrid.js +141 -0
  530. package/dist/world/geometry.d.ts +64 -0
  531. package/dist/world/geometry.js +94 -0
  532. package/dist/world/grassKind.d.ts +51 -0
  533. package/dist/world/grassKind.js +101 -0
  534. package/dist/world/pathInstances.d.ts +27 -0
  535. package/dist/world/pathInstances.js +27 -0
  536. package/dist/world/pathTerrain.d.ts +80 -0
  537. package/dist/world/pathTerrain.js +142 -0
  538. package/dist/world/placeAsset.d.ts +81 -0
  539. package/dist/world/placeAsset.js +77 -0
  540. package/dist/world/placement.d.ts +4 -0
  541. package/dist/world/placement.js +4 -0
  542. package/dist/world/placementController.d.ts +6 -0
  543. package/dist/world/placementController.js +6 -0
  544. package/dist/world/polyline.d.ts +34 -0
  545. package/dist/world/polyline.js +81 -0
  546. package/dist/world/roads.d.ts +8 -0
  547. package/dist/world/roads.js +38 -0
  548. package/dist/world/scatterRegion.d.ts +164 -0
  549. package/dist/world/scatterRegion.js +409 -0
  550. package/dist/world/sceneShapes.d.ts +43 -0
  551. package/dist/world/sceneShapes.js +1 -0
  552. package/dist/world/segment.d.ts +27 -0
  553. package/dist/world/segment.js +43 -0
  554. package/dist/world/soilKind.d.ts +48 -0
  555. package/dist/world/soilKind.js +92 -0
  556. package/dist/world/spatialSample.d.ts +241 -0
  557. package/dist/world/spatialSample.js +465 -0
  558. package/dist/world/terraform.d.ts +213 -1
  559. package/dist/world/terraform.js +655 -20
  560. package/dist/world/terrain.d.ts +119 -20
  561. package/dist/world/terrain.js +247 -41
  562. package/dist/world/terrainGuides.d.ts +182 -0
  563. package/dist/world/terrainGuides.js +343 -0
  564. package/dist/world/vec2.d.ts +81 -0
  565. package/dist/world/vec2.js +128 -0
  566. package/dist/world/vec3.d.ts +49 -0
  567. package/dist/world/vec3.js +76 -0
  568. package/dist/world/vegetation.d.ts +71 -0
  569. package/dist/world/vegetation.js +151 -0
  570. package/dist/world/visibilityField.d.ts +154 -0
  571. package/dist/world/visibilityField.js +271 -0
  572. package/dist/world/volumetricClouds.d.ts +52 -0
  573. package/dist/world/volumetricClouds.js +43 -0
  574. package/dist/world/walls.d.ts +9 -0
  575. package/dist/world/walls.js +9 -0
  576. package/dist/world/waterKind.d.ts +55 -0
  577. package/dist/world/waterKind.js +99 -0
  578. package/dist/world.d.ts +132 -0
  579. package/dist/world.js +132 -0
  580. package/package.json +32 -8
  581. package/skills/jgengine/SKILL.md +51 -0
  582. package/skills/jgengine/api.md +434 -0
  583. package/skills/jgengine/capabilities.md +29 -0
  584. package/skills/jgengine/reference-cartridge.md +72 -0
  585. package/skills/jgengine-combat/SKILL.md +34 -0
  586. package/skills/jgengine-combat/api.md +549 -0
  587. package/skills/jgengine-combat/capabilities.md +169 -0
  588. package/skills/jgengine-combat/reference.md +98 -0
  589. package/skills/jgengine-gameplay/SKILL.md +39 -0
  590. package/skills/jgengine-gameplay/api.md +1794 -0
  591. package/skills/jgengine-gameplay/capabilities.md +378 -0
  592. package/skills/jgengine-gameplay/reference-systems.md +60 -0
  593. package/skills/jgengine-world/SKILL.md +38 -0
  594. package/skills/jgengine-world/api.md +2652 -0
  595. package/skills/jgengine-world/capabilities.md +370 -0
  596. package/skills/jgengine-world/reference.md +222 -0
  597. package/dist/cartridge/runtime.d.ts +0 -15
  598. package/dist/cartridge/runtime.js +0 -556
  599. package/dist/cartridge/spec.d.ts +0 -188
  600. package/dist/cartridge/spec.js +0 -19
  601. package/dist/cartridge/validate.d.ts +0 -2
  602. package/dist/cartridge/validate.js +0 -78
  603. package/dist/store/engineStore.d.ts +0 -22
  604. package/dist/store/engineStore.js +0 -50
  605. package/dist/store/features.d.ts +0 -10
  606. package/dist/store/features.js +0 -23
  607. package/llms.txt +0 -5389
@@ -43,4 +43,5 @@ export type GameRuntime = {
43
43
  joinPlayer: (snapshot: GameRuntimeSnapshot, userId: string, isNew: boolean) => GameRuntimeSnapshot;
44
44
  toProfileRow: (snapshot: GameRuntimeSnapshot, userId: string) => RuntimeProfileRow | null;
45
45
  };
46
+ /** @internal */
46
47
  export declare function createGameRuntime(definition: GameRuntimeDefinition): GameRuntime;
@@ -1,5 +1,6 @@
1
1
  import { runCommand } from "./commandRunner.js";
2
2
  import { createEmptyPlayerRow, createRuntimeSnapshot, } from "./snapshot.js";
3
+ /** @internal */
3
4
  export function createGameRuntime(definition) {
4
5
  const loop = definition.loop;
5
6
  let initialized = false;
@@ -0,0 +1,60 @@
1
+ import type { GameDefinition, GameLoop } from "../game/defineGame.js";
2
+ import type { PointerAxisState } from "../input/pointerAxis.js";
3
+ import type { ModelAssetRef } from "../scene/assetCatalog.js";
4
+ import { type GameContext, type GameContextContent } from "./gameContext.js";
5
+ import type { InputSnapshot } from "./inputSnapshot.js";
6
+ /** One step's worth of player intent handed to {@link HeadlessRunner.step} — the held-action set and pointer state the shell would otherwise publish from the browser each frame. */
7
+ export interface HeadlessInput {
8
+ /** Replaces the held-action set for this step; edge detection (`justPressed`/`justReleased`) rolls the previous set forward. Omit to keep the last published set. */
9
+ held?: readonly string[];
10
+ /** Replaces the normalized pointer state; omit to leave the last pointer unchanged (pass `null` to clear it). */
11
+ pointer?: PointerAxisState | null;
12
+ }
13
+ export interface HeadlessRunnerOptions<TAssetRef extends ModelAssetRef, TMultiplayer> {
14
+ definition: GameDefinition<TAssetRef, TMultiplayer>;
15
+ /** Catalog resolvers (`entityById`/`objectById`) the context uses; defaults to an empty catalog. */
16
+ content?: GameContextContent;
17
+ /** Lifecycle hooks — `onInit`/`onNewPlayer` fire at construction, `onTick` on every {@link HeadlessRunner.step}. The shell keeps this separate from `definition` (presentation wraps it); a headless caller passes it directly. */
18
+ loop?: GameLoop<GameContext>;
19
+ /** The single local player; defaults to `{ userId: "player", isNew: true }`. */
20
+ player?: {
21
+ userId: string;
22
+ isNew: boolean;
23
+ };
24
+ /** Wall-clock source for the sim clock — inject a deterministic counter for reproducible runs. */
25
+ now?: () => number;
26
+ /** Per-step real-dt clamp in seconds, matching the shell's frame cap so one long stall can't fast-forward the sim. Default `0.05`. */
27
+ maxStepSeconds?: number;
28
+ /**
29
+ * Drive the built-in keyboard player-movement controller from the held-action set each step, exactly as the shell's
30
+ * FrameDriver does for pose-driven games. Off by default — cartridge/tick-driven games move their own entities inside
31
+ * `onTick` and don't need it.
32
+ */
33
+ playerMovement?: boolean;
34
+ /** Yaw heading (radians) fed to the movement controller when `playerMovement` is on; the shell supplies its camera yaw. */
35
+ heading?: number;
36
+ }
37
+ /**
38
+ * A renderer-free driver for a game loop: builds a {@link GameContext} from a {@link GameDefinition}, runs the init
39
+ * hooks, then advances the simulation one step at a time from injected input. No React, R3F, or three.js — the whole
40
+ * play path (time, input, `onTick`, behaviour nav, optional player movement) runs from `core` primitives alone, so a
41
+ * non-React host (a server tick, a test, a CLI replay) can play a real game and read its world snapshot. The shell's
42
+ * FrameDriver is one such driver bolted to `useFrame`; this is the same step distilled out of the render tree.
43
+ *
44
+ * @capability headless-runner play a real game loop with no renderer — tick, feed input, read the world snapshot
45
+ */
46
+ export interface HeadlessRunner {
47
+ /** The live game context — read `ctx.scene.entity.list()`, `ctx.game.store`, `ctx.subscribe`/`ctx.version()` for the world snapshot. */
48
+ readonly ctx: GameContext;
49
+ /** The per-frame input the loop reads; the same object exposed as `ctx.input`. */
50
+ readonly input: InputSnapshot;
51
+ readonly userId: string;
52
+ /**
53
+ * Advance the simulation one step. Publishes `input` (if given), advances the sim clock by the clamped real dt,
54
+ * runs optional player movement, then `loop.onTick` and behaviour nav. Returns the scaled game dt `onTick` saw.
55
+ */
56
+ step(dtSeconds: number, input?: HeadlessInput): number;
57
+ /** Publish input without advancing — for pre-seeding the held set before the first {@link step}. */
58
+ publishInput(input: HeadlessInput): void;
59
+ }
60
+ export declare function createHeadlessRunner<TAssetRef extends ModelAssetRef, TMultiplayer>(options: HeadlessRunnerOptions<TAssetRef, TMultiplayer>): HeadlessRunner;
@@ -0,0 +1,44 @@
1
+ import { resolvePlayerMovementTuning, stepPlayerMovement, } from "../movement/playerMovement.js";
2
+ import { advanceBehaviors } from "../scene/behaviorRuntime.js";
3
+ import { createGameContext } from "./gameContext.js";
4
+ export function createHeadlessRunner(options) {
5
+ const { definition, loop } = options;
6
+ const content = options.content ?? {};
7
+ const player = options.player ?? { userId: "player", isNew: true };
8
+ const maxStep = options.maxStepSeconds ?? 0.05;
9
+ const ctx = createGameContext({
10
+ definition,
11
+ content,
12
+ player,
13
+ ...(options.now === undefined ? {} : { now: options.now }),
14
+ });
15
+ loop?.onInit?.(ctx);
16
+ loop?.onNewPlayer?.(ctx);
17
+ const tuning = options.playerMovement === true
18
+ ? resolvePlayerMovementTuning({ physics: definition.physics, world: definition.world })
19
+ : null;
20
+ function publishInput(input) {
21
+ if (input.held !== undefined)
22
+ ctx.input.publish(input.held);
23
+ if (input.pointer !== undefined)
24
+ ctx.input.publishPointer(input.pointer);
25
+ }
26
+ return {
27
+ ctx,
28
+ input: ctx.input,
29
+ userId: player.userId,
30
+ publishInput,
31
+ step(dtSeconds, input) {
32
+ if (input !== undefined)
33
+ publishInput(input);
34
+ const dt = Math.min(dtSeconds, maxStep);
35
+ const gameDt = ctx.time.advance(dt);
36
+ if (tuning !== null) {
37
+ stepPlayerMovement(ctx, player.userId, { held: ctx.input.held(), pointer: ctx.input.pointer() }, dt, tuning, options.heading);
38
+ }
39
+ loop?.onTick?.(ctx, gameDt);
40
+ advanceBehaviors(ctx, gameDt);
41
+ return gameDt;
42
+ },
43
+ };
44
+ }
@@ -58,11 +58,13 @@ export type LeaderboardEntry = {
58
58
  value: number;
59
59
  };
60
60
  export declare const LEADERBOARD_PENDING_KEY = "leaderboardPending";
61
+ /** @internal */
61
62
  export declare function drainPendingLeaderboardIncrements(session: Record<string, unknown>): {
62
63
  increments: LeaderboardIncrement[];
63
64
  session: Record<string, unknown>;
64
65
  };
65
66
  export declare const LEADERBOARD_TOP_LIMIT = 100;
67
+ /** @internal */
66
68
  export declare function clampLimit(value: number | undefined, fallback: number, max: number): number;
67
69
  export type LeaderboardRow = {
68
70
  gameId: string;
@@ -73,8 +75,11 @@ export type LeaderboardRow = {
73
75
  value: number;
74
76
  updatedAt: number;
75
77
  };
78
+ /** @internal */
76
79
  export declare function leaderboardRowKey(row: Omit<LeaderboardRow, "value" | "updatedAt">): string;
80
+ /** @internal */
77
81
  export declare function applyLeaderboardRows(rows: Map<string, LeaderboardRow>, gameId: string, entries: LeaderboardIncrement[], now: number): void;
82
+ /** @internal */
78
83
  export declare function topLeaderboardRows(rows: Iterable<LeaderboardRow>, args: {
79
84
  gameId: string;
80
85
  stat: string;
@@ -82,9 +87,12 @@ export declare function topLeaderboardRows(rows: Iterable<LeaderboardRow>, args:
82
87
  serverId?: string;
83
88
  limit?: number;
84
89
  }): LeaderboardEntry[];
90
+ /** @internal */
85
91
  export declare function profileLeaderboardStats(rows: Iterable<LeaderboardRow>, gameId: string, userId: string): Record<string, number>;
86
92
  export declare const FEED_RING_LIMIT = 20;
93
+ /** @internal */
87
94
  export declare function trimFeedEntries<T>(entries: T[], limit?: number): T[];
95
+ /** @internal */
88
96
  export declare function shouldAutoSave(save: SaveConfig, dirtyAt: number | undefined, lastSavedAt: number | undefined, now: number): boolean;
89
97
  export type ServerListing = {
90
98
  serverId: string;
@@ -101,9 +109,11 @@ export type ServerListing = {
101
109
  export type ToServerListingOptions = {
102
110
  includeJoinCode?: boolean;
103
111
  };
112
+ /** @internal */
104
113
  export declare function toServerListing(record: GameServerRecord, options?: ToServerListingOptions): ServerListing;
105
114
  export declare const OPEN_SERVER_LISTING_LIMIT = 20;
106
115
  export declare const OPEN_SERVER_LISTING_MAX = 100;
116
+ /** @internal */
107
117
  export declare function toOpenServerListings(listings: Iterable<ServerListing>, limit?: number): ServerListing[];
108
118
  export type HostPersistence = {
109
119
  savePlan?: (plan: ServerPersistPlan) => Promise<void>;
@@ -141,6 +151,7 @@ export type HostPersistence = {
141
151
  userId: string;
142
152
  }) => Promise<Record<string, number>>;
143
153
  };
154
+ /** @internal */
144
155
  export declare function buildHydratePlayers(server: GameServerRecord, profiles: Record<string, PlayerProfileRecord | null>): Record<string, RuntimePlayerRow>;
145
156
  export type ServerPersistPlan = {
146
157
  server: GameServerRecord;
@@ -149,4 +160,5 @@ export type ServerPersistPlan = {
149
160
  deletedChunks: string[];
150
161
  leaderboard: LeaderboardIncrement[];
151
162
  };
163
+ /** @internal */
152
164
  export declare function planServerPersist(server: GameServerRecord, snapshot: GameRuntimeSnapshot, save: SaveConfig, now: number): ServerPersistPlan;
@@ -11,6 +11,7 @@ function isLeaderboardIncrement(value) {
11
11
  typeof candidate.by === "number" &&
12
12
  (candidate.serverId === undefined || typeof candidate.serverId === "string"));
13
13
  }
14
+ /** @internal */
14
15
  export function drainPendingLeaderboardIncrements(session) {
15
16
  const raw = session[LEADERBOARD_PENDING_KEY];
16
17
  if (!Array.isArray(raw) || raw.length === 0) {
@@ -21,15 +22,18 @@ export function drainPendingLeaderboardIncrements(session) {
21
22
  return { increments: raw.filter(isLeaderboardIncrement), session: rest };
22
23
  }
23
24
  export const LEADERBOARD_TOP_LIMIT = 100;
25
+ /** @internal */
24
26
  export function clampLimit(value, fallback, max) {
25
27
  const candidate = value ?? fallback;
26
28
  if (!Number.isFinite(candidate))
27
29
  return fallback;
28
30
  return Math.min(Math.max(Math.floor(candidate), 1), max);
29
31
  }
32
+ /** @internal */
30
33
  export function leaderboardRowKey(row) {
31
34
  return [row.gameId, row.scope, row.stat, row.serverId ?? "", row.userId].join("|");
32
35
  }
36
+ /** @internal */
33
37
  export function applyLeaderboardRows(rows, gameId, entries, now) {
34
38
  for (const entry of entries) {
35
39
  const key = leaderboardRowKey({ ...entry, gameId });
@@ -50,6 +54,7 @@ export function applyLeaderboardRows(rows, gameId, entries, now) {
50
54
  }
51
55
  }
52
56
  }
57
+ /** @internal */
53
58
  export function topLeaderboardRows(rows, args) {
54
59
  const limit = clampLimit(args.limit, LEADERBOARD_TOP_LIMIT, LEADERBOARD_TOP_LIMIT);
55
60
  return [...rows]
@@ -61,6 +66,7 @@ export function topLeaderboardRows(rows, args) {
61
66
  .slice(0, limit)
62
67
  .map((row) => ({ userId: row.userId, value: row.value }));
63
68
  }
69
+ /** @internal */
64
70
  export function profileLeaderboardStats(rows, gameId, userId) {
65
71
  const profile = {};
66
72
  for (const row of rows) {
@@ -71,11 +77,13 @@ export function profileLeaderboardStats(rows, gameId, userId) {
71
77
  return profile;
72
78
  }
73
79
  export const FEED_RING_LIMIT = 20;
80
+ /** @internal */
74
81
  export function trimFeedEntries(entries, limit = FEED_RING_LIMIT) {
75
82
  if (entries.length <= limit)
76
83
  return entries;
77
84
  return entries.slice(entries.length - limit);
78
85
  }
86
+ /** @internal */
79
87
  export function shouldAutoSave(save, dirtyAt, lastSavedAt, now) {
80
88
  if (!isSaveEnabled(save))
81
89
  return false;
@@ -85,6 +93,7 @@ export function shouldAutoSave(save, dirtyAt, lastSavedAt, now) {
85
93
  const anchor = lastSavedAt ?? 0;
86
94
  return now - anchor >= intervalMs;
87
95
  }
96
+ /** @internal */
88
97
  export function toServerListing(record, options = {}) {
89
98
  return {
90
99
  serverId: record.serverId,
@@ -103,12 +112,14 @@ export function toServerListing(record, options = {}) {
103
112
  }
104
113
  export const OPEN_SERVER_LISTING_LIMIT = 20;
105
114
  export const OPEN_SERVER_LISTING_MAX = 100;
115
+ /** @internal */
106
116
  export function toOpenServerListings(listings, limit = OPEN_SERVER_LISTING_LIMIT) {
107
117
  return [...listings]
108
118
  .filter((listing) => listing.status === "running")
109
119
  .sort((a, b) => b.updatedAt - a.updatedAt)
110
120
  .slice(0, clampLimit(limit, OPEN_SERVER_LISTING_LIMIT, OPEN_SERVER_LISTING_MAX));
111
121
  }
122
+ /** @internal */
112
123
  export function buildHydratePlayers(server, profiles) {
113
124
  const players = {};
114
125
  for (const userId of server.memberUserIds) {
@@ -129,6 +140,7 @@ export function buildHydratePlayers(server, profiles) {
129
140
  }
130
141
  return players;
131
142
  }
143
+ /** @internal */
132
144
  export function planServerPersist(server, snapshot, save, now) {
133
145
  const drained = drainPendingLeaderboardIncrements(snapshot.server.session);
134
146
  const serverState = drained.increments.length > 0 ? { ...snapshot.server, session: drained.session } : snapshot.server;
@@ -4,7 +4,7 @@ import type { ModelAssetRef } from "../scene/assetCatalog.js";
4
4
  import { type GameContext, type GameContextContent } from "./gameContext.js";
5
5
  import { type InputFrame } from "./inputSnapshot.js";
6
6
  import { type WorldDiff } from "./worldReplication.js";
7
- import type { WorldSnapshot } from "./worldSnapshot.js";
7
+ import type { SnapshotViewer, WorldSnapshot } from "./worldSnapshot.js";
8
8
  export type { InputFrame };
9
9
  /** Reserved command name the authoritative host intercepts on the existing `runCommand` transport to route a client's {@link InputFrame} to `session.input`, so per-tick input needs no separate wire. */
10
10
  export declare const INPUT_COMMAND = "engine.input";
@@ -41,9 +41,14 @@ export interface HostedGameRunner {
41
41
  tick(dt: number): number;
42
42
  diff(sinceRevision: number): WorldDiff;
43
43
  revision(): number;
44
- snapshot(): WorldSnapshot;
44
+ /** The full world baseline — projected to only what `viewer` may see when the context carries a replication policy, else the whole world. */
45
+ snapshot(viewer?: SnapshotViewer): WorldSnapshot;
46
+ /** True when {@link snapshot} is viewer-dependent (a replication policy projects private/AOI state); a host must then serve each viewer its own frame. */
47
+ projectsViewers(): boolean;
45
48
  members(): readonly string[];
46
49
  context(): GameContext;
47
50
  }
48
- /** Build a {@link HostedGameRunner} — one authoritative GameContext world driven server-side from the game's own loop. */
51
+ /** Build a {@link HostedGameRunner} — one authoritative GameContext world driven server-side from the game's own loop.
52
+ * @internal
53
+ */
49
54
  export declare function createHostedGameRunner<TAssetRef extends ModelAssetRef, TMultiplayer>(options: HostedGameRunnerOptions<TAssetRef, TMultiplayer>): HostedGameRunner;
@@ -1,9 +1,13 @@
1
+ import { syncLifecyclePhase } from "../game/gamePhase.js";
2
+ import { advanceBehaviors } from "../scene/behaviorRuntime.js";
1
3
  import { createGameContext } from "./gameContext.js";
2
4
  import {} from "./inputSnapshot.js";
3
5
  import { createWorldReplicator } from "./worldReplication.js";
4
6
  /** Reserved command name the authoritative host intercepts on the existing `runCommand` transport to route a client's {@link InputFrame} to `session.input`, so per-tick input needs no separate wire. */
5
7
  export const INPUT_COMMAND = "engine.input";
6
- /** Build a {@link HostedGameRunner} — one authoritative GameContext world driven server-side from the game's own loop. */
8
+ /** Build a {@link HostedGameRunner} — one authoritative GameContext world driven server-side from the game's own loop.
9
+ * @internal
10
+ */
7
11
  export function createHostedGameRunner(options) {
8
12
  const { definition, content, host, now, restore } = options;
9
13
  const ctx = createGameContext({
@@ -11,20 +15,28 @@ export function createHostedGameRunner(options) {
11
15
  content,
12
16
  player: host ?? { userId: "host", isNew: true },
13
17
  ...(now === undefined ? {} : { now }),
18
+ ...(definition.replication === undefined ? {} : { replication: definition.replication }),
14
19
  });
15
20
  const loop = definition.loop ?? {};
16
- const replicator = createWorldReplicator(() => ctx.snapshot());
21
+ const replicator = createWorldReplicator(() => ctx.snapshot(), {
22
+ worldVersion: () => ctx.replicationVersion(),
23
+ });
17
24
  const members = new Map();
18
25
  const inputs = new Map();
26
+ const inputSeq = new Map();
19
27
  loop.onInit?.(ctx);
28
+ syncLifecyclePhase(ctx, definition.lifecycle);
20
29
  if (restore !== undefined)
21
30
  ctx.hydrate(restore);
22
31
  return {
23
32
  join(userId, isNew) {
33
+ if (members.has(userId))
34
+ return;
24
35
  const player = { userId, isNew };
25
36
  members.set(userId, player);
26
37
  ctx.game.players?.join(userId, isNew);
27
38
  loop.onNewPlayer?.(ctx, player);
39
+ syncLifecyclePhase(ctx, definition.lifecycle);
28
40
  },
29
41
  resume(userId) {
30
42
  members.set(userId, { userId, isNew: false });
@@ -36,10 +48,18 @@ export function createHostedGameRunner(options) {
36
48
  return;
37
49
  members.delete(userId);
38
50
  inputs.delete(userId);
51
+ inputSeq.delete(userId);
39
52
  loop.onPlayerLeave?.(ctx, player);
40
53
  ctx.game.players?.leave(userId);
41
54
  },
42
55
  input(userId, frame) {
56
+ const seq = frame.seq;
57
+ if (seq !== undefined) {
58
+ const lastSeq = inputSeq.get(userId);
59
+ if (lastSeq !== undefined && seq <= lastSeq)
60
+ return;
61
+ inputSeq.set(userId, seq);
62
+ }
43
63
  inputs.set(userId, frame);
44
64
  ctx.game.players?.setInput(userId, frame);
45
65
  },
@@ -51,11 +71,14 @@ export function createHostedGameRunner(options) {
51
71
  },
52
72
  tick(dt) {
53
73
  loop.onTick?.(ctx, dt);
74
+ advanceBehaviors(ctx, dt);
75
+ syncLifecyclePhase(ctx, definition.lifecycle);
54
76
  return replicator.commit();
55
77
  },
56
78
  diff: (sinceRevision) => replicator.diff(sinceRevision),
57
79
  revision: () => replicator.revision(),
58
- snapshot: () => ctx.snapshot(),
80
+ snapshot: (viewer) => ctx.snapshot(viewer),
81
+ projectsViewers: () => ctx.replicatesPerViewer(),
59
82
  members: () => Array.from(members.keys()),
60
83
  context: () => ctx,
61
84
  };
@@ -4,7 +4,7 @@ import type { GameContext, GameContextContent } from "./gameContext.js";
4
4
  import type { GameDefinition, LoopPlayer } from "../game/defineGame.js";
5
5
  import { type HostedGameRunner, type InputFrame } from "./hostedGameRunner.js";
6
6
  import type { WorldDiff } from "./worldReplication.js";
7
- import type { WorldSnapshot } from "./worldSnapshot.js";
7
+ import type { SnapshotViewer, WorldSnapshot } from "./worldSnapshot.js";
8
8
  /** One hosted world's persisted authoritative state — the unit a {@link HostedWorldStore} loads and saves. */
9
9
  export interface HostedWorldRecord {
10
10
  snapshot: WorldSnapshot;
@@ -19,7 +19,9 @@ export interface HostedWorldStore {
19
19
  load(): HostedWorldRecord | null;
20
20
  save(record: HostedWorldRecord): void;
21
21
  }
22
- /** In-process {@link HostedWorldStore} for tests, local play, and the browser-tab P2P host. */
22
+ /** In-process {@link HostedWorldStore} for tests, local play, and the browser-tab P2P host.
23
+ * @internal
24
+ */
23
25
  export declare function memoryWorldStore(seed?: HostedWorldRecord): HostedWorldStore;
24
26
  /** A client replication pull: a full baseline (first sync / fell behind) or a diff since the client's cursor. */
25
27
  export type HostedWorldSync = {
@@ -38,7 +40,7 @@ export interface HostedWorldSessionOptions<TAssetRef extends ModelAssetRef, TMul
38
40
  now?: () => number;
39
41
  /** Where the authoritative snapshot persists; defaults to {@link memoryWorldStore}. */
40
42
  store?: HostedWorldStore;
41
- /** Minimum elapsed `now()` ms between auto-saves on tick. Default `0` — persist on every revision-changing tick. */
43
+ /** Minimum elapsed ms between auto-saves on tick, measured against `now` (defaults to `Date.now` when omitted). Default `0` — persist on every revision-changing tick. */
42
44
  saveIntervalMs?: number;
43
45
  }
44
46
  /**
@@ -55,11 +57,17 @@ export interface HostedWorldSession {
55
57
  tick(dt: number): number;
56
58
  /** Replication pull: `null`/`0` cursor → full baseline; a prior revision → a diff since it. */
57
59
  sync(sinceRevision: number | null): HostedWorldSync;
60
+ /** The full world baseline projected for one viewer (private/AOI). Identity when no replication policy is set. */
61
+ snapshotFor(viewer: SnapshotViewer): WorldSnapshot;
62
+ /** True when {@link snapshotFor} is viewer-dependent — a host must serve each connection its own projected frame instead of a shared diff. */
63
+ projectsViewers(): boolean;
58
64
  revision(): number;
59
65
  members(): readonly string[];
60
66
  /** Force-persist the current world to the store. */
61
67
  save(): void;
62
68
  runner(): HostedGameRunner;
63
69
  }
64
- /** Build a {@link HostedWorldSession} — a live runner loaded from a {@link HostedWorldStore} and auto-persisted on tick. */
70
+ /** Build a {@link HostedWorldSession} — a live runner loaded from a {@link HostedWorldStore} and auto-persisted on tick.
71
+ * @internal
72
+ */
65
73
  export declare function createHostedWorldSession<TAssetRef extends ModelAssetRef, TMultiplayer>(options: HostedWorldSessionOptions<TAssetRef, TMultiplayer>): HostedWorldSession;
@@ -1,5 +1,7 @@
1
1
  import { createHostedGameRunner } from "./hostedGameRunner.js";
2
- /** In-process {@link HostedWorldStore} for tests, local play, and the browser-tab P2P host. */
2
+ /** In-process {@link HostedWorldStore} for tests, local play, and the browser-tab P2P host.
3
+ * @internal
4
+ */
3
5
  export function memoryWorldStore(seed) {
4
6
  let record = seed ?? null;
5
7
  return {
@@ -9,9 +11,12 @@ export function memoryWorldStore(seed) {
9
11
  },
10
12
  };
11
13
  }
12
- /** Build a {@link HostedWorldSession} — a live runner loaded from a {@link HostedWorldStore} and auto-persisted on tick. */
14
+ /** Build a {@link HostedWorldSession} — a live runner loaded from a {@link HostedWorldStore} and auto-persisted on tick.
15
+ * @internal
16
+ */
13
17
  export function createHostedWorldSession(options) {
14
18
  const { definition, content, host, now, saveIntervalMs = 0 } = options;
19
+ const clock = now ?? Date.now;
15
20
  const store = options.store ?? memoryWorldStore();
16
21
  const loaded = store.load();
17
22
  const runner = createHostedGameRunner({
@@ -22,7 +27,7 @@ export function createHostedWorldSession(options) {
22
27
  ...(loaded === null ? {} : { restore: loaded.snapshot }),
23
28
  });
24
29
  let savedRevision = loaded?.revision ?? 0;
25
- let lastSaveAt = now?.() ?? 0;
30
+ let lastSaveAt = clock();
26
31
  function persist() {
27
32
  savedRevision = runner.revision();
28
33
  store.save({ snapshot: runner.snapshot(), revision: savedRevision });
@@ -35,7 +40,7 @@ export function createHostedWorldSession(options) {
35
40
  tick(dt) {
36
41
  const revision = runner.tick(dt);
37
42
  if (revision !== savedRevision) {
38
- const at = now?.() ?? 0;
43
+ const at = clock();
39
44
  if (saveIntervalMs <= 0 || at - lastSaveAt >= saveIntervalMs) {
40
45
  lastSaveAt = at;
41
46
  persist();
@@ -49,6 +54,8 @@ export function createHostedWorldSession(options) {
49
54
  }
50
55
  return { kind: "diff", diff: runner.diff(sinceRevision) };
51
56
  },
57
+ snapshotFor: (viewer) => runner.snapshot(viewer),
58
+ projectsViewers: () => runner.projectsViewers(),
52
59
  revision: () => runner.revision(),
53
60
  members: () => runner.members(),
54
61
  save: persist,
@@ -6,14 +6,19 @@ export interface InputFrame {
6
6
  pointer: PointerAxisState | null;
7
7
  }
8
8
  export interface InputSnapshot {
9
- /** Replaces the held-action set for this frame. Called by the shell before `onTick` each frame; does not bump `ctx.version()` or notify `ctx.subscribe` listeners — per-frame publishes would storm subscribers. */
9
+ /** Replaces the held-action set for this frame, rolling the previous held set forward for edge detection (#671). Called by the shell before `onTick` each frame; does not bump `ctx.version()` or notify `ctx.subscribe` listeners — per-frame publishes would storm subscribers. */
10
10
  publish(held: readonly string[]): void;
11
11
  /** Replaces the normalized pointer-position state for this frame (#293). Same no-notify contract as `publish`. */
12
12
  publishPointer(state: PointerAxisState | null): void;
13
13
  isDown(action: string): boolean;
14
+ /** The held-action set for this frame — an owned, frozen array; the array {@link publish} was called with is never aliased or returned. */
14
15
  held(): readonly string[];
15
- /** Pointer position over the play surface, `[-1, 1]` per axis with `+y` down, published by the shell each frame; `null` until the first pointer move. */
16
- pointer(): PointerAxisState | null;
16
+ /** True only on the frame `action` transitions from up to down (#671) — derived from the last two published held sets, so it stays replay-safe. */
17
+ justPressed(action: string): boolean;
18
+ /** True only on the frame `action` transitions from down to up (#671); mirrors {@link justPressed}. */
19
+ justReleased(action: string): boolean;
20
+ /** Pointer position over the play surface, `[-1, 1]` per axis with `+y` down, published by the shell each frame; `null` until the first pointer move. Frozen — an owned copy of what {@link publishPointer} was called with. */
21
+ pointer(): Readonly<PointerAxisState> | null;
17
22
  /**
18
23
  * Instantaneous analog axis sample against the held-action set and current pointer (#533.7) — bind
19
24
  * throttle/steer/handbrake (or any axes) to *action names*, not raw key codes, since the held set is
@@ -1,19 +1,23 @@
1
1
  import { sampleAxisBindings } from "../input/axisInput.js";
2
2
  export function createInputSnapshot() {
3
3
  let heldSet = new Set();
4
+ let previousHeldSet = new Set();
4
5
  let heldList = [];
5
6
  let pointerState = null;
6
7
  return {
7
8
  publish(held) {
8
- heldList = held;
9
+ previousHeldSet = heldSet;
10
+ heldList = Object.freeze([...held]);
9
11
  heldSet = new Set(held);
10
12
  },
11
13
  publishPointer(state) {
12
- pointerState = state;
14
+ pointerState = state === null ? null : Object.freeze({ ...state });
13
15
  },
14
16
  isDown: (action) => heldSet.has(action),
15
17
  held: () => heldList,
16
18
  pointer: () => pointerState,
17
19
  axis: (bindings, ranges) => sampleAxisBindings(bindings, (action) => heldSet.has(action), pointerState, ranges),
20
+ justPressed: (action) => heldSet.has(action) && !previousHeldSet.has(action),
21
+ justReleased: (action) => !heldSet.has(action) && previousHeldSet.has(action),
18
22
  };
19
23
  }
@@ -21,6 +21,10 @@ export interface MotionIntents {
21
21
  setVerticalVelocity(velocityY: number): void;
22
22
  setY(y: number): void;
23
23
  takePending(): MotionIntentBatch | null;
24
+ /** Non-draining copy of the pending intents for a whole-world save; unlike `takePending` it leaves the queue intact. */
25
+ snapshot(): MotionIntentBatch;
26
+ /** Replace the pending intents from a {@link snapshot} payload on save load. */
27
+ hydrate(batch: MotionIntentBatch): void;
24
28
  }
25
29
  export interface MotionIntentBatch {
26
30
  impulses: readonly number[];
@@ -28,8 +32,13 @@ export interface MotionIntentBatch {
28
32
  verticalVelocity: number | null;
29
33
  y: number | null;
30
34
  }
35
+ /** @internal */
31
36
  export declare function createMotionIntents(): MotionIntents;
32
- /** Fold a batch's vertical impulses into a controller's velocity, then apply an outright `setVerticalVelocity` override — the vertical counterpart of {@link applyHorizontalImpulses}. */
37
+ /** Fold a batch's vertical impulses into a controller's velocity, then apply an outright `setVerticalVelocity` override — the vertical counterpart of {@link applyHorizontalImpulses}.
38
+ * @internal
39
+ */
33
40
  export declare function applyMotionImpulses(currentVelocity: number, batch: MotionIntentBatch | null): number;
34
- /** Fold a batch's horizontal pushes into a controller's velocity pair — shared by the walk and voxel drivers. */
41
+ /** Fold a batch's horizontal pushes into a controller's velocity pair — shared by the walk and voxel drivers.
42
+ * @internal
43
+ */
35
44
  export declare function applyHorizontalImpulses(velocityX: number, velocityZ: number, batch: MotionIntentBatch | null): readonly [number, number];
@@ -1,3 +1,4 @@
1
+ /** @internal */
1
2
  export function createMotionIntents() {
2
3
  let impulses = [];
3
4
  let horizontalImpulses = [];
@@ -27,9 +28,20 @@ export function createMotionIntents() {
27
28
  y = null;
28
29
  return batch;
29
30
  },
31
+ snapshot() {
32
+ return { impulses: [...impulses], horizontalImpulses: [...horizontalImpulses], verticalVelocity, y };
33
+ },
34
+ hydrate(batch) {
35
+ impulses = [...batch.impulses];
36
+ horizontalImpulses = batch.horizontalImpulses.map(([x, z]) => [x, z]);
37
+ verticalVelocity = batch.verticalVelocity;
38
+ y = batch.y;
39
+ },
30
40
  };
31
41
  }
32
- /** Fold a batch's vertical impulses into a controller's velocity, then apply an outright `setVerticalVelocity` override — the vertical counterpart of {@link applyHorizontalImpulses}. */
42
+ /** Fold a batch's vertical impulses into a controller's velocity, then apply an outright `setVerticalVelocity` override — the vertical counterpart of {@link applyHorizontalImpulses}.
43
+ * @internal
44
+ */
33
45
  export function applyMotionImpulses(currentVelocity, batch) {
34
46
  if (batch === null)
35
47
  return currentVelocity;
@@ -40,7 +52,9 @@ export function applyMotionImpulses(currentVelocity, batch) {
40
52
  velocity = batch.verticalVelocity;
41
53
  return velocity;
42
54
  }
43
- /** Fold a batch's horizontal pushes into a controller's velocity pair — shared by the walk and voxel drivers. */
55
+ /** Fold a batch's horizontal pushes into a controller's velocity pair — shared by the walk and voxel drivers.
56
+ * @internal
57
+ */
44
58
  export function applyHorizontalImpulses(velocityX, velocityZ, batch) {
45
59
  if (batch === null || batch.horizontalImpulses.length === 0)
46
60
  return [velocityX, velocityZ];
@@ -0,0 +1,15 @@
1
+ import type { GameContext } from "./gameContext.js";
2
+ /**
3
+ * Per-`GameContext` lazy state, keyed by context identity through a `WeakMap` so it is reclaimed when
4
+ * the context is — the seam a game uses instead of a module-global `Map`, which is process-global and
5
+ * bleeds across worlds when one host serves several `serverId`s (#632). `init` runs once per distinct
6
+ * context on first access; the same context always resolves to the same value. This mirrors the engine's
7
+ * built-in per-ctx pattern (`ctx.player.motion`, `stepPlayerMovement`).
8
+ *
9
+ * ```ts
10
+ * const heroRuntimes = perContext(() => new Map<string, HeroRuntime>());
11
+ * // per world:
12
+ * heroRuntimes(ctx).set(userId, runtime);
13
+ * ```
14
+ */
15
+ export declare function perContext<T>(init: (ctx: GameContext) => T): (ctx: GameContext) => T;
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Per-`GameContext` lazy state, keyed by context identity through a `WeakMap` so it is reclaimed when
3
+ * the context is — the seam a game uses instead of a module-global `Map`, which is process-global and
4
+ * bleeds across worlds when one host serves several `serverId`s (#632). `init` runs once per distinct
5
+ * context on first access; the same context always resolves to the same value. This mirrors the engine's
6
+ * built-in per-ctx pattern (`ctx.player.motion`, `stepPlayerMovement`).
7
+ *
8
+ * ```ts
9
+ * const heroRuntimes = perContext(() => new Map<string, HeroRuntime>());
10
+ * // per world:
11
+ * heroRuntimes(ctx).set(userId, runtime);
12
+ * ```
13
+ */
14
+ export function perContext(init) {
15
+ const byContext = new WeakMap();
16
+ return (ctx) => {
17
+ if (!byContext.has(ctx))
18
+ byContext.set(ctx, init(ctx));
19
+ return byContext.get(ctx);
20
+ };
21
+ }