Level in ProfileStore is overwriting/saving as nan everytime

I created a post on how to prevent overwritten data to prevent data regression. I learned that the way to do this was session locking, in which I found ProfileService was my best option(even though I had previously used ProfileService and had the same error I’m having now).

Leveling Module
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Players = game:GetService("Players")

local Data = require(script.Parent.PlayerDataHandler)
local Remotes = ReplicatedStorage.Remotes
local Bindables = ReplicatedStorage.Bindables

local Leveling = {}

Bindables.OnServer.Event:Connect(function(signal,player,amount)
	if signal == "Gain" then
		player:SetAttribute("Round_XP",player:GetAttribute("Round_XP") + amount)
		
		Data:Update(player,"Experience",function(past)
			return past + amount
		end)
		local xp = Data:Get(player,"Experience")
		local level = Data:Get(player,"Level")
		local progress = xp / (300 * level)
		if progress >= 1 then
			Data:Update(player,"Experience",function(past)
				return past - (300 * level)
			end)
			Data:Update(player,"Level",function(past)
				return past + 1
			end)
			progress = Data:Get(player,"Experience") / (300 * Data:Get(player,"Level"))
		end
	elseif signal == "UI" then
		for _,player in Players:GetPlayers() do
			if player:GetAttribute("Enabled") == false then return end

			local level = Data:Get(player,"Level")
			local experience = Data:Get(player,"Experience")
			
			print(level)
			Remotes.ToClient:FireClient(player,"LoadXP",experience,level,player:GetAttribute("Round_XP"))
			player:SetAttribute("Round_XP",nil)
		end
	end
end)

return Leveling

ProfileDataHandler
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Assets = ReplicatedStorage.Assets

local EmotesList = require(script.EmotesList)
local Leaderboards = require(script.Leaderboards)

local function create_abilities()
	local tab_ = {}
	for _,ability in Assets.Shop:GetChildren() do
		if not ability:IsA("ModuleScript") then
			tab_[ability.Name] = {false,0}
		end
	end
	return tab_
end

local function create_emotes()
	local tab_ = {}
	for emote,value in EmotesList do
		tab_[emote] = value
	end 
	return tab_
end

local PlayerDataHandler = {}

function PlayerDataHandler:Leaderstats(player)
	local folder = Instance.new("Folder")
	folder.Name = "leaderstats"
	local wins = Instance.new("IntValue")
	wins.Name = "Wins"
	wins.Value = self:Get(player,"Wins")
	local kills = Instance.new("IntValue")
	kills.Name = "Kills"
	kills.Value = self:Get(player,"Kills")
	local money = Instance.new("IntValue")
	money.Name = "Money"

	money.Changed:Connect(function(value)
		self:Set(player,"Money",value)
	end)

	money.Parent = player
	wins.Parent = folder
	kills.Parent = folder
	folder.Parent = player
end

local dataTemplate = {
	Money = 0,
	Wins = 0,
	Equipped = "",
	Kills = 0,
	Abilities = create_abilities(),
	
	Level = 1,
	Experience = 0,
	
	Emotes = create_emotes(),
	EmoteProgress = 2,
	
	Gamepasses = {
		["DoubleEmotes"] = false
	}
}
local ProfileService = require(script.Parent.ProfileService)
local Players = game:GetService("Players")
local ProfileStore = ProfileService.GetProfileStore(
	"PlayerProfile",
	dataTemplate
)

local Profiles = {}

local function playerAdded(player)
	local profile = ProfileStore:LoadProfileAsync("Player_"..player.UserId)
	if profile then
		profile:AddUserId(player.UserId)
		profile:Reconcile()
		
		profile:ListenToRelease(function()
			Profiles[player] = nil
			player:Kick()
		end)
		
		if not player:IsDescendantOf(Players) then
			profile:Release()
		else
			Profiles[player] = profile
			PlayerDataHandler:Leaderstats(player)
		end
	else
		player:Kick()
	end
	task.spawn(function()
		while true do
			Leaderboards:Set(player,"Kills",PlayerDataHandler:Get(player,"Kills"))
			Leaderboards:Set(player,"Wins",PlayerDataHandler:Get(player,"Wins"))
			task.wait(50)
		end
	end)
	print(PlayerDataHandler:Get(player,"Level"))

end

function PlayerDataHandler:Init()
	for _,player in Players:GetPlayers() do
		task.spawn(playerAdded,player)
	end
	Players.PlayerAdded:Connect(playerAdded)

	Players.PlayerRemoving:Connect(function(player)
		if Profiles[player] then
			Profiles[player]:Release()
		end
	end)
	task.spawn(function()
		while true do
			Leaderboards:Refresh("Kills")
			Leaderboards:Refresh("Wins")
			task.wait(50)
		end
	end)
end

local function getProfile(player)
	assert(Profiles[player],string.format("Profile does not exist for %s",player.UserId))
	return Profiles[player]
end

function PlayerDataHandler:Get(player,key)
	local profile = getProfile(player)
	assert(profile.Data[key],string.format("Data does not exist for key: %s",key))
	return profile.Data[key]
end

function PlayerDataHandler:Set(player,key,value)
	local profile = getProfile(player)
	assert(profile.Data[key],string.format("Data does not exist for key: %s",key))
	assert(type(profile.Data[key]) == type(value))
	profile.Data[key] = value
end

function PlayerDataHandler:Update(player,key,callback)
	local profile = getProfile(player)
	local oldData = self:Get(player,key)
	local newData = callback(oldData)
	self:Set(player,key,newData)
end

return PlayerDataHandler

Both of these scripts I think are valid and I got the ProfileDataHandler from this video.

I don’t understand why I am getting nan despite the intialization for the dataTemplate key “Level” being 1(cannot be nan, only 0/0, and level only adds += 1). I also don’t understand how this would be happening if profileservice is handling the sessionlocking for me.

I assume though that this is happening because of a previous error I had when creating levels, and I did create a ProfileServiceHandler just like this one for my game in the past.

Any ideas?

When I play a Local server test of 1 player, the leveling system works perfectly. Have any ideas on how I could fix this for specificially my player’s level key in ProfileService? I don’t want to live with nan as my level on my main account :skull:.

For now I’ll keep this as solution, because data-saving, leveling, and I’m sure for the future session-locking will work.

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