Having trouble with datastores

Hello, I am working on a simple game that requires a datastore to save only one value–problem is I can’t even get that to work.

This is the entirety of my save/leaderboard script, you can ignore the autosave stuff.

local save = game:GetService("DataStoreService"):GetDataStore("Points")
local event = game.ReplicatedStorage.SaveData --remote event
local players = game.Players:GetPlayers()

---------
-- Save will be in the format: Player_USERID , points
---------
function saveInt(player, score)
    if player.UserId > 0 then
	    save:SetAsync("Player_" .. tostring(player.UserID), score)
    end
end

function loadInt(player, stat)
    if player.UserId > 0 then
	    stat.Value = save:GetAsync("Player_" .. tostring(player.UserId))
    end
end

function playerAdded(plr)
    local stats = Instance.new('IntValue', plr)
    stats.Name = "leaderstats"

    local Points = Instance.new("IntValue", stats)
    Points.Name = "Points"

    local tPoints = Instance.new("IntValue", stats)
    tPoints.Name = "Total Points"

    --plr:WaitForDataReady()

    Points = 0
    loadInt(plr, tPoints, "Total Points")
end

function playerRemoving(name)
    local plr = players[name]
    local stats = plr:FindFirstChild("leaderstats")
    if stats ~= nil then
	    saveInt(plr, stats.tPoints.Value)
    end
end


game.Players.PlayerAdded:Connect(playerAdded)
game.Players.PlayerRemoving:Connect(playerRemoving)

--event.OnServerEvent:Connect(playerRemoving) --reuse player removing for autosave

Also, is there a better way to insert code rather than going line by line adding spaces?

The only possible problem I can see is that I didn’t use all the pcall network stuff (which I have yet to learn).

I would appreciate any help.
Thanks!

Your issue is there. PlayerRemoving doesn’t return a string, it returns a reference to the player who left. Make sure to change that to this:

function playerRemoving(plr)
    local stats = plr:FindFirstChild("leaderstats")
    if stats ~= nil then
	    saveInt(plr, stats.tPoints.Value)
    end
end

Just change that and you should be good.

Another problematic thing is you’re doing this:

When you do :GetPlayers(), it doesn’t update when a new player is added, it returns a static array of the players at the time of that function being called.

You have to do :GetPlayers() every time a new player joins to get an updating array. Don’t do that, because there’s no use for doing that in this case

I feel like I should also mention that if you were to use :GetPlayers(), you couldn’t do local plr = players[name] because they keys are numerical, not strings. Keys are the part you use brackets / . to get

Ok, thanks for the input, I’ll try it out.

I do believe you can use strings as keys though as this works fine:

local Players = game.Players--get current players
Players[IT_name].Character:MoveTo(Vector3.new(0, 10, 0)) --teleport IT

(It is a string of a player’s name)

Yeah, but that’s a reference to the service, it updates because it’s an instance, however doing game.Players:GetPlayers() returns numerical keys.

-- :GetPlayers()
local players = {[1] = game.Players.Player1, [2] = game.Players.Player2} -- You can't do players[player.Name], the keys are numbers.
-- game.Players
local players = game.Players -- returns an instance
-- instance keys are organized by the name of the object and it's properties
-- look at the explorer to see how it's organized

I’m pretty sure that the explorer sorts them for the sake of convenience but the engine actually recognises GetChildren arrays based on the order of which they were added in. The same goes for GetPlayers, GetTeams, so on; organisation isn’t implicit. You’d have to do a test to confirm this.

I’m not saying that. I’m just showing why you can’t reference a value in an array using a string.

Basically, what I mean by “look at the explorer to see how it’s organized” is to see what the keys of an instance are.

I’m referencing this comment.

Sorry if I didn’t clarify soon enough, I updated my reply prior to the creation of this post.