Separate DataStores & Multiple Values - Improvement Needed

Greetings! I hope you’re having a great day so far.

Anywho, I’m looking to improve the organization of my data stores so that they’re more efficient (with respect to the limits of the DataStoreService). I’m not satisfied with the way my script is organized, as well as the inconsistency of data being saved/loaded.

For context, the code creates two values. The first is stored in a common leaderstats folder and is basically the currency for the game. The second value is stored directly inside of the player and represents the amount of Robux that the player has donated. My code is inside a server script, which is located in ServerScriptService.

Although my system works fine, there have been some rare occurrences where only the currency value is saved, and the donation amount is queued and dropped (resulting in the donation amount not being saved) when the player leaves the game. This is what I’m primarily worried about, and this also makes it clear that there’s definitely some room for improvement.

Code
local DataStoreService = game:GetService("DataStoreService")

local CashData = DataStoreService:GetDataStore("CashData")
local DonationData = DataStoreService:GetDataStore("DonationData")

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 donationamount = Instance.new("IntValue")
	donationamount.Name = "DonationAmount"
	donationamount.Parent = player
	
	local dataCASH
	local dataDONATION
	
	local success, errormessage = pcall(function()
		dataCASH = CashData:GetAsync(player.UserId .. "Cash")
		dataDONATION = DonationData:GetAsync(player.UserId .. "DonationAmount")
	end)
	
	if success then
		cash.Value = dataCASH
		donationamount.Value = dataDONATION
		print(player.Name .. " has joined the game. Their cash and donation stats have been successfully loaded.")
	else
		warn(player.Name .. " has joined the game. Their cash and donation stats COULD NOT be loaded due to an error. (" .. errormessage .. ")")
	end
	
end)

game.Players.PlayerRemoving:Connect(function(player)
	
	local success, errormessage = pcall(function()
		CashData:SetAsync(player.UserId .. "Cash", player.leaderstats.Cash.Value)
		DonationData:SetAsync(player.UserId .. "DonationAmount", player.DonationAmount.Value)
	end)
	
end)

game:BindToClose(function(player)
	
	local success, errormessage = pcall(function()
		CashData:SetAsync(player.UserId .. "Cash", player.leaderstats.Cash.Value)
		DonationData:SetAsync(player.UserId .. "DonationAmount", player.DonationAmount.Value)
	end)
	
	if success then
		print(player.Name .. " has left the game. Their cash and donation stats have been successfully saved.")
	else
		warn(player.Name .. " has left the game. Their cash and donation stats COULD NOT be saved due to an error. (" .. errormessage .. ")")
	end
	
end)

All suggestions will be greatly appreciated, as I wish to have the most efficient data store system for the game I’m working on. Thank you in advance!

Consider saving these values in a table as soon as possible. Saving separate keys for values that are that related becomes a pain later on. Also look into using :UpdateAsync() and using the DataId ‘tecnic’ shown here.

(Also your bind to close doesn’t make sense)

1 Like

Try saving data in a table, its good for the long term

heres a snip of my saving for my datastore


			local success, message
			local counter = 0
			local DataFolder = Data:FindFirstChild(self.Player.Name)

			local DataTable = {}
			DataTable.SaveValues = {}

			if DataFolder then
				DataTable.SaveID = DataFolder.SaveID.Value
				DataTable.SaveTable = self.SaveTable
				for SaveName, SaveValue in pairs(SaveValues) do
					local Value = DataFolder[SaveValue[2]][SaveName]
					DataTable.SaveValues[Value.Name] = {Value.Value, SaveValue[3]}
				end
				print("here")
				repeat
					success, message = pcall(function()
						DataStore:UpdateAsync(self.Key, function(OldData)
							if not OldData then
								return DataTable
							else
								local OldID = OldData.SaveID or 0
								if OldID == DataTable.SaveID then
									DataTable.SaveID += 1
									return DataTable
								end
							end
							warn("returned nil")
							return nil
						end)
					end)
					counter += 1
				until counter >= RepeatSaveAmount or success

				print(DataTable)

				if isLeaving then
					DataFolder:Destroy()
				end

				if success then
					if not isLeaving then
						DataFolder.SaveID.Value = DataTable.SaveID
						self.FailedAmount = 0
					end
				else
					if not isLeaving then
						self.FailedAmount += 1
						if self.FailedAmount >= FailedSaveAmount then
							self.Player:Kick("An error has occurred")
							return
						end
					end
				end

				self.CanSave = true

remember thats not all of it.
ever since i used that, i have never got any dataloss. its kinda like ds2 but no lag lol

1 Like