Migrating data to use ProfileStore instead

I’m currently trying to remake the data system my tower defense game uses with ProfileStore and I was wondering if this is correct? I’m still new to how this module works so I would appreciate any help!!

New Datastore Script:

local profileStore = require(game.ReplicatedStorage.Modules.ProfileStore)

local runService = game:GetService("RunService")
local badgeService = game:GetService("BadgeService")
local marketPlaceService = game:GetService("MarketplaceService")
local dataStoreService = game:GetService("DataStoreService")
local oldDatabase = dataStoreService:GetDataStore("dataTest")

local PROFILE_TEMPLATE = {
	Coins = 50,
	Level = 1,
	XP = 0,
	RequiredXP = 100,
	Inventory = {
		SelectedTowers = {"Bowsman X1"},
		OwnedTowers = {"Bowsman X1"},
		OwnedSkins = {},
		SelectedSkins = {},
	},
	Triumphs = 0,
	Losses = 0,
}
local PlayerStore = profileStore.New("PlayerStore", PROFILE_TEMPLATE)

local function migratePlayerData(userId)
	local success, oldData = pcall(function()
		return oldDatabase:GetAsync(tostring(userId))
	end)

	if success and oldData then
		print("Old data found for userId:", userId)
		local newData = {
			Coins = oldData.Stars or PROFILE_TEMPLATE.Coins,
			Level = oldData.Level or PROFILE_TEMPLATE.Level,
			XP = oldData.Exp or PROFILE_TEMPLATE.XP,
			RequiredXP = oldData.RequiredExp or PROFILE_TEMPLATE.RequiredXP,
			Inventory = {
				SelectedTowers = oldData.SelectedTowers or PROFILE_TEMPLATE.Inventory.SelectedTowers,
				OwnedTowers = oldData.OwnedTowers or PROFILE_TEMPLATE.Inventory.OwnedTowers,
				OwnedSkins = oldData.OwnedSkins or PROFILE_TEMPLATE.Inventory.OwnedSkins,
				SelectedSkins = oldData.SelectedSkins or PROFILE_TEMPLATE.Inventory.SelectedSkins,
			},
			Triumphs = oldData.Triumphs or PROFILE_TEMPLATE.Triumphs,
			Losses = oldData.Losses or PROFILE_TEMPLATE.Losses,
		}

		local profile = PlayerStore:StartSessionAsync(`{userId}`, {
			Cancel = function()
				return false
			end,
		})

		if profile then
			profile.Data = newData
			profile:Reconcile()
			profile:EndSession()
			print("Data migrated successfully for userId:", userId)
		else
			warn("Failed to start session for userId:", userId)
		end
	else
		print("No old data found for userId:", userId)
	end
end

game.Players.PlayerAdded:Connect(function(player)
	local userId = player.UserId
	migratePlayerData(userId)
end)

Old Datastore Script:

local DataStoreService = game:GetService("DataStoreService")
local Players = game:GetService("Players")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local RunService = game:GetService("RunService")
local BadgeService = game:GetService("BadgeService")
local markeetplace = game:GetService("MarketplaceService")

local database = DataStoreService:GetDataStore("dataTest")
local towers = require(ReplicatedStorage:WaitForChild("TowerShop"))

local MAX_SELECTED_TOWERS = 6

local data = {}

local function givetower(player, tower)
	local playerData = data[player.UserId]
	if not table.find(playerData.OwnedTowers, tower) then
		table.insert(playerData.OwnedTowers, tower) 
	else
		return
	end
end

