How to make DataStores?

Where’s the DataStore variables? Where’s the protective call for GetAsync? I don’t see you’re learning the basics of DataStore, I recommend you just watch a tutorial.

Forgot to add those in. Will do that now.

First, if you haven’t already, enable studio access to API services (Game settings, Security)

What you need to do is create a datastore for each one using DataStoreService (Just going to use your moneyStat as an example) and then tell it to place whatever value that is in the datastore to your moneyStat.

local DataStoreService = game:GetService("DataStoreService")
local moneyDataStore = DataStoreService:GetDataStore("Money")
local function onPlayerJoin(player)
local moneyStat = Instance.new("IntValue",leaderstats)
moneyStat.Name = "Money"
moneyStat.Value = 0
moneyStat.Parent = leaderstats
local playerUserId = "Player_"..player.UserId
local data
local success, errormessage = pcall(function()
	data = moneyDataStore:GetAsync(playerUserId)
end)
if success then
	player.Money.Value = data
	print("Successfully loaded player data!")
else
	print("Error loading in a player's data")
end
end

game.Players.PlayerAdded:Connect(onPlayerJoin)

Also please correct me if any of the code is wrong

What if I wanted to save multiple stats?

Then you would just create multiple datastores with each stat that you want:

local moneyDataStore = DataStoreService:GetDataStore("Money")
local statisticsDataStore = DataStoreService:GetDataStore("statistics")
local multiplierDataStore = DataStoreService:GetDataStore("Multiplier")
local maxAmountDataStore = DataStoreService:GetDataStore("RandomAmountMax")
local minAmountDataStore = DataStoreService:GetDataStore("RandomAmountMax")

and then you can modify the pcall function to be:

local data
local data2 -- etc.
local success, errormessage = pcall(function()
	data = moneyDataStore:GetAsync(playerUserId)
    data2 = statisticsDataStore:GetAsync(playerUserId)
    -- Basically just repeat this for each datastore (data3 = (datastore):GetAsync(playerUserId), data4, data5...)
-- Or you can just set up a table of the values like Vong25 said
end)
if success then
	player.Money.Value = data
    player.statistics.Value = data2
   -- You can also just repeat it for each value 
	print("Successfully loaded player data!")
else
	print("Error loading in a player's data")
end
end

But that is just to set the data when the player joins.

Right now the data doesnt get saved when the player leaves so in order to do that:

game.Players.PlayerRemoving:Connect(function(player)
	local playerUserId = "Player_"..player.UserId
	local data = player.Money.Value
    local data2 = player.statistics.Value
    -- Pretty much just repeat for each value again
   -- Or you can just set up a table of the values like Vong25 said
	local success, errormessage = pcall(function()
		 moneyDataStore:SetAsync(playerUserId, data)
         statisticsDataStore:SetAsync(player.UserId, data)
            -- and also repeat for each datastore too.
	end)
	if success then
		print("Successfully saved  data")
	else
		print("Error saving data")
	end
end
)

There’s probably a better way than what I am doing.

There is a better way, put all the data in a table and save the table.

local data = {
    Money = 0
    -- rest of data
}
1 Like

There’s just one little problem… that I have no clue how to fix, unless I’m missing something very obvious.
image

It should be r3generat3.leaderstats.Money; you omitted the leaderstats.

Hello! DataStores are an ever growing thing ROBLOX uses to help players save player data in game. Tables are usually the best way to do it!

But, thankfully, there have been methods of DataStores that are easy to use, and simple to operate with! I will provide you with some helpful links to checkout! These links are what helped me, and will help you if you put the time in to read them!

This is a DevForum Post that I found useful!

All of these links should provide you with enough information YOU NEED to start creating your very own DataStore system for tools, money, and more!

Right. Woops. Though, what else happens is that all of my stats get set to 0 by default. Even when I have such things as a Multiplier set to 1 by default.

1 Like

It took me a few months to get datastores working properly. Datastores are tricky because of all the assumptions that tutorials have of your understanding of the API they provide. That’s the reason why so many people opt for a premade datastore handler that is easier to use like DataStore2 or ProfileService which do the tricky stuff for you.

