Issues saving data with ProfileService?

I’ve decided to migrate an upcoming game from Roblox’s Datastore to ProfileService. However, now it doesn’t want to save any of my data. It’s quite annoying, as I have tried various methods to get it up and running, to no avail. Is there something I am doing wrong? Something that needs to be tweaked to get it to save data? API Services are enabled and there are no errors:

Code

local ServerScriptService = game:GetService("ServerScriptService")
local ProfileService = require(ServerScriptService.ProfileService)
local PlayersService = game:GetService("Players")
local profileTemplate = {
	["SpleefCoins"] = 0,
	["WinTokens"] = 0,
	["Level"] = 1,
	["Rank"] = "Newbie",
	["Effect"] = "White",
	["Trail"] = "White",
	["XP"] = 0,
	["MaxXP"] = 30,
	["TrailBuff"] = 1,
	["EffectBuff"] = 1,
	["DonateTokens"] = 0,
	["Wins"] = 0
}
local Profiles = {}

local GameProfileStore = ProfileService.GetProfileStore(
	"PlayerData",
	profileTemplate
)

local function InstanceValues(Player)
	for name, Value in pairs(profileTemplate) do
		if name ~= "Wins" then
			if typeof(Value) == "number" then
				local NewValue = Instance.new("NumberValue")
				NewValue.Name = name
				NewValue.Parent = Player
				NewValue.Value = Value
				NewValue.Changed:Connect(function()
					Profiles[Player][name] = Value
				end)
			else
				local NewValue = Instance.new("StringValue")
				NewValue.Value = Value
				NewValue.Parent = Player
				NewValue.Name = name
				NewValue.Changed:Connect(function()
					Profiles[Player][name] = Value
				end)
			end
		else
			local leaderstats = Instance.new("Folder")
			leaderstats.Parent = Player
			leaderstats.Name = "leaderstats"
			local WinsValue = Instance.new("NumberValue")
			WinsValue.Parent = leaderstats
			WinsValue.Value = Value
			WinsValue.Name = "Wins"
			WinsValue.Changed:Connect(function()
				Profiles[Player].Wins = WinsValue.Value
			end)
		end
	end

	print("Instanced all values for "..Player.Name)
end


local function OnPlayerAdded(Player)
	local ProfileData = GameProfileStore:LoadProfileAsync(
		"Player_"..Player.UserId,
		"ForceLoad"
	)
	if ProfileData ~= nil then
		ProfileData:Reconcile()
		ProfileData:ListenToRelease(function()
			Profiles[Player] = nil
			Player:Kick()
		end)
		if Player:IsDescendantOf(PlayersService) then
			Profiles[Player] = ProfileData
			InstanceValues(Player)
		else
			ProfileData:Release()
		end
	end
end

for _, player in ipairs(PlayersService:GetPlayers()) do
	coroutine.wrap(OnPlayerAdded)(player)
end

local function OnPlayerLeave(Player)
	print(Player.Name.." Left")
	local profile = Profiles[Player]
	if profile ~= nil then
		profile:Save() 
		profile:Release()
	end
end

local function OnServerShutdown()
	print("Saving all data before server shutdown")
	for i = 1, #Profiles do
		Profiles[i]:Save() 
	end
end
PlayersService.PlayerAdded:Connect(OnPlayerAdded)
PlayersService.PlayerRemoving:Connect(OnPlayerLeave)
game:BindToClose(OnServerShutdown)

I thought server shutdown was causing it, so I included handling for server shutdown, unsure if ProfileService automatically did this.

Any help?

3 Likes

You have to change the profile data with Profile.Data.Wins, and not Profile.Wins

Ohhhhhh. Ok I see where I went wrong. Thanks for pointing that out! I’ll change my code and test it later on

Unfortunately, no difference. Still won’t save data, no errors though.

local ServerScriptService = game:GetService("ServerScriptService")
local ProfileService = require(ServerScriptService.ProfileService)
local PlayersService = game:GetService("Players")
local profileTemplate = {
	["SpleefCoins"] = 0,
	["WinTokens"] = 0,
	["Level"] = 1,
	["Rank"] = "Newbie",
	["Effect"] = "White",
	["Trail"] = "White",
	["XP"] = 0,
	["MaxXP"] = 30,
	["TrailBuff"] = 1,
	["EffectBuff"] = 1,
	["DonateTokens"] = 0,
	["Wins"] = 0
}
local Profiles = {}

local GameProfileStore = ProfileService.GetProfileStore(
	"PlayerData",
	profileTemplate
)

local function InstanceValues(Player)
	for name, Value in pairs(profileTemplate) do
		if name ~= "Wins" then
			if typeof(Value) == "number" then
				local NewValue = Instance.new("NumberValue")
				NewValue.Name = name
				NewValue.Parent = Player
				NewValue.Value = Value
				NewValue:GetPropertyChangedSignal("Value"):Connect(function()
					print("Recieved Change")
					Profiles[Player].Data[name] = Value
				end)
			else
				local NewValue = Instance.new("StringValue")
				NewValue.Value = Value
				NewValue.Parent = Player
				NewValue.Name = name
				NewValue:GetPropertyChangedSignal("Value"):Connect(function()
					print("Recieved Change")
					Profiles[Player].Data[name] = Value
				end)
			end
		else
			local leaderstats = Instance.new("Folder")
			leaderstats.Parent = Player
			leaderstats.Name = "leaderstats"
			local WinsValue = Instance.new("NumberValue")
			WinsValue.Parent = leaderstats
			WinsValue.Value = Value
			WinsValue.Name = "Wins"
			WinsValue:GetPropertyChangedSignal("Value"):Connect(function()
				print("Recieved Change")
				Profiles[Player].Data.Wins = WinsValue.Value
			end)
		end
	end

	print("Instanced all values for "..Player.Name)
