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.
- package/bin/vimp-sim.js +19 -1
- package/core/Cargo.toml +1 -1
- package/package.json +1 -1
- package/src/client/components/controller/Controls.js +5 -0
- package/src/client/components/controller/Lobby.js +4 -4
- package/src/client/components/controller/RoomMenu.js +43 -0
- package/src/client/components/controller/Vote.js +18 -2
- package/src/client/components/model/ClientReports.js +6 -2
- package/src/client/components/model/Controls.js +27 -0
- package/src/client/components/model/Games.js +5 -1
- package/src/client/components/model/Lobby.js +32 -24
- package/src/client/components/model/LobbyAuth.js +20 -4
- package/src/client/components/model/RoomMenu.js +121 -0
- package/src/client/components/model/Stat.js +2 -1
- package/src/client/components/model/Vote.js +122 -4
- package/src/client/components/view/Auth.js +20 -10
- package/src/client/components/view/ClientReports.js +16 -5
- package/src/client/components/view/Games.js +39 -14
- package/src/client/components/view/Lobby.js +90 -43
- package/src/client/components/view/LobbyAuth.js +13 -7
- package/src/client/components/view/Panel.js +1 -2
- package/src/client/components/view/RoomMenu.js +69 -0
- package/src/client/debug.js +24 -1
- package/src/client/lib/FpsMeter.js +46 -0
- package/src/client/lib/JoinRetry.js +73 -0
- package/src/client/lib/diagnostics.js +28 -5
- package/src/client/lib/hostCaps.js +82 -0
- package/src/client/lib/hostUnloadGuard.js +108 -0
- package/src/client/lib/hostVoteCommand.js +92 -0
- package/src/client/lib/pageReload.js +29 -0
- package/src/client/lib/roomLink.js +257 -0
- package/src/client/lib/signalingErrors.js +74 -0
- package/src/client/main.js +674 -451
- package/src/client/network/HiddenHostHealthLog.js +76 -0
- package/src/client/network/HostConnectionManager.js +62 -8
- package/src/client/network/HostController.js +376 -23
- package/src/client/network/HostHealthPolicy.js +307 -0
- package/src/client/network/HostHealthReporter.js +54 -0
- package/src/client/network/HostPrewarm.js +235 -0
- package/src/client/network/LoopbackTransport.js +16 -1
- package/src/client/network/PlannedHandoff.js +366 -0
- package/src/client/network/Promotion.js +420 -0
- package/src/client/network/RoomPeersReporter.js +81 -0
- package/src/client/network/SessionSupervisor.js +730 -0
- package/src/client/network/SignalingClient.js +183 -30
- package/src/client/network/StandbyReceiver.js +287 -0
- package/src/client/network/StandbySender.js +319 -0
- package/src/client/network/TokenHandoffTimer.js +81 -0
- package/src/client/network/WebRtcManager.js +338 -11
- package/src/client/network/policyClose.js +32 -2
- package/src/client/network/standbyChunks.js +185 -0
- package/src/client/session/GuestSession.js +428 -0
- package/src/client/session/HandoffFlow.js +399 -0
- package/src/client/session/HostRole.js +708 -0
- package/src/client/session/Membership.js +179 -0
- package/src/client/session/PromotionFlow.js +325 -0
- package/src/client/session/RouteBoot.js +432 -0
- package/src/client/session/StandbyRole.js +195 -0
- package/src/client/session/hostRoomPrep.js +152 -0
- package/src/client/session/roomContext.js +32 -0
- package/src/client/style.css +83 -22
- package/src/client/views/gameShell.js +7 -0
- package/src/client/views/includes/informer.pug +4 -0
- package/src/client/views/includes/lobby.pug +0 -3
- package/src/client/views/includes/roomMenu.pug +9 -0
- package/src/client/views/index.pug +1 -0
- package/src/config/closeCodes.js +1 -1
- package/src/config/env.js +37 -0
- package/src/config/hostDefaults.js +24 -0
- package/src/config/lobby.js +154 -3
- package/src/config/master.js +104 -21
- package/src/config/wsports.js +8 -0
- package/src/devtools/RecordingSocketManager.js +3 -2
- package/src/devtools/ScenarioRunner.js +123 -8
- package/src/devtools/VirtualClient.js +20 -0
- package/src/devtools/contract/format.js +4 -1
- package/src/devtools/contract/index.js +1 -2
- package/src/devtools/contract/rules/a2-package-scripts.js +1 -3
- package/src/devtools/contract/rules/b8-system-messages.js +1 -1
- package/src/devtools/contract/rules/b9-vote-names.js +25 -1
- package/src/devtools/contract/rules/c11-stat-mode.js +4 -1
- package/src/devtools/contract/rules/c6-stat-columns.js +1 -1
- package/src/devtools/contract/rules/c7-key-sets.js +8 -4
- package/src/devtools/contract/rules/d3-snapshot-interp.js +2 -1
- package/src/devtools/contract/rules/e1-sound-pairs.js +3 -1
- package/src/devtools/contract/rules/e4-map-layers.js +13 -2
- package/src/devtools/contract/rules/e5-map-radar-walls.js +7 -1
- package/src/devtools/contract/rules/index.js +38 -5
- package/src/devtools/invariants.js +10 -4
- package/src/devtools/pluginLoader.js +1 -4
- package/src/devtools/report.js +17 -1
- package/src/host/DebugRecorder.js +6 -1
- package/src/host/GameCoreAdapter.js +45 -0
- package/src/host/HostGame.js +928 -59
- package/src/host/PortMachine.js +268 -20
- package/src/host/host.worker.js +222 -16
- package/src/host/meta/SocketManager.js +20 -0
- package/src/host/meta/core/RoundManager.js +89 -14
- package/src/host/meta/modules/Accolades.js +4 -1
- package/src/host/meta/modules/Panel.js +30 -0
- package/src/host/meta/modules/PlayerDataSync.js +255 -46
- package/src/host/meta/modules/RTTManager.js +34 -0
- package/src/host/meta/modules/TimerManager.js +215 -18
- package/src/host/meta/modules/chat/systemMessages.js +22 -0
- package/src/host/meta/player/HumanParticipant.js +10 -0
- package/src/host/meta/player/ParticipantManager.js +98 -5
- package/src/lib/AbstractTimer.js +63 -1
- package/src/lib/Publisher.js +26 -0
- package/src/lib/capabilities.js +5 -0
- package/src/lib/checkpointCodec.js +125 -0
- package/src/lib/clientIp.js +9 -2
- package/src/lib/createHostRuntime.js +95 -6
- package/src/lib/formOptions.js +3 -1
- package/src/lib/gameConfigView.js +10 -0
- package/src/lib/gameId.js +13 -0
- package/src/lib/jwt.js +3 -1
- package/src/lib/loadGamePackage.js +2 -2
- package/src/lib/resumeKey.js +38 -0
- package/src/lib/roomId.js +39 -0
- package/src/lib/roomSettings.js +59 -0
- package/src/lib/validators.js +7 -0
- package/tests/fixtures/generations/gen-api3/host/ScriptedManager.js +2 -3
- package/tests/fixtures/generations/gen-api3/host/fakeCore.js +31 -5
- package/tests/fixtures/generations/gen-api3/manifest.json +1 -3
- package/tests/fixtures/generations/gen-api4/host/ScriptedManager.js +2 -3
- package/tests/fixtures/generations/gen-api4/host/fakeCore.js +31 -5
- package/tests/fixtures/generations/gen-api4/manifest.json +1 -3
- package/tests/fixtures/miniGame/config/client.js +15 -0
- package/tests/fixtures/miniGame/host/ScriptedManager.js +2 -3
- 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,
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
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(
|
|
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(
|
|
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
|
-
|
|
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(
|
|
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)
|
package/src/devtools/report.js
CHANGED
|
@@ -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(
|
|
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({
|
|
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
|
+
}
|