--Load the player's data.
local function LoadData(player)

	local success = nil
	local playerData = nil
	local attempt = 1

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

	repeat
		success, playerData = pcall(function()
			return database:GetAsync(player.UserId)
		end)

		attempt += 1
		if not success then
			warn(playerData)
			task.wait(1)
		end

	until success or attempt == 3

	if success then
		print("Connection Success!")
		if not playerData then
			print("New player, giving default data")
			playerData = {
				["Stars"] = 50,
				["SelectedTowers"] = {"Bowsman X1"},
				["OwnedTowers"] = {"Bowsman X1"},
				["Level"] = 0,
				["Exp"] = 0,
				["RequiredExp"] = 100,
				["Triumphs"] = 0,
				["Losses"] = 0,

				["OwnedSkins"] = {},
				["SelectedSkins"] = {}
			}
		end
		data[player.UserId] = playerData
		
		
		
		if player.Name=="RoboNinjaYTpl" then
			playerData = {
				["Stars"] = 9999999,
				["SelectedTowers"] = {"Bowsman X1"},
				["OwnedTowers"] = {"Bowsman X1"},
				["Level"] = 0,
				["Exp"] = 0,
				["RequiredExp"] = 100,
				["Triumphs"] = 0,
				["Losses"] = 0,

				["OwnedSkins"] = {},
				["SelectedSkins"] = {}
			}
			
			data[player.UserId]=playerData
		end

		if not data[player.UserId]["Level"] then
			data[player.UserId]["Level"] = 1
			data[player.UserId]["Exp"] = 0
			data[player.UserId]["RequiredExp"] = 100
		end

		if not data[player.UserId]["Triumphs"] then
			data[player.UserId]["Triumphs"] = 0
			data[player.UserId]["Losses"] = 0
		end

		if not data[player.UserId]["SelectedSkins"] then
			data[player.UserId]["SelectedSkins"] = {}
			data[player.UserId]["OwnedSkins"] = {}
		end

		if player.Name=="devvres" then
			data[player.UserId].Stars=10000000
			table.insert(data[player.UserId].OwnedSkins, "Devvres Sub Machine")
			table.insert(data[player.UserId].OwnedSkins, "Sheep Boomboxer")
			table.insert(data[player.UserId].OwnedSkins, "Bighead Mercenary")
			table.insert(data[player.UserId].OwnedSkins, "10 Hour Executor")
			table.insert(data[player.UserId].OwnedSkins, "Arctic Frost Shooter")
			
			--table.insert(data[player.UserId].OwnedSkins, "Deadeye?")
			--table.insert(data[player.UserId].OwnedSkins, "Bowsman?")
		end
		if string.lower(player.Name)=="roboninjaytplacc2" then
			data[player.UserId].Stars=10000000
		end
		if player.Name == "NOKIA23716" then
			data[player.UserId].Stars=100000
		end

		if player.Name=="devvingRN" then
			data[player.UserId].Stars=100000
		end
		
		if player.Name=="realcixors" then
			data[player.UserId].Stars=32323232
			table.insert(data[player.UserId].OwnedSkins, "Sheep Boomboxer")
			table.insert(data[player.UserId].OwnedSkins, "Devvres Sub Machine")
			table.insert(data[player.UserId].OwnedSkins, "Arctic Frost Shooter")
			table.insert(data[player.UserId].OwnedSkins, "Bowsman?")
		end
		
		if player.Name=="raelgoob" then
			data[player.UserId].Stars=10000000
			table.insert(data[player.UserId].OwnedSkins, "Devvres Sub Machine")
			table.insert(playerData.OwnedTowers, "Bloxxer X1")
			table.insert(data[player.UserId].OwnedSkins, "10 Hour Executor")
			table.insert(data[player.UserId].OwnedSkins, "Deadeye?")
			table.insert(data[player.UserId].OwnedSkins, "Bowsman?")
		end

		while task.wait() and data[player.UserId] do
			if data[player.UserId]["Level"] and data[player.UserId]["Exp"] and data[player.UserId]["RequiredExp"] then
				if playerData.Exp >= playerData.RequiredExp then
					playerData.Exp = playerData.Exp - playerData.RequiredExp
					playerData.Level += 1
					playerData.RequiredExp = 155 + (playerData.Level * 1.5)
				end
			else
				wait(playerData.Level and playerData.Exp and playerData.RequiredExp)
				if playerData.Exp >= playerData.RequiredExp then
					playerData.Exp = playerData.Exp - playerData.RequiredExp
					playerData.Level += 1
					playerData.RequiredExp = 155 + (playerData.Level * 1.5)
				end
			end
		end--]]
		
		if BadgeService:UserHasBadgeAsync(player.UserId, 2153889525) then -- Replace with your badge Id
			if not table.find(playerData.OwnedTowers, "Deadeye X1") then
				table.insert(playerData.OwnedTowers, "Deadeye X1")
			end
		end

		if BadgeService:UserHasBadgeAsync(player.UserId, 1032409634298595) then -- Replace with your badge Id
			if not table.find(playerData.OwnedSkins, "Bighead Mercenary") then
				table.insert(playerData.OwnedSkins, "Bighead Mercenary")
			else
				print("this player has bighead skin!!")
			end
		end

		if BadgeService:UserHasBadgeAsync(player.UserId, 3803315976370583) then -- Replace with your badge Id
			if not table.find(playerData.OwnedTowers, "Bloxxer X1") then
				table.insert(playerData.OwnedTowers, "Bloxxer X1")
			end
		end

		if BadgeService:UserHasBadgeAsync(player.UserId, 3803315976370583) then -- Replace with your badge Id
			if not table.find(playerData.OwnedTowers, "Bloxxer X1") then
				table.insert(playerData.OwnedTowers, "Bloxxer X1")
			end
		end

		--	if BadgeService:UserHasBadgeAsync(player.UserId, 2153788838) or player.UserId == 1090530019 then -- Replace with your badge Id
		--	if not table.find(data[player.UserId].OwnedSkins, "10 Hour Executor") then
		--			table.insert(data[player.UserId].OwnedSkins, "10 Hour Executor")
		--		end
		--end

		if BadgeService:UserHasBadgeAsync(player.UserId, 703372011984396) then -- Replace with your badge Id
			if not table.find(playerData.OwnedSkins, "Deadeye?") then
				table.insert(playerData.OwnedSkins, "Deadeye?")
			end
			if not table.find(playerData.OwnedSkins, "Bowsman?") then
				table.insert(playerData.OwnedSkins, "Bowsman?")
			end
		end

		if markeetplace:UserOwnsGamePassAsync(player.UserId, 138357039) then  -- Replace with your badge Id
			if not table.find(playerData.OwnedSkins, "Deadeye?") and not table.find(playerData.OwnedSkins, "Bowsman?") then
				table.insert(playerData.OwnedSkins, "Deadeye?")
				table.insert(playerData.OwnedSkins, "Bowsman?")
			end
		end

		if markeetplace:UserOwnsGamePassAsync(player.UserId, 663320679) then -- Replace with your badge Id
			if not table.find(playerData.OwnedTowers, "Vulcan X1") then
				table.insert(playerData.OwnedTowers, "Vulcan X1")
			end
		end

		if player.UserId == 171709662 or player.UserId == 2465383027 or player.UserId == 954079762 then -- Replace with your badge Id
			if not table.find(playerData.OwnedSkins, "Sheep Boomboxer") then
				table.insert(playerData.OwnedSkins, "Sheep Boomboxer")
			end
		end

		local CoinStats = Instance.new("NumberValue")
		CoinStats.Name = "Coins"
		CoinStats.Value = playerData.Stars
		CoinStats.Parent = leaderstats

		local winStats = Instance.new("NumberValue")
		winStats.Name = "🏆Triumphs🏆"
		winStats.Value = playerData.Triumphs
		winStats.Parent = leaderstats

		local loseStats = Instance.new("NumberValue")
		loseStats.Name = "💀Losses💀"
		loseStats.Value = playerData.Losses
		loseStats.Parent = leaderstats
		--local levelStats = Instance.new("IntValue")
		--levelStats.Name = "Level"
		--levelStats.Value = playerData.Level
		--levelStats.Parent = leaderstats

	else
		warn("Unable to get data for player ", player.UserId)
		player:Kick("There was an issue retrieving your data.")
	end
