Secure Data Store
Hello i’m DylTheDeveloperX i do my own Secure Data Store back then last month and i get alot of source in Social Media, to know how will i handle Data Loss.
Things I do :
- BindToClose()
- Update Async
- Repeat Until Sucess Per Minute
- If player leave then repeat until sucess wont work!
- Auto Save()
- When GetAsync() fails then it wont save!
- Wrappers for loading data!
- Pcalls.
Model :
Questions ?
- How can i improve this data store?
Code :
local Players = game:GetService("Players")
local DataStoreService = game:GetService("DataStoreService")
local myDataStore = DataStoreService:GetDataStore("myDataStore")
-- [[ SETTINGS]] --
local tries = 3 -- Retries
local Closing = 8.5 -- When shutdowns wait() dont make it higher than 8
local tries2 = 3 -- Dont set it higher than 4 because its part of BindToClose()
local Slowdown = 60 -- Slowdown GetAsync()
local AutoSaved = 60 -- Auto saving wait()
local IsInGame = {} -- In this variable will verify if Player still in game.
local dataLoaded = {} -- Tables per Saves.
local function Set(plr)
local key = "plr-" .. plr.UserId
IsInGame[key] = true -- Means Closed Case
-- Notifier if dataLoaded = false
if dataLoaded[key] == false then
warn("We cant save the value because the dataLoaded key is = false " .. key)
end
if dataLoaded[key] == true then -- Make sure it loads
local count = 0
local data = {
["Coins"] = plr.leaderstats.Coins.Value,
}
-- Repeating when player leave will cause bug that's why AutoSaves is here.
--[[ Example : ]]
-- Player loss his data while leaving then when she rejoin his data will retrieve because of AutoSaves
-- 3 Parts Of Saving --
-- When players leave.
-- When game Shutdown.
-- Autosaves.
local sucess, err
sucess, err = pcall(function()
myDataStore:UpdateAsync(key, function(oldValue)
local newValue = data or oldValue or 0
return newValue
end)
end)
if not sucess then
warn("Failed to set the value. Error code: " .. tostring(err))
return
end
else
return
end
end
local function Get(plr, value)
local key = "plr-" .. plr.UserId
IsInGame[key] = false -- When they just join
local count = 0
local data
local sucess, err
if IsInGame[key] == false then
repeat
sucess, err = pcall(function()
data = myDataStore:GetAsync(key)
end)
count = count + 1
if script.SelfCheck.Value == true and count >= 2 then -- Prints The progress.
print(count.. " We retrying to load the data.")
end
if count >= 2 then
wait(Slowdown) -- Slow Down The Process ; Repeats
end
until count >= tries or sucess
end
-- individual
dataLoaded[key] = true
if not sucess then
dataLoaded[key] = false
warn("Failed to read. Data. Error code: " .. tostring(err))
plr:Kick("Sorry were not able to load your data roblox is currently down please try again in next time.")
return
end
if sucess then
if data then
print(dataLoaded)
return data
else
return {
["Coins"] = script.Increment.Value,
}
end
end
end
-- Auto Saving --
local function AutoSaves(plr)
if plr then
local key = "plr-" .. plr.UserId
if dataLoaded[key] == true then -- Make sure it loads so it wont save
if IsInGame[key] == false then -- Make sure he / she is still in game.
local data = {
["Coins"] = plr.leaderstats.Coins.Value,
}
local sucess, err
sucess, err = pcall(function()
myDataStore:UpdateAsync(key, function(oldValue)
local newValue = data or oldValue or 0
return newValue
end)
end)
if not sucess then
warn("Failed to set the value. Error code: " .. tostring(err))
return
end
else
return
end
end
end
end
local function createLeaderstats(plr)
local leaderstats = Instance.new("Folder",plr)
leaderstats.Name = "leaderstats"
local Coins = Instance.new("IntValue", leaderstats)
Coins.Name = "Coins"
Coins.Value = 0
local values = Get(plr)
local SetValue = pcall(function()
Coins.Value = values.Coins
end)
end
local function Closing(plr) -- When saving in shutdown...
local key = "plr-" .. plr.UserId
IsInGame[key] = true -- Means Closed Case
if dataLoaded[key] == true then
local count = 0
local data = {
["Coins"] = plr.leaderstats.Coins.Value,
}
local sucess, err
repeat
sucess, err = pcall(function()
myDataStore:UpdateAsync(key, function(oldValue)
local newValue = data or oldValue or 0
return newValue
end)
end)
count = count + 1
if script.SelfCheck.Value == true and count >= 2 then
print(count.. " We retrying to load the data.")
end
if count >= 2 then
wait(Closing) -- Slow Down The Process ; Repeats
end
until count >= tries2 or sucess
if not sucess then
warn("Failed to set the value while BindToClose. Error code: " .. tostring(err))
return
end
else
return
end
end
Players.PlayerRemoving:Connect(Set)
Players.PlayerAdded:Connect(createLeaderstats)
local RunService = game:GetService("RunService")
game:BindToClose(function()
if (RunService:IsStudio())then
else
for i, v in next, game:GetPlayers() do
if v then
coroutine.wrap(Closing)(v)
end
end
end
end)
-- Saving The Value
while wait(AutoSaved) do
coroutine.wrap(AutoSaves)-- This Autosaving part is very important because it make sure that when
end