DataStore Does Not Want To Work

Hello, so I’ve been trying to save Cash in my game for the past 2 days and I can just not figure out why it’s not working. This is my code:

local DataStoreService = game:GetService("DataStoreService")
local myDataStore = DataStoreService:GetDataStore("myDataStore")

game.Players.PlayerAdded:Connect(function(player)
	local leaderstats = Instance.new("Folder")
	leaderstats.Name = "leaderstats"
	leaderstats.Parent = player
	
	local Cash = Instance.new("IntValue")
	Cash.Name = "Cash"
	Cash.Parent = leaderstats
	
	local playerUserId = "Player_"..player.UserId
	local data
	local success, errormessage = pcall(function()
		data = myDataStore:GetAsync(playerUserId)
	end)
	
	if success then
		Cash.Value = data
	end
end)

game.Players.PlayerRemoving:Connect(function(player)
	local playerUserId = "Player_"..player.UserId
	local data = player.leaderstats.Cash.Value
	local success, errormessage = pcall(function()
	myDataStore:SetAsync(playerUserId, data)	
	end)
	if success then
		print("data loaded")
	else
		print("error occur")
	end
end)

Any help would be appreciated, thank you for reading.

Are you attempting this in studio or in the actual game? I would also recommend you to use BindToClose.

I’m attempting it in studio, and yes my API permissions to DataStores are enabled.image

Okay, I think the issue is that .PlayerRemoved gets fired but SetAsync does not complete quickly enough. This can be fixed by using BindToClose as you are able to save the data before the server shuts down completely.

It saves the amount that I give the player, but it doesn’t save the new amount when a player buys something. Example: I give the player 1000 cash, they rejoin and they still have 1,000 cash. They buy something from the in-game shop for 100 cash. Their cash goes to 900. They rejoin and then their cash is 1,000 again.

New script with the BindToClose:

local DataStoreService = game:GetService("DataStoreService")
local myDataStore = DataStoreService:GetDataStore("myDataStore")

game.Players.PlayerAdded:Connect(function(player)
	local leaderstats = Instance.new("Folder")
	leaderstats.Name = "leaderstats"
	leaderstats.Parent = player
	
	local Cash = Instance.new("IntValue")
	Cash.Name = "Cash"
	Cash.Parent = leaderstats
	
	local playerUserId = "Player_"..player.UserId
	local data
	local success, errormessage = pcall(function()
		data = myDataStore:GetAsync(playerUserId)
	end)
	
	if success then
		Cash.Value = data
	end
end)

game.Players.PlayerRemoving:Connect(function(player)
	local playerUserId = "Player_"..player.UserId
	local data = player.leaderstats.Cash.Value
	local success, errormessage = pcall(function()
	myDataStore:SetAsync(playerUserId, data)	
	end)
	if success then
		print("data loaded")
	else
		print("error occur")
	end
end)

game:BindToClose(function()
	local RunService = game:GetService("RunService")
	local Players = game:GetService("Players")

	if RunService:IsStudio() then
		return
	end

	print("saving player data")


	local players = Players:GetPlayers()
	for _, player in pairs(players) do
		local userId = player.UserId
		local data = myDataStore[userId]
		if data then

			local success, result = pcall(function()

				myDataStore:SetAsync(userId, data)
			end)
			if not success then
				warn(result)
			end    
		end
	end

	print("completed saving player data")

end)

I don’t think you are able to index a Datastore instance like that, instead you would probably want to get it from a locally stored user cache.

1 Like

May you explain it a bit more depth or write a code for it? I do not understand the
“Locally stored user cache” part and what it does.

I changed it to this now, about to test it out:

local data = myDataStore:GetAsync(playerUserId)

That wouldn’t make a difference as you would be getting the current data and not the updated one. Since I assume you want to be storing their cash you can do something like this:

local data = player.leaderstats.Cash.Value
1 Like

Still did not work, no idea why.

If you are still testing it in studio, I’d recommend you to remove this line:

if RunService:IsStudio() then
	return
end

If it still does not work then check if you are getting any error messages in the output.

I’m testing them in the ROBLOX game, not in Roblox Studio anymore since that’s there, so that’s not the problem as of now.

1 Like

No errors regarding the datastore in my output.

I saw you asking for help in HD, this should work:

local DataStoreService = game:GetService("DataStoreService")
local myDataStore = DataStoreService:GetDataStore("myDataStore")
local DefaultAmount = 200

