In game user id system not saving

Hello. I’m making an in game (not Roblox) user id system for my upcoming game Arksie. Basically the first person to join that game gets the id of 1, the 2nd person gets the id of 2, etc. This is what’s wrong with it.
image
data.UserId is nil. Here’s the code:
(Bits are the in game currency)

local DSS = game:GetService("DataStoreService")
local DS = DSS:GetDataStore("ArksieData")

local LOADED_PLAYERS = {}

local function GenerateDataKey(Player)
	local Key = "UID_" .. Player.UserId
	return Key
end 

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

	local bits = Instance.new("IntValue")
	bits.Name = "Bits"
	bits.Value = 10 --starter amt
	bits.Parent = ls
	
	local UserId = Instance.new("IntValue")
	UserId.Name = "UserId"
	UserId.Parent = ls

	local key = GenerateDataKey(player)
	local data = nil
	local Id = 0
	
	local success,err = pcall(function()
		data = DS:GetAsync(key)
		Id = DS:GetAsync("Id")
	end)
	if not success then
		player:Kick("Couldn't fetch data!\n\nError:\n"..err)
	else
		if data.UserId ~= nil then
			UserId.Value = data.UserId
		else
			if Id ~= nil then
				Id += 1
				DS:SetAsync("Id", Id)
				UserId.Value = tonumber(Id)
			else
				Id = 1
				DS:SetAsync("Id", Id)
				UserId.Value = Id
			end
		end
	end

	if data then
		print(data.Bits, data.UserId, Id)
		bits.Value = data.Bits
		UserId.Value = data.UserId
	else
		print('no data')
	end
	LOADED_PLAYERS[player] = true
end)

game.Players.PlayerRemoving:Connect(function(player)
	local Id = player.leaderstats.UserId.Value
	
	if not LOADED_PLAYERS[player] then return end;
	LOADED_PLAYERS[player] = nil

	local key = GenerateDataKey(player)
	local data = {
		Bits = player.leaderstats.Bits.Value,
		UserId = player.leaderstats.UserId.Value,
	}
	local success, err = pcall(function()
		DS:SetAsync(key, data)
	end)
	if not success then
		warn(err)
	end
end)

game:BindToClose(function()
	local leftToSave = 0
	for player in pairs(LOADED_PLAYERS) do
		LOADED_PLAYERS[player] = nil
		leftToSave += 1

		coroutine.wrap(function()
			local data = {
				Bits = player.leaderstats.Bits.Value,
				UserId = player.leaderstats.UserId.Value,
			}

			local success, errorMessage = pcall(function()
				DS:SetAsync(GenerateDataKey(player), data)
			end)
			leftToSave -= 1
		end)()
	end
	local RunService = game:GetService("RunService")
	while leftToSave > 0 do
		RunService.Heartbeat:Wait()
	end
end)

I advise against doing this because there’s a good chance duplicate IDs will come up because if someone joins at roughly the same time as someone else, the same value will be loaded. If you want to create a unique identifier system, I would recommend HTTPService:GenerateGUID(). If you want to stick with this, I recommend using :IncrementAsync as opposed to :GetAsync().

Anyway, the reason this probably isn’t working is because when the player first joins and the data is nil, you’re never actually modifying the data table, thus it’s always going to be nil.

    local success,err = pcall(function()
		data = DS:GetAsync(key)
		Id = DS:GetAsync("Id")
        data = data or {UserId = Id; Bits = bits.Value} -- if data is nil, it automates to the default value which is the table after the or operator
	end)
1 Like

Hey! Instead of doing data.UserId try just using UserId. This should solve your problem. With the PlayerAdded function you’ve declared the UserId being the int value.

Read the post. I want an in game user id system. Not Roblox.

I’m aware.

Did you try this out? (Feel free to mark this as a solution if this solved your problem.)

Oh, my bad. I misunderstood you. That wouldn’t work because UserId is in a table called data.

Thank you so much. I was going crazy over this.

1 Like