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
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
// Сводка здоровья хоста за эпизод скрытой вкладки (host-migration этап
|
|
2
|
+
// 9a): браузер троттлит Worker скрытой вкладки (этап 0), и в журнал
|
|
3
|
+
// клиентских ошибок уходит, насколько просел матч, — одна запись на эпизод,
|
|
4
|
+
// а не на каждую секунду (журнал дедуплицирует по коду и хранит details
|
|
5
|
+
// только первой записи).
|
|
6
|
+
//
|
|
7
|
+
// Эпизод закрывается возвратом видимости, потерей роли хоста или
|
|
8
|
+
// выгрузкой страницы (flush). Следующие эпизоды той же сессии журнал
|
|
9
|
+
// склеивает с первым: растёт счётчик, details остаются первого — осознанно.
|
|
10
|
+
// Эпизод без единой метрики (матч стоял, скрытие короче окна цикла) не
|
|
11
|
+
// пишется. Без DOM: видимость сообщает владелец.
|
|
12
|
+
|
|
13
|
+
export const HIDDEN_HEALTH_CODE = 'engine.host.hiddenHealth';
|
|
14
|
+
|
|
15
|
+
export default class HiddenHostHealthLog {
|
|
16
|
+
/**
|
|
17
|
+
* @param {Object} options
|
|
18
|
+
* @param {Function} options.warn - (code, summary) запись в журнал.
|
|
19
|
+
* @param {boolean} [options.hidden] - вкладка скрыта в момент создания.
|
|
20
|
+
* @param {Function} [options.now] - монотонные часы, мс.
|
|
21
|
+
*/
|
|
22
|
+
constructor({ warn, hidden = false, now = () => performance.now() }) {
|
|
23
|
+
this._warn = warn;
|
|
24
|
+
this._now = now;
|
|
25
|
+
this._episode = null;
|
|
26
|
+
|
|
27
|
+
this.setHidden(hidden);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
setHidden(hidden) {
|
|
31
|
+
if (hidden && !this._episode) {
|
|
32
|
+
this._episode = {
|
|
33
|
+
startedAt: this._now(),
|
|
34
|
+
samples: 0,
|
|
35
|
+
minTickRate: Infinity,
|
|
36
|
+
maxGapMs: 0,
|
|
37
|
+
lostMs: 0,
|
|
38
|
+
};
|
|
39
|
+
} else if (!hidden) {
|
|
40
|
+
this.flush();
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// метрика Worker'а (HostController.onHealth): в зачёт только скрытой вкладки
|
|
45
|
+
add(health) {
|
|
46
|
+
const episode = this._episode;
|
|
47
|
+
|
|
48
|
+
if (!episode || !health) {
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
episode.samples += 1;
|
|
53
|
+
episode.minTickRate = Math.min(episode.minTickRate, health.tickRate);
|
|
54
|
+
episode.maxGapMs = Math.max(episode.maxGapMs, health.maxGapMs);
|
|
55
|
+
episode.lostMs += health.lostMs;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// закрыть эпизод (если идёт) и записать сводку
|
|
59
|
+
flush() {
|
|
60
|
+
const episode = this._episode;
|
|
61
|
+
|
|
62
|
+
this._episode = null;
|
|
63
|
+
|
|
64
|
+
if (!episode || episode.samples === 0) {
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
this._warn(HIDDEN_HEALTH_CODE, {
|
|
69
|
+
hiddenMs: Math.round(this._now() - episode.startedAt),
|
|
70
|
+
samples: episode.samples,
|
|
71
|
+
minTickRate: episode.minTickRate,
|
|
72
|
+
maxGapMs: episode.maxGapMs,
|
|
73
|
+
lostMs: episode.lostMs,
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
}
|
|
@@ -26,7 +26,8 @@ export default class HostConnectionManager {
|
|
|
26
26
|
this._threshold = opts.backpressureThreshold ?? 262144; // 256 КБ
|
|
27
27
|
this._onPeersChange = opts.onPeersChange;
|
|
28
28
|
|
|
29
|
-
|
|
29
|
+
// clientId → { pc, meta, state, openCount, memberId }
|
|
30
|
+
this._peers = new Map();
|
|
30
31
|
|
|
31
32
|
signaling.publisher.on('webrtc_offer', 'onOffer', this);
|
|
32
33
|
signaling.publisher.on('ice_candidate', 'onRemoteCandidate', this);
|
|
@@ -35,19 +36,39 @@ export default class HostConnectionManager {
|
|
|
35
36
|
|
|
36
37
|
// приём SDP-оффера клиента: создаёт peer, отвечает answer
|
|
37
38
|
async onOffer(msg) {
|
|
38
|
-
|
|
39
|
+
// memberId — id вкладки гостя (переживает реконнект сигналинга);
|
|
40
|
+
// понадобится назначению преемника (host-migration, этап 6)
|
|
41
|
+
const { clientId, sdp, memberId = null } = msg;
|
|
42
|
+
// переподключение гостя к матчу (host-migration этап 4): Worker не
|
|
43
|
+
// начнёт хендшейк, а будет ждать RESUME_REQUEST
|
|
44
|
+
const resume = msg.resume === true;
|
|
39
45
|
|
|
40
46
|
if (this._peers.has(clientId)) {
|
|
41
|
-
|
|
47
|
+
// гость с тем же сигнальным id переподключается: для него прежнее
|
|
48
|
+
// соединение уже мертво, а у нас ещё полуоткрыто — снять его
|
|
49
|
+
// (Worker отсоединит участника и дождётся возобновления)
|
|
50
|
+
if (!resume) {
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
this._closePeer(clientId);
|
|
42
55
|
}
|
|
43
56
|
|
|
44
57
|
const pc = this._peerFactory({ iceServers: this._iceServers });
|
|
45
|
-
const peer = {
|
|
58
|
+
const peer = {
|
|
59
|
+
pc,
|
|
60
|
+
meta: null,
|
|
61
|
+
state: null,
|
|
62
|
+
openCount: 0,
|
|
63
|
+
memberId,
|
|
64
|
+
resume,
|
|
65
|
+
};
|
|
46
66
|
|
|
47
67
|
this._peers.set(clientId, peer);
|
|
48
68
|
|
|
49
69
|
// каналы создаёт offerer — ловим их здесь
|
|
50
|
-
pc.ondatachannel = event =>
|
|
70
|
+
pc.ondatachannel = event =>
|
|
71
|
+
this._wireChannel(clientId, peer, event.channel);
|
|
51
72
|
|
|
52
73
|
pc.onicecandidate = event => {
|
|
53
74
|
if (event.candidate) {
|
|
@@ -123,11 +144,14 @@ export default class HostConnectionManager {
|
|
|
123
144
|
peer.openCount += 1;
|
|
124
145
|
|
|
125
146
|
// оба канала открыты — поднимаем соединение клиента в Worker'е
|
|
126
|
-
// (Worker сразу шлёт CONFIG_DATA по meta
|
|
147
|
+
// (Worker сразу шлёт CONFIG_DATA по meta, а при resume ждёт
|
|
148
|
+
// RESUME_REQUEST)
|
|
127
149
|
if (peer.openCount === 2) {
|
|
128
150
|
this._controller.open(clientId, {
|
|
129
|
-
onMessage: (payload, reliable) =>
|
|
151
|
+
onMessage: (payload, reliable) =>
|
|
152
|
+
this._deliver(peer, payload, reliable),
|
|
130
153
|
onClose: () => this._closePeer(clientId),
|
|
154
|
+
resume: peer.resume,
|
|
131
155
|
});
|
|
132
156
|
|
|
133
157
|
this._onPeersChange?.(this._peers.size);
|
|
@@ -182,7 +206,37 @@ export default class HostConnectionManager {
|
|
|
182
206
|
this._onPeersChange?.(this._peers.size);
|
|
183
207
|
}
|
|
184
208
|
|
|
185
|
-
//
|
|
209
|
+
// RTCPeerConnection гостя по memberId (канал standby преемнику,
|
|
210
|
+
// host-migration этап 6): только пир с открытыми meta/state; null — нет
|
|
211
|
+
peerConnectionOf(memberId) {
|
|
212
|
+
if (!memberId) {
|
|
213
|
+
return null;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
for (const peer of this._peers.values()) {
|
|
217
|
+
if (peer.memberId === memberId && peer.openCount === 2) {
|
|
218
|
+
return peer.pc;
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
return null;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
// memberId гостей с открытыми meta и state — отчёт room_peers мастеру
|
|
226
|
+
// (кого хост действительно видит)
|
|
227
|
+
connectedMemberIds() {
|
|
228
|
+
const ids = [];
|
|
229
|
+
|
|
230
|
+
for (const peer of this._peers.values()) {
|
|
231
|
+
if (peer.openCount === 2 && peer.memberId) {
|
|
232
|
+
ids.push(peer.memberId);
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
return ids;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
// число активных пиров
|
|
186
240
|
get peerCount() {
|
|
187
241
|
return this._peers.size;
|
|
188
242
|
}
|