Skip to content

🇬🇧 English | 🇺🇦 Українська

← До змісту

10. Сценарії розгортання

Той самий плагін поводиться по-різному залежно від того, де виконується код: в однокористувацькій грі, у мережевій сесії чи на виділеному сервері. Розділ про те, хто саме звертається до сховища в кожному випадку і що з цього випливає.


Коротка відповідь

Хто звертається до сховища Звідки ключі Головна пастка
Однокористувацька гра Сам клієнт Сценарій B або D Вшитий ключ у збірці
Мережева гра (listen) Хост, і лише він Сценарій B Кожен клієнт звертається сам і платить трафіком
Виділений сервер Сервер Змінні оточення Спроба зробити те саме на клієнті
Настільний застосунок Клієнт Сценарій D Ключі розробника замість ключів користувача

Докладніше про самі сценарії — 3. Облікові дані.


Підсистема і мережа

UDemoS3Subsystem — це UGameInstanceSubsystem. Практичні наслідки:

  • Вона існує в кожному екземплярі гри окремо: у клієнта своя, у сервера своя.
  • У Play In Editor із кількома вікнами кожне вікно має власну підсистему й власного клієнта.
  • Вона нічого не реплікує. Плагін не є мережевою системою: він робить HTTP-запити з того процесу, у якому його викликали.

Тому питання «а як воно працює в мультиплеєрі» насправді зводиться до питання «у якому процесі я викликаю ноду». Плагін не вирішує це за вас — і не має вирішувати.


Однокористувацька гра

Найпростіший випадок: є один процес, він і звертається до сховища.

Типові задачі — хмарні збереження, завантаження користувацького вмісту, вивантаження знімків чи звітів про збої.

Що робити:

  1. Ключі — за сценарієм B2 (короткоживучі від вашого бекенда) або B1 (підписані посилання). Якщо бекенда немає взагалі, а бакет належить користувачеві — сценарій D.
  2. Виклик із будь-якого місця: Blueprint актора, віджета, Game Instance.
  3. Пам'ятайте, що операція асинхронна: гра продовжує йти, поки вона виконується.

Приклад: хмарне збереження

Event Save Game
   │
   ├─► Save Game to Slot            (звичайне локальне збереження)
   │
   └─► Get S3 Subsystem → Get Default S3 Client → S3 Upload File
           Bucket     : Get Default Bucket
           Object Key : saves/{PlayerId}/slot1.sav
           File Path  : (шлях до збереженого файлу)
              │
              ├─ On Success → показати «збережено у хмару»
              └─ On Failure → лишити локальне збереження й спробувати пізніше

Порядок тут не випадковий: спершу зберігаємо локально, потім вивантажуємо. Якщо мережі немає, гравець не втрачає прогрес — він просто не синхронізований.


Мережева гра: listen-сервер

Хост — це водночас і сервер, і гравець. Решта підключаються до нього.

Головне рішення: хто звертається до сховища.

Варіант 1 — тільки хост (рекомендований)

Хост зберігає стан світу, вивантажує його, роздає результати іншим через звичайну реплікацію.

Event Save World State   (виконується на сервері)
   │
   ├─ Switch Has Authority
   │     ├─ Authority → S3 Upload File → (успіх) → Multicast: «світ збережено»
   │     └─ Remote    → нічого не робити

Чому так: одне звернення замість N, один набір ключів замість N, і немає потреби давати право запису кожному клієнтові.

Варіант 2 — кожен клієнт сам

Виправдано, коли дані належать конкретному гравцеві й нікого більше не стосуються: його власні скріншоти, його налаштування, його профіль.

Тоді кожен клієнт має отримати свої короткоживучі ключі з політикою, що обмежує його власним префіксом (users/${user_id}/*). Спільний ключ на всіх — це можливість перезаписати чужі дані.

Чого не варто робити

Не викликайте ноду і на сервері, і на клієнтах, не подумавши. Blueprint-подія, яка виконується скрізь, у сесії на вісьмох дасть вісім однакових завантажень одного файлу — за вісім оплачених запитів, із непередбачуваним порядком запису.

Перевіряйте Has Authority (або Switch Has Authority) там, де операція має бути одна.


Виділений сервер

Найзручніший випадок із погляду безпеки: бінарник сервера у гравців не буває, тож довгоживучі ключі тут доречні.

Що робити:

  1. Credential Source → Environment variables.
  2. Ключі задає середовище запуску: змінні процесу, роль інстанса, менеджер секретів.
  3. Клієнти не звертаються до сховища взагалі — або звертаються лише за підписаними посиланнями, які видає сервер.
# systemd unit, Docker, скрипт запуску - будь-що, що ставить оточення
export AWS_ACCESS_KEY_ID=...
export AWS_SECRET_ACCESS_KEY=...
./MyGameServer -log

Особливості серверної збірки

Плагін працює без світу й без актора. Затримки між повторами відлічує FTSTicker, а не таймер світу, тож операції коректно виконуються під час завантаження карти, у консольній утиліті й у commandlet.

Модуль тестів у серверну збірку не потрапляє — він має тип DeveloperTool і збирається лише для редактора та Development.

Секцій Editor Only на сервері немає. Це не обмеження, а гарантія: те, що ви вписали в редакторі, не могло поїхати в збірку. На сервері працюють лише змінні оточення або те, що ви встановили кодом.

Роздача підписаних посилань

Типова схема, коли клієнт має щось завантажити, але ключів мати не повинен:

Клієнт: RPC до сервера — «хочу залити збереження»
   │
Сервер: перевіряє право, далі
   │      Make Presigned URL (PUT, 900 секунд)
   │
   └─► повертає адресу клієнтові
         │
Клієнт: звичайний HTTP PUT за цією адресою

Клієнт при цьому може бути налаштований як Anonymous — підписувати йому нічого.


Настільний застосунок

Бакет належить користувачеві. Сценарій D: екран введення ключів, зашифроване локальне сховище, Local user store.

Дві поради, які економлять час:

  • Дайте профілю осмислене ім'я (Local Store Profile Name), а не default, якщо застосунків у вас кілька: так ключі одного не побачить інший.
  • Перевіряйте ключі одразу після введення — зробіть кнопку «Перевірити», яка викликає S3 List Objects з лімітом 1. Помилка одразу після введення зрозуміла; та сама помилка через півгодини під час першого справжнього збереження — ні.

Play In Editor: що варто знати

  • Кожне вікно PIE — окремий екземпляр гри, тож і клієнт у кожного свій.
  • Ключі беруться з редакторських секцій (див. 3. Облікові дані) — зібрана гра поводитиметься інакше, і це навмисно.
  • Запустивши PIE у режимі виділеного сервера, ви отримаєте той самий поділ, що й у бою: перевіряти Has Authority варто саме тут, а не після пакування.

Клієнти в PIE окремі, а диск — спільний. Вікна PIE є окремими екземплярами гри, але живуть в одному процесі й пишуть в один і той самий Saved/. Для передавань це має практичний наслідок: два екземпляри, які виконують той самий граф із тим самим Local File Path, працюють з одним файлом на диску. Найпомітніше це на S3 Download File Chunked — обидва відкриють один <файл>.s3part і писатимуть у нього навперемін, зіпсувавши результат; записи про відновлення в Saved/S3/ теж спільні, бо їх ідентифікатор рахується з бакета, ключа й шляху, а вони в обох однакові.

Це не специфіка PIE як такої — так само поводяться дві копії зібраної гри, запущені з однієї теки на одній машині. Рішення те саме, що й у «Чого не варто робити»: або Has Authority там, де передавання має бути одне, або різний Local File Path для кожного екземпляра.


Контрольний список перед релізом

  • [ ] У DefaultGame.ini і в ассетах профілів немає ключів.
  • [ ] Credential Source відповідає способу постачання (не Environment variables у грі, яку завантажують гравці).
  • [ ] Операції, які мають виконуватися один раз, захищені перевіркою Has Authority.
  • [ ] Політика ключа звужена до потрібних дій і потрібного префікса.
  • [ ] Помилки мережі оброблені: у гравця має бути зрозуміла поведінка без інтернету.
  • [ ] Великі передавання можна скасувати, і скасування перевірено — див. 5. Передавання файлів.
  • [ ] Ключі, якими ви користувалися під час розробки, перевипущені перед публікацією.
  • [ ] S3.Live.* прогнано проти вашого власного бакета й провайдера, а не лише проти налаштувань за замовчуванням — див. 9. Тестування.

Далі: 11. Поширені запитання · див. також 13. Профілі на практиці, де ті самі конфігурації показано через ассети профілів і джерела облікових даних