Any feedback within my Data Store

Secure Data Store

Hello i’m DylTheDeveloperX i do my own Secure Data Store back then last month and i get alot of source in Social Media, to know how will i handle Data Loss.

Things I do :

  • BindToClose()
  • Update Async
  • Repeat Until Sucess Per Minute
  • If player leave then repeat until sucess wont work!
  • Auto Save()
  • When GetAsync() fails then it wont save!
  • Wrappers for loading data!
  • Pcalls.

Model :

Questions ?

  • How can i improve this data store?

Code :

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

--      [[ SETTINGS]]   --
local tries = 3 -- Retries
local Closing = 8.5 -- When shutdowns wait() dont make it higher than 8
local tries2 = 3 -- Dont set it higher than 4 because its part of BindToClose()
local Slowdown = 60 -- Slowdown GetAsync()
local AutoSaved = 60 -- Auto saving wait()
local IsInGame = {} -- In this variable will verify if Player still in game.	
local dataLoaded = {} -- Tables per Saves.

local function Set(plr)
	local key = "plr-" .. plr.UserId
	
	IsInGame[key] = true -- Means Closed Case
	
	-- Notifier if dataLoaded = false 
	
	if dataLoaded[key] == false then
		warn("We cant save the value because the dataLoaded key is = false " .. key)
	end
	
	if dataLoaded[key] == true then -- Make sure it loads
		
		local count = 0
		
		
			local data = {
				
			["Coins"] = plr.leaderstats.Coins.Value,
			
			}
		
		-- Repeating when player leave will cause bug that's why AutoSaves is here.
		
		--[[ Example : ]]
		
		-- Player loss his data while leaving then when she rejoin his data will retrieve because of AutoSaves
		
		-- 3 Parts Of Saving --
		
		-- When players leave.
		-- When game Shutdown.
		-- Autosaves.
		
		local sucess, err
		
			sucess, err = pcall(function()
				myDataStore:UpdateAsync(key, function(oldValue)
				local newValue = data or oldValue or 0
				
					return newValue
				end)
			end)
			
		if not sucess then
			warn("Failed to set the value. Error code: " .. tostring(err))
				return
			end
	else
		
		return
		end
	
end

local function Get(plr, value)
	
	local key = "plr-" .. plr.UserId
	
	IsInGame[key] = false -- When they just join
	
	local count = 0
	
	
	local data
	
	local sucess, err
	
	if IsInGame[key] == false then
		
	
	repeat 
			sucess, err = pcall(function()
				
				 data = myDataStore:GetAsync(key)
		end)
			
		count = count + 1
		if script.SelfCheck.Value == true and count >= 2 then -- Prints The progress.
				print(count.. " We retrying to load the data.")
				
		end
			if count >= 2 then 
			wait(Slowdown) -- Slow Down The Process ; Repeats
			end

	until count >= tries or sucess
end
	 -- individual
	dataLoaded[key] = true
	
	if not sucess then
	  dataLoaded[key] = false
		
		warn("Failed to read. Data. Error code: " .. tostring(err))
		
		plr:Kick("Sorry were not able to load your data roblox is currently down please try again in next time.")
		
		return
	end
	if sucess then
		if data then
			
			print(dataLoaded)
			return data
			
		else
			return {
				["Coins"] = script.Increment.Value,
			}
		end
		
		
	end
end


													-- Auto Saving --
local function AutoSaves(plr)
	if plr then
		
	local key = "plr-" .. plr.UserId
		
		if dataLoaded[key] == true then -- Make sure it loads so it wont save
			
			if IsInGame[key] == false then -- Make sure he / she is still in game.
				
		local data = {
			["Coins"] = plr.leaderstats.Coins.Value,

		}

		local sucess, err
		
			sucess, err = pcall(function()
				myDataStore:UpdateAsync(key, function(oldValue)
						local newValue = data or oldValue or 0
						
						return newValue
					end)	
				end)
					if not sucess then
						
					
					warn("Failed to set the value. Error code: " .. tostring(err))
						return
					end
				else
				return
			end
		end
	end
end

		
	local function createLeaderstats(plr)
	
	
	local leaderstats = Instance.new("Folder",plr) 
	leaderstats.Name = "leaderstats"

	local Coins = Instance.new("IntValue", leaderstats)
	Coins.Name = "Coins" 
	Coins.Value = 0
	
	local values = Get(plr)
	
	local SetValue = pcall(function()
		Coins.Value = values.Coins
	end)
end



local function Closing(plr) -- When saving in shutdown...
	
	local key = "plr-" .. plr.UserId
	
	IsInGame[key] = true -- Means Closed Case
		
		if dataLoaded[key] == true then
		local count = 0

		local data = {
			["Coins"] = plr.leaderstats.Coins.Value,
		}



		local sucess, err

		repeat
			sucess, err = pcall(function()
				myDataStore:UpdateAsync(key, function(oldValue)
					local newValue = data or oldValue or 0
					return newValue

				end)
			end)
			count = count + 1

			if script.SelfCheck.Value == true and count >= 2 then
				print(count.. " We retrying to load the data.")
			end
			if count >= 2 then 
				wait(Closing) -- Slow Down The Process ; Repeats
			end

		until count >= tries2 or sucess
		if not sucess then
			warn("Failed to set the value while BindToClose. Error code: " .. tostring(err))

			return
		end
	else
		return
	end	
end


Players.PlayerRemoving:Connect(Set)
Players.PlayerAdded:Connect(createLeaderstats)

local RunService = game:GetService("RunService")
	game:BindToClose(function()
	if (RunService:IsStudio())then
		
	else
		for i, v in next, game:GetPlayers() do
		if v then
					coroutine.wrap(Closing)(v) 
			end
		end
	end
end)

-- Saving The Value

while wait(AutoSaved) do
	coroutine.wrap(AutoSaves)-- This Autosaving part is very important because it make sure that when
end
2 Likes

Its pretty decent, You’ve gone with systematically putting things through which helps manage things. The only things I can pick out it that your functions are kind of limited to the one script it was made for and you don’t really have a que for when DSS is overloaded.

Some of my DSS3 uses about the same kind of thing but yours is only made for one kind of game and with one store which is ok for personal use but it would be worth revaluating what your DSS is really capable of. For example, many people misunderstand that both the store name and the identifier are string, DSS does not care if it is inputted from a function or in there from the start.

You’ve started on serialisation but not got it to the level where you can take this script anywhere you want, I think your Script has some potential you just need to think a little outside the box.

Overall though its a good base to start on and I’m guessing its one of your first DSS scripts.

Here’s my recommendations:

  • Make the script universal so you can put store names and identifiers into a function to save data
  • Add a que for when DSS is struggling
  • Use Encrypted messaging service for when a server shuts down without completing all data saves (Another server takes on the workload)
  • Add a function to remove a players data (If a player is banned or deletes their account you may have to remove their data)
  • Convert Arrays into string (Roblox now supports saving of arrays but you need to remember that at the core of all of this they are still designed to save string)
  • Don’t use repeat, it is the worst form of looping within Roblox, you would be better of using until success.

Its a good start but I think you can do so much more, reading through the way you wrote that script you defiantly understand the way it all works but just need to think outside the box a little. I hope your script turns into something spectacular in its own way.

1 Like