end
Players.PlayerAdded:Connect(function(player)
	LoadData(player)
end)

--Save the players data
local function SaveData(player)
	if data[player.UserId] then
		local success = nil
		local playerData = nil
		local attempt = 1

		repeat
			success, playerData = pcall(function()
				return database:UpdateAsync(player.UserId, function()
					return data[player.UserId]
				end)
			end)

			attempt += 1
			if not success then
				warn(playerData)
				task.wait(1)
			end

		until success or attempt == 3

		if success then
			print("Data Saved!")
		else
			warn("Unable to save data for player ", player.UserId, " :(")
		end
	else
		warn("No session data for ", player.UserId)
	end

end
Players.PlayerRemoving:Connect(function(player)
	SaveData(player)
	data[player.UserId] = nil
end)

game:BindToClose(function()
	if not RunService:IsStudio() then
		for index, player in pairs(Players:GetPlayers()) do
			task.spawn(function()
				SaveData(player)
			end)
		end
	else
		print("Shutting down inside studio.")
	end
end)


local function getItemStatus(player,itemName,skin)
	local playerData=data[player.UserId]
	if not skin then
		if table.find(playerData.SelectedTowers, itemName) then
			return "Equipped"
		elseif table.find(playerData.OwnedTowers, itemName) then
			return "Owned"
		else
			return "For Sale"
		end
	else
		local can=true

		for i, skin in pairs(playerData.SelectedSkins) do
			if skin and skin.Name then
				if skin.Name==itemName then
					can=false
					return "Equipped"
				end
			end
		end

		if can then
			if table.find(playerData.OwnedSkins,itemName) then
				return "Owned"
			else
				return "For Sale"
			end
		end
	end

