Global Leaderboards using Profile Service

Hello readers

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.

3 Likes

No need, here’s a script for leaderboard I have:

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.

4 Likes

Oh, you are right, that indeed is obvious, I don’t think I did a bad job on my system tho :smiley:

1 Like

Yeah it was good, i’m just saying that you could’ve done this instead. Much easier.

1 Like

You know SortedMaps are a thing in MemoryStoreService, right?

Every entry can represent a player’s progress, but more importantly it can also have a sorting order.

It also has automatic expiry, meaning a player could fall off the leaderboards if their stats haven’t changed for a while.

It’s like this was designed just for leaderboards.

It has more forgiving limits than MessagingService and definitely Ordered Datastores too.

1 Like