DataStore only updates/saves once?

  1. What do you want to achieve?
    I’d like to have the data be saved each time the user leaves or is about to leave.

  2. What is the issue?
    In the script, when the player leaves it should print “Data saved successfully” or something along those lines. The first time I wrote this code and tested it, it clearly saved indicated by the “Data Saved” print in the output. When I rejoin the data isn’t loaded though and my data is registered as “New Data”

  3. What solutions have you tried so far?
    I have tried 0 solutions. Do note that the code is taken from a tutorial I am following.

ShopServer script inside ServerScriptService. API access is turned on.

local DataStoreService = game:GetService("DataStoreService")
local Players = game:GetService("Players")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local towers = require(ReplicatedStorage:WaitForChild("TowerShop"))
local database = DataStoreService:GetDataStore("database")


local MAX_SELECTED_TOWERS = 5

local data = { 
	
}
local defaultData = {
	["Gems"] = 100,
	["SelectedTowers"] = {"Cutler"},
	["OwnedTowers"] = {"Cutler", "Gunslinger"}
}


local function LoadData(player)
	local success = nil
	local playerData = nil
	local attempt = 1
	
	
	repeat
		success, playerData = pcall(function()
			return database:GetAsync(player.UserId)
		end)
		
		attempt += 1
		if not success then
			warn(playerData)
			task.wait()
		end
	until success == true or attempt == 3
	
	if success then
		print("Connection established")
		if not playerData then
			print("New player, giving default data")
			playerData= {
				["Gems"] = 100,
				["SelectedTowers"] = {"Cutler"},
				["OwnedTowers"] = {"Cutler", "Gunslinger"}
			}
		end
		data[player.UserId] = playerData
	else
		warn("Unable to get data for player", player.UserId)
		player:Kick("There was a problem loading your data! Message the developer on Roblox if this problem continues!")
	end
end

Players.PlayerAdded:Connect(LoadData)

local function SaveData(player)
	if data[player.UserId] then
		local success = nil
		local playerData = nil
		local attempt = 1


		repeat
			success, playerData = pcall(function()
				return database:UpdateAsync(player.UserId, function()
					return data[player.UserId]
				end)
			end)

			attempt += 1
			if not success then
				warn(playerData)
				task.wait()
			end
		until success == true or attempt == 3

		if success then
			print("Data saved successfully")
			
		else
			warn("Unable to save data for", player.UserId)
		end
	else
		warn("No session data for", player.UserId)
	end
	
	
	
	
end


Players.PlayerRemoving:Connect(SaveData)

local function GetItemStatus(player, itemName)
	local playerData = data[player.UserId]
	if table.find(playerData.SelectedTowers, itemName) then
		return "Equipped"
	elseif table.find(playerData.OwnedTowers, itemName) then
		return "Owned"
	else
		return "For Sale"
	end
end

ReplicatedStorage.InteractItem.OnServerInvoke = function(player, itemName)
	local shopItem = towers[itemName]
	local playerData = data[player.UserId]
	if shopItem and playerData then
		local status = GetItemStatus(player, itemName)
		
		if status == "For Sale" and shopItem.Price <= playerData.Gems then
			-- Purchase
			playerData.Gems -= shopItem.Price
			table.insert(playerData, shopItem.Name)
		elseif status == "Owned" then
			--Equip Tower
			table.insert(playerData.SelectedTowers, shopItem.Name)
			if #playerData.SelectedTowers > MAX_SELECTED_TOWERS then
				table.remove(playerData.SelectedTowers, 1)
			end
		elseif status == "Equipped" then
			-- Unselect tower
			if #playerData.SelectedTowers > 1 then
				local towerToRemove = table.find(playerData.SelectedTowers, itemName)
				table.remove(playerData.SelectedTowers, towerToRemove)
			end
		end
		return playerData
	else
		warn("Tower/Player Data Does Not Exist!")
	end
	return false
end

ReplicatedStorage.GetData.OnServerInvoke = function(player)
	return data[player.UserId]
end

If you need anymore information then please let me know!

Try this, I modified a few things

local function LoadData(player)
	local success
	local playerData
	local attempt = 1
	
	
	repeat
		success, errormessage = pcall(function()
			playerData = database:GetAsync(player.UserId)
		end)
		
		attempt += 1
		if not success then
			warn(errormessage)
			task.wait()
		end
	until success or attempt == 3
	
	if success then
		print("Connection established")
		if playerData == nil then
			print("New player, giving default data")
			playerData= {
				["Gems"] = 100,
				["SelectedTowers"] = {"Cutler"},
				["OwnedTowers"] = {"Cutler", "Gunslinger"}
			}
		end
		data[player.UserId] = playerData
		print(data[player.UserId]) --prints the loaded data for debugging. you can remove this later.
	else
		warn("Unable to get data for player", player.UserId)
		player:Kick("There was a problem loading your data! Message the developer on Roblox if this problem continues!")
		warn(errormessage)
	end
