public static void GetOptionsAndNameAssets <T>(
            this ICustomOptionNamesProvider <T> provider,
            ref string[] optionNames, ref T[] nameAssets, string[] defaultOptions
            ) where T : ScriptableObject, IFlagNames
        {
            if (optionNames != null)
            {
                return;
            }
            var guids = AssetDatabase.FindAssets($"t:{typeof(T).Name}");

            nameAssets = guids
                         .Select(AssetDatabase.GUIDToAssetPath)
                         .Select(AssetDatabase.LoadAssetAtPath <T>)
                         .Where(c => c != null)
                         .ToArray();
            optionNames = nameAssets.FirstOrDefault()?.FlagNames.ToArray() ?? defaultOptions;
            for (var i = 0; i < optionNames.Length; ++i)
            {
                optionNames[i] = string.IsNullOrEmpty(optionNames[i]) ? defaultOptions[i] : optionNames[i];
            }
        }
        public static void DoCustomNamesPopup <T>(
            Rect position, SerializedProperty property, GUIContent label, ICustomOptionNamesProvider <T> optionsProvider
            ) where T : ScriptableObject
        {
            if (optionsProvider.NameAssets?.Count == 0)
            {
                position.xMax -= Styles.CreateAssetButtonWidth + EditorGUIUtility.standardVerticalSpacing;
            }
            else if (optionsProvider.NameAssets?.Count > 1)
            {
                position.xMax -= EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing;
            }

            EditorGUI.BeginProperty(position, label, property);

            var controlPosition = EditorGUI.PrefixLabel(position, label);

            var indent = EditorGUI.indentLevel;

            EditorGUI.indentLevel = 0;
            var showMixed = EditorGUI.showMixedValue;

            var value      = 0;
            var everything = 0;

            for (int i = 0, count = property.arraySize; i < count; ++i)
            {
                var sp = property.GetArrayElementAtIndex(i);
                EditorGUI.showMixedValue |= sp.hasMultipleDifferentValues;
                value      |= sp.boolValue ? 1 << i : 0;
                everything |= 1 << i;
            }
            // in case size is smaller than 32
            if (value == everything)
            {
                value = ~0;
            }

            EditorGUI.BeginChangeCheck();
            value = EditorGUI.MaskField(controlPosition, GUIContent.none, value, optionsProvider.GetOptions());
            if (EditorGUI.EndChangeCheck())
            {
                for (int i = 0, count = property.arraySize; i < count; ++i)
                {
                    property.GetArrayElementAtIndex(i).boolValue = (value & (1 << i)) != 0;
                }
            }

            EditorGUI.showMixedValue = showMixed;
            EditorGUI.indentLevel    = indent;

            EditorGUI.EndProperty();

            if (optionsProvider.NameAssets?.Count == 0)
            {
                position.width = Styles.CreateAssetButtonWidth;
                position.x     = controlPosition.xMax + EditorGUIUtility.standardVerticalSpacing;
                Styles.CreateAssetLabel.tooltip =
                    string.Format(Styles.CreateAssetButtonTooltip, ObjectNames.NicifyVariableName(typeof(T).Name));
                if (GUI.Button(position, Styles.CreateAssetLabel, EditorStyles.miniButton))
                {
                    var assetPath =
                        AssetDatabase.GenerateUniqueAssetPath($"Assets/{typeof(T).Name}.asset");
                    AssetDatabase.CreateAsset(ScriptableObject.CreateInstance <T>(), assetPath);
                    Selection.activeObject = AssetDatabase.LoadAssetAtPath <T>(assetPath);
                    optionsProvider.Update();
                }
            }
            else if (optionsProvider.NameAssets.Count > 1)
            {
                var id = GUIUtility.GetControlID(FocusType.Passive);
                if (Event.current.type == EventType.Repaint)
                {
                    position.width = EditorGUIUtility.singleLineHeight;
                    position.x     = controlPosition.xMax + EditorGUIUtility.standardVerticalSpacing;
                    Styles.MultipleAssetsWarning.tooltip = string.Format(
                        Styles.MultipleAssetsTooltip,
                        ObjectNames.NicifyVariableName(typeof(T).Name),
                        optionsProvider.NameAssets.FirstOrDefault(n => n != null)?.name
                        );
                    GUIStyle.none.Draw(position, Styles.MultipleAssetsWarning, id);
                }
            }
        }