DataStore Saving

Hello its me Inquistor again, and I have a question. My DataStore for my game saves the currency in my game, but sometimes it doesn’t save correctly like sometimes it does not load and sometimes when you leave incorrectly or when you leave and its in between the stages of saving, it does not load. Is there anyway for me to speed up the datastore or make a new datastore?

Thanks!

2 Likes

Can you show us your script? That’ll help us all out a ton!

1 Like

Okay

local function SaveData(plr,t)
	if plr and t then
		data:SetAsync(plr.UserId,t.Value)
	end
end
game.Players.PlayerAdded:Connect(function(plr)
	Instance.new("Folder",plr).Name = "leaderstats"
	local stat
	local function Getleaderstats()
		wait(0.1)
		if not plr:FindFirstChild("leaderstats") then
			wait(1.5)
			Getleaderstats()
		else
			stat = plr:WaitForChild("leaderstats")
			return true;
		end
	end
	Getleaderstats()
	local function CreateStat(class,name,parent) 
		local i = Instance.new(class) 
		i.Name = tostring(name) 
		i.Parent = parent
		return i
	end
	local money = CreateStat("IntValue","Gold",stat)
	wait(0.03)
	local SavedLevel = data:GetAsync(plr.UserId)
	if SavedLevel then
		money.Value = SavedLevel
	else
		money.Value = 1
		wait(0.08)
		SaveData(plr,money)
	end
end)
game.Players.PlayerRemoving:Connect(function(plr)
	if plr:FindFirstChild("leaderstats") and plr.leaderstats:FindFirstChild("Gold") then
		SaveData(plr,plr.leaderstats["Gold"])
	end
end)
if not game:GetService("RunService"):IsStudio() then
	game:BindToClose(function()
		for _,plr in pairs(game:GetService("Players")) do
			if plr:FindFirstChild("leaderstats") and plr.leaderstats:FindFirstChild("Gold") then
				SaveData(plr,plr.leaderstats["Gold"])
			end
		end
		wait(10)
	end)
end
---This is the first script, in ServerScriptService then then next is--- 