end


local function OnPlayerAdded(Player)
	local ProfileData = GameProfileStore:LoadProfileAsync(
		"Player_"..Player.UserId,
		"ForceLoad"
	)
	if ProfileData ~= nil then
		ProfileData:Reconcile()
		ProfileData:ListenToRelease(function()
			Profiles[Player] = nil
			Player:Kick()
		end)
		if Player:IsDescendantOf(PlayersService) then
			Profiles[Player] = ProfileData
			InstanceValues(Player)
		else
			ProfileData:Release()
		end
	end
end

for _, player in ipairs(PlayersService:GetPlayers()) do
	coroutine.wrap(OnPlayerAdded)(player)
end

local function OnPlayerLeave(Player)
	print(Player.Name.." Left")
	local profile = Profiles[Player]
	if profile ~= nil then
		profile:Save() 
		profile:Release()
	end
end

local function OnServerShutdown()
	print("Saving all data before server shutdown")
	for i = 1, #Profiles do
		Profiles[i]:Save() 
	end
end
PlayersService.PlayerAdded:Connect(OnPlayerAdded)
PlayersService.PlayerRemoving:Connect(OnPlayerLeave)
game:BindToClose(OnServerShutdown)
1 Like

did you check the output, or the saving and receiving data is the problem

Yeah. It printed the following but none of them were errors:

  13:00:13.978  [ProfileService]: Roblox API services available - data will be saved  -  Server - ProfileService:1909
  13:00:20.108  Instanced all values for JeffTheEpicRobloxian  -  Server - DatastoreScript:62
  13:03:42.952  JeffTheEpicRobloxian Left  -  Server - DatastoreScript:91
  13:03:42.953  Saving all data before server shutdown
1 Like

@p49p0 @Jxl_s I seemed to have kinda got it working, but at some cost. Now, even though it has saved and loaded data, it is duplicating everything, making it look like utter chaos.

Removing the release did the trick, but I doubt it was worth it.

1 Like

Remove the :Save. By default, it will already save once the player leaves.

By not releasing, there can be memory leaks since the players and their profiles will stay in the table.

Ok, thanks for the information :smiley: I’ll try it rn

you mean it saves because you’re the last player and using game:BindToClose()

2 Likes

It works to an extent, but for some reason duplicate values are being instanced. Any reason why?

Code:

local ServerScriptService = game:GetService("ServerScriptService")
local ProfileService = require(ServerScriptService.ProfileService)
local PlayersService = game:GetService("Players")
local profileTemplate = {
	["SpleefCoins"] = 0,
	["WinTokens"] = 0,
	["Level"] = 1,
	["Rank"] = "Newbie",
	["Effect"] = "White",
	["Trail"] = "White",
	["XP"] = 0,
	["MaxXP"] = 30,
	["TrailBuff"] = 1,
	["EffectBuff"] = 1,
	["DonateTokens"] = 0,
	["Wins"] = 0
}
local Profiles = {}

local GameProfileStore = ProfileService.GetProfileStore(
	"PlayerData_2",
	profileTemplate
)

local function InstanceValues(Player)
	for name, Value in pairs(profileTemplate) do
		if name ~= "Wins" then
			if typeof(Value) == "number" then
				local NewValue = Instance.new("NumberValue")
				NewValue.Name = name
				NewValue.Parent = Player
				NewValue.Value = Value
				NewValue:GetPropertyChangedSignal("Value"):Connect(function()
					print("Recieved Change")
					Profiles[Player].Data[name] = Value
				end)
			else
				local NewValue = Instance.new("StringValue")
				NewValue.Value = Value
				NewValue.Parent = Player
				NewValue.Name = name
				NewValue:GetPropertyChangedSignal("Value"):Connect(function()
					print("Recieved Change")
					Profiles[Player].Data[name] = Value
				end)
			end
		else
			local leaderstats = Instance.new("Folder")
			leaderstats.Parent = Player
			leaderstats.Name = "leaderstats"
			local WinsValue = Instance.new("NumberValue")
			WinsValue.Parent = leaderstats
			WinsValue.Value = Value
			WinsValue.Name = "Wins"
			WinsValue:GetPropertyChangedSignal("Value"):Connect(function()
				print("Recieved Change")
				Profiles[Player].Data.Wins = WinsValue.Value
			end)
		end
	end

	print("Instanced all values for "..Player.Name)
end


local function OnPlayerAdded(Player)
	local ProfileData = GameProfileStore:LoadProfileAsync(
		"Player_"..Player.UserId,
		"ForceLoad"
	)
	if ProfileData ~= nil then
		ProfileData:Reconcile()
		ProfileData:ListenToRelease(function()
			Profiles[Player] = nil
			Player:Kick()
		end)
		if Player:IsDescendantOf(PlayersService) then
			Profiles[Player] = ProfileData
			InstanceValues(Player)
		else
			ProfileData:Release()
		end
	end
end
local function OnPlayerLeave(Player)
	Profiles[Player]:Release()
end

PlayersService.PlayerAdded:Connect(OnPlayerAdded)
PlayersService.PlayerRemoving:Connect(OnPlayerLeave)

1 Like

I’m having the same issue where data is just not saving at all, and I have no idea how to fix it. I’ve added :WaitForChild() events everywhere for no errors yet still nothing is saving.

Edit: Sorry for the 3 year late response LOL

1 Like

No problem about bumping, I’m having the same issue lol

I figured out that all of my data wasn’t being saved because it wasn’t being updated on the server, only the client, therefore I made a RemoveEvent where I just type the name of the value and it searches through the player to get the value that changed and updates it.