vimp-engine 0.20.0 → 0.22.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/package.json +1 -1
- package/src/client/components/model/Chat.js +2 -1
- package/src/client/components/model/Stat.js +123 -2
- package/src/client/components/view/Chat.js +8 -0
- package/src/client/components/view/Stat.js +43 -0
- package/src/client/lib/accolades.js +56 -0
- package/src/client/main.js +33 -4
- package/src/client/style.css +25 -4
- package/src/config/lobby.js +64 -0
- package/src/config/master.js +30 -0
- package/src/config/opcodes.js +3 -1
- package/src/config/wsports.js +3 -0
- package/src/devtools/contract/rules/c11-stat-mode.js +60 -0
- package/src/devtools/contract/rules/c4-component-dependencies.js +9 -2
- package/src/devtools/contract/rules/c6-stat-columns.js +29 -1
- package/src/devtools/contract/rules/index.js +2 -1
- package/src/host/HostGame.js +104 -8
- package/src/host/meta/SocketManager.js +11 -0
- package/src/host/meta/core/RoundManager.js +9 -4
- package/src/host/meta/modules/Accolades.js +283 -0
- package/src/host/meta/modules/PlayerDataSync.js +484 -85
- package/src/host/meta/modules/chat/Chat.js +9 -3
- package/src/host/meta/player/Participant.js +6 -0
- package/src/host/meta/player/ParticipantManager.js +16 -0
- package/src/lib/validators.js +47 -0
|
@@ -26,9 +26,15 @@ class Chat {
|
|
|
26
26
|
delete this._userList[gameId];
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
-
// добавляет
|
|
30
|
-
|
|
31
|
-
|
|
29
|
+
// добавляет сообщение. color ('#rrggbb') — цвет ника, который игра задала
|
|
30
|
+
// через ParticipantManager.setChatColor; без него четвёртого элемента в
|
|
31
|
+
// массиве нет вовсе, и провод игры, которая цвет не задаёт, не меняется
|
|
32
|
+
push(message, name, teamId, color) {
|
|
33
|
+
if (typeof color === 'string') {
|
|
34
|
+
this._list.push([message, name, teamId, color]);
|
|
35
|
+
} else {
|
|
36
|
+
this._list.push([message, name, teamId]);
|
|
37
|
+
}
|
|
32
38
|
}
|
|
33
39
|
|
|
34
40
|
// добавляет системное сообщение для всех
|
|
@@ -7,6 +7,12 @@ class Participant {
|
|
|
7
7
|
this.team = team;
|
|
8
8
|
this.teamId = teamId;
|
|
9
9
|
this.status = 'spectator'; // 'spectator' | 'active' | 'dead'
|
|
10
|
+
|
|
11
|
+
// цвет ника в чате ('#rrggbb') или null — тогда ник красит класс команды.
|
|
12
|
+
// Ставит его игра (ParticipantManager.setChatColor): движок не знает, чем
|
|
13
|
+
// игра различает игроков визуально, а команда для этого годится не всегда
|
|
14
|
+
// — в игре на одну команду все ники одного цвета
|
|
15
|
+
this.chatColor = null;
|
|
10
16
|
// индекс точки респауна, занятой этим участником, или null. Раздаёт и
|
|
11
17
|
// освобождает его RoundManager: размер команды для этого не годится —
|
|
12
18
|
// он меняется на входах и выходах, а между попаданием в команду и
|
|
@@ -149,6 +149,22 @@ class ParticipantManager {
|
|
|
149
149
|
this._participants.delete(gameId);
|
|
150
150
|
}
|
|
151
151
|
|
|
152
|
+
// задаёт цвет ника в чате: '#rgb'/'#rrggbb' или null (цвет команды).
|
|
153
|
+
// Единственный вход для игры — HostGame отдаёт это значение в chat.push,
|
|
154
|
+
// а клиентская view кладёт его инлайновой переменной на строку
|
|
155
|
+
setChatColor(gameId, color) {
|
|
156
|
+
const participant = this._participants.get(gameId);
|
|
157
|
+
|
|
158
|
+
if (!participant) {
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
participant.chatColor =
|
|
163
|
+
typeof color === 'string' && /^#(?:[0-9a-f]{3}|[0-9a-f]{6})$/i.test(color)
|
|
164
|
+
? color
|
|
165
|
+
: null;
|
|
166
|
+
}
|
|
167
|
+
|
|
152
168
|
get(gameId) {
|
|
153
169
|
return this._participants.get(gameId);
|
|
154
170
|
}
|
package/src/lib/validators.js
CHANGED
|
@@ -168,3 +168,50 @@ export const clampLimit = (value, fallback, max) => {
|
|
|
168
168
|
|
|
169
169
|
return Number.isInteger(num) ? Math.min(Math.max(num, 1), max) : fallback;
|
|
170
170
|
};
|
|
171
|
+
|
|
172
|
+
// Сколько завершённых игр движок может склеить в один запрос: окно склейки
|
|
173
|
+
// на его стороне — минута (lobbyConfig.playerData.minFlushInterval), столько
|
|
174
|
+
// игр в неё не влезает.
|
|
175
|
+
//
|
|
176
|
+
// Множитель СВЯЗАН с rank.maxPoints auth-сервиса (packages/auth/src/config/
|
|
177
|
+
// auth.js): мастер не должен пропускать то, что auth отклонит. Отклонённое
|
|
178
|
+
// тело для хоста неустранимо — PlayerDataSync повторял бы его до конца жизни
|
|
179
|
+
// комнаты, — поэтому при правке per-game maxGameScore проверяется и потолок
|
|
180
|
+
// суммы на той стороне.
|
|
181
|
+
const MERGED_GAMES_PER_WINDOW = 20;
|
|
182
|
+
|
|
183
|
+
// клампит результат игры (snakes-v3 этап 3.3): `best` — очки ОДНОЙ игры,
|
|
184
|
+
// `points` — сумма склеенных игр с прошлой синхронизации. Потолок одной
|
|
185
|
+
// игры объявляет сама игра (master:games[].maxGameScore), потолок суммы —
|
|
186
|
+
// это же значение на минутное окно синхронизации; всё, что больше, значит
|
|
187
|
+
// либо взломанного клиента, либо неверно настроенную игру, и мастер режет
|
|
188
|
+
// его перед проксированием, а не отклоняет запрос целиком: честная часть
|
|
189
|
+
// результата не должна пропадать из-за одной аномальной строки.
|
|
190
|
+
// Инвариант `best <= points` держится и после клампа — auth его требует
|
|
191
|
+
export const clampGameResult = (points, best, maxGameScore) => {
|
|
192
|
+
const maxPoints = maxGameScore * MERGED_GAMES_PER_WINDOW;
|
|
193
|
+
const toInt = value => {
|
|
194
|
+
const num = Math.trunc(Number(value));
|
|
195
|
+
|
|
196
|
+
return Number.isFinite(num) ? Math.max(num, 0) : 0;
|
|
197
|
+
};
|
|
198
|
+
const cappedBest = Math.min(toInt(best), maxGameScore);
|
|
199
|
+
const cappedPoints = Math.min(toInt(points), maxPoints);
|
|
200
|
+
|
|
201
|
+
return {
|
|
202
|
+
points: cappedPoints,
|
|
203
|
+
// best > points — битый клиент: сумма не может быть меньше своего
|
|
204
|
+
// максимума. Поднимать сумму до максимума значило бы дорисовать
|
|
205
|
+
// месячному рейтингу очки, которых не было, поэтому режется best
|
|
206
|
+
best: Math.min(cappedBest, cappedPoints),
|
|
207
|
+
// превышение логируется вызывающим: это сигнал о сломанной игре
|
|
208
|
+
clamped: cappedBest !== toInt(best) || cappedPoints !== toInt(points),
|
|
209
|
+
};
|
|
210
|
+
};
|
|
211
|
+
|
|
212
|
+
// Ключ сопоставления ника с глобальным топом. Уникальность users.nick в auth
|
|
213
|
+
// регистронезависимая (миграция 002), поэтому и сравнивать надо так же —
|
|
214
|
+
// иначе «Alice» и «alice» разъедутся. Правило одно, а мест, где по нику
|
|
215
|
+
// ищут, три (host/meta/modules/Accolades.js, client/components/model/Stat.js
|
|
216
|
+
// и сам auth), поэтому оно живёт здесь, а не переписывается в каждом.
|
|
217
|
+
export const nickKey = nick => String(nick ?? '').toLowerCase();
|