Skinstashery
Roblox
Home / Roblox / Studio script library / Save data with DataStore
RB-004

Roblox save data with datastore script

Loads and saves each player's Coins between visits, with retries and safe error handling.

Script type
Script
Where it goes
ServerScriptService
Category
Player data and money

For your own game in Roblox Studio. Not for use in other people's games.

The code

-- Save data: loads Coins when a player joins and saves when they leave.
-- This script makes the leaderstats itself. Do not also use the Leaderstats (coins) script.

local STORE_NAME = "PlayerData_v1"   -- change the name to start with a fresh, empty store
local DEFAULT_COINS = 0
local AUTOSAVE_SECONDS = 120
local MAX_TRIES = 3

local Players = game:GetService("Players")
local DataStoreService = game:GetService("DataStoreService")

local store = DataStoreService:GetDataStore(STORE_NAME)
local loaded = {}   -- players whose data loaded OK. We only save these.

-- Runs fn up to MAX_TRIES times. Returns true and the result, or false.
local function tryCall(fn)
	for attempt = 1, MAX_TRIES do
		local ok, result = pcall(fn)
		if ok then
			return true, result
		end
		warn("DataStore call failed (try " .. attempt .. "): " .. tostring(result))
		task.wait(2)
	end
	return false, nil
end

local function keyFor(player)
	return "Player_" .. player.UserId
end

local function savePlayer(player)
	if not loaded[player] then
		return -- the load failed, so saving would wipe real data with defaults
	end

	local leaderstats = player:FindFirstChild("leaderstats")
	local coins = leaderstats and leaderstats:FindFirstChild("Coins")
	if not coins then
		return
	end

	local data = { Coins = coins.Value }
	local ok = tryCall(function()
		store:SetAsync(keyFor(player), data)
	end)
	if not ok then
		warn("Could not save data for " .. player.Name)
	end
end

local function onPlayerAdded(player)
	local leaderstats = Instance.new("Folder")
	leaderstats.Name = "leaderstats"
	leaderstats.Parent = player

	local coins = Instance.new("IntValue")
	coins.Name = "Coins"
	coins.Value = DEFAULT_COINS
	coins.Parent = leaderstats

	local ok, data = tryCall(function()
		return store:GetAsync(keyFor(player))
	end)

	if not ok then
		warn("Could not load data for " .. player.Name .. ". Their progress will not be saved this visit.")
		return
	end

	if type(data) == "table" and type(data.Coins) == "number" then
		coins.Value = data.Coins
	end
	loaded[player] = true
end

local function onPlayerRemoving(player)
	savePlayer(player)
	loaded[player] = nil
end

Players.PlayerAdded:Connect(onPlayerAdded)
Players.PlayerRemoving:Connect(onPlayerRemoving)

for _, player in Players:GetPlayers() do
	task.spawn(onPlayerAdded, player)
end

-- Save everyone when the server shuts down.
game:BindToClose(function()
	for _, player in Players:GetPlayers() do
		task.spawn(savePlayer, player)
	end
	task.wait(3)
end)

-- Save everyone every couple of minutes in case of a crash.
task.spawn(function()
	while true do
		task.wait(AUTOSAVE_SECONDS)
		for _, player in Players:GetPlayers() do
			task.spawn(savePlayer, player)
		end
	end
end)

How to set it up

  1. In Studio, open Home > Game Settings > Security and turn on "Enable Studio Access to API Services". Without this, saving fails in Studio.
  2. Publish your game (File > Publish to Roblox). DataStores need a published game.
  3. Add a Script to ServerScriptService and paste the code. Remove any other Script that makes leaderstats.
  4. Play, change your Coins value in the Explorer, stop the test, and play again. The number should still be there.

Change it

More in Player data and money

All Roblox scripts

More Roblox tools