Save your player data with ProfileService! (DataStore Module)

I’d take it even without the documentation

1 Like

please release the module we havent gotten an update in over 2 years i think :pray:

1 Like

bro it’s probably the most used datastore module ever made.

yes, the community is interested. let’s just uhhh skip on past that hype train and get to the part where you release it. pleaseee!!! :smiley:

2 Likes

+1 to the community interest for a release

1 Like

would be awesome to see an upgraded profileservice! interested to see what specific changes were made :eyes:

1 Like

Please add support for typechecking! :pray:

2 Likes

There’s one on GitHub made by another user iirc, just check the Github repo

just release it, people be craving for an update

how can i migrate my data to profile service? i’ve been using the traditional datastore and experiencing data loss

Definitely interested in the ReplicaService rewrite, even without documentation

ProfileStore

An updated module, successor to ProfileService, has been RELEASED:

3 Likes

I’m having an issue.

I’m using TeleportAsync to attempt to reconnect afk players prior to Roblox’s disconnect. I have my script set to release the players data, then I use ListenToHopReady as well as a small delay prior to teleporting. I’ve verified that :IsActive() is being set to false. When the player is rejoined to the same server, no problem. However, if the player is put into a different server LoadProfileAsync is returning nil indicating two servers attempting to access the profile. In the case that LoadProfileAsync returns nil, I have it set to reconnect players through TeleportAsync which seems to work fine.

What might I be doing wrong? Ideally I want to avoid this double teleport

ProfileService is no-longer supported or being updated, but I would like to know if anyone else has experienced this same problem.

Randomly last night starting around 7:30 PM 3 thousand errors over a period of 6 hours occurred relating to profile service.

I have not seen this error occur on any of my other experiences so it’s pretty bizarre. Thanks!

I’m also getting occasional errors loading data upon joining a place after a teleport

Hello, I am constantly getting an error (not in studio) that tells me that the profile is not existing.
I followed the youtube video given on the very top as a recommendation.
I personally do not get this issue in studio, but in the actual game many users seem to trigger this error.

The source code is pretty much like in the video in terms of getting / loading the actual data in.
I will provide source code to this post here later but does anyone have a idea why this could be?

Thanks in advance.

Yours sincerely, Sxato | Marv.

Source code:

local function added(Player)
    dataTemplate = dataStructure.getStructure(Player)
    local profileStore = PS.GetProfileStore("PlayerProfile", dataTemplate["Saveables"])
    local profile
    repeat
        local success, errormsg = pcall(function()
            profile = profileStore:LoadProfileAsync("TestPlayerProfile" .. Player.UserId)
        end)
        if not success then warn(errormsg) task.wait(1) end
    until success
    
    
    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
        end
else
Player:kick()
end
    
    Player:SetAttribute("DataLoaded", true)
end

Can anyone confirm that this should work? Because for some reason my assert in another function is being triggered. The assert has the following in it:

assert(profiles[Player], string.format("Profile does not exist for: %s", Key)

any help is appreciated.

Hey, basically I have no idea what I’m doing, and just copy-pasted it from another one of my games where data saving works, but it doesn’t in this game.

Here’s my script. Can someone tell me what the issue is?

local ProfileTemplate = {
	PlayerStats = {Kills = 0, Wins = 0, Level = 1, Exp = 0, Coins = 0},
	Weapons = 
		{
			WeaponStats = {EquippedKnife = "Classic", EquippedGun = "Classic", EquippedSword = "Classic"},
			Knives = {Classic = 1, Bronze = 0, Silver = 0, Gold = 0, Platinum = 0, Lapis = 0, Obsidian = 0, Diamond = 0, Amethyst = 0, Ruby = 0, Emerald = 0, Turqoise = 0, Flame = 0, Frost = 0, Shadow = 0, Lunar = 0, Supernova = 0, Void = 0},
			Guns = {Classic = 1, Bronze = 0, Silver = 0, Gold = 0, Platinum = 0, Lapis = 0, Obsidian = 0, Diamond = 0, Amethyst = 0, Ruby = 0, Emerald = 0, Turqoise = 0, Flame = 0, Frost = 0, Shadow = 0, Lunar = 0, Supernova = 0, Void = 0},
			Swords = {Classic = 1, Bronze = 0, Silver = 0, Gold = 0, Platinum = 0, Lapis = 0, Obsidian = 0, Diamond = 0, Amethyst = 0, Ruby = 0, Emerald = 0, Turqoise = 0, Flame = 0, Frost = 0, Shadow = 0, Lunar = 0, Supernova = 0, Void = 0}
		}		
}

----- Loaded Modules -----

local ProfileService = require(script.ProfileService)

----- Private Variables -----

local Players = game:GetService("Players")

local ProfileStore = ProfileService.GetProfileStore("PlayerData", ProfileTemplate)

local Profiles = {}

local function DoSomethingWithALoadedProfile(Player, Profile)
	local PlayerStats = Player:WaitForChild("PlayerStats")
	local Weapons = Player:WaitForChild("Weapons")
	
	PlayerStats.Kills.Value = Profile.Data.PlayerStats.Kills
	PlayerStats.Wins.Value = Profile.Data.PlayerStats.Wins
	PlayerStats.Level.Value = Profile.Data.PlayerStats.Level
	PlayerStats.Exp.Value = Profile.Data.PlayerStats.Exp
	PlayerStats.Coins = Profile.Data.PlayerStats.Coins
	
	Weapons.EquippedKnife = Profile.Data.Weapons.WeaponStats.EquippedKnife
	Weapons.EquippedGun = Profile.Data.Weapons.WeaponStats.EquippedGun
	Weapons.EquippedSword = Profile.Data.Weapons.WeaponStats.EquippedSword
	
	
	PlayerStats.Kills.Changed:Connect(function(Value)
		Profile.Data.PlayerStats.Kills = Value
	end)

	PlayerStats.Wins.Changed:Connect(function(Value)
		Profile.Data.PlayerStats.Wins = Value
	end)

	PlayerStats.Level.Changed:Connect(function(Value)
		Profile.Data.PlayerStats.Level = Value
	end)

	PlayerStats.Exp.Changed:Connect(function(Value)
		Profile.Data.PlayerStats.Exp = Value
	end)
	
	PlayerStats.Coins.Changed:Connect(function(Value)
		Profile.Data.PlayerStats.Coins = Value
	end)
	
	for _, Knife in Weapons.Knives:GetChildren() do
		Knife.Changed:Connect(function(Value)
			Profile.Data.Weapons.Knives[Knife.Name] = Value
		end)
	end

	for _, Gun in Weapons.Guns:GetChildren() do
		Gun.Changed:Connect(function(Value)
			Profile.Data.Weapons.Guns[Gun.Name] = Value
		end)
	end

	for _, Sword in Weapons.Swords:GetChildren() do
		Sword.Changed:Connect(function(Value)
			Profile.Data.Weapons.Swords[Sword.Name] = Value
		end)
	end
end

local function PlayerAdded(Player)
	local Profile = ProfileStore:LoadProfileAsync(tostring(Player.UserId))
	if Profile ~= nil then
		Profile:AddUserId(Player.UserId)
		Profile:Reconcile()
		Profile:ListenToRelease(function()
			Profiles[Player] = nil
			Player:Kick()
		end)
		
		if Player:IsDescendantOf(Players) == true then
			Profiles[Player] = Profile
			DoSomethingWithALoadedProfile(Player, Profile)
		else
			Profile:Release()
		end
	else
		Player:Kick() 
	end
end

----- Initialize -----

for _, Player in ipairs(Players:GetPlayers()) do
	task.spawn(PlayerAdded, Player)
end

----- Connections -----

Players.PlayerAdded:Connect(PlayerAdded)

Players.PlayerRemoving:Connect(function(Player)
	local Profile = Profiles[Player]
	if Profile ~= nil then
		Profile:Release()
	end
end)
1 Like

session locking should solve pretty much all of the issue from the datastore side. anything in another layer in on you of course

this could be a race condition
your code might check for the profile before the profile is loaded! datastores aren’t immediate.

do some printing to see the order

usually when I used profileservice I’d have an extra wrapper for it with Signals and :WaitFor functions to deal with this and to overall simplify the use of profiles

Thanks for your response, I ended up yielding the Datastore with a “repeat until” so I do not let the system continue until the profile is there or the player is gone.

All I had to do was change the name of one variable! I love scripting :grin::grin::grin::grin: