The big differences are that ProfileService has session locking (data will not be written until other servers have successfully saved the data), data reconciliation (where if you add new data to the data template, existing players will have that added to their data as well), service failure handling (if the datastores are down, it will attempt to manage it for you), etc.
There are a lot of great features most people wouldnt bother to add. It makes it super super unlikely to lose any data, which your players will thank you for.
1. Session locking wastes resources because the only way I can think of this is like using messagingService. Roblox instantly saves your data and I check if the data is outdated before saving anyways so if they notice that their data was lost and leave the game then rejoin it restores their data with mys ystem.
2. Data reconciliation: I already have this in my code where it checks if it will override existing data using Tick()
If you’re looking for an alternative to ProfileService, you could also try out Suphi’s DataStore module:
This datastore implementation helps handle some of the spin-locking nature from ProfileService’s session locking, which is something you may have issues with. There’s more details about the comparison of these modules in this video:
The best practice is to use a DataStore module like ProfileService or Suphi’s. ProfileService is battle-tested and has been used by a number of very popular games. It also addresses all of my concerns below.
Your script doesn’t have autosaving, so if the server crashes, you’ll lose all of your data.
Your script also attempts to fetch the player’s data 5 times, but if that fails, it will just set your data to the default template. When the player leaves the game, if the UpdateAsync call works, they’ve just lost their data.
Session locking is another big issue your script doesn’t address. This is prone to servers fighting over your player data. Which opens you up to dupe vulnerabilities.
There’s also no way for another script to call your edit/save functions since you don’t use a ModuleScript or expose any API to do that.
The function connected to PlayerRemoving function won’t work properly.
game.Players.PlayerRemoving:Connect(function(plr)
if #game.Players:GetPlayers() == 0 then
game:BindToClose(function()
saveData(plr)
end)
else
saveData(plr)
end
end)
According to documentation: Fires when a player is about to leave the game
Hence, GetPlayers() will not return an empty table.
Moreover, creating a connection to BindToClose under such weird condition is incorrect. BindToClose will trigger right after the sever is requested to be shut down.
It means, that when you decide to shutdown some server, the BindToClose will not trigger because it’s not yet initialized.
Move it out of PlayerRemoving and loop through the players saving their data.
Then, add a condition in PlayerRemoving to prevent double save.
You’re not checking whether the data has been loaded before saving them.
This is the most frequent cause of data loses so you should definitely make sure you’re handling it properly.
Generally, there’s more to improve, for example indexing directly the result of findData(). What if the data was not found?
Then, your script errors.
If you’re not experienced with creating data store systems, it’s recommended to use a battle-tested module which handles the difficulties for you.
I personally never used one but I had to learn from many mistakes.
if it still errors after 5 attempts, i will kick them and tell the player the game is experiencing issues
to adress crashes, i will add a module.save function for the developers. The developers should call this function during major events like beating a level or buying currency.
——
for session locking, i will add a lock boolean. Im still thinking about how i would do this without costing resources.
Still would trigger the PlayerRemoving event which would overwrite their data. You need to check to see if the module loaded their data before updating it in the PlayerRemoving event.
If you’re sharing a public module I would leave kicking up to the developer.
This is fair. ProfileService and other modules like it usually just autosave every 30 seconds or so.
I don’t see that logic in any of the snippets you’ve posted. It simply calls saveData in the PlayerRemoving event, which is why I assumed it’s an issue.
EDIT: This reply is referencing the code snippet(s) you posted in this thread. If you want people to review your DataStore module you should post it in #help-and-feedback:code-review so people aren’t confused.
local Players = game:GetService("Players")
Players.PlayerRemoving:Connect(saveData)
game:BindToClose(function()
for _, Player in ipairs(Players:GetPlayers()) do
saveData(Player)
end
end)