ProfileService Data loading issue

so basically, I’m making an obby game. Mainly the issue is when you spawn in, it’ll not load the data in time it seems , and with that issue, comes the issue of randomly spawning the character in a different place in the obby periodically e.g here’s the script

Players.PlayerAdded:Connect(function(player)
    player.CharacterAdded:Connect(function()
        task.wait()
        local Data = DataService:GetPlayerData(player)

        if Data then
            print("no lols")
            player.RespawnLocation = workspace.Checkpoints[Data.Levels]

        elseif not Data then
            print("lols")
            player.RespawnLocation = workspace.Checkpoints["0"]


        end
        Players.RespawnTime = 0.1
    end)

end)

Here’s the issue in video format


Also, it indeed did print “lol”

Now, I want to list some things I believe might also be the issue, but my brain has yet to come up with a solution with-

The main issue seems to be that the script in the module is running slower than the one in the server (this is an assumption). So, it never does what it needs to do in time which makes the data load slower and, boom the server runs without allowing the module script to work before it. (edited)

1 Like

One way in which I have synched server to client is by getting the server to create an object in RS and a waitforchild using its name in the client.

1 Like

I think this boils down to trying to set the respawn location using the character added event. Surely you need to set the respawn location before the character is loaded so using character added is too late.

You could simply set the respawn location in the player added event and then update the respawn location whenever the data changes rather than waiting for the character event.

2 Likes

The difference now is that I keep getting set to the first spawn point (which was the goal if you didn’t have any data, so it’s a step forward), but the issue still stands in which the character does have data, but I believe the module script is moving slower than the server script, and I don’t really know how to delay it until the data is loaded.

1 Like

If you want ultimate control of the respawn mechanics then you can turn Players.CharacterAutoLoads to false. You would then need to call Player:LoadCharacter() for any spawning behaviour to happen but this would allow you to wait for whatever you want before a player spawns / respawns.

There is also the situation where the character loads before the player added event finishes running (not sure if this is possible but lets assume it is). In this case you would need to use SetPrimaryPartCFrame when the player first joins the server.

The main issue still stands, the data seems to be loading/working slower than the server script. I’ll show you the module script, but at this point I sincerely don’t know what to do, or if I have to make a retry function (which I don’t know how to do, but I’ll attempt it).

local ServerStorage = game:GetService("ServerStorage")
local Players = game:GetService("Players")
local ProfileService = require(ServerStorage:WaitForChild("Modules"):FindFirstChild("ProfileService"))


local ProfileTemplate = {
	Levels = 0,
	Deaths = 0,
}


local GameProfileStore = ProfileService.GetProfileStore("Player", ProfileTemplate)

local Profiles = {} -- All player profiles that are stored.
local function onPlayerAdded(player)
	local ProfileStore = GameProfileStore:LoadProfileAsync(
		"Player_" .. player.UserId,
		"ForceLoad"
	)
	
	if ProfileStore then
		
		ProfileStore:ListenToRelease(function()
			Profiles[player] = nil
			player:Kick("How are you still in game?")
		end)
		
		if player:IsDescendantOf(Players) then
			Profiles[player] = ProfileStore
		else
			ProfileStore:Release()
		end
	else
		player:Kick()
	end
end


local function OnPlayerRemoving(player)
	local Profile = Profiles[player]
	if Profile then
		Profile:Release()
	end
end


game.Players.PlayerAdded:Connect(function(player)
	onPlayerAdded(player)
end)
game.Players.PlayerRemoving:Connect(function(player)
	OnPlayerRemoving(player)
end)

The system would work like this:

Use DataService to keep track of the player’s checkpoint.

Update checkpoint via DataService when the player touches the next checkpoint.

Control spawning using player:LoadCharacter(). Set respawn point / use CFrame manipulation to spawn the character where you want.

Have you tried any of the suggested ideas already?

I tried it on the server, not knowing this whole time it was meant to be used on DataManager. I’ll see if it fixes itself if I do it on the module.

I attempted these suggestions,
now giving me errors
image

