Is my DataStore Great?

Hello,

I’m still getting the hang of working with DataStore, and I wanted to make sure everything is set up correctly. I’m using the ProfileService module and connecting to the profile service via another server script. If anyone has the time, I’d really appreciate it if you could review the code and let me know if there’s anything I can improve. :blush:

Thank you in advance!

Here is the Server Script :

local ProfileService = require(game.ServerScriptService:WaitForChild("ProfileService"))
local MPS = game:GetService("MarketplaceService")

-- Profile template
local profile_template = {
	Cash = 0,
	hunger = 100,
	rent = 0,
	item1 = false,
	item2 = false,
	item3 = false,
	item4 = false,
	item5 = false,
}

-- ProfileStore
local ProfileStore = ProfileService.GetProfileStore("PlayerDataStore", profile_template)

local Profiles = {}  -- Stores profiles by player UserId

-- Function to handle player data
local function savePlayerData(player)
	local profile = Profiles[player.UserId]
	if profile then
		profile.Data.Cash = player.leaderstats.Cash.Value
		profile.Data.hunger = game.Workspace.Friend["HumanoidRootPart"].HungerBar.Hunger.Value
		profile.Data.rent = game.Workspace.InteractiveValues.RentAmount.Value
		profile.Data.item1 = game.ServerScriptService.PurchasedItemsForData.Roommate.Value
		profile.Data.item2 = game.ServerScriptService.PurchasedItemsForData.Post.Value
		profile.Data.item3 = game.ServerScriptService.PurchasedItemsForData.Maid.Value
		profile.Data.item4 = game.ServerScriptService.PurchasedItemsForData.Pet.Value
		profile.Data.item5 = game.ServerScriptService.PurchasedItemsForData.DoorKeys.Value

		print("Auto-saving data for", player.Name)
	end
end

-- Function to handle player data on load
local function loadPlayerData(player)
	local profile = ProfileStore:LoadProfileAsync("Player_" .. player.UserId, "ForceLoad")
	if profile then
		profile:Reconcile() 
		profile:ListenToRelease(function()
			Profiles[player.UserId] = nil
			player:Kick("Oops! We couldn't load your profile this time. Please rejoin to try again!")
		end)
		if player:IsDescendantOf(game.Players) then
			Profiles[player.UserId] = profile
		else
			profile:Release()
		end

		local folder = Instance.new("Folder")
		folder.Name = "leaderstats"
		folder.Parent = player

		local purchasedfolder = Instance.new("Folder")
		purchasedfolder.Name = "purchasedstuff"
		purchasedfolder.Parent = player

		local cash = Instance.new("IntValue")
		cash.Name = "Cash"
		cash.Value = profile.Data.Cash
		cash.Parent = folder

		game.Workspace.Friend["HumanoidRootPart"].HungerBar.Hunger.Value = profile.Data.hunger
		game.Workspace.InteractiveValues.RentAmount.Value = profile.Data.rent

		game.ServerScriptService.PurchasedItemsForData.Roommate.Value = profile.Data.item1
		game.ServerScriptService.PurchasedItemsForData.Post.Value = profile.Data.item2
		game.ServerScriptService.PurchasedItemsForData.Maid.Value = profile.Data.item3
		game.ServerScriptService.PurchasedItemsForData.Pet.Value = profile.Data.item4
		game.ServerScriptService.PurchasedItemsForData.DoorKeys.Value = profile.Data.item5

		print("Player data loaded successfully for", player.Name)
	else
		player:Kick("Failed to load your data. Please rejoin.")
	end
end

-- Auto-Save Loop
local autoSaveInterval = 60 -- Save every 60 seconds
spawn(function()
	while true do
		wait(autoSaveInterval)
		for _, player in pairs(game.Players:GetPlayers()) do
			local success, err = pcall(savePlayerData, player)
			if not success then
				warn("Failed to save data for", player.Name, ":", err)
			end
		end
	end
end)

-- PlayerAdded function
game.Players.PlayerAdded:Connect(function(player)
	local success, err = pcall(loadPlayerData, player)
	if not success then
		warn("Failed to load data for", player.Name, ":", err)
	end
end)

-- PlayerRemoving function for saving on leave
game.Players.PlayerRemoving:Connect(function(player)
	local success, err = pcall(savePlayerData, player)
	if not success then
		warn("Failed to save data for", player.Name, ":", err)
	end

	local profile = Profiles[player.UserId]
	if profile then
		profile:Release()
	end
end)

-- BindToClose for auto-saving when the server is shutting down
game:BindToClose(function()
	for _, player in pairs(game.Players:GetPlayers()) do
		local success, err = pcall(savePlayerData, player)
		if not success then
			warn("Failed to save data for", player.Name, ":", err)
		end
		local profile = Profiles[player.UserId]
		if profile then
			profile:Release()
		end
	end
end)

-- Erase Data
game.ReplicatedStorage.EraseData.OnServerEvent:Connect(function(player)
	local profile = Profiles[player.UserId]
	if profile then
		print("Erasing profile data for", player.Name)
		ProfileStore:WipeProfileAsync("Player_" .. player.UserId)
		profile:Release()
		player:Kick("Your file has been erased.")
	end
end)

-- NPCDied event
game.ReplicatedStorage.NPCDied.OnServerEvent:Connect(function()
	for _, player in ipairs(game.Players:GetPlayers()) do
		local profile = Profiles[player.UserId]
		if profile then
			print("Npc died, erasing profile for", player.Name)
			ProfileStore:WipeProfileAsync("Player_" .. player.UserId)
			profile:Release()
			player:Kick("Npc Died")
		end
	end
end) ```