How to make a DataStore work better

You could try this. I added some code to check if there is a tool in the player’s character, if there is then it saves that too.

local DataStore = game:GetService("DataStoreService"):GetDataStore("MyDataStore")

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

	local data

	local success, errorMessage = pcall(function()
		data = DataStore:GetAsync(plr.UserId)
	end)
	if data ~= nil then
		for _, toolName in pairs(data) do

			local tool = game.ReplicatedStorage.ToolsSaved:FindFirstChild(toolName)

			if tool then
				local newTool = tool:Clone()
				newTool.Parent = plr.Backpack

				local newTool = tool:Clone()
				newTool.Parent = plr.StarterGear

			end
		end
	end	
end)
game.Players.PlayerRemoving:Connect(function(plr)

	local toolsTable = {}

	for _, tool in pairs(plr.Backpack:GetChildren()) do
		if game.ReplicatedStorage.ToolsSaved:FindFirstChild(tool.Name) then
			table.insert(toolsTable,tool.Name)
		end
	end
       local toolcheck = plr.Character:FindFirstChildWhichIsA("Tool")
       if toolcheck then  
              table.insert(toolsTable,toolcheck.Name)
       end

	local success, errorMessage = pcall(function()
		DataStore:SetAsync(plr.UserId,toolsTable)
	end)

end)

game:BindToClose(function()
	for _, plr in pairs(game.Players:GetPlayers()) do
		local toolsTable = {}

		for _, tool in pairs(plr.StarterGear:GetChildren()) do
			if game.ReplicatedStorage.ToolsSaved:FindFirstChild(tool.Name) then
				table.insert(toolsTable,tool.Name)
			end
		end


		local success, errorMessage = pcall(function()
			DataStore:SetAsync(plr.UserId,toolsTable)
		end)	
	end
end)

while wait(10) do --Every 30 seconds loop through all of the players (you can also change this time to anything you want)
	for i, plr in pairs (game.Players:GetChildren()) do  --loop through all of the players
		local toolsTable = {}

		for _, tool in pairs(plr.StarterGear:GetChildren()) do
			if game.ReplicatedStorage.ToolsSaved:FindFirstChild(tool.Name) then
				table.insert(toolsTable,tool.Name)
			end
		end

		local success, errorMessage = pcall(function()
			DataStore:SetAsync(plr.UserId,toolsTable)
		end)	
	end
end

It will only kick the player if the script fails to load the data after 5 tries. It won’t randomly kick players.

I’m going to refer you to my other replies in regard to this specific post:

Oh! I never knew that you could repeat datastore attempts!

A new thing learned everyday! :slight_smile:

1 Like

The others are correct about equipped tools being lost. If the tool is equipped it is taken from the backpack and put into the character (A Descendant of workspace).

A fix for this would be to add in any tools inside the character into the table you are saving.

local Tools = {}

local SearchChar = Player.Character:GetDescendants()
for i = 1,#SearchChar do
    if SearchChar.ClassName == "tool" then
        table.insert(Tools,SearchChar[i].Name)
    end
end

2 Likes

A simpler way of doing this would just be:

local Tools = {}
if player.Character:FindFirstChildWhichIsA("Tool") then
       table.insert(Tools, player.Character:FindFirstChildWhichIsA("Tool").Name)
end
2 Likes

The first example you gave worked and I did not lose the tool when I equipped it and left.

1 Like

I strongly recommend splitting up your data persistence code into modules for saving/loading. Not doing so can make the whole thing difficult to edit and maintain. Second off, you should have pcalls retry themself if they don’t succeed. My current solution is having a set wait time, attempting the pcall, and if it fails, double the wait time and repeat. There are other things you may want to consider like making it stop retrying after a certain amount of tries, but that’s up to you.

Second, I don’t recommend using StarterGear as a spot to save things, this will create issues if the player leaves and you’re trying to save the data, the tools could get cleaned up by the time you’re saving it. Store any critical player info in a folder in ReplicatedStorage (or ServerStorage) instead so you don’t have to worry about that, and refer to it in other scripts like so.

1 Like

Yes but I am still not sure on how to make the pcalls inside there. Also I was not using StarterGear until someone suggested me to do so.

1 Like

Use pcalls, UpdateAsync and kicking the player when retrieving data causes an error and not saving anything if that happends…

Ooh, yeah. I was the one who suggested it, he was using Backpack which was much worse. So yeah, having that somewhere in ServerStorage, pretty good idea. Everytime a new child gets added probs.

Sure.

Before any request to the data store you should do:

Example:

local sucess, errorMsg = pcall(function()
    playerData = ds:GetAsync(plr.UserId)
end)

if not sucess and errorMsg then 
    --if the script didn't work and if there was an error then
    warn(errorMsg)
end

Sucess (first argument) would be a bool value, if it is true, the script went fine. If it’s false then something’s wrong.

errorMsg (second argument) will be usually a string contains info about any errors that happened in that function. Another thing you should be careful with, is that if you return anything inside this function, errorMsg gets set to that.

This method of pcalls is used to make it so that the script still works if there’s a problem retrieving info for example.

Would there be a way to make this keep repeating until true?