How do you store data properly?

I havent made a game with a datastore before

what is the most efficient way to store data?

this how i store

local DSS = game:GetService("DataStoreService")
local Data =DSS:GetDataStore("Data")

game.Players.PlayerAdded:Connect(function(Player)

	local PlayerStat = Data:GetAsync(Player.UserId) or { 
		["Coins"] = 0,
		["Rank"] = 0,
	}	
	
	local Coins = PlayerStat.Coins
	local Rank = PlayerStat.Rank
	
end)

local function SetData(Player)
	Data:SetAsync(Player.UserId,
		{
			["Coins"] = VALUE_TO_STORE,  
			["Rank"] = VALUE_TO_STORE, 
		}
	)
end

game.Players.PlayerRemoving:Connect(SetData)

game:BindToClose(function()
	for _, Player in pairs(game.Players:GetPlayers()) do
		SetData(Player)
	end
end)

i found lots of topics make data store but i really couldnt understand them
like profile service thingy

1 Like

Is this method working for you? This looks pretty good to me. I think this is an excellent and optimized data storage system.

1 Like

There’s no single “proper” way to save it, many devs have different styles so your script is ok. There are definitely wrong ways though, but as long as you aren’t using several DataStores to save several values (with the exception of OrderedDataStores, this is generally the right way to do it, with an array. However, you need to add pcalls because :SetAsync and :GetAsync aren’t guaranteed to not error.

I’d also suggest that in your BindToClose function, you call SetData in a separate thread because it yields, if it yields for a long time for some reason, it won’t set before the server shuts down, causing data loss.

1 Like

It’s not 100% excellent, there are a lot of edge cases this piece of code doesn’t consider, like the player leaving before their data is loaded. So ultimately I would recommend they use ProfileService which handles every edge case you might fall in, and profile service makes data saving even easier than what roblox already provides.

1 Like

Since nothing would be yielding, BindToClose would shut the server down immediately and not save anyway. I’d recommend keeping the server open until every player has left, and showing a UI which tells players to rejoin once their data has finished saving. Use task.spawn() to separate the thread so that it wont yield for other players. Something like

game:BindToClose(function()
	for _, Player in pairs(game.Players:GetPlayers()) do
        task.spawn(function())
		    SetData(Player)
        end
	end

    --maybe here fire some remote to tell players that the server is shutting down

    repeat --keeps the server open until everybody has left, BindToClose automatically force shutsdown after 30 seconds so no need to worry about it staying open forever.
       task.wait(1)
    until #game:GetPlayers() <= 0
end)

Yeah, you’d have to make a function that yields until everyone is saved, however if you did one player after the other, it would keep saving players in order which would take a longer amount of time (if you have 10 players, it would take 10x the amount of time) than if you were to save everything at the same time.

1 Like

You have a mistype here, and also you should probably use GetOrderedDataStore(“Data”)
Also when saving the data, make the script put it in a folder