Save your player data with ProfileService! (DataStore Module)

What’s the reason for having PlaceId and JobId as an ActiveSession? Since JobId is unique, isn’t that sufficient?

Because game universes can have several places.

3 Likes

I’m curious, I have not tested this, let’s say I update the profile template, and a returning user, let’s call him Bob, comes back when I’ve updated the template and it isn’t the same one as he last saved, do I manually have to rewrite that profile to use the new template, or does the module automatically do that for me?

ProfileService does not fill in missing values from the profile template for old profiles. You can either fill in the missing values right after the profile is loaded, or you can check if values are nil before using those values from the profile.

3 Likes

As loleris said, you would have to check if the new value in the template is nil. There is an example of this in the example code: local function giveCash(). In the function, the if profile.Data.Cash == nil would be how to test the values.

Sure, but what does that have to do with the uniquness of a JobId? No matter the place, the JobId should be unique.

It has less to do with the uniqueness of JobId and more to do with already providing you with a PlaceId instead of having to do some dark magic to figure out which PlaceId the JobId it belongs to.

Oh right - you might’ve not noticed that ProfileService exposes JobId and PlaceId for custom session lock handling.

2 Likes

would this work across different places?

Games (previously known as universes) can be made up of several places - DataStoreService keys are global among all places within a single game, so you can have the same player profiles accessible through all those places under one game.

4 Likes

Currently, I’m using DataStore2 for a game I’m working on, but I prefer to have the safest and most secure code possible- especially when it comes to a game’s economy in case we end up deciding to add something like trading. I want to convert any data handling I have in my game to use ProfileService, but a big reason I use DataStore2 is how easily I can make a module to allow for replicating saved data and adding different parts to a player’s profile.

-- ProfileTemplate table is what empty profiles will default to. -- Updating the template will not include missing template values -- in existing player profiles!

This wording is slightly confusing to me, so I got a couple of questions regarding that as well.

  1. If I remove a key from the template, will it be removed from the player’s profile?

  2. If I add a new key to the template, will be added to the player’s profile?

  3. If I change the default value of a key in the template, will the profile keep its current value or update to the new one.

  4. If one of the values of a key is a table in the template if I add a new value to the table, will it add the new value to the player’s profile?

  5. (This one isn’t about the profile template) How would I listen to updates when data is changed in a profile (so I can replicate the changes to the client), or do I need to write my own “interface” for that?

1 Like
  1. No
  2. No
  3. Keep
  4. No
  5. You need to write your own interface
3 Likes

[08/10/2020]
ProfileService will now access live DataStore keys when studio access to API services is enabled.

Console log when not saving to live keys (Studio only):
image
Console log when saving to live keys (Studio only):
image


Added "Steal" as an argument for not_released_handler or a return of a not_released_handler function:

Update your module by loading it from the Roblox library again or by grabbing the source from GitHub.

10 Likes

How would you use ProfileService between Places since I’m going to be using it and in my game you teleport between places.

You can use it as you would normally.

Okay thanks for telling also I find this topic very useful.

local ProfileService = require(script.Parent:WaitForChild("ProfileService"))
local Players = game:GetService("Players")
local Profiles = {}

local saveStructure = {
	Coins = 0;
	Gems = 0;
}

local PlayerProfileStore = ProfileService.GetProfileStore("PlayerSaveData", saveStructure)

local function PlayerDataLoaded(player)
	local profile = Profiles[player]
	
	local folder = Instance.new("Folder")
	folder.Name = "leaderstats"
	folder.Parent = player
	
	local Coins = Instance.new("IntValue")
	Coins.Name = "Coins"
	Coins.Value = profile.Data.Coins
	Coins.Parent = folder
	
	local Gems = Instance.new("IntValue")
	Gems.Name = "Gems"
	Gems.Value = profile.Data.Gems
	Gems.Parent = folder
	
	spawn(function()
		while true do
			local profile = Profiles[player]
			
			if profile ~= nil then
				Coins.Value = profile.Data.Coins
				Gems.Value = profile.Data.Gems
			else
				break
			end
			
			player.Character.Humanoid.Died:Connect(function()
				profile.Data.Gems = profile.Data.Gems + 100
			end)
			
			wait(0.1)
		end
	end)
	 
	print(player.Name .. "'s data is loaded")
end

local function PlayerAdded(player)
	local profile = PlayerProfileStore:LoadProfileAsync("Player_" .. player.UserId, "ForceLoad")
	
	if profile ~= nil then
		profile:ListenToRelease(function()
			Profiles[player] = nil
			player:Kick("Your profile has been loaded remotely. Please rejoin.")
		end)
		
		if player:IsDescendantOf(Players) then
			Profiles[player] = profile
			PlayerDataLoaded(player)
		else
			profile:Release()
		end
	else
		player:Kick("Unable to load saved data. Please rejoin.")
	end
end

for _, player in ipairs(Players:GetPlayers()) do
	spawn(function()
		PlayerAdded(player)
	end)
end

Players.PlayerAdded:Connect(PlayerAdded)

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

return Profiles

Could anyone tell me what I’m doing wrong here? It prints in output ( [19:37:12.682 - ServerScriptService.DataManager.DataService:60: attempt to perform arithmetic (add) on nil and number])

1 Like

Whenever you load your data, make sure to check that Gems exists. If it doesn’t, set it to 0.

When I replace Gems with Coins it works fine and the data also saves fine.

Okay I’ll try that out and see if it works. It seems that Gems doesn’t exist in the table. Do you know why?? @EncodedLua

At the time your data was saved, Gems was not part of the save structure. ProfileService does not merge save structures. You will need to create a system to do that yourself.