У будь-якій грі Roblox одночасно існує кілька копій одного й того самого світу: одна — на комп'ютері кожного гравця (клієнт), і ще одна — на сервері Roblox, якій підпорядковуються всі інші. Клієнт показує картинку і приймає натискання клавіш, але остаточне рішення — скільки монет у гравця, чи влучила куля, чи відчинилися двері — завжди ухвалює тільки сервер. Саме цей поділ називають клієнт-серверною архітектурою, і саме йому присвячена четверта тема курсу Roblox Studio: Pro Developer, одразу після того, як діти навчилися розбивати гру на модулі (ModuleScript).
Чому в Roblox взагалі два окремих світи
На перших заняттях Roblox Старту дитина пише скрипт, який виконується ніби в одному місці, — і на простих проєктах цього вистачає. Але щойно в грі з'являється більше одного гравця, виникає питання: хто з них бачить правду? Якщо кожен клієнт самостійно вирішував би, скільки в нього монет, два гравці бачили б різні цифри одного й того самого рахунку, а гра розсипалася б на непогоджені шматки.
Рішення Roblox — зробити сервер єдиним джерелом істини. Він один для всіх гравців одночасно, тримає реальний стан гри (здоров'я, інвентар, рахунок) і єдиний має право його змінювати. Клієнт — це лише вікно, крізь яке конкретний гравець дивиться на цей загальний стан і надсилає серверу свої наміри: «я натиснув W», «я хочу купити цей меч».
Що станеться, якщо довіряти рішення клієнту
Найнебезпечніша помилка новачка — переконати гру, що здоров'я чи гроші можна змінювати прямо зі скрипта на клієнті. Клієнт виконується на комп'ютері самого гравця, а значить, гравець технічно контролює все, що там відбувається, включно з можливістю підмінити значення змінної своїм інструментом стороннього розробника. Якщо сервер довіряє цифрі, яку прислав клієнт, — «у мене тепер 99999 монет» — він просто її приймає без перевірки, і гра стає відкритою для чит-кодів. Саме тому анти-чит у Roblox Studio будується не на хитрих трюках, а на одному простому правилі: сервер ніколи не вірить клієнту на слово, він лише приймає запит і сам перевіряє, чи має сенс його виконати.
RemoteEvent і RemoteFunction: як клієнт і сервер говорять один з одним
Раз клієнт і сервер — це фізично різні місця виконання коду, їм потрібен спосіб передавати повідомлення між собою. RemoteEvent — це односторонній «гудок»: клієнт викликає FireServer(), щоб повідомити серверу про подію («гравець натиснув кнопку атаки»), або сервер викликає FireClient(), щоб сказати конкретному гравцю оновити інтерфейс. Відповіді тут не чекають — повідомлення просто летить в один бік.
RemoteFunction працює інакше: він чекає на відповідь. Клієнт запитує «скільки монет у мене зараз?», і виконання коду зупиняється, поки сервер не надішле реальне число назад. Це повільніше за RemoteEvent, тому на курсі вчать використовувати RemoteFunction рідше — лише там, де відповідь дійсно потрібна одразу, а не для постійного потоку дій на кшталт стрільби чи руху.
Чи можна написати гру без RemoteEvent взагалі?
Для гри з одним гравцем у локальному тесті — технічно можна, бо клієнт і сервер працюють на одному комп'ютері й різниця не відчувається. Але щойно гру публікують для кількох гравців одночасно, без Remote-механізмів дії одного гравця просто не долетять до сервера й не вплинуть на інших: кожен бачитиме лише свою ізольовану картинку. Тому навіть у маленьких навчальних проєктах курсу Remote-механізми вводять заздалегідь, щоб звичка писати код «на дві сторони» сформувалася одразу.
Приклад на пальцях: кнопка купівлі меча
Гравець натискає кнопку «Купити меч» в інтерфейсі — це подія на клієнті. Клієнт викликає FireServer() з назвою меча. Сервер отримує запит, сам перевіряє в DataStore, чи достатньо в гравця монет, і лише тоді списує монети й додає меч в інвентар. Насамкінець сервер викликає FireClient(), щоб оновити цифру монет на екрані саме цього гравця. Жодного моменту клієнт сам не вирішує, що в нього достатньо монет, — він лише просить і показує результат, який прислав сервер.
Цей самий ланцюжок потім використовується в темі збереження прогресу через DataStore: саме тому, що сервер — єдине місце, де рахунок дійсно існує, його можна надійно зберегти між сесіями, не боячись, що у двох клієнтів записані різні цифри.
Де ця тема стоїть у програмі курсу і що буде далі
Клієнт-серверна архітектура — четверта тема з тридцяти одної в повній програмі курсу Pro Developer, одразу перед збереженням прогресу. Порядок не випадковий: DataStore, система раундів, магазин за ігрову валюту й навіть анти-чит — усе це на наступних заняттях будується на тому самому принципі «сервер вирішує, клієнт показує», який діти засвоюють саме тут. Пропустити цю тему й одразу перейти до DataStore означає вчити збереження даних, не розуміючи, чому саме сервер за нього відповідає.
Викладачі курсу спеціально дають цю тему на простому прикладі — кнопці чи важелю, — перш ніж переходити до більш складних механік із системою раундів чи магазином, саме тому, що сама ідея «двох сторін коду» для підлітка непроста з першого разу. Діти, які відразу зрозуміли принцип на прикладі з монетами, потім набагато швидше розбираються в темах 9 і 17–18 програми, де той самий RemoteEvent працює вже всередині складнішої системи хвиль ворогів і донатної монетизації.
Що діти роблять на фінальному проєкті з цією темою
У фінальному портфоліо-проєкті курсу (теми 21–26 програми) клієнт-серверна архітектура вже не окрема вправа, а наскрізна вимога: кожна механіка гри — чи то відкриття скрині, чи то покупка в ігровому магазині — повинна проходити саме через цей ланцюжок перевірки на сервері. Викладач на захисті проєкту навмисно перевіряє, чи не можна обійти логіку гри прямим втручанням у клієнт, — це і є практична перевірка того, наскільки добре засвоєна тема.
Подвійна перевірка RemoteEvent і звичних подій
У програмі подій Roblox Studio RemoteEvent стоїть поруч зі звичайними локальними подіями гри, але працює за іншим принципом — саме тому цю різницю варто тримати окремо в голові, а не змішувати «подію всередині одного скрипта» з «подією між клієнтом і сервером».
Чому сервер не бачить клієнта напряму, а лише слухає запити
Сервер Roblox не «заглядає» в комп'ютер гравця і не читає, що там відбувається, — у нього фізично немає такого доступу, і це свідома частина архітектури, а не обмеження, яке колись виправлять. Єдиний спосіб для сервера дізнатися про дії гравця — чекати, поки клієнт сам надішле RemoteEvent. Це означає, що будь-яка логіка, написана тільки на клієнті без підтвердження сервером, для гри фактично не існує: сервер про неї просто не знає, а значить, не може врахувати її у спільному стані для всіх гравців.
Саме тому досвідчені розробники формулюють правило просто: «клієнт пропонує, сервер затверджує». Клієнт може намалювати будь-яку анімацію постфактум — наприклад, показати спалах від удару одразу, не чекаючи відповіді сервера, щоб гра не здавалася загальмованою, — але остаточний факт («удар справді завдав шкоди») завжди підтверджує лише сервер.
Часті запитання
Чому не можна просто написати всю гру на сервері, без клієнта взагалі? Бо гравцю потрібна картинка, звук і миттєва реакція на свої клавіші — сервер цього не показує напряму, він лише рахує і підтверджує. Клієнт відповідає за відчуття гри, сервер — за її правду.
Скільки RemoteEvent можна створити в одній грі? Стільки, скільки потрібно за змістом — зазвичай по одному на кожну дію, яку гравець може виконати (атака, купівля, телепорт). Обмеження тут практичне, не технічне: занадто багато окремих Remote-подій ускладнює код, тому досвідчені розробники групують пов'язані дії в одну подію з параметром.
Чи сповільнює клієнт-серверний обмін гру? Сам RemoteEvent спрацьовує за частки секунди, тож на звичному домашньому інтернеті затримка непомітна. Проблеми виникають не від самого механізму, а від того, що RemoteEvent викликають занадто часто там, де вистачило б однієї перевірки на весь раунд.