@v12-engine/engine 0.1.0 → 0.4.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 (951) hide show
  1. package/dist/abilities/amounts.d.ts +28 -0
  2. package/dist/abilities/amounts.js +74 -0
  3. package/dist/abilities/amounts.js.map +1 -0
  4. package/dist/abilities/buffs.d.ts +106 -6
  5. package/dist/abilities/buffs.js +443 -0
  6. package/dist/abilities/buffs.js.map +1 -0
  7. package/dist/abilities/castTold.d.ts +2 -0
  8. package/dist/abilities/castTold.js +66 -0
  9. package/dist/abilities/castTold.js.map +1 -0
  10. package/dist/abilities/chance.d.ts +38 -0
  11. package/dist/abilities/chance.js +77 -0
  12. package/dist/abilities/chance.js.map +1 -0
  13. package/dist/abilities/charges.d.ts +18 -0
  14. package/dist/abilities/charges.js +101 -0
  15. package/dist/abilities/charges.js.map +1 -0
  16. package/dist/abilities/control.d.ts +28 -0
  17. package/dist/abilities/control.js +113 -0
  18. package/dist/abilities/control.js.map +1 -0
  19. package/dist/abilities/dispel.js +51 -0
  20. package/dist/abilities/dispel.js.map +1 -0
  21. package/dist/abilities/effectFields.d.ts +1 -1
  22. package/dist/abilities/effectFields.js +676 -0
  23. package/dist/abilities/effectFields.js.map +1 -0
  24. package/dist/abilities/effectIndex.d.ts +27 -0
  25. package/dist/abilities/effectIndex.js +64 -0
  26. package/dist/abilities/effectIndex.js.map +1 -0
  27. package/dist/abilities/effects/buff.d.ts +9 -3
  28. package/dist/abilities/effects/buff.js +84 -0
  29. package/dist/abilities/effects/buff.js.map +1 -0
  30. package/dist/abilities/effects/conditions.d.ts +2 -0
  31. package/dist/abilities/effects/conditions.js +41 -0
  32. package/dist/abilities/effects/conditions.js.map +1 -0
  33. package/dist/abilities/effects/core.js +54 -0
  34. package/dist/abilities/effects/core.js.map +1 -0
  35. package/dist/abilities/effects/damage.d.ts +1 -1
  36. package/dist/abilities/effects/damage.js +43 -0
  37. package/dist/abilities/effects/damage.js.map +1 -0
  38. package/dist/abilities/effects/heal.d.ts +2 -2
  39. package/dist/abilities/effects/heal.js +51 -0
  40. package/dist/abilities/effects/heal.js.map +1 -0
  41. package/dist/abilities/effects/missile.d.ts +13 -1
  42. package/dist/abilities/effects/missile.js +104 -0
  43. package/dist/abilities/effects/missile.js.map +1 -0
  44. package/dist/abilities/effects/morph.d.ts +5 -0
  45. package/dist/abilities/effects/morph.js +43 -0
  46. package/dist/abilities/effects/morph.js.map +1 -0
  47. package/dist/abilities/effects/moves.d.ts +16 -4
  48. package/dist/abilities/effects/moves.js +212 -0
  49. package/dist/abilities/effects/moves.js.map +1 -0
  50. package/dist/abilities/effects/passives.d.ts +19 -9
  51. package/dist/abilities/effects/passives.js +131 -0
  52. package/dist/abilities/effects/passives.js.map +1 -0
  53. package/dist/abilities/effects/proxy.d.ts +5 -0
  54. package/dist/abilities/effects/proxy.js +60 -0
  55. package/dist/abilities/effects/proxy.js.map +1 -0
  56. package/dist/abilities/effects/sight.d.ts +2 -2
  57. package/dist/abilities/effects/sight.js +39 -0
  58. package/dist/abilities/effects/sight.js.map +1 -0
  59. package/dist/abilities/effects/spawn.d.ts +5 -2
  60. package/dist/abilities/effects/spawn.js +40 -0
  61. package/dist/abilities/effects/spawn.js.map +1 -0
  62. package/dist/abilities/effects/timed.d.ts +2 -2
  63. package/dist/abilities/effects/timed.js +96 -0
  64. package/dist/abilities/effects/timed.js.map +1 -0
  65. package/dist/abilities/effects/trade.d.ts +1 -1
  66. package/dist/abilities/effects/trade.js +25 -0
  67. package/dist/abilities/effects/trade.js.map +1 -0
  68. package/dist/abilities/effects.d.ts +97 -23
  69. package/dist/abilities/effects.js +860 -0
  70. package/dist/abilities/effects.js.map +1 -0
  71. package/dist/abilities/land.d.ts +38 -4
  72. package/dist/abilities/land.js +189 -0
  73. package/dist/abilities/land.js.map +1 -0
  74. package/dist/abilities/recast.d.ts +45 -0
  75. package/dist/abilities/recast.js +118 -0
  76. package/dist/abilities/recast.js.map +1 -0
  77. package/dist/abilities/scaled.js +40 -0
  78. package/dist/abilities/scaled.js.map +1 -0
  79. package/dist/abilities/screen.d.ts +6 -0
  80. package/dist/abilities/screen.js +83 -0
  81. package/dist/abilities/screen.js.map +1 -0
  82. package/dist/abilities/shapes.d.ts +66 -0
  83. package/dist/abilities/shapes.js +122 -0
  84. package/dist/abilities/shapes.js.map +1 -0
  85. package/dist/abilities/text.d.ts +14 -2
  86. package/dist/abilities/text.js +204 -0
  87. package/dist/abilities/text.js.map +1 -0
  88. package/dist/abilities/triggers.d.ts +98 -0
  89. package/dist/abilities/triggers.js +351 -0
  90. package/dist/abilities/triggers.js.map +1 -0
  91. package/dist/abilityChanges.d.ts +131 -0
  92. package/dist/abilityChanges.js +345 -0
  93. package/dist/abilityChanges.js.map +1 -0
  94. package/dist/ai/area.d.ts +4 -1
  95. package/dist/ai/brain.d.ts +4 -1
  96. package/dist/ai/brain.js +844 -0
  97. package/dist/ai/brain.js.map +1 -0
  98. package/dist/ai/budget.js +74 -0
  99. package/dist/ai/budget.js.map +1 -0
  100. package/dist/ai/checks.d.ts +9 -1
  101. package/dist/ai/checks.js +242 -0
  102. package/dist/ai/checks.js.map +1 -0
  103. package/dist/ai/computer.d.ts +11 -4
  104. package/dist/ai/computer.js +251 -0
  105. package/dist/ai/computer.js.map +1 -0
  106. package/dist/ai/defence.d.ts +4 -0
  107. package/dist/ai/defence.js +430 -0
  108. package/dist/ai/defence.js.map +1 -0
  109. package/dist/ai/define.d.ts +3 -2
  110. package/dist/ai/define.js +31 -0
  111. package/dist/ai/define.js.map +1 -0
  112. package/dist/ai/economy.d.ts +10 -7
  113. package/dist/ai/economy.js +780 -0
  114. package/dist/ai/economy.js.map +1 -0
  115. package/dist/ai/geometry.js +38 -0
  116. package/dist/ai/geometry.js.map +1 -0
  117. package/dist/ai/goals.d.ts +1 -0
  118. package/dist/ai/goals.js +560 -0
  119. package/dist/ai/goals.js.map +1 -0
  120. package/dist/ai/knowledge.d.ts +72 -7
  121. package/dist/ai/knowledge.js +804 -0
  122. package/dist/ai/knowledge.js.map +1 -0
  123. package/dist/ai/lanes.d.ts +10 -2
  124. package/dist/ai/lanes.js +715 -0
  125. package/dist/ai/lanes.js.map +1 -0
  126. package/dist/ai/melee/build.js +264 -0
  127. package/dist/ai/melee/build.js.map +1 -0
  128. package/dist/ai/melee/goals.d.ts +7 -0
  129. package/dist/ai/melee/goals.js +720 -0
  130. package/dist/ai/melee/goals.js.map +1 -0
  131. package/dist/ai/melee/heroes.js +68 -0
  132. package/dist/ai/melee/heroes.js.map +1 -0
  133. package/dist/ai/melee/index.d.ts +1 -1
  134. package/dist/ai/melee/index.js +51 -0
  135. package/dist/ai/melee/index.js.map +1 -0
  136. package/dist/ai/melee/production.js +29 -0
  137. package/dist/ai/melee/production.js.map +1 -0
  138. package/dist/ai/melee/surrender.js +64 -0
  139. package/dist/ai/melee/surrender.js.map +1 -0
  140. package/dist/ai/micro.d.ts +9 -0
  141. package/dist/ai/micro.js +1316 -0
  142. package/dist/ai/micro.js.map +1 -0
  143. package/dist/ai/mission.d.ts +9 -2
  144. package/dist/ai/mission.js +538 -0
  145. package/dist/ai/mission.js.map +1 -0
  146. package/dist/ai/missionRules.d.ts +1 -1
  147. package/dist/ai/missionRules.js +26 -0
  148. package/dist/ai/missionRules.js.map +1 -0
  149. package/dist/ai/module.d.ts +6 -2
  150. package/dist/ai/module.js +37 -0
  151. package/dist/ai/module.js.map +1 -0
  152. package/dist/ai/options.d.ts +3 -3
  153. package/dist/ai/plans/build.d.ts +20 -1
  154. package/dist/ai/plans/build.js +608 -0
  155. package/dist/ai/plans/build.js.map +1 -0
  156. package/dist/ai/plans/placement.d.ts +4 -1
  157. package/dist/ai/plans/placement.js +295 -0
  158. package/dist/ai/plans/placement.js.map +1 -0
  159. package/dist/ai/plans/plans.d.ts +9 -0
  160. package/dist/ai/plans/plans.js +110 -0
  161. package/dist/ai/plans/plans.js.map +1 -0
  162. package/dist/ai/plans/production.d.ts +14 -2
  163. package/dist/ai/plans/production.js +434 -0
  164. package/dist/ai/plans/production.js.map +1 -0
  165. package/dist/ai/plans/purse.d.ts +6 -3
  166. package/dist/ai/plans/purse.js +139 -0
  167. package/dist/ai/plans/purse.js.map +1 -0
  168. package/dist/ai/plans/tech.d.ts +6 -0
  169. package/dist/ai/plans/tech.js +122 -0
  170. package/dist/ai/plans/tech.js.map +1 -0
  171. package/dist/ai/profiles.d.ts +4 -4
  172. package/dist/{profiles-B3NS9jwk.js → ai/profiles.js} +3 -98
  173. package/dist/ai/profiles.js.map +1 -0
  174. package/dist/ai/reach.js +54 -0
  175. package/dist/ai/reach.js.map +1 -0
  176. package/dist/ai/report.d.ts +8 -0
  177. package/dist/ai/report.js +87 -0
  178. package/dist/ai/report.js.map +1 -0
  179. package/dist/ai/roles.d.ts +4 -0
  180. package/dist/ai/roles.js +207 -0
  181. package/dist/ai/roles.js.map +1 -0
  182. package/dist/ai/rules.d.ts +8 -2
  183. package/dist/ai/rules.js +416 -0
  184. package/dist/ai/rules.js.map +1 -0
  185. package/dist/ai/scouting.d.ts +6 -0
  186. package/dist/ai/scouting.js +324 -0
  187. package/dist/ai/scouting.js.map +1 -0
  188. package/dist/ai/settings.js +99 -0
  189. package/dist/ai/settings.js.map +1 -0
  190. package/dist/ai/squads.d.ts +21 -2
  191. package/dist/ai/squads.js +916 -0
  192. package/dist/ai/squads.js.map +1 -0
  193. package/dist/ai/strength.js +320 -0
  194. package/dist/ai/strength.js.map +1 -0
  195. package/dist/ai/task.d.ts +3 -1
  196. package/dist/ai/task.js +17 -0
  197. package/dist/ai/task.js.map +1 -0
  198. package/dist/ai/tasks/attack.js +24 -0
  199. package/dist/ai/tasks/attack.js.map +1 -0
  200. package/dist/ai/tasks/capture.d.ts +3 -3
  201. package/dist/ai/tasks/capture.js +37 -0
  202. package/dist/ai/tasks/capture.js.map +1 -0
  203. package/dist/ai/tasks/creep.js +29 -0
  204. package/dist/ai/tasks/creep.js.map +1 -0
  205. package/dist/ai/tasks/defend.js +61 -0
  206. package/dist/ai/tasks/defend.js.map +1 -0
  207. package/dist/ai/tasks/drop.js +81 -0
  208. package/dist/ai/tasks/drop.js.map +1 -0
  209. package/dist/ai/tasks/escort.js +59 -0
  210. package/dist/ai/tasks/escort.js.map +1 -0
  211. package/dist/ai/tasks/gather.js +48 -0
  212. package/dist/ai/tasks/gather.js.map +1 -0
  213. package/dist/ai/tasks/harass.js +39 -0
  214. package/dist/ai/tasks/harass.js.map +1 -0
  215. package/dist/ai/tasks/hold.js +32 -0
  216. package/dist/ai/tasks/hold.js.map +1 -0
  217. package/dist/ai/tasks/index.js +34 -0
  218. package/dist/ai/tasks/index.js.map +1 -0
  219. package/dist/ai/tasks/move.js +26 -0
  220. package/dist/ai/tasks/move.js.map +1 -0
  221. package/dist/ai/tasks/patrol.js +59 -0
  222. package/dist/ai/tasks/patrol.js.map +1 -0
  223. package/dist/ai/tasks/retreat.js +28 -0
  224. package/dist/ai/tasks/retreat.js.map +1 -0
  225. package/dist/ai/tasks/scout.js +73 -0
  226. package/dist/ai/tasks/scout.js.map +1 -0
  227. package/dist/ai/tasks/shared.d.ts +1 -1
  228. package/dist/ai/tasks/shared.js +137 -0
  229. package/dist/ai/tasks/shared.js.map +1 -0
  230. package/dist/ai/team.d.ts +18 -1
  231. package/dist/ai/team.js +492 -0
  232. package/dist/ai/team.js.map +1 -0
  233. package/dist/ai/threat.d.ts +6 -0
  234. package/dist/ai/threat.js +206 -0
  235. package/dist/ai/threat.js.map +1 -0
  236. package/dist/ai/view.d.ts +21 -7
  237. package/dist/ai/view.js +677 -0
  238. package/dist/ai/view.js.map +1 -0
  239. package/dist/ai/waves.d.ts +6 -0
  240. package/dist/ai/waves.js +410 -0
  241. package/dist/ai/waves.js.map +1 -0
  242. package/dist/ai.js +54 -6239
  243. package/dist/aiTesting.d.ts +6 -3
  244. package/dist/aiTesting.js +229 -0
  245. package/dist/aiTesting.js.map +1 -0
  246. package/dist/areas.d.ts +4 -1
  247. package/dist/areas.js +295 -0
  248. package/dist/areas.js.map +1 -0
  249. package/dist/attacks.d.ts +3 -3
  250. package/dist/attacks.js +127 -0
  251. package/dist/attacks.js.map +1 -0
  252. package/dist/burning.d.ts +267 -0
  253. package/dist/burning.js +795 -0
  254. package/dist/burning.js.map +1 -0
  255. package/dist/bytes.js +21 -0
  256. package/dist/bytes.js.map +1 -0
  257. package/dist/callings.d.ts +71 -0
  258. package/dist/callings.js +157 -0
  259. package/dist/callings.js.map +1 -0
  260. package/dist/cameraOrders.d.ts +78 -0
  261. package/dist/cameraOrders.js +114 -0
  262. package/dist/cameraOrders.js.map +1 -0
  263. package/dist/camps.d.ts +70 -4
  264. package/dist/camps.js +501 -0
  265. package/dist/camps.js.map +1 -0
  266. package/dist/capture.d.ts +15 -3
  267. package/dist/capture.js +304 -0
  268. package/dist/capture.js.map +1 -0
  269. package/dist/cellLayers.d.ts +78 -13
  270. package/dist/cellLayers.js +275 -0
  271. package/dist/cellLayers.js.map +1 -0
  272. package/dist/cellPatches.d.ts +24 -0
  273. package/dist/cellPatches.js +73 -0
  274. package/dist/cellPatches.js.map +1 -0
  275. package/dist/cinematics.d.ts +10 -5
  276. package/dist/cinematics.js +161 -0
  277. package/dist/cinematics.js.map +1 -0
  278. package/dist/clock.d.ts +2 -2
  279. package/dist/clock.js +78 -0
  280. package/dist/clock.js.map +1 -0
  281. package/dist/commands.d.ts +36 -4
  282. package/dist/commands.js +636 -0
  283. package/dist/commands.js.map +1 -0
  284. package/dist/components.d.ts +31 -10
  285. package/dist/components.js +74 -0
  286. package/dist/components.js.map +1 -0
  287. package/dist/computers.d.ts +4 -4
  288. package/dist/computers.js +194 -0
  289. package/dist/computers.js.map +1 -0
  290. package/dist/concealment.d.ts +25 -2
  291. package/dist/concealment.js +409 -0
  292. package/dist/concealment.js.map +1 -0
  293. package/dist/coreComponents.js +130 -0
  294. package/dist/coreComponents.js.map +1 -0
  295. package/dist/createGame.d.ts +306 -0
  296. package/dist/createGame.js +405 -0
  297. package/dist/createGame.js.map +1 -0
  298. package/dist/dashing.d.ts +18 -2
  299. package/dist/dashing.js +41 -0
  300. package/dist/dashing.js.map +1 -0
  301. package/dist/debug.d.ts +8 -0
  302. package/dist/debug.js +5 -3
  303. package/dist/debug2.js +76 -0
  304. package/dist/debug2.js.map +1 -0
  305. package/dist/debugCommands.d.ts +6 -6
  306. package/dist/debugCommands.js +537 -0
  307. package/dist/debugCommands.js.map +1 -0
  308. package/dist/debugging.d.ts +1 -0
  309. package/dist/defaultSets.d.ts +183 -0
  310. package/dist/defaultSets.js +216 -0
  311. package/dist/defaultSets.js.map +1 -0
  312. package/dist/definitions.d.ts +6 -0
  313. package/dist/definitions.js +78 -0
  314. package/dist/definitions.js.map +1 -0
  315. package/dist/defs.d.ts +1895 -165
  316. package/dist/defs.js +380 -0
  317. package/dist/defs.js.map +1 -0
  318. package/dist/denying.d.ts +4 -4
  319. package/dist/denying.js +106 -0
  320. package/dist/denying.js.map +1 -0
  321. package/dist/destructibles.d.ts +2 -2
  322. package/dist/destructibles.js +36 -0
  323. package/dist/destructibles.js.map +1 -0
  324. package/dist/determinism.d.ts +4 -4
  325. package/dist/determinism.js +247 -0
  326. package/dist/determinism.js.map +1 -0
  327. package/dist/dialog.d.ts +17 -2
  328. package/dist/dialog.js +108 -0
  329. package/dist/dialog.js.map +1 -0
  330. package/dist/effectRefs.js +28 -0
  331. package/dist/effectRefs.js.map +1 -0
  332. package/dist/effects.d.ts +27 -11
  333. package/dist/effects.js +110 -0
  334. package/dist/effects.js.map +1 -0
  335. package/dist/endings.d.ts +1 -1
  336. package/dist/endings.js +78 -0
  337. package/dist/endings.js.map +1 -0
  338. package/dist/engagement.d.ts +40 -6
  339. package/dist/engagement.js +530 -0
  340. package/dist/engagement.js.map +1 -0
  341. package/dist/engineEvents.d.ts +72 -9
  342. package/dist/engineEvents.js +520 -0
  343. package/dist/engineEvents.js.map +1 -0
  344. package/dist/entity.d.ts +275 -26
  345. package/dist/entity.js +441 -0
  346. package/dist/entity.js.map +1 -0
  347. package/dist/entityIndex.d.ts +10 -3
  348. package/dist/entityIndex.js +149 -0
  349. package/dist/entityIndex.js.map +1 -0
  350. package/dist/errors.d.ts +6 -2
  351. package/dist/errors.js +59 -0
  352. package/dist/errors.js.map +1 -0
  353. package/dist/events.d.ts +11 -5
  354. package/dist/events.js +158 -0
  355. package/dist/events.js.map +1 -0
  356. package/dist/exactMath.js +273 -0
  357. package/dist/exactMath.js.map +1 -0
  358. package/dist/features.d.ts +1 -1
  359. package/dist/features.js +127 -0
  360. package/dist/features.js.map +1 -0
  361. package/dist/fields.d.ts +25 -5
  362. package/dist/fields.js +140 -0
  363. package/dist/fields.js.map +1 -0
  364. package/dist/fixture.d.ts +3 -3
  365. package/dist/fixture.js +512 -0
  366. package/dist/fixture.js.map +1 -0
  367. package/dist/fog.d.ts +26 -3
  368. package/dist/fog.js +333 -0
  369. package/dist/fog.js.map +1 -0
  370. package/dist/foliage.d.ts +476 -0
  371. package/dist/foliage.js +1478 -0
  372. package/dist/foliage.js.map +1 -0
  373. package/dist/foliageDebug.d.ts +57 -0
  374. package/dist/foliageDebug.js +172 -0
  375. package/dist/foliageDebug.js.map +1 -0
  376. package/dist/foliageRegrowth.d.ts +20 -0
  377. package/dist/foliageRegrowth.js +332 -0
  378. package/dist/foliageRegrowth.js.map +1 -0
  379. package/dist/formState.d.ts +67 -0
  380. package/dist/formState.js +65 -0
  381. package/dist/formState.js.map +1 -0
  382. package/dist/formation.d.ts +46 -8
  383. package/dist/formation.js +297 -0
  384. package/dist/formation.js.map +1 -0
  385. package/dist/forms.d.ts +58 -0
  386. package/dist/forms.js +146 -0
  387. package/dist/forms.js.map +1 -0
  388. package/dist/friendlyFire.d.ts +2 -2
  389. package/dist/friendlyFire.js +37 -0
  390. package/dist/friendlyFire.js.map +1 -0
  391. package/dist/game.d.ts +141 -48
  392. package/dist/game.js +834 -0
  393. package/dist/game.js.map +1 -0
  394. package/dist/gameData.d.ts +96 -22
  395. package/dist/gameData.js +1690 -0
  396. package/dist/gameData.js.map +1 -0
  397. package/dist/gameFiles.d.ts +3 -3
  398. package/dist/gameFiles.js +14 -0
  399. package/dist/gameFiles.js.map +1 -0
  400. package/dist/gates.js +92 -0
  401. package/dist/gates.js.map +1 -0
  402. package/dist/generate.d.ts +28 -1
  403. package/dist/generate.js +1062 -0
  404. package/dist/generate.js.map +1 -0
  405. package/dist/generateWorker.d.ts +7 -3
  406. package/dist/generateWorker.js +86 -0
  407. package/dist/generateWorker.js.map +1 -0
  408. package/dist/grid.d.ts +9 -0
  409. package/dist/grid.js +102 -0
  410. package/dist/grid.js.map +1 -0
  411. package/dist/ground.d.ts +17 -1
  412. package/dist/ground.js +375 -0
  413. package/dist/ground.js.map +1 -0
  414. package/dist/groundObjects.d.ts +70 -0
  415. package/dist/groundObjects.js +371 -0
  416. package/dist/groundObjects.js.map +1 -0
  417. package/dist/groundSpeed.d.ts +20 -3
  418. package/dist/groundSpeed.js +117 -0
  419. package/dist/groundSpeed.js.map +1 -0
  420. package/dist/hero.d.ts +126 -10
  421. package/dist/hero.js +432 -0
  422. package/dist/hero.js.map +1 -0
  423. package/dist/holds.d.ts +94 -0
  424. package/dist/holds.js +305 -0
  425. package/dist/holds.js.map +1 -0
  426. package/dist/home.d.ts +1 -1
  427. package/dist/home.js +30 -0
  428. package/dist/home.js.map +1 -0
  429. package/dist/hooks.d.ts +339 -57
  430. package/dist/hooks.js +105 -0
  431. package/dist/hooks.js.map +1 -0
  432. package/dist/hotReload.d.ts +6 -5
  433. package/dist/hotReload.js +145 -0
  434. package/dist/hotReload.js.map +1 -0
  435. package/dist/ids.d.ts +3 -3
  436. package/dist/ids.js +30 -0
  437. package/dist/ids.js.map +1 -0
  438. package/dist/idsFile.d.ts +36 -0
  439. package/dist/idsFile.js +134 -0
  440. package/dist/idsFile.js.map +1 -0
  441. package/dist/index.d.ts +105 -68
  442. package/dist/index.js +194 -4701
  443. package/dist/inspect.d.ts +29 -2
  444. package/dist/{inspect-D9dWHmZ0.js → inspect.js} +21 -12
  445. package/dist/inspect.js.map +1 -0
  446. package/dist/inventory.d.ts +14 -1
  447. package/dist/inventory.js +84 -0
  448. package/dist/inventory.js.map +1 -0
  449. package/dist/items.d.ts +136 -8
  450. package/dist/items.js +585 -0
  451. package/dist/items.js.map +1 -0
  452. package/dist/lanes.d.ts +12 -3
  453. package/dist/lanes.js +496 -0
  454. package/dist/lanes.js.map +1 -0
  455. package/dist/life.d.ts +6 -2
  456. package/dist/life.js +287 -0
  457. package/dist/life.js.map +1 -0
  458. package/dist/log.d.ts +26 -3
  459. package/dist/log.js +192 -0
  460. package/dist/log.js.map +1 -0
  461. package/dist/manaBurn.d.ts +2 -2
  462. package/dist/manaBurn.js +75 -0
  463. package/dist/manaBurn.js.map +1 -0
  464. package/dist/map/file.d.ts +56 -3
  465. package/dist/map/file.js +264 -0
  466. package/dist/map/file.js.map +1 -0
  467. package/dist/map/images.js +61 -0
  468. package/dist/map/images.js.map +1 -0
  469. package/dist/map/look.d.ts +1 -1
  470. package/dist/map/look.js +30 -0
  471. package/dist/map/look.js.map +1 -0
  472. package/dist/map/pathProfile.js +183 -0
  473. package/dist/map/pathProfile.js.map +1 -0
  474. package/dist/map/resize.d.ts +4 -0
  475. package/dist/map/resize.js +136 -0
  476. package/dist/map/resize.js.map +1 -0
  477. package/dist/map/schema.js +257 -0
  478. package/dist/map/schema.js.map +1 -0
  479. package/dist/map/terrain.js +214 -0
  480. package/dist/map/terrain.js.map +1 -0
  481. package/dist/map/types.d.ts +92 -13
  482. package/dist/map/types.js +251 -0
  483. package/dist/map/types.js.map +1 -0
  484. package/dist/mapCheck/cells.js +94 -0
  485. package/dist/mapCheck/cells.js.map +1 -0
  486. package/dist/mapCheck/rules/foliage.d.ts +9 -0
  487. package/dist/mapCheck/rules/foliage.js +83 -0
  488. package/dist/mapCheck/rules/foliage.js.map +1 -0
  489. package/dist/mapCheck/rules/names.js +39 -0
  490. package/dist/mapCheck/rules/names.js.map +1 -0
  491. package/dist/mapCheck/rules/objects.d.ts +1 -1
  492. package/dist/mapCheck/rules/objects.js +56 -0
  493. package/dist/mapCheck/rules/objects.js.map +1 -0
  494. package/dist/mapCheck/rules/paths.js +32 -0
  495. package/dist/mapCheck/rules/paths.js.map +1 -0
  496. package/dist/mapCheck/rules/players.js +20 -0
  497. package/dist/mapCheck/rules/players.js.map +1 -0
  498. package/dist/mapCheck/rules/races.js +56 -0
  499. package/dist/mapCheck/rules/races.js.map +1 -0
  500. package/dist/mapCheck/rules/random.js +47 -0
  501. package/dist/mapCheck/rules/random.js.map +1 -0
  502. package/dist/mapCheck/rules/regions.js +30 -0
  503. package/dist/mapCheck/rules/regions.js.map +1 -0
  504. package/dist/mapCheck/rules/targets.js +31 -0
  505. package/dist/mapCheck/rules/targets.js.map +1 -0
  506. package/dist/mapCheck/rules/walking.js +45 -0
  507. package/dist/mapCheck/rules/walking.js.map +1 -0
  508. package/dist/mapCheck.d.ts +2 -2
  509. package/dist/mapCheck.js +63 -0
  510. package/dist/mapCheck.js.map +1 -0
  511. package/dist/mapFields.d.ts +25 -2
  512. package/dist/mapFields.js +134 -0
  513. package/dist/mapFields.js.map +1 -0
  514. package/dist/mapFile.js +176 -0
  515. package/dist/mapFile.js.map +1 -0
  516. package/dist/mapMeasure.d.ts +8 -0
  517. package/dist/mapMeasure.js +283 -0
  518. package/dist/mapMeasure.js.map +1 -0
  519. package/dist/mapMerge.d.ts +1 -0
  520. package/dist/mapMerge.js +172 -0
  521. package/dist/mapMerge.js.map +1 -0
  522. package/dist/mapObjectives.js +138 -0
  523. package/dist/mapObjectives.js.map +1 -0
  524. package/dist/mapObjects.js +80 -0
  525. package/dist/mapObjects.js.map +1 -0
  526. package/dist/math.d.ts +37 -7
  527. package/dist/math.js +155 -0
  528. package/dist/math.js.map +1 -0
  529. package/dist/messages.d.ts +71 -4
  530. package/dist/messages.js +29 -0
  531. package/dist/messages.js.map +1 -0
  532. package/dist/missionRules.d.ts +10 -2
  533. package/dist/{missionRules-C-bGxm0Q.js → missionRules.js} +30 -150
  534. package/dist/missionRules.js.map +1 -0
  535. package/dist/mods.d.ts +39 -20
  536. package/dist/mods.js +271 -0
  537. package/dist/mods.js.map +1 -0
  538. package/dist/moves.d.ts +87 -0
  539. package/dist/moves.js +539 -0
  540. package/dist/moves.js.map +1 -0
  541. package/dist/names.d.ts +7 -0
  542. package/dist/names.js +122 -0
  543. package/dist/names.js.map +1 -0
  544. package/dist/navigation/agentParams.js +14 -0
  545. package/dist/navigation/agentParams.js.map +1 -0
  546. package/dist/navigation/air.d.ts +7 -3
  547. package/dist/navigation/air.js +401 -0
  548. package/dist/navigation/air.js.map +1 -0
  549. package/dist/navigation/builds.d.ts +34 -2
  550. package/dist/navigation/builds.js +287 -0
  551. package/dist/navigation/builds.js.map +1 -0
  552. package/dist/navigation/groundAreas.d.ts +59 -1
  553. package/dist/navigation/groundAreas.js +407 -0
  554. package/dist/navigation/groundAreas.js.map +1 -0
  555. package/dist/navigation/navigation.d.ts +98 -9
  556. package/dist/navigation/recast.d.ts +194 -18
  557. package/dist/navigation/recast.js +1379 -0
  558. package/dist/navigation/recast.js.map +1 -0
  559. package/dist/navigation/sidePaths.d.ts +8 -3
  560. package/dist/navigation/sidePaths.js +241 -0
  561. package/dist/navigation/sidePaths.js.map +1 -0
  562. package/dist/navigation/sized.js +243 -0
  563. package/dist/navigation/sized.js.map +1 -0
  564. package/dist/nearest.js +32 -0
  565. package/dist/nearest.js.map +1 -0
  566. package/dist/noise.js +59 -0
  567. package/dist/noise.js.map +1 -0
  568. package/dist/objectives.d.ts +12 -3
  569. package/dist/objectives.js +144 -0
  570. package/dist/objectives.js.map +1 -0
  571. package/dist/orders/basic.d.ts +5 -5
  572. package/dist/orders/basic.js +417 -0
  573. package/dist/orders/basic.js.map +1 -0
  574. package/dist/orders/build.js +278 -0
  575. package/dist/orders/build.js.map +1 -0
  576. package/dist/orders/cast.d.ts +13 -3
  577. package/dist/orders/cast.js +558 -0
  578. package/dist/orders/cast.js.map +1 -0
  579. package/dist/orders/facts.js +16 -0
  580. package/dist/orders/facts.js.map +1 -0
  581. package/dist/orders/harvest.d.ts +21 -5
  582. package/dist/orders/harvest.js +540 -0
  583. package/dist/orders/harvest.js.map +1 -0
  584. package/dist/orders/idle.d.ts +3 -1
  585. package/dist/orders/idle.js +234 -0
  586. package/dist/orders/idle.js.map +1 -0
  587. package/dist/orders/items.js +92 -0
  588. package/dist/orders/items.js.map +1 -0
  589. package/dist/orders/queue.js +108 -0
  590. package/dist/orders/queue.js.map +1 -0
  591. package/dist/orders/waiting.d.ts +39 -0
  592. package/dist/orders/waiting.js +149 -0
  593. package/dist/orders/waiting.js.map +1 -0
  594. package/dist/pack.schema.js +13 -0
  595. package/dist/pack.schema.js.map +1 -0
  596. package/dist/pack.schema.json +7622 -841
  597. package/dist/packs/director/index.d.ts +13 -5
  598. package/dist/packs/director/index.js +204 -0
  599. package/dist/packs/director/index.js.map +1 -0
  600. package/dist/packs/heroes/campaign.d.ts +3 -2
  601. package/dist/packs/heroes/campaign.js +241 -0
  602. package/dist/packs/heroes/campaign.js.map +1 -0
  603. package/dist/packs/heroes/carry.d.ts +6 -0
  604. package/dist/packs/heroes/carry.js +112 -0
  605. package/dist/packs/heroes/carry.js.map +1 -0
  606. package/dist/packs/heroes/commands.js +115 -0
  607. package/dist/packs/heroes/commands.js.map +1 -0
  608. package/dist/packs/heroes/fallen.d.ts +43 -0
  609. package/dist/packs/heroes/fallen.js +61 -0
  610. package/dist/packs/heroes/fallen.js.map +1 -0
  611. package/dist/packs/heroes/hire.js +60 -0
  612. package/dist/packs/heroes/hire.js.map +1 -0
  613. package/dist/packs/heroes/index.d.ts +7 -6
  614. package/dist/packs/heroes/index.js +130 -0
  615. package/dist/packs/heroes/index.js.map +1 -0
  616. package/dist/packs/heroes/loop.d.ts +95 -0
  617. package/dist/packs/heroes/loop.js +250 -0
  618. package/dist/packs/heroes/loop.js.map +1 -0
  619. package/dist/packs/heroes/making.d.ts +6 -3
  620. package/dist/packs/heroes/making.js +55 -0
  621. package/dist/packs/heroes/making.js.map +1 -0
  622. package/dist/packs/heroes/respawn.d.ts +3 -3
  623. package/dist/packs/heroes/respawn.js +87 -0
  624. package/dist/packs/heroes/respawn.js.map +1 -0
  625. package/dist/packs/heroes/sets.d.ts +32 -0
  626. package/dist/packs/heroes/sets.js +51 -0
  627. package/dist/packs/heroes/sets.js.map +1 -0
  628. package/dist/packs/heroes/spells.d.ts +16 -0
  629. package/dist/packs/heroes/spells.js +269 -0
  630. package/dist/packs/heroes/spells.js.map +1 -0
  631. package/dist/packs/items/defaults.d.ts +43 -0
  632. package/dist/packs/items/defaults.js +1504 -0
  633. package/dist/packs/items/defaults.js.map +1 -0
  634. package/dist/packs/items/index.d.ts +27 -0
  635. package/dist/packs/items/index.js +214 -0
  636. package/dist/packs/items/index.js.map +1 -0
  637. package/dist/packs/moba/index.d.ts +3 -3
  638. package/dist/packs/moba/index.js +174 -0
  639. package/dist/packs/moba/index.js.map +1 -0
  640. package/dist/packs/pack.d.ts +15 -15
  641. package/dist/packs/pack.js +14 -0
  642. package/dist/packs/pack.js.map +1 -0
  643. package/dist/packs.d.ts +15 -7
  644. package/dist/packs.js +222 -0
  645. package/dist/packs.js.map +1 -0
  646. package/dist/paths.d.ts +2 -0
  647. package/dist/paths.js +109 -0
  648. package/dist/paths.js.map +1 -0
  649. package/dist/plain.js +57 -0
  650. package/dist/plain.js.map +1 -0
  651. package/dist/player.d.ts +33 -10
  652. package/dist/player.js +159 -0
  653. package/dist/player.js.map +1 -0
  654. package/dist/portals.d.ts +1 -1
  655. package/dist/portals.js +194 -0
  656. package/dist/portals.js.map +1 -0
  657. package/dist/prefabs.d.ts +25 -2
  658. package/dist/prefabs.js +239 -0
  659. package/dist/prefabs.js.map +1 -0
  660. package/dist/presetBuildings.js +58 -0
  661. package/dist/presetBuildings.js.map +1 -0
  662. package/dist/presetFoliage.d.ts +27 -0
  663. package/dist/presetFoliage.js +98 -0
  664. package/dist/presetFoliage.js.map +1 -0
  665. package/dist/presetGround.js +65 -0
  666. package/dist/presetGround.js.map +1 -0
  667. package/dist/proxies.d.ts +12 -0
  668. package/dist/proxies.js +79 -0
  669. package/dist/proxies.js.map +1 -0
  670. package/dist/query.d.ts +56 -0
  671. package/dist/query.js +88 -0
  672. package/dist/query.js.map +1 -0
  673. package/dist/races.d.ts +15 -14
  674. package/dist/races.js +172 -0
  675. package/dist/races.js.map +1 -0
  676. package/dist/randomGroups.js +91 -0
  677. package/dist/randomGroups.js.map +1 -0
  678. package/dist/registry.d.ts +117 -53
  679. package/dist/registry.js +323 -0
  680. package/dist/registry.js.map +1 -0
  681. package/dist/remains.d.ts +11 -9
  682. package/dist/remains.js +188 -0
  683. package/dist/remains.js.map +1 -0
  684. package/dist/replication.d.ts +12 -7
  685. package/dist/replication.js +100 -0
  686. package/dist/replication.js.map +1 -0
  687. package/dist/rng.d.ts +2 -0
  688. package/dist/rng.js +40 -0
  689. package/dist/rng.js.map +1 -0
  690. package/dist/rules.d.ts +186 -99
  691. package/dist/rules.js +179 -0
  692. package/dist/rules.js.map +1 -0
  693. package/dist/rulesCheck.d.ts +5 -4
  694. package/dist/rulesCheck.js +693 -0
  695. package/dist/rulesCheck.js.map +1 -0
  696. package/dist/runes.d.ts +2 -2
  697. package/dist/runes.js +80 -0
  698. package/dist/runes.js.map +1 -0
  699. package/dist/save.d.ts +37 -12
  700. package/dist/save.js +532 -0
  701. package/dist/save.js.map +1 -0
  702. package/dist/scenario.d.ts +2 -2
  703. package/dist/scenario.js +99 -0
  704. package/dist/scenario.js.map +1 -0
  705. package/dist/scheduler.d.ts +3 -0
  706. package/dist/scheduler.js +156 -0
  707. package/dist/scheduler.js.map +1 -0
  708. package/dist/score.d.ts +19 -19
  709. package/dist/score.js +709 -0
  710. package/dist/score.js.map +1 -0
  711. package/dist/sequences.d.ts +10 -6
  712. package/dist/sequences.js +206 -0
  713. package/dist/sequences.js.map +1 -0
  714. package/dist/server/doorman.js +154 -0
  715. package/dist/server/doorman.js.map +1 -0
  716. package/dist/server/gameServer.d.ts +16 -1
  717. package/dist/server/gameServer.js +643 -0
  718. package/dist/server/gameServer.js.map +1 -0
  719. package/dist/server/index.d.ts +1 -1
  720. package/dist/server/lobby.js +199 -0
  721. package/dist/server/lobby.js.map +1 -0
  722. package/dist/server/log.js +18 -0
  723. package/dist/server/log.js.map +1 -0
  724. package/dist/server/match.js +267 -0
  725. package/dist/server/match.js.map +1 -0
  726. package/dist/server/mode.d.ts +18 -9
  727. package/dist/server/mode.js +220 -0
  728. package/dist/server/mode.js.map +1 -0
  729. package/dist/{navigation-worker.js → server/navigation-worker.js} +1 -1
  730. package/dist/server/navigation-worker.js.map +1 -0
  731. package/dist/server/navigation.js +39 -0
  732. package/dist/server/navigation.js.map +1 -0
  733. package/dist/server/ops.d.ts +4 -0
  734. package/dist/server/ops.js +137 -0
  735. package/dist/server/ops.js.map +1 -0
  736. package/dist/server/packs.d.ts +3 -3
  737. package/dist/server/packs.js +32 -0
  738. package/dist/server/packs.js.map +1 -0
  739. package/dist/server/ratings.d.ts +5 -0
  740. package/dist/server/ratings.js +104 -0
  741. package/dist/server/ratings.js.map +1 -0
  742. package/dist/server/relay.d.ts +12 -2
  743. package/dist/server/relay.js +144 -0
  744. package/dist/server/relay.js.map +1 -0
  745. package/dist/server/rooms.d.ts +9 -2
  746. package/dist/server/rooms.js +442 -0
  747. package/dist/server/rooms.js.map +1 -0
  748. package/dist/server/seat.js +116 -0
  749. package/dist/server/seat.js.map +1 -0
  750. package/dist/server/seatSettings.d.ts +3 -3
  751. package/dist/server/seatSettings.js +63 -0
  752. package/dist/server/seatSettings.js.map +1 -0
  753. package/dist/server/secret.js +13 -0
  754. package/dist/server/secret.js.map +1 -0
  755. package/dist/server/start.d.ts +13 -6
  756. package/dist/server/start.js +76 -0
  757. package/dist/server/start.js.map +1 -0
  758. package/dist/server/websocket.d.ts +9 -1
  759. package/dist/server/websocket.js +306 -0
  760. package/dist/server/websocket.js.map +1 -0
  761. package/dist/server.js +15 -2861
  762. package/dist/session/can.js +26 -0
  763. package/dist/session/can.js.map +1 -0
  764. package/dist/session/commandReplay.d.ts +8 -2
  765. package/dist/session/commandReplay.js +293 -0
  766. package/dist/session/commandReplay.js.map +1 -0
  767. package/dist/session/debug.js +151 -0
  768. package/dist/session/debug.js.map +1 -0
  769. package/dist/session/delay.js +62 -0
  770. package/dist/session/delay.js.map +1 -0
  771. package/dist/session/delta.d.ts +14 -1
  772. package/dist/session/delta.js +407 -0
  773. package/dist/session/delta.js.map +1 -0
  774. package/dist/session/entityState.js +415 -0
  775. package/dist/session/entityState.js.map +1 -0
  776. package/dist/session/local.d.ts +47 -5
  777. package/dist/session/local.js +670 -0
  778. package/dist/session/local.js.map +1 -0
  779. package/dist/session/memory.d.ts +20 -2
  780. package/dist/session/memory.js +131 -0
  781. package/dist/session/memory.js.map +1 -0
  782. package/dist/session/protocol.d.ts +325 -31
  783. package/dist/session/protocol.js +55 -0
  784. package/dist/session/protocol.js.map +1 -0
  785. package/dist/session/remote.d.ts +74 -12
  786. package/dist/session/remote.js +1394 -0
  787. package/dist/session/remote.js.map +1 -0
  788. package/dist/session/replay.d.ts +11 -2
  789. package/dist/session/replay.js +160 -0
  790. package/dist/session/replay.js.map +1 -0
  791. package/dist/session/seed.js +12 -0
  792. package/dist/session/seed.js.map +1 -0
  793. package/dist/session/share.d.ts +5 -1
  794. package/dist/session/share.js +94 -0
  795. package/dist/session/share.js.map +1 -0
  796. package/dist/session/socket.d.ts +1 -1
  797. package/dist/session/socket.js +29 -0
  798. package/dist/session/socket.js.map +1 -0
  799. package/dist/session/wire.d.ts +5 -0
  800. package/dist/session/wire.js +84 -0
  801. package/dist/session/wire.js.map +1 -0
  802. package/dist/session/worker.d.ts +77 -12
  803. package/dist/session/worker.js +499 -0
  804. package/dist/session/worker.js.map +1 -0
  805. package/dist/shared.d.ts +31 -5
  806. package/dist/shared.js +166 -0
  807. package/dist/shared.js.map +1 -0
  808. package/dist/sides.d.ts +9 -3
  809. package/dist/sides.js +149 -0
  810. package/dist/sides.js.map +1 -0
  811. package/dist/sight.js +85 -0
  812. package/dist/sight.js.map +1 -0
  813. package/dist/simulate-worker.js +1 -1
  814. package/dist/simulate.d.ts +12 -8
  815. package/dist/{simulate-oXBiw1Ff.js → simulate.js} +10 -11
  816. package/dist/simulate.js.map +1 -0
  817. package/dist/smart.js +77 -0
  818. package/dist/smart.js.map +1 -0
  819. package/dist/spatial.d.ts +32 -16
  820. package/dist/spatial.js +234 -0
  821. package/dist/spatial.js.map +1 -0
  822. package/dist/spawning.d.ts +1 -0
  823. package/dist/spawning.js +224 -0
  824. package/dist/spawning.js.map +1 -0
  825. package/dist/stances.d.ts +6 -3
  826. package/dist/stances.js +169 -0
  827. package/dist/stances.js.map +1 -0
  828. package/dist/start.d.ts +10 -10
  829. package/dist/start.js +75 -0
  830. package/dist/start.js.map +1 -0
  831. package/dist/stats.d.ts +42 -16
  832. package/dist/stats.js +290 -0
  833. package/dist/stats.js.map +1 -0
  834. package/dist/summoned.d.ts +52 -0
  835. package/dist/summoned.js +38 -0
  836. package/dist/summoned.js.map +1 -0
  837. package/dist/summons.d.ts +10 -13
  838. package/dist/summons.js +271 -0
  839. package/dist/summons.js.map +1 -0
  840. package/dist/systems/abilities.js +224 -0
  841. package/dist/systems/abilities.js.map +1 -0
  842. package/dist/systems/combat.d.ts +35 -1
  843. package/dist/systems/combat.js +677 -0
  844. package/dist/systems/combat.js.map +1 -0
  845. package/dist/systems/combatTold.d.ts +3 -1
  846. package/dist/systems/combatTold.js +85 -0
  847. package/dist/systems/combatTold.js.map +1 -0
  848. package/dist/systems/construction.js +80 -0
  849. package/dist/systems/construction.js.map +1 -0
  850. package/dist/systems/economy.d.ts +0 -6
  851. package/dist/systems/economy.js +128 -0
  852. package/dist/systems/economy.js.map +1 -0
  853. package/dist/systems/fog.d.ts +1 -1
  854. package/dist/systems/fog.js +120 -0
  855. package/dist/systems/fog.js.map +1 -0
  856. package/dist/systems/life.js +32 -0
  857. package/dist/systems/life.js.map +1 -0
  858. package/dist/systems/movement.d.ts +24 -12
  859. package/dist/systems/movement.js +1247 -0
  860. package/dist/systems/movement.js.map +1 -0
  861. package/dist/systems/orders.js +64 -0
  862. package/dist/systems/orders.js.map +1 -0
  863. package/dist/systems/production.js +322 -0
  864. package/dist/systems/production.js.map +1 -0
  865. package/dist/systems/productionQueue.js +120 -0
  866. package/dist/systems/productionQueue.js.map +1 -0
  867. package/dist/systems/victory.d.ts +1 -1
  868. package/dist/systems/victory.js +56 -0
  869. package/dist/systems/victory.js.map +1 -0
  870. package/dist/talk.d.ts +6 -6
  871. package/dist/talk.js +153 -0
  872. package/dist/talk.js.map +1 -0
  873. package/dist/targeting.d.ts +142 -0
  874. package/dist/targeting.js +49 -0
  875. package/dist/targeting.js.map +1 -0
  876. package/dist/tech.d.ts +20 -3
  877. package/dist/tech.js +239 -0
  878. package/dist/tech.js.map +1 -0
  879. package/dist/techTree.d.ts +7 -0
  880. package/dist/techTree.js +90 -0
  881. package/dist/techTree.js.map +1 -0
  882. package/dist/terrain.d.ts +59 -7
  883. package/dist/terrain.js +389 -0
  884. package/dist/terrain.js.map +1 -0
  885. package/dist/terrainSave.d.ts +6 -0
  886. package/dist/terrainSave.js +74 -0
  887. package/dist/terrainSave.js.map +1 -0
  888. package/dist/testing.d.ts +8 -7
  889. package/dist/testing.js +13 -739
  890. package/dist/testing.js.map +1 -1
  891. package/dist/tiles.d.ts +1 -1
  892. package/dist/tiles.js +43 -0
  893. package/dist/tiles.js.map +1 -0
  894. package/dist/timers.d.ts +29 -4
  895. package/dist/timers.js +242 -0
  896. package/dist/timers.js.map +1 -0
  897. package/dist/tomes.d.ts +4 -4
  898. package/dist/tomes.js +94 -0
  899. package/dist/tomes.js.map +1 -0
  900. package/dist/trade.js +103 -0
  901. package/dist/trade.js.map +1 -0
  902. package/dist/transport.d.ts +6 -1
  903. package/dist/transport.js +281 -0
  904. package/dist/transport.js.map +1 -0
  905. package/dist/tunables.d.ts +10 -3
  906. package/dist/tunables.js +56 -0
  907. package/dist/tunables.js.map +1 -0
  908. package/dist/unitResources.d.ts +67 -0
  909. package/dist/unitResources.js +266 -0
  910. package/dist/unitResources.js.map +1 -0
  911. package/dist/upkeep.d.ts +6 -1
  912. package/dist/upkeep.js +26 -0
  913. package/dist/upkeep.js.map +1 -0
  914. package/dist/veterancy.d.ts +8 -3
  915. package/dist/veterancy.js +131 -0
  916. package/dist/veterancy.js.map +1 -0
  917. package/dist/vision.d.ts +36 -0
  918. package/dist/vision.js +133 -0
  919. package/dist/vision.js.map +1 -0
  920. package/dist/walls.d.ts +1 -1
  921. package/dist/walls.js +278 -0
  922. package/dist/walls.js.map +1 -0
  923. package/dist/world.d.ts +606 -88
  924. package/dist/world.js +1263 -0
  925. package/dist/world.js.map +1 -0
  926. package/package.json +2 -2
  927. package/dist/ai.js.map +0 -1
  928. package/dist/attributes.d.ts +0 -66
  929. package/dist/brain-BvVdUhX8.js +0 -7659
  930. package/dist/brain-BvVdUhX8.js.map +0 -1
  931. package/dist/builds-C6LfgvEU.js +0 -460
  932. package/dist/builds-C6LfgvEU.js.map +0 -1
  933. package/dist/coreComponents-syuh2fPG.js +0 -5149
  934. package/dist/coreComponents-syuh2fPG.js.map +0 -1
  935. package/dist/debugCommands-CzjrSm66.js +0 -14739
  936. package/dist/debugCommands-CzjrSm66.js.map +0 -1
  937. package/dist/determinism-BCymQwiE.js +0 -518
  938. package/dist/determinism-BCymQwiE.js.map +0 -1
  939. package/dist/game-DiJEN-Ks.js +0 -5800
  940. package/dist/game-DiJEN-Ks.js.map +0 -1
  941. package/dist/index.js.map +0 -1
  942. package/dist/inspect-D9dWHmZ0.js.map +0 -1
  943. package/dist/local-Dkovq42k.js +0 -1379
  944. package/dist/local-Dkovq42k.js.map +0 -1
  945. package/dist/missionRules-C-bGxm0Q.js.map +0 -1
  946. package/dist/navigation-worker.js.map +0 -1
  947. package/dist/packs-g5thvmGn.js +0 -3199
  948. package/dist/packs-g5thvmGn.js.map +0 -1
  949. package/dist/profiles-B3NS9jwk.js.map +0 -1
  950. package/dist/server.js.map +0 -1
  951. package/dist/simulate-oXBiw1Ff.js.map +0 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"remote.js","names":[],"sources":["../../src/session/remote.ts"],"sourcesContent":["import { worldFailed } from '#engine/engineEvents'\nimport { hasGroundSpeeds, navigationSpeedOn } from '#engine/groundSpeed'\nimport { type DataKind, type DataValues, type GameData, mergeValues, redefineIn, redefinitions, restoreRedefinitions } from '#engine/gameData'\nimport { type GameCommandMessage, type GameHostMessage, type HostToPlayer, isServerMessage, readHostMessage, type ServerToPlayer } from './wire'\nimport { errorFields } from '#engine/log'\nimport type { GameMap, MapCamera, MapDoodad, MapEnvironment, MapPath, MapRegion } from '#engine/map'\nimport { footprintOf } from '#engine/defs'\nimport type { EntityId, PlayerId } from '#engine/entity'\nimport { formationPreview, type FormationUnit } from '#engine/formation'\nimport type { Rules } from '#engine/game'\nimport { createRegistry } from '#engine/game'\nimport { BuildGrid } from '#engine/grid'\nimport type { Vec2 } from '#engine/math'\nimport { AirNavigation } from '#engine/navigation/air'\nimport type { Navigation } from '#engine/navigation/navigation'\nimport { RecastNavigation, type RecastNavigationOptions } from '#engine/navigation/recast'\nimport { placementCells, siteOf } from '#engine/orders/build'\nimport type { Registry } from '#engine/registry'\nimport { loadTerrain, saveTerrain, type TerrainSave } from '#engine/terrainSave'\nimport {\n\tapplyTerrainPatch,\n\tgroundOf,\n\tisGroundChanges,\n\tMissingGround,\n\tsavedGround,\n\ttype SavedGround,\n\tterrainPatchProblem,\n\tapplyGroundChanges\n} from '#engine/ground'\nimport type { Terrain } from '#engine/terrain'\nimport { groundKnownTo } from '#engine/cellLayers'\nimport type { World } from '#engine/world'\nimport { type MessageRef, toMessage } from '#engine/messages'\nimport { LocalSession, endSharedCaptures, shareCaptures } from './local'\nimport { askDebug, DEBUG_EVERY, LocalDebug, RemoteDebug } from './debug'\nimport { apply, bytesByKey, type Delta, diff, type FogMessage, type Frame, quantize } from './delta'\nimport {\n\ttype CampInfo,\n\ttype EntityState,\n\ttype FogState,\n\ttype GameSession,\n\tisFiniteNumber,\n\ttype PlayerCommand,\n\tPROTOCOL_VERSION,\n\tprotocolMismatch,\n\treadMessage,\n\ttype SessionEvent,\n\ttype Snapshot,\n\ttype SessionCan,\n\ttype SessionDebug\n} from './protocol'\n\n/*\n * A session over a wire. The simulation runs on one side (`SessionHost`, a server or a page standing in for one), each\n * player's screen on the other (`RemoteSession`). Between them only text goes, as it would over a WebSocket: what the\n * host sends a player is what that player's `LocalSession` seat would give, as JSON, and what a player sends is their\n * commands. Everything the screen asks besides (the fog, whether it can build somewhere, the way a unit would walk) is\n * answered on its own side, from what it has been told\n */\n\n/**\n * One end of a connection: text in, text out, in order\n *\n * @beta\n */\nexport interface Transport {\n\t/** Sends one text message to the other end */\n\tsend(message: string): void\n\t/** What comes in from the other end. One handler: a later one takes the place of the one before */\n\tonMessage(handler: (message: string) => void): void\n\t/** Told when the other end closes */\n\tonClose(handler: () => void): void\n\t/** Closes the connection; the other end's `onClose` handler is told */\n\tclose(): void\n}\n\n/**\n * An end of a `loopback`, which counts what it sends: for a budget of bandwidth\n *\n * @beta\n */\nexport interface LoopbackEnd extends Transport {\n\t/** Characters sent, a byte each as the JSON goes over a WebSocket of mostly ASCII */\n\treadonly bytesSent: number\n\t/** How many messages have been sent through this end */\n\treadonly messagesSent: number\n}\n\n/**\n * A connection inside the page, standing in for a network (`loopback`)\n *\n * @beta\n */\nexport interface LoopbackOptions {\n\t/** Milliseconds each message takes, one way */\n\tlatency?: number\n\t/** Milliseconds a message may take on top of that, at random: never out of order, the way a WebSocket keeps it */\n\tjitter?: number\n\t/**\n\t * The share of the snapshots that never arrive, 0..1, for what a lossy connection does to the screen. Only from the\n\t * host: the welcome and the player's commands always do. The events of a snapshot lost are lost with it\n\t */\n\tloss?: number\n\t/** Random numbers for jitter and loss: `Math.random` when left out (the simulation does not use it) */\n\trandom?: () => number\n}\n\n/**\n * Two ends of a connection in the page, `[client, host]`: everything sent is text, delivered after the latency the\n * options give. The whole networked way, in one page and in tests\n *\n * @beta\n */\nexport function loopback(options: LoopbackOptions = {}): [LoopbackEnd, LoopbackEnd] {\n\tconst { latency = 0, jitter = 0, loss = 0, random = Math.random } = options\n\n\t/** One end: what it is handed to deliver, and the transport its side holds */\n\tclass End implements LoopbackEnd {\n\t\tpeer!: End\n\t\tbytesSent = 0\n\t\tmessagesSent = 0\n\t\tprivate handler: (message: string) => void = () => {}\n\t\tprivate closed: () => void = () => {}\n\t\tprivate open = true\n\t\t/** When the last message sent is due: none overtakes the one before */\n\t\tprivate last = 0\n\n\t\tconstructor(private readonly lossy: boolean) {}\n\n\t\tsend(message: string): void {\n\t\t\tif (!this.open) return\n\t\t\tthis.bytesSent += message.length\n\t\t\tthis.messagesSent++\n\t\t\t// snapshots only: the welcome comes first, and commands go the other way\n\t\t\tif (this.lossy && loss > 0 && message.startsWith('{\"type\":\"delta\"') && random() < loss) return\n\t\t\tconst due = Math.max(performance.now() + latency + random() * jitter, this.last)\n\t\t\tthis.last = due\n\t\t\tconst { peer } = this\n\t\t\tsetTimeout(() => peer.deliver(message), Math.max(due - performance.now(), 0))\n\t\t}\n\n\t\tdeliver(message: string): void {\n\t\t\tif (this.open) this.handler(message)\n\t\t}\n\n\t\tonMessage(handler: (message: string) => void): void {\n\t\t\tthis.handler = handler\n\t\t}\n\n\t\tonClose(handler: () => void): void {\n\t\t\tthis.closed = handler\n\t\t}\n\n\t\tclose(): void {\n\t\t\tthis.shut()\n\t\t\t// the other end hears of it once what was on its way has arrived\n\t\t\tconst { peer } = this\n\t\t\tsetTimeout(() => peer.shut(), Math.max(this.last - performance.now(), latency, 0))\n\t\t}\n\n\t\tshut(): void {\n\t\t\tif (!this.open) return\n\t\t\tthis.open = false\n\t\t\tthis.closed()\n\t\t}\n\t}\n\n\tconst client = new End(false)\n\tconst host = new End(true)\n\tclient.peer = host\n\thost.peer = client\n\treturn [client, host]\n}\n\n// ---- what goes over the wire: `wire.ts`\n\n/** Whether what a player sent as a command is one to look at: an object with a type. Its fields are its definition's to check */\nconst isCommand = (value: unknown): value is PlayerCommand =>\n\ttypeof value === 'object' && value !== null && !Array.isArray(value) && typeof (value as { type?: unknown }).type === 'string'\n\n/**\n * Runs of equal values: how many 0s, then how many 1s, and so on\n *\n * @internal\n */\nexport function toRuns(cells: Uint8Array): number[] {\n\tconst runs: number[] = []\n\tlet value = 0\n\tlet count = 0\n\tfor (let i = 0; i < cells.length; i++) {\n\t\tconst cell = cells[i] ? 1 : 0\n\t\tif (cell === value) count++\n\t\telse {\n\t\t\truns.push(count)\n\t\t\tvalue = cell\n\t\t\tcount = 1\n\t\t}\n\t}\n\truns.push(count)\n\treturn runs\n}\n\n/**\n * Cells back from `toRuns`, into `out`\n *\n * @internal\n */\nexport function fromRuns(runs: readonly number[], out: Uint8Array): Uint8Array {\n\tlet at = 0\n\tlet value = 0\n\tfor (const run of runs) {\n\t\tout.fill(value, at, Math.min(at + run, out.length))\n\t\tat += run\n\t\tvalue ^= 1\n\t}\n\treturn out\n}\n\n/** The fog for the wire: nothing of its cells when the whole map is lit, which they say nothing about then */\nconst fogMessage = (fog: FogState): FogMessage =>\n\tfog.revealed ? { revealed: true, visible: [], explored: [] } : { revealed: false, visible: toRuns(fog.visible), explored: toRuns(fog.explored) }\n\n/** The runs of a team's fog, by its cells, as they were at a version of the fog: the seats of a team share them */\nconst fogRuns = new WeakMap<Uint8Array, { version: number; message: FogMessage }>()\nconst revealedFog: FogMessage = { revealed: true, visible: [], explored: [] }\n\n/** The fog for the wire, its runs made once for every seat of a team while it stays as it is */\nfunction fogMessageOf(fog: FogState): FogMessage {\n\tif (fog.revealed) return revealedFog\n\tconst known = fogRuns.get(fog.visible)\n\tif (known && known.version === fog.version) return known.message\n\tconst message = fogMessage(fog)\n\tfogRuns.set(fog.visible, { version: fog.version, message })\n\treturn message\n}\n\n/**\n * What each state told was rounded to (`quantize`), by the very object: a state that did not change is the object it\n * was (`LocalSession` hands back what it told while it still says the truth), so it is rounded once and stays the same\n * object round after round, which the diff then passes over without looking inside (`diff`)\n */\nconst quantizedStates = new WeakMap<EntityState, EntityState>()\nfunction quantizedOf(state: EntityState): EntityState {\n\tlet made = quantizedStates.get(state)\n\tif (!made) quantizedStates.set(state, (made = quantize(state)))\n\treturn made\n}\n\n/**\n * The entities of a frame as the wire has them (`quantize`), one list between the seats of a round told the very same\n * (the seats of a side, the observers: what they are told of an entity is one object between them, `LocalSession`), so\n * that it is rounded once and a diff of the same two lists is worked out once (`diff`). `made` is this round's so far\n */\nfunction quantizedList(entities: readonly EntityState[], made: { told: readonly EntityState[]; sent: EntityState[] }[]): EntityState[] {\n\tfor (const { told, sent } of made) {\n\t\tif (told.length !== entities.length) continue\n\t\tlet alike = true\n\t\tfor (let i = 0; i < told.length; i++) {\n\t\t\tif (told[i] !== entities[i]) {\n\t\t\t\talike = false\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tif (alike) return sent\n\t}\n\tconst sent = entities.map(quantizedOf)\n\tmade.push({ told: entities, sent })\n\treturn sent\n}\n\n/** Milliseconds between two pings, to measure the time to the host and back */\nconst PING_EVERY = 2000\n\n/** Seconds of jitter the interpolation buffer makes room for, at most */\nexport const MAX_JITTER = 0.2\n\n/**\n * Seconds with no snapshot after which the host is taken to have gone quiet, at the least (three of its usual gaps\n * between two where they are longer), as it does while its world stands still (a replay held, a game paused): the\n * screen then comes to the newest snapshot it has, there being nothing to make room for\n */\nconst QUIET = 0.5\n\n/**\n * What a player's side keeps and how often it asks, set by `ConnectOptions`: each the number it has always been when\n * left out\n *\n * @beta\n */\nexport interface PlayerLimits {\n\t/** Milliseconds between two pings, to measure the time to the host and back. 2000 when left out */\n\tpingEvery?: number\n\t/** Seconds of jitter the interpolation buffer makes room for, at most: a spike of lateness is not waited out for good. 0.2 when left out */\n\tmaxJitter?: number\n\t/** Snapshots waiting for the screen, at most: past that the oldest is folded into the next. 64 when left out */\n\tkeptSnapshots?: number\n\t/** Events the folded snapshots carry together, at most: the newest kept. 2000 when left out */\n\tkeptScreenEvents?: number\n}\n\n/**\n * Where a host's time went over a while: see `SessionHost.takeTiming`\n *\n * @beta\n */\nexport interface HostTiming {\n\t/** When the counting started, `performance.now()` */\n\tsince: number\n\t/** How many simulation ticks were stepped in the period */\n\tticks: number\n\t/** Milliseconds the ticks took, added up, and the longest */\n\ttickTime: number\n\t/** The longest a single tick took, in milliseconds */\n\ttickMax: number\n\t/** Rounds of sending everyone what changed */\n\tsends: number\n\t/** Milliseconds the rounds of sending took, added up */\n\tsendTime: number\n\t/** The longest a single round of sending took, in milliseconds */\n\tsendMax: number\n\t/**\n\t * Where the sending's milliseconds went, added up over the seats: what each player may know taken from the world\n\t * (`capture`), its positions rounded (`quantize`), the fog made runs (`fog`), what changed since the frame they\n\t * have (`diff`), made text (`stringify`)\n\t *\n\t * @beta\n\t */\n\tparts: { capture: number; quantize: number; fog: number; diff: number; stringify: number }\n\t/**\n\t * Characters of the rounds' text, to every seat, before any compression of the wire\n\t *\n\t * @beta\n\t */\n\tbytes: number\n\t/**\n\t * Those characters by what they carry, when the host counts them (`SessionHostOptions.bytesByKey`): each field of\n\t * the entities added and changed (`entity.health`, `entity.own.abilities`), the other parts (`rest.players`, `rest.fog`),\n\t * `events`, `removed`, and the rest (ids, brackets) as `other`. They add up to `bytes`\n\t *\n\t * @beta\n\t */\n\tkeys?: Record<string, number>\n}\n\nconst emptyTiming = (since: number, byKey = false): HostTiming => ({\n\tsince,\n\tticks: 0,\n\ttickTime: 0,\n\ttickMax: 0,\n\tsends: 0,\n\tsendTime: 0,\n\tsendMax: 0,\n\tparts: { capture: 0, quantize: 0, fog: 0, diff: 0, stringify: 0 },\n\tbytes: 0,\n\t...(byKey && { keys: {} })\n})\n\n/** Frames kept on either side, at most: more than a second and a half of ticks a player has not said it got */\nconst KEPT_FRAMES = 64\n\n/**\n * Bytes of the frames kept for one player, at most (`SessionHostOptions.keptBytes`): 8 MB, some thirty frames of a\n * thousand units (a frame of them is about 250 KB). A player who has said nothing for longer is sent everything again\n */\nconst KEPT_BYTES = 8 * 1024 * 1024\n\n/** What each list of entities a frame keeps takes as the wire writes it: one list between the seats of a side (`quantizedList`) */\nconst listBytes = new WeakMap<object, number>()\n\n/** Entities of a list written out to tell what the list takes: the rest are taken to be as big */\nconst SAMPLED = 8\n\n/**\n * What a frame kept for a player takes, about: its entities as the wire writes them (some of them written out, the rest\n * taken to be as big: writing out all of a thousand units' at every send costs more than the send itself), its fog,\n * its players\n */\nfunction frameBytes(frame: Frame): number {\n\tconst { entities, players } = frame.snapshot\n\tlet bytes = listBytes.get(entities)\n\tif (bytes === undefined) {\n\t\tconst sampled = Math.min(entities.length, SAMPLED)\n\t\tlet written = 0\n\t\tfor (let i = 0; i < sampled; i++) written += JSON.stringify(entities[Math.floor((i * entities.length) / sampled)]).length\n\t\tlistBytes.set(entities, (bytes = sampled ? Math.round((written / sampled) * entities.length) : 0))\n\t}\n\tlet fog = listBytes.get(frame.fog)\n\tif (fog === undefined) listBytes.set(frame.fog, (fog = JSON.stringify(frame.fog).length))\n\tlet told = listBytes.get(players)\n\tif (told === undefined) listBytes.set(players, (told = JSON.stringify(players).length))\n\treturn bytes + fog + told\n}\n\n/**\n * Snapshots waiting for the screen, at most (`RemoteSession.update`): three seconds of them at 20 a second. A page\n * whose screen stops asking (a tab in the background) folds the oldest into the next, their events kept, rather than\n * keeping every one for as long as it is away\n */\nconst KEPT_SNAPSHOTS = 64\n\n/** Events the folded snapshots carry together, at most: the newest kept. What is the screen's only (the state is in the snapshot) */\nconst KEPT_SCREEN_EVENTS = 2000\n\n// ---- the host\n\n/** A player connected to a host */\ninterface Seat {\n\ttransport: Transport\n\tsession: LocalSession\n\t/** The debug tools' view of the world, for a player who may use them and asked (`debug`), and when it last went */\n\tdebug?: { view: LocalDebug; sentAt: number }\n\t/** What was sent at each tick, until the player has said it got a later one */\n\tframes: Map<number, Frame>\n\t/** What each of those frames takes (`frameBytes`), and all of them together */\n\tframeSizes: Map<number, number>\n\tkeptBytes: number\n\t/** The last tick the player said it got whose frame was still kept: deltas are made against it. None yet before the first */\n\tacked: number\n\t/** The last tick the player said it got at all, kept or not: what it has heard up to */\n\theardUpTo: number\n\t/**\n\t * The whole frame (a delta against nothing) last sent and not yet said to be had, and when it went: no other whole\n\t * one goes until it is, or its answer is overdue (RV11)\n\t */\n\twhole?: { tick: number; at: number }\n\t/**\n\t * Events the player has not said it got: each batch by its own number (`n`, as talk goes out between ticks too, RV14),\n\t * the tick it went out with, and when it last was sent\n\t */\n\tevents: { tick: number; n: number; events: SessionEvent[]; sentAt?: number }[]\n\t/** The number of the last batch of events made for the player */\n\teventsMade: number\n\t/** When the frame of each tick went out, for the time an answer takes */\n\tsentAt: Map<number, number>\n\t/** Milliseconds from sending a frame to hearing it got there, evened out */\n\troundTrip: number\n\t/** The tick of the world when the player last said it got something, or connected */\n\theard: number\n\t/** What the host answers of its own, with the next snapshot: commands the limit let go, refused (`allow`) */\n\tanswers: SessionEvent[]\n\t/** The parts of the ground sent: each goes once */\n\tgroundSent: Set<number>\n\t/** The transport loses nothing and keeps the order (`connect`'s `inOrder`): what went is had, with no answer waited for */\n\tinOrder: boolean\n}\n\n/**\n * What a `SessionHost` is made with: its send rate, catching-up limit, watchdog and error callbacks and whether it owns its world\n *\n * @beta\n */\nexport interface SessionHostOptions {\n\t/** Snapshots a second sent to each player, at most: the simulation runs at its tick rate all the same. 20 when left out */\n\tsendRate?: number\n\t/**\n\t * Ticks one update catches up at most. A host that fell further behind (a stall, a machine too slow for the game)\n\t * lets the rest go, and the game runs slower for a moment, rather than spiralling. 8 when left out\n\t */\n\tmaxTicksPerUpdate?: number\n\t/** Told of a tick that took longer than a tick lasts, with how many milliseconds: the watchdog */\n\tonSlowTick?: (milliseconds: number, tick: number) => void\n\t/**\n\t * Told when stepping the world threw, running by the clock (`start`): the host has stopped by then, and what\n\t * becomes of the game is whoever runs it's to say. Said in the world's log, and nothing more, when left out. An\n\t * error is never a reason for the process to go\n\t */\n\tonError?: (error: unknown) => void\n\t/**\n\t * The world is the host's, and goes with it (`dispose`): for a server's game, or a game run in the page behind a\n\t * wire. Not for a world the page plays itself and only lets others watch (`recordGame`, `shareGame`). No when left out\n\t */\n\townsWorld?: boolean\n\t/**\n\t * Seconds of the game a player may go without saying it got what it was sent, before its seat is closed: what is\n\t * kept for it to send again (the events it has not said it got) would grow for as long as it says nothing. 15 when\n\t * left out; `Infinity` never closes one\n\t */\n\tdropSilentAfter?: number\n\t/**\n\t * Ticks of events kept for a player who has not said they got them, at most: past that the oldest that already went\n\t * are let go, not sent again. They are there already over a transport that loses nothing (a worker, a WebSocket),\n\t * so this bounds only a player who goes on hearing but has stopped answering (a page frozen in the background). 600\n\t * when left out\n\t *\n\t * @beta\n\t */\n\tkeptEvents?: number\n\t/**\n\t * Frames kept for each player to make a delta against, at most: a player who says nothing for longer is sent\n\t * everything again, once, and nothing more until it answers (or its answer is overdue); an answer to a frame let go\n\t * still says the player is there. 64 when left out (more than a second and a half of ticks)\n\t *\n\t * @beta\n\t */\n\tkeptFrames?: number\n\t/**\n\t * Bytes of the frames kept for each player, at most, summed (what each takes as the wire writes it): a player who\n\t * says nothing while a thousand units fight is sent everything again sooner than `keptFrames` would. 8 MB when left\n\t * out\n\t *\n\t * @beta\n\t */\n\tkeptBytes?: number\n\t/**\n\t * Characters of the ground in one message, for a player who does not have the map and asks for it a part at a\n\t * time: well under what a connection holds. 262144 when left out\n\t *\n\t * @beta\n\t */\n\tgroundPart?: number\n\t/**\n\t * Whether `takeTiming` says what the characters sent were spent on, field by field (`HostTiming.keys`): what a\n\t * measure of the wire asks for (`net.bench.ts`), at the cost of writing each field again. No when left out\n\t *\n\t * @beta\n\t */\n\tbytesByKey?: boolean\n}\n\n/**\n * Runs a world for players connected to it over transports: the server's job, done anywhere. It steps the world by\n * the clock (`start`) or by hand (`update`), and at most `sendRate` times a second sends every player what changed in\n * what they may know (`Delta`), as their `LocalSession` seat sees it: against the last tick they said they got, with\n * the events they have not. Their commands come in as they arrive, and go in at the next tick\n *\n * @beta\n */\nexport class SessionHost {\n\tprivate readonly seats = new Set<Seat>()\n\tprivate accumulator = 0\n\tprivate sinceSent = Infinity\n\tprivate timer?: ReturnType<typeof setInterval>\n\tprivate last = 0\n\tprivate readonly sendEvery: number\n\t/** Simulation speed multiplier, 0 pauses */\n\tspeed = 1\n\n\tconstructor(\n\t\t/** The world the host steps and sends its players views of */\n\t\treadonly world: World,\n\t\toptions: SessionHostOptions = {}\n\t) {\n\t\tthis.sendEvery = 1 / (options.sendRate ?? 20)\n\t\tthis.maxTicks = options.maxTicksPerUpdate ?? 8\n\t\tthis.onSlowTick = options.onSlowTick\n\t\tthis.ownsWorld = options.ownsWorld ?? false\n\t\tthis.dropSilentAfter = options.dropSilentAfter ?? 15\n\t\tthis.keptEvents = options.keptEvents ?? 600\n\t\tthis.keptFrames = Math.max(2, options.keptFrames ?? KEPT_FRAMES)\n\t\tthis.keptBytes = Math.max(1, options.keptBytes ?? KEPT_BYTES)\n\t\tthis.groundPart = Math.max(1, options.groundPart ?? GROUND_PART)\n\t\tthis.byKey = options.bytesByKey ?? false\n\t\tthis.timing = emptyTiming(performance.now(), this.byKey)\n\t\tthis.onError = options.onError\n\t\t// a game that ends on an error says so to everyone at it, once\n\t\tthis.stopFailed = world.events.on(worldFailed, (failure) => {\n\t\t\tfor (const seat of this.seats) this.post(seat, { type: 'failed', message: failure.message })\n\t\t})\n\t}\n\n\tprivate readonly onError?: (error: unknown) => void\n\tprivate readonly stopFailed: () => void\n\n\tprivate readonly dropSilentAfter: number\n\tprivate readonly keptFrames: number\n\tprivate readonly keptBytes: number\n\tprivate readonly groundPart: number\n\tprivate readonly keptEvents: number\n\t/** Whether the characters sent are counted by what they carry (`bytesByKey`) */\n\tprivate readonly byKey: boolean\n\n\tprivate readonly ownsWorld: boolean\n\n\tprivate readonly maxTicks: number\n\tprivate readonly onSlowTick?: (milliseconds: number, tick: number) => void\n\n\t/**\n\t * Seats a player at the world, on the host's end of a transport. The welcome goes out at once: everything the player\n\t * may know, also to one who comes back. `readOnly` for who only watches: their commands go nowhere but their lines\n\t * of chat and their pings, which go to who watches alone (`observers`, said by `name`); and with `observer` they see\n\t * everything, from `player`'s side. `allow` decides on each command before it goes in: a limit of how many, a game\n\t * paused. One it lets go is answered, refused (the `command` event of its `seq`): with what it gives for why, or\n\t * `cannotDoThat` for `false`. `inOrder` for a transport that loses nothing and keeps the order (a worker's messages):\n\t * each frame is the base of the next once it went, with no answer waited for, so the player always gets what changed\n\t * since the frame it has, and takes it in without looking over the rest\n\t */\n\tconnect(\n\t\tplayer: PlayerId,\n\t\ttransport: Transport,\n\t\toptions: { readOnly?: boolean; observer?: boolean; allow?: () => boolean | MessageRef; name?: string; inOrder?: boolean } = {}\n\t): void {\n\t\tconst session = new LocalSession(this.world, player, { observer: options.observer })\n\t\tconst seat: Seat = {\n\t\t\ttransport,\n\t\t\tsession,\n\t\t\tframes: new Map(),\n\t\t\tframeSizes: new Map(),\n\t\t\tkeptBytes: 0,\n\t\t\tacked: -1,\n\t\t\theardUpTo: -1,\n\t\t\tevents: [],\n\t\t\teventsMade: 0,\n\t\t\tsentAt: new Map(),\n\t\t\troundTrip: 100,\n\t\t\theard: this.world.tick,\n\t\t\tanswers: [],\n\t\t\tgroundSent: new Set(),\n\t\t\tinOrder: options.inOrder ?? false\n\t\t}\n\t\tthis.seats.add(seat)\n\t\ttransport.onMessage((text) => {\n\t\t\t// the player's word, of any shape: what is not as it should be is dropped (a command's fields are checked\n\t\t\t// further on, by its definition)\n\t\t\tconst message = readMessage(text)\n\t\t\tif (!message) return\n\t\t\tif (message.type === 'ack') {\n\t\t\t\tif (isFiniteNumber(message.tick)) this.acknowledge(seat, message.tick, isFiniteNumber(message.events) ? message.events : undefined)\n\t\t\t} else if (message.type === 'ping') {\n\t\t\t\tif (isFiniteNumber(message.at)) this.post(seat, { type: 'pong', at: message.at })\n\t\t\t} else if (message.type === 'ground') {\n\t\t\t\t// a part of the ground the world started as, one at a time as asked: never more than a part waits to go\n\t\t\t\t// (each part once: a screen asks for each once, and the ground is many times what asks for it, RV37)\n\t\t\t\tconst parts = this.groundParts()\n\t\t\t\tconst { part } = message\n\t\t\t\tif (parts && Number.isInteger(part) && (part as number) >= 0 && (part as number) < parts.length && !seat.groundSent.has(part as number)) {\n\t\t\t\t\tseat.groundSent.add(part as number)\n\t\t\t\t\tthis.post(seat, { type: 'ground', part: part as number, parts: parts.length, text: parts[part as number] })\n\t\t\t\t}\n\t\t\t} else if (message.type === 'debug') {\n\t\t\t\t// only a player the world lets use the debug tools (`world.debugPlayers`): anyone can send anything\n\t\t\t\tif (!this.world.debugPlayers.has(player)) return\n\t\t\t\tseat.debug ??= { view: new LocalDebug(this.world), sentAt: -Infinity }\n\t\t\t\taskDebug(seat.debug.view, message)\n\t\t\t\tseat.debug.sentAt = -Infinity\n\t\t\t} else if (message.type === 'command' && options.readOnly) {\n\t\t\t\t// who watches says a line or marks a spot, for who watches alone: nothing else of theirs goes in\n\t\t\t\tconst { command } = message\n\t\t\t\tif (!isCommand(command) || (command.type !== 'chat' && command.type !== 'ping')) return\n\t\t\t\tsession.send({ ...command, to: 'observers', by: options.name ?? 'A watcher' } as PlayerCommand)\n\t\t\t\tthis.heardOutside = true\n\t\t\t} else if (message.type === 'command') {\n\t\t\t\t// every command counts against the limit, one of no shape as well (RV37)\n\t\t\t\tconst allowed = options.allow?.() ?? true\n\t\t\t\tconst seq = isFiniteNumber(message.seq) ? message.seq : undefined\n\t\t\t\tif (!isCommand(message.command)) return\n\t\t\t\t// what who watches says is theirs: a player's line to them would tell them what the side knows\n\t\t\t\tif ((message.command.type === 'chat' || message.command.type === 'ping') && (message.command as { to?: unknown }).to === 'observers') return\n\t\t\t\tif (allowed === true) {\n\t\t\t\t\tsession.send(message.command, seq)\n\t\t\t\t\t// talk, carried out at once: told now, a paused game's too (RV14)\n\t\t\t\t\tif (this.world.registry.command(message.command.type)?.outsideTick) this.heardOutside = true\n\t\t\t\t}\n\t\t\t\t// one let go is answered, refused: a screen waits on its number otherwise (RV14)\n\t\t\t\telse if (seq !== undefined) seat.answers.push({ type: 'command', seq, refusal: allowed ? toMessage(allowed) : { key: 'cannotDoThat' } })\n\t\t\t}\n\t\t})\n\t\ttransport.onClose(() => this.leave(seat))\n\t\tconst { registry } = this.world\n\t\tthis.post(seat, {\n\t\t\ttype: 'welcome',\n\t\t\tprotocol: PROTOCOL_VERSION,\n\t\t\tplayer,\n\t\t\ttickRate: this.world.tickRate,\n\t\t\tgame: registry.game,\n\t\t\thash: registry.dataHash,\n\t\t\t// the cells changed out of the player's sight as their team last saw them (RV7)\n\t\t\tterrain: savedGround(\n\t\t\t\tgroundKnownTo(this.world, options.observer ? undefined : this.world.player(player).team),\n\t\t\t\tthis.world.ground,\n\t\t\t\tthis.world.registry.module?.maps,\n\t\t\t\tthis.world.registry.module ?? {}\n\t\t\t),\n\t\t\t...(this.world.map.environment && { environment: this.world.map.environment }),\n\t\t\t...(this.world.map.doodads.length > 0 && { doodads: [...this.world.map.doodads] }),\n\t\t\t...(this.world.map.regions.length > 0 && { regions: [...this.world.map.regions] }),\n\t\t\t...(this.world.map.cameras.length > 0 && { cameras: [...this.world.map.cameras] }),\n\t\t\t...(this.world.map.paths.length > 0 && { paths: [...this.world.map.paths] }),\n\t\t\t// (looked at, not made: a world nothing was changed of has none, nor its save)\n\t\t\t...(this.world.states.has(redefinitions) && { redefinitions: structuredClone(this.world.state(redefinitions)) }),\n\t\t\tfirst: this.deltaFor(seat),\n\t\t\t...(options.observer ? { observer: true } : {}),\n\t\t\t...(this.world.debugPlayers.has(player) && { debug: true })\n\t\t})\n\t}\n\n\t/** The ground the world started as, whole, in parts small enough to go one at a time: made the first time one is asked for */\n\tprivate groundParts(): string[] | undefined {\n\t\tconst base = this.world.ground\n\t\tif (!base) return undefined\n\t\tif (!this.ground) {\n\t\t\tconst text = JSON.stringify(saveTerrain(base.terrain))\n\t\t\tthis.ground = []\n\t\t\tfor (let i = 0; i < text.length; i += this.groundPart) this.ground.push(text.slice(i, i + this.groundPart))\n\t\t}\n\t\treturn this.ground\n\t}\n\n\tprivate ground?: string[]\n\n\t/** The player has the frame of `tick`: what comes next is made against it, and what it has is not sent again */\n\tprivate acknowledge(seat: Seat, tick: number, events?: number): void {\n\t\t// the batches of events it says it got, the talk between two ticks too\n\t\tif (events !== undefined) seat.events = seat.events.filter((sent) => sent.n > events)\n\t\t// (never a tick not there yet: what is said to be had is let go)\n\t\tif (tick <= seat.heardUpTo || tick > this.world.tick) return\n\t\t// heard, whether the frame it got is still kept or was let go: a player whose answers take longer than the frames\n\t\t// kept last still answers, and is not let go as silent (RV11)\n\t\tseat.heardUpTo = tick\n\t\tseat.heard = this.world.tick\n\t\tconst sent = seat.sentAt.get(tick) ?? (seat.whole?.tick === tick ? seat.whole.at : undefined)\n\t\tif (sent !== undefined) seat.roundTrip += (performance.now() - sent - seat.roundTrip) * 0.2\n\t\tif (seat.whole && tick >= seat.whole.tick) seat.whole = undefined\n\t\tfor (const kept of seat.sentAt.keys()) if (kept <= tick) seat.sentAt.delete(kept)\n\t\tseat.events = seat.events.filter((sent) => sent.tick > tick)\n\t\t// a base for the deltas from now on, where its frame is still kept\n\t\tif (!seat.frames.has(tick)) return\n\t\tseat.acked = tick\n\t\tfor (const kept of [...seat.frames.keys()]) if (kept < tick) this.forget(seat, kept)\n\t}\n\n\t/**\n\t * Whether a player is sent nothing this round: it has no frame kept to make a delta against, and the whole one it\n\t * was sent last is on its way still. Another would be as big, and come no sooner than the answer to the first\n\t */\n\tprivate holding(seat: Seat, now: number): boolean {\n\t\treturn !!seat.whole && !seat.frames.has(seat.acked) && now - seat.whole.at <= seat.roundTrip * 1.5 + this.sendEvery * 1000\n\t}\n\n\tprivate leave(seat: Seat): void {\n\t\tif (!this.seats.delete(seat)) return\n\t\tseat.session.dispose()\n\t\tseat.debug?.view.dispose()\n\t\t// running by the clock for nobody: stops, until someone connects and it is started again\n\t\tif (this.seats.size === 0) this.stop()\n\t}\n\n\t/** How many players are connected */\n\tget players(): number {\n\t\treturn this.seats.size\n\t}\n\n\t/**\n\t * How much the host keeps for each connected player, for a test of its limits (`keptFrames`, `keptEvents`): the\n\t * frames it may make a delta against, when each was sent, and the events not yet said to be had\n\t *\n\t * @internal\n\t */\n\tkept(): { frames: number; bytes: number; sentAt: number; events: number }[] {\n\t\treturn [...this.seats].map((seat) => ({ frames: seat.frames.size, bytes: seat.keptBytes, sentAt: seat.sentAt.size, events: seat.events.length }))\n\t}\n\n\tprivate post(seat: Seat, message: GameHostMessage): void {\n\t\tseat.transport.send(JSON.stringify(message))\n\t}\n\n\t/** Lets `dt` seconds pass: the ticks that fit into it, then what changed to everyone, when it is time to send */\n\tupdate(dt: number): void {\n\t\tconst { world } = this\n\t\tlet stepped = false\n\t\tthis.accumulator += dt * this.speed * world.cheats.speed\n\t\tif (world.cheats.speed === 0 && this.speed > 0 && world.debugWaiting) this.accumulator += world.dt\n\t\tthis.sinceSent += dt\n\t\tlet ticks = 0\n\t\twhile (this.accumulator >= world.dt) {\n\t\t\tif (ticks++ >= this.maxTicks) {\n\t\t\t\t// too far behind to catch up: the rest is let go\n\t\t\t\tthis.accumulator = 0\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tconst began = performance.now()\n\t\t\tworld.step()\n\t\t\tconst took = performance.now() - began\n\t\t\tconst { timing, totals } = this\n\t\t\ttiming.ticks++\n\t\t\ttiming.tickTime += took\n\t\t\ttiming.tickMax = Math.max(timing.tickMax, took)\n\t\t\ttotals.ticks++\n\t\t\ttotals.tickTime += took\n\t\t\ttotals.lastTick = took\n\t\t\tif (took > world.dt * 1000) this.onSlowTick?.(took, world.tick)\n\t\t\tthis.accumulator -= world.dt\n\t\t\tstepped = true\n\t\t}\n\t\t// talk heard between ticks goes out with no tick to wait for: a paused game's too (RV14)\n\t\tif (stepped || this.heardOutside) this.sendDue()\n\t}\n\n\t/** What the debug tools of a seat follow, as the world stands: when they follow, list or log anything */\n\tprivate sendDebug(seat: Seat, debug: NonNullable<Seat['debug']>, now: number): void {\n\t\tdebug.sentAt = now\n\t\tconst { view } = debug\n\t\tview.refresh()\n\t\tif (!view.inspection && !view.world && !view.logging) return\n\t\tthis.post(seat, { type: 'debug', inspection: view.inspection, world: view.world, log: view.logging ? [...view.log()] : [] })\n\t}\n\n\t/** Moves the game on by `ticks` at the next update, however fast it goes: a step of a held game (`speed` 0) */\n\tadvance(ticks = 1): void {\n\t\tthis.accumulator += this.world.dt * Math.max(0, Math.floor(ticks))\n\t}\n\n\t/**\n\t * Sends everyone what changed, when it is time to, for a world something else steps: the page's own game, shared with\n\t * those who watch it (`shareGame`). `dt` is the seconds since the last call. Nothing goes while the world stands still\n\t */\n\tpublish(dt: number): void {\n\t\tthis.sinceSent += dt\n\t\tif (this.world.tick !== this.sentTick || this.heardOutside) this.sendDue()\n\t}\n\n\t/** The tick what changed went out at last */\n\tprivate sentTick = -1\n\t/** Talk was carried out since what changed went out last: it goes out with no tick to wait for (RV14) */\n\tprivate heardOutside = false\n\n\t/** What changed to everyone, when the rate allows */\n\tprivate sendDue(): void {\n\t\tif (this.sinceSent < this.sendEvery) return\n\t\tthis.sentTick = this.world.tick\n\t\tthis.heardOutside = false\n\t\t// what was over carries on to the next: updates a tick apart still send at the rate asked, on average\n\t\tthis.sinceSent = Math.min(this.sinceSent - this.sendEvery, this.sendEvery)\n\t\tconst began = performance.now()\n\t\tconst silent = this.dropSilentAfter * this.world.tickRate\n\t\t// every seat is captured from the same world: what everyone is told of an entity is described once between them\n\t\tshareCaptures(this.world)\n\t\tthis.roundEntities = []\n\t\ttry {\n\t\t\tfor (const seat of [...this.seats]) {\n\t\t\t\t// one who has said nothing for long is let go: everything it was not sent again would pile up for it\n\t\t\t\tif (this.world.tick - seat.heard > silent) {\n\t\t\t\t\tseat.transport.close()\n\t\t\t\t\tthis.leave(seat)\n\t\t\t\t} else if (this.holding(seat, began)) {\n\t\t\t\t\t// it is owed this tick: told at the next round though the world stands still by then (`publish`)\n\t\t\t\t\tthis.sentTick = -1\n\t\t\t\t} else {\n\t\t\t\t\tconst delta = this.deltaFor(seat)\n\t\t\t\t\tconst made = performance.now()\n\t\t\t\t\tconst text = JSON.stringify({ type: 'delta', ...delta } satisfies GameHostMessage)\n\t\t\t\t\tthis.timing.parts.stringify += performance.now() - made\n\t\t\t\t\tthis.timing.bytes += text.length\n\t\t\t\t\tif (this.timing.keys) bytesByKey(delta, text, this.timing.keys)\n\t\t\t\t\tseat.transport.send(text)\n\t\t\t\t}\n\t\t\t\tif (seat.debug && began - seat.debug.sentAt >= DEBUG_EVERY) this.sendDebug(seat, seat.debug, began)\n\t\t\t}\n\t\t} finally {\n\t\t\tendSharedCaptures(this.world)\n\t\t\tthis.roundEntities = []\n\t\t}\n\t\tconst took = performance.now() - began\n\t\tconst { timing, totals } = this\n\t\ttiming.sends++\n\t\ttiming.sendTime += took\n\t\ttiming.sendMax = Math.max(timing.sendMax, took)\n\t\ttotals.sends++\n\t\ttotals.sendTime += took\n\t}\n\n\t/**\n\t * Where the host's time went since it was last asked (`takeTiming`): ticks of the simulation, and rounds of sending\n\t * everyone what changed (the snapshots, the diffs, the JSON), each in milliseconds, added up and at most\n\t */\n\tprivate timing: HostTiming\n\n\t/**\n\t * Where the host's time went since it started, never counted anew: ticks and rounds of sending, with the\n\t * milliseconds they took, and how long the last tick took. What a server's numbers are made of (`/metrics`)\n\t */\n\treadonly totals = { ticks: 0, tickTime: 0, lastTick: 0, sends: 0, sendTime: 0 }\n\n\t/** Where the time went since the last call, and starts counting anew: for a server to print */\n\ttakeTiming(): HostTiming & { seconds: number } {\n\t\tconst now = performance.now()\n\t\tconst timing = { ...this.timing, seconds: (now - this.timing.since) / 1000 }\n\t\tthis.timing = emptyTiming(now, this.byKey)\n\t\treturn timing\n\t}\n\n\t/** The lists of entities told this round so far, and what each was sent as, for the seats told the same to share one (`quantizedList`) */\n\tprivate roundEntities: { told: readonly EntityState[]; sent: EntityState[] }[] = []\n\n\t/** What the player knows now, as what changed since the tick they last said they got */\n\tprivate deltaFor(seat: Seat): Delta {\n\t\tconst { session } = seat\n\t\tconst { parts } = this.timing\n\t\tconst began = performance.now()\n\t\tconst snapshot = session.snapshot()\n\t\tconst captured = performance.now()\n\t\tconst told = seat.answers.length ? [...snapshot.events, ...seat.answers.splice(0)] : snapshot.events\n\t\tif (told.length) seat.events.push({ tick: snapshot.tick, n: ++seat.eventsMade, events: told })\n\t\t// a player who hears but does not answer: the oldest that went already are let go\n\t\tlet over = seat.events.length - this.keptEvents\n\t\twhile (over-- > 0 && seat.events[0].sentAt !== undefined) seat.events.shift()\n\t\tconst entities = quantizedList(snapshot.entities, this.roundEntities)\n\t\tconst quantized = performance.now()\n\t\tconst fog = fogMessageOf(session.fog())\n\t\tconst fogged = performance.now()\n\t\tconst frame: Frame = {\n\t\t\tsnapshot: { ...snapshot, entities, events: [] },\n\t\t\tfog,\n\t\t\tcamps: session.camps().map((camp) => ({ ...camp })),\n\t\t\tteam: session.team\n\t\t}\n\t\t// events go once, and again only when the answer that they got there is overdue: lost on the way\n\t\tconst now = performance.now()\n\t\tconst overdue = seat.roundTrip * 1.5 + this.sendEvery * 1000\n\t\tconst events = seat.events.filter((sent) => sent.sentAt === undefined || now - sent.sentAt > overdue)\n\t\tfor (const sent of events) sent.sentAt = now\n\t\tconst base = seat.frames.get(seat.acked)\n\t\tconst delta: Delta = {\n\t\t\t...diff(base, frame, this.world.registry),\n\t\t\tevents: events.map(({ tick, n, events }) => ({ tick, n, events }))\n\t\t}\n\t\tif (!base) seat.whole = { tick: frame.snapshot.tick, at: now }\n\t\tparts.capture += captured - began\n\t\tparts.quantize += quantized - captured\n\t\tparts.fog += fogged - quantized\n\t\tparts.diff += performance.now() - fogged\n\t\tthis.keep(seat, frame)\n\t\t// what goes is had (`inOrder`): the base of the next, the frames before it let go\n\t\tif (seat.inOrder) {\n\t\t\tseat.acked = frame.snapshot.tick\n\t\t\tseat.whole = undefined\n\t\t\tfor (const kept of [...seat.frames.keys()]) if (kept < seat.acked) this.forget(seat, kept)\n\t\t}\n\t\tseat.sentAt.set(frame.snapshot.tick, now)\n\t\tif (seat.sentAt.size > this.keptFrames) seat.sentAt.delete(seat.sentAt.keys().next().value!)\n\t\treturn delta\n\t}\n\n\t/**\n\t * Keeps the frame a player was sent, to make the next delta against: the oldest let go past `keptFrames` of them or\n\t * `keptBytes` together, the newest kept whatever it takes. A player who says nothing for long is sent everything\n\t * again, once its base is no longer kept\n\t */\n\tprivate keep(seat: Seat, frame: Frame): void {\n\t\tconst { tick } = frame.snapshot\n\t\tconst bytes = frameBytes(frame)\n\t\tseat.frames.set(tick, frame)\n\t\tseat.frameSizes.set(tick, bytes)\n\t\tseat.keptBytes += bytes\n\t\twhile (seat.frames.size > 1 && (seat.frames.size > this.keptFrames || seat.keptBytes > this.keptBytes))\n\t\t\tthis.forget(seat, seat.frames.keys().next().value!)\n\t}\n\n\t/** Lets go of a frame kept for a player */\n\tprivate forget(seat: Seat, tick: number): void {\n\t\tif (!seat.frames.delete(tick)) return\n\t\tseat.keptBytes -= seat.frameSizes.get(tick) ?? 0\n\t\tseat.frameSizes.delete(tick)\n\t}\n\n\t/** Runs the world by the clock, `rate` updates a second, until `stop` or `dispose` */\n\tstart(rate = this.world.tickRate): void {\n\t\tthis.stop()\n\t\tthis.last = performance.now()\n\t\tthis.timer = setInterval(() => {\n\t\t\tconst now = performance.now()\n\t\t\t// a tab in the background is held back: it catches up a little at a time, not all at once\n\t\t\tconst dt = Math.min((now - this.last) / 1000, 0.25)\n\t\t\tthis.last = now\n\t\t\ttry {\n\t\t\t\tthis.update(dt)\n\t\t\t} catch (error) {\n\t\t\t\t// thrown out of a timer, it would end the process, and every other game with it: the host stops here\n\t\t\t\tthis.stop()\n\t\t\t\tif (this.onError) this.onError(error)\n\t\t\t\telse this.world.log.error('server', 'stepping the game threw: it is stopped', { error: errorFields(error) })\n\t\t\t}\n\t\t}, 1000 / rate)\n\t}\n\n\t/** Stops stepping the world by the clock; does nothing if it was not started */\n\tstop(): void {\n\t\tif (this.timer !== undefined) clearInterval(this.timer)\n\t\tthis.timer = undefined\n\t}\n\n\t/** Whether it runs by the clock */\n\tget running(): boolean {\n\t\treturn this.timer !== undefined\n\t}\n\n\t/** Stops, and closes every connection. The world goes too, when it is the host's (`ownsWorld`) */\n\t/**\n\t * Stops, and lets every player go: their connections closed, unless `closeTransports` is false (a server that keeps\n\t * them for its lobby, after the game)\n\t */\n\tdispose(options: { closeTransports?: boolean } = {}): void {\n\t\tthis.stop()\n\t\tthis.stopFailed()\n\t\tfor (const seat of [...this.seats]) {\n\t\t\tif (options.closeTransports !== false) seat.transport.close()\n\t\t\tthis.leave(seat)\n\t\t}\n\t\tif (this.ownsWorld) this.world.dispose()\n\t}\n}\n\n// ---- the player's side\n\n/** A structure the player knows of, as it stands on their copy of the map */\ninterface Known {\n\tcellX: number\n\tcellZ: number\n\tw: number\n\td: number\n\t/** The kind of resource it is, for a resource: what a building that goes up on one looks for (`builtOn`) */\n\tresource?: string\n}\n\n/**\n * What the player's side keeps of the map, to answer the screen without asking the host: a placement grid and the\n * ways to walk of the map as it was made, with the structures the player has seen on them. What they have not seen\n * is not there: a path preview never goes around a building in the dark, and gives it away\n */\nexport class ClientWorld {\n\treadonly grid: BuildGrid\n\tprivate readonly known = new Map<number, Known>()\n\tprivate readonly seen = new Set<number>()\n\n\tconstructor(\n\t\treadonly terrain: Terrain,\n\t\tprivate readonly registry: Registry,\n\t\treadonly nav: Navigation,\n\t\treadonly air: Navigation\n\t) {\n\t\tthis.grid = new BuildGrid(terrain)\n\t}\n\n\t/** Whether a resource of a kind that it knows of covers just this ground, with nothing it knows of standing on it */\n\tresourceAt(kind: string, cellX: number, cellZ: number, w: number, d: number): boolean {\n\t\tlet found = false\n\t\tfor (const structure of this.known.values()) {\n\t\t\tif (structure.cellX !== cellX || structure.cellZ !== cellZ || structure.w !== w || structure.d !== d) continue\n\t\t\tif (structure.resource !== kind) return false\n\t\t\tfound = true\n\t\t}\n\t\treturn found\n\t}\n\n\t/** Brings the structures up to date with a snapshot: those in it stand, those no longer in it are gone */\n\tsync(snapshot: Snapshot): void {\n\t\tconst { seen, known } = this\n\t\tseen.clear()\n\t\tlet changed = false\n\t\tfor (const entity of snapshot.entities) {\n\t\t\tif (!this.registry.units.has(entity.type)) continue\n\t\t\tif (!this.registry.unit(entity.type).footprint) continue\n\t\t\tseen.add(entity.id)\n\t\t\tif (this.stand(entity)) changed = true\n\t\t}\n\t\tconst gone: number[] = []\n\t\tfor (const id of known.keys()) if (!seen.has(id)) gone.push(id)\n\t\tthis.settle(gone, changed)\n\t}\n\n\t/**\n\t * Brings the structures up to date with a snapshot made on the one before it, from what came and went alone: the\n\t * last `added` of its entities (`apply` puts those that came after the rest), and the ids of those `removed`. What\n\t * `sync` does, without looking over every entity of the map\n\t */\n\tchange(snapshot: Snapshot, added: number, removed: readonly number[]): void {\n\t\tconst { entities } = snapshot\n\t\tlet changed = false\n\t\t// gone first: one whose type changed under its id (a building upgraded) went and came again\n\t\tconst gone = removed.filter((id) => this.known.has(id))\n\t\tfor (const id of gone) this.release(id)\n\t\tfor (let i = entities.length - added; i < entities.length; i++) {\n\t\t\tconst entity = entities[i]\n\t\t\tif (!this.registry.units.has(entity.type) || !this.registry.unit(entity.type).footprint) continue\n\t\t\tif (this.stand(entity)) changed = true\n\t\t}\n\t\tthis.settle([], changed || gone.length > 0, gone.length > 0)\n\t}\n\n\t/** Puts a structure on the map, where it is not on it yet: whether it was put */\n\tprivate stand(entity: EntityState): boolean {\n\t\tconst { known, grid, nav } = this\n\t\tif (known.has(entity.id)) return false\n\t\tconst def = this.registry.unit(entity.type)\n\t\tconst site = siteOf(def, entity)\n\t\tconst { w, d } = footprintOf(def)\n\t\tknown.set(entity.id, { cellX: site.cellX, cellZ: site.cellZ, w, d, ...(def.resource && { resource: def.resource.id }) })\n\t\tgrid.occupy(site.cellX, site.cellZ, w, d, entity.id)\n\t\t// what blocks the way is what the host treats as an obstacle: every structure, trees and mines too\n\t\tnav.addObstacle(entity.id, site)\n\t\treturn true\n\t}\n\n\t/** Takes a structure off the map */\n\tprivate release(id: number): void {\n\t\tconst structure = this.known.get(id)!\n\t\tthis.known.delete(id)\n\t\tthis.grid.release(structure.cellX, structure.cellZ, structure.w, structure.d, id)\n\t\tthis.nav.removeObstacle(id)\n\t}\n\n\t/** Takes off those gone, gives the ground back to what stood on them, and has the navmesh take in what changed */\n\tprivate settle(gone: readonly number[], changed: boolean, released = false): void {\n\t\tfor (const id of gone) this.release(id)\n\t\treleased ||= gone.length > 0\n\t\t// what stood on another (a cursed mine on a gold mine) gave it its ground back\n\t\tif (released) for (const [id, structure] of this.known) this.grid.occupy(structure.cellX, structure.cellZ, structure.w, structure.d, id)\n\t\t// the navmesh takes in what changed as it updates\n\t\tif (changed || released) this.nav.update(0)\n\t}\n}\n\n/**\n * The host said no, with why: to come back to a game that is over, or a player let go. Trying again does not help\n *\n * @beta\n */\nexport class SessionRefused extends Error {\n\tconstructor(\n\t\t/** Why the host refused, in words */\n\t\treadonly reason: string\n\t) {\n\t\tsuper(reason)\n\t\tthis.name = 'SessionRefused'\n\t}\n}\n\n/**\n * A player's seat at a world that runs elsewhere, over a transport (see `connect`). It rebuilds what the host sends\n * as changes (`Delta`) into whole snapshots, keeping the objects of what did not change, says which ticks it got, and\n * answers the screen's questions from those and its own copy of the map (`ClientWorld`). No debug access, and no\n * checkpoints: those belong to a simulation in the page\n *\n * @beta\n */\nexport class RemoteSession implements GameSession {\n\t/**\n\t * A seat over a wire can none of what a game in this page can (`SessionCan`), but the debug tools' view of the world\n\t * for a player the host lets use them (`inspect`, said over the wire)\n\t */\n\treadonly can: SessionCan\n\t/** The debug tools' view of the world, for a player the host lets use them (the welcome's `debug`) */\n\tprotected get debugView(): SessionDebug | undefined {\n\t\treturn this.remoteDebug\n\t}\n\tprivate readonly remoteDebug?: RemoteDebug\n\t/** The player this seat plays, as the host welcomed it */\n\treadonly playerId: PlayerId\n\t/** The team of that player; updated when a snapshot says it changed */\n\tteam: number\n\t/** The ground, built from the welcome and the parts the host sent */\n\treadonly terrain: Terrain\n\t/** The map's look (sky, mist, light) from the welcome, when it has one */\n\treadonly environment?: MapEnvironment\n\t/** The map's scenery objects from the welcome */\n\treadonly doodads: readonly MapDoodad[]\n\t/** The map's named regions from the welcome */\n\treadonly regions: readonly MapRegion[]\n\t/** The map's named camera positions from the welcome */\n\treadonly cameras: readonly MapCamera[]\n\t/** The map's named paths from the welcome */\n\treadonly paths: readonly MapPath[]\n\t/** The definitions of the game, from the rules the player connected with */\n\treadonly registry: Registry\n\t/** Simulation ticks per second the host runs at, from the welcome */\n\treadonly tickRate: number\n\t/** How far, 0..1, the shown tick is between the last two snapshots, for blending the drawing */\n\talpha = 1\n\n\t/** What the player knows by tick, for the deltas to come: from the base of the last one on */\n\tprivate readonly frames = new Map<number, Frame>()\n\tprivate latest: Frame\n\tprivate readonly incoming: Snapshot[] = []\n\t/** What the host's definitions were changed to while it ran (`world.redefine`), as this screen heard it */\n\tprivate readonly redefined: GameData = {}\n\n\t/** The number of the last batch of events that went to the screen (`Delta.events`): those sent again are not applied twice */\n\tprivate eventsUpTo = -1\n\tprivate readonly fogState: FogState\n\tprivate closed = false\n\n\t/*\n\t * The interpolation buffer. The screen is shown a little behind the newest snapshot (`delay` ticks), always between\n\t * two it has, so that what moves goes on moving smoothly however unevenly the snapshots arrive. Its own clock\n\t * (`renderTick`) follows the host's: a little faster when it falls behind, a little slower when it gets ahead, and\n\t * a jump ahead when it is far behind (never back: what was shown is not taken back). Once the host goes quiet (`QUIET`)\n\t * it comes to the newest snapshot\n\t */\n\t/** The tick the screen shows, between the last two snapshots given out */\n\tprivate renderTick?: number\n\t/** The tick of the snapshot given out last, and of the one before it */\n\tprivate shownTick: number\n\tprivate shownBefore: number\n\t/** Ticks between two snapshots, evened out */\n\tprotected interval = 1\n\t/** How far off the time snapshots arrive at is from the ticks between them, in seconds, evened out */\n\tprotected jitter = 0\n\t/** Seconds between two snapshots' arrivals, evened out: a seek's come as often as any, their ticks far apart */\n\tprivate gap = 0\n\t/** When the last snapshot arrived, and its tick */\n\tprivate arrival?: { at: number; tick: number }\n\n\tconstructor(\n\t\tprivate transport: Transport,\n\t\twelcome: Extract<GameHostMessage, { type: 'welcome' }>,\n\t\tregistry: Registry,\n\t\tprivate readonly map: ClientWorld,\n\t\t/** How much it keeps and how often it asks (`ConnectOptions`) */\n\t\tprotected readonly limits: PlayerLimits = {}\n\t) {\n\t\tthis.playerId = welcome.player\n\t\tthis.tickRate = welcome.tickRate\n\t\tthis.observer = welcome.observer ?? false\n\t\tthis.remoteDebug = welcome.debug ? new RemoteDebug((ask) => this.tell({ type: 'debug', ...ask })) : undefined\n\t\tthis.can = this.remoteDebug ? { inspect: this.remoteDebug } : {}\n\t\tthis.registry = registry\n\t\tthis.terrain = map.terrain\n\t\tthis.environment = welcome.environment\n\t\tthis.doodads = welcome.doodads ?? []\n\t\tthis.regions = welcome.regions ?? []\n\t\tthis.cameras = welcome.cameras ?? []\n\t\tthis.paths = welcome.paths ?? []\n\t\t// what the definitions were changed to before this player came, before anything is made of them\n\t\trestoreRedefinitions(registry, welcome.redefinitions)\n\t\tthis.heardRedefined(welcome.redefinitions)\n\t\tconst cells = this.terrain.width * this.terrain.depth\n\t\tthis.fogState = {\n\t\t\twidth: this.terrain.width,\n\t\t\tdepth: this.terrain.depth,\n\t\t\tversion: 0,\n\t\t\trevealed: false,\n\t\t\tvisible: new Uint8Array(cells),\n\t\t\texplored: new Uint8Array(cells)\n\t\t}\n\t\tconst first = this.take(welcome.first)!\n\t\tthis.latest = first\n\t\tthis.team = first.team\n\t\t// the events that came with it are in the first snapshot the screen asks for\n\t\tthis.incoming.length = 0\n\t\tthis.shownTick = this.shownBefore = first.snapshot.tick\n\t\tthis.attach(transport)\n\t}\n\n\t/** Talks through a transport from now on: what comes in is taken, and its closing is a drop */\n\tprivate attach(transport: Transport): void {\n\t\tthis.transport = transport\n\t\tthis.closed = false\n\t\tthis.leaving = false\n\t\ttransport.onMessage((text) => {\n\t\t\tconst message = readHostMessage(text)\n\t\t\tif (message) this.receive(message)\n\t\t})\n\t\ttransport.onClose(() => {\n\t\t\t// one closed before it is not this one's to say\n\t\t\tif (this.transport !== transport) return\n\t\t\tthis.closed = true\n\t\t\tclearInterval(this.pinger)\n\t\t\tif (!this.leaving) this.onDisconnect?.()\n\t\t})\n\t\tthis.sendPing()\n\t\tclearInterval(this.pinger)\n\t\tthis.pinger = setInterval(() => this.sendPing(), this.limits.pingEvery ?? PING_EVERY)\n\t}\n\n\t/** Whether the host has gone */\n\tget disconnected(): boolean {\n\t\treturn this.closed\n\t}\n\n\t/**\n\t * Told when the connection drops, not by this side's leaving (`dispose`): to try again (`resume`), or to say the\n\t * game is lost\n\t */\n\tonDisconnect?: () => void\n\t/** This side closed it: not a drop */\n\tprivate leaving = false\n\n\t/**\n\t * Goes on with the same game over a new connection, once the host has welcomed it there again (a server does, to who\n\t * comes back with their seat's token): everything known sent again, and the screen catches up. What the host says\n\t * besides the game before the welcome goes to `onServer`; a `refused` fails it with the reason, as does a connection\n\t * that closes first, or a host that runs another game\n\t */\n\tasync resume(transport: Transport): Promise<void> {\n\t\tconst welcome = await new Promise<Extract<GameHostMessage, { type: 'welcome' }>>((resolve, reject) => {\n\t\t\ttransport.onClose(() => reject(new Error('The host closed the connection before it took the player back')))\n\t\t\ttransport.onMessage((text) => {\n\t\t\t\tconst message = readHostMessage(text)\n\t\t\t\tif (!message) return\n\t\t\t\tif (message.type === 'welcome') resolve(message)\n\t\t\t\telse if (message.type === 'refused') reject(new SessionRefused(String(message.reason ?? 'refused')))\n\t\t\t\telse if (isServerMessage(message)) this.onServer?.(message)\n\t\t\t})\n\t\t})\n\t\tconst problem = welcomeProblem(welcome as unknown as Record<string, unknown>)\n\t\tif (problem) {\n\t\t\ttransport.close()\n\t\t\tthrow new Error(problem)\n\t\t}\n\t\tif (welcome.game !== this.registry.game || welcome.hash !== this.registry.dataHash || welcome.player !== this.playerId) {\n\t\t\ttransport.close()\n\t\t\tthrow new Error('The host took the player back to another game')\n\t\t}\n\t\t// what the definitions were changed to while this side was away\n\t\trestoreRedefinitions(this.registry, welcome.redefinitions)\n\t\tthis.heardRedefined(welcome.redefinitions)\n\t\t// a seat of its own on the host: its batches of events are numbered from the first again\n\t\tthis.eventsUpTo = -1\n\t\t// talked through first, so that the host hears this side got the welcome\n\t\tthis.attach(transport)\n\t\t// everything again, from nothing: the frames before are no base for what comes\n\t\tthis.frames.clear()\n\t\tthis.incoming.length = 0\n\t\t// and the arrival clock with them: the first snapshot after the outage is not one tick after the last before it\n\t\tthis.arrival = undefined\n\t\tthis.interval = 1\n\t\tthis.jitter = 0\n\t\tthis.gap = 0\n\t\t// taken back to before what was shown (a replay gone back to its start): shown from there, and its events heard\n\t\t// again, or nothing older than what was shown would come out (`update`) and every event up to it would be skipped\n\t\tif (welcome.first.tick < this.shownTick) {\n\t\t\tthis.shownTick = this.shownBefore = welcome.first.tick\n\t\t\tthis.renderTick = undefined\n\t\t\tthis.eventsUpTo = welcome.first.tick - 1\n\t\t}\n\t\tthis.take(welcome.first)\n\t\t// the debug tools follow on the host it is served from now\n\t\tthis.remoteDebug?.askAgain()\n\t}\n\n\t/** Keeps what the host's definitions were changed to, over what was kept before */\n\tprivate heardRedefined(data: GameData | undefined): void {\n\t\tfor (const [kind, byId] of Object.entries(data ?? {}) as [DataKind, Record<string, DataValues>][])\n\t\t\tfor (const [id, values] of Object.entries(byId)) {\n\t\t\t\tconst kept = (this.redefined[kind] ??= {})\n\t\t\t\tkept[id] = mergeValues(kept[id] ?? {}, values)\n\t\t\t}\n\t}\n\n\t/**\n\t * Takes a new version of the game into this screen's registry (hot reload, a game in a worker): its definitions as\n\t * the new version has them, what the host changed of them while it ran over them again\n\t */\n\ttakeGame(game: Rules): void {\n\t\tthis.registry.takeFrom(createRegistry(game))\n\t\trestoreRedefinitions(this.registry, this.redefined)\n\t}\n\n\t/** Takes in a message of the host's: what the transport hands it, and what came in while the session was made */\n\treceive(message: HostToPlayer): void {\n\t\tif (message.type === 'delta') this.take(message)\n\t\telse if (message.type === 'debug') this.remoteDebug?.take(message)\n\t\telse if (message.type === 'pong') {\n\t\t\tconst took = performance.now() - message.at\n\t\t\t// evened out, from the first answer on\n\t\t\tthis.ping = this.ping === undefined ? took : this.ping + (took - this.ping) * 0.3\n\t\t} else if (message.type === 'failed') {\n\t\t\tif (typeof message.message === 'string') this.failure = { message: message.message }\n\t\t} else if (isServerMessage(message)) {\n\t\t\t// a server's pause: who asked for it, and until when at most\n\t\t\tif (message.type === 'paused') {\n\t\t\t\tthis.pause =\n\t\t\t\t\tmessage.paused === true\n\t\t\t\t\t\t? {\n\t\t\t\t\t\t\t\t...(typeof message.player === 'number' && { player: message.player }),\n\t\t\t\t\t\t\t\t...(typeof message.seconds === 'number' && { until: Date.now() + message.seconds * 1000 })\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t: null\n\t\t\t\tthis.onPause?.(this.pause)\n\t\t\t}\n\t\t\tthis.onServer?.(message)\n\t\t}\n\t}\n\n\t/**\n\t * The game paused by the server, for everyone: by a player (`player`, until a time at most, in `Date.now()`'s\n\t * milliseconds) or an admin (neither). Null while it goes on\n\t */\n\tpause: { player?: PlayerId; until?: number } | null = null\n\t/** Told each time the server pauses the game or lets it go on */\n\tonPause?: (pause: { player?: PlayerId; until?: number } | null) => void\n\n\t/** Says something to the server beside the game: a lobby's message (`{ type: 'resume' }`) */\n\ttell(message: { type: string } & Record<string, unknown>): void {\n\t\tif (!this.closed) this.transport.send(JSON.stringify(message))\n\t}\n\n\t/** Why the game ended on an error in its rules, once the host said so */\n\tfailure: { message: string } | null = null\n\n\t/** Milliseconds a message takes to the host and back, evened out: measured every couple of seconds */\n\tping?: number\n\t/** Whether the player only watches, and sees everything */\n\treadonly observer: boolean\n\tprivate pinger?: ReturnType<typeof setInterval>\n\n\t/** Asks the host to answer at once, to measure the time there and back */\n\tprivate sendPing(): void {\n\t\tif (!this.closed) this.transport.send(JSON.stringify({ type: 'ping', at: performance.now() } satisfies GameCommandMessage))\n\t}\n\n\t/** Told of what the host says besides the game: a server's messages (see `ConnectOptions.onServer`) */\n\tonServer?: ConnectOptions['onServer']\n\n\t/** Rebuilds the frame a delta makes, says it got it, and has its snapshot wait for the screen */\n\tprivate take(delta: Delta): Frame | undefined {\n\t\tconst base = delta.base === null ? undefined : this.frames.get(delta.base)\n\t\t// made against a frame this side no longer has: wait for one against what it said it got\n\t\tif (delta.base !== null && !base) return undefined\n\t\t// what did not change keeps the objects of the frame before, which the screen tells changes by\n\t\tconst frame = apply(base, delta, this.latest)\n\t\tconst { snapshot } = frame\n\t\tthis.frames.set(snapshot.tick, frame)\n\t\t// the host makes nothing against anything older than this base from now on\n\t\tfor (const tick of this.frames.keys()) if (delta.base !== null && tick < delta.base) this.frames.delete(tick)\n\t\tif (delta.rest.fog) this.takeFog(delta.rest.fog)\n\t\tif (delta.rest.team !== undefined) this.team = delta.rest.team\n\t\t// each batch of events once, however often it was sent: by its number, as talk goes between ticks too (RV14)\n\t\tconst events: SessionEvent[] = []\n\t\tfor (const sent of delta.events) {\n\t\t\tif (sent.n <= this.eventsUpTo) continue\n\t\t\tevents.push(...sent.events)\n\t\t\tthis.eventsUpTo = sent.n\n\t\t\t// what the ground says it is now: the cells of the game's layers set as the game runs; and the definitions\n\t\t\tfor (const event of sent.events) {\n\t\t\t\tif (event.type === 'redefined') {\n\t\t\t\t\tredefineIn(this.registry, event.kind, event.definition, event.values)\n\t\t\t\t\tthis.heardRedefined({ [event.kind]: { [event.definition]: event.values } })\n\t\t\t\t}\n\t\t\t\tif (event.type === 'ground' && !terrainPatchProblem(this.terrain, event.patch)) applyTerrainPatch(this.terrain, event.patch)\n\t\t\t\tif (event.type !== 'cells') continue\n\t\t\t\tconst layer = this.terrain.cellLayer(event.layer)\n\t\t\t\tfor (const c of event.at) if (c >= 0 && c < layer.length) layer[c] = event.value\n\t\t\t}\n\t\t}\n\t\tthis.incoming.push({ ...snapshot, events })\n\t\tif (this.incoming.length > (this.limits.keptSnapshots ?? KEPT_SNAPSHOTS)) this.fold()\n\t\tthis.arrived(snapshot.tick)\n\t\t// made on the frame before: what came and went is all that changed of the structures (a worker's game, a line\n\t\t// that keeps up). Made on an older one, the whole of it is looked over: what came and went since is not in the delta\n\t\tif (base && base === this.latest) this.map.change(snapshot, delta.added.length, delta.removed)\n\t\telse this.map.sync(snapshot)\n\t\tthis.latest = frame\n\t\tif (!this.closed) this.transport.send(JSON.stringify({ type: 'ack', tick: snapshot.tick, events: this.eventsUpTo } satisfies GameCommandMessage))\n\t\treturn frame\n\t}\n\n\t/**\n\t * The oldest snapshot waiting let go, its events put before the next one's: the screen, when it asks again, jumps\n\t * to the newest anyway. The state is in every snapshot; the events (deaths, sounds, lines said) are what would be lost\n\t */\n\tprivate fold(): void {\n\t\tconst oldest = this.incoming.shift()!\n\t\tif (!oldest.events.length) return\n\t\tconst next = this.incoming[0]\n\t\tconst events = oldest.events.concat(next.events)\n\t\tconst mostEvents = this.limits.keptScreenEvents ?? KEPT_SCREEN_EVENTS\n\t\tthis.incoming[0] = { ...next, events: events.length > mostEvents ? events.slice(-mostEvents) : events }\n\t}\n\n\t/**\n\t * Snapshots come in and not yet given to the screen (`update`): a few normally, never more than a few seconds of\n\t * them, however long the screen does not ask\n\t *\n\t * @beta\n\t */\n\tget waiting(): number {\n\t\treturn this.incoming.length\n\t}\n\n\tprivate takeFog(message: FogMessage): void {\n\t\tconst fog = this.fogState\n\t\tfog.revealed = message.revealed\n\t\tfromRuns(message.visible, fog.visible)\n\t\tfromRuns(message.explored, fog.explored)\n\t\tfog.version++\n\t}\n\n\t/** The newest snapshot the host sent */\n\tsnapshot(): Snapshot {\n\t\treturn this.latest.snapshot\n\t}\n\n\t/** The tick the screen is shown at, between two snapshots: behind the newest by `delay` */\n\tget shownAt(): number {\n\t\treturn this.renderTick ?? this.shownTick\n\t}\n\n\t/**\n\t * The ticks between two snapshots, and the jitter the interpolation makes room for, as it has them evened out. A\n\t * test may set the jitter, as a late line would have\n\t *\n\t * @internal\n\t */\n\tget pacing(): { interval: number; jitter: number } {\n\t\treturn { interval: this.interval, jitter: this.jitter }\n\t}\n\n\t/** @internal */\n\tset pacing(pacing: { jitter: number }) {\n\t\tthis.jitter = pacing.jitter\n\t}\n\n\t/** How far behind the newest snapshot the screen is shown, in ticks: about two snapshots, and room for the jitter */\n\tget delay(): number {\n\t\t// a spike of lateness (a tab in the background, a line that stalled) is not waited out for good: a fifth of a second at most\n\t\treturn this.interval * 2 + Math.min(this.jitter, this.limits.maxJitter ?? MAX_JITTER) * this.tickRate * 2\n\t}\n\n\t/** Takes note of when a snapshot arrived, for how far apart they come and how unevenly */\n\tprivate arrived(tick: number): void {\n\t\tconst now = performance.now()\n\t\tconst last = this.arrival\n\t\tthis.arrival = { at: now, tick }\n\t\tif (!last || tick <= last.tick) return\n\t\tconst ticks = tick - last.tick\n\t\tthis.interval += (ticks - this.interval) * 0.1\n\t\tthis.gap += ((now - last.at) / 1000 - this.gap) * 0.1\n\t\tconst off = Math.abs((now - last.at) / 1000 - ticks / this.tickRate)\n\t\tthis.jitter += (off - this.jitter) * 0.1\n\t}\n\n\t/**\n\t * Lets the screen's clock go on by `dt`, and gives out the snapshots it has come to, oldest first: the screen draws\n\t * between the last two (`alpha`). The time is the host's: the clock follows the snapshots, not the other way around\n\t */\n\tupdate(dt: number): Snapshot[] {\n\t\tconst newest = this.incoming.length ? this.incoming[this.incoming.length - 1].tick : this.shownTick\n\t\t// the host gone quiet, its world standing still (a replay held, at the moment it was taken to): nothing is coming\n\t\t// to make room for, so the screen comes to what it was last sent. Behind it by the delay, it stood where it was for\n\t\t// good: a seek's snapshots come far apart, and their delay was eight seconds of the game short of the moment\n\t\tconst quiet = !!this.arrival && performance.now() - this.arrival.at > Math.max(QUIET, this.gap * 3) * 1000\n\t\tconst target = quiet ? newest : newest - this.delay\n\t\t// far behind, a jump ahead; far ahead (the delay grew, as by a seek's snapshots), slower until it is behind again:\n\t\t// a jump back would show again what was shown\n\t\tif (this.renderTick === undefined || target - this.renderTick > this.tickRate) this.renderTick = target\n\t\telse {\n\t\t\t// a tenth faster or slower at most: nobody sees a clock catch up that way\n\t\t\tconst rate = 1 + Math.max(-0.1, Math.min((target - this.renderTick) * 0.05, 0.1))\n\t\t\tthis.renderTick += dt * this.tickRate * rate\n\t\t}\n\t\t// never past what has come in\n\t\tthis.renderTick = Math.min(this.renderTick, newest)\n\t\tconst out: Snapshot[] = []\n\t\t// the next one goes out once the screen has come to the one before it: it is drawn towards from there\n\t\twhile (this.incoming.length && this.renderTick >= this.shownTick) {\n\t\t\tconst next = this.incoming.shift()!\n\t\t\tthis.shownBefore = this.shownTick\n\t\t\tthis.shownTick = next.tick\n\t\t\tout.push(next)\n\t\t}\n\t\tconst span = this.shownTick - this.shownBefore\n\t\tthis.alpha = span > 0 ? Math.max(0, Math.min((this.renderTick - this.shownBefore) / span, 1)) : 1\n\t\treturn out\n\t}\n\n\t/** Sends a command to the host and returns the number it was given, which the host's answer names; does nothing once closed */\n\tsend(command: PlayerCommand): number {\n\t\tconst seq = ++this.lastSeq\n\t\tif (!this.closed) this.transport.send(JSON.stringify({ type: 'command', seq, command } satisfies GameCommandMessage))\n\t\treturn seq\n\t}\n\n\t/** The number of the last command sent */\n\tprivate lastSeq = 0\n\n\t/** The team's fog as built from what the host sent */\n\tfog(): FogState {\n\t\treturn this.fogState\n\t}\n\n\t/** The creep camps as the newest frame has them */\n\tcamps(): readonly CampInfo[] {\n\t\treturn this.latest.camps\n\t}\n\n\t/**\n\t * Whether the player could build this here, as far as they can tell: on their copy of the map, with the structures\n\t * they know, on ground they have explored. The game's own say (the `canPlace` hook) is the host's: it may still refuse\n\t */\n\tcanPlace(unitType: string, point: Vec2): boolean {\n\t\tif (!this.registry.units.has(unitType)) return false\n\t\tconst def = this.registry.unit(unitType)\n\t\tconst site = siteOf(def, point)\n\t\tconst { w, d } = footprintOf(def)\n\t\t// on a resource of its kind that it knows of, with nothing on it yet; anywhere else, on free ground\n\t\tif (\n\t\t\tdef.builtOn !== undefined\n\t\t\t\t? !this.map.resourceAt(def.builtOn, site.cellX, site.cellZ, w, d)\n\t\t\t\t: !this.map.grid.canPlace(site.cellX, site.cellZ, w, d)\n\t\t)\n\t\t\treturn false\n\t\tconst fog = this.fogState\n\t\tif (fog.revealed) return true\n\t\tconst explored = (x: number, z: number) => fog.explored[Math.floor(z) * fog.width + Math.floor(x)] === 1\n\t\treturn (\n\t\t\texplored(site.x - site.hw + 0.5, site.z - site.hd + 0.5) &&\n\t\t\texplored(site.x + site.hw - 0.5, site.z - site.hd + 0.5) &&\n\t\t\texplored(site.x - site.hw + 0.5, site.z + site.hd - 0.5) &&\n\t\t\texplored(site.x + site.hw - 0.5, site.z + site.hd - 0.5)\n\t\t)\n\t}\n\n\t/** Which cells of a building's ground are in the way, as `canPlace` sees them: on the player's copy of the map, explored */\n\tplaceCells(unitType: string, point: Vec2): readonly boolean[] | undefined {\n\t\tif (!this.registry.units.has(unitType)) return undefined\n\t\tconst fog = this.fogState\n\t\treturn placementCells(\n\t\t\tthis.registry.unit(unitType),\n\t\t\tpoint,\n\t\t\t(x, z) => this.map.grid.canPlace(x, z, 1, 1),\n\t\t\tfog.revealed ? undefined : (x, z) => fog.explored[z * fog.width + x] === 1\n\t\t)\n\t}\n\n\t/** The way a unit would walk, on the player's copy of the map: around the structures they know, and no others */\n\t/** Where a group would stand sent to a point in a formation, `rows` when none is named: the rules are the host's (`GameSession.formationPlaces`) */\n\tformationPlaces(\n\t\tunits: readonly (FormationUnit & { readonly flying?: boolean })[],\n\t\tpoint: Vec2,\n\t\tfacing?: number,\n\t\tformation = 'rows'\n\t): Map<EntityId, Vec2> {\n\t\treturn formationPreview(this.registry, units, point, this.map, formation, facing)\n\t}\n\n\t/** A path over the ground the player has, on the air layer when `flying`; null when there is none */\n\tfindPath(from: Vec2, to: Vec2, flying = false): Vec2[] | null {\n\t\treturn (flying ? this.map.air : this.map.nav).findPath(from, to)\n\t}\n\n\t/** Stops pinging, closes the connection and frees the navigation made from the ground */\n\tdispose(): void {\n\t\tclearInterval(this.pinger)\n\t\tthis.leaving = true\n\t\tif (!this.closed) this.transport.close()\n\t\tthis.closed = true\n\t\tthis.map.nav.dispose()\n\t\tthis.map.air.dispose()\n\t}\n}\n\n/**\n * What `connect` is given: the rules, navigation settings, maps, limits and a handler for the host's other messages\n *\n * @beta\n */\nexport interface ConnectOptions {\n\t/**\n\t * The game module the host runs: the player's side needs its data, and checks it is the very same version. Or the\n\t * games the player has, by id, for a host that says which it runs\n\t */\n\trules: Rules | Record<string, Rules>\n\t/** Settings for the navigation the player's side builds of the ground */\n\tnavigation?: RecastNavigationOptions\n\t/** The maps the welcome's ground may be one of (S36): the game's own (`Rules.maps`) when left out */\n\tmaps?: readonly GameMap[]\n\t/**\n\t * What the player's side keeps and how often it asks: `pingEvery`, `maxJitter`, `keptSnapshots`,\n\t * `keptScreenEvents` (`PlayerLimits`)\n\t *\n\t * @beta\n\t */\n\tlimits?: PlayerLimits\n\t/** What else the host says, before the game and during it: a server's lobby, a pause, the result */\n\tonServer?: (message: ServerToPlayer) => void\n}\n\n/** How much of the ground goes in one message, for a player who does not have its map: well under what a connection holds */\nconst GROUND_PART = 256 * 1024\n\n/**\n * The ground of a welcome: all of it, or the map it started as among the player's (S36), the changes put on it. A\n * player without that map asks the host for it, a part at a time, and puts the changes on what it is sent\n */\nasync function groundOfWelcome(\n\ttransport: Transport,\n\tground: SavedGround,\n\tmaps: readonly GameMap[] | undefined,\n\tgame: Rules,\n\tearly: string[],\n\t/** Told of a close while the ground is sent, as the caller's own handler is put aside meanwhile */\n\tdropped: () => void\n): Promise<Terrain> {\n\ttry {\n\t\treturn groundOf(ground, maps, game).terrain\n\t} catch (error) {\n\t\tif (!(error instanceof MissingGround) || !isGroundChanges(ground)) throw error\n\t}\n\tconst whole = await new Promise<TerrainSave>((resolve, reject) => {\n\t\tconst parts: string[] = []\n\t\ttransport.onClose(() => {\n\t\t\tdropped()\n\t\t\treject(new Error('The host closed the connection while the ground was sent'))\n\t\t})\n\t\ttransport.onMessage((text) => {\n\t\t\tconst message = readHostMessage(text)\n\t\t\tif (message?.type !== 'ground') {\n\t\t\t\tearly.push(text)\n\t\t\t\treturn\n\t\t\t}\n\t\t\tparts[message.part] = message.text\n\t\t\tif (message.part + 1 < message.parts) transport.send(JSON.stringify({ type: 'ground', part: message.part + 1 }))\n\t\t\telse {\n\t\t\t\ttransport.onMessage((later) => early.push(later))\n\t\t\t\tresolve(JSON.parse(parts.join('')) as TerrainSave)\n\t\t\t}\n\t\t})\n\t\ttransport.send(JSON.stringify({ type: 'ground', part: 0 }))\n\t})\n\treturn applyGroundChanges(loadTerrain(whole), ground)\n}\n\n/**\n * What is wrong with a welcome, before anything of it is used: another version of the wire (`PROTOCOL_VERSION`), or a\n * shape that is not one. What comes after it is the host's word, trusted as the welcome said it would be\n */\nfunction welcomeProblem(welcome: Record<string, unknown>): string | undefined {\n\tif (welcome.protocol !== PROTOCOL_VERSION) return protocolMismatch(welcome.protocol)\n\tconst good =\n\t\tNumber.isInteger(welcome.player) &&\n\t\tisFiniteNumber(welcome.tickRate) &&\n\t\t(welcome.tickRate as number) > 0 &&\n\t\ttypeof welcome.game === 'string' &&\n\t\ttypeof welcome.hash === 'string' &&\n\t\ttypeof welcome.terrain === 'object' &&\n\t\twelcome.terrain !== null &&\n\t\ttypeof welcome.first === 'object' &&\n\t\twelcome.first !== null\n\treturn good ? undefined : 'The host sent a welcome this player cannot read'\n}\n\n/**\n * Connects to a host over a transport (the player's end of it), and waits for the welcome: what the session is\n * made of. Fails when the host runs another version of the game, or of the engine's wire (`PROTOCOL_VERSION`), and\n * when the connection closes before the session is made: while the map is made from the welcome too\n *\n * @public\n */\nexport function connect(transport: Transport, options: ConnectOptions): Promise<RemoteSession> {\n\treturn connectAs(transport, options, (...made) => new RemoteSession(...made))\n}\n\n/** `connect`, for a session of a kind of its own: `make` is given what a `RemoteSession` is made of */\nexport async function connectAs<S extends RemoteSession>(\n\ttransport: Transport,\n\toptions: ConnectOptions,\n\tmake: (...made: ConstructorParameters<typeof RemoteSession>) => S\n): Promise<S> {\n\t// a drop after the welcome, until the session is made, is heard here: the session's own handler is not on yet, and a\n\t// transport says it once (RV9)\n\tlet dropped = false\n\tconst drop = () => {\n\t\tdropped = true\n\t}\n\tconst welcome = await new Promise<Extract<GameHostMessage, { type: 'welcome' }>>((resolve, reject) => {\n\t\ttransport.onClose(() => {\n\t\t\tdrop()\n\t\t\treject(new Error('The host closed the connection before the game started'))\n\t\t})\n\t\ttransport.onMessage((text) => {\n\t\t\tconst message = readHostMessage(text)\n\t\t\tif (!message) return\n\t\t\tif (message.type === 'welcome') resolve(message)\n\t\t\telse if (isServerMessage(message)) options.onServer?.(message)\n\t\t})\n\t})\n\tconst problem = welcomeProblem(welcome as unknown as Record<string, unknown>)\n\tif (problem) {\n\t\ttransport.close()\n\t\tthrow new Error(problem)\n\t}\n\tconst game =\n\t\t'id' in options.rules && typeof options.rules.id === 'string' ? (options.rules as Rules) : (options.rules as Record<string, Rules>)[welcome.game]\n\t// a game of the same base with other packs of content (or mods): which, said (campaign plan RC6)\n\tconst own = 'id' in options.rules && typeof options.rules.id === 'string' ? (options.rules as Rules).id : undefined\n\tconst others = otherPacks(welcome.game, game?.id ?? own)\n\tif (!game) {\n\t\ttransport.close()\n\t\tthrow new Error(others ?? `The host runs ${welcome.game}, which this player does not have`)\n\t}\n\tconst registry = createRegistry(game)\n\tif (welcome.game !== registry.game || welcome.hash !== registry.dataHash) {\n\t\ttransport.close()\n\t\tthrow new Error(others ?? `The host runs ${welcome.game} (${welcome.hash}), this is ${registry.game} (${registry.dataHash}): not the same game`)\n\t}\n\t// what comes in while the map is made waits for the session\n\tconst early: string[] = []\n\ttransport.onMessage((text) => early.push(text))\n\ttransport.onClose(drop)\n\tconst lost = 'The host closed the connection while the map was made'\n\t// (its ground asked for of a host already gone would never come)\n\tif (dropped) throw new Error(lost)\n\tconst terrain = await groundOfWelcome(transport, welcome.terrain, options.maps ?? game.maps, game, early, drop)\n\ttransport.onClose(drop)\n\t// weighing slow ground as the host's does (EN2): the ways it shows are the ones its units take\n\tconst speedAt = hasGroundSpeeds(registry) ? (x: number, z: number) => navigationSpeedOn(registry, terrain, x, z) : undefined\n\tconst nav = await RecastNavigation.create(terrain, { agentRadius: 0.5, ...(speedAt && { speedAt }), ...options.navigation })\n\tif (dropped) {\n\t\tnav.dispose()\n\t\tthrow new Error(lost)\n\t}\n\tconst map = new ClientWorld(terrain, registry, nav, new AirNavigation(terrain.width, terrain.depth))\n\tconst session = make(transport, welcome, registry, map, options.limits)\n\tsession.onServer = options.onServer\n\tfor (const text of early) {\n\t\tconst message = readHostMessage(text)\n\t\tif (message) session.receive(message)\n\t}\n\treturn session\n}\n\n/**\n * What a player is told who joins a game of the same base as theirs with other packs of content or mods\n * (`melee+gnomes` against `melee`): the host's and theirs. Nothing for games of other bases, or the same\n */\nfunction otherPacks(host: string, own: string | undefined): string | undefined {\n\tif (own === undefined || own === host) return undefined\n\tconst [hostBase, ...hostPacks] = host.split('+')\n\tconst [ownBase, ...ownPacks] = own.split('+')\n\tif (hostBase !== ownBase) return undefined\n\tconst list = (packs: string[]) => (packs.length ? packs.join(', ') : 'none')\n\treturn `The host plays ${hostBase} with the packs ${list(hostPacks)}, this player with ${list(ownPacks)}: the host's are the game's`\n}\n"],"mappings":"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"}
