Hi! I scripted a datastore with session locking.
Is there anything I should change to make it more secure?
local DataStoreService = game:GetService("DataStoreService")
local RunService = game:GetService("RunService")
local Players = game:GetService("Players")
local CashDataStore = DataStoreService:GetDataStore("CashDataStore")
local failedToGet = {}
local function waitForRequestBudget(requestType)
local currentBudget = DataStoreService:GetRequestBudgetForRequestType(requestType)
while currentBudget < 1 do
currentBudget = DataStoreService:GetRequestBudgetForRequestType(requestType)
wait(5)
end
end
local function playerAdded(plr)
local userId = plr.UserId
local leaderstats = Instance.new("Folder")
leaderstats.Name = "leaderstats"
leaderstats.Parent = plr
local cash = Instance.new("IntValue")
cash.Value = 0 --default
cash.Name = "Cash"
cash.Parent = leaderstats
local data
repeat
waitForRequestBudget(Enum.DataStoreRequestType.UpdateAsync)
local success, errormessage = pcall(function()
CashDataStore:UpdateAsync(userId, function(oldValue)
if oldValue then --he might be new
if oldValue.SessionLock == false then
data = oldValue.Cash --getAsync kinda
return {Cash = oldValue.Cash, SessionLock = true} --make SessionLock true
else
failedToGet[plr.Name] = true
plr:Kick("The server you were in before is still trying to save your data, please rejoin or wait...") --kick him
end
end
end)
end)
until success
--maybe he left by now?
if plr:IsDescendantOf(Players) and data then
cash.Value = data --he has data saved
end
end
local function playerRemoving(plr, dontWait)
if failedToGet[plr.Name] == nil then --only save if it could get his data
local cash = plr.leaderstats.Cash.Value
local userId = plr.UserId
repeat
if dontWait == nil then --else dont wait, there is no time for that, the server is shutting down
waitForRequestBudget(Enum.DataStoreRequestType.SetIncrementAsync)
end
local success, errormessage = pcall(function()
CashDataStore:SetAsync(userId, {Cash = cash, SessionLock = false}) --updateAsync not needed, i dont care about oldValue, he might've bought something
end)
until success
else
failedToGet[plr.Name] = nil
end
end
--maybe someone already joined while making these functions
for i,v in ipairs(Players:GetPlayers()) do
playerAdded(v)
end
Players.PlayerAdded:Connect(playerAdded)
Players.PlayerRemoving:Connect(playerRemoving)
game:BindToClose(function()
if RunService:IsStudio() == false then
for i,v in ipairs(Players:GetPlayers()) do
playerRemoving(v, true)
end
else
wait(3) --wait so that playerRemoving can fire, often it shuts down too fast in studio
end
end)
--now autosave
while true do
wait(30) --wait can return false, it's very rare as far as I know but it can occur
for i,v in ipairs(Players:GetPlayers()) do
playerRemoving(v) --can wait
end
end
Thanks.