game.Players.PlayerAdded:Connect(function(player)
	local leaderstats = Instance.new("Folder")
	leaderstats.Name = "leaderstats"
	leaderstats.Parent = player

	local Cash = Instance.new("IntValue")
	Cash.Name = "Cash"
	Cash.Parent = leaderstats

	local playerUserId = "Player_"..player.UserId
	local data
	local success,data = pcall(function()
		return myDataStore:GetAsync(playerUserId)
	end)
	print(data)

	if (success and data) then
		Cash.Value = data
	elseif (success and not data) then
		Cash.Value = DefaultAmount
	end 
end)

game.Players.PlayerRemoving:Connect(function(player)
	local playerUserId = "Player_"..player.UserId
	local data = player.leaderstats.Cash.Value
	local success, errormessage = pcall(function()
		myDataStore:SetAsync(playerUserId, data)
	end)
	if success then
		print("data loaded")
	else
		print("error occur")
	end
end)

Make sure you are using a server script for the datastore and that any changes to the Cash.Value are made on the server or the datastore won’t be able to save that data I added a default amount of 200 so you can make sure it’s actually saving by seeing what print(data) prints.

Hope this solves your problem.

I’m sure this will solve your queries. This method is a very short method. You can compare your code with this and in case it errors, feel free to contact me. If I helped, mark as the solution :slight_smile: I’ll also advise you to change the topic name.

local DataStoreService = game:GetService("DataStoreService")
local myDataStore = DataStoreService:GetDataStore("myDataStore")
local playersLeft = 0

game.Players.PlayerAdded:Connect(function(player)
	playersLeft += 1
	local leaderstats = Instance.new("Folder",player)
	leaderstats.Name = "leaderstats"
	
	local Cash = Instance.new("IntValue",leaderstats)
	Cash.Name = "Cash"
	
	pcall(function()
		Cash.Value= myDataStore:GetAsync(player.UserId.."-Cash") or 0
	end)

end)

local BindableEvent = Instance.new("BindableEvent")

game.Players.PlayerRemoving:Connect(function(player)
	pcall(function()
		myDataStore:SetAsync(player.UserId.."-Cash", player.leaderstats.Cash.Value)	
	end)
	playersLeft -= 1
	BindableEvent:Fire()
end)

game:BindToClose(function()
	while playersLeft > 0 do
		BindableEvent.Event:Wait()
	end	
end)

I looked into the problem further and managed to solve it. When the BindToClose handler gets called, GetPlayers might return no players. To fix this we have to store all players who join in a table, we of course remove them once their data is saved.

image

local DataStoreService = game:GetService("DataStoreService")
local myDataStore = DataStoreService:GetDataStore("myDataStore")

local players = {}

local function GetData(player)
	local playerUserId = "Player_"..player.UserId
	local data
	local success, err = pcall(function()
		data = myDataStore:GetAsync(playerUserId)
	end)
	
	if (not success) then
		warn(err)
	end
	
	print("Got data", playerUserId, data)
	return success and data or 0
end

local function SaveData(player)
	local playerUserId = "Player_" .. player.UserId
	local data = player.leaderstats.Cash.Value
	print("Saving", playerUserId, data)
	
	local success, result = pcall(function()
		myDataStore:SetAsync(playerUserId, data)
	end)
	if not success then
		warn(result)
	end
	
	print("Saved data", playerUserId)
	
	return success
end

game.Players.PlayerAdded:Connect(function(player)
	local leaderstats = Instance.new("Folder")
	leaderstats.Name = "leaderstats"
	leaderstats.Parent = player

	local Cash = Instance.new("IntValue")
	Cash.Name = "Cash"
	Cash.Parent = leaderstats
	Cash.Value = GetData(player)
	
	players[player] = player
end)

game.Players.PlayerRemoving:Connect(function(player)

	
	-- If we are in studio let BindToClose save the data
	local RunService = game:GetService("RunService")
	if (RunService:IsStudio()) then
		return
	end
	
	players[player] = nil
	
	SaveData(player)
end)

game:BindToClose(function()
	local Players = game:GetService("Players")

	for _, player in pairs(players) do
		SaveData(player)
		players[player] = nil
	end

	print("completed saving player data")
end)
1 Like

Did not work for some reason. :man_shrugging:

Did not work either. No idea why datastores have so many problems…

Where should I put the BindableEvent?

1 Like

Updated! Sorry, forgot that in haste. It’ll come above PlayerRemoving Event.

1 Like