It won’t get removed. You would need to have your own function for that.
local function ReconcileWithExtraKeyRemoval(Profile)
Profile:Reconcile()
local ProfileData = Profile.Data
for key in pairs(ProfileData) do
if DataTemplate[key] == nil then
ProfileData[key] = nil
end
end
end
You can’t remove indexes from nested tables (sub tables if you don’t know what that means) because that means that you would not be able to have things like weapons, for example:
I’m also wondering the same, this seems like quite a big update and hopefully it can open up doors to more features or at least optimise the current features.
Seeing UserIds get tagged for GDPR requests would be really useful. Especially if roblox decide to automate GDPR requests provided the right data is tagged.
Is there anyway to use :GetOrderedDataStore in ProfileService? I’ve made an entire game framework with ProfileService, but ran into a problem when making global leaderboards. Has anyone found a way to accomplish this? I’m genuinely not sure, been here for about 2 hours trying to script it. But can’t find anyway, all help appreciated. Thanks!
Full DataStore v2 support. You’re not going to miss a thing.
I’ve written all the explanations in the docs, so there’s not much I can really say here… Epic DSv2 speedrun?
I’d say the safety of this module is around 99% - I did extensive artificial testing plus all the original tests that helped ProfileService stay 99.99% germ-proof through every other update. I will react to error reports pretty fast.
Summary:
:LoadProfileAsync() second argument is now optional - You can just omit passing “ForceLoad” after the profile key.
:ViewProfileAsync() and :ProfileVersionQuery() can now be used to create “Profile payloads” by editing Profile objects created by these methods and pushing them via :OverwriteAsync(). This should only be used for rollbacks or careless data editing.
Added proper DataStore:RemoveAsync() support for ProfileStore:WipeProfileAsync()
Also fixed passing nil as second argument sort_direction for ProfileStore:ProfileVersionQuery() resulting in an error. github and Roblox library versions have already been updated so just switch your module with a new one.
Profile:AddUserId() marks the profile’s DataStore key with the UserId which would supposedly help Roblox delete the key on their own instead of sending you direct messages to remove it manually (In the near future, possibly).
I think what’s going to happen is that Roblox will always remember every player that played your game and will send you a GDPR notice unless they find a DataStore key tagged with the UserId.
One, there is the DataApi (which is the main area for the data)
And the other which loads the player in.
Inside the loader script, I ask for the player’s profile from the DataApi script using a function that returns the profile. However, it errors saying “attempted to index ‘Data’ with nil”
The profilescript
-- ProfileTemplate table is what empty profiles will default to.
-- Updating the template will not include missing template values
-- in existing player profiles!
local module = {}
local ProfileTemplate = require(script.Data)
----- Loaded Modules -----
local ProfileService = require(game.ServerScriptService.ProfileService)
----- Private Variables -----
local Players = game:GetService("Players")
local GameProfileStore = ProfileService.GetProfileStore(
"PlayerData",
ProfileTemplate
)
local Profiles = {}
----- Private Functions -----
function PlayerAdded(player)
local profile = GameProfileStore:LoadProfileAsync(
"Player_" .. player.UserId,
"ForceLoad"
)
print(profile.Data.Coins)
if profile ~= nil then
profile:Reconcile() -- Fill in missing variables from ProfileTemplate (optional)
profile:ListenToRelease(function()
Profiles[player] = nil
-- The profile could've been loaded on another Roblox server:
player:Kick("Released")
end)
if player:IsDescendantOf(Players) == true then
Profiles[player] = profile
else
-- Player left before the profile loaded:
profile:Release()
end
else
-- The profile couldn't be loaded possibly due to other
-- Roblox servers trying to load this profile at the same time:
player:Kick("Failed to load DataProfile (This is probably a result of Roblox data outage.)")
end
end
----- Initialize -----
-- In case Players have joined the server earlier than this script ran:
for _, player in ipairs(Players:GetPlayers()) do
coroutine.wrap(PlayerAdded)(player)
end
----- Give Data to other scripts -----
function module:Get(Player)
local profile = Profiles[Player]
if profile then
print("yeah")
return profile
end
end
----- Connections -----
Players.PlayerAdded:Connect(PlayerAdded)
Players.PlayerRemoving:Connect(function(player)
local profile = Profiles[player]
if profile ~= nil then
profile:Release()
end
end)
return module
I use the Get() function to return the profile to other scripts.
I’ve tried making waits inside the loader script but this doesn’t solve the issue.
It for some reason works just fine in other scripts but it does not return anything.
Before I had the forceload portion in the loader script instead of the data script, and it worked with everything else, but that would cause data errors. How can I get it to return the profile?
You might wanna consider have a :WaitForProfile function.
Get a signal module, then, you can implement it something like this: (pseudo code)
local ON_PROFILE_CACHED = Signal.new()
-- On loading the profile
PROFILES[player] = profile
ON_PROFILE_CACHED:Fire(player, profile)
--
function ProfileHandler:WaitForProfile(player)
--\\ This function CAN return nil, and it will do so if the player has left.
do
local profile = PROFILES[player]
if profile then
return profile
end
end
if player.Parent ~= Players then
return
end
while true do
local playerFromProfile, profile = ON_PROFILE_CACHED:Wait()
if playerFromProfile == player then
return profile
end
if player.Parent ~= Players then
return
end
end
end
:OverwriteAsync(): Using this method for editing latest player data when the player is in-game can lead to several minutes of lost progress - it should be replaced by [:LoadProfileAsync()]
How would I use :LoadProfileAsync() instead of :OverwriteAsync() when player is active?
How do I know if the player is active?
Wouldn`t that kick the active player by default if profile is stolen?
Wouldn`t loading and manipulating data be slower than Overwriting?
Profile:ClearGlobalUpdates()
Are these updates that would come from the old save or are these currently live ones that will be eliminated? Why would you want it?
What would be the use case for .RobloxMetaData if it`s so limited and ProfileService already has this great feature?
You just use it like you would load regular player data - Load, edit, release.
:LoadProfileAsync() will wait for a remote server to do it’s final auto-save and create a profile release signal which would notify developer code not to attempt editing the profile anymore. If there’s no remote server currently using the profile, :LoadProfileAsync() will return a Profile much more instantly.
GlobalUpdates are stored in the profile itself under the same DataStore key, but outside Profile.Data, like metada. Profile:ClearGlobalUpdates() can be used for profile payloads retrieved through :ViewProfileAsync() and :ProfileVersionQuery() to clear GlobalUpdates data in the profile payload. Profile payloads don’t get auto-saved or released - any changes made to them would only be saved to the DataStore if you called :OverwriteAsync().
If you’re not using GlobalUpdates in your game at all, then this method will have no effect to data and can be omitted.
And if you’re actually using GlobalUpdates… Using Profile:ClearGlobalUpdates() when rolling back is not mandatory, in which case a player would recover GlobalUpdates in the exact state they existed in the profile snapshot that was rolled back to.
Yeah. .RobloxMetaData is currently useless and Profile.MetaData.MetaTags, Profile:SetMetaTag(), Profile:GetMetaTag() should be used instead (the former having a 300 character (300 byte) limit, the latter (combined with Profile.Data) having a 4 megabyte limit).
Roblox is promising “querying and indexing based on such metadata will be supported in future releases”, so ProfileService is just being prepared for it.
Wanted to use this module, I have some questions though:
Is there a readable way of using serialization? For instance, in DataStore2 the saved data can get serialized, but when reading the data its deserialized.
Is there anything I would need to do with BindToClose? Or is it done automatically?