Help with datastores

As of now, I don’t have any datastore script for my game because I can’t find a working one. I have a leaderboard in my game called “Shells”, and I have even tried Roblox’s datastore script and many YouTube tutorials, but none of them worked. I really need this feature in my game as it would annoy players if the data didn’t save. Can someone please help me try and create a working datastore? I don’t need a full script, I just don’t know how I would type one and how I would get it to work.

Here’s a quick script I just wrote for you to look at to give you a starting point for learning about datastores:

local DSS = game:GetService("DataStoreService") 
local MyDataStore=DSS:GetDataStore("MyGame_PlayerData") -- You can name your datastore whatever you want

-- Function to get player data from datastore
local function GetDataFromDataStore(Player)

	local tries = 0	
	local success
	local PlrData
	repeat
		tries = tries + 1
		success = pcall(function() PlrData=MyDataStore:GetAsync(Player.userId) end)
		if not success then wait(3) end
	until tries == 3 or success
	if not success then warn("Cannot Read Player Data!") return false end
	return PlrData

end

-- Function to save player data to datastore
local function SaveDataToDataStore(Player)

	if Player then
		local PlrData=Player.Data.Cash.Value
		
		local tries = 0	
		local success
		repeat
			tries = tries + 1
			success = pcall(function() MyDataStore:SetAsync(Player.userId, PlrData)end)
			if not success then wait(3) end
	    until tries == 3 or success
	    if not success then warn("Couldn't Save Player Data!") return false else return true end
    end
	
end

 -- function to setup player data when joined
local function NewPlayer(Player)
	
	-- Setup the new player with a folder to store their data
	local PlrFolder = Instance.new("Folder")           
	PlrFolder.Name = "Data"         	
	PlrFolder.Parent = Player
	local Cash=Instance.new("IntValue")
	Cash.Name="Cash"
	Cash.Parent=PlrFolder
	
	Cash.Value=GetDataFromDataStore(Player) or 0  -- Check if datastore has save for player, if not cash=0
	
	
end


game:GetService("Players").PlayerAdded:Connect(NewPlayer)
game:GetService("Players").PlayerRemoving:Connect(SaveDataToDataStore)

Datastores are fairly easy to use, but are prone to errors and subsequent data loss. Instead of using datastores directly, you should take a look at DataStore2 and ProfileService. ProfileService offers an enormours array of features, but might be difficult to setup for beginners. DataStore2 is much more limited, but easier to use.

In case you want to use Roblox’s datastore service, first call service:GetDatastore(storename) (in your case, the name would be “shells” or something). This will get the previously created datastore or create a new one.

There are 2 methods for saving data: SetAsync(keyname,value) and UpdateAsync(keyname,function). UpdateAync accepts 2 arguments, one being the key’s name (usually the ID of the player you want to save the data for) and the other being a function that should return the value you want to save. That function’s argument is the existing value so you can handle any issues properly. I would recommend never using SetAsync as it essentially brute forces the data into the store, ignoring whether some other server is trying to edit it., while UpdateAsync runs in a queue.

There is only one method for getting data: GetAsync(keyname). Don’t really need to explain much here.

When saving data, make sure your table doesn’t have mixed indices (numbers only or strings only) and that the values don’t contain and instances as you might end up with weird bugs.

Finally, make sure you wrap all method calls in pcall as any internal error will stop your script. By catching that exception, you can handle the errors properly and quickly debug in case it was a mistake on your end.

I’m not going to write anything about DataStore2 and ProfileService here as they have more than enough good tutorials.

Okay, thank you. So if I were to use something like this, would I change cash to shells?

1 Like

You should not be promoting this script. Repeating saving requests until they go through is never a good way to force a save.

Yes.
Also I forgot to mention to Enable Studio Access to API Services in your game settings to use Datastores

Ok. This would work in a normal script if I put it in ServerScriptService, right?

1 Like

They aren’t repeated until they go through, it gets retried a max of 3 times.
The script is basically the same as the one Roblox uses when teaching people about DataStores:
https://developer.roblox.com/en-us/articles/Saving-Player-Data
which includes the repeat … until tries == 3 or success so tell them not me.

1 Like

I’m surprised that’s that what they have listed. I suppose capping it as three isn’t too bad in the case of an error. Sorry

2 Likes

The cases between your code and the thread that got linked are completely different so raising that thread here was a fairly irrelevant misuse of a response I made earlier.

As Roblox has disabled automatic retries on the backend due to internal technical complications, developers are expected to create their own retry logic when appropriate. In the case of the linked thread, OP seemed to want to circumvent budget limits and force data to load without doing any proper handling in the case of an error. That’s the root of the response.

In your case it is fine because you have a limitation to the amount of times that a DataStore request can be performed as well as a respect to rate limits. That being said, however, your own code also poses problems in the DataStore workflow that need attention.

Retry logic can be very useful to have but not if you aren’t going to do anything in the case of a failed load. Setting up that retry logic without doing any error handling may cause data loss, especially noting the fact that you’re using a bad DataStore anti-pattern, Get or nil. The case of a failed load is not respected, so players who encounter DataStore errors will lose data with your code.

If you add error handling to your code, then you’ll also be able to get more information about a fetch request and block save requests that might cause data loss. For example, your load code will either return the value of a DataStore key or nil but no information on why it was nil. Was it a load error or has the player not had data stored before? Should we process future save requests or no?

As for your save function, you can cut out all that retry logic if you just use UpdateAsync. UpdateAsync is the canonical and proper method of updating DataStore keys and it has the right tooling to do the job as well. The data currently saved to the key you want to update is provided as a parameter to the function given to update data and its called as many times as needed to ensure data gets saved. SetAsync does not perform any data validation and should only be used if you need to force-write a value to a key one time.

I typed the script into ServerScriptService as a normal script, and I tested it in studio and as a published game, but it didn’t save anything.

I copied the code you sent and just changed everything to shells, am I doing something wrong?