Коротко: DataStore — сховище на серверах Roblox, де гра запам'ятовує прогрес між заходами. Без нього монети й рівні зникають при виході; з ним гравець повертається туди, де зупинився.

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

Що таке DataStoreService насправді

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

local DataStoreService = game:GetService("DataStoreService")
local playerData = DataStoreService:GetDataStore("PlayerCoins")

game.Players.PlayerAdded:Connect(function(player)
  local savedCoins = playerData:GetAsync(player.UserId)
  player.leaderstats.Coins.Value = savedCoins or 0
end)

Три рядки — і гра вже «пам'ятає» гравця. Але тут і починаються складнощі.

Чому це працює тільки на сервері

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

Тому правило просте: усе, що стосується збереження, живе на сервері, а клієнт лише показує результат. Для дитини це перше по-справжньому дороге знайомство з думкою «не можна довіряти тому, що приходить від гравця» — і воно потім знадобиться в будь-якій мережевій розробці, не тільки в іграх.

Пастка №1: забути зберегти дані при виході

Завантажити дані — це половина роботи. Друга половина — зберегти їх, коли гравець виходить:

game.Players.PlayerRemoving:Connect(function(player)
  playerData:SetAsync(player.UserId, player.leaderstats.Coins.Value)
end)

Без цього рядка вся система працює лише наполовину: дані завантажуються, але ніколи не оновлюються.

Пастка №2: перевищення лімітів запитів

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

Пастка №3: втрата даних при збої сервера

Сервер може «впасти» до того, як спрацює PlayerRemoving. У серйозних проєктах для цього використовують автозбереження — окремий цикл, який зберігає прогрес кожні кілька хвилин незалежно від виходу гравця.

Друга половина цієї ж проблеми — планова зупинка сервера. Roblox дає для цього окремий гачок, game:BindToClose: у ньому встигають зберегти дані всіх, хто ще в грі, перед тим як сервер закриється. Без нього останні хвилини гри регулярно зникають, і виглядає це для гравця як «гра з'їла мій прогрес».

Пастка №4: виклик без pcall

Звернення до DataStore — це запит через мережу, а мережа інколи не відповідає. Якщо викликати GetAsync напряму, у момент збою скрипт просто впаде — і далі не виконається нічого.

local ok, data = pcall(function()
  return playerData:GetAsync(player.UserId)
end)

if not ok then
  warn("Не вдалося завантажити дані: ", data)
  return -- нічого не перезаписуємо!
end

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

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

Одна таблиця замість десяти ключів

Коли даних стає більше однієї цифри, з'являється спокуса завести окреме сховище для монет, окреме для рівня, окреме для інвентарю. Це і б'є по лімітах, і розсинхронізує дані між собою.

Робочий підхід — зберігати все однією таблицею під одним ключем гравця:

local profile = {
  coins = 120,
  level = 3,
  items = { "sword", "key" },
}

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

Гра змінилась — а збереження старі

Через місяць після запуску дитина додає в гру нову річ: скажімо, енергію або другу валюту. Код готовий, у тесті все працює — а в старих гравців гра ламається, бо в їхньому збереженні цього поля просто немає.

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

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

Думка викладача

«DataStore — одна з тих тем, де діти вперше стикаються з поняттям надійності системи, а не просто «зробив і працює». Це вже інженерне мислення, не просто програмування заради ефекту», — зазначає один із наших менторів курсу.

Тестування DataStore: підводний камінь для новачків

DataStore не працює у режимі Studio за замовчуванням — потрібно окремо увімкнути опцію «Enable Studio Access to API Services» у налаштуваннях гри. Без цього кроку код виглядає робочим, але жодні дані нікуди не зберігаються, і початківець довго шукає неіснуючу помилку.

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

Коли варто вивчати DataStore?

Ми зазвичай вводимо цю тему не на першому занятті, а коли учень вже впевнено працює зі змінними, подіями і базовими скриптами — приблизно на другому місяці курсу Roblox Studio. Раніше — просто занадто багато нових понять одразу.

Ще одна причина не поспішати: DataStore змінює саму розмову про гру. До нього дитина питає «як зробити, щоб працювало», після нього — «що буде, якщо зламається». Це різні рівні мислення, і другий дається легше, коли перший уже впевнений.

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