Issue with getting data on PlayerAdded

Leaderboard System

Summary

I am working with a leaderboard system and each time a player joins, the PlayerAdded event fires, resulting in a function that is located in this script

Code

local PlayerData = require(game.ServerScriptService.Data["Player Data"])

game.Players.PlayerAdded:Connect(function(Player: Player)
	print("Test")
	local Data = PlayerData.GetData(Player)
	print("Test2")
	--Value Insert
	local Leaderstats = Instance.new("Folder")
	Leaderstats.Name = "leaderstats"
	Leaderstats.Parent = Player
	
	local Cash = Instance.new("NumberValue")
	Cash.Name = "Cash"
	Cash.Parent = Leaderstats
	Cash.Value = Data.Currencies.Cash
end)

Breaking it down

Let me break down what my script does (Not the PlayerAdding, the Value inserting and the print functions):

local PlayerData = require(game.ServerScriptService.Data.ProfileStore)

The PlayerData variable requires a module script that essentially acts as a Loading and Saving script based on the ProfileStore library (Not ProfileService (It is a different module, please don’t mistake it)). Here is the official script to see what I mean

Here is the script to understand better
local RunService = game:GetService("RunService")

local PlayerDatatemplate = require(game.ReplicatedStorage.Data["Player Data"])
local ProfileStore = require(game.ServerScriptService.Librairies.ProfileStore)

local DataStoreKey = "Testing1"
local PlayerStore = ProfileStore.New(DataStoreKey, PlayerDatatemplate.PlayerDefaultData)

local Profiles: {[Player]: typeof(PlayerStore:StartSessionAsync())} = {}

local Local = {}
local Shared = {}

function Local.OnStart()
	for _, Player in game.Players:GetPlayers() do
		task.spawn(Local.LoadProfile, Player)
	end
	game.Players.PlayerAdded:Connect(Local.LoadProfile)
	game.Players.PlayerRemoving:Connect(Local.RemoveProfile)
end

function Local.LoadProfile(Player: Player)
	local Profile = PlayerStore:StartSessionAsync(`{Player.UserId}`, {
		Cancel = function()
			return Player.Parent ~= game.Players
		end,
	})
	
	if Profile == nil then
		return Player:Kick("Data not loaded")
	end
	
	Profile:AddUserId(Player.UserId)
	Profile:Reconcile()
	
	Profile.OnSessionEnd:Connect(function()
		Profiles[Player] = nil
		Player:Kick()
	end)
	
	local isInGame = Player.Parent == game.Players
	if isInGame then
		Profiles[Player] = Profile
	else
		Profile:EndSession()
	end
end

function Local.RemoveProfile(Player: Player)
	local Profile = Profiles[Player]
	if Profile ~= nil then
		Profile:EndSession()
	end
end

function Shared.GetData(Player: Player): PlayerDatatemplate.PlayerData
	local Profile = Profiles[Player]
	if not Profile then repeat task.wait() until Profile ~= nil end
	
	return Profile.Data
end

Local.OnStart()

return Shared

local Data = PlayerData.GetData(Player)

This line calls a function in the script mentioned earlier which is the following

function Shared.GetData(Player: Player): PlayerDatatemplate.PlayerData
	local Profile = Profiles[Player]
	if not Profile then repeat task.wait() until Profile ~= nil end
	
	return Profile.Data
end

The function gets the profile of the DataStore and it’s data, then it repeats task.wait() till Profile.Data is not empty.

Note: Profile.Data is a table
Note2: If you don’t know what Profiles are, then read the ProfileStore Documentation

Issue

For some reason, the Data variable in the leaderboard script, acts like a literal breakpoint. I added two print() functions, one printing “Hi” which is before the variable, and the other printing “Hi2”, which is after the variable. Only “Hi” gets printed, and everything after the variable is not ran. Sadly I can’t print the Data table since anything after it won’t be executed.

1 Like

Try adding prints in your uh data fetching module after every line to see where it actually stops.

It’s probably this line though

1 Like

The problem is probably that the GetData function is yielding forever from the line above.

It’s probably not good to wait like this anyways: what if there is an error when loading? It will just wait forever in that case too.

This is probably a problem in how you’re using ProfileStore causing the data to never load, though I don’t keep up on the specifics of that module.

1 Like

you check if Profile ~= nil but then Profile.Data could still be nil

function Shared.GetData(Player: Player): PlayerDatatemplate.PlayerData
	local Profile = Profiles[Player]

    if not Profile and not Profile.Data then
	    repeat task.wait() until Profile and Profile.Data
    end
	
	return Profile.Data
end

this updated code should work as it checks for both Profile and Profile.Data!

Note: if you need client replication of the profile data you should really look into Replica (it’s also made by loleris)

1 Like

Sorry, but it is not really working, it cannot index my data and it does not wait for the data not to be nil. I tried or instead of and, but came back to square one.

I am calling the function in another script (not on PlayerAdded), and works flawlessly!

The require is most likely taking longer than the player takes to join. So by the time the event starts the player is already added.

Define the module as nil and inside of the player added check if the module is nil and if it is then require it.

So like how do I define the model as nil? Also, doesn’t the function do the job, by waiting for the PlayerData to be added to the profile?

Here is my previous reply (I don’t want to post the same thing, so that it isn’t marked as spam):

1 Like

Oh, the problem is a common coding error. The Profile variable is never updated:

This means that if Profiles[Player] is nil when Profile is set, it will always be nil because it’s never updated.

To fix this, you need to do:

function Shared.GetData(Player: Player): PlayerDatatemplate.PlayerData
	local Profile = Profiles[Player]
	if not Profile then repeat
		Profile = Profiles[Player]
		task.wait()
	until Profile ~= nil end
	
	return Profile.Data
end

instead.

3 Likes

Thank you so much! This is exactly the solution!

1 Like