end

ReplicatedStorage.InteractItem.OnServerInvoke = function(player, itemName,skin,iscrate,crateprice)

	ReplicatedStorage.InteractGui:FireClient(player)

	local shopItem = towers[itemName]
	if skin then
		shopItem=require(ReplicatedStorage.SkinShop)[itemName]
	end
	local playerData = data[player.UserId]

	if shopItem and playerData then
		local status = getItemStatus(player, itemName,skin)

		if not skin then
			if status == "For Sale" and shopItem.Price <= playerData.Stars then
				-- purchase

				playerData.Stars -= shopItem.Price
				table.insert(playerData.OwnedTowers, shopItem.Name)
				local BadgeID = 0
				if game:GetService("BadgeService"):UserHasBadgeAsync(player.UserId,BadgeID) then

					print("Gave tower!")
				end




			elseif status == "Owned" then
				-- equip the tower
				table.insert(playerData.SelectedTowers, shopItem.Name)
				if #playerData.SelectedTowers > MAX_SELECTED_TOWERS then
					table.remove(playerData.SelectedTowers, 1)
				end

			elseif status == "Equipped" then
				-- unselect the tower (if more than 1 selected)
				if #playerData.SelectedTowers > 0 then
					--print(playerData.SelectedTowers)
					local towerToRemove = table.find(playerData.SelectedTowers, itemName)
					table.remove(playerData.SelectedTowers, towerToRemove)
				end
			end
		else
			if iscrate then
				if tonumber(crateprice)<=playerData.Stars then
					playerData.Stars -= tonumber(crateprice)
					table.insert(playerData.OwnedSkins, shopItem.Name)
				end
			else
				if status == "For Sale" and shopItem.Price <= playerData.Stars then
					-- purchase
					playerData.Stars -= shopItem.Price
					table.insert(playerData.OwnedSkins, shopItem.Name)
					local BadgeID = 0
					if game:GetService("BadgeService"):UserHasBadgeAsync(player.UserId,BadgeID) then

						print("Gave tower!")
					end
				elseif status == "Owned" then
					-- equip the tower
					for i, skin in pairs(playerData.SelectedSkins) do
						if skin.Name and skin.Tower then
							if skin.Tower==shopItem.Tower then
								playerData.SelectedSkins[skin.Name]=nil
							end
						end
					end

					playerData.SelectedSkins[shopItem.Name]={
						["Name"]=shopItem.Name,
						["Tower"]=shopItem.Tower,
					}
				elseif status == "Equipped" then
					-- unselect the tower (if more than 1 selected)
					for i, skin in pairs(playerData.SelectedSkins) do
						if skin.Name and skin.Tower then
							if skin.Tower==shopItem.Tower then
								playerData.SelectedSkins[skin.Name]=nil
							end
						end
					end
				end
			end
		end



		return playerData
	else
		warn("Tower/player data does not exist")
	end

	return false
end

--ReplicatedStorage.GetData.OnServerInvoke = function(player)
--	return data[player.UserId]
--end
ReplicatedStorage.GetData.OnServerInvoke = function(playerthing:Player, desired:boolean, desiredplayer:Player)
	if desired == false then
		return data[playerthing.UserId]
	elseif desired == true then
		return data[desiredplayer.UserId]
	end
end

ReplicatedStorage.GetLevelData.OnInvoke = function(player)
	return data[player.UserId]
end

The new Datastore script isn’t fully finished but I’m just figuring out how data migration would work.