vimp-engine 0.35.6 → 0.36.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 (130) hide show
  1. package/bin/vimp-sim.js +19 -1
  2. package/core/Cargo.toml +1 -1
  3. package/package.json +1 -1
  4. package/src/client/components/controller/Controls.js +5 -0
  5. package/src/client/components/controller/Lobby.js +4 -4
  6. package/src/client/components/controller/RoomMenu.js +43 -0
  7. package/src/client/components/controller/Vote.js +18 -2
  8. package/src/client/components/model/ClientReports.js +6 -2
  9. package/src/client/components/model/Controls.js +27 -0
  10. package/src/client/components/model/Games.js +5 -1
  11. package/src/client/components/model/Lobby.js +32 -24
  12. package/src/client/components/model/LobbyAuth.js +20 -4
  13. package/src/client/components/model/RoomMenu.js +121 -0
  14. package/src/client/components/model/Stat.js +2 -1
  15. package/src/client/components/model/Vote.js +122 -4
  16. package/src/client/components/view/Auth.js +20 -10
  17. package/src/client/components/view/ClientReports.js +16 -5
  18. package/src/client/components/view/Games.js +39 -14
  19. package/src/client/components/view/Lobby.js +90 -43
  20. package/src/client/components/view/LobbyAuth.js +13 -7
  21. package/src/client/components/view/Panel.js +1 -2
  22. package/src/client/components/view/RoomMenu.js +69 -0
  23. package/src/client/debug.js +24 -1
  24. package/src/client/lib/FpsMeter.js +46 -0
  25. package/src/client/lib/JoinRetry.js +73 -0
  26. package/src/client/lib/diagnostics.js +28 -5
  27. package/src/client/lib/hostCaps.js +82 -0
  28. package/src/client/lib/hostUnloadGuard.js +108 -0
  29. package/src/client/lib/hostVoteCommand.js +92 -0
  30. package/src/client/lib/pageReload.js +29 -0
  31. package/src/client/lib/roomLink.js +257 -0
  32. package/src/client/lib/signalingErrors.js +74 -0
  33. package/src/client/main.js +674 -451
  34. package/src/client/network/HiddenHostHealthLog.js +76 -0
  35. package/src/client/network/HostConnectionManager.js +62 -8
  36. package/src/client/network/HostController.js +376 -23
  37. package/src/client/network/HostHealthPolicy.js +307 -0
  38. package/src/client/network/HostHealthReporter.js +54 -0
  39. package/src/client/network/HostPrewarm.js +235 -0
  40. package/src/client/network/LoopbackTransport.js +16 -1
  41. package/src/client/network/PlannedHandoff.js +366 -0
  42. package/src/client/network/Promotion.js +420 -0
  43. package/src/client/network/RoomPeersReporter.js +81 -0
  44. package/src/client/network/SessionSupervisor.js +730 -0
  45. package/src/client/network/SignalingClient.js +183 -30
  46. package/src/client/network/StandbyReceiver.js +287 -0
  47. package/src/client/network/StandbySender.js +319 -0
  48. package/src/client/network/TokenHandoffTimer.js +81 -0
  49. package/src/client/network/WebRtcManager.js +338 -11
  50. package/src/client/network/policyClose.js +32 -2
  51. package/src/client/network/standbyChunks.js +185 -0
  52. package/src/client/session/GuestSession.js +428 -0
  53. package/src/client/session/HandoffFlow.js +399 -0
  54. package/src/client/session/HostRole.js +708 -0
  55. package/src/client/session/Membership.js +179 -0
  56. package/src/client/session/PromotionFlow.js +325 -0
  57. package/src/client/session/RouteBoot.js +432 -0
  58. package/src/client/session/StandbyRole.js +195 -0
  59. package/src/client/session/hostRoomPrep.js +152 -0
  60. package/src/client/session/roomContext.js +32 -0
  61. package/src/client/style.css +83 -22
  62. package/src/client/views/gameShell.js +7 -0
  63. package/src/client/views/includes/informer.pug +4 -0
  64. package/src/client/views/includes/lobby.pug +0 -3
  65. package/src/client/views/includes/roomMenu.pug +9 -0
  66. package/src/client/views/index.pug +1 -0
  67. package/src/config/closeCodes.js +1 -1
  68. package/src/config/env.js +37 -0
  69. package/src/config/hostDefaults.js +24 -0
  70. package/src/config/lobby.js +154 -3
  71. package/src/config/master.js +104 -21
  72. package/src/config/wsports.js +8 -0
  73. package/src/devtools/RecordingSocketManager.js +3 -2
  74. package/src/devtools/ScenarioRunner.js +123 -8
  75. package/src/devtools/VirtualClient.js +20 -0
  76. package/src/devtools/contract/format.js +4 -1
  77. package/src/devtools/contract/index.js +1 -2
  78. package/src/devtools/contract/rules/a2-package-scripts.js +1 -3
  79. package/src/devtools/contract/rules/b8-system-messages.js +1 -1
  80. package/src/devtools/contract/rules/b9-vote-names.js +25 -1
  81. package/src/devtools/contract/rules/c11-stat-mode.js +4 -1
  82. package/src/devtools/contract/rules/c6-stat-columns.js +1 -1
  83. package/src/devtools/contract/rules/c7-key-sets.js +8 -4
  84. package/src/devtools/contract/rules/d3-snapshot-interp.js +2 -1
  85. package/src/devtools/contract/rules/e1-sound-pairs.js +3 -1
  86. package/src/devtools/contract/rules/e4-map-layers.js +13 -2
  87. package/src/devtools/contract/rules/e5-map-radar-walls.js +7 -1
  88. package/src/devtools/contract/rules/index.js +38 -5
  89. package/src/devtools/invariants.js +10 -4
  90. package/src/devtools/pluginLoader.js +1 -4
  91. package/src/devtools/report.js +17 -1
  92. package/src/host/DebugRecorder.js +6 -1
  93. package/src/host/GameCoreAdapter.js +45 -0
  94. package/src/host/HostGame.js +928 -59
  95. package/src/host/PortMachine.js +268 -20
  96. package/src/host/host.worker.js +222 -16
  97. package/src/host/meta/SocketManager.js +20 -0
  98. package/src/host/meta/core/RoundManager.js +89 -14
  99. package/src/host/meta/modules/Accolades.js +4 -1
  100. package/src/host/meta/modules/Panel.js +30 -0
  101. package/src/host/meta/modules/PlayerDataSync.js +255 -46
  102. package/src/host/meta/modules/RTTManager.js +34 -0
  103. package/src/host/meta/modules/TimerManager.js +215 -18
  104. package/src/host/meta/modules/chat/systemMessages.js +22 -0
  105. package/src/host/meta/player/HumanParticipant.js +10 -0
  106. package/src/host/meta/player/ParticipantManager.js +98 -5
  107. package/src/lib/AbstractTimer.js +63 -1
  108. package/src/lib/Publisher.js +26 -0
  109. package/src/lib/capabilities.js +5 -0
  110. package/src/lib/checkpointCodec.js +125 -0
  111. package/src/lib/clientIp.js +9 -2
  112. package/src/lib/createHostRuntime.js +95 -6
  113. package/src/lib/formOptions.js +3 -1
  114. package/src/lib/gameConfigView.js +10 -0
  115. package/src/lib/gameId.js +13 -0
  116. package/src/lib/jwt.js +3 -1
  117. package/src/lib/loadGamePackage.js +2 -2
  118. package/src/lib/resumeKey.js +38 -0
  119. package/src/lib/roomId.js +39 -0
  120. package/src/lib/roomSettings.js +59 -0
  121. package/src/lib/validators.js +7 -0
  122. package/tests/fixtures/generations/gen-api3/host/ScriptedManager.js +2 -3
  123. package/tests/fixtures/generations/gen-api3/host/fakeCore.js +31 -5
  124. package/tests/fixtures/generations/gen-api3/manifest.json +1 -3
  125. package/tests/fixtures/generations/gen-api4/host/ScriptedManager.js +2 -3
  126. package/tests/fixtures/generations/gen-api4/host/fakeCore.js +31 -5
  127. package/tests/fixtures/generations/gen-api4/manifest.json +1 -3
  128. package/tests/fixtures/miniGame/config/client.js +15 -0
  129. package/tests/fixtures/miniGame/host/ScriptedManager.js +2 -3
  130. package/tests/fixtures/miniGame/host/fakeCore.js +31 -5
