say a player buys a devproduct that gives them 500 coins and they leave before the autosave cycle (every 30 seconds) takes place. Now regarding this I have two questions:
A) Does ProfileService keep that player’s data in the autosave queue, saves it to the datastore when the next autosave cycle takes place, and then clear it out/release the profile if the player is no longer in the game (or maybe the data is force saved when the profile is released?)
OR
B) will I have to call Profile:Save() to make sure that player’s purchase saves
EDIT: Went through the source code, ProfileService does seem to save the data when Profile:Release() is called
It would make sense to save it manually, since relying on autosave intervals doesn’t guarantee saved data. Are you saying after they fully leave the game? Because at that point the server is closed and profile service can’t save it even if it’s in a queue, if you’re saying right before they leave, then sure if the times match up, but I wouldn’t rely on it.
Could anyone guide me to how I would go about using this to save Skills. I understand that you can use this to save a profile that already has pre-writen data inside. But what if i wanted to add something new to the profile table without hardcoding it to the file before hand?
Sure thing!
So in my game, I save skills as a table of strings. It’s as simple as table.insert(profile.Data.Skills, “SkillName”) to unlock a skill. When a player character spawns, it will load the skills table and check through the tools folder in server storage for any tool that matches the name. If it finds it, then it clones it and places it in the player’s backpack. This is a very simple version, if your game has different systems then you may need to adjust this idea for it.
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:
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.
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.
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
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.
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.