end

Try the script again, I had to edit the post a few times

The issue is still occurring with your edited code you’ve sent me.

I forgot to remove the local from playerData. Try my script again and see if you get any errors.

edit: just saw your updated reply

local function LoadData(player)
	local playerData
	local attempt = 1
	
	
	local success, errormessage = pcall(function()
		playerData = database:GetAsync(player.UserId)
	end)
		
	if not success then
		warn("Error with loading data. Error: "..errormessage)
		player:Kick("There was a problem loading your data! Message the developer on Roblox if this problem continues!")
		return
	end
	
	if success then
		print("Got data successfully.")
		print(playerData)
		if playerData == nil then
			print("New player, giving default data")
			playerData = {
				["Gems"] = 100,
				["SelectedTowers"] = {"Cutler"},
				["OwnedTowers"] = {"Cutler", "Gunslinger"}
			}
		end
		data[player.UserId] = playerData
		print(data[player.UserId]) --prints the loaded data for debugging. you can remove this later.
	end
end

Also, change this in your save script

success, errormessage = pcall(function()
	database:SetAsync(player.UserId, data[player.UserId])
end)
if success then
	print("Saved data for"..player.Name)
else
	warn(errormessage)
end

I’ve made the changes and no “Data Saved” message appeared and it just reverts data. No errors appear at all.

Here is my updated code, maybe I made a change that were made wrong?

local DataStoreService = game:GetService("DataStoreService")
local Players = game:GetService("Players")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local towers = require(ReplicatedStorage:WaitForChild("TowerShop"))
local database = DataStoreService:GetDataStore("database")


local MAX_SELECTED_TOWERS = 5

local data = { 
	
}
local defaultData = {
	["Gems"] = 100,
	["SelectedTowers"] = {"Cutler"},
	["OwnedTowers"] = {"Cutler", "Gunslinger"}
}


local function LoadData(player)
	local playerData
	local attempt = 1


	local success, errormessage = pcall(function()
		playerData = database:GetAsync(player.UserId)
	end)

	if not success then
		warn("Error with loading data. Error: "..errormessage)
		player:Kick("There was a problem loading your data! Message the developer on Roblox if this problem continues!")
		return
	end

	if success then
		print("Got data successfully.")
		print(playerData)
		if playerData == nil then
			print("New player, giving default data")
			playerData = {
				["Gems"] = 100,
				["SelectedTowers"] = {"Cutler"},
				["OwnedTowers"] = {"Cutler", "Gunslinger"}
			}
		end
		data[player.UserId] = playerData
		print(data[player.UserId]) --prints the loaded data for debugging. you can remove this later.
	end
end

Players.PlayerAdded:Connect(LoadData)

local function SaveData(player)
	if data[player.UserId] then
		local success = nil
		local playerData = nil
		local attempt = 1
		local errormessage = nil

		repeat
			success, errormessage = pcall(function()
				return database:SetAsync(player.UserId, data[player.UserId])
			end)

			attempt += 1
			if success then
				print("Saved Data For " .. player.Name )
			else
				warn(errormessage)
			end
		until success == true or attempt == 3

		--if success then
		--	print("Data saved successfully")

		--else
		--	warn("Unable to save data for", player.UserId)
		--end
	else
		warn("No session data for", player.UserId)
	end




end


Players.PlayerRemoving:Connect(SaveData)

local function GetItemStatus(player, itemName)
	local playerData = data[player.UserId]
	if table.find(playerData.SelectedTowers, itemName) then
		return "Equipped"
	elseif table.find(playerData.OwnedTowers, itemName) then
		return "Owned"
	else
		return "For Sale"
	end
end

ReplicatedStorage.InteractItem.OnServerInvoke = function(player, itemName)
	local shopItem = towers[itemName]
	local playerData = data[player.UserId]
	if shopItem and playerData then
		local status = GetItemStatus(player, itemName)
		
		if status == "For Sale" and shopItem.Price <= playerData.Gems then
			-- Purchase
			playerData.Gems -= shopItem.Price
			table.insert(playerData, shopItem.Name)
		elseif status == "Owned" then
			--Equip Tower
			table.insert(playerData.SelectedTowers, shopItem.Name)
			if #playerData.SelectedTowers > MAX_SELECTED_TOWERS then
				table.remove(playerData.SelectedTowers, 1)
			end
		elseif status == "Equipped" then
			-- Unselect tower
			if #playerData.SelectedTowers > 1 then
				local towerToRemove = table.find(playerData.SelectedTowers, itemName)
				table.remove(playerData.SelectedTowers, towerToRemove)
			end
		end
		return playerData
	else
		warn("Tower/Player Data Does Not Exist!")
	end
	return false
