Datastore Introduction

An intro to Datastores!

by synoooot

Author Avatar

Update 11/15/19: FAQ added Hey there! Thanks for checking out my tutorial. Today I'll be going over Datastores.

What is a Datastore?

Essentially, a "Datastore" is a thing you use to store data for your game. It could be something like player experience, or their tools, pets, so on and so forth.

The Datastore wiki page can be a bit confusing, so that's why I'm making this tutorial.

In today's example we're going to make a datastore that saves a player's coins.

Just a quick heads up before we get into the coding:

  1. All datastore names can and should be changed to your liking
  2. Store data the way you want, as this is my method to it.
  3. Never forget to use pcalls()! This is very important!

Part 1: Setup

I'll be saving the coins in the a folder inside of the workspace, when a player joins.

Here's the script to do that (put it in ServerScriptService):

local players = game.Players
players.PlayerAdded:Connect(function(player)
    local coins = Instance.new("IntValue")
    coins.Name = player.Name .. "Coins"
    coins.Parent = workspace.CoinValues
end)

Now, here's what it does. The first line gets the Players service. The second line checks whenever a player joins, and the third lines (and onward) set up the coins variable for the player.

If you want this script to work, make a Folder inside of workspace named "CoinValues".

Heads up: Always set the properties of an Instance before setting it's parent.

This is the result:

img|50x40

Note: The player name does not matter.

Next up:

Part 2: Getting Data

Now we get into the meat of things! This is where we set up the datastore.

Now we're going to check when a player leaves:

players.PlayerRemoving:Connect(function(player)
    print(player.Name .. " has left the server, saving data")
end)

Now, we add the DataStore code! Put this before the "players.PlayerAdded" line:

local DataStoreService = game:GetService("DataStoreService")

function GetPlayerData(player)
    local playerData = DataStoreService:GetDataStore("PlayerData")
    local success, data = pcall(function()
        playerData:GetAsync(player.UserId)
    end)
    if not success then
        wait(0.5)
        GetPlayerData(player)
    else
        if Data then
            workspace.CoinValues[player.Name .. "Coins"].Value = Data
        else
            workspace.CoinValues[player.Name .. "Coins"].Value = 0
        end
        print("Player has " .. workspace.CoinValues[player.Name .. "Coins"].Value)
    end
end

Now, let me explain this. First, we get the DataStoreService, and we then make a function named "GetPlayerData" Next, we get a DataStore with all the player's data inside. Now, we.. use a pcall? pcall stands for "Protected Call". It doesn't let errors stop your code from running.

Getting a DataStore entry can go wrong sometimes, so having a pcall stops your code from breaking.

Now, if it didn't get the entry, we try again in a half-second. Why? Making too many datastore calls can cause an error, too.

Most of this is to keep our code safe and running. Then, if it succeeded, we check if the player already has stored data. If they do, we set their Coins value to the stored data.

Another thing: You should store multiple values in a table. DataStores support any datatype so I would heavily recommend saving multiple values in a table.

Continuing on, we then print out the amount of coins the player has.

Now, add this to the end of the "players.PlayerAdded" function:

GetPlayerData(player)

This simply allows us to get the player's data.

Part 3: Saving Data

Remember when we made a "players.PlayerRemoving" function? Well, when the player leaves, we're going to save their coin value. Now, for the sake of the tutorial, we're going to set the player's coins to 10 when they leave, but that's only because we can't change the player's coin value to test the DataStore.

So, add this new fancy function before the players.PlayerRemoving line:

function SavePlayerData(player)
    local playerData = DataStoreService:GetDataStore("PlayerData")
    local success = pcall(function()
        playerData:SetAsync(player.UserId, workspace.CoinValues[player.Name] .. "Coins")
    end)
    if success then
        workspace.CoinValues[player.Name .. "Coins"]:Destroy()
        print("Successfully saved " .. player.Name .. "'s data.")
    else
        wait(0.5)
        SavePlayerData(player)
    end
end

What's that sound? It's explanation time, of course!

Now, this is similar to the GetPlayerData() function. Except... On line 5, we use the "SetAsync" method of our DataStore. Now, there are two parameters to it:

  1. Entry name
  2. Entry data

Now, we set the entry name to the player's UserId, so in the case that the player changes their name, it'll still be able to get their data.

Next, we put in their coins as the second parameter, and voila! Data saved. Now, we get rid of their coin value in workspace just in case they rejoin the same server.

Now this is the last edit you'll have to do to the script. Add this line to the end of the players.PlayerRemoving function:

SavePlayerData(player)

and now it's complete.

Overview

Now, incase I lost you along the way, here's the final script we've made:

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

function GetPlayerData(player)
    local playerData = DataStoreService:GetDataStore("PlayerData")
    local success, data = pcall(function()
        playerData:GetAsync(player.UserId)
    end)
    if not success then
        wait(0.5)
        GetPlayerData(player)
    else
        if data then
            workspace.CoinValues[player.Name .. "Coins"].Value = data
        else
            workspace.CoinValues[player.Name .. "Coins"].Value = 0
        end
        print(player.Name .. " has " .. workspace.CoinValues[player.Name .. "Coins"].Value)
    end
end

players.PlayerAdded:Connect(function(player)
    local coins = Instance.new("IntValue")
    coins.Name = player.Name .. "Coins"
    coins.Parent = workspace.CoinValues
    GetPlayerData(player)
end)

function SavePlayerData(player)
    local playerData = DataStoreService:GetDataStore("PlayerData")
    local success = pcall(function()
        playerData:SetAsync(player.UserId, workspace.CoinValues[player.Name] .. "Coins".Value)
    end)
    if success then
        workspace.CoinValues[player.Name .. "Coins"]:Destroy()
        print("Successfully saved " .. player.Name .. "'s data.")
    else
        wait(0.5)
        SavePlayerData(player)
    end
end

players.PlayerRemoving:Connect(function(player)
    print(player.Name .. " has left the server, saving data")
    workspace.CoinValues[player.Name .. "Coins"].Value = 10
    SavePlayerData(player)
end)

Seems a tad bit long, correct? Well, I hope you were able to learn from this anyways! Note: you cannot test this in Studio! Even if you let Studio have access to the data apis, you still cannot save when the player leaves unless you go into a regular, published game.

FAQ

Question: How do I store multiple values in a table? Answer: You have to do it like this. Say your table was named dogs, and you wanted to store the name of your dogs in it. Well, you could do this: dogs = {"Richard", "BarkMcBarks III", "Bob"} You get each name from the table from it's index. The indexes start out at one and continue increasing until the end of this table. In this case, to get BarkMcBarks, you'd need to do dogs[2]. You cannot save a mixed table (A table with different types of variable types, like bob = {1, "name"}) in a datastore.

Have a good day! -synoooot

View in-game to comment, award, and more!