Scripting Helpers is winding down operations and is now read-only. More info→
Ad
Log in to vote
0

Wondering why my leaderboard datastore script doesn't work?

Asked by 1 year ago

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
You shouldn't use a .Changed event with SetAsync(), you'll stress out the server and the datastore if it updates too quickly. pwx 1581 — 1y

1 answer

Log in to vote
0
Answered by 1 year ago
Edited 1 year ago

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)
Ad

Answer this question