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

DataStore isn't loading the stat?

Asked by 7 years ago
local DSService = game:GetService('DataStoreService'):GetDataStore('Stats')
game.Players.PlayerAdded:connect(function(plr)
repeat wait() until plr.Character
local char = plr.Character
local uniquekey = 'id-'..plr.userId

    if DSService:GetAsync(uniquekey) then
        plr.Leaderstats.Skillpoints.Value = DSService:GetAsync(uniquekey)[1]
    end


plr.PlayerGui.Options.Frame.Save.MouseButton1Click:connect(function()
    DSService:SetAsync(uniquekey, plr.Leaderstats.Skillpoints.Value)
    plr.PlayerGui.Options.Frame.Save.Text = 'Saved'
    wait(2)
    plr.PlayerGui.Options.Frame.Save.Text = 'Save'
end)




end) -- end for playeradd function

This is a normal script so no it isn't localscript, Skillpoints is another value already made in inside the player in another script, and the GUI is just there to notify the players the data's been saved. the problem is it isn't loading when I rejoin?

In output, it also says ServerScriptService.Data:8: attempt to index a number value

0
Because you're not saving it as a table. Just do DSService:GetAsync(uniquekey) and see if that works. User#14829 0 — 7y
0
Thanks! it works now, however the script loads too fast to the point where the making of the values in the other script are slow, and when it says "Leaderstats is not apart of Player" but I just added a wait(10) above the GetAsync thing and now it works fine. Is there a better way for it to wait? HornedWyven 10 — 7y

1 answer

Log in to vote
0
Answered by 7 years ago

There are a number of problems with your script.

  • You do not use the player's character, but wait for it anyway
  • You do not wait for the leaderboard script to insert the "Leaderstats" object into the player. You should use WaitForChild in that case (with a timeout in-case something goes wrong). Since you're accessing multiple children, it may be worth using the function I wrote below.
  • You call GetAsync twice unnecessarily. You should assign the result to a variable so you only need to call GetAsync once.
  • You do not implement debounce on the save feature. A person could rapidly click to save repeatedly, wasting your server's requests.
  • You must put datastore commands in pcall as they may error
local DSService = game:GetService('DataStoreService'):GetDataStore('Stats')
function WaitForChildren(obj, timeout, ...)
    local t = {...}
    for i = 1, #t do
        obj = obj:WaitForChild(t[i], timeout)
        if not obj then return nil end
    end
    return obj
end
game.Players.PlayerAdded:connect(function(plr)
    local skillpoints = WaitForChildren(plr, 5, "Leaderstats", "Skillpoints")
    --or could do "skillPoints = plr:WaitForChild("Leaderstats"):WaitForChild("Skillpoints")", but it wouldn't have a timeout
    if not skillpoints then print(plr, "did not receive Leaderstats.Skillpoints") return end
    local uniquekey = 'id-'..plr.userId
    --Uncomment the following line and its corresponding '--end))' if you want the player to be able to save immediately upon loading your game, even if the GetAsync errors. If it errors, this might mean that the datastores are down, so if you let the player save over it without first loading, they might lose the information stored there. Because of this, you might want to change what happens in the 'i == 5' code.
    --coroutine.resume(coroutine.create(function()
        local success, value
        for i = 1, 5 do --try 5x, once every 15 seconds
            success, value = pcall(function() return DSService:GetAsync(uniquekey) end)
            if success then break end
            if i == 5 then
                print("Could not retrieve data for", plr,", error message:", value)
                value = nil
                break
            end
            wait(15)
        end     
        if value then
            skillpoints.Value = value
        end
    --end))

    local save = WaitForChildren(plr, 5, "PlayerGui", "Options", "Frame", "Save")
    if save then
        local saveDB = false
        save.MouseButton1Click:connect(function()
            if saveDB then return end
            local success, errorMsg = pcall(function()
                DSService:SetAsync(uniquekey, skillpoints.Value)
            end)
            if success then
                save.Text = 'Saved'
            else
                save.Text = "Error: " .. errorMsg
            end
            saveDB = true
            wait(2)
            saveDB = false
            save.Text = 'Save'
        end)
    end
end) -- end for playeradd function

I also recommend against allowing players to save every 2 seconds. Per player, you get a request every 6 seconds (and a few more for the server), meaning that it's only safe to save every 6 seconds on average (per player). Though, if you don't expect players to abuse this, it's probably okay.

Ad

Answer this question