Scripting HelpersARCHIVE
A little piece of Roblox history. Preserved for everyone, one question at a time.Read about the archive →
COMMUNITY QUESTION

Wondering why my leaderboard datastore script doesn't work?

need help fixing this

local datastore = game:GetService("DataStoreService") local ds1 = datastore:GetDataStore("KillsSaveSystem") local ds2 = datastore:GetDataStore("CashSavSsystem") player = game.Players

game.Players.PlayerAdded:connect(function(player) local lb = Instance.new("Folder", player) lb.Name = "leaderstats" local Kills = Instance.new("IntValue", lb) Kills.Name = "Kills" local Cash = Instance.new("IntValue", lb) Cash.Name = "Cash"

Kills.Value = ds1:GetAsync(player.UserId)
ds1:SetAsync(player.UserId, game.Players.leaderstats.Kills.Value)

Cash.Value = ds1:GetAsync(player.UserId)
ds2:SetAsync(player.UserId, game.Players.leaderstats.Cash.Value)

Kills.Changed:connect(function()
	ds1:SetAsync(player.UserId, game.Players.leaderstats.Kills.Value)
Cash.Changed:connect(function()
		ds2:SetAsync(player.UserId, game.Players.leaderstats.Cash.Value)
	end)
end)

end)

1 comment

1

You shouldn't use a .Changed event with SetAsync(), you'll stress out the server and the datastore if it updates too quickly.

1 answer

As what @pwx said, you shouldn't save a value whenever it is changed since you will cause stress to the server (it might break the game) and just save it whenever the player leaves instead.

Also, when using :SetAsync() and :GetAsync(), it might cause errors and eventually break the whole game. To fix this, you need to use a pcall() so that if anything errors, it will be returned by the pcall() and won't be printed in the output (which won't break the game!)

Here's a tip: You don't need to create a DataStore for each value, you can just store them in a table and save the table.

local datastore = game:GetService("DataStoreService")
local ds = datastore:GetDataStore("SaveSystem")
local Players = game:GetService("Players")
local RunService = game:GetService("RunService")

local function waitForRequestBudget(requestType: Enum.DataStoreRequestType)
	local currentBudget = DataStoreService:GetRequestBudgetForRequestType(requestType)
	while currentBudget < 1 do
		currentBudget = DataStoreService:GetRequestBudgetForRequestType(requestType)
		task.wait(5)
	end
end

local function loadData(player)
	local lb = Instance.new("Folder", player)
	lb.Name = "leaderstats"
	
	local Kills = Instance.new("IntValue", lb)
	Kills.Name = "Kills"
	
	local Cash = Instance.new("IntValue", lb)
	Cash.Name = "Cash"
	
	waitForRequestBudget(Enum.DataStoreRequestType.GetAsync) -- we will use this to avoid errors
	local success, data = pcall(function()
		return ds:GetAsync(player.UserId)
	end)
	
	if success and data then
		Kills.Value = data.Kills
		Cash.Value = data.Cash
	else
		print("Player " .. player.Name .. " has no data saved.")
		warn(data) -- warns the error
	end
end

local function saveData(player, dontWait)
	local lb = player.leaderstats
	local data = {
		["Kills"] = lb.Kills.Value,
		["Cash"] = lb.Cash.Value
	}
	
	local success
	repeat
		if not dontWait then -- if game not shutting down
			waitForRequestBudget(Enum.DataStoreRequestType.UpdateAsync) -- we will use this to avoid errors
		end
		-- use :UpdateAsync()  instead of :SetAsync()
		success = pcall(function()
			ds:UpdateAsync(player.UserId, function() -- saved data
				return data
			end)
		end)
	until success -- looping this until datta saved successfully
end

for _, player in ipairs(Players:GetPlayers()) do
	coroutine.wrap(loadData)(player)
end

Players.PlayerAdded:Connect(loadData) -- when player joins the game
Players.PlayerRemoving:Connect(saveData) -- when player is leaving the game

game:BindToClose(function() -- when the game shuts down
	if RunService:IsStudio() then -- if the game is on Roblox Studio
		task.wait(2) -- we will wait 2 seconds and it will fire the .PlayerRemoving event
	else -- if not
		local finished = Instance.new("BindableEvent") -- we will use this wait for everyone's data to save
		local allPlayers = Players:GetPlayers() -- gets every player in the server
		local leftPlayers = #allPlayers -- number of players left in the server
		
		for _, player in ipairs(allPlayers) do
			coroutine.wrap(function()
				saveData(player, true)
				leftPlayers -= 1 -- decreasing the amount of players whose data haven't been saved yet
				if leftPlayers == 0 then -- if no players left
					finished:Fire()
				end
			end)()
		end
		
		finished.Event:Wait()
	end
end)

This discussion is preserved as it was. New answers, comments, and votes are closed.