Hey! For my DataManager script, I added some code to convert the value: score so that it can be processed onto a leaderboard.
Section of script responsible for converting:
function ConvertScoreListToODS()
for order, store in pairs(InfoStore) do
local UserID = store.key
local score = store.Score
ScoreOrd:SetAsync(UserID,score)
end
end
function LoopCSLTO()
while true do
task.wait(12)
ConvertScoreListToODS()
end
end
The entire DataManager script:
local RepStore = game:GetService("ReplicatedStorage")
local SvrStore = game:GetService("ServerStorage")
local DatStore = game:GetService("DataStoreService")
local Players = game:GetService("Players")
local PlayerDataFolder = RepStore.PlayerData
local InfoStore = DatStore:GetDataStore("PlayerData")
local ScoreOrd = DatStore:GetOrderedDataStore("OrderedPlayerScore")
local Incall = game.ServerScriptService.DataManager.InCall
function UnloadPlayerData(PlayerID)
local success, err = pcall(function()
local PlayerData = InfoStore:GetAsync(PlayerID)
if not PlayerData.Level and PlayerData.Score then
warn("data empty")
PlayerData = {}
PlayerData.Level = 0
PlayerData.Score = 0
end
local PlayerFolder = Instance.new("Folder")
PlayerFolder.Name = PlayerID
PlayerFolder.Parent = PlayerDataFolder
for store, data in pairs(PlayerData) do
local IntHolder = Instance.new("IntValue")
IntHolder.Name = store
IntHolder.Value = data
IntHolder.Parent = PlayerFolder
end
end)
if not success then warn(err) end
end
function PackPlayerData(PlayerID)
local PlayerFolder = PlayerDataFolder:FindFirstChild(PlayerID)
local success, err = pcall(function()
local PlayerData = {}
for i, v in pairs(PlayerFolder:GetChildren()) do
PlayerData[v.Name] = v.Value
end
InfoStore:SetAsync(PlayerID,PlayerData)
end)
if success then
PlayerFolder:Destroy()
else
warn(err)
end
end
function TranslateCall(callData)
for i, v in pairs(callData) do
local suc, err = pcall(function()
local PlrId = v.PlrId
local Ttype = v.Type
local value = v.Value
local LPlrFol = PlayerDataFolder[PlrId]
local SVal = LPlrFol[Ttype]
SVal.Value = SVal.Value + value
end)
if not suc then warn(err) end
end
end
function ConvertScoreListToODS()
for order, store in pairs(InfoStore) do
local UserID = store.key
local score = store.Score
ScoreOrd:SetAsync(UserID,score)
end
end
function LoopCSLTO()
while true do
task.wait(12)
ConvertScoreListToODS()
end
end
LoopCSLTO()
Players.PlayerAdded:Connect(UnloadPlayerData)
Players.PlayerRemoving:Connect(PackPlayerData)
Incall.Event:Connect(TranslateCall)
You are attempting to iterate through a DataStore instance here;
function ConvertScoreListToODS()
for order, store in pairs(InfoStore) do --> InfoStore
local UserID = store.key
local score = store.Score
ScoreOrd:SetAsync(UserID,score)
end
end
When you can only do this type of iteration with a table. I think a different way you can do this instead is by saving score data for people in the server every x amount of seconds and have it save to the Ordered Data Store.
function ConvertScoreListToODS()
for order, plr in pairs(Players:GetPlayers()) do
local PlayerData = InfoStore:GetAsync(plr.UserId)
if PlayerData then
local score = PlayerData.Score
ScoreOrd:SetAsync(plr.UserId,score)
end
end
end
This I’d only recommend to do maybe every 30 seconds to 1 minute though, they could also leave in between these intervals and their data might not be saved to the ordered data store. I usually combat this by also attempting to save to the ODS when they leave as well. Be cautious with how frequent the DataStore tries to load or save data because it could cause players to lose data entirely.
well, since my game hasn’t been released yet, I am storing the player score data to the score OrderedDataScore when the player leaves and the rest of their data is saved.
The function I provided should work then, considering there is no true way to get every datastore and all individual data; if it did it’d be really unhealthy for the server.
I’m pretty sure there isn’t. You can always look at whatever is inside of the pcall scope and figure out what line it is based off of the error message.
function UnloadPlayerData(PlayerID)
local success, err = pcall(function()
local PlayerData = InfoStore:GetAsync(PlayerID)
if not PlayerData then
warn("data empty")
PlayerData = {}
PlayerData.Level = 0
PlayerData.Score = 0
end
if not PlayerData.Level or PlayerData.Score then
PlayerData.Level = 0
PlayerData.Score = 0
end
local PlayerFolder = Instance.new("Folder")
PlayerFolder.Name = PlayerID
PlayerFolder.Parent = PlayerDataFolder
for store, data in pairs(PlayerData) do
local IntHolder = Instance.new("IntValue")
IntHolder.Name = store
IntHolder.Value = data
IntHolder.Parent = PlayerFolder
end
end)
if not success then warn(err) end
end
Oh yeah, completely disregard what I said about that. The problem would be at line 29. ‘PlayerID’ must be the player instance instead of the actual userId because that’s the first paramater of PlayerRemoving. Try PlayerID.UserId instead.
function UnloadPlayerData(PlayerID)
PlayerID = PlayerID.UserId
local success, err = pcall(function()
local PlayerData = InfoStore:GetAsync(PlayerID)
if not PlayerData then
warn("data empty")
PlayerData = {}
PlayerData.Level = 0
PlayerData.Score = 0
end
if not PlayerData.Level or PlayerData.Score then
PlayerData.Level = 0
PlayerData.Score = 0
end
local PlayerFolder = Instance.new("Folder")
PlayerFolder.Name = PlayerID
PlayerFolder.Parent = PlayerDataFolder
for store, data in pairs(PlayerData) do
local IntHolder = Instance.new("IntValue")
IntHolder.Name = store
IntHolder.Value = data
IntHolder.Parent = PlayerFolder
end
end)
if not success then warn(err) end
end