@zaisma/game-server 1.4.0 → 1.5.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 (342) hide show
  1. package/README.md +2 -0
  2. package/bench/brand/.assetsignore +4 -0
  3. package/bench/brand/README.md +51 -0
  4. package/bench/brand/_headers +13 -0
  5. package/bench/brand/app-icon-1024.png +0 -0
  6. package/bench/brand/app-icon-192.png +0 -0
  7. package/bench/brand/app-icon-512.png +0 -0
  8. package/bench/brand/apple-touch-icon.png +0 -0
  9. package/bench/brand/cover-guide/coin-cascade-busy-fine.webp +0 -0
  10. package/bench/brand/cover-guide/gem-grid-cover.webp +0 -0
  11. package/bench/brand/cover-guide/gem-grid-screenshot.webp +0 -0
  12. package/bench/brand/cover-guide/good-arena.webp +0 -0
  13. package/bench/brand/cover-guide/good-four-in-a-row.webp +0 -0
  14. package/bench/brand/cover-guide/lava-leap-extra-text.webp +0 -0
  15. package/bench/brand/cover-guide/lava-leap-fake-reward.webp +0 -0
  16. package/bench/brand/cover-guide/lava-leap-fine.webp +0 -0
  17. package/bench/brand/cover-guide/lava-leap-overlay.webp +0 -0
  18. package/bench/brand/cover-guide/screenshot-fine.webp +0 -0
  19. package/bench/brand/cover-guide/screenshot-not-fine.webp +0 -0
  20. package/bench/brand/design/covers/ashen-crown.webp +0 -0
  21. package/bench/brand/design/covers/frostline.webp +0 -0
  22. package/bench/brand/design/covers/glasswing.webp +0 -0
  23. package/bench/brand/design/covers/hollow-tide.webp +0 -0
  24. package/bench/brand/design/covers/iron-vigil.webp +0 -0
  25. package/bench/brand/design/covers/kestrel.webp +0 -0
  26. package/bench/brand/design/covers/neon-drift.webp +0 -0
  27. package/bench/brand/design/covers/verdant.webp +0 -0
  28. package/bench/brand/favicon-32.png +0 -0
  29. package/bench/brand/favicon.ico +0 -0
  30. package/bench/brand/favicon.svg +1 -0
  31. package/bench/brand/flags/LICENSE +21 -0
  32. package/bench/brand/flags/ad.png +0 -0
  33. package/bench/brand/flags/ae.png +0 -0
  34. package/bench/brand/flags/af.png +0 -0
  35. package/bench/brand/flags/ag.png +0 -0
  36. package/bench/brand/flags/ai.png +0 -0
  37. package/bench/brand/flags/al.png +0 -0
  38. package/bench/brand/flags/am.png +0 -0
  39. package/bench/brand/flags/ao.png +0 -0
  40. package/bench/brand/flags/aq.png +0 -0
  41. package/bench/brand/flags/ar.png +0 -0
  42. package/bench/brand/flags/as.png +0 -0
  43. package/bench/brand/flags/at.png +0 -0
  44. package/bench/brand/flags/au.png +0 -0
  45. package/bench/brand/flags/aw.png +0 -0
  46. package/bench/brand/flags/ax.png +0 -0
  47. package/bench/brand/flags/az.png +0 -0
  48. package/bench/brand/flags/ba.png +0 -0
  49. package/bench/brand/flags/bb.png +0 -0
  50. package/bench/brand/flags/bd.png +0 -0
  51. package/bench/brand/flags/be.png +0 -0
  52. package/bench/brand/flags/bf.png +0 -0
  53. package/bench/brand/flags/bg.png +0 -0
  54. package/bench/brand/flags/bh.png +0 -0
  55. package/bench/brand/flags/bi.png +0 -0
  56. package/bench/brand/flags/bj.png +0 -0
  57. package/bench/brand/flags/bl.png +0 -0
  58. package/bench/brand/flags/bm.png +0 -0
  59. package/bench/brand/flags/bn.png +0 -0
  60. package/bench/brand/flags/bo.png +0 -0
  61. package/bench/brand/flags/bq.png +0 -0
  62. package/bench/brand/flags/br.png +0 -0
  63. package/bench/brand/flags/bs.png +0 -0
  64. package/bench/brand/flags/bt.png +0 -0
  65. package/bench/brand/flags/bv.png +0 -0
  66. package/bench/brand/flags/bw.png +0 -0
  67. package/bench/brand/flags/by.png +0 -0
  68. package/bench/brand/flags/bz.png +0 -0
  69. package/bench/brand/flags/ca.png +0 -0
  70. package/bench/brand/flags/cc.png +0 -0
  71. package/bench/brand/flags/cd.png +0 -0
  72. package/bench/brand/flags/cf.png +0 -0
  73. package/bench/brand/flags/cg.png +0 -0
  74. package/bench/brand/flags/ch.png +0 -0
  75. package/bench/brand/flags/ci.png +0 -0
  76. package/bench/brand/flags/ck.png +0 -0
  77. package/bench/brand/flags/cl.png +0 -0
  78. package/bench/brand/flags/cm.png +0 -0
  79. package/bench/brand/flags/cn.png +0 -0
  80. package/bench/brand/flags/co.png +0 -0
  81. package/bench/brand/flags/cp.png +0 -0
  82. package/bench/brand/flags/cr.png +0 -0
  83. package/bench/brand/flags/cu.png +0 -0
  84. package/bench/brand/flags/cv.png +0 -0
  85. package/bench/brand/flags/cw.png +0 -0
  86. package/bench/brand/flags/cx.png +0 -0
  87. package/bench/brand/flags/cy.png +0 -0
  88. package/bench/brand/flags/cz.png +0 -0
  89. package/bench/brand/flags/de.png +0 -0
  90. package/bench/brand/flags/dg.png +0 -0
  91. package/bench/brand/flags/dj.png +0 -0
  92. package/bench/brand/flags/dk.png +0 -0
  93. package/bench/brand/flags/dm.png +0 -0
  94. package/bench/brand/flags/do.png +0 -0
  95. package/bench/brand/flags/dz.png +0 -0
  96. package/bench/brand/flags/ec.png +0 -0
  97. package/bench/brand/flags/ee.png +0 -0
  98. package/bench/brand/flags/eg.png +0 -0
  99. package/bench/brand/flags/eh.png +0 -0
  100. package/bench/brand/flags/er.png +0 -0
  101. package/bench/brand/flags/es.png +0 -0
  102. package/bench/brand/flags/et.png +0 -0
  103. package/bench/brand/flags/eu.png +0 -0
  104. package/bench/brand/flags/fi.png +0 -0
  105. package/bench/brand/flags/fj.png +0 -0
  106. package/bench/brand/flags/fk.png +0 -0
  107. package/bench/brand/flags/fm.png +0 -0
  108. package/bench/brand/flags/fo.png +0 -0
  109. package/bench/brand/flags/fr.png +0 -0
  110. package/bench/brand/flags/ga.png +0 -0
  111. package/bench/brand/flags/gb.png +0 -0
  112. package/bench/brand/flags/gd.png +0 -0
  113. package/bench/brand/flags/ge.png +0 -0
  114. package/bench/brand/flags/gf.png +0 -0
  115. package/bench/brand/flags/gg.png +0 -0
  116. package/bench/brand/flags/gh.png +0 -0
  117. package/bench/brand/flags/gi.png +0 -0
  118. package/bench/brand/flags/gl.png +0 -0
  119. package/bench/brand/flags/gm.png +0 -0
  120. package/bench/brand/flags/gn.png +0 -0
  121. package/bench/brand/flags/gp.png +0 -0
  122. package/bench/brand/flags/gq.png +0 -0
  123. package/bench/brand/flags/gr.png +0 -0
  124. package/bench/brand/flags/gs.png +0 -0
  125. package/bench/brand/flags/gt.png +0 -0
  126. package/bench/brand/flags/gu.png +0 -0
  127. package/bench/brand/flags/gw.png +0 -0
  128. package/bench/brand/flags/gy.png +0 -0
  129. package/bench/brand/flags/hk.png +0 -0
  130. package/bench/brand/flags/hm.png +0 -0
  131. package/bench/brand/flags/hn.png +0 -0
  132. package/bench/brand/flags/hr.png +0 -0
  133. package/bench/brand/flags/ht.png +0 -0
  134. package/bench/brand/flags/hu.png +0 -0
  135. package/bench/brand/flags/ic.png +0 -0
  136. package/bench/brand/flags/id.png +0 -0
  137. package/bench/brand/flags/ie.png +0 -0
  138. package/bench/brand/flags/il.png +0 -0
  139. package/bench/brand/flags/im.png +0 -0
  140. package/bench/brand/flags/in.png +0 -0
  141. package/bench/brand/flags/io.png +0 -0
  142. package/bench/brand/flags/iq.png +0 -0
  143. package/bench/brand/flags/ir.png +0 -0
  144. package/bench/brand/flags/is.png +0 -0
  145. package/bench/brand/flags/it.png +0 -0
  146. package/bench/brand/flags/je.png +0 -0
  147. package/bench/brand/flags/jm.png +0 -0
  148. package/bench/brand/flags/jo.png +0 -0
  149. package/bench/brand/flags/jp.png +0 -0
  150. package/bench/brand/flags/ke.png +0 -0
  151. package/bench/brand/flags/kg.png +0 -0
  152. package/bench/brand/flags/kh.png +0 -0
  153. package/bench/brand/flags/ki.png +0 -0
  154. package/bench/brand/flags/km.png +0 -0
  155. package/bench/brand/flags/kn.png +0 -0
  156. package/bench/brand/flags/kp.png +0 -0
  157. package/bench/brand/flags/kr.png +0 -0
  158. package/bench/brand/flags/kw.png +0 -0
  159. package/bench/brand/flags/ky.png +0 -0
  160. package/bench/brand/flags/kz.png +0 -0
  161. package/bench/brand/flags/la.png +0 -0
  162. package/bench/brand/flags/lb.png +0 -0
  163. package/bench/brand/flags/lc.png +0 -0
  164. package/bench/brand/flags/li.png +0 -0
  165. package/bench/brand/flags/lk.png +0 -0
  166. package/bench/brand/flags/lr.png +0 -0
  167. package/bench/brand/flags/ls.png +0 -0
  168. package/bench/brand/flags/lt.png +0 -0
  169. package/bench/brand/flags/lu.png +0 -0
  170. package/bench/brand/flags/lv.png +0 -0
  171. package/bench/brand/flags/ly.png +0 -0
  172. package/bench/brand/flags/ma.png +0 -0
  173. package/bench/brand/flags/mc.png +0 -0
  174. package/bench/brand/flags/md.png +0 -0
  175. package/bench/brand/flags/me.png +0 -0
  176. package/bench/brand/flags/mf.png +0 -0
  177. package/bench/brand/flags/mg.png +0 -0
  178. package/bench/brand/flags/mh.png +0 -0
  179. package/bench/brand/flags/mk.png +0 -0
  180. package/bench/brand/flags/ml.png +0 -0
  181. package/bench/brand/flags/mm.png +0 -0
  182. package/bench/brand/flags/mn.png +0 -0
  183. package/bench/brand/flags/mo.png +0 -0
  184. package/bench/brand/flags/mp.png +0 -0
  185. package/bench/brand/flags/mq.png +0 -0
  186. package/bench/brand/flags/mr.png +0 -0
  187. package/bench/brand/flags/ms.png +0 -0
  188. package/bench/brand/flags/mt.png +0 -0
  189. package/bench/brand/flags/mu.png +0 -0
  190. package/bench/brand/flags/mv.png +0 -0
  191. package/bench/brand/flags/mw.png +0 -0
  192. package/bench/brand/flags/mx.png +0 -0
  193. package/bench/brand/flags/my.png +0 -0
  194. package/bench/brand/flags/mz.png +0 -0
  195. package/bench/brand/flags/na.png +0 -0
  196. package/bench/brand/flags/nc.png +0 -0
  197. package/bench/brand/flags/ne.png +0 -0
  198. package/bench/brand/flags/nf.png +0 -0
  199. package/bench/brand/flags/ng.png +0 -0
  200. package/bench/brand/flags/ni.png +0 -0
  201. package/bench/brand/flags/nl.png +0 -0
  202. package/bench/brand/flags/no.png +0 -0
  203. package/bench/brand/flags/np.png +0 -0
  204. package/bench/brand/flags/nr.png +0 -0
  205. package/bench/brand/flags/nu.png +0 -0
  206. package/bench/brand/flags/nz.png +0 -0
  207. package/bench/brand/flags/om.png +0 -0
  208. package/bench/brand/flags/pa.png +0 -0
  209. package/bench/brand/flags/pc.png +0 -0
  210. package/bench/brand/flags/pe.png +0 -0
  211. package/bench/brand/flags/pf.png +0 -0
  212. package/bench/brand/flags/pg.png +0 -0
  213. package/bench/brand/flags/ph.png +0 -0
  214. package/bench/brand/flags/pk.png +0 -0
  215. package/bench/brand/flags/pl.png +0 -0
  216. package/bench/brand/flags/pm.png +0 -0
  217. package/bench/brand/flags/pn.png +0 -0
  218. package/bench/brand/flags/pr.png +0 -0
  219. package/bench/brand/flags/ps.png +0 -0
  220. package/bench/brand/flags/pt.png +0 -0
  221. package/bench/brand/flags/pw.png +0 -0
  222. package/bench/brand/flags/py.png +0 -0
  223. package/bench/brand/flags/qa.png +0 -0
  224. package/bench/brand/flags/re.png +0 -0
  225. package/bench/brand/flags/ro.png +0 -0
  226. package/bench/brand/flags/rs.png +0 -0
  227. package/bench/brand/flags/ru.png +0 -0
  228. package/bench/brand/flags/rw.png +0 -0
  229. package/bench/brand/flags/sa.png +0 -0
  230. package/bench/brand/flags/sb.png +0 -0
  231. package/bench/brand/flags/sc.png +0 -0
  232. package/bench/brand/flags/sd.png +0 -0
  233. package/bench/brand/flags/se.png +0 -0
  234. package/bench/brand/flags/sg.png +0 -0
  235. package/bench/brand/flags/sh.png +0 -0
  236. package/bench/brand/flags/si.png +0 -0
  237. package/bench/brand/flags/sj.png +0 -0
  238. package/bench/brand/flags/sk.png +0 -0
  239. package/bench/brand/flags/sl.png +0 -0
  240. package/bench/brand/flags/sm.png +0 -0
  241. package/bench/brand/flags/sn.png +0 -0
  242. package/bench/brand/flags/so.png +0 -0
  243. package/bench/brand/flags/sr.png +0 -0
  244. package/bench/brand/flags/ss.png +0 -0
  245. package/bench/brand/flags/st.png +0 -0
  246. package/bench/brand/flags/sv.png +0 -0
  247. package/bench/brand/flags/sx.png +0 -0
  248. package/bench/brand/flags/sy.png +0 -0
  249. package/bench/brand/flags/sz.png +0 -0
  250. package/bench/brand/flags/tc.png +0 -0
  251. package/bench/brand/flags/td.png +0 -0
  252. package/bench/brand/flags/tf.png +0 -0
  253. package/bench/brand/flags/tg.png +0 -0
  254. package/bench/brand/flags/th.png +0 -0
  255. package/bench/brand/flags/tj.png +0 -0
  256. package/bench/brand/flags/tk.png +0 -0
  257. package/bench/brand/flags/tl.png +0 -0
  258. package/bench/brand/flags/tm.png +0 -0
  259. package/bench/brand/flags/tn.png +0 -0
  260. package/bench/brand/flags/to.png +0 -0
  261. package/bench/brand/flags/tr.png +0 -0
  262. package/bench/brand/flags/tt.png +0 -0
  263. package/bench/brand/flags/tv.png +0 -0
  264. package/bench/brand/flags/tw.png +0 -0
  265. package/bench/brand/flags/tz.png +0 -0
  266. package/bench/brand/flags/ua.png +0 -0
  267. package/bench/brand/flags/ug.png +0 -0
  268. package/bench/brand/flags/um.png +0 -0
  269. package/bench/brand/flags/un.png +0 -0
  270. package/bench/brand/flags/us.png +0 -0
  271. package/bench/brand/flags/uy.png +0 -0
  272. package/bench/brand/flags/uz.png +0 -0
  273. package/bench/brand/flags/va.png +0 -0
  274. package/bench/brand/flags/vc.png +0 -0
  275. package/bench/brand/flags/ve.png +0 -0
  276. package/bench/brand/flags/vg.png +0 -0
  277. package/bench/brand/flags/vi.png +0 -0
  278. package/bench/brand/flags/vn.png +0 -0
  279. package/bench/brand/flags/vu.png +0 -0
  280. package/bench/brand/flags/wf.png +0 -0
  281. package/bench/brand/flags/ws.png +0 -0
  282. package/bench/brand/flags/xk.png +0 -0
  283. package/bench/brand/flags/xx.png +0 -0
  284. package/bench/brand/flags/ye.png +0 -0
  285. package/bench/brand/flags/yt.png +0 -0
  286. package/bench/brand/flags/za.png +0 -0
  287. package/bench/brand/flags/zm.png +0 -0
  288. package/bench/brand/flags/zw.png +0 -0
  289. package/bench/brand/fonts/OFL.txt +93 -0
  290. package/bench/brand/fonts/jost.7726a5cd.woff2 +0 -0
  291. package/bench/brand/loader/gif/zaisma-loader-black-128.gif +0 -0
  292. package/bench/brand/loader/gif/zaisma-loader-black-512.gif +0 -0
  293. package/bench/brand/loader/gif/zaisma-loader-white-128.gif +0 -0
  294. package/bench/brand/loader/gif/zaisma-loader-white-512.gif +0 -0
  295. package/bench/brand/loader/png/zaisma-loader-black-128.png +0 -0
  296. package/bench/brand/loader/png/zaisma-loader-black-512.png +0 -0
  297. package/bench/brand/loader/png/zaisma-loader-white-128.png +0 -0
  298. package/bench/brand/loader/png/zaisma-loader-white-512.png +0 -0
  299. package/bench/brand/loader/webp/zaisma-loader-black-128.webp +0 -0
  300. package/bench/brand/loader/webp/zaisma-loader-black-512.webp +0 -0
  301. package/bench/brand/loader/webp/zaisma-loader-white-128.webp +0 -0
  302. package/bench/brand/loader/webp/zaisma-loader-white-512.webp +0 -0
  303. package/bench/brand/loader/zaisma-loader-black.svg +1 -0
  304. package/bench/brand/loader/zaisma-loader-white.svg +1 -0
  305. package/bench/brand/loader/zaisma-loader.svg +1 -0
  306. package/bench/brand/sign-in/city-day-phone.webp +0 -0
  307. package/bench/brand/sign-in/city-day.webp +0 -0
  308. package/bench/brand/sign-in/city-night-phone.webp +0 -0
  309. package/bench/brand/sign-in/city-night.webp +0 -0
  310. package/bench/brand/zaisma-app-icon.svg +1 -0
  311. package/bench/brand/zaisma-mark-black-2048.png +0 -0
  312. package/bench/brand/zaisma-mark-black.svg +1 -0
  313. package/bench/brand/zaisma-mark-metal-2048.png +0 -0
  314. package/bench/brand/zaisma-mark-metal.svg +1 -0
  315. package/bench/brand/zaisma-mark-small-black.svg +1 -0
  316. package/bench/brand/zaisma-mark-small-white.svg +1 -0
  317. package/bench/brand/zaisma-mark-tricolor.svg +1 -0
  318. package/bench/brand/zaisma-mark-white-2048.png +0 -0
  319. package/bench/brand/zaisma-mark-white.svg +1 -0
  320. package/bench/brand/zaisma-wordmark-black-2400.png +0 -0
  321. package/bench/brand/zaisma-wordmark-black.svg +1 -0
  322. package/bench/brand/zaisma-wordmark-metal-2400.png +0 -0
  323. package/bench/brand/zaisma-wordmark-metal.svg +1 -0
  324. package/bench/brand/zaisma-wordmark-white-2400.png +0 -0
  325. package/bench/brand/zaisma-wordmark-white.svg +1 -0
  326. package/bench/glass.js +46466 -0
  327. package/bin/local-play-bench.d.ts +8 -0
  328. package/bin/local-play-bench.js +218 -0
  329. package/bin/local-play-certificate.js +99 -0
  330. package/bin/local-play-runner.js +43 -0
  331. package/bin/local-play.d.ts +41 -0
  332. package/bin/local-play.js +1567 -0
  333. package/bin/node.js +66 -1
  334. package/package.json +1 -1
  335. package/sdk/picture.js +97 -0
  336. package/sdk/relay.js +269 -0
  337. package/sdk/saves.js +884 -0
  338. package/sdk/zaisma.d.ts +1720 -0
  339. package/sdk/zaisma.js +2374 -0
  340. package/src/qr-code.d.ts +20 -0
  341. package/src/qr-code.js +319 -0
  342. package/src/room.js +1 -1
