ProfileStore - Save your player data easy (DataStore Module)

is it normal for it to take a long time to get into the game from the studio?
roblox studio stops responding for a while and then comes back

Hi, I wanted to implement the dev product game into my game, but I also have gifting of dev product. is there any way you would make it works for gifting ?

Hello sorry for late reply, but cant you just add a getpropertychangedsignal to each value and when it changes change the profile.data and that way it keeps the autosaves?

like couldnt u do something like this?

function ProfileSetup(Player, Profile)
	
	local PlayerFolder = Instance.new'Folder';
	PlayerFolder.Name = 'Data';
	PlayerFolder.Parent = Player;
	
	UtilityModule.TableToObject(Profile.Data, PlayerFolder);
	
	for _, V in PlayerFolder:GetChildren() do
		if V:IsA'Folder' then
			for _, V2 in V:GetChildren() do
				V2:GetPropertyChangedSignal'Value':Connect(function()
					if Profile and Profile.Data and Profile.Data[V2.Name] then
						Profile.Data[V2.Name] = V2.Value; 
					end
				end)
			end
		 	continue
		end
		V:GetPropertyChangedSignal'Value':Connect(function()
			if Profile and Profile.Data and Profile.Data[V.Name] then
				Profile.Data[V.Name] = V.Value;
			end
		end)
	end
	
end

Yeah, I don’t see why not. Probably just a matter of preference at that point.

I believe you would need to use PlayerStore:MessageAsync and listen to the change on the profile using Profile:MessageHandler.

1 Like

UPDATE - MessagingService call blocking prevention

There have been some reports that lead me to believe that MessagingService methods may sometimes yield indefinitely or throw errors which was not mentioned in the official documentation for MessagingService as of writing this. As a precaution all MessagingService methods have been protected inside ProfileStore and can no longer block ProfileStore’s code.

This should also fix issues for people who have tried to use ProfileStore in Team Test ((TOPIC) :SubscribeAsync() yields silently and indefinetly on Team Test)

You may get the new version of ProfileStore from GitHub or Roblox library

Happy saving!

28 Likes

Thanks Man. You are Awesome. Please Continue to release Peak.

2 Likes

Not sure what happened to the message but its true. Dead Rails is using both ProfileStore and Replica.

6 Likes

Nice :grin: Really glad to see my open source materials help get a game reach the top!

Also congrats on your success :+1:

Also donations are always appreciated, but not mandatory :eyes::rofl:

4 Likes

I am going to use ProfileStore to save my settings. Is there anything I need to be careful of?

Anything like what?

There shouldn’t be unless you use it improperly or in an unintended way.

I keep seeing this error when players join my game. Not all, but a lot of them, it even happened to me (i have a good internet connection and a decent computer).

Im guessing its not related to ProfileStore since the game doesn’t even load whatsoever but this is the only error im getting and its related to ProfileStore so im posting this here.

Discord_68ChhqW5Z0

Any help will be appreciated!

Can you show us your ProfileStore code?

Main

local ServerStorage = game:GetService("ServerStorage")
local ServerScriptService = game:GetService("ServerScriptService")
local ReplicatedStorage = game:GetService("ReplicatedStorage")

local ProfileStore = require(ServerStorage.Scripts.ProfileStore)
local Manager = require(ServerScriptService.PlayerData.Manager)
local Template = require(ReplicatedStorage.Scripts.Template)

local Players = game:GetService("Players")

local PlayerStore = ProfileStore.New("Production2", Template)
local Profiles: {[player]: typeof(PlayerStore:StartSessionAsync())} = {}

