Feed Back On My Data Handler code

The code saves and loads the player’s data. It’s worked so far and I’ve had only one report of dataloss (It was because of a typo, not the code) But I want to make absolutely sure it will not corrupt data and will save it securely every time before I advertise the game. I’ve tested the code multiple times and it hasn’t thrown an error ever. But as I’m sure your aware, saving data properly is of utmost importance.
I’m terrible at coding datastores so I’m aware this code is probably a mess XD

Feedback Keynotes.
1: Any ways to make the code faster or more streamlined?
2: Are there any glaring issues with my code?
3: Possible redundancies

CODE FILE:
DataMain.rbxm (13.4 KB)

Code :

-- Services/DataStores
local DataStoreService = game:GetService("DataStoreService")
local DataStore = DataStoreService:GetDataStore("PlayerData")
local MS = game:GetService("MarketplaceService")
local DS2 = require(1936396537)

-- Variables
local OneHund = 1174259916
local TwoHund = 1174259915
local ThreeHund = 1174259912 
local FourHund = 1174259911
local FiveHund = 1174259910
local OneThous = 1174259909
local players = game:GetService("Players")
local Tries = 4

-- Functions


local function SaveData(plr,PlayerDataFolder)

	local PlrData = {}

	PlrData.Coins = PlayerDataFolder.Coins.Value
	PlrData.Level = PlayerDataFolder.Level.Value
	PlrData.XP = PlayerDataFolder.Experience.Value
	PlrData.MaxXP = PlayerDataFolder.MaxExperience.Value
	PlrData.EquippedSheepSkin = PlayerDataFolder.EquippedSheepSkin.Value
	PlrData.EquippedFarmerSkin = PlayerDataFolder.EquippedFarmerSkin.Value
	PlrData.EquippedWeaponSkin = PlayerDataFolder.EquippedWeaponSkin.Value
	PlrData.SheepSkins = {}
	PlrData.FarmerSkins = {}
	PlrData.WeaponSkins = {}
	PlrData.Codes = {}

	for index1, Skin in pairs(PlayerDataFolder.SheepSkins:GetChildren()) do
		table.insert(PlrData.SheepSkins,Skin.Name)
	end
	for index1, Skin in pairs(PlayerDataFolder.FarmerSkins:GetChildren()) do
		table.insert(PlrData.FarmerSkins,Skin.Name)
	end
	for index2, WeaponSkin in pairs(PlayerDataFolder.WeaponSkins:GetChildren()) do
		table.insert(PlrData.WeaponSkins,WeaponSkin.Name)
	end
	for index3, Code in pairs(PlayerDataFolder.Codes:GetChildren()) do
		table.insert(PlrData.Codes,Code.Name)
	end

	local succes, errormsg = pcall(function()
		if plr.Loaded.Value == true then
			if PlrData ~= nil then
				DataStore:SetAsync(plr.UserId,PlrData)
			else 
				print("No data, Cancelled save")
			end	
		end
	end)
	if succes then
		print("Saved")
	elseif errormsg then
		print(errormsg)
	end
end

local function GetData(plr,PlayerDataFolder)

	local data
	local count = 0
	local succes, errormsg
		repeat 
			succes, errormsg = pcall(function()
				
				data = DataStore:GetAsync(plr.UserId)

			end)
			count += 1
		until count >= Tries or succes
		if succes then
			print("Succes")
		elseif errormsg then
			print(errormsg)
		end
	if not succes then
		plr:Kick("A fatal Datastore error occured and You have been kicked to prevent data loss, Try rejoining")
	end
	if succes then
		if data ~= nil then
			if data.Level then
				PlayerDataFolder.Level.Value = data.Level
			end
			if data.XP then
				PlayerDataFolder.Experience.Value = data.XP
			end
			if data.MaxXP then
				PlayerDataFolder.MaxExperience.Value = data.MaxXP
			end
			if data.Coins then
				PlayerDataFolder.Coins.Value = data.Coins
			end
			if data.SheepSkins then
				for index, Skin in pairs(data.SheepSkins) do
					if not PlayerDataFolder.SheepSkins:FindFirstChild(Skin) then
						local SkinVal = Instance.new("StringValue")
						SkinVal.Name = Skin
						SkinVal.Parent = PlayerDataFolder.SheepSkins
					end
				end
			end
			if data.FarmerSkins then
				for index, Skin in pairs(data.FarmerSkins) do
					if not PlayerDataFolder.FarmerSkins:FindFirstChild(Skin) then
						local SkinVal = Instance.new("StringValue")
						SkinVal.Name = Skin
						SkinVal.Parent = PlayerDataFolder.FarmerSkins
					end
				end
			end
			if data.WeaponSkins then
				for index, Skin in pairs(data.WeaponSkins) do
					if not PlayerDataFolder.WeaponSkins:FindFirstChild(Skin) then
						local SkinVal = Instance.new("StringValue")
						SkinVal.Name = Skin
						SkinVal.Parent = PlayerDataFolder.WeaponSkins
					end
				end
			end
			if data.Codes then
				for index, Code in pairs(data.Codes) do
					local CodeVal = Instance.new("StringValue")
					CodeVal.Name = Code
					CodeVal.Parent = PlayerDataFolder.Codes
				end
			end
			if data.EquippedSheepSkin then
				--if not data.EquippedSheepSkin == "" then
					PlayerDataFolder.EquippedSheepSkin.Value = data.EquippedSheepSkin
				--end
			end
			if data.EquippedFarmerSkin then
				--if not data.EquippedFarmerSkin == "" then
					PlayerDataFolder.EquippedFarmerSkin.Value = data.EquippedFarmerSkin
				--end
			end
			if data.EquippedWeaponSkin then
				--if not data.EquippedWeaponSkin == "" then
					PlayerDataFolder.EquippedWeaponSkin.Value = data.EquippedWeaponSkin
				--end  
			end
		end
		plr.Loaded.Value = true
	end
