Справочник конфигурации игры
Конфигурация, которую игра-плагин добавляет к движку или читает у него: дефолты хоста движка, которые игра вправе переопределить, игровая половина конфига хоста, клиентский конфиг (clientDefaults плюс собственный конфиг игры), форма авторизации и каталог звуков игры, порты и опкоды движка, системные сообщения чата, часы и игровые данные. Переменные окружения и собственные конфиги платформы в контракт плагина не входят.
Дефолты хоста движка (vimp-engine/config/hostDefaults.js)
Источник: vimp-engine/src/config/hostDefaults.js. Движковая половина конфига хоста: лимиты, таймеры, кик-политики, спектаторский keyset (наблюдение — механизм движка). Worker хоста merge'ит её с HostPlugin.gameConfig активной игры-плагина и применяет поверх настройки комнаты.
| Параметр | Значение | Описание |
|---|---|---|
isDevMode | false | Флаг режима разработки: открывает dev-команды чата и отладочный рекордер в HostGame (debugging.md). Комната берёт его из room.isDevMode, который клиент выставляет из import.meta.env.DEV; в прод-бандле остаётся false |
maxPlayers | 30 | Дефолтный лимит участников; комната хоста ограничивает его настройкой создателя (кламп к roomDefaults.maxPlayers игры), лимит считается по людям |
chatMaxLength | 60 | Максимальная длина сообщения чата (авторитетно на хосте; должна совпадать с maxlength поля ввода чата) |
spectatorKeys | nextPlayer/prevPlayer | Команды наблюдателя и неактивного игрока (переключение наблюдаемого) |
Таймеры (timers, мс)
| Параметр | Значение | Описание |
|---|---|---|
timeStep | 1000/120 | Шаг физического тика ядра (~120 Гц) |
networkSendRate | 4 | Снапшот отправляется каждый N-й тик (4 → 30 пакетов/сек) |
roundTime | 120000 | Время раунда |
mapTime | 600000 | Время карты |
roomTimeMin / roomTimeMax | 10000 / 3600000 | Серверные границы клампа пользовательских roundTime/mapTime комнаты (форма лобби — не граница доверия) |
voteTime | 10000 | Время жизни окна голосования |
timeBlockedVote | 30000 | Кулдаун между голосованиями одной темы |
teamChangeGracePeriod | 10000 | Окно смены команды в начале раунда |
roundRestartDelay | 5000 | Пауза между раундами |
mapChangeDelay | 2000 | Пауза перед сменой карты после голосования |
rttPingInterval | 3000 | Интервал RTT-пингов |
idleCheckInterval | 30000 | Периодичность проверки бездействия |
Кики (rtt, idleKickTimeout)
rtt.maxMissedPings: 5— количество подряд пропущенных pong-ответов до кика;rtt.maxLatency: 1000— сглаженная (EMA) задержка (мс), при превышении которой игрок кикается; порог рассчитан на P2P-хостинг с домашних каналов (реальный RTT 200–300 мс и спайки на смене карты — норма);idleKickTimeout.player: 120000— кик игрока за бездействие (2 минуты);idleKickTimeout.spectator: null—nullотключает кик (наблюдатели не кикаются).
Игровая половина конфига хоста
Игровая половина конфига хоста приходит в Worker полем gameConfig активной игры-плагина (Worker хоста грузит HostPlugin динамически по entries.host активного GameManifest) — параметры вроде friendlyFire, mapScale, teams, scripted, soundCues, схемы stat/panel/ playerKeys и playerState.defaultState. Это полностью игровые данные — их конкретные значения игра документирует сама. Движок синхронизирует rank/state с платформой (plugin-api.md); rank и state для движка непрозрачны — форму интерпретирует только игра.
coreParams — необязательный непрозрачный словарь собственных параметров ядра игры. buildCoreConfig вливает его в игровую половину конфига ядра (hostPlugin.createCore(...)), причём известные движку ключи (friendlyFire, models, weapons, playerKeys, panel) перекрывают одноимённые — подменить движковую часть контракта игра не может. Остальное движок не читает и не валидирует, он лишь довозит его до GameSim::new: именно поэтому новый параметр игрового ядра больше не требует релиза движка (@vimp-games/tanks, например, передаёт так параметры падения 2.5D).
mapFallTime — сколько секунд длится падение на уровень высоты (по умолчанию 0.35). В отличие от coreParams это движковый ключ: buildCoreConfig кладёт его в половину engine, потому что траектория (FallModel в ядре) общая для всего, что роняет игра, и для динамических тел самой карты — их шагает движок. Тело, под которым не осталось плиты, падает на ближайшую плиту снизу.
У игры со своими уровнями это число обычно уже есть — в coreParams.levels.fallTime: по нему её ядро роняет танки и предсказывает на клиенте те же самые ящики. Два независимых поля роняли бы ящик у хоста и у его же клиента с разной скоростью, и разошлись бы они молча, поэтому buildCoreConfig берёт coreParams.levels.fallTime (если это конечное положительное число) ещё и как mapFallTime. Движковый ключ остаётся умолчанием для игр без уровней, а явный override по-прежнему сильнее обоих.
maps[].levelHeight — высота одного уровня в мировых единицах (без масштаба: масштаб карты умножает её ядро; по умолчанию — размер тайла). Она делает уклон рампы безразмерным — rise * levelHeight / span вместо «уровней на пиксель», — и константы подъёма (тяга, наклон корпуса, пыль) снова подбираются как уклон. Проверяют ядро и правило E4: конечное число больше нуля.
maps[].volumes (и maps[].levels[n].volumes) — необязательный словарь { "<ключ layers>": высота }: визуальная высота рендер-слоя в уровнях. Его проверяют ядро и правило контракта E4 (ключ обязан называть рендер-слой того же уровня, высота — лежать в (0, 8]), через хост он едет нетронутым и доезжает до рендер-парта полем volume; геометрию строит игра.
spectatorKeys — команды наблюдателя (nextPlayer/prevPlayer); набор движковый, живёт в vimp-engine/src/config/hostDefaults.js. playerKeys (команды игрока) — игровой конфиг, каждая клавиша имеет битовую маску key (1 << n, используется предиктором и ядром в истории ввода) и опциональный type:
type: 0(по умолчанию) — многократное действие: начинается на keyDown, завершается на keyUp (движение, поворот башни);type: 1— срабатывает один раз на keyDown.
Клиентский конфиг: clientDefaults.js + собственный клиентский конфиг игры
Клиентский CONFIG_DATA собирается из двух половин: движковые дефолты — vimp-engine/src/config/clientDefaults.js (интерполяция, режимы/служебные клавиши управления, DOM-структуры движковых модулей, techInformList) и игровая половина, которую поставляет HostPlugin.buildClientGameConfig() активной игры-плагина (parts.*, канвасы, keyset игрока, схемы panel/stat, тексты chat/vote/gameInform, initIdList). Deep-merge выполняет buildClientConfig в Worker'е хоста; перед отправкой он дописывает:
modules.vote.params.time=game:timers:voteTime;prediction— данные для клиентской реплики движения и стрельбы (timeStep,playerKeys,models,weapons, всё игровое).
Полная таблица, какие поля конфига движковые, а какие поставляет игра, — в plugin-api.md (раздел ClientPlugin API).
interpolation — snapshot-интерполяция (движок)
delay: 100— мс; мир рендерится в прошлом (renderTime = serverNow − delay), ~3 кадра при 30 пакетах/сек;maxFrameAge: 1000— страховочная очистка старых кадров буфера.
divergence — детектор рассинхрона предикта (движок, опционально)
В боевом конфиге секции нет, и тогда путь кадра не делает ничего лишнего. Читается клиентским ядром, в headless-прогоне задаётся полем divergence сценария: thresholds (позиционно по player-блоку), defaultThreshold, capacity (кольцевой буфер), angles (индексы компонентов-углов, сравниваемых по окружности). См. debugging.md.
modules.canvasManager — полотна и камера
Общие параметры dynamicCamera — движковые; набор полотен canvases — игровой. Canvas-элементы генерирует клиент движка из этого конфига (ключ — id элемента; width/height — стартовый размер до первого resize):
| Параметр | Описание |
|---|---|
aspectRatio | Соотношение сторон ('16:9'). Canvas заполняет максимум окна, сохраняя пропорцию. Без параметра — 100% окна |
fixSize | Фиксированный размер в px ('150' — квадрат, '200:100' — прямоугольник). Отключает aspectRatio и адаптивное масштабирование |
baseScale | Базовый зум ('Числитель:Знаменатель'). Для адаптивных полотен — масштаб при эталонной ширине 1920px (итог = ширина/1920 × baseScale); для фиксированных — постоянный множитель |
dynamicCamera | Включает динамическую камеру (look-ahead + zoom от скорости) |
shakeCamera | Разрешает тряску камеры |
Адаптивное масштабирование гарантирует одинаковый угол обзора на любых мониторах (эталон — Full HD 1920px).
dynamicCamera (общие параметры): lookAheadFactor (смещение камеры вперёд по движению), zoomOutFactor/maxZoomOut (отдаление от скорости), smoothnessPosition/smoothnessZoom/smoothnessVelocity (плавность).
pointerCanvas (игра, необязательный) — полотно, в систему координат которого пересчитывается канал указателя; по умолчанию первое объявленное.
Имена полотен, размеры и зум — данные игры; напр. @vimp-games/tanks задаёт vimp (16:9, зум 5:1, динамическая камера, тряска) и radar (150×150px, масштаб 1:8).
modules.controls — управление
keySetList(игра) — массив наборовkeyCode: 'команда', целиком заданных игрой (напр.@vimp-games/tanksиспользует два:[0]— наблюдатель (n/p— переключение наблюдаемого игрока),[1]— игрок (w/s/a/d— движение,k/l/u— башня,j— огонь,n/p— смена оружия)). Какой набор активен, диктует хост через порт17(KEYSET_DATA).pointer(игра, необязательный) — канал указателя (мышь/палец/стилус). Без этого ключа движок не вешает ни одного слушателя указателя. Поля:keySets(индексы наборовkeySetList, в которых канал живой; по умолчанию все),doubleTapMs/doubleTapPx(пороги двойного тапа, по умолчанию300/40),sendIntervalMs(минимум между двумяmove, по умолчанию50). Формат провода —"seq:aim:x:y:flags"с мировой точкой; см. client-api.md.modes(движок) — режимы UI:c— чат,m— голосование,tab— статистика.cmds(движок) — служебные клавиши (escape,enter), имеют высший приоритет и используются внутри режимов.
Прочие модули
DOM-структуры (elems) — движковые; тексты и схемы — игровые:
chat— id DOM-элементов, лимиты вывода (listLimit: 5строк,lineTime: 15000мс) и кэш — движок; шаблоны системных сообщений (messages, игра): реестр кодов групп, движковые группыs(статусы),v(голосования),m(карты),c(команды) плюс любые группы, которые регистрирует игра-плагин (напр.@vimp-games/tanksдобавляетbдля ботов). Хост шлёт только'группа:номер:параметры', текст собирает клиент. У движковых групп есть английские умолчания вsrc/config/chatMessages.js(ниже); строка игры по тому же индексу их перекрывает,''— не показывать сообщение,null/нет — умолчание. Игровая группа целиком на игре.panel— контейнерcontainerId(движок); сопоставление серверных ключей (t,h,wa,w1,w2) полям (keys) и типизированная схема полейfields(игра): упорядоченный список{ name, elem, type: 'bar'|'value'|'time'|'weapon', max?, blocks? }—PanelViewгенерирует DOM и поведение по типам, а не по именам полей.stat— id контейнера (движок); подписи колонокcolumns, таблицы шапок/тел (heads,bodies) иsortList(игра) — DOM scoreboard генерируетStatViewпо схеме;sortList— параметры сортировки: массив пар[номер ячейки, по убыванию?]; при равенстве сравнение переходит к следующей паре.vote— id/классы DOM (движок) и шаблоны голосований (templates, игра):[заголовок с плейсхолдерами {0}, варианты (массив — статичные, строка — запросить список у хоста), timeOff].menu— пункты главного меню голосования.gameInform/techInformList— шаблоны игровых сообщений (id элемента — движок, текстыlist— игра) и технических экранов (движок): комната полна, кик за бездействие/задержку и т.д.initIdList(игра) — какие модули/полотна инициализировать при старте (vimp,radar,panel,chat); механика инициализации — движковая. Эти DOM-id скрыты, пока не завершится авторизация; затемpanelпоказывается какdisplay: flex, все остальные id — какdisplay: block.
Детали, которые легко упустить:
- Ячейки панели.
barрисует блочную полосу —blocksпо умолчанию30,max—100, с цветовой рампой по блокам, миганием при низком значении и анимированным наполнением на старте раунда (500 мс);value— просто число;time—M:SS;weaponполучает класс.active, когда это активное оружие. Ключtдвижок жёстко задаёт как время раунда в секундах. - Колонки статистики.
columns— подписи заголовков, позиционно сопоставляемые индексамkeyколонок хоста; команда, присутствующая вbodies, но не вheads(наблюдатели), получает строки, но не агрегатный заголовок;sortListсортирует численно (~~textContent), поэтому текстовая колонка сортируется как0. Движок пишет свои пять имён в объявленные колонки и отбрасывает остальные, но его CSS раскладывает только пять (#stat …:nth-child(1)…(5), плюс классы строк.line1–.line3): у лишней колонки нет ширины, пока игра не повторит раскладку вstyles(правило контрактаC6предупреждает об этом). - Режим статистики
leaderboard. Игра, чьё табло — глобальный топ, объявляетmodules.stat.params.mode: 'leaderboard'(сperiod,limit,columns) иstatMode: 'leaderboard'вgameConfig— на обеих половинах, иначе хост рассылает таблицу комнаты, которую никто не рисует, либо клиент рисует таблицу, которую никто не наполняет (правило контрактаC11— ошибка в обоих случаях). Вид рисует один список.stat-leaderboardиз.stat-row(место · ник · очки), присылаемый хостом черезACCOLADES_DATA; собственная строка вызывающего подсвечена (is-self), заменяет последнюю строку, когда он вне топа, и показывает—, когда за период он не ранжирован. CSS движка даёт лишь голый трёхколоночный каркас (правилоC6проверяет, чтоstylesигры упоминают.stat-leaderboard). - UI голосований. Шаблон —
[title, values?, timeOff?];values— массив подписей или'teams'/'maps'для списков, подставляемых движком;timeOff: trueскрывает обратный отсчёт.menu— список голосований по инициативе игрока — движок в него ничего не добавляет (голосование «Сменить хост» стартует через/changehost, а его окно — движковое голосование@changeHost; имена с@зарезервированы).params.timeподставляется изtimers.voteTime. Весь блокmodules.voteопционален: игра, которой не о чем голосовать, может его опустить.
Игровой конфиг авторизации
Схема формы авторизации (HostPlugin.authSchema: id DOM-элементов, параметры формы, игровые валидаторы, тексты) — полностью игровые данные; движок лишь предоставляет нейтральный шаблон экрана авторизации (заголовок, справочные секции, кнопка Start — без поля name: ник берётся из проверенной личности игрока) и AuthView, которая подставляет заголовок/подсказки игры из texts. authSchema.params обычно объявляет только игровые поля (например, model у @vimp-games/tanks, валидируемый её же isValidModel); движковый валидатор isValidName (validators) существует для игры, которая захочет добавить в форму поле ника, но в дефолтной форме не используется — ник берётся из проверенного токена identity лобби, а не вводится пользователем. Валидация выполняется и на клиенте (валидаторы из бандла игры), и повторно хостом (Worker) как итоговым авторитетом; по проводу (AUTH_DATA, порт 1) уходят только elems/params/texts — код валидаторов не передаётся. Собственный конфиг авторизации игры документирован в её репозитории.
Игровой каталог звуков
Каталог звуков (имена файлов, приоритеты, громкость, флаги зацикливания, список кодеков) — игровые данные, отдаются под assetsBase игры. Механика воспроизведения (лимиты голосов, приоритеты) — движковая, см. client-api.md. Там же описан необязательный блок parts.sounds.spatial (профиль проекции, виртуальная высота, радиус рассеивания, атрибуты PannerNode): игра, которая его не объявила, получает движковые дефолты. Переменных .env задача не вводит.
Порты и опкоды (vimp-engine/config/wsports.js, opcodes.js)
wsports.js— реестр числовых портов игрового протокола (источник истины). Полные таблицы — в snapshot.md.opcodes.js— версия бинарного snapshot-формата (SNAPSHOT_FORMAT_VERSION = 5),ENGINE_API_VERSIONиHOT_FLAGS. Реестр снапшот-ключей — игровые данные, поставляемые черезHostPlugin.gameConfig.snapshot(числовой id +kindна каждый ключ, задающий байтовую раскладку блока). Незарегистрированный ключ уронит упаковку кадра. Подробности — в snapshot.md.gameCodes.js— коды сообщенийGAME_INFORM_DATA(порт 7) (winnerTeam/roundStart/gameOver), источник истины, общий для хоста и клиента (код1запускает анимацию старта раунда на панели и логотипе).
Системные сообщения чата (vimp-engine/config/chatMessages.js)
Английские тексты движковых кодов чата по умолчанию, группы s, v, m, c (индекс = номер кода). Лежат отдельно от clientDefaults.js: при слиянии конфига массивы заменяются целиком, и массив s игры стёр бы умолчания. ChatModel сначала берёт строку игры по тому же индексу; '' — не показывать сообщение; null или нет индекса — умолчание. Новый код движка добавляется в ENGINE_MESSAGE_CODES, в эту таблицу и в диапазоны правила B8 одним изменением (согласованность проверяет tests/config/chatMessages.test.js).
| Группа | Тексты по индексам |
|---|---|
s | 0 "Team {0} is full. Your current team: {1}", 1 "Your team: {0}", 2 "Your new team: {0}", 3 "Your new status: spectator", 4 "{0} killed {1}", 5 "{0} joined the game", 6 "{0} left the game", 7 "Host changed", 8 "You are no longer the host (connection lost)", 9 "Host changed: the previous host was lagging", 10 "… went inactive", 11 "… had a poor connection" |
v | 0 "A vote has been created", 1 "Voting has started", 2 "Your vote has been accepted", 3 "Voting is temporarily unavailable", 4 "Vote passed", 5 "Vote failed", 6 "Usage: /changehost", 7 "You are the host — use “Hand over host” in the room menu", 8 "No connection to the master server", 9 "A host vote was held recently", 10 "No other player can host", 11 "A host vote is already in progress", 12 "A host vote is not possible right now", 13 "Vote to change host passed ({0}/{1})", 14 "Vote to change host failed ({0}/{1})", 15 "Host vote cancelled" |
m | 0 "Current map: {0}", 1 "Next map: {0}" |
c | 0 "Command not found", 1 "Your rank: {0}" |
s:8 и v:6–v:15 клиент добавляет сам, по проводу они не ходят. Плейсхолдеры — {0}, {1}, … — подставляются из массива params.
Часы (vimp-engine/lib/clock.js)
Источник: clock. Не конфиг, а точка подмены, делающая матч воспроизводимым: синглтон (в идиоме lib/config.js) с методами now() (эпоха, мс, Date.now), monotonic() (высокое разрешение, performance.now), random(), setTimeout/clearTimeout/setInterval/clearInterval плюс install(custom) (возвращает функцию отката) и reset().
Все таймеры хоста идут через lib/AbstractTimer.js, который берёт таймер-функции из clock; call-site хоста зовут clock.now()/clock.monotonic()/clock.random() вместо глобалов. Дефолты резолвят глобалы в момент вызова, поэтому поведение в проде (и vi.useFakeTimers() в тестах) не меняется, а headless-runner подставляет VirtualClock и прогоняет десятиминутный матч за секунды — детерминированно. См. debugging.md.
Игровые данные (модели, оружие, карты)
Параметры моделей/танков, определения оружия и карты — полностью игровые статические данные, см. доки активной игры-плагина (например, docs/ru/configuration.md в @vimp-games/tanks) для их конкретной формы и значений. Один сквозной инвариант, важный для контрибьютора движка: коэффициенты модели движения обычно общие между авторитетным ядром игры и репликой клиентского предикта, поэтому игры закрывают их изменение своими cargo-тестами на паритет.
← Предыдущая: Plugin API · Следующая: Схема снапшота и форматы передачи →