I am creating a game myself using Profile Service. I wanted to implement global leaderboads into my game, but figured out it’s not so easy as we all expected. When searching the forum I found that I wasn’t the only person with this issue.
Why is it not easy?
When making a leaderboard system, most people use Roblox’ DataStoreService to save data. When creating a leaderboard they just call the Sorted Datastore. Since Profile Service does not support this, that is not an option. Even worse, the API does not have any function to fetch e.g. the best 100 players.
What’s an alternative?
I have discovered a good strategy to tackle this problem. So I will guide you into the right direction.
You will be using MessagingService and will create a SubscribeAsync() function. Then you will create a while loop, with a desired refresh rate. This loop will check how many Coins the lowest player on the board has, if the player has a higher amount, you will create a table with the playerName and how many Coins they have. Then you will PublishAsync() using the topic and Encoded table. In the SubscribeAsync() function you will decode the table. Then you can do the rest of the logic such as adding a tag for the player, calculating which position they actually have etc.
Now you may have noticed when a new server opens, it will put the best player on the board who’s actually playing right now. That is why we create a DataStore that will hold a sorted table with the best players, and update that table after every refresh. When a new server opens, we just call that DataStore and load the leaderboard with the best players.
I would recommend setting a refresh rate between 60 and 300 seconds. To make sure the DataStore does not get overloaded.
If you had the same problem, I hope this post helped you.
local datastoreservice = game:GetService("DataStoreService")
local datastore = datastoreservice:GetDataStore("Test")
local OrderedStore = datastoreservice:GetOrderedDataStore("Ordered")
local LeaderBoard = workspace.LeaderBoard
local Names = LeaderBoard.SurfaceGui.Frame.Names:GetChildren()
local Ranks = LeaderBoard.SurfaceGui.Frame.Ranks:GetChildren()
local Values = LeaderBoard.SurfaceGui.Frame.Values:GetChildren()
local function RemoveTableValues()
table.remove(Names, 1)
table.remove(Ranks, 1)
table.remove(Values, 1)
end
local function CopyData(Key, data)
OrderedStore:SetAsync(Key.KeyName, data)
end
local function AssignRanks(index, KeyInstance)
if Ranks[index] and Ranks[index].ClassName == "TextLabel" then
Ranks[index].Text = index
end
if Names[index] and Names[index].ClassName == "TextLabel" then
Names[index].Text = KeyInstance.key
end
if Values[index] and Values[index].ClassName == "TextLabel" then
Values[index].Text = KeyInstance.value
end
end
RemoveTableValues()
while true do
local Pages = datastore:ListKeysAsync()
local Page = Pages:GetCurrentPage()
for Every, Key in Page do
local success, data = pcall(function()
return datastore:GetAsync(Key.KeyName)
end)
if data and success then
pcall(CopyData(Key, data))
end
end
local OrderedPages = OrderedStore:GetSortedAsync(false, 100)
local OrderedPage = OrderedPages:GetCurrentPage()
for index, KeyInstance in OrderedPage do
AssignRanks(index, KeyInstance)
end
task.wait(60)
end
Profileservice uses datastoreservice, so when you make a profilestore you’re making a datastore. Just switch the datastore name to your profilestore’s name.