@@ -1,6 +1,7 @@
1
1
  import { type CommandReplay } from './commandReplay';
2
2
  import type { PlayerId } from '#engine/entity';
3
- import type { GameModule } from '#engine/game';
3
+ import type { Rules } from '#engine/game';
4
+ import type { NavigationBuilds } from '#engine/navigation/builds';
4
5
  import type { Component } from '#engine/components';
5
6
  import type { World } from '#engine/world';
6
7
  import { type RemoteSession } from './remote';
@@ -17,14 +18,17 @@ export type Replay = FramesReplay | CommandReplay;
17
18
  * @beta
18
19
  */
19
20
  export interface FramesReplay {
21
+ /** The replay's file format, always 1 for a frames replay */
20
22
  format: 1;
21
23
  /** The game it is of, by id: a page plays back what it has */
22
24
  game: string;
23
25
  /** Whose side it was seen from: their lines and cinematics, everything in sight besides */
24
26
  player: PlayerId;
27
+ /** Ticks per second the game ran at */
25
28
  tickRate: number;
26
29
  /** The tick it started and ended at */
27
30
  from: number;
31
+ /** The tick the recording ended at */
28
32
  to: number;
29
33
  /** What the host sent, as it sent it, with the tick of the world then */
30
34
  frames: [tick: number, message: string][];
@@ -49,7 +53,9 @@ export interface ReplayRecorder {
49
53
  * @beta
50
54
  */
51
55
  export interface RecordOptions {
56
+ /** The player whose side the replay is seen from when played back */
52
57
  player: PlayerId;
58
+ /** Which kind of replay to make: `commands` (the default) or `frames` */
53
59
  kind?: 'commands' | 'frames';
54
60
  /** Frames a second, of a `frames` replay: 10 when left out */
55
61
  sendRate?: number;
@@ -97,6 +103,7 @@ export interface ReplayPlayer {
97
103
  * since), or null while it has not. Never for a replay of frames
98
104
  */
99
105
  readonly apart?: number | null;
106
+ /** Stops playing the replay and lets go of what it holds */
100
107
  stop(): void;
101
108
  }
102
109
  /**
@@ -107,8 +114,10 @@ export interface ReplayPlayer {
107
114
  * @beta
108
115
  */
109
116
  export declare function playReplay(replay: Replay, options: {
110
- game: GameModule | Record<string, GameModule>;
117
+ rules: Rules | Record<string, Rules>;
111
118
  at?: number;
112
119
  /** What the app kept in the world beside the game's (`CreateWorldOptions.components`): a replay of commands loads its saves with them */
113
120
  components?: readonly Component<unknown, unknown>[];
121
+ /** Who builds the navigation of the world a replay of commands runs again, and where what was built is kept: its own thread when left out */
122
+ navigation?: NavigationBuilds;
114
123
  }): ReplayPlayer;
@@ -0,0 +1,160 @@
1
+ import { SessionHost, connect } from "./remote.js";
2
+ import { playCommands, recordCommands } from "./commandReplay.js";
3
+ //#region src/session/replay.ts
4
+ /** How often the recorder looks whether the world went on, a second: it keeps what changed at its own rate */
5
+ var LOOKS = 30;
6
+ /**
7
+ * The tick a message says it brings, to answer that it got there: of a delta, from the head of its text where it comes
8
+ * first; of the welcome, of the first frame it carries
9
+ */
10
+ var tickOf = (message) => {
11
+ const found = /^\{"type":"delta","tick":(\d+)/.exec(message) ?? (message.startsWith("{\"type\":\"welcome\"") ? /"first":\{"tick":(\d+)/.exec(message) : null);
12
+ return found ? Number(found[1]) : void 0;
13
+ };
14
+ /**
15
+ * Records a game played in the page (`RecordOptions`): as its start and its players' commands (`kind: 'commands'`,
16
+ * the default: `recordCommands`), or as an observer from `player`'s side sees it, what changed `sendRate` times a
17
+ * second (`kind: 'frames'`). Frames are answered at once, as by a watcher who missed nothing, so what is kept is what
18
+ * changed and not the whole world again
19
+ *
20
+ * @beta
21
+ */
22
+ function recordGame(world, options) {
23
+ if ((options.kind ?? "commands") === "commands") return recordCommands(world, options);
24
+ const host = new SessionHost(world, { sendRate: options.sendRate ?? 10 });
25
+ const frames = [];
26
+ const from = world.tick;
27
+ let answer = () => {};
28
+ host.connect(options.player, {
29
+ send(message) {
30
+ frames.push([world.tick, message]);
31
+ const tick = tickOf(message);
32
+ if (tick !== void 0) answer(JSON.stringify({
33
+ type: "ack",
34
+ tick
35
+ }));
36
+ },
37
+ onMessage: (handler) => answer = handler,
38
+ onClose: () => {},
39
+ close: () => {}
40
+ }, {
41
+ readOnly: true,
42
+ observer: true
43
+ });
44
+ let last = performance.now();
45
+ const timer = setInterval(() => {
46
+ const now = performance.now();
47
+ host.publish((now - last) / 1e3);
48
+ last = now;
49
+ }, 1e3 / LOOKS);
50
+ let replay;
51
+ return {
52
+ get ticks() {
53
+ return world.tick - from;
54
+ },
55
+ stop() {
56
+ if (replay) return replay;
57
+ clearInterval(timer);
58
+ host.dispose();
59
+ replay = {
60
+ format: 1,
61
+ game: world.registry.game,
62
+ player: options.player,
63
+ tickRate: world.tickRate,
64
+ from,
65
+ to: world.tick,
66
+ frames
67
+ };
68
+ return replay;
69
+ }
70
+ };
71
+ }
72
+ /**
73
+ * Plays a replay back, as a watcher's session (`connect`): a replay of commands run again (`playCommands`), or what the
74
+ * host sent coming in as it came, by the replay's ticks; `speed` times as fast. `game` is the game module it is of, or
75
+ * the modules the page has, by id
76
+ *
77
+ * @beta
78
+ */
79
+ function playReplay(replay, options) {
80
+ if (replay.format === 2) {
81
+ const games = options.rules;
82
+ const game = "units" in games && typeof games.id === "string" ? games : games[replay.game];
83
+ if (!game) throw new Error(`This page does not have the game the replay is of (${replay.game})`);
84
+ return playCommands(replay, {
85
+ rules: game,
86
+ at: options.at,
87
+ components: options.components,
88
+ navigation: options.navigation
89
+ });
90
+ }
91
+ let deliver = () => {};
92
+ const watching = () => ({
93
+ send: () => {},
94
+ onMessage: (handler) => void (deliver = handler),
95
+ onClose: () => {},
96
+ close: () => {}
97
+ });
98
+ const within = (tick) => Math.min(Math.max(tick, replay.from), replay.to);
99
+ let next = 0;
100
+ /** The moment it is asked to be at: the clock, or where a seek goes */
101
+ let due = within(options.at ?? replay.from);
102
+ let last = performance.now();
103
+ /** The tick of the last frame handed to the session */
104
+ const shown = () => next > 0 ? replay.frames[next - 1][0] : replay.from;
105
+ /** Whether frames are still to be handed over to come to the moment asked */
106
+ const pending = () => next < replay.frames.length && replay.frames[next][0] <= due;
107
+ let session;
108
+ const player = {
109
+ session: connect(watching(), { rules: options.rules }),
110
+ get tick() {
111
+ return pending() ? shown() : due;
112
+ },
113
+ speed: 1,
114
+ skipTo(target) {
115
+ due = within(target);
116
+ if (session && due < shown()) {
117
+ next = 0;
118
+ session.resume(watching()).catch(() => void 0);
119
+ deliver(replay.frames[next++]?.[1] ?? "");
120
+ }
121
+ },
122
+ get behind() {
123
+ return pending() ? Math.max(Math.floor(due) - shown(), 1) : 0;
124
+ },
125
+ get ended() {
126
+ return next >= replay.frames.length;
127
+ },
128
+ stop() {
129
+ stopped = true;
130
+ clearInterval(timer);
131
+ }
132
+ };
133
+ /** Hands the session the frames up to the moment asked, until `deadline` is past */
134
+ const flush = (deadline) => {
135
+ let handed = 0;
136
+ while (pending()) {
137
+ deliver(replay.frames[next++][1]);
138
+ if (++handed % 16 === 0 && performance.now() > deadline) return;
139
+ }
140
+ };
141
+ let timer;
142
+ let stopped = false;
143
+ deliver(replay.frames[next++]?.[1] ?? "");
144
+ player.session.then((made) => {
145
+ if (stopped) return;
146
+ session = made;
147
+ last = performance.now();
148
+ timer = setInterval(() => {
149
+ const now = performance.now();
150
+ if (!pending()) due = Math.min(due + (now - last) / 1e3 * replay.tickRate * player.speed, replay.to);
151
+ last = now;
152
+ flush(now + 12);
153
+ }, 1e3 / LOOKS);
154
+ }, () => void 0);
155
+ return player;
156
+ }
157
+ //#endregion
158
+ export { playReplay, recordGame };
159
+
160
+ //# sourceMappingURL=replay.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"replay.js","names":[],"sources":["../../src/session/replay.ts"],"sourcesContent":["import { type CommandReplay, playCommands, recordCommands, REPLAY_SLICE } from './commandReplay'\nimport type { PlayerId } from '#engine/entity'\nimport type { Rules } from '#engine/game'\nimport type { NavigationBuilds } from '#engine/navigation/builds'\nimport type { Component } from '#engine/components'\nimport type { World } from '#engine/world'\nimport { connect, type RemoteSession, SessionHost, type Transport } from './remote'\n\n/*\n * Replays: a game as an observer saw it, recorded, and played back. What is recorded is what a host sends someone who\n * watches (the welcome, and what changed after it), with the tick each went out at: played back through the same\n * remote session a watcher has, it shows the game as it was, at any speed. Not the commands run again: the engine does\n * not come back exactly from a save (ground paths, `PLAN.md`), and a run again would drift\n */\n\n/**\n * A game recorded (`recordGame`), to play back (`playReplay`): its commands, run again (`CommandReplay`), or the frames\n * a watcher of it was sent (`FramesReplay`)\n *\n * @beta\n */\nexport type Replay = FramesReplay | CommandReplay\n\n/**\n * A game recorded as the frames a watcher of it was sent: only what `player` saw, and what it was sent of it\n *\n * @beta\n */\nexport interface FramesReplay {\n\t/** The replay's file format, always 1 for a frames replay */\n\tformat: 1\n\t/** The game it is of, by id: a page plays back what it has */\n\tgame: string\n\t/** Whose side it was seen from: their lines and cinematics, everything in sight besides */\n\tplayer: PlayerId\n\t/** Ticks per second the game ran at */\n\ttickRate: number\n\t/** The tick it started and ended at */\n\tfrom: number\n\t/** The tick the recording ended at */\n\tto: number\n\t/** What the host sent, as it sent it, with the tick of the world then */\n\tframes: [tick: number, message: string][]\n}\n\n/**\n * A game being recorded\n *\n * @beta\n */\nexport interface ReplayRecorder {\n\t/** Ticks recorded so far */\n\treadonly ticks: number\n\t/** Stops, and gives what was recorded */\n\tstop(): Replay\n}\n\n/**\n * How a game is recorded (`recordGame`): whose side it is seen from when played back, and which kind of replay.\n * `commands` (the default) keeps the start and what the players told it, and plays it back by running it again: a few\n * kilobytes, every side of it, and the same to the last bit while the rules are (determinism D4). `frames` keeps what a\n * watcher from `player`'s side was sent, `sendRate` times a second: for a game whose rules cannot be run again\n *\n * @beta\n */\nexport interface RecordOptions {\n\t/** The player whose side the replay is seen from when played back */\n\tplayer: PlayerId\n\t/** Which kind of replay to make: `commands` (the default) or `frames` */\n\tkind?: 'commands' | 'frames'\n\t/** Frames a second, of a `frames` replay: 10 when left out */\n\tsendRate?: number\n\t/** Ticks between the hashes a `commands` replay keeps: 300 when left out */\n\tevery?: number\n\t/**\n\t * Ticks between the checkpoints a `commands` replay keeps (the world as a save, to be played from a moment without\n\t * running all before it: going back, opening it halfway). None when left out: each is as big as a save @beta\n\t */\n\tcheckpoints?: number\n}\n\n/** How often the recorder looks whether the world went on, a second: it keeps what changed at its own rate */\nconst LOOKS = 30\n\n/**\n * The tick a message says it brings, to answer that it got there: of a delta, from the head of its text where it comes\n * first; of the welcome, of the first frame it carries\n */\nconst tickOf = (message: string): number | undefined => {\n\tconst found =\n\t\t/^\\{\"type\":\"delta\",\"tick\":(\\d+)/.exec(message) ?? (message.startsWith('{\"type\":\"welcome\"') ? /\"first\":\\{\"tick\":(\\d+)/.exec(message) : null)\n\treturn found ? Number(found[1]) : undefined\n}\n\n/**\n * Records a game played in the page (`RecordOptions`): as its start and its players' commands (`kind: 'commands'`,\n * the default: `recordCommands`), or as an observer from `player`'s side sees it, what changed `sendRate` times a\n * second (`kind: 'frames'`). Frames are answered at once, as by a watcher who missed nothing, so what is kept is what\n * changed and not the whole world again\n *\n * @beta\n */\nexport function recordGame(world: World, options: RecordOptions): ReplayRecorder {\n\tif ((options.kind ?? 'commands') === 'commands') return recordCommands(world, options)\n\tconst host = new SessionHost(world, { sendRate: options.sendRate ?? 10 })\n\tconst frames: FramesReplay['frames'] = []\n\tconst from = world.tick\n\tlet answer: (text: string) => void = () => {}\n\tconst transport: Transport = {\n\t\tsend(message) {\n\t\t\tframes.push([world.tick, message])\n\t\t\tconst tick = tickOf(message)\n\t\t\tif (tick !== undefined) answer(JSON.stringify({ type: 'ack', tick }))\n\t\t},\n\t\tonMessage: (handler) => (answer = handler),\n\t\tonClose: () => {},\n\t\tclose: () => {}\n\t}\n\thost.connect(options.player, transport, { readOnly: true, observer: true })\n\tlet last = performance.now()\n\tconst timer = setInterval(() => {\n\t\tconst now = performance.now()\n\t\thost.publish((now - last) / 1000)\n\t\tlast = now\n\t}, 1000 / LOOKS)\n\tlet replay: FramesReplay | undefined\n\treturn {\n\t\tget ticks() {\n\t\t\treturn world.tick - from\n\t\t},\n\t\tstop() {\n\t\t\tif (replay) return replay\n\t\t\tclearInterval(timer)\n\t\t\thost.dispose()\n\t\t\treplay = { format: 1, game: world.registry.game, player: options.player, tickRate: world.tickRate, from, to: world.tick, frames }\n\t\t\treturn replay\n\t\t}\n\t}\n}\n\n/**\n * A replay playing (`playReplay`): its session, and its clock\n *\n * @beta\n */\nexport interface ReplayPlayer {\n\t/** The game as it was, once the welcome is in */\n\tsession: Promise<RemoteSession>\n\t/** The tick of the game it is at */\n\treadonly tick: number\n\t/** How fast it plays: 1 as it was played, 0 holds it */\n\tspeed: number\n\t/**\n\t * Goes to a tick, ahead or back, run (or handed over) a slice a look (`REPLAY_SLICE`) so that the page goes on\n\t * meanwhile: `behind` says how much is left. Back starts again in the same session (`RemoteSession.resume`): a\n\t * replay of commands from the last checkpoint before the tick, one of frames from its start\n\t */\n\tskipTo(tick: number): void\n\t/** Ticks still to run (or hand over) to come to the moment asked, by a seek or a fast speed: 0 while it keeps up */\n\treadonly behind: number\n\t/** Whether all of it has played */\n\treadonly ended: boolean\n\t/**\n\t * Of a replay of commands, the tick it came apart from the game recorded at (its hash differed: the rules changed\n\t * since), or null while it has not. Never for a replay of frames\n\t */\n\treadonly apart?: number | null\n\t/** Stops playing the replay and lets go of what it holds */\n\tstop(): void\n}\n\n/**\n * Plays a replay back, as a watcher's session (`connect`): a replay of commands run again (`playCommands`), or what the\n * host sent coming in as it came, by the replay's ticks; `speed` times as fast. `game` is the game module it is of, or\n * the modules the page has, by id\n *\n * @beta\n */\nexport function playReplay(\n\treplay: Replay,\n\toptions: {\n\t\trules: Rules | Record<string, Rules>\n\t\tat?: number\n\t\t/** What the app kept in the world beside the game's (`CreateWorldOptions.components`): a replay of commands loads its saves with them */\n\t\tcomponents?: readonly Component<unknown, unknown>[]\n\t\t/** Who builds the navigation of the world a replay of commands runs again, and where what was built is kept: its own thread when left out */\n\t\tnavigation?: NavigationBuilds\n\t}\n): ReplayPlayer {\n\tif (replay.format === 2) {\n\t\tconst games = options.rules\n\t\tconst game = 'units' in games && typeof games.id === 'string' ? (games as Rules) : (games as Record<string, Rules>)[replay.game]\n\t\tif (!game) throw new Error(`This page does not have the game the replay is of (${replay.game})`)\n\t\treturn playCommands(replay, { rules: game, at: options.at, components: options.components, navigation: options.navigation })\n\t}\n\tlet deliver: (text: string) => void = () => {}\n\t// what a watcher says back (that it got a tick, a ping) goes nowhere: nothing is playing at the other end\n\tconst watching = (): Transport => ({ send: () => {}, onMessage: (handler) => void (deliver = handler), onClose: () => {}, close: () => {} })\n\tconst within = (tick: number) => Math.min(Math.max(tick, replay.from), replay.to)\n\tlet next = 0\n\t/** The moment it is asked to be at: the clock, or where a seek goes */\n\tlet due = within(options.at ?? replay.from)\n\tlet last = performance.now()\n\t/** The tick of the last frame handed to the session */\n\tconst shown = () => (next > 0 ? replay.frames[next - 1][0] : replay.from)\n\t/** Whether frames are still to be handed over to come to the moment asked */\n\tconst pending = () => next < replay.frames.length && replay.frames[next][0] <= due\n\tlet session: RemoteSession | undefined\n\tconst player: ReplayPlayer = {\n\t\tsession: connect(watching(), { rules: options.rules }),\n\t\tget tick() {\n\t\t\treturn pending() ? shown() : due\n\t\t},\n\t\tspeed: 1,\n\t\tskipTo(target) {\n\t\t\tdue = within(target)\n\t\t\t// back: what changed is told against what came before it, so the session takes it all again from the welcome\n\t\t\tif (session && due < shown()) {\n\t\t\t\tnext = 0\n\t\t\t\tvoid session.resume(watching()).catch(() => undefined)\n\t\t\t\tdeliver(replay.frames[next++]?.[1] ?? '')\n\t\t\t}\n\t\t},\n\t\tget behind() {\n\t\t\treturn pending() ? Math.max(Math.floor(due) - shown(), 1) : 0\n\t\t},\n\t\tget ended() {\n\t\t\treturn next >= replay.frames.length\n\t\t},\n\t\tstop() {\n\t\t\tstopped = true\n\t\t\tclearInterval(timer)\n\t\t}\n\t}\n\t/** Hands the session the frames up to the moment asked, until `deadline` is past */\n\tconst flush = (deadline: number) => {\n\t\tlet handed = 0\n\t\twhile (pending()) {\n\t\t\tdeliver(replay.frames[next++][1])\n\t\t\tif (++handed % 16 === 0 && performance.now() > deadline) return\n\t\t}\n\t}\n\t// the welcome at once; the rest once the session has made its map of it, from where it is to start, a slice a look\n\tlet timer: ReturnType<typeof setInterval> | undefined\n\tlet stopped = false\n\tdeliver(replay.frames[next++]?.[1] ?? '')\n\tplayer.session.then(\n\t\t(made) => {\n\t\t\tif (stopped) return\n\t\t\tsession = made\n\t\t\tlast = performance.now()\n\t\t\ttimer = setInterval(() => {\n\t\t\t\tconst now = performance.now()\n\t\t\t\tif (!pending()) due = Math.min(due + ((now - last) / 1000) * replay.tickRate * player.speed, replay.to)\n\t\t\t\tlast = now\n\t\t\t\tflush(now + REPLAY_SLICE)\n\t\t\t}, 1000 / LOOKS)\n\t\t},\n\t\t() => undefined\n\t)\n\treturn player\n}\n"],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ //#region src/session/seed.ts
2
+ /**
3
+ * A seed of the moment, for a game no other was (the clock: a session's, never the rules'): where every new world made without a seed of its own gets its seed
4
+ * (a map played in a page, on a server, in a worker). The same seed, the same game
5
+ *
6
+ * @beta
7
+ */
8
+ var randomSeed = () => Date.now() % 1e5;
9
+ //#endregion
10
+ export { randomSeed };
11
+
12
+ //# sourceMappingURL=seed.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"seed.js","names":[],"sources":["../../src/session/seed.ts"],"sourcesContent":["/**\n * A seed of the moment, for a game no other was (the clock: a session's, never the rules'): where every new world made without a seed of its own gets its seed\n * (a map played in a page, on a server, in a worker). The same seed, the same game\n *\n * @beta\n */\nexport const randomSeed = (): number => Date.now() % 100000\n"],"mappings":";;;;;;;AAMA,IAAa,mBAA2B,KAAK,IAAI,IAAI"}
@@ -42,7 +42,11 @@ export type RelayNotice =
42
42
  type: 'ended';
43
43
  key: string;
44
44
  };
45
- /** @beta */
45
+ /**
46
+ * What `shareGame` is given: the relay's address, the key and name of the share and whose side watchers see
47
+ *
48
+ * @beta
49
+ */
46
50
  export interface ShareOptions {
47
51
  /** The relay's address, `ws://host:port` */
48
52
  url: string;
@@ -0,0 +1,94 @@
1
+ import { SessionHost } from "./remote.js";
2
+ import { openSocket } from "./socket.js";
3
+ //#region src/session/share.ts
4
+ /** How often the host looks whether the world went on, a second: it sends at its own rate */
5
+ var LOOKS = 30;
6
+ /**
7
+ * Shares the page's world through a relay, for others to watch. Fails when the relay cannot be reached
8
+ *
9
+ * @beta
10
+ */
11
+ async function shareGame(world, options) {
12
+ const relay = await openSocket(options.url);
13
+ const host = new SessionHost(world, { sendRate: options.sendRate });
14
+ /** Each watcher's end of the connection, as the host holds it: what the relay brings from them goes to it */
15
+ const ends = /* @__PURE__ */ new Map();
16
+ let state = "shared";
17
+ let changed = () => {};
18
+ const ask = (request) => relay.send(JSON.stringify(request));
19
+ const seat = (id) => {
20
+ const end = {
21
+ message: (_text) => {},
22
+ closed: () => {}
23
+ };
24
+ ends.set(id, end);
25
+ host.connect(options.player, {
26
+ send: (text) => ask({
27
+ type: "send",
28
+ to: id,
29
+ text
30
+ }),
31
+ onMessage: (handler) => end.message = handler,
32
+ onClose: (handler) => end.closed = handler,
33
+ close: () => {}
34
+ }, {
35
+ readOnly: true,
36
+ observer: true
37
+ });
38
+ };
39
+ let last = performance.now();
40
+ const timer = setInterval(() => {
41
+ const now = performance.now();
42
+ host.publish((now - last) / 1e3);
43
+ last = now;
44
+ }, 1e3 / LOOKS);
45
+ /** Over once: closed, or never shared as the key was taken */
46
+ const stop = (next = "closed") => {
47
+ if (state !== "shared") return;
48
+ clearInterval(timer);
49
+ host.dispose();
50
+ ends.clear();
51
+ state = next;
52
+ changed();
53
+ };
54
+ relay.onMessage((text) => {
55
+ const notice = JSON.parse(text);
56
+ if (notice.type === "taken") {
57
+ stop("taken");
58
+ relay.close();
59
+ } else if (notice.type === "watcher") {
60
+ seat(notice.id);
61
+ changed();
62
+ } else if (notice.type === "from") ends.get(notice.watcher)?.message(notice.text);
63
+ else if (notice.type === "gone") {
64
+ ends.get(notice.watcher)?.closed();
65
+ ends.delete(notice.watcher);
66
+ changed();
67
+ }
68
+ });
69
+ relay.onClose(() => stop());
70
+ ask({
71
+ type: "share",
72
+ key: options.key,
73
+ name: options.name
74
+ });
75
+ return {
76
+ get state() {
77
+ return state;
78
+ },
79
+ get watchers() {
80
+ return ends.size;
81
+ },
82
+ onChange(handler) {
83
+ changed = handler;
84
+ },
85
+ close() {
86
+ stop();
87
+ relay.close();
88
+ }
89
+ };
90
+ }
91
+ //#endregion
92
+ export { shareGame };
93
+
94
+ //# sourceMappingURL=share.js.map