local function onPlayerAdded(player)
	Players.CharacterAutoLoads = false
	local ProfileStore = GameProfileStore:LoadProfileAsync(
		"Player_" .. player.UserId,
		"ForceLoad"
	)
	
	if ProfileStore then
		
		player.RespawnLocation = workspace.Checkpoints[Profiles[player].Data.Levels]
		player:LoadCharacter()
		ProfileStore:ListenToRelease(function()
			Profiles[player] = nil
			player:Kick("How are you still in game?")
		end)
		
		if player:IsDescendantOf(Players) then
			Profiles[player] = ProfileStore
		else
			ProfileStore:Release()
		end
	else
		player:Kick()
	end
end


local function OnPlayerRemoving(player)
	local Profile = Profiles[player]
	if Profile then
		Profile:Release()
	end
end



game.Players.PlayerAdded:Connect(function(player)
	onPlayerAdded(player)
end)
game.Players.PlayerRemoving:Connect(function(player)
	OnPlayerRemoving(player)
end)

for _, Checkpoints in pairs(workspace.Checkpoints:GetChildren()) do



	Checkpoints.Touched:Connect(function(Hit)
		if Hit and Hit.Parent:FindFirstChild("Humanoid") then
			
			local player = Players:GetPlayerFromCharacter(Hit.Parent)



			

			player.RespawnLocation = Checkpoints.Parent[Profiles[player].Data.Levels]

			if tonumber(Checkpoints.Name) == Profiles[player].Data.Levels + 1 then
				print(Profiles[player].Data.Levels)

				Profiles[player].Data.Levels  += 1	
			end
		end
	end)	
end

It’s just getting confusing. I understand what you want me to do, but it’s not working out for me.

You seem to be doing things in the wrong order that’s why you get this error. You need to initialise the profile cache (Profiles[player] = ProfileStore) before you try reading from it to set the respawn location.

I’ve written in some tweaks that I think should fix things.

Code Tweaks
local RESPAWN_TIME = 10

local GameProfileStore -- add reference here

local Profiles = {}

game.Players.CharacterAutoLoads = false

local function spawnPlayer(player)
	local Profile = Profiles[player]
	
	if not Profile then
		warn("No profile for player", player)
		return
	end
	
	player.RespawnLocation = workspace.Checkpoints[Profile.Data.Levels]
	player:LoadCharacter()
end

local function onCharacterAdded(player, character)
	local humanoid = character:WaitForChild("Humanoid")
	humanoid.Died:Connect(function()
		wait(RESPAWN_TIME)
		spawnPlayer(player)
	end)
end

local function onPlayerAdded(player)
	
	local Profile = GameProfileStore:LoadProfileAsync(
		"Player_" .. player.UserId,
		"ForceLoad"
	)

	if not Profile then
		player:Kick()
	end

	Profile:ListenToRelease(function()
		Profiles[player] = nil
		player:Kick("Profile released...")
	end)

	if player:IsDescendantOf(game.Players) then
		Profiles[player] = Profile
	else
		Profile:Release()
	end
	
	player.CharacterAdded:Connect(function(character)
		onCharacterAdded(player, character)
	end)
	if player.Character then
		onCharacterAdded(player, player.Character)
	end
	
	spawnPlayer(player)
end


local function OnPlayerRemoving(player)
	local Profile = Profiles[player]
	if Profile then
		Profile:Release()
	end
end

game.Players.PlayerAdded:Connect(function(player)
	onPlayerAdded(player)
end)
for _, player in game.Players:GetPlayers() do
	onPlayerAdded(player)
end

game.Players.PlayerRemoving:Connect(function(player)
	OnPlayerRemoving(player)
end)

for _, Checkpoints in pairs(workspace.Checkpoints:GetChildren()) do
	Checkpoints.Touched:Connect(function(Hit)
		if Hit and Hit.Parent:FindFirstChild("Humanoid") then

			local player = game.Players:GetPlayerFromCharacter(Hit.Parent)
			
			if not player then
				return
			end
			
			local Profile = Profiles[player]

			player.RespawnLocation = Checkpoints.Parent[Profile .Data.Levels]

			if tonumber(Checkpoints.Name) == Profile.Data.Levels + 1 then
				print(Profile.Data.Levels)

			Profile.Data.Levels  += 1	
			end
		end
	end)	
end

2 Likes