-- Finds an unobstructed spot teleportDistance studs away from destinationCharacter (nil if none found)

function TeleportToPlayer.getCharacterTeleportPoint(destinationCharacter: Model, teleportDistance: number): CFrame
	local rootPart = destinationCharacter and destinationCharacter:FindFirstChild("HumanoidRootPart")
	local humanoid = destinationCharacter and destinationCharacter:FindFirstChild("Humanoid")
	if not rootPart or not humanoid then
		return
	end

	-- Pre-populate ignore list with destinationCharacter in case it's not a player character (ex: NPCs)
	local ignoreList = { destinationCharacter }
	for _, player in ipairs(Players:GetChildren()) do
		table.insert(ignoreList, player.Character)
	end
	local params = RaycastParams.new()
	params.FilterType = Enum.RaycastFilterType.Blacklist
	params.FilterDescendantsInstances = ignoreList

	-- Scan a circular area around the player to find a spot that's not blocked by a wall and has solid ground
	-- below it
	for i = 1, RAYCASTS_NUMBER do
		local rotated = rootPart.CFrame * CFrame.Angles(0, math.pi * 2 * (i / RAYCASTS_NUMBER), 0)
		-- First raycast to check if there is no obstacle in front
		local forwardRaycastResult = workspace:Raycast(rootPart.Position, rotated.LookVector * 5, params)
		if not forwardRaycastResult then
			local forward = rotated + rotated.LookVector * teleportDistance
			-- Second raycast to check if there is ground to stand on
			local downwardRaycastResult = workspace:Raycast(forward.Position, Vector3.new(0, -MAX_HEIGHT, 0), params)
			local position = downwardRaycastResult and downwardRaycastResult.Position
			if position then
				local lookAt = Vector3.new(rootPart.CFrame.X, position.Y, rootPart.CFrame.Z)
				return CFrame.lookAt(position, lookAt)
			end
		end
	end
	return
end
