Understanding datastores and creating a datastore effectively. -- Community tutorial

Tutorial basic requirements

You’ll need to know the fundamentals of scripting, so like functions, printing, if statements, events, tables, and what not. Please nail down these fundamentals before proceeding onto the tutorial. You’ll also need to know how to create basic leaderstats without saving. Datastores are pretty tricky to understand but I’ll try to keep it as simple as possible.

You will also need to save/publish your place on studio, and enable Studio access to API Services so that this will work. This can be done simply in the following order: Game Settings > Security > Enable Studio Access to API Services

Why use datastoreservice?
I’m pretty sure you know why you want to use it but, the reason you should use datastoreservice is to save things like items, values and what not. Anything to do with saving something of the player after leaving a session requires the use of datastoreservice. So let’s begin.

How to access a datastore

First you need to get the service. How? Simple.

local Datastoreservice = game:GetService("DataStoreService")

Now that we have the service we can access the datastore, using the method :GetDataStore()

local DataStore = Datastoreservice:GetDataStore("Data", "Gold")

The first parameter required is the name (string) of your datastore. Now, the name of your datastore is very important. If you randomly decide to change the name of your datastore it’ll create a new datastore and everyone’s data will be reset. So bare that in mind if you decide to change the name, the second parameter is an optional parameter that you can write in like I did (I named mine “Gold”) but by default is called “global”. The second parameter is called a scope (a unique string). A scope allows you to fetch keys and values which I will explain later. A scope also allows you to keep your code clean, scopes will automatically attach themselves to the keys that you provide using :GetAsync() and I will explain that method later on aswell.

Scopes

Here’s an example of what I mean by scopes attaching themselves to the keys you provide:

Key: gold/PlayerUserId
Scope: gold

Loading Data

Okay, hopefully that made sense. Next, we need to use :GetAsync() to fetch the value from the key.

game.Players.PlayerAdded:Connect(function(player)
local leaderstats = Instance.new("Folder", player)
leaderstats.Name = "leaderstats"

local gold = Instance.new("IntValue", leaderstats)
gold.Name = "Gold"
data = DataStore:GetAsync("Player_"..player.UserId) -- Concatening the string with the player's user 
id
end)

Let me explain this now. :GetAsync() only requires one parameter (well technically two but no one uses the second really, also we’re making a basic datastore). This parameter is what we call a key (string). So, :GetAsync() also returns a value (which is a Tuple, a tuple is a list of values) from the provided key, I am storing that value in the variable called data as you can see in the code above. Let me explain why I did this in the next section. We’re loading the data in a PlayerAdded event because we need to be loading the player’s data when they join.

Error handling

However, :GetAsync() can sometimes fail or error. Having errors in a datastore is a huge issue for a game. THerefore, it’s best to wrap this method in a pcall

game.Players.PlayerAdded:Connect(function(player)
local leaderstats = Instance.new("Folder", player)
leaderstats.Name = "leaderstats"
	
local gold = Instance.new("IntValue", leaderstats)
gold.Name = "Gold"

local success, errormessage = pcall(function()
data = DataStore:GetAsync("Player_"..player.UserId)
end)
if success and data then
print("Success")
player.leaderstats.Gold.Value = data
else
warn(errormessage)
player:Kick()
end

Let me explain what this above code is doing, the first variable success is checking if the function has succeeded, if it has it will print a message in the output "Success". then I am setting Gold’s value to data, this is because when we use :SetAsync() later we will be setting a value to the key, we then need to set the leaderstats’ gold value to the value saved to the key . If :GetAsync() fails however, It will show a warning in the output stating why the function failed and kick the player. Using a pcall is important because if :GetAsync() does error then the rest of the script would not break, and the player can for example simply just rejoin and the data would successfully load the next time they join. We also need to use a pcall for :SetAsync(), I will explain what this method does soon.

Also I should mention that, you do not need to load data in a PlayerAdded event if you want to modify the value by maybe adding 100. In our certain scenario it would be easier to just change the gold’s value, however in different ones such as maybe if you have a redeemable code you can just do what we did above outside of a playeradded event.

Setting Data

Now, I’ll need to explain the concept of keys and datastores further.

Keys and datastores

A datastore is sort of like a lua dictionairy, the key that you provide will store a value. Here’s an illustration.

 Key:        Value:
"Gold"       = 1230                        
"4040312"    = "Amritss"
"cheese"     = true

To save/set our data that we have loaded, we must use :SetAsync(). This method allows you to set a value to the key, this will create essentially a dictionary like we have above with a key holding a value.

game.Players.PlayerRemoving:Connect(function(player)
local success, errormessage = pcall(function()
	DataStore:SetAsync("Player_"..player.UserId, player.leaderstats.Gold.Value)
	end)
	if success then
		print("Success")
	else
		warn(errormessage)
	end
end)

So we’re setting the player’s gold value to the key so that when the player leaves which I hope you guys sort of know why we do that, we set the value to the key so that when the player joins back
and we use :GetAsync() we can set the player’s gold value to the value we set to the key right now with :SetAsync().

Error handling

So, we’re almost done. However, the server called shut down after the player leaves not allowing the PlayerRemoving event to fire in time. Therefore, we can do this.

game:BindToClose(function() -- Incase the server shuts down
	for i, plr in ipairs(game.Players:GetPlayers()) do -- This will run the code for every player
		local success, errormessage = pcall(function()
			DataStore:SetAsync("Player_"..plr.UserId, plr.leaderstats.Gold.Value)
		end)
		if success then
			print("Success")
		else
			warn(errormessage)
		end
	end
end)

Testing the Datastore

Now I am going to join on studio and see if my data saves, I’ve seen that sometimes data will be saved/loaded if you’re joining and leaving on studio and sometimes there will be errors shown even if your datastore is working. Therefore, try publishing your game and testing it there for it to work 100%.

  • Good tutorial?

0 voters

7 Likes