How to Wait Until a Profile is Loaded with ProfileService

I’m using some data from ProfileService to decide what accessories the player spawns in with. This means that I need the data ASAP.

I’m running into numerous issues with trying to use the data before it’s loaded in. Below is my attempt at resolving this issue.

game.Players.PlayerAdded:Connect(function(Player)
	game.StarterPlayer.LoadCharacterAppearance = false
	local profile = nil
	Player.CharacterAdded:Connect(function(Character)
		local attempts = 0
		
		while profile == nil do
			profile = Manager.Profiles[Player]
			task.wait(3)
			attempts += 1
			
			if attempts >= 8 then
				Player:Kick("An error loading your data occured. Please try reconnecting!")
				break;
			end
		end
		
		LoadPlayerAccessories(Player)
	end)
end)

This while loop approach is really not an appropriate solution, and is more of a bandaid on the problem. What would be a better way to ensure the data is loaded in before I try to use it?

i dont see anything wrong with the script but, set CharacterAdded as a function and fire it just when the player joins and the CharacterAdded thing

and define the profile variable

game.Players.PlayerAdded:Connect(function(Player)
	game.StarterPlayer.LoadCharacterAppearance = false
	
	local profile = Manager.Profiles[Player]
	local function CharacterAdded(Character)
		local attempts = 0

		while not profile do
			profile = Manager.Profiles[Player]
			task.wait(3)
			attempts += 1

			if attempts >= 8 then
				Player:Kick("An error loading your data occured. Please try reconnecting!")
				break
			end
		end

		LoadPlayerAccessories(Player)
	end
	
	CharacterAdded(Player.Character or Player.ChildAdded:Wait())
	Player.CharacterAdded:Connect(CharacterAdded)
end)
1 Like

I would recommend moving this character added function to your data loading script. Set up your script like this:
Load the data (which will yield until finished), connect the character added, and finally run the character added on the player’s existing character if their character loaded before their data.

Hope I could help!

1 Like

Move everything you want to do to the handler itself. Something like this:

local function PlayerAdded(Player)
	local Profile = ProfileStore:LoadProfileAsync("Player_"..Player.UserId)
	
	if not Profile then
		Player:Kick(DataErrorMessage)
		return
	end
	
	Profile:AddUserId(Player.UserId)
	Profile:Reconcile()

	Profile:ListenToRelease(function()
		Manager.Profiles[Player] = nil
		Player:Kick(DataErrorMessage)
	end)
	
	if Player:IsDescendantOf(Players) then
		Manager.Profiles[Player] = Profile
	else
		Profile:Release()
	end
	
	-- Things to initialize before being ready to play
	FS_Character.OnCharacterAdded(Player) -- this is a modulescript. You can just write a Player.CharacterAdded event directly here if you want.
end

while profile == nil do
profile = Manager.Profiles[Player]
wait(3)
attempts += 1
end

This code isn’t doing what you think it’s doing. It’s not waiting 3 seconds, it’s waiting until profile is nil, then 3 seconds, then it’s waiting until profile is nil, then 3 seconds, then profile is not nil so it exits the loop.
I’m not sure what Manager.Profiles[Player] is, but if it’s an asynchronous function that returns a Promise you should be able to do this:
local profilePromise = Manager.Profiles[Player]
local profile = profilePromise:Await()

If it’s not a Promise then you should make it one.

It’s a serversided dictionary, which holds the data of the current players in the game. The data is session locked to that specific server, until ProfileService has released the profile. Release will happen after data is saved - upon player removal or shutdown of the server.