Скрипт: сохранение прогресса в DataStore

Готовый каркас сохранений: монеты и уровень игрока переживают перезаход и рестарт сервера. Каждый сетевой запрос обёрнут в pcall — иначе сбой связи обрывает скрипт.

Куда положить

ServerScriptService, тип объекта Script

Что должно быть в проекте

  • Игра опубликована в Roblox
  • В настройках игры включён доступ к API-сервисам (Studio Access to API Services)

Код

ServerScriptService/SaveData.lua
  1. local DataStoreService = game:GetService("DataStoreService")
  2. local Players = game:GetService("Players")
  3.  
  4. local store = DataStoreService:GetDataStore("PlayerData_v1")
  5. local DEFAULT = { coins = 0, level = 1 }
  6.  
  7. local cache = {}
  8.  
  9. local function keyFor(player)
  10. return "user_" .. player.UserId
  11. end
  12.  
  13. local function save(player)
  14. local data = cache[player.UserId]
  15.  
  16. if not data then
  17. return
  18. end
  19.  
  20. local ok, err = pcall(function()
  21. store:UpdateAsync(keyFor(player), function()
  22. return data
  23. end)
  24. end)
  25.  
  26. if not ok then
  27. warn("Сохранение не прошло: " .. tostring(err))
  28. end
  29. end
  30.  
  31. Players.PlayerAdded:Connect(function(player)
  32. local ok, data = pcall(function()
  33. return store:GetAsync(keyFor(player))
  34. end)
  35.  
  36. if not ok then
  37. warn("Загрузка не прошла, играем без сохранения")
  38. return
  39. end
  40.  
  41. cache[player.UserId] = data or table.clone(DEFAULT)
  42. end)
  43.  
  44. Players.PlayerRemoving:Connect(function(player)
  45. save(player)
  46. cache[player.UserId] = nil
  47. end)
  48.  
  49. game:BindToClose(function()
  50. for _, player in ipairs(Players:GetPlayers()) do
  51. save(player)
  52. end
  53.  
  54. task.wait(2)
  55. end)
  56.  
  57. return {
  58. get = function(player)
  59. return cache[player.UserId]
  60. end,
  61. }

Если загрузка не прошла, данные в кэш не кладутся вовсе — так пустой прогресс не запишется поверх настоящего.

На что обратить внимание

  • Версия в имени хранилища — PlayerData_v1 — пригодится, когда формат данных изменится
  • Не сохраняй после каждого действия: у запросов есть лимиты по частоте
  • Никогда не принимай от клиента, что именно сохранять