I released a game about a week ago and when I released the game I thought the global leaderboards were working fine until I soon realized that all the values were the same across each leaderboard. I’ve been looking up how to make multiple leaderboards and I keep hearing that each stat needs to be stored in its own key because of how OrderedDataStores work. The problem is, I think this would reset the data of the players that have already played my game. Any good solution to fix this?
Here’s the DataStore script:
local DS = game:GetService("DataStoreService")
local DSName = DS:GetDataStore("cannonDataStore05")
local leaderStatDS = DS:GetDataStore("cannonLeaderstats05")
local cannonUtils = require(script.Parent.cannonUtils)
function convertTableToInstance(container, tbl)--loads in datastore values
for name, data in pairs(tbl) do
local inst = Instance.new(data["ClassName"])
inst.Name = name
if data["ClassName"] ~= "Folder" then
inst.Value = data["Value"]
end
inst.Parent = container
convertTableToInstance(inst, data["Children"])
end
end
game.Players.PlayerAdded:Connect(function(player) --initiates loading
local plrdafold = Instance.new("Folder", player)--main folder for storing all values
plrdafold.Name = "playerData"
local leaderstats = Instance.new("Folder", player)--main folder for storing all values
leaderstats.Name = "leaderstats"
local moneyDS = leaderStatDS:GetAsync(player.UserId)
local plrdata = DSName:GetAsync(player.UserId)--gets the datastore
if plrdata == nil or moneyDS == nil then--if this is a new player
print("New Player - Creating Data")
local folder
local money = Instance.new("NumberValue")
money.Name = "Coins"
money.Value = 0
money.Parent = leaderstats
local rebirth = Instance.new("IntValue")
rebirth.Name = "Rebirths"
rebirth.Value = 0
rebirth.Parent = leaderstats
local score = Instance.new("IntValue")
score.Name = "Highscore"
score.Value = 0
score.Parent = leaderstats
local AO = Instance.new("StringValue")
AO.Name = "EquippedCannon"
AO.Value = "Basic"
AO.Parent = plrdafold
local AO = Instance.new("StringValue")
AO.Name = "EquippedTrail"
AO.Value = ""
AO.Parent = plrdafold
local A1 = Instance.new("IntValue")
A1.Name = "CannonPower"
A1.Value = 150
A1.Parent = plrdafold
local A3 = Instance.new("IntValue")
A3.Name = "Multiplier"
A3.Value = 1
A3.Parent = plrdafold
local A2 = Instance.new("Folder")
A2.Name = "Inventory"
A2.Parent = plrdafold
local A3 = Instance.new("Folder")
A3.Name = "Trails"
A3.Parent = plrdafold
cannonUtils.giveCannon(player, "Basic") --gives the default cannon
else --If this is a returning player
print("Returning Player - Loading Data")
print(plrdata)
print(moneyDS)
convertTableToInstance(plrdafold, plrdata)--starts loading in data
convertTableToInstance(leaderstats, moneyDS)
end
end)
function convertInstanceToTable(folder) --uploads all of the values into the datastore
local tbl = {}
for i, inst in pairs(folder:GetChildren()) do
if inst.ClassName == "Folder" then
tbl[inst.Name] = {["ClassName"] = "Folder", ["Children"] = convertInstanceToTable(inst)}
else
tbl[inst.Name] = {["ClassName"] = inst.ClassName, ["Value"] = inst.Value, ["Children"] = convertInstanceToTable(inst)}
end
end
return tbl
end
game.Players.PlayerRemoving:Connect(function(player)--when the player leaves
local dataTbl = convertInstanceToTable(player.playerData)
local dataTbl2 = convertInstanceToTable(player.leaderstats)
print(dataTbl)
print(dataTbl2)
DSName:SetAsync(player.UserId, dataTbl)
leaderStatDS:SetAsync(player.UserId, dataTbl2)
end)
game:BindToClose(function() --when the game shuts down
for i, player in pairs(game.Players:GetPlayers())do --gets the player list
if player then --if the player exists
player:kick("The game is shutting down, please rejoin later") --kick message
end
end
wait(4) --wait to make sure the data saves
end)
And here is the script I use for the global leaderboards (I just duplicate this script and change the StatsName for each leaderboard)
local StatsName = "Coins" -- Your stats name
local MaxItems = 20 -- Max number of items to be displayed on the leaderboard
local MinValueDisplay = 1 -- Any numbers lower than this will be excluded
local MaxValueDisplay = 1000000000e1000000 -- (10 ^ 15) Any numbers higher than this will be excluded
local UpdateEvery = 60 -- (in seconds) How often the leaderboard has to update
local suffixes = {"K", "M", "B", "T", "Qd"} -- numbers don't go higher than 'Q' in Lua.
local function toSuffixString(n)
if n <= 0 then
return 0
else
local i = math.floor(math.log(n, 1e3))
local v = math.pow(10, i * 3)
return ("%.1f"):format(n / v):gsub("%.?0+$", "") .. (suffixes[i] or "")
end
end
local DataStoreService = game:GetService("DataStoreService")
local DataStore = DataStoreService:GetOrderedDataStore("cannonLeaderstats05") --CoinsDataStore
local SurfaceGui = script.Parent
local Sample = script.Sample
local List = SurfaceGui.TopBar
local ItemsFrame = SurfaceGui.ScrollingFrame
local function GetItems()
local Data = DataStore:GetSortedAsync(false, MaxItems, MinValueDisplay, MaxValueDisplay)
local TopPage = Data:GetCurrentPage()
--ItemsFrame.Nothing.Visible = #TopPage == 0 and true or false
for i, v in ipairs(TopPage) do
local UserId = v.key
local Value = v.value
local Username = "[Not Available]"
local Color = Color3.fromRGB(38, 50, 56)
local Success, Error = pcall(function()
Username = game.Players:GetNameFromUserIdAsync(UserId)
end)
if i == 1 then
Color = Color3.fromRGB(255, 215, 0)
elseif i == 2 then
Color = Color3.fromRGB(192, 192, 192)
elseif i == 3 then
Color = Color3.fromRGB(205, 127, 50)
end
local image = game.Players:GetUserThumbnailAsync(UserId, Enum.ThumbnailType.HeadShot, Enum.ThumbnailSize.Size150x150)
local Item = Sample:Clone()
Item.Name = Username
Item.LayoutOrder = i
Item.Image.Image = image
Item.Image.Place.TextColor3 = Color
Item.Image.Place.Text = i
Item.PName.Text = Username
Item.PName.TextColor3 = Color
Item.Value.Text = toSuffixString(Value)
Item.Parent = ItemsFrame
end
end
while true do
for i, v in pairs(game.Players:GetPlayers()) do
local lstats = v.leaderstats:WaitForChild(StatsName).Value
if lstats then
pcall(function()
DataStore:UpdateAsync(v.UserId, function(Value)
return tonumber(lstats)
end)
end)
end
end
for i, v in pairs(ItemsFrame:GetChildren()) do
if v:IsA("Frame") then
v:Destroy()
end
end
GetItems()
wait()
--List.Value.Text = StatsName
--List.CanvasSize = UDim2.new(0, 0, 0, ItemsFrame.UIListLayout.AbsoluteContentSize.Y + 35)
wait(UpdateEvery)
end
Thanks for any help