end


-- Main Setup
game.Players.PlayerAdded:Connect(function(plr)
	-- Main Data Storage Folder
	
	local PlayerDataFolder = Instance.new("Folder")
	PlayerDataFolder.Name = "Data"
	PlayerDataFolder.Parent = plr
	
	local Level = Instance.new("IntValue",PlayerDataFolder)
	Level.Value = 1
	Level.Name = "Level"
	
	local XP = Instance.new("IntValue",PlayerDataFolder)
	XP.Value = 0
	XP.Name = "Experience"
	
	local MaxXP = Instance.new("IntValue",PlayerDataFolder)
	MaxXP.Value = 200
	MaxXP.Name = "MaxExperience"
	
	local DataLoaded = Instance.new("BoolValue")
	DataLoaded.Name = "Loaded"
	DataLoaded.Value = false
	DataLoaded.Parent = plr
	-- Coins
	local Coins = Instance.new("IntValue")
	Coins.Name = "Coins"
	Coins.Value = 0 
	Coins.Parent = PlayerDataFolder

	-- Skins
	local SkinsFolder = Instance.new("Folder")
	SkinsFolder.Name = "SheepSkins"
	SkinsFolder.Parent = PlayerDataFolder

	local FarmerSkinsFolder = Instance.new("Folder")
	FarmerSkinsFolder.Name = "FarmerSkins"
	FarmerSkinsFolder.Parent = PlayerDataFolder
	
	-- Weapons Skins
	local WeaponsSkinsFolder = Instance.new("Folder")
	WeaponsSkinsFolder.Name = "WeaponSkins"
	WeaponsSkinsFolder.Parent = PlayerDataFolder
	
	--Codes
	local CodesFolder = Instance.new("Folder")
	CodesFolder.Name = "Codes"
	CodesFolder.Parent = PlayerDataFolder
	
	-- Equipped
	local EquippedSheepSkin = Instance.new("StringValue")
	EquippedSheepSkin.Name = "EquippedSheepSkin"
	EquippedSheepSkin.Parent = PlayerDataFolder
	EquippedSheepSkin.Value = "Sheep"

	local EquippedFarmerSkin = Instance.new("StringValue")
	EquippedFarmerSkin.Name = "EquippedFarmerSkin"
	EquippedFarmerSkin.Parent = PlayerDataFolder
	EquippedFarmerSkin.Value = "Farmer"

	local EquippedWeaponSkin = Instance.new("StringValue")
	EquippedWeaponSkin.Name = "EquippedWeaponSkin"
	EquippedWeaponSkin.Parent = PlayerDataFolder
	EquippedWeaponSkin.Value = "ShotGun"

	--Base Skins
	local ShotGun = Instance.new("StringValue")
	ShotGun.Name = "ShotGun"
	ShotGun.Parent = WeaponsSkinsFolder
	
	local Sheep = Instance.new("StringValue")
	Sheep.Name = "Sheep"
	Sheep.Parent = SkinsFolder
	
	local Farmer = Instance.new("StringValue")
	Farmer.Name = "Farmer"
	Farmer.Parent = FarmerSkinsFolder

	GetData(plr,PlayerDataFolder)
	local SurvivalXp = Instance.new("IntValue",PlayerDataFolder)
	SurvivalXp.Value = 0
	SurvivalXp.Name = "SurvivalXP"
	
	local SurvivedTime = Instance.new("IntValue")
	SurvivedTime.Name = "SurvivalTime"
	SurvivedTime.Value = 0
	SurvivedTime.Parent = PlayerDataFolder
	
	local RoundCoins = Instance.new("IntValue")
	RoundCoins.Name = "RoundCoins"
	RoundCoins.Value = 0 
	RoundCoins.Parent = PlayerDataFolder

end)

game.Players.PlayerRemoving:Connect(function(plr)
	if plr:FindFirstChild("Loaded") then
		if plr.Loaded.Value == true then
			SaveData(plr,plr.Data)
		end
	end
end)

game:BindToClose(function()
	
	for index, plr in pairs(game.Players:GetChildren()) do
		if plr:FindFirstChild("Loaded") then
			if plr.Loaded.Value == true then
				SaveData(plr,plr.Data)
			end
		end
	end

end)




local function processReceipt(info)

	local plr = players:GetPlayerByUserId(info.PlayerId)
	if not plr then
		return Enum.ProductPurchaseDecision.NotProcessedYet
	end

	if plr then
		if info.ProductId == OneHund then
			plr:WaitForChild("Data").Coins.Value += 100
		end
		if info.ProductId == TwoHund then
			plr:WaitForChild("Data").Coins.Value += 200
		end
		if info.ProductId == ThreeHund then
			plr:WaitForChild("Data").Coins.Value += 300
		end
		if info.ProductId == FourHund then
			plr:WaitForChild("Data").Coins.Value += 400
		end
		if info.ProductId == FiveHund then
			plr:WaitForChild("Data").Coins.Value += 500
		end
		if info.ProductId == OneThous then
			plr:WaitForChild("Data").Coins.Value += 1000
		end
		SaveData(plr,plr.Data)
	end

	return Enum.ProductPurchaseDecision.PurchaseGranted
end

MS.ProcessReceipt = processReceipt
1 Like

why are the if statements turned into comments?

1 Like

There outdated code i was afraid to outwrite remove, nice catch

one thing I recommend is adding a space after the comma
it improves readability

oh ok, that makes sense

1 Like

Yeah, I’ve been realizing that the hard way lol.
Most of the code I wrote since this (about a few weeks ago) is better for readability

You can reduce all the variables to make instances by using a function with recursion

1 Like