Bugs in wait in a wait line game

Here is the code, and yes the swapHum() function is ai generated as i tried for 3 days to fix it and could not figure out why it does not work, the ai version doesn’t work either it has the same bugs, them being

  1. after a player wins if they buy the dev product they are sent to the very front of the line for some reason

  2. if you buy it back to back you on the first time move forwards one space as intended but on the second time you move forwards 2 places for some reason

the intended behavior is always that when you buy it you move forwards once space and the guy who was their prior gets sent to where you where.

the other bug is that if multiple player join at the same time they can be positioned wrongly and for example have 2 players on the same spot. doesn’t happen al the time but it can

local SpotsFolder = game.Workspace:WaitForChild("Spots")
local WinSpot = game.Workspace.WinSpot
local Data = require(game.ServerScriptService:WaitForChild("PlayerData"):WaitForChild("Data"))
local Players = game:GetService("Players")
local PlayersInGame = 0
local Emitter = game.Workspace["Eye of Rah"].Character.Head.ParticleEmitter

local canSwap = true

function win(player)

	local char = player.Character

	SpotsFolder.Spot1.MoveTo.Occupant.Value = ""

	if char then
		player:FindFirstChild("Spot").Value = 0
		char.Humanoid:MoveTo(WinSpot.MoveTo.Position)
		Data.Profiles[player].Data.Wins += 1

		task.wait(1.25)
		Emitter:Emit(100)
		task.wait(1.75)

		print(player.Name, " has won")
		
		local chosenSpotMoveTo = #Players:GetPlayers()
		
		if char then
			char.HumanoidRootPart.CFrame = SpotsFolder:FindFirstChild("Spot"..chosenSpotMoveTo).MoveTo.CFrame + Vector3.new(0,6,0)
			char.HumanoidRootPart.CFrame = CFrame.lookAt(char.HumanoidRootPart.Position, SpotsFolder:FindFirstChild("Spot"..chosenSpotMoveTo).LookAt.Position)	
			SpotsFolder:FindFirstChild("Spot"..chosenSpotMoveTo).MoveTo.Occupant.Value = char.Name
			player:FindFirstChild("Spot").Value = chosenSpotMoveTo
		end		
	end
end

function moveHum(hum)
	local root = hum.Parent.HumanoidRootPart

	if root then
		local player = Players:GetPlayerFromCharacter(root.Parent)
		local plrPosition = player:FindFirstChild("Spot")

		if plrPosition then
			if plrPosition.Value > 1 then				
				if hum then
					SpotsFolder:FindFirstChild("Spot"..plrPosition.Value).MoveTo.Occupant.Value = ""
					player:FindFirstChild("Spot").Value -= 1
					hum:MoveTo(SpotsFolder:FindFirstChild("Spot"..player:FindFirstChild("Spot").Value).MoveTo.Position)
					SpotsFolder:FindFirstChild("Spot"..player:FindFirstChild("Spot").Value).MoveTo.Occupant.Value = hum.Parent.Name
					hum.MoveToFinished:Wait()
					if root then
						local yes, no  = pcall(function()
							root.CFrame = CFrame.lookAt(root.Position, SpotsFolder:FindFirstChild("Spot"..player:FindFirstChild("Spot").Value).LookAt.Position)
						end)						
					end
				end	
			end		
		end	
	end
end



function assign(player, ammount)
	local chosenSpot = ammount

	while SpotsFolder:FindFirstChild("Spot"..chosenSpot).MoveTo.Occupant.Value ~= "" do
		chosenSpot -= 1
	end

	local char = player.Character or player.CharacterAdded:Wait()
	local root = char:WaitForChild("HumanoidRootPart")

	local newVal = Instance.new('NumberValue', player)
	newVal.Name = "Spot"
	newVal.Value = chosenSpot

	local assignSpot = SpotsFolder:FindFirstChild("Spot"..chosenSpot)
	assignSpot.MoveTo.Occupant.Value = player.Name
	root.CFrame = assignSpot.MoveTo.CFrame + Vector3.new(0,6,0)
	root.CFrame = CFrame.lookAt(root.Position, assignSpot.LookAt.Position)

	for _, part in pairs(char:GetChildren()) do
		if part:IsA("BasePart") then
			part.CollisionGroup = "Player"
		end
	end

	return "Done"
end




function plrLeftAdjust(playerLeftPosition)
	for i, player in pairs(Players:GetPlayers()) do
		local plrPosition = player:FindFirstChild("Spot")

		if plrPosition then
			if plrPosition.Value > playerLeftPosition then

				local hum  = player.Character.Humanoid

				task.spawn(moveHum, hum)
			end
		end
	end
end

for i, player in pairs(Players:GetPlayers()) do
	local ammount = #game.Players:GetPlayers()
	task.spawn(assign, player, ammount)
end

Players.PlayerAdded:Connect(function(player)
	local ammount = #game.Players:GetPlayers()
	task.spawn(assign, player, ammount)
end)

