The question is simply what I could improve with the system? (I have not implemented BindToClose and UpdateAsync because I do not know how to use them correctly.)
Setup:
Module
--// 𝙎𝙀𝙍𝙑𝙀𝙍
local DataService = {}
-- VARIABLES
local Players = game:GetService("Players")
local RunService = game:GetService("RunService")
local Marketplace = game:GetService("MarketplaceService")
local DataStoreService = game:GetService("DataStoreService")
local PlayerData = DataStoreService:GetDataStore("PlayerData")
local GameVersion = script:WaitForChild("Version")
local AutoSaveTime = 120
local PlayerSessionData = {} -- Storage for every players' data.
-- DATA STRUCTURE
local DataStructure = {
Version = GameVersion.Value,
Currencies = {
Money = 0,
},
}
-- DATASTORE
-- Change version value to one higher when an update is made.
function DataService:GetVersion(data, version) -- Gets current version of players' data.
if data.Version ~= version.Value then -- Checks if data version is the same as dataservice' version.
return true
else
return false
end
end
function DataService:CopyTable(t)
local tCopy = {}
for k,v in pairs(t) do
if (type(v) == "table") then
tCopy[k] = self:CopyTable(v)
else
tCopy[k] = v
end
end
return tCopy
end
function DataService:Sync(tbl, templateTbl)
for k,v in pairs(tbl) do
local vTemplate = templateTbl[k]
if (vTemplate == nil) then
tbl[k] = nil
elseif (type(v) ~= type(vTemplate)) then
if (type(vTemplate) == "table") then
tbl[k] = self:CopyTable(vTemplate)
else
tbl[k] = vTemplate
end
elseif (type(v) == "table") then
self:Sync(v, vTemplate)
end
end
for k,vTemplate in pairs(templateTbl) do
local v = tbl[k]
if (v == nil) then
if (type(vTemplate) == "table") then
tbl[k] = self:CopyTable(vTemplate)
else
tbl[k] = vTemplate
end
end
end
end
function Sync2(orig)
local orig_type = type(orig)
local copy
if orig_type == 'table' then
copy = {}
for orig_key, orig_value in next, orig, nil do
copy[Sync2(orig_key)] = Sync2(orig_value)
end
setmetatable(copy, Sync2(getmetatable(orig)))
else
copy = orig
end
return copy
end
function DataService:UpToDate(player) -- Check if any new data is added.
local Data = PlayerData:GetAsync("data:"..player.UserId)
local Updated = self:GetVersion(Data, GameVersion)
if Updated then
print(player.Name.."'s data is not up to date!")
self:Sync(PlayerSessionData[player], DataStructure)
PlayerSessionData[player].Version = GameVersion.Value
print(player.Name.."'s data should now be up to date!")
else
print(player.Name.."'s data is already up to date!")
end
end
function DataService:SaveData(player) -- Saves players' data.
local tries = 0
local success
repeat
tries = tries + 1
success = pcall(function()
PlayerData:SetAsync("data:"..player.UserId, PlayerSessionData[player])
end)
if not success then
wait(1)
end
until tries == 5 or success
if not success then
warn("Cannot save data for "..player.Name.."!")
else
warn("Data was saved for "..player.Name.."!")
end
end
function DataService:LoadData(player) -- Loads players' data.
local success, currentData = pcall(function()
return PlayerData:GetAsync("data:"..player.UserId)
end)
if success then
local Data = PlayerData:GetAsync("data:"..player.UserId)
PlayerSessionData[player] = Sync2(Data)
else
player:Kick("Data could not load successfully!")
end
end
function DataService:SetupLeaderstats(player)
local Folder = Instance.new("Folder", player)
Folder.Name = "leaderstats"
local Money = Instance.new("IntValue", Folder)
Dribbles.Name = "Money"
Dribbles.Value = PlayerSessionData[player].Currencies.Money
end
function DataService:SyncLeaderstats(player)
local leaderstats = player:WaitForChild("leaderstats")
leaderstats.Money.Value = PlayerSessionData[player].Currencies.Money
end
function DataService:SetupData(player) -- The setup for players' data.
local Data = PlayerData:GetAsync("data:"..player.UserId)
if not Data then -- Creates new data if the player doesn't have it.
PlayerSessionData[player] = Sync2(DataStructure)
self:SetupLeaderstats(player) -- Add physically visible leaderstats.
return print(player.Name .. " has no data!")
end
if Data then
print(player.Name.." has data!")
self:LoadData(player) -- Load data.
wait(0.5) -- Wait extra to wait for data to prevent UpToDate error.
self:UpToDate(player) -- Check for any new additions & etc.
wait(0.5)
self:SetupLeaderstats(player) -- Add physically visible leaderstats.
end
end
return DataService
Script
--// 𝙎𝙀𝙍𝙑𝙀𝙍
-- VARIABLES
local DataService = require(script.Parent.Parent.DataService)
local Players = game:GetService("Players")
local DataStoreService = game:GetService("DataStoreService")
local PlayerData = DataStoreService:GetDataStore("PlayerData")
local RunService = game:GetService("RunService")
-- FUNCTIONS
game.Players.PlayerAdded:Connect(function(player)
DataService:SetupData(player)
end)
game.Players.PlayerRemoving:Connect(function(player)
DataService:SaveData(player)
end)