```game.Players.PlayerAdded:connect(function(player)
local DataStore = game:GetService("DataStoreService")

	 local leader = Instance.new("Folder",player)
leader.Name = "leaderstats"

for i,v in pairs(script:GetChildren()) do 
local d = DataStore:GetDataStore(v.Name)
local x = Instance.new("NumberValue",leader)
x.Name = v.Name
x.Value = d:GetAsync(player.UserId) or v.Value



end
end)

game.Players.PlayerRemoving:Connect(function(player)
	for i,v in pairs(script:GetChildren()) do 
		print("Getting")
		local DataStore = game:GetService("DataStoreService")
		local d = DataStore:GetDataStore(v.Name)
		d:SetAsync(player.UserId, player.leaderstats[v.Name].Value)
		print("Saved")
	end
end)
---This is a seperate script in ServerScriptService---

First off if you are the last player in the game you should make a game:BindToClose function that will make it so if the server is ready to shutdown it must execute said code before it can shutdown

like kick every player left in the server and wait 5 seconds before shuting down use this code

local MDT = DTS:GetDataStore("CurrencyDT") -- Change you YOUR datastore name
local PS = game:GetService("Players")
local currencyName = "Currency" -- Change to your currency name

game.Players.PlayerAdded:Connect(function(plr)
	local Folder = Instance.new("Folder")
	Folder.Name = "leaderstats"
	Folder.Parent = plr
	
	local Value = Instance.new("IntValue")
	Value.Name = currencyName
	Value.Parent = Folder
	
	local ID = currencyName.."-"..plr.UserId
	
	local savedData = nil
	pcall(function()
		savedData = MDT:GetAsync(ID)
	end)
	
	if savedData ~= nil then
		Value.Value = savedData
		print(plr.Name.."'s data has loaded!")
	elseif savedData == nil then
		Value.Value = 200
		print(plr.Name.." is a new player!")
	end
end)

game.Players.PlayerRemoving:Connect(function(plr)
	local ID = currencyName.."-"..plr.UserId
	
	MDT:SetAsync(ID, plr.leaderstats[currencyName].Value)
end)

game:BindToClose(function()
	for i, player in pairs(game.Players:GetPlayers()) do
		if player then
			player:Kick("This server is shutting down! Your data should be saved!")
		end
	end
	
	wait(5)
end)

Okay thanks where would I replace that code to.

Thanks!

Studio is infamous for shutting down before the data gets saved, that’s why you have to use a BindToClose function, if you’re also checking if your current game is inside studio you can solve this issue.

See this exampel:

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

game:BindToClose(function()
	if RunService:IsStudio() then
		for _,Player in ipairs(Players:GetPlayers()) do
			local Success,ErrorMessage = pcall(function()
				--Your data saving script comes into here
			end)
			if not Success then
				warn("Error: "..ErrorMessage)
			end
		end
	end
end)

I also suggest using a pcall function since saving data can sometimes throw errors.

Okay Thanks where would I put this to at the end of my code?

It is up to you where you put it

Also, there is already a bindtoclose funciton at the end of my code

I don’t know how functions behave, if they do behave like events you’d need to put that script into your BindToClose function as events have the problem of not running if they have have been used mutliple times in one script.

The code you have written could potentially lose data for a lot of users - most notably the use of SetAsync and lack of pcalls.

I suggest using a proper module like DataStore2 or ProfileService to handle data saving.

Okay how would I use DataStore2 using my currency I can not find the model for DataStore 2 and I can not find a real manual on hwo touse it

What you’re doing is pretty simple, just use a dictionary to store data.

local Players = game:GetService("Players")
local DataStoreService = game:GetService("DataStoreService")
local GoldData = DataStoreService:GetDataStore("Gold")

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

    local gold = Instance.new("IntValue")
    gold.Name = "Gold"

    local data = nil
    local success, err = pcall(function() 
        data = GoldData:GetAsync(player.User.."-gold")
    end)

    if success then — if getting data was successful 
        if data then — if the player has data then...
            gold.Value = data.Gold — looks into the dictionary, and grabs gold’s value
        else — there’s no data, must be a new player
            gold.Value = 100 — give the player 100 gold when they first join
        end
    else — getting data wasn’t successful 
        warn("There was an error whilst grabbing data!")
        warn("Error:", err)
    end
end)

Players.PlayerRemoving:Connect(function(player) 
    
    local gold = player:WaitForChild("leaderstats").Gold
    local data = {
        Gold = gold.Value — save a key called “Gold” to be referenced later
    }

    local success, err = pcall(function() 
        GoldData:UpdateAsync(player.UserId.."-gold", function() 
            return data — save the data
        end)
    end)

    if not success then
        warn("There was an error whilst saving data!")
        warn("Error:", err)
    end

end)


Would that be able to save most of the time?

Thanks! Because I do not want my game to make all players to lose their gold.

Also theres a problem with that I already have a different script that names my leaderstats that is named Gold. So how would I refer to that using your script?

is this happening in-game or in studio?

since im pretty sure when you hit close in a play-solo you kinda “force shut” the game. I think in real servers the server gets shut down after 2-3 seconds of the last player leaves (which gives the server time to save the data)

I made a DataStore2 and it works. But how would I add my currency that kills players for money inside of it?
Here is my DataStore2 code here. I know where to plug the script in just need to know how it would be plugged in.


local defaultValue = 100

game.Players.PlayerAdded:Connect(function(plr)
	
	local goldDataStore = DataStore2("gold",plr)
	
	local leaderstats = Instance.new("Folder", plr)
	leaderstats.Name = "leaderstats"
	
	local gold = Instance.new("IntValue", leaderstats)
	gold.Name = "Gold"
	
	local function goldUpdate(updatedValue)
		gold.Value = goldDataStore:Get(updatedValue)
	end
	
	goldUpdate(defaultValue)
	
	goldDataStore:OnUpdate(goldUpdate)
end)

game.Workspace:WaitForChild("ChickenO").ClickDetector.MouseClick:Connect(function(player)
	local goldDataStore = DataStore2("gold", player)
	
	goldDataStore:Increment(50, defaultValue)
	
end)

The data might not save properly in studio because the game leaves really fast, or the server shuts down in an unexpected way. But there is a really really useful function for that (as some people mentioned already.) game:BindOnClose()!

You can check more about this function or how to properly save here.

P.S. This thread helped a lot of people. Including me!

You might want to read up the guide for DataStore2

1 Like