No the server only closes if theres no players left. What if theres 11 players left after this one player leaves? I guess I’ll manually save
In my PlayerRemoving function such as deleting current game state caches related to that player and other various functions. I understand that :Kick() fires PlayerRemoving so listening to releases are safe, but I heard that there are times where PlayerRemoving won’t fire despite the player leaving and therefore important functions won’t fire. Is there anything in ProfileService that could cause this? I asked this a few months back:
Just a concern on mine, having players leave the game and not firing PlayerRemoving could cause some serious bugs.
Hey,
main cause of this is Game Shutdown (mainly in studio) and I don’t know if ProfileService is listening to :BingToClose() automatically but you can try to look for it or implement it yourself.
Found another bug (happened after 1.4 Million visits)
ServerScriptService.Modules.ProfileService:747: attempt to index nil with ‘ActiveSession’ ServerScriptService.Modules.ProfileService, line 747
ServerScriptService.Modules.ProfileService, line 538
ServerScriptService.Modules.ProfileService
ProfileService does BindToClose for you, and does it pretty well, you shouldn’t have to worry.
For more advanced use:
If you wanna do something after a profile is released completely, let’s say have a soft shutdown scheme on your game while using ProfileService, then you can check out :ListenToServerHopReady
which fires after a profile is actually fully released.
In that scenario, have your own BindToClose and loop through all profiles and add a ListenToServerHopReady
handler which teleports the player into another server.
Can ProfileService be used to save data that is not attached to a player? Such as a server system
quoting from the original post,
- Made for ambitious projects - ProfileService is a profile object abstraction detached from the
Player
instance - this allows the developer to create profiles for entities other than players, such as: group-owned houses, savable multiplayer game instances, etc.
yes
Hey loleris, I have a question. I’m running into a “Resolved profile corruption” warning that wipes out the players data. I figured out from looking at your code that the it’s because I needlessly encode my players saved data to JSON string before saving it to the data store.
It looks like I need to edit your code to add a JSON decoding step if the datastore returns just a string. I’m going to edit the script around line 652 to add a (type()== string ) case. Please let me know if I’m about to make a big mistake.
This library is such a great contribution to the community. Thanks so much!
Ideally you wouldn’t have to fork ProfileService for changes so you could easily update the module with future updates. You could do a double query on two coroutines for your old data and new profiles for different DataStore keys whenever a player joins, wait until both queries finish (at basically no time penalty compared to loading just the new profile) and then merge the data if it wasn’t merged before.
local result1, result2
local is_finished1, is_finished2 = false, false
-- 2 asynchronous tasks:
coroutine.wrap(function()
-- Do something that yields
-- Don’t forget to wrap basic DataStore calls in pcall here
result1 = 1
is_finished1 = true
end)()
coroutine.wrap(function()
-- Do something that yields
-- Don’t forget to wrap basic DataStore calls in pcall here
result2 = 1
is_finished2 = true
end)()
-- Waiting until all tasks finish:
while is_finished1 == false or is_finished2 == false do
RunService.Heartbeat:Wait()
end
I built off your suggestion, and deployed my save data refactor to my live game. No one has reported any problems yet. Thanks so much loleris!
Can you use this module in a class? or is that not required? Can I call it multiple times?
Thank you!
From the troubleshooting section:
Failure to prevent these data types may result in silent data loss, silent errors, fatal errors and overall failure to save data.
Would it make sense / be possible to report these as warnings? In my case, I was inadvertently trying to use non-sequential number keys rather than string keys for one of my tables and the result was that the Profile stored these as numbers but the datastore converted them to strings.
Does :Reconcile() remove old data? For example if my data table is this:
local DataToSave = {
Coins = 0,
Diamonds = 5,
}
But then I decide I don’t want to use Diamonds as a currency anymore so I remove it from the table like so:
local DataToSave = {
Coins = 0,
}
Will Diamonds
get removed from the players data upon reconciling? Or will it just stop it from getting added to new player data?
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:
Profile.Data.Weapons = {
"Sword",
"Axe",
"Hammer"
}
These values don’t exist in the data template,
– so looking for extra “sub tables” would remove things like these.
Hey! With the recent datastore v2 announcements, do you plan on updating this module utilizing the new features roblox provides?
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!
[08/14/2021]
I grinded this 10 hours non-stop. Even I think that I deserve some praise. Anyways here’s the moment we’ve been waiting for…
ProfileService - DataStore v2 edition
(But backwards-compatible, lol)
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 forProfileStore:WipeProfileAsync()
- Now using the task library.
- Updated internal signal class with GoodSignal coroutine recycling.
- ProfileService test module now includes tests for Roblox Metadata, profile payloads and versioning.
- Updated the basic usage example with :AddUserId().
New ProfileStore
methods:
- ProfileStore:ProfileVersionQuery() - Rollbacks made easy, baby!
New Profile
members:
- Profile.RobloxMetaData [table]
- Profile.UserIds [table]
- Profile.KeyInfo [DataStoreKeyInfo]
- Profile.KeyInfoUpdated [ScriptSignal] (key_info)
New Profile
methods:
- Profile:AddUserId()
- Profile:RemoveUserId()
- Profile:ClearGlobalUpdates() - View-mode (payload profile) only
- Profile:OverwriteAsync() - View-mode (payload profile) only
As always, you may update the module through github or the Roblox library.
bro a datastore update isnt worth ur eyesight
Anyways, amazing module, nice work!