end

ReplicatedStorage.GetData.OnServerInvoke = function(player)
	return data[player.UserId]
end

If you’re testing in studio, data saving in studio is (from my experience) very unreliable, try testing in an actual game server
Other than that nothing appears to be wrong with the script (except for maybe UpdateAsync)

My Modified Version of the provided script

local DataStoreService = game:GetService("DataStoreService")
local Players = game:GetService("Players")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local towers = require(ReplicatedStorage:WaitForChild("TowerShop"))
local database = DataStoreService:GetDataStore("database")


local MAX_SELECTED_TOWERS = 5

local data = { 
	
}
local defaultData = {
	["Gems"] = 100,
	["SelectedTowers"] = {"Cutler"},
	["OwnedTowers"] = {"Cutler", "Gunslinger"}
}


local function LoadData(player)
	local success = nil
	local playerData = nil
	local attempt = 1
	
	while not success and attempt < 4 do
		success, playerData = pcall(function()
			return database:GetAsync(player.UserId)
		end)
		if not success then
			attempt += 1
			warn(playerData)
			task.wait()
		end
	end
	--[[			Repeat until is often unreliable
	repeat
	until
	]]
	if success then
		print("Data Loaded Successfully")  --Why connection established??
		if not playerData then
			print("New player, giving default data")
			playerData= {
				["Gems"] = 100,
				["SelectedTowers"] = {"Cutler"},
				["OwnedTowers"] = {"Cutler", "Gunslinger"}
			}
		end
		data[player.UserId] = playerData
	else
		warn("Unable to get data for player", player.UserId)
		player:Kick("There was a problem loading your data! Message the developer on Roblox if this problem continues!")
	end
end

Players.PlayerAdded:Connect(LoadData)

local function SaveData(player)
	if data[player.UserId] then
		local success = nil
		local playerData = nil
		local attempt = 1

		while not success and attempt < 4 do
			success, playerData = pcall(function()
				database:SetAsync(player.UserId, data[player.UserId])
				--[[			UpdateAsync overcomplicates things in my opinion
				return database:UpdateAsync(player.UserId, function()
					return data[player.UserId]
				end)
				]]
			end)

			if not success then
				attempt += 1
				warn(playerData)
				task.wait()
			end
		end
		--[[				Again repeat until is often unreliable
		repeat
		until success == true or attempt == 3
		]]
		if success then
			print("Data saved successfully")
			
		else
			warn("Unable to save data for", player.UserId)
		end
	else
		warn("No Data for", player.UserId)
	end
	
	
	
	
end


Players.PlayerRemoving:Connect(SaveData)

-- I won't bother changing anything else

local function GetItemStatus(player, itemName)
	local playerData = data[player.UserId]
	if table.find(playerData.SelectedTowers, itemName) then
		return "Equipped"
	elseif table.find(playerData.OwnedTowers, itemName) then
		return "Owned"
	else
		return "For Sale"
	end
end

ReplicatedStorage.InteractItem.OnServerInvoke = function(player, itemName)
	local shopItem = towers[itemName]
	local playerData = data[player.UserId]
	if shopItem and playerData then
		local status = GetItemStatus(player, itemName)
		
		if status == "For Sale" and shopItem.Price <= playerData.Gems then
			-- Purchase
			playerData.Gems -= shopItem.Price
			table.insert(playerData, shopItem.Name)
		elseif status == "Owned" then
			--Equip Tower
			table.insert(playerData.SelectedTowers, shopItem.Name)
			if #playerData.SelectedTowers > MAX_SELECTED_TOWERS then
				table.remove(playerData.SelectedTowers, 1)
			end
		elseif status == "Equipped" then
			-- Unselect tower
			if #playerData.SelectedTowers > 1 then
				local towerToRemove = table.find(playerData.SelectedTowers, itemName)
				table.remove(playerData.SelectedTowers, towerToRemove)
			end
		end
		return playerData
	else
		warn("Tower/Player Data Does Not Exist!")
	end
	return false
end

ReplicatedStorage.GetData.OnServerInvoke = function(player)
	return data[player.UserId]
end

Thank you, I didn’t think of Studio being unstable at all. It seems to work perfectly! Thank you so much!

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.