It takes time getting used to it if you are doing it on your own. It might be helpful looking into how DataStore2 and ProfileService implement things (though I have to admit it is confusing to read through).

One thing I noticed in the thread that hasn’t been taken into account is initialized data. If a player has never saved before, their data is nil. You have to check for that, and if you find a nil value, set it equal to the default value. Otherwise you are resetting the default value to nil which I would think has undefined behaviour but apparently it is setting everything to 0 by default for you.

For this:

One thing I noticed in the thread that hasn’t been taken into account is initialized data. If a player has never saved before, their data is nil . You have to check for that, and if you find a nil value, set it equal to the default value. Otherwise you are resetting the default value to nil which I would think has undefined behaviour but apparently it is setting everything to 0 by default for you.

I’ve tried doing this:

	local playerUserId = "Player_"..player.UserId
	local data
	local data2
	local data3 
	local data4 
	local data5 -- etc.
	local success, errormessage = pcall(function()
		data = moneyDataStore:GetAsync(playerUserId)
		data2 = maxAmountDataStore:GetAsync(playerUserId)
		data3 = multiplierDataStore:GetAsync(playerUserId)
		data4 = rebirthDataStore:GetAsync(playerUserId)
		data5 = minAmountDataStore:GetAsync(playerUserId)
		-- Basically just repeat this for each datastore (data3 = (datastore):GetAsync(playerUserId), data4, data5...)
	end)
	if success then
		player.leaderstats.Money.Value = data
		player.statistics.RandomAmountMax.Value = data2
		player.leaderstats.Multiplier.Value = data3
		player.leaderstats.Rebirths.Value = data4
		player.statistics.RandomAmountMin.Value = data5
		-- You can also just repeat it for each value 
		print("Successfully loaded player data!")
	else
		player.leaderstats.Money.Value = 0
		player.statistics.RandomAmountMax.Value = 5
		player.statistics.RandomAmountMin.Value = 1
		player.leaderstats.Rebirths.Value = 0
		player.leaderstats.Multiplier.Value = 1
		print("Error loading in a player's data")
	end
end)

But this didn’t seem to work and I’m not sure what to do.

If you saved it once then it will stay that way, any changes won’t be registered because the data is already stored with all the values being set to 0. So what I suggest is you go in Test > Server and change the values on the server yourself and then switch on the client and leave the game, the data should then save.

1 Like

I tried that, and it still keeps getting reset to 0.

EDIT: Now my money giver doesn’t work.

First, you probably have to understand how DataStores work.

DataStores basically work like a dictionary. They need a key to access the data.
For instance, it might look like this inside of the DataStore

{1512612612 = 500}

Basically the first value is the key and the second one is the value that can be accessed with the key (just like dictionaries work)

Here is an easy example:

local DataStoreService = game:GetService("DataStoreService")
local MyFirstDataStore = DataStoreService:GetDataStore("MyFirstDataStore")

Alright, here we just make two variables. The first one defines the DataStoreService which is a service, just like ReplicatedStorage, Workspace, ServerStorage, … .

Then, we call a method on our DataStoreService variable which is called GetDataStore.
GetDataStore basically creates gets the DataStore with the name in the quotation marks, if there is no DataStore with that name yet, it creates one.

Alright, so we assigned our new DataStore with the name MyFirstDataStore to our MyFirstDataStore variable.

Now we actually want to save Data.
I will try to make this as easy as possible for you.

Alright, so for now we are going to give your friend who is called Ben 500 cash when he joins the game.

In our case, Ben is our key (don’t do that please, use the UserId instead as it’s more unique, Ben could change his name for example and his data would be lost).

We want the dictionary to look like this

{["Ben"] = 500}

So we do

local DataStoreService = game:GetService("DataStoreService")
local MyFirstDataStore = DataStoreService:GetDataStore("MyFirstDataStore")

MyFirstDataStore:SetAsync("Ben", 500)

Alright. Now we call a method on our MyFirstDataStore variable which is SetAsync.

SetAsync basically creates a new entry into our DataStore dictionary. The first parameter is the key and the second parameter is the actual value.

Our key is “Ben” and our value is 500.

Alright. Now we set our DataStore entry but we have to check everytimes a player joins if his name is Ben and if so, give him 500 coins.

Let’s do that!

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