local function CreateLeaderstats(Player: Player)
	local profile = Manager.Profiles[Player]
	if not profile then return end

	local leaderstats = Instance.new("Folder", Player)
	leaderstats.Name = "leaderstats"

	local Extras = Instance.new("Folder")
	Extras.Name = "Extras"
	Extras.Parent = Player

	local Kills = Instance.new("NumberValue", leaderstats)
	Kills.Name = "Kills"
	Kills.Value = profile.Data.Kills

	local Berries = Instance.new("NumberValue", leaderstats)
	Berries.Name = "Berries"
	Berries.Value = profile.Data.Berries

	local LastHit = Instance.new("StringValue")
	LastHit.Name = "LastHit"
	LastHit.Value = Template.LastHit
	LastHit.Parent = Extras

	local Settings = Instance.new("Folder")
	Settings.Name = "Settings"
	Settings.Parent = Player

	for _, Value in ipairs(Template.Settings) do
		if type(Value[2]) == "boolean" then
			local ValueInstance = Instance.new("BoolValue")
			ValueInstance.Name = Value[1]
			if profile.Data[Value[1]] ~= nil then
				ValueInstance.Value = profile.Data[Value[1]]
			else
				ValueInstance.Value = Value[2]
			end
			ValueInstance.Parent = Settings
		elseif type(Value[2]) == "number" then
			local ValueInstance = Instance.new("NumberValue")
			ValueInstance.Name = Value[1]
			if profile.Data[Value[1]] ~= nil then
				ValueInstance.Value = profile.Data[Value[1]]
			else
				ValueInstance.Value = Value[2]
			end
			ValueInstance.Parent = Settings
		elseif type(Value[2]) == "table" or type(Value[2]) == "string" then
			local ValueInstance = Instance.new("StringValue")
			ValueInstance.Name = Value[1]
			if profile.Data[Value[1]] ~= nil then
				ValueInstance.Value = tostring(profile.Data[Value[1]])
			else
				ValueInstance.Value = Value[2]
			end
			ValueInstance.Parent = Settings
		end
	end
end

local function PlayerAdded(player)
	local profile = PlayerStore:StartSessionAsync(`{player.UserId}`, {
		Cancel = function()
			return player.Parent ~= Players
		end,
	})

	if profile ~= nil then

		profile:AddUserId(player.UserId)
		profile:Reconcile()

		profile.OnSessionEnd:Connect(function()
			Manager.Profiles[player] = nil
			player:Kick(`Profile session end - Please rejoin`)
		end)

		if player.Parent == Players then
			Manager.Profiles[player] = profile
			CreateLeaderstats(player)
		else
			profile:EndSession()
		end

	else
		player:Kick(`Profile load fail - Please rejoin`)
	end

end

-- In case Players have joined the server earlier than this script ran:
for _, player in Players:GetPlayers() do
	task.spawn(PlayerAdded, player)
end

Players.PlayerAdded:Connect(PlayerAdded)

Players.PlayerRemoving:Connect(function(player)
	local profile = Profiles[player]
	if profile ~= nil then
		profile:EndSession()
	end
end)

Manager (Shortend for your sake)

local ReplicatedStorage = game:GetService("ReplicatedStorage")

local Remotes = ReplicatedStorage.Remotes.Data

local ServerId = game.PrivateServerId

local Manager = {}

Manager.Profiles = {}

function Manager.AdjustKills(Player, Amount)
	local Profile = Manager.Profiles[Player]
	if not Profile or ServerId ~= "" then return end
	
	Profile.Data.Kills += Amount
	Player.leaderstats.Kills.Value = Profile.Data.Kills
	Remotes.Kills:FireClient(Player, Profile.Data.Kills)
end

local function GetData(Player, Directory)
	local Profile = Manager.Profiles[Player]
	if not Profile then return end
	return Profile.Data[Directory]
end

local function GetAllData(Player)
	local Profile = Manager.Profiles[Player]
	if not Profile then return end
	return Profile.Data
end

Remotes.GetData.OnServerInvoke = GetData
Remotes.GetAllData.OnServerInvoke = GetAllData

return Manager

You put the profiles in “Manager.Profiles” instead of “Profiles” table in your “Main” module - you should as well index the profile from “Manager.Profiles” where you call :EndSession() in “Main”.

1 Like

Ah okay thank you so much, btw is this what you mean by that last part you said or am i misunderstanding?
6ugXqsMNx2

No, your mistake was at the very bottom of the main script, 5th line from bottom.

Oh okay but can you explain this a bit more tho?

Not sure what you mean by it.


Getting a lot of errors like these in my game, using profilestore

In your script, you put all the profiles inside of Manager.Profiles and inside the PlayerRemoving event, you were checking the Profiles table for the players profile when its not there because once again, you put all the profiles inside of Manager.Profiles.

1 Like