DataStore: сохранить прогресс и не потерять его
Загружать и сохранять данные игрока так, чтобы сбой сети ничего не стирал.
Теория
DataStore — облачное хранилище Roblox. Работает только на сервере и только в опубликованной игре с включённым доступом к API-сервисам. В Studio без этой галочки запрос упадёт.
Любой запрос идёт по сети и может не ответить. Поэтому его оборачивают в pcall: функция вернёт признак успеха и результат, и код сам решит, что делать с неудачей. Без pcall упавший запрос обрывает весь скрипт.
Загружают данные при входе, сохраняют при выходе и при закрытии сервера. Последнее важно: без BindToClose сервер выключится раньше, чем сохранение успеет уйти.
- UpdateAsync безопаснее SetAsync: он видит текущее значение перед записью
- Имя хранилища с версией — PlayerData_v1 — спасает при смене формата
- Не сохраняй по запросу клиента: что и когда писать, решает сервер
- Пустой результат при первом входе — не ошибка, а новый игрок
Пример
Загрузка при входе и сохранение при выходе.
local DataStoreService = game:GetService("DataStoreService")local Players = game:GetService("Players")local store = DataStoreService:GetDataStore("PlayerData_v1")local cache = {}Players.PlayerAdded:Connect(function(player)local ok, data = pcall(function()return store:GetAsync("user_" .. player.UserId)end)cache[player.UserId] = ok and data or { coins = 0 }if not ok thenwarn("Данные не загрузились, играем без сохранения")endend)Players.PlayerRemoving:Connect(function(player)local data = cache[player.UserId]if not data thenreturnendpcall(function()store:UpdateAsync("user_" .. player.UserId, function()return dataend)end)cache[player.UserId] = nilend)
Задача
Добавь к этому коду сохранение при закрытии сервера, чтобы прогресс последних игроков не пропал при рестарте.
- game:BindToClose(function() … end) вызывается перед выключением
- Пройдись по всем оставшимся записям кэша
Показать решение
game:BindToClose(function()for userId, data in pairs(cache) dopcall(function()store:UpdateAsync("user_" .. userId, function()return dataend)end)endtask.wait(2)end)
Небольшое ожидание в конце даёт запросам уйти до выключения сервера.
Проверь себя
Зачем запросы к DataStore оборачивают в pcall?
Показать ответ
pcall перехватывает ошибку и даёт коду решить, что делать дальше.
Почему UpdateAsync предпочтительнее SetAsync?
Показать ответ
UpdateAsync принимает решение на основе того, что уже лежит в хранилище.