Loading All User Data saved through Profile Service

Hello, I am creating a game where you can place a gravestone and once you do it stays there forever. (saved in the players datastore through their UserID as a key using profile service). I don’t know how I would load all of the gravestones when a new server is created and without the player who own a gravestone in that said server.

Here is my code for saving if it helps at all

if Profile.Data["HasGrave"] == false then
		local RandomPosition = GetRandomLocation(RegionPart).Position
		local Success, Grave = PlaceGrave(RandomPosition)
		
		if Success and Grave then -- Nothing blocking the grave
			local Time = os.date("*t")
			print("Placed grave!")
			
			Profile.Data["HasGrave"] = true
			Profile.Data["JoinDate"] = {
				Month = Time.month;
				Day = Time.day;
				Year = Time.year
			}
			Profile.Data["GraveLocation"] = { -- Compress the data
				X = math.round(RandomPosition.X / 0.001) * 0.001;
				Y = math.round(RandomPosition.Y / 0.001) * 0.001;
				Z = math.round(RandomPosition.Z / 0.001) * 0.001
			}
		end
	else
		print("Player already has a grave!")
	end
2 Likes

I don’t believe it’s possible to retrieve an offline player’s data with ProfileService, I may be wrong and this tutorial may cover it:
Global Updates: ProfileService Tutorial Part 2 (Roblox Studio) (youtube.com)

As an alternative you’re better off using DataStores.

1 Like

But how do other games do it like The Graveyard [HEAVEN] - Roblox

1 Like

It is possible, there’s nothing in the way ProfileService grabs data that requires it to be tied to a Player currently in game.

https://madstudioroblox.github.io/ProfileService/api/#profilestoreloadprofileasync

@Cronoaix

Doing something like this is a bit tricky to do coherently with ProfileService, because of session-locking. If all you are doing is just building a graveyard from all the players in the server - that’s simple. Once you’ve loaded the data, just generate the gravestone from whatever information you’ve saved.

If you are creating a graveyard from every player that has ever played your game - this is more difficult and requires a thoughtful construction. It’s not great to save the data to all the players and then retrieve it, because ProfileService will error if you try to load a Profile that has not been released. This will happen if the player is in another server, because session-locking.

Okay, so what about saving all of the data to the server? Ex: :LoadProfileAsync("GlobalServerData", ...? You will run into the same session-locking issues here. If one server (presumably the first server) loads the server data, then other subsequent servers will not be able to load the data, because session-locking.

Two recommended solutions:

  1. Use regular datastores for this. You won’t have to worry about session locking because it’s not applicable here. This would be your simplest approach.
  2. Avoid session-lock constraints by loading the server data on only one server and communicating server data to all other servers via MessagingService. This is very tricky to implement properly, because you need to handle a bunch of edge cases. I would not recommend doing this unless the way you handle data is very much wrapped up in ProfileService and it would be a major pain to disentangle it all. If you would like to chat about this method, feel free to DM me. Contrary to my own advice, I have taken this approach in the past.

A third outside the box solution

  • MemoryStores. You won’t have every player ever who has played the game, but this might be attractive. Displaying every single player’s gravestone is probably not sustainable at scale, so this might be exactly what you are looking for.
1 Like

Figured it out using regular datastore, I would just have to set up a rate limiting system because as the datastore increases in size the limits would become more likely to be reached

local function LoadGraves()
	local success, pages = pcall(function()
		return Datastore:ListKeysAsync()
	end)

	if success then
		while true do
			for _, key in pages:GetCurrentPage() do
				local success, value = pcall(function()
					return Datastore:GetAsync(key.KeyName)
				end)
				if success then
					print("Key:", key, "Value:", value)
				else
					warn("Failed to get value for key:", key)
				end
			end
			if pages.IsFinished then
				break
			end
			pages:AdvanceToNextPageAsync()
		end
	else
		warn("Failed to list keys in DataStore")
	end
end
1 Like

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.