@@ -40,11 +40,44 @@ import e7 from './e7-map-game-field.js';
40
40
  // Порядок групп — порядок отчёта: A пакет и сборка, B host, C client,
41
41
  // D снапшот, E ассеты (plan/create-vimp-game/stage_1.md).
42
42
  export const rules = [
43
- a1, a2, a3, a4, a5, a6, a7,
44
- b1, b2, b3, b4, b5, b6, b7, b8, b9, b10,
45
- c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11,
46
- d1, d2, d3,
47
- e1, e2, e3, e4, e5, e6, e7,
43
+ a1,
44
+ a2,
45
+ a3,
46
+ a4,
47
+ a5,
48
+ a6,
49
+ a7,
50
+ b1,
51
+ b2,
52
+ b3,
53
+ b4,
54
+ b5,
55
+ b6,
56
+ b7,
57
+ b8,
58
+ b9,
59
+ b10,
60
+ c1,
61
+ c2,
62
+ c3,
63
+ c4,
64
+ c5,
65
+ c6,
66
+ c7,
67
+ c8,
68
+ c9,
69
+ c10,
70
+ c11,
71
+ d1,
72
+ d2,
73
+ d3,
74
+ e1,
75
+ e2,
76
+ e3,
77
+ e4,
78
+ e5,
79
+ e6,
80
+ e7,
48
81
  ];
