Hello. How could I make a user id system? This is what I mean: When a player joins, a id gets added to their data. The first player to join has a user id of 1. The second, 2, the third, 3, etc. And their user id never changes. How could I make something like that?
Current code (UserId prints nil):
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 = Id
else
Id = 1
DS:SetAsync("Id", Id)
UserId.Value = Id
end
end
end
if data then
print(data.Bits, data.UserId)
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)
Oh, you can use OrderedDataStore, first see if they have a number assigned and, if not, you give it one and save it with the player id, but this can be inconvenient in games with many players and / or servers.
local DS = game:GetService("DataStoreService")
local UserIdSystem = DS:GetDataStore("UserId")
game.Players.PlayerAdded:Connect(function(Player)
local CustomId = Instance.new("IntValue")
CustomId.Name = "CustomId"
CustomId.Parent = Player
local Id
local success, errormessage = pcall(function()
Id = UserIdSystem:GetAsync("Id")
PlayerId = UserIdSystem:GetAsync(Player.UserId)
end)
if success then
if PlayerId ~= nil then
CustomId.Value = PlayerId
else
if Id ~= nil then
Id += 1
UserIdSystem:SetAsync("Id", Id)
CustomId.Value = Id
else
Id = 1
UserIdSystem:SetAsync("Id", Id)
CustomId.Value = Id
end
end
else
print("There was an error loading")
end
end)
game.Players.PlayerRemoving:Connect(function(Player)
local Id = Player.CustomId.Value
local success, errormessage = pcall(function()
UserIdSystem:SetAsync(Player.UserId, Id)
end)
if success then
print("Saved id for "..Player.DisplayName)
else
print("There was an error loading")
end
end)
Pseudo code without error handling or anything but just the general idea:
local function Joined(player)
local hasId = IDs:GetAsync(player.UserId)
if not hasId then
local setTo
IDs:UpdateAsync("NextId",
function(nextId)
setTo = nextId
return nextId + 1
end)
-- fine to split up Get/Set
-- like this bc the same
-- player won't be in two
-- servers at once
IDs:SetAsync(player.UserId, setTo)
end
end
This is nice, I would just be careful because two servers could call GetAsync at the same time, get the same value, and assign two players the same ID. That’s what UpdateAsync is useful for
I used your code and edited it to fit my code, but it isn’t working. UserId is nil. Here’s the full code:
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
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 = Id
else
Id = 1
DS:SetAsync("Id", Id)
UserId.Value = Id
end
end
end
if data then
print(data.Bits, data.UserId)
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)