Securing DataStore

--loading
local data = DataStore:GetAsync(plr.UserId)
	
	if data then
		Wins.Value = data.Wins
		crystalCoins.Value = data.crystalCoins
		
		if #skillInventory.Value > #data.skillInventory then
			for i = 1, #skillInventory.Value - #data.skillInventory do
				local InvTable = game.HttpService:JSONDecode(data.skillInventory)
				table.insert(InvTable, data.skillInventory[#data.skillInventory + i])
				data.skillInventory = game.HttpService:JSONEncode(InvTable)
			end
		end
		skillInventory.Value = data.skillInventory
		equippedInventory.Value = data.equippedInventory
	end
--saving 
DataStore:SetAsync(plr.UserId, {
			Wins = plr.leaderstats.Wins.Value,
			crystalCoins = plr.currencyFile.crystalCoins.Value,
			skillInventory = plr.inventoryFile.skillInventory.Value,
			equippedInventory = plr.inventoryFile.equippedInventory.Value
		})

here is my saving and loading code for the game. the point is that i don’t have any protection when it failed to load and save, how do i secure it?

1 Like

You can add pcall to see if it fails and if it fails try to save it again.

To check if it failed:

local success, errorMsg = pcall(function()
    DataStore:SetAsync(plr.UserId, {
			Wins = plr.leaderstats.Wins.Value,
			crystalCoins = plr.currencyFile.crystalCoins.Value,
			skillInventory = plr.inventoryFile.skillInventory.Value,
			equippedInventory = plr.inventoryFile.equippedInventory.Value
		})
end)

if not success then
    --Save failed
    warn(errorMsg)
end

Edit: Also you should do this for GetAsync too

1 Like

You can use pcall as @TalhaSa99 has mentioned above. To be extra secure, you should have some boolean that will determine if the load is successful. If it is unsuccessful, you should deny the save so it does not overwrite the player’s data with the default values.

so how should i do it with getAsync, like how do i set the values? Also i heard a thing that i should repeat the pcall serval times, how exactly do i do that? repeat?

local attempts = 0
		local successed = false
		repeat
			local success, errorMsg = pcall(function()
				DataStore:SetAsync(plr.UserId, {
					Wins = plr.leaderstats.Wins.Value,
					crystalCoins = plr.currencyFile.crystalCoins.Value,
					skillInventory = plr.inventoryFile.skillInventory.Value,
					equippedInventory = plr.inventoryFile.equippedInventory.Value
				})
				successed = true
			end)

			if not success then
				attempts = attempts+1
				warn(errorMsg)
			end
		until attempts > 3 or successed
``` sth like this?

Yes, something like this. Also you should add a wait before trying it again.

if not success then
	attempts = attempts+1
	warn(errorMsg)
	task.wait(5) -- waiting 5 seconds before trying it again.
end

If the data is nil and pcall doesnt give an error, probably the player is joining for the first time (If you didn’t reset), you can give a value by checking it.

how about repeating the Loading area?
here is my code rn

local success, errorMsg
	local data
	success, errorMsg= pcall(function()
		data = DataStore:GetAsync(plr.UserId)
	end)
	
	if data then
		Wins.Value = data.Wins
		crystalCoins.Value = data.crystalCoins
		
		if #skillInventory.Value > #data.skillInventory then
			for i = 1, #skillInventory.Value - #data.skillInventory do
				local InvTable = game.HttpService:JSONDecode(data.skillInventory)
				table.insert(InvTable, data.skillInventory[#data.skillInventory + i])
				data.skillInventory = game.HttpService:JSONEncode(InvTable)
			end
		end
		skillInventory.Value = data.skillInventory
		equippedInventory.Value = data.equippedInventory
	end

You can repeat the loading code, if it gives nil and doesnt give errors probably there isnt any data on this key, you can set the value to your default data, but as @Dragonfable6000 said you can add a bool to check the loading. If errors occured, dont overwrite the data.