Players.PlayerRemoving:Connect(function(player)
	local playerPosition = player.Spot.Value

	for _, v in pairs(SpotsFolder:GetDescendants()) do
		if v:IsA("StringValue") and v.Value == player.Name then
			v.Value = ""
		end
	end

	PlayersInGame -= 1

	if playerPosition == 1 then
		SpotsFolder.Spot1.MoveTo.Occupant.Value = SpotsFolder.Spot2.MoveTo.Occupant.Value
	end

	if playerPosition ~= 0 then
		task.spawn(plrLeftAdjust, playerPosition)
	end
end)


function swapHum(movingForwards)
	if not movingForwards then return end  

	local movingForwardsChar = movingForwards.Character
	local movingForwardsCharRoot = movingForwardsChar and movingForwardsChar:FindFirstChild("HumanoidRootPart")
	if not movingForwardsChar or not movingForwardsCharRoot then return end

	-- Ensure player has the "Spot" value
	local spotValue = movingForwards:FindFirstChild("Spot")
	if not spotValue then return end 

	-- Get the player's current spot position
	local currentSpotValue = spotValue.Value

	-- Prevent moving if player is at the first spot
	if currentSpotValue <= 1 then return end

	-- Get the spots the players occupy
	local currentSpot = SpotsFolder:FindFirstChild("Spot" .. currentSpotValue)
	local forwardSpot = SpotsFolder:FindFirstChild("Spot" .. (currentSpotValue - 1))

	if not currentSpot or not forwardSpot then return end

	-- Get the players in both spots
	local currentSpotOccupant = currentSpot.MoveTo.Occupant.Value
	local forwardSpotOccupant = forwardSpot.MoveTo.Occupant.Value

	-- Ensure both spots are occupied
	if not currentSpotOccupant or not forwardSpotOccupant then return end

	-- Get the player objects
	local playerA = Players:GetPlayerFromCharacter(game.Workspace:FindFirstChild(currentSpotOccupant))
	local playerB = Players:GetPlayerFromCharacter(game.Workspace:FindFirstChild(forwardSpotOccupant))
	if not playerA or not playerB then return end

	-- Update the Spot values for both players
	playerA:FindFirstChild("Spot").Value = currentSpotValue - 1
	playerB:FindFirstChild("Spot").Value = currentSpotValue

	-- Swap the Occupants in both spots
	currentSpot.MoveTo.Occupant.Value = forwardSpotOccupant
	forwardSpot.MoveTo.Occupant.Value = currentSpotOccupant

	-- Move Player A to Player B's spot
	local playerAChar = playerA.Character
	local playerBChar = playerB.Character

	-- Move Player A to Player B's spot
	if playerAChar then
		local playerARoot = playerAChar:FindFirstChild("HumanoidRootPart")
		if playerARoot then
			playerARoot.CFrame = forwardSpot.MoveTo.CFrame + Vector3.new(0, 6, 0)
			playerARoot.CFrame = CFrame.lookAt(playerARoot.Position, forwardSpot.LookAt.Position)
		end
	end

	-- Move Player B to Player A's spot
	if playerBChar then
		local playerBRoot = playerBChar:FindFirstChild("HumanoidRootPart")
		if playerBRoot then
			playerBRoot.CFrame = currentSpot.MoveTo.CFrame + Vector3.new(0, 6, 0)
			playerBRoot.CFrame = CFrame.lookAt(playerBRoot.Position, currentSpot.LookAt.Position)
		end
	end
end




function changeAllUIS(command)
	if command == "Invisible" then
		for i, player in pairs(Players:GetPlayers()) do
			local ui = player.PlayerGui.Purchase
			if ui then
				local ui2 = ui.SkipAhead
				if ui2 then
					ui2.Visible = false
				end
			end
		end
	else
		for i, player in pairs(Players:GetPlayers()) do
			local ui = player.PlayerGui.Purchase
			if ui then
				local ui2 = ui.SkipAhead
				if ui2 then
					ui2.Visible = true
				end
			end
		end
	end
end


task.spawn(function()
	while task.wait(10) do
		canSwap = false
		changeAllUIS("Invisible")
		task.wait(2)
		
		local player = Players:GetPlayerFromCharacter(game.Workspace:FindFirstChild(SpotsFolder.Spot1.MoveTo.Occupant.Value))
		if player then
			SpotsFolder.Spot1.MoveTo.Occupant.Value = ""
			task.spawn(win, player)
		end

		for i, player in pairs(Players:GetPlayers()) do
			local plrPosition = player:FindFirstChild("Spot")

			if plrPosition then
				if plrPosition.Value > 1 then
					local hum  = player.Character.Humanoid
					task.spawn(moveHum, hum)
				end
			end
		end
		task.wait(3)
		changeAllUIS("Visible")
		canSwap = true

	end
end)

local MS = game:GetService("MarketplaceService")

local function process(info)

	local userId = info.PlayerId
	local productId = info.ProductId
	local player = game.Players:GetPlayerByUserId(userId)

	if info.ProductId == 2840392821 then

		if player:FindFirstChild('Spot').Value > 1 and canSwap then
			swapHum(player)
		else
			return Enum.ProductPurchaseDecision.NotProcessedYet
		end

	end

end

MS.ProcessReceipt = process