Can my DataStoreMethod be made more effiecent and/or secure?

Hey! For my King-of-the-hill theme game, I made a DataStore method for, of course, storing UserData.

The system I have in place is well-functioning, but I am confident that it can be improved on to help with security and functional aspects.

How it works:
When a player joins, a folder with the player’s ID as its name is made under ReplicatedStorage.PlayerData, that folder contains all the IntValues for the User. (currently my only variables are Score and Level. That folder can then be read but not edited by LocalScripts. And when the player leaves, the data is saved and the folder is removed.

It also controls Data changes with the TranslateCall function.

local RepStore = game:GetService("ReplicatedStorage")
local SvrStore = game:GetService("ServerStorage")
local DatStore = game:GetService("DataStoreService")
local Players = game:GetService("Players")
local PlayerDataFolder = RepStore.PlayerData

local InfoStore = DatStore:GetDataStore("PlayerData")

function UnloadPlayerData(PlayerID)
	local success, err = pcall(function()
		local PlayerData = InfoStore:GetAsync(PlayerID)

		if not PlayerData.Level and PlayerData.Score then
			warn("data empty")
			PlayerData = {}
			PlayerData.Level = 0
			PlayerData.Score = 0
		end

		local PlayerFolder = Instance.new("Folder")
		PlayerFolder.Name = PlayerID
		PlayerFolder.Parent = PlayerDataFolder

		for store, data in pairs(PlayerData) do
			local IntHolder = Instance.new("IntValue")
			IntHolder.Name = store
			IntHolder.Value = data
			IntHolder.Parent = PlayerFolder
		end
	end)
	if not success then warn(err) end
end

function PackPlayerData(PlayerID)
	local PlayerFolder = PlayerDataFolder:FindFirstChild(PlayerID)
	local success, err = pcall(function()
		local PlayerData = {}

		for i, v in pairs(PlayerFolder:GetChildren()) do
			PlayerData[v.Name] = v.Value
		end

		InfoStore:SetAsync(PlayerID,PlayerData)
	end)
	if success then
		PlayerFolder:Destroy()
	else
		warn(err)
	end
end

function TranslateCall(callData)
	for i, v in pairs(callData) do
		local PlrId = callData.PlrId
		local Ttype = callData.Type
		local value = callData.Value
		
		local LPlrFol = PlayerDataFolder[PlrId]
		local SVal = LPlrFol[Ttype]
		SVal.Value = SVal.Value + value
	end
end
Players.PlayerAdded:Connect(function(player) UnloadPlayerData(player.UserId) end)
Players.PlayerRemoving:Connect(function(player) PackPlayerData(player.UserId) end)



I mean its basically just a normal datastore system.

1 Like

I’ve never seen anyone using 2 functions just to pass an UserId, this is unnecessary. Also, to secure data save after the server shuts down, add a :BindToClose() function, or else the last player to leave could have saving issues or even yourself when testing.

game:BindToClose(function()
	for _, player in ipairs(Players:GetChildren()) do
		PackPlayerData(player.UserId)
	end
end)
1 Like

It seems like it is doing it itself. Testing the game in studio and on website, I experienced no saving issues.