MyFirstDataStore:SetAsync("Ben", 500)

Players.PlayerAdded:Connect(function(playerThatJoined)
    --create leaderstats
    local leaderstats = Instance.new("Folder")
    leaderstats.Name = "leaderstats"
    leaderstats.Parent = playerThatJoined

    local cash = Instance.new("IntValue")
    cash.Name = "Cash"
    cash.Parent = leaderstats

    --now check if the player that joined is your friend, Ben
    local async = MyFirstDataStore:GetAsync(playerThatJoined.Name) --This will become 500 (our value for Ben) if it's actually Ben. If not, it will be nil
    if async ~= nil then --Check if it's not nil
        --it's not nil. It's Ben!
        cash.Value = async --async is 500 (our value for Ben) 
    end
end) 

Alright. Now you know the basics of getting data and setting data.
Remember that DataStores are like dictionaries, they have a key and a value that is assigned to that key.

When doing DataStore:GetAsync(playerName), then it will either become the value of the key that you entered as parameter or nil.

You can store strings, numbers, tables, … inside of DataStores! They are very useful.
If you still don’t understand something, I would recommend you Youtube. Also you might want to try the DevHub, even though I found it a little worse than Youtube.

Here a script that saves when someone leaves and gets their value when someone joins:

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

Players.PlayerAdded:Connect(function(playerThatJoined)
	--create leaderstats
	local leaderstats = Instance.new("Folder")
	leaderstats.Name = "leaderstats"
	leaderstats.Parent = playerThatJoined

	local cash = Instance.new("IntValue")
	cash.Name = "Cash"
	cash.Parent = leaderstats

	local async = MyFirstDataStore:GetAsync(playerThatJoined.UserId) 
	if async ~= nil then --Check if it's not nil
		cash.Value = async 
	end
end) 

Players.PlayerRemoving:Connect(function(playerThatLeaves)
	MyFirstDataStore:SetAsync(playerThatLeaves.UserId, playerThatLeaves.leaderstats.Cash.Value)
end)

You would also want to pcall the SetAsyncs, but you will eventually find out yourself.

I understand, but putting it in is confusing, if that makes any sense. It breaks my game.

If you just directly jump on to a stage in programming which requires knowledge of previous elements such as Tables etc, then it is pretty hard to know how to solve these kind of problems.



That being said, a really basic example to show how saving multiple stats might be like (again, This is just an idea) :

A really simple example. I will also put comments that will help you understand, leaving no way that you won’t understand the basics of saving multiple stats in one datastore, unless you’re really beginning with programming.

local statStore = game:GetService("DataStoreService"):GetDataStore("StatStore")
local players = game:GetService("Players")

players.PlayedAdded:Connect(function(player)
    local cash = Instance.new("IntValue", player)
    cash.Name = "Cash"

    local level = Instance.new("IntValue", player)
    level.Name = "Level" --Some Basic Value Instances for our stats

    local success, response = pcall(statStore.GetAsync, statStore, player.UserId) --Getting the current data for the player, wrapped in a pcall to handle errors.

    local data = response or { --This table will be used in case the response is nil, meaning theres no data.
            Cash = 100,
            Level = 1
    }

    if success then
       cash.Value = data.Cash
       level.Value = data.Level --Setting our stat values to the loaded values from the datastore / default ones.
    else
         --However you want to handle errors
    end
end)

players.PlayerRemoving:Connect(function(player)
    local saveTable = { --Just like the data table while loading data, this is for the saving structure.
        Cash = player.Cash.Value
        Level = player.Level.Value
    }

    local success, response = pcall(statStore.SetAsync, statStore, player.UserId, saveTable)
--Just like loading data, we now use the SetAsync method to save our data.

    if success then
          print("Successfully Saved Data!")
    else
          --Handle errors here, maybe retry or something?
    end
end)

But this example breaks at around line 29.
image

I should have said I haven’t tested that example, also its just a typo, you shouldn’t just copy paste examples but also use some of your own logic. Replace the saveTable variable:

local saveTable = { --Just like the data table while loading data, this is for the saving structure.
		Cash = player.Cash.Value,
		Level = player.Level.Value
}

It still didn’t work.

You know what, I give up.