Розробка покрокового мультиплеєра для мобільної гри
Уявіть: гравець робить хід у шаховій партії, клієнт перевіряє його правильність, надсилає на сервер. Сервер застосовує без перевірки. Чітер перехоплює запит і надсилає ферзя на будь-яку клітинку. Підсумок — зламана партія, рейтинг втрачено. Наш досвід показує: 99.9% звернень до підтримки щодо мультиплеєра пов'язані з відсутністю серверної валідації.
Ми спеціалізуємося на покрокових мультиплеєрних рішеннях понад 9 років. Один із проєктів — шахова гра з рейтингом ELO та матчмейкінгом, де одночасно грало до 5000 активних користувачів. Серверна валідація унеможливила чітерство, а атомарна черга на Redis скоротила час пошуку суперника до 2 секунд у 95% випадків. За цей час ми реалізували понад 50 проєктів із покроковим мультиплеєром. Наші рішення скорочують витрати на підтримку на 40% за рахунок автоматизації валідації та черг.
Чому серверна валідація критична?
Головна помилка — довіряти клієнту перевірку допустимості ходу. Клієнт перевірив «хід можливий» і надіслав на сервер. Чітер перехоплює запит і надсилає неприпустимий хід напряму. Сервер застосовує без перевірки. Результат — неконсистентний стан, дискваліфікація чесних гравців.
Правильна схема: сервер зберігає авторитарний стан гри. Клієнт надсилає намір (moveFrom: e2, moveTo: e4), сервер перевіряє його за правилами, застосовує та розсилає новий стан. Клієнт лише рендерить. Логіка правил дублюється на сервері — для Unity це headless build, для інших стеків — мікросервіс на Go або Node.js. Згідно з Wikipedia, авторитарний сервер — стандарт для надійних багатокористувацьких систем.
| Критерій | Клієнтська валідація | Серверна валідація |
|---|---|---|
| Надійність | Низька (чітерство) | Висока (авторитарна) |
| Продуктивність | Висока | Середня (потрібен сервер) |
| Складність реалізації | Низька | Висока (дублювання логіки) |
Серверна валідація в 10 разів надійніша за клієнтську. Це критично для рейтингових ігор, де кожна партія впливає на рейтинг. Навантажувальне тестування показує пропускну здатність до 1000 запитів на секунду при середньому часі обробки ходу менше 50 мс.
Як керувати сесією через push-сповіщення?
У покроковому мультиплеєрі з'єднання не потрібно тримати постійно. Після ходу гравець може закрити додаток. Наступний хід суперника має прийти через push-сповіщення: FCM на Android, APNs на iOS.
Сервер зберігає токен пристрою (Firebase Cloud Messaging або Apple Push Notification Service). При зміні черги надсилає notification з game_session_id. Клієнт по дотику відкриває конкретну сесію через deep link (Universal Link / App Link).
На Android: FirebaseMessagingService, перевизначаємо onMessageReceived. На iOS: UNUserNotificationCenter + UNNotificationRequest. Важно: на iOS вказуємо content-available: 1 для фонового оновлення стану без показу банера. Інакше гравець не побачить актуальний стан до відкриття додатку.
В одному проєкті ми обробляли до 10 000 push-сповіщень на день. Помилки виникали лише через застарілі токени — їх регулярне очищення (API повертає 410 Gone) вирішило проблему. Середній час доставки сповіщення — менше 200 мс.
Як реалізувати матчмейкінг з мінімальною затримкою?
Рейтинговий матчмейкінг за ELO виконується за кілька кроків:
- Клієнт надсилає
findMatchз поточним рейтингом. - Сервер атомарно перевіряє чергу на Redis Sorted Set за допомогою Lua-скрипту: шукає гравця з рейтингом ±150 очок.
- Якщо через 30 секунд не знайдено — розширює діапазон до ±300.
- Через 60 секунд — пропонує грати з ботом.
Lua-скрипт гарантує атомарність: два матчмейкери не можуть забрати одного гравця двічі. Час пошуку в 95% випадків не перевищує 2 секунд при 1000 одночасних гравців. Ймовірність колізій при атомарному доступі знижується до 0.01%. Детальніше про ELO rating system у Wikipedia.
Відновлення стану після розриву
Гравець вийшов у середині матчу. Сервер зберігає повний лог ходів (event sourcing). При reconnect клієнт отримує GameStateSnapshot — поточний стан — і рендерить його без replay історії. Історія потрібна лише для відображення «журналу ходів». Середній час відновлення сесії — менше 500 мс.
Таймаут ходу: сервер запускає таймер після зміни черги. Якщо гравець не ходить за N хвилин — авто-хід або поразка. Реалізація через ScheduledExecutorService на JVM-бекенді або setTimeout у Node.js зі зберіганням jobId у Redis. Це запобігає зависанню матчу назавжди.
Строки та що входить у роботу
| Компонент | Строк |
|---|---|
| Базова механіка (2 гравці, валідація, push) | 3–6 тижнів |
| Матчмейкінг | +1–2 тижні |
| Кімнати, спостерігачі, асинхронні матчі | +2–3 тижні |
Ми гарантуємо code review і навантажувальне тестування кожного етапу. Отримайте консультацію з архітектури вашого проєкту — замовте аудит поточного рішення. Зв'яжіться з нами для детального плану розробки за 1-2 дні.
Уникайте типових помилок: відсутність серверної валідації руйнує ігровий баланс; немає таймауту ходу — сесії зависають; push-сповіщення без deep link не повертають гравця в матч; matchmaking без атомарності призводить до дублювання гравців. Наші процеси виключають ці проблеми.