@@ -0,0 +1,20 @@
1
+ /**
2
+ * QR codes for game and room links (docs/DECISIONS.md, "QR codes"): players get one behind Share,
3
+ * developers on the dashboard and through the API and MCP. Byte mode, error correction level M,
4
+ * versions 1 to 10 (up to 213 bytes, far more than a link needs). Written here rather than taken from a
5
+ * package so the site's page and the API draw the same code with no dependency; it follows ISO/IEC
6
+ * 18004 the way Project Nayuki's reference encoder does.
7
+ */
8
+ export declare const QR_CODE_LIMITS: {
9
+ /** Version 10 at level M holds 213 bytes. */
10
+ readonly maximumTextBytes: 213;
11
+ /** Light modules around the code, as the standard asks. */
12
+ readonly quietZoneModuleCount: 4;
13
+ };
14
+ /**
15
+ * The code's modules for `text`, as rows of dark (true) and light (false), with no quiet zone. Throws
16
+ * a RangeError when the text is over QR_CODE_LIMITS.maximumTextBytes in UTF-8.
17
+ */
18
+ export declare function qrCodeModules(text: string): boolean[][];
19
+ /** The code for `text` as an SVG document: dark modules on white, with the quiet zone, one unit a module. */
20
+ export declare function qrCodeSvg(text: string): string;
package/src/qr-code.js ADDED
@@ -0,0 +1,319 @@
1
+ /**
2
+ * QR codes for game and room links (docs/DECISIONS.md, "QR codes"): players get one behind Share,
3
+ * developers on the dashboard and through the API and MCP. Byte mode, error correction level M,
4
+ * versions 1 to 10 (up to 213 bytes, far more than a link needs). Written here rather than taken from a
5
+ * package so the site's page and the API draw the same code with no dependency; it follows ISO/IEC
6
+ * 18004 the way Project Nayuki's reference encoder does.
7
+ */
8
+ export const QR_CODE_LIMITS = {
9
+ /** Version 10 at level M holds 213 bytes. */
10
+ maximumTextBytes: 213,
11
+ /** Light modules around the code, as the standard asks. */
12
+ quietZoneModuleCount: 4,
13
+ };
14
+ // Level M: error correction codewords per block and blocks, by version (index 0 unused).
15
+ const ERROR_CORRECTION_CODEWORD_COUNTS_PER_BLOCK = [0, 10, 16, 26, 18, 24, 16, 18, 22, 22, 26];
16
+ const ERROR_CORRECTION_BLOCK_COUNTS = [0, 1, 1, 1, 2, 2, 4, 4, 4, 5, 5];
17
+ /** Error correction level M (medium)'s two bits in the format information. */
18
+ const MEDIUM_CORRECTION_FORMAT_NUMBER = 0;
19
+ const HIGHEST_VERSION_NUMBER = 10;
20
+ const isBitSet = (bitsNumber, bitIndex) => ((bitsNumber >>> bitIndex) & 1) !== 0;
21
+ function rawDataModuleCount(versionNumber) {
22
+ let moduleCount = (16 * versionNumber + 128) * versionNumber + 64;
23
+ if (versionNumber >= 2) {
24
+ const alignmentCount = Math.floor(versionNumber / 7) + 2;
25
+ moduleCount -= (25 * alignmentCount - 10) * alignmentCount - 55;
26
+ if (versionNumber >= 7)
27
+ moduleCount -= 36;
28
+ }
29
+ return moduleCount;
30
+ }
31
+ const dataCodewordCount = (versionNumber) => Math.floor(rawDataModuleCount(versionNumber) / 8) - ERROR_CORRECTION_CODEWORD_COUNTS_PER_BLOCK[versionNumber] * ERROR_CORRECTION_BLOCK_COUNTS[versionNumber];
32
+ // Reed-Solomon over GF(256) with the polynomial 0x11D.
33
+ function multiplied(leftNumber, rightNumber) {
34
+ let productNumber = 0;
35
+ for (let bitIndex = 7; bitIndex >= 0; bitIndex--) {
36
+ productNumber = (productNumber << 1) ^ ((productNumber >>> 7) * 0x11d);
37
+ productNumber ^= ((rightNumber >>> bitIndex) & 1) * leftNumber;
38
+ }
39
+ return productNumber;
40
+ }
41
+ function divisorOf(degreeCount) {
42
+ const coefficients = new Array(degreeCount).fill(0);
43
+ coefficients[degreeCount - 1] = 1;
44
+ let rootNumber = 1;
45
+ for (let stepIndex = 0; stepIndex < degreeCount; stepIndex++) {
46
+ for (let index = 0; index < coefficients.length; index++) {
47
+ coefficients[index] = multiplied(coefficients[index], rootNumber);
48
+ if (index + 1 < coefficients.length)
49
+ coefficients[index] = coefficients[index] ^ coefficients[index + 1];
50
+ }
51
+ rootNumber = multiplied(rootNumber, 0x02);
52
+ }
53
+ return coefficients;
54
+ }
55
+ function remainderOf(codewords, divisor) {
56
+ const remainders = divisor.map(() => 0);
57
+ for (const codewordNumber of codewords) {
58
+ const factorNumber = codewordNumber ^ remainders.shift();
59
+ remainders.push(0);
60
+ divisor.forEach((coefficientNumber, index) => (remainders[index] = remainders[index] ^ multiplied(coefficientNumber, factorNumber)));
61
+ }
62
+ return remainders;
63
+ }
64
+ /** The data codewords with their error correction, split into blocks and interleaved. */
65
+ function withErrorCorrection(dataCodewords, versionNumber) {
66
+ const blockCount = ERROR_CORRECTION_BLOCK_COUNTS[versionNumber];
67
+ const blockCorrectionCount = ERROR_CORRECTION_CODEWORD_COUNTS_PER_BLOCK[versionNumber];
68
+ const rawCodewordCount = Math.floor(rawDataModuleCount(versionNumber) / 8);
69
+ const shortBlockCount = blockCount - (rawCodewordCount % blockCount);
70
+ const shortBlockCodewordCount = Math.floor(rawCodewordCount / blockCount);
71
+ const divisor = divisorOf(blockCorrectionCount);
72
+ const blocks = [];
73
+ for (let blockIndex = 0, startIndex = 0; blockIndex < blockCount; blockIndex++) {
74
+ const block = dataCodewords.slice(startIndex, startIndex + shortBlockCodewordCount - blockCorrectionCount + (blockIndex < shortBlockCount ? 0 : 1));
75
+ startIndex += block.length;
76
+ const correction = remainderOf(block, divisor);
77
+ if (blockIndex < shortBlockCount)
78
+ block.push(0);
79
+ blocks.push(block.concat(correction));
80
+ }
81
+ const interleaved = [];
82
+ for (let codewordIndex = 0; codewordIndex < blocks[0].length; codewordIndex++) {
83
+ blocks.forEach((block, blockIndex) => {
84
+ if (codewordIndex !== shortBlockCodewordCount - blockCorrectionCount || blockIndex >= shortBlockCount)
85
+ interleaved.push(block[codewordIndex]);
86
+ });
87
+ }
88
+ return interleaved;
89
+ }
90
+ function alignmentIndexes(versionNumber, sideModuleCount) {
91
+ if (versionNumber === 1)
92
+ return [];
93
+ const alignmentCount = Math.floor(versionNumber / 7) + 2;
94
+ const stepModuleCount = Math.ceil((versionNumber * 4 + 4) / (alignmentCount * 2 - 2)) * 2;
95
+ const indexes = [6];
96
+ for (let moduleIndex = sideModuleCount - 7; indexes.length < alignmentCount; moduleIndex -= stepModuleCount)
97
+ indexes.splice(1, 0, moduleIndex);
98
+ return indexes;
99
+ }
100
+ /** The standard's eight masks, by column and row. */
101
+ const MASKS = [
102
+ (columnIndex, rowIndex) => (columnIndex + rowIndex) % 2 === 0,
103
+ (...indexes) => indexes[1] % 2 === 0,
104
+ (columnIndex) => columnIndex % 3 === 0,
105
+ (columnIndex, rowIndex) => (columnIndex + rowIndex) % 3 === 0,
106
+ (columnIndex, rowIndex) => (Math.floor(columnIndex / 3) + Math.floor(rowIndex / 2)) % 2 === 0,
107
+ (columnIndex, rowIndex) => ((columnIndex * rowIndex) % 2) + ((columnIndex * rowIndex) % 3) === 0,
108
+ (columnIndex, rowIndex) => (((columnIndex * rowIndex) % 2) + ((columnIndex * rowIndex) % 3)) % 2 === 0,
109
+ (columnIndex, rowIndex) => (((columnIndex + rowIndex) % 2) + ((columnIndex * rowIndex) % 3)) % 2 === 0,
110
+ ];
111
+ /** A score for how hard a masked code is to read (lower is better), from the standard's rules. */
112
+ function penaltyPointCount(modules) {
113
+ const sideModuleCount = modules.length;
114
+ let pointCount = 0;
115
+ const scoreLines = (isDarkAt) => {
116
+ for (let lineIndex = 0; lineIndex < sideModuleCount; lineIndex++) {
117
+ let runModuleCount = 0;
118
+ let isRunDark = false;
119
+ const line = [];
120
+ for (let alongIndex = 0; alongIndex < sideModuleCount; alongIndex++) {
121
+ const isDark = isDarkAt(lineIndex, alongIndex);
122
+ line.push(isDark);
123
+ if (alongIndex > 0 && isDark === isRunDark) {
124
+ runModuleCount++;
125
+ if (runModuleCount === 5)
126
+ pointCount += 3;
127
+ else if (runModuleCount > 5)
128
+ pointCount++;
129
+ }
130
+ else {
131
+ isRunDark = isDark;
132
+ runModuleCount = 1;
133
+ }
134
+ }
135
+ // Finder-like runs: dark-light-dark-dark-dark-light-dark with four light modules on a side.
136
+ const padded = [false, false, false, false, ...line, false, false, false, false];
137
+ for (let startIndex = 0; startIndex + 11 <= padded.length; startIndex++) {
138
+ const isDarkAtOffset = (offsetIndex) => padded[startIndex + offsetIndex];
139
+ if (!(isDarkAtOffset(4) && !isDarkAtOffset(5) && isDarkAtOffset(6) && isDarkAtOffset(7) && isDarkAtOffset(8) && !isDarkAtOffset(9) && isDarkAtOffset(10)))
140
+ continue;
141
+ const isLightBefore = !isDarkAtOffset(0) && !isDarkAtOffset(1) && !isDarkAtOffset(2) && !isDarkAtOffset(3);
142
+ const isLightAfter = startIndex + 15 <= padded.length && !isDarkAtOffset(11) && !isDarkAtOffset(12) && !isDarkAtOffset(13) && !isDarkAtOffset(14);
143
+ if (isLightBefore || isLightAfter)
144
+ pointCount += 40;
145
+ }
146
+ }
147
+ };
148
+ scoreLines((rowIndex, columnIndex) => modules[rowIndex][columnIndex]);
149
+ scoreLines((columnIndex, rowIndex) => modules[rowIndex][columnIndex]);
150
+ for (let rowIndex = 0; rowIndex + 1 < sideModuleCount; rowIndex++) {
151
+ for (let columnIndex = 0; columnIndex + 1 < sideModuleCount; columnIndex++) {
152
+ const isDark = modules[rowIndex][columnIndex];
153
+ if (isDark === modules[rowIndex][columnIndex + 1] && isDark === modules[rowIndex + 1][columnIndex] && isDark === modules[rowIndex + 1][columnIndex + 1])
154
+ pointCount += 3;
155
+ }
156
+ }
157
+ const darkModuleCount = modules.flat().filter(Boolean).length;
158
+ const moduleCount = sideModuleCount * sideModuleCount;
159
+ pointCount += (Math.ceil(Math.abs(darkModuleCount * 20 - moduleCount * 10) / moduleCount) - 1) * 10;
160
+ return pointCount;
161
+ }
162
+ /**
163
+ * The code's modules for `text`, as rows of dark (true) and light (false), with no quiet zone. Throws
164
+ * a RangeError when the text is over QR_CODE_LIMITS.maximumTextBytes in UTF-8.
165
+ */
166
+ export function qrCodeModules(text) {
167
+ const textBytes = [...new TextEncoder().encode(text)];
168
+ const neededBitCount = (candidateNumber) => 4 + (candidateNumber < 10 ? 8 : 16) + textBytes.length * 8;
169
+ let versionNumber = 1;
170
+ while (versionNumber <= HIGHEST_VERSION_NUMBER && neededBitCount(versionNumber) > dataCodewordCount(versionNumber) * 8)
171
+ versionNumber++;
172
+ if (versionNumber > HIGHEST_VERSION_NUMBER)
173
+ throw new RangeError(`The text is ${textBytes.length} bytes; a QR code here holds at most ${QR_CODE_LIMITS.maximumTextBytes}.`);
174
+ // The bit stream: byte mode, the length, the bytes, a terminator, then padding.
175
+ const capacityBitCount = dataCodewordCount(versionNumber) * 8;
176
+ const bits = [];
177
+ const append = (bitsNumber, bitCount) => {
178
+ for (let bitIndex = bitCount - 1; bitIndex >= 0; bitIndex--)
179
+ bits.push((bitsNumber >>> bitIndex) & 1);
180
+ };
181
+ append(0b0100, 4);
182
+ append(textBytes.length, versionNumber < 10 ? 8 : 16);
183
+ for (const textByte of textBytes)
184
+ append(textByte, 8);
185
+ append(0, Math.min(4, capacityBitCount - bits.length));
186
+ append(0, (8 - (bits.length % 8)) % 8);
187
+ for (let padByte = 0xec; bits.length < capacityBitCount; padByte ^= 0xec ^ 0x11)
188
+ append(padByte, 8);
189
+ const dataCodewords = [];
190
+ for (let bitIndex = 0; bitIndex < bits.length; bitIndex += 8)
191
+ dataCodewords.push(bits.slice(bitIndex, bitIndex + 8).reduce((byteNumber, bitNumber) => (byteNumber << 1) | bitNumber, 0));
192
+ const codewords = withErrorCorrection(dataCodewords, versionNumber);
193
+ const sideModuleCount = versionNumber * 4 + 17;
194
+ const modules = Array.from({ length: sideModuleCount }, () => new Array(sideModuleCount).fill(false));
195
+ const isFunction = Array.from({ length: sideModuleCount }, () => new Array(sideModuleCount).fill(false));
196
+ const setFunction = (columnIndex, rowIndex, isDark) => {
197
+ modules[rowIndex][columnIndex] = isDark;
198
+ isFunction[rowIndex][columnIndex] = true;
199
+ };
200
+ for (let moduleIndex = 0; moduleIndex < sideModuleCount; moduleIndex++) {
201
+ setFunction(6, moduleIndex, moduleIndex % 2 === 0);
202
+ setFunction(moduleIndex, 6, moduleIndex % 2 === 0);
203
+ }
204
+ const finderCenters = [[3, 3], [sideModuleCount - 4, 3], [3, sideModuleCount - 4]];
205
+ for (const [centerColumnIndex, centerRowIndex] of finderCenters) {
206
+ for (let rowOffsetIndex = -4; rowOffsetIndex <= 4; rowOffsetIndex++) {
207
+ for (let columnOffsetIndex = -4; columnOffsetIndex <= 4; columnOffsetIndex++) {
208
+ const columnIndex = centerColumnIndex + columnOffsetIndex;
209
+ const rowIndex = centerRowIndex + rowOffsetIndex;
210
+ const ringIndex = Math.max(Math.abs(columnOffsetIndex), Math.abs(rowOffsetIndex));
211
+ if (columnIndex >= 0 && columnIndex < sideModuleCount && rowIndex >= 0 && rowIndex < sideModuleCount)
212
+ setFunction(columnIndex, rowIndex, ringIndex !== 2 && ringIndex !== 4);
213
+ }
214
+ }
215
+ }
216
+ const alignments = alignmentIndexes(versionNumber, sideModuleCount);
217
+ const lastAlignmentIndex = alignments.length - 1;
218
+ alignments.forEach((centerColumnIndex, alignmentColumnIndex) => alignments.forEach((centerRowIndex, alignmentRowIndex) => {
219
+ const isCorner = (alignmentColumnIndex === 0 && alignmentRowIndex === 0) || (alignmentColumnIndex === 0 && alignmentRowIndex === lastAlignmentIndex) || (alignmentColumnIndex === lastAlignmentIndex && alignmentRowIndex === 0);
220
+ if (isCorner)
221
+ return;
222
+ for (let rowOffsetIndex = -2; rowOffsetIndex <= 2; rowOffsetIndex++) {
223
+ for (let columnOffsetIndex = -2; columnOffsetIndex <= 2; columnOffsetIndex++) {
224
+ setFunction(centerColumnIndex + columnOffsetIndex, centerRowIndex + rowOffsetIndex, Math.max(Math.abs(columnOffsetIndex), Math.abs(rowOffsetIndex)) !== 1);
225
+ }
226
+ }
227
+ }));
228
+ const drawFormat = (maskIndex) => {
229
+ const formatNumber = (MEDIUM_CORRECTION_FORMAT_NUMBER << 3) | maskIndex;
230
+ let remainderNumber = formatNumber;
231
+ for (let stepIndex = 0; stepIndex < 10; stepIndex++)
232
+ remainderNumber = (remainderNumber << 1) ^ ((remainderNumber >>> 9) * 0x537);
233
+ const formatBitsNumber = ((formatNumber << 10) | remainderNumber) ^ 0x5412;
234
+ for (let bitIndex = 0; bitIndex <= 5; bitIndex++)
235
+ setFunction(8, bitIndex, isBitSet(formatBitsNumber, bitIndex));
236
+ setFunction(8, 7, isBitSet(formatBitsNumber, 6));
237
+ setFunction(8, 8, isBitSet(formatBitsNumber, 7));
238
+ setFunction(7, 8, isBitSet(formatBitsNumber, 8));
239
+ for (let bitIndex = 9; bitIndex < 15; bitIndex++)
240
+ setFunction(14 - bitIndex, 8, isBitSet(formatBitsNumber, bitIndex));
241
+ for (let bitIndex = 0; bitIndex < 8; bitIndex++)
242
+ setFunction(sideModuleCount - 1 - bitIndex, 8, isBitSet(formatBitsNumber, bitIndex));
243
+ for (let bitIndex = 8; bitIndex < 15; bitIndex++)
244
+ setFunction(8, sideModuleCount - 15 + bitIndex, isBitSet(formatBitsNumber, bitIndex));
245
+ setFunction(8, sideModuleCount - 8, true);
246
+ };
247
+ drawFormat(0);
248
+ if (versionNumber >= 7) {
249
+ let remainderNumber = versionNumber;
250
+ for (let stepIndex = 0; stepIndex < 12; stepIndex++)
251
+ remainderNumber = (remainderNumber << 1) ^ ((remainderNumber >>> 11) * 0x1f25);
252
+ const versionBitsNumber = (versionNumber << 12) | remainderNumber;
253
+ for (let bitIndex = 0; bitIndex < 18; bitIndex++) {
254
+ const farIndex = sideModuleCount - 11 + (bitIndex % 3);
255
+ const nearIndex = Math.floor(bitIndex / 3);
256
+ setFunction(farIndex, nearIndex, isBitSet(versionBitsNumber, bitIndex));
257
+ setFunction(nearIndex, farIndex, isBitSet(versionBitsNumber, bitIndex));
258
+ }
259
+ }
260
+ // The codewords, zigzagging up and down two columns at a time from the bottom right.
261
+ let codewordBitIndex = 0;
262
+ for (let rightColumnIndex = sideModuleCount - 1; rightColumnIndex >= 1; rightColumnIndex -= 2) {
263
+ if (rightColumnIndex === 6)
264
+ rightColumnIndex = 5;
265
+ for (let stepIndex = 0; stepIndex < sideModuleCount; stepIndex++) {
266
+ for (let pairIndex = 0; pairIndex < 2; pairIndex++) {
267
+ const columnIndex = rightColumnIndex - pairIndex;
268
+ const rowIndex = ((rightColumnIndex + 1) & 2) === 0 ? sideModuleCount - 1 - stepIndex : stepIndex;
269
+ if (!isFunction[rowIndex][columnIndex] && codewordBitIndex < codewords.length * 8) {
270
+ modules[rowIndex][columnIndex] = isBitSet(codewords[codewordBitIndex >>> 3], 7 - (codewordBitIndex & 7));
271
+ codewordBitIndex++;
272
+ }
273
+ }
274
+ }
275
+ }
276
+ // The mask that reads best.
277
+ const masked = (maskIndex) => {
278
+ const copy = modules.map((row) => row.slice());
279
+ for (let rowIndex = 0; rowIndex < sideModuleCount; rowIndex++) {
280
+ for (let columnIndex = 0; columnIndex < sideModuleCount; columnIndex++) {
281
+ if (!isFunction[rowIndex][columnIndex] && MASKS[maskIndex](columnIndex, rowIndex))
282
+ copy[rowIndex][columnIndex] = !copy[rowIndex][columnIndex];
283
+ }
284
+ }
285
+ return copy;
286
+ };
287
+ let bestMaskIndex = 0;
288
+ let bestPointCount = Infinity;
289
+ for (let maskIndex = 0; maskIndex < MASKS.length; maskIndex++) {
290
+ drawFormat(maskIndex);
291
+ const pointCount = penaltyPointCount(masked(maskIndex));
292
+ if (pointCount < bestPointCount) {
293
+ bestMaskIndex = maskIndex;
294
+ bestPointCount = pointCount;
295
+ }
296
+ }
297
+ drawFormat(bestMaskIndex);
298
+ return masked(bestMaskIndex);
299
+ }
300
+ /** The code for `text` as an SVG document: dark modules on white, with the quiet zone, one unit a module. */
301
+ export function qrCodeSvg(text) {
302
+ const modules = qrCodeModules(text);
303
+ const marginModuleCount = QR_CODE_LIMITS.quietZoneModuleCount;
304
+ const sideModuleCount = modules.length + marginModuleCount * 2;
305
+ let path = "";
306
+ modules.forEach((row, rowIndex) => {
307
+ for (let columnIndex = 0; columnIndex < row.length; columnIndex++) {
308
+ if (!row[columnIndex])
309
+ continue;
310
+ let runEndIndex = columnIndex;
311
+ while (runEndIndex + 1 < row.length && row[runEndIndex + 1])
312
+ runEndIndex++;
313
+ const runModuleCount = runEndIndex - columnIndex + 1;
314
+ path += `M${columnIndex + marginModuleCount} ${rowIndex + marginModuleCount}h${runModuleCount}v1h-${runModuleCount}z`;
315
+ columnIndex = runEndIndex;
316
+ }
317
+ });
318
+ return `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 ${sideModuleCount} ${sideModuleCount}" shape-rendering="crispEdges"><rect width="${sideModuleCount}" height="${sideModuleCount}" fill="#fff"/><path d="${path}" fill="#000"/></svg>`;
319
+ }
package/src/room.js CHANGED
@@ -1898,7 +1898,7 @@ export class RoomCore {
1898
1898
  const viewerIds = this.stateViewerIds();
1899
1899
  const stateView = this.server.stateView;
1900
1900
  const state = this.state;
1901
- const round = tracker.round(state, viewerIds, stateView ? (viewerId) => stateView(state, (this.players.get(viewerId) ?? this.spectators.get(viewerId)), this.stateViewRoom) : null, this.backedUpViewers(viewerIds));
1901
+ const round = tracker.round(state, viewerIds, stateView ? (viewerId) => stateView(state, { ...(this.players.get(viewerId) ?? this.spectators.get(viewerId)) }, this.stateViewRoom) : null, this.backedUpViewers(viewerIds));
1902
1902
  for (const problem of round.problems)
1903
1903
  console.error(`Game server error: ${problem}`);
1904
1904
  for (const { playerIds, frame } of round.frames)