ProfileService Datastore Script any suggestions?

I am just beginning to use profile service as datastore in Roblox. I want to make sure this script is very secure and there are no chances of data loss. I also want to know if I did everything correctly.

local ProfileService = require(game.ServerScriptService.ProfileService)

-- Variables
local ProfileStore = ProfileService.GetProfileStore("PlayerDataStore", {})

local playertabledata = {}
local playerProfiles = {}

local function CheckData(async, dataname)
	if async == nil then
		return dataname
	else
		return async
	end
end

local function AddNewTemplateData(player)
	-- This function can be modified or removed if no template is used
end

local function AddDataToTable(player)
	if not playertabledata[player.Name] then playertabledata[player.Name] = {} end
	for _, item in pairs(player.DataFolder:GetChildren()) do
		local itemData = {
			Value = item.Value,
			Attributes = {}
		}
		for attr, _ in pairs(item:GetAttributes()) do
			itemData.Attributes[attr] = item:GetAttribute(attr)
		end
		playertabledata[player.Name][item.Name] = itemData
	end
end

local function RetrieveDataFromTable(player)
	if not playertabledata[player.Name] then playertabledata[player.Name] = {} end
	for i, v in pairs(playertabledata[player.Name]) do
		local item = player.DataFolder:FindFirstChild(i) or Instance.new("NumberValue", player.DataFolder)
		item.Name = i
		item.Value = v.Value
		for attr, value in pairs(v.Attributes) do
			item:SetAttribute(attr, value)
		end
	end
end

local function DeepCopy(orig)
	local orig_type = type(orig)
	local copy
	if orig_type == 'table' then
		copy = {}
		for orig_key, orig_value in next, orig, nil do
			copy[DeepCopy(orig_key)] = DeepCopy(orig_value)
		end
		setmetatable(copy, DeepCopy(getmetatable(orig)))
	else -- number, string, boolean, etc
		copy = orig
	end
	return copy
end

local function savePlayerData(player)
	local profile = playerProfiles[player]
	if profile and playertabledata[player.Name] then
		AddDataToTable(player)
		local safeData = DeepCopy(playertabledata[player.Name])
		profile.Data = safeData
	end
end

local function deleteValue(player, valueName)
	local Folder = player:FindFirstChild("Folder")
	if not Folder then
		return
	end

	local value = Folder:FindFirstChild(valueName)
	if value then
		value:Destroy()

		-- Update the data table
		if playertabledata[player.Name] then
			playertabledata[player.Name][valueName] = nil
		end

		-- Save the updated data to the ProfileService immediately
		savePlayerData(player)
	else
		warn("Value not found:", valueName)
	end
end

game.Players.PlayerAdded:Connect(function(player)
	local Folder = Instance.new("Folder")
	Folder.Name = "Folder"
	Folder.Parent = player

	-- Load player data
	local profile = ProfileStore:LoadProfileAsync("Player_"..player.UserId)

	if profile then
		profile:AddUserId(player.UserId)
		profile:Reconcile()
		playerProfiles[player] = profile

		playertabledata[player.Name] = CheckData(profile.Data, {})
		AddNewTemplateData(player)
		RetrieveDataFromTable(player)

		-- Save player data when they leave
		player.AncestryChanged:Connect(function()
			if not player:IsDescendantOf(game) then
				savePlayerData(player)
				profile:Release()
				playerProfiles[player] = nil
			end
		end)
	else
		player:Kick("Could not load data. Please try again later.")
	end
end)

game.Players.PlayerRemoving:Connect(function(player)
	savePlayerData(player)
	local profile = playerProfiles[player]
	if profile then
		profile:Release()
		playerProfiles[player] = nil
	end
end)

game:BindToClose(function()
	for _, player in pairs(game.Players:GetPlayers()) do
		savePlayerData(player)
		local profile = playerProfiles[player]
		if profile then
			profile:Release()
		end
	end
end)


2 Likes

If this works in saving player’s data when they leave, it should be find. It’s good you have the :BindToClose() as well. Another thing you can add to is an autosave. I believe ProfileService has that feature built in, but couldn’t hurt to make sure it’s enabled.

3 Likes

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.