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.
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.
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.
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.
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.
-
If I remove a key from the template, will it be removed from the player’s profile?
-
If I add a new key to the template, will be added to the player’s profile?
-
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.
-
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?
-
(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?
- No
- No
- Keep
- No
- You need to write your own interface
[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):
Console log when saving to live keys (Studio only):
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.
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])
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.