Help with datastores

Would it be fine telling me how datastores work,
e.g. saving something, let’s say Cash. And then loading it when they next join. Couldn’t understand wiki page

8 Likes

Welcome to the developer forum!

I will follow up with you in private messages on how to make this question more specific so people can help you out.

4 Likes

Have you tried watching some helpful video tutorials?

Here are some examples:

5 Likes

Hi, thanks for asking this question! I’ll explain the basics of datastores here.

Before we get into detail on how to use datastores, let’s review a bit of background information.


What are datastores?

Datastores, put simply, are databases where information is stored, retrieved and written to. ROBLOX datastores serve the purpose of letting developers save and retrieve information / data across multiple playsessions.

To quote the Datastore Wiki directly :

“Data stores are a storage feature for Roblox games that can be used to save data that will persist even after a game’s server has shut down. They are designed to store custom player data or to control global game configurations. Data stores are shared per game, so any place in a game, including places in different servers, can access and change the same data”

How do I save information to datastores, and retrieve it later?

Like any other ROBLOX service, DataStores have an API, which you can read here.

DataStores are a service, that is, you access them via the game:GetService() function.

For this example, we will be using a simple currency system. A player’s “Money” will be displayed in the default ROBLOX leaderboard, and save when they leave. When a player joins the game later, their money will load.

To start off, create a ServerScript and place it in game.ServerScriptService. Name it whatever you like, something such as “DataHandler” will suffice.

Decide what you want your DataStore to be named. “Player_Data”, or “Player_Saves” perhaps? Your DataStore should be named according to its function or purpose. For this example, I will name the datastore “Player_Data”.

Place the following code in our new script, the code will be explained :

local DataStoreService=game:GetService("DataStoreService")
local DataStore=DataStoreService:GetDataStore("Player_Data")

In the first line, we access the DataStoreService. The DataStore service is your gateway to managing your datastores.

In the second line of code, we use the GetDataStore() function to retrieve our datastore, which is named “Player_Data” in this case. Don’t worry about the datastore not existing beforehand, if you fetch a name for a datastore that doesn’t exist, a new datastore will be created under that name.

The GetDataStore() function takes one argument, GetDataStore(string DataStoreName).

Now that we have our datastore, what do we do with it?

Now, we load a player’s data when they join the game (If their data exists, that is) and save it when they leave! We also want to display the player’s money amount on the ROBLOX leaderboard, so we have to enable and update the leaderboard as well (you can read the leaderboard wiki here.)

Under the first two lines of code, paste this code :

--[[
	A player has joined the game. Load/Create their data.
--]]
game.Players.PlayerAdded:connect(function(Player)
	
	local PlayerData; --Will hold the player's data when fetched from the datastore.	
	
	--[[
		Set up the player's leaderstats and add them to the ROBLOX leaderboard.
	--]]
	local Stats=Instance.new('Model')
	Stats.Name="leaderstats"
	local Money=Instance.new('NumberValue',Stats)
	Money.Name="Money"
	Stats.Parent=Player
	
	--[[
		We are fetching the player's data, if it exists.
		If it does not exist, we will create new data for the player as they
		must logically be new to the game.
	--]]
	local CanSave=Instance.new('BoolValue',Player) --This is used to determine whether or not the 
	                                               --player's data can be saved when they leave.
	CanSave.Name="CanSaveData"
	CanSave.Value=true
	
	local DataFetchSuccess,ErrorMessage=pcall(function() --We are wrapping the datastore request in a protected function, as web requests can error. 
	                                                     --Safely handling datastore errors can prevent player data corruption.
	PlayerData=DataStore:GetAsync(tostring(Player.UserId))
	end)
	
	if DataFetchSuccess then --The datastore GET request was successful!
		
		if PlayerData~=nil then --The player's data exists, they have played this game before. Put their data into the leaderboard.
			Player.leaderstats.Money.Value=PlayerData
		else --The player's data does not exist, they're new to the game. Create their data on the leaderboard.
			Player.leaderstats.Money.Value=100 --Players start out with 100 money in this example.
		end
		
	else --The GET request failed, datastores could be down.
		
		--[[
			There are many ways to handle datastore failures. In this case, we will kick the player, 
			letting them know their data failed to load. 
			Because their data wasn't loaded, we won't save their data when they leave.
		]]--
	
		Player.CanSaveData.Value=false
		Player:Kick("Your data failed to load! Please rejoin.")	
			
	end
  
end)
--[[
	A player is leaving the game. Save their data.
--]]
game.Players.PlayerRemoving:connect(function(Player)
	
	if Player.CanSaveData.Value==false then return end --Player data can't be saved, so do nothing.
	
	local PlayerData=Player.leaderstats.Money.Value
	
	local DataWriteSuccess,ErrorMessage=pcall(function() --Once again, we are safely calling a web request. If it fails, we can safely handle it.
		DataStore:SetAsync(tostring(Player.UserId),PlayerData)
	end)	
	
	if not DataWriteSuccess then --Uh oh, player data didnt' save. Handle this error.
		--We will attempt to save the player's data 5 more times. If it fails after 5 times, 
		--we will abort the save and the player's data will not be changed in the datastores.
		
		local Retry_Count=0
		
		while Retry_Count<6 do
			wait(60) --Wait 1 minute between each retry
			local Succeded,Error=pcall(function()
				DataStore:SetAsync(tostring(Player.UserId),PlayerData)
			end)
			if Succeded then break end --HURRAY, DATA SAVED!
			Retry_Count=Retry_Count+1
		end
		
	end
	
end)

I know this is a bit much, but let’s break down this code, shall we?

In the first segment of code, we load the player’s data when they join the game (or create new data for them if they’re new to the game). In the event that their data fails to load, they are kicked from the game with the message “Your data failed to load! Please rejoin.”, and their data is not saved as to preserve their data on the datastores.

In the second segment of code, we do the following :

  1. When the player leaves, the server checks if their data can be saved. If their data failed to load originally, the server won’t replace their intact data on the datastores.
  2. If the player’s data can be saved, it attempts to write their new data to their datastore key.
  3. If it fails to save the new data, it will try 5 more times across the timespan of 5 minutes. If it fails all 5 times, the new data will not be saved.

The GetAsync() function allows you to retrieve data from a datastore key. A datastore key is a unique table of information in a datastore. In this example, we set the player’s key as their user ID. You never want to use a user’s name as a key, as they can change their names for R$ 1,000. If they changed their name and you used their name as their data key, their data wouldn’t be loaded anymore!

The SetAsync() function allows you to save data to a datastore key.

Wrap up

If you need detailed information, the wikis are linked in this post. I hope this was helpful to you!

I apologize if this wasn’t exactly the clearest explanation, I’m not the best at explaining things via typing. :slight_smile:

EDIT :
Fixed some issues with the code, it should work as expected now.

46 Likes

Very helpful and detailed tutorial for our new developers, Great job!

3 Likes

I’m not really a new developer, I’ve just never understood datastores

I meant “developers” as in everyone and not just specifically you.

2 Likes