49
82
 
50
83
  export default rules;
@@ -35,7 +35,9 @@ const CHECKS = [
35
35
  [12, 'determinism', 'two runs produce a byte-identical frame stream'],
36
36
  ];
37
37
 
38
- const TITLES = new Map(CHECKS.map(([id, name, title]) => [name, { id, title }]));
38
+ const TITLES = new Map(
39
+ CHECKS.map(([id, name, title]) => [name, { id, title }]),
40
+ );
39
41
 
40
42
  /**
41
43
  * Выполняет проверки 1–11 по итогам прогона (12 — только по требованию,
@@ -223,7 +225,9 @@ function frameFormat({ clients, socketManager }) {
223
225
 
224
226
  for (const client of clients) {
225
227
  for (const error of client.decodeErrors) {
226
- violations.push(`${client.socketId}: push_frame threw — ${error.message}`);
228
+ violations.push(
229
+ `${client.socketId}: push_frame threw — ${error.message}`,
230
+ );
227
231
  }
228
232
  }
229
233
 
@@ -277,7 +281,7 @@ function hotLayout({ clients }) {
277
281
  item.message
278
282
  ? `${client.socketId}: ${item.message} (len ${item.len})`
279
283
  : `${client.socketId}: hot buffer len ${item.len}, traversal consumed ` +
280
- `${item.consumed} — record width or group order drifted`,
284
+ `${item.consumed} — record width or group order drifted`,
281
285
  );
282
286
  }
283
287
 
@@ -463,7 +467,9 @@ function predictionDrift({ clients, scenario }) {
463
467
  (client.divergenceStats.dropped ?? 0);
464
468
 
465
469
  if (hidden) {
466
- violations.push(`${client.socketId}: +${hidden} more divergence record(s)`);
470
+ violations.push(
471
+ `${client.socketId}: +${hidden} more divergence record(s)`,
472
+ );
467
473
  }
468
474
  }
469
475
 
@@ -16,10 +16,7 @@ import { loadGamePackage } from '../lib/loadGamePackage.js';
16
16
  // пути в манифесте. Его отсутствие не ошибка — просто игра не прогоняется
17
17
  // headless своим настоящим ядром.
18
18
 
19
- const FIXTURE_DIR = new URL(
20
- '../../tests/fixtures/miniGame/',
21
- import.meta.url,
22
- );
19
+ const FIXTURE_DIR = new URL('../../tests/fixtures/miniGame/', import.meta.url);
23
20
 
24
21
  // значение поля source у фикстуры: по нему отличается «своя игра, схему
25
22
  // которой инструмент знает» от чужого плагина (см. builtinScenario.js)
@@ -103,6 +103,20 @@ export function formatMarkdown(report) {
103
103
  }
104
104
  }
105
105
 
106
+ // смены хоста через контрольную точку: 'soft' у игры, которая ждала
107
+ // 'midRound', — первое, что автор должен увидеть
108
+ if (report.checkpointRestores?.length) {
109
+ lines.push('');
110
+ lines.push('## Host checkpoints');
111
+ lines.push('');
112
+
113
+ for (const restore of report.checkpointRestores) {
114
+ lines.push(
115
+ `- tick ${restore.tick}: \`${restore.mode}\`, ${restore.bytes} B`,
116
+ );
117
+ }
118
+ }
119
+
106
120
  lines.push('');
107
121
 
108
122
  return `${lines.join('\n')}\n`;
@@ -191,7 +205,9 @@ function invariantSection(report) {
191
205
  const mark = { pass: '✅', fail: '❌', skip: '⏭️' }[check.status];
192
206
  const note = check.note ? ` — ${check.note}` : '';
193
207
 
194
- lines.push(`- ${mark} ${check.id}. \`${check.name}\`: ${check.title}${note}`);
208
+ lines.push(
209
+ `- ${mark} ${check.id}. \`${check.name}\`: ${check.title}${note}`,
210
+ );
195
211
 
196
212
  for (const violation of check.violations) {
197
213
  lines.push(` - ${violation}`);
@@ -48,7 +48,12 @@ export default class DebugRecorder {
48
48
  * @param {Array} [params.participants] - [{ gameId, name, model, socketId,
49
49
  * team }] — люди, уже находящиеся в комнате.
50
50
  */
51
- start({ seed = null, map = null, networkSendRate = null, participants = [] }) {
51
+ start({
52
+ seed = null,
53
+ map = null,
54
+ networkSendRate = null,
55
+ participants = [],
56
+ }) {
52
57
  this._reset();
53
58
 
54
59
  this._recording = true;
@@ -241,6 +241,45 @@ export default class GameCoreAdapter {
241
241
  );
242
242
  }
243
243
 
244
+ // ***** контрольная точка (host-migration этап 5) ***** //
245
+
246
+ /**
247
+ * Дамп состояния ядра (замороженный ABI `serialize_state`). Звать только
248
+ * на границе кадра — сразу после packBody: накопители снапшота должны
249
+ * быть опустошены (предусловие ядра).
250
+ * @returns {Uint8Array} Собственная копия байтов в JS-куче.
251
+ * @throws {Error} Ядро не смогло сериализовать мир — точка пропускается.
252
+ */
253
+ serializeState() {
254
+ let bytes;
255
+
256
+ try {
257
+ bytes = this._core.serialize_state();
258
+ } catch (e) {
259
+ throw new Error(`core serialize_state failed: ${errorText(e)}`);
260
+ }
261
+
262
+ if (!(bytes instanceof Uint8Array)) {
263
+ throw new Error('core serialize_state returned no bytes');
264
+ }
265
+
266
+ return bytes;
267
+ }
268
+
269
+ /**
270
+ * Поднимает мир ядра из дампа. Конфиг ядра обязан совпадать с конфигом
271
+ * ядра, снявшего дамп.
272
+ * @param {Uint8Array} bytes
273
+ * @throws {Error} Битый или несовместимый дамп.
274
+ */
275
+ deserializeState(bytes) {
276
+ try {
277
+ this._core.deserialize_state(bytes);
278
+ } catch (e) {
279
+ throw new Error(`core deserialize_state failed: ${errorText(e)}`);
280
+ }
281
+ }
282
+
244
283
  // ***** отладка ***** //
245
284
 
246
285
  /**
@@ -296,3 +335,9 @@ export default class GameCoreAdapter {
296
335
  return Boolean(participant && participant.isScripted);
297
336
  }
298
337
  }
338
+
339
+ // JsError wasm-bindgen и обычный Error — у обоих есть message; строка из
340
+ // throw внутри фейка — тоже ответ
341
+ function errorText(e) {
342
+ return e && e.message ? e.message : String(e);
343
+ }