Таксономия нетокода: три модели
Механизм: что кладём на провод
Вся таксономия растёт из одного решения. Можно слать по сети состояние мира («игрок A в точке X с HP 80») — тогда клиенту не нужен детерминизм, он просто рисует присланное, но объём растёт с числом сущностей, и кто-то должен быть авторитетом, иначе клиент соврёт. Либо слать ввод/команды («нажал вперёд», «юниты 5–40 — атаковать сюда») и воспроизводить их одинаковой симуляцией на всех машинах — тогда трафик крошечный, но любое расхождение в вычислениях рушит всё (desync).
Стоимость канала
Грубая модель трафика на игрока. При рассылке состояния платим за каждую видимую сущность каждый снапшот:
При локстепе/роллбэке — только за команды или биты ввода, и это не зависит от числа юнитов:
Это и есть тезис статьи Бэттнера и Террано «1500 Archers on a 28.8» (GDC 2001, Ensemble, Age of Empires): попытка слать позиции юнитов упирала RTS в ~250 объектов на модеме 28.8k; рассылка команд при детерминированной симуляции сняла потолок до 1500+ — на проводе те же несколько команд за ход, хоть тысяча лучников на экране.
Стоимость задержки
Скрытие пинга у трёх моделей даёт разную ощущаемую задержку ввода (через сколько ты видишь реакцию на свою кнопку). Кадр при 60 fps = 16.67 мс; пусть RTT = 100 мс (one-way ≈ 50 мс ≈ 3 кадра).
Локстеп откладывает твой собственный ввод на input delay — столько кадров, чтобы команда успела дойти до пира до общего исполнения кадра:
То есть ~50 мс лага — и его чувствуют оба игрока, всегда. Роллбэк и клиент-предсказание дают ощущаемую задержку ≈ 0 (свой ввод применяется в этом же кадре), а цену платят иначе: предсказанием чужого + откатом (роллбэк) или сверкой с сервером (клиент-сервер). Наивный авторитет без предсказания — это весь RTT, 100 мс, «управление по почте».
Три модели рядом
| Свойство | Клиент-сервер + lag-comp | Локстеп (детерм.) | Роллбэк |
|---|---|---|---|
| На проводе | состояние мира (дельты) | команды | биты ввода |
| Авторитет | выделенный сервер | нет (все равны) | нет (P2P, 2 игрока) |
| Детерминизм | не обязателен | обязателен, строгий | обязателен |
| Трафик | ∝ числу сущностей | крошечный | крошечный |
| Скрытие пинга | предсказание + сверка + интерп. | input delay | предсказание ввода + откат |
| Артефакт | rubber-banding, «смерть за углом» | все ждут самого медленного | визуальный «снап» |
| Игроков | от 2 до тысяч | 2–8 (масса юнитов) | обычно 2 |
| Жанр | MMO, BR, шутеры | RTS, авто-баталеры | файтинги |
Числовой итог при RTT 100 мс / 60 fps: наивный авторитет — 100 мс лага; локстеп — 50 мс, но всем; клиент-предсказание и роллбэк — ~0 мс лага, но первый ловит rubber-band при расхождении с сервером, второй — «снап» на 1–3 кадра при ошибке предсказания. Дальше каждую модель — отдельным уроком: клиент-предсказание (готов), роллбэк подробно.
🕹 В какие игры поиграть — и что заметить
Три модели нельзя прочувствовать в одной игре — у каждой свой жанр-носитель. Сыграй в три разные и поймай сигнатуру задержки каждой: что именно «лагает», когда сеть плохая.
Выделенный сервер — истина, ты предсказываешь своё движение и стрельбу, чужих видишь чуть в прошлом (интерполяция), сервер отматывает время для попаданий. Сигнатура плохой сети — rubber-banding (тебя дёргает назад при расхождении прогноза) и «я умер уже за углом» (favor-the-shooter).
🎮 Сыграй: в CS введи net_graph 3, поиграй на высоком пинге. Лагает твоё движение резиной и чужие телепортируются — но мир не замирает целиком. Это состояние-на-проводе с предсказанием.
Шлются только команды, симуляцию крутят синхронно все машины. Поэтому сотни юнитов — без проблем по трафику, но твой клик исполняется через input delay (turn N+k), и при чьём-то лаге замирает вся игра, не отдельный юнит.
🎮 Сыграй: в старый StarCraft/AoE на плохой сети — заметь, что лагает весь мир разом (ждём всех), а юниты двигаются плавно и одинаково на всех экранах. Это команды-на-проводе + детерминизм. В PC-баге Кореи это было незаметно: пинг низкий.
P2P, 2 игрока, биты ввода на проводе. Свой ввод — мгновенно; ввод оппонента предсказывается («жмёт то же, что в прошлом кадре»), при ошибке — откат и пересчёт нескольких кадров. Сигнатура плохой сети — короткий «телепорт-снап» персонажа, но никогда input lag.
🎮 Сыграй: в GGST/KI онлайн при скачке пинга поймай микро-«тряску» оппонента — это видимый откат+пересимуляция. Сравни с делэй-нетокодом (ранний Smash Ultimate / старый SFV): там вместо снапа — ровный input lag на всё. Глубже — урок про роллбэк.
Та же клиент-серверная семья, но доведённая до предела: единый сервер (Tranquility), и при перегрузке вместо лага сервер замедляет время (Time Dilation) — все действия идут в 10–30% скорости, но согласованно. Авторитет сохранён ценой темпа.
🎮 Посмотри: зайди в EVE в момент крупного боя (или ролики B-R5RB 2014). Индикатор TiDi покажет «10%» — мир едет в slow-mo, но не рассыпается. Это выбор «консистентность важнее темпа». Подробно — в уроке «Персистентность и шардинг».
Хардкор · инженерия: детерминизм, float и почему локстеп страшнее роллбэкаможно пропустить
Детерминизм — это требование «одинаковый ввод → побитово одинаковый результат на всех машинах». Враг номер один — floating point: один и тот же код на разных CPU/компиляторах даёт разный результат (порядок операций, FMA, x87 80-бит vs SSE 64-бит, fast-math). Поэтому детерминированные движки берут fixed-point (целочисленную арифметику) или строго фиксируют float.
Почему локстеп — самый суровый
- Расхождение фатально и тихо. В клиент-сервере сервер всё равно поправит клиента; в локстепе одно расхождение в одном юните из тысяч → desync, и дальше миры разъезжаются необратимо. Нужен побитовый детерминизм по всей симуляции.
- Детерминированный рандом. ГПСЧ с общим сидом, синхронный порядок вызовов. Любой «незаметный»
rand()вне синхросимуляции (партикл, звук) не должен влиять на геймплей. - Порядок команд. Команды всех игроков на кадр N сортируются детерминированно (по player id), иначе A→B и B→A дадут разный итог.
- Контрольные суммы. Движки периодически шлют хэш состояния; разошёлся — ловим desync сразу, а не через 10 минут.
Роллбэк vs локстеп — общая ДНК
Оба детерминированы и шлют ввод, но локстеп ждёт ввод перед исполнением (input delay), а роллбэк предсказывает и исполняет сразу, откатывая при ошибке. Роллбэк = «оптимистичный локстеп». Цена роллбэка — сейв состояния каждый кадр (для отката); поэтому он живёт там, где состояние крошечное (файтинг ~10–50 КБ), и почти не применим к RTS, где состояние огромно. См. отдельный урок.
Хардкор · хостинг: dedicated vs P2P, NAT и где это считатьможно пропустить
- Кто хостит. Клиент-сервер MMO/шутеров требует выделенных серверов: античит, нет «host advantage», стабильность. Локстеп и роллбэк обычно P2P — нет состояния-истины, нечего хостить централизованно; дёшево, но падает при дисконнекте «хоста»/пира.
- NAT и matchmaking. P2P упирается в NAT-traversal (STUN/TURN, hole punching); часть соединений всё равно идёт через relay. Поэтому даже «P2P» файтинги держат relay-серверы.
- Авторитет ≠ топология. Можно P2P с одним пиром-авторитетом (listen-server, кооп вроде Helldivers/Deep Rock): дёшево, но хост видит мир без пинга и его сложнее защитить от читов.
- Региональные серверы. Физику пинга не обмануть:
RTT ≥ 2·расстояние/c. Все три модели выигрывают от близкого дата-центра — матчмейкинг привязывает к региону, чтобы снизить базовый RTT, на котором работает скрытие. - Гибриды. Современные кооп-игры берут клиент-сервер с ослабленным авторитетом (меньше игроков, социальный контекст, терпимость к лагу) — компромисс между ценой dedicated и защитой P2P.
Распределённые системы: локстеп = детерминированный state-machine replication (Raft/Paxos: реплицируем лог команд, не снапшоты; все реплики применяют одинаковые команды в одинаковом порядке → одинаковое состояние). Клиент-сервер со снапшотами = primary-replica с пересылкой состояния. «Шлём команды, требуем детерминизм» vs «шлём состояние, детерминизм не нужен» — ровно эта дихотомия.
ML / AI: распределённый трейнинг — та же развилка. Data-parallel = «шлём состояние»: каждый воркер считает градиенты, all-reduce синхронизирует веса/градиенты (большой трафик, но воркеры независимы). Детерминированная пересборка из сида = «шлём команды»: храним сид+порядок данных и воспроизводим эпоху побитово вместо хранения чекпойнтов — дёшево по месту, но требует детерминизма (как локстеп). А off-policy-акторы (IMPALA), действующие устаревшей политикой с последующей коррекцией, — это «оптимистичный» путь, родственник роллбэка.
Бэкенд / БД: репликация через лог операций (event sourcing, WAL-shipping) vs через снимок (snapshot replication) — выбор «команды или состояние». Детерминизм реплики = воспроизводимость лога.
Принцип: реши, что дешевле двигать — состояние (гибко, дорого, не нужен детерминизм) или команды (дёшево, но всё держится на побитовой воспроизводимости). И отдельно реши, у кого авторитет.
MultiplayerSynchronizer) и любой роллбэк-плагин (GodotSteam/SnapNet или GGRS на Rust). В клиент-серверном включи отрисовку серверной и предсказанной позиции; в роллбэке — счётчик rollback frames и предсказанный ввод. Покрути искусственный лаг и сравни поведение.net_fakelag в Source), input delay и «вся игра ждёт» (локстеп RTS на плохой сети), визуальный «снап» (роллбэк-файтинг). Чеклист: один артефакт = одна модель, не перепутай.Почему просто не слать состояние всегда — это же не требует детерминизма?
Если роллбэк = «оптимистичный локстеп», почему RTS не используют роллбэк, а файтинги — да?
«Ждём самого медленного» в локстепе — это можно обойти?
Почему детерминизм в локстепе «страшнее», чем в роллбэке, если оба его требуют?
rand()) → desync всей игры без шанса на коррекцию (нет авторитета, чтобы поправить). Поэтому RTS-движки одержимы fixed-point, детерминированным ГПСЧ, порядком команд и контрольными суммами состояния.Кооп на 4 игрока (Helldivers, Deep Rock) — какая это модель?
- Paul Bettner & Mark Terrano, «1500 Archers on a 28.8: Network Programming in Age of Empires and Beyond» (GDC 2001) — канонический разбор локстепа.
- Glenn Fiedler (Gaffer on Games), «What Every Programmer Needs to Know About Game Networking» — обзор всех трёх семейств.
- Yahn Bernier, «Latency Compensating Methods…» (Valve, 2001) — клиент-серверный lag-comp.
- GGPO (Tony Cannon) + GDC-доклады — роллбэк; разбор в следующем уроке.
- Модуль 4 (
04-online-worlds-1997-2005.md), раздел «Networking model taxonomy».