protected void DrawRecord(int recordIndex, out bool recordRemoved)
        {
            recordRemoved = false;
            var record = filteredRecords[recordIndex];

            ACTkEditorGUI.Separator();

            using (ACTkEditorGUI.Horizontal(ACTkEditorGUI.PanelWithBackground))
            {
                if (GUILayout.Button(new GUIContent("X", "Delete this pref."), ACTkEditorGUI.CompactButton, GUILayout.Width(20)))
                {
                    record.Delete();
                    allRecords.Remove(record);
                    filteredRecords.Remove(record);
                    recordRemoved = true;
                    return;
                }

                GUI.enabled = (record.dirtyValue || record.dirtyKey) && record.prefType != PrefsRecord.PrefsType.Unknown;
                if (GUILayout.Button(new GUIContent("S", "Save changes in this pref."), ACTkEditorGUI.CompactButton, GUILayout.Width(20)))
                {
                    record.Save();
                    GUIUtility.keyboardControl = 0;
                }

                GUI.enabled = record.prefType != PrefsRecord.PrefsType.Unknown;

                if (record.Obscured)
                {
                    GUI.enabled &= record.obscuredType == ObscuredPrefs.DataType.String ||
                                   record.obscuredType == ObscuredPrefs.DataType.Int ||
                                   record.obscuredType == ObscuredPrefs.DataType.Float;
                    if (GUILayout.Button(new GUIContent("D", "Decrypt this pref using ObscuredPrefs"), ACTkEditorGUI.CompactButton, GUILayout.Width(25)))
                    {
                        record.Decrypt();
                        GUIUtility.keyboardControl = 0;
                    }
                }
                else
                {
                    if (GUILayout.Button(new GUIContent("E", "Encrypt this pref using ObscuredPrefs"), ACTkEditorGUI.CompactButton, GUILayout.Width(25)))
                    {
                        record.Encrypt();
                        GUIUtility.keyboardControl = 0;
                    }
                }
                GUI.enabled = true;

                if (GUILayout.Button(new GUIContent("...", "Other operations"), ACTkEditorGUI.CompactButton, GUILayout.Width(25)))
                {
                    ShowOtherMenu(record);
                }

                var guiColor = GUI.color;
                if (record.Obscured)
                {
                    GUI.color = obscuredColor;
                }

                GUI.enabled = record.prefType != PrefsRecord.PrefsType.Unknown;

                if (record.Obscured && !(record.obscuredType == ObscuredPrefs.DataType.String ||
                                         record.obscuredType == ObscuredPrefs.DataType.Int ||
                                         record.obscuredType == ObscuredPrefs.DataType.Float))
                {
                    GUI.enabled = false;
                    EditorGUILayout.TextField(record.Key, GUILayout.MaxWidth(200), GUILayout.MinWidth(50));
                    GUI.enabled = record.prefType != PrefsRecord.PrefsType.Unknown;
                }
                else
                {
                    record.Key = EditorGUILayout.TextField(record.Key, GUILayout.MaxWidth(200), GUILayout.MinWidth(50));
                }

                if ((record.prefType == PrefsRecord.PrefsType.String && !record.Obscured) || (record.Obscured && record.obscuredType == ObscuredPrefs.DataType.String))
                {
                    // to avoid TextMeshGenerator error because of too much characters
                    if (record.StringValue.Length > 16382)
                    {
                        GUI.enabled = false;
                        EditorGUILayout.TextField(StringTooLong, GUILayout.MinWidth(150));
                        GUI.enabled = record.prefType != PrefsRecord.PrefsType.Unknown;
                    }
                    else
                    {
                        record.StringValue = EditorGUILayout.TextField(record.StringValue, GUILayout.MinWidth(150));
                    }
                }
                else if (record.prefType == PrefsRecord.PrefsType.Int || (record.Obscured && record.obscuredType == ObscuredPrefs.DataType.Int))
                {
                    record.IntValue = EditorGUILayout.IntField(record.IntValue, GUILayout.MinWidth(150));
                }
                else if (record.prefType == PrefsRecord.PrefsType.Float || (record.Obscured && record.obscuredType == ObscuredPrefs.DataType.Float))
                {
                    record.FloatValue = EditorGUILayout.FloatField(record.FloatValue, GUILayout.MinWidth(150));
                }
                else if (record.Obscured)
                {
                    GUI.enabled = false;
                    EditorGUILayout.TextField(UnsupportedValueDescription, GUILayout.MinWidth(150));
                    GUI.enabled = record.prefType != PrefsRecord.PrefsType.Unknown;
                }
                else
                {
                    GUI.enabled = false;
                    EditorGUILayout.TextField(UnknownValueDescription, GUILayout.MinWidth(150));
                    GUI.enabled = record.prefType != PrefsRecord.PrefsType.Unknown;
                }
                GUI.color   = guiColor;
                GUI.enabled = true;

                EditorGUILayout.LabelField(record.DisplayType, GUILayout.Width(70));
            }
        }
        private void DrawRecordsPages()
        {
            recordsTotalPages = Math.Max(1, (int)Math.Ceiling((double)filteredRecords.Count / RecordsPerPage));

            if (recordsCurrentPage < 0)
            {
                recordsCurrentPage = 0;
            }
            if (recordsCurrentPage + 1 > recordsTotalPages)
            {
                recordsCurrentPage = recordsTotalPages - 1;
            }

            var fromRecord = recordsCurrentPage * RecordsPerPage;
            var toRecord   = fromRecord + Math.Min(RecordsPerPage, filteredRecords.Count - fromRecord);

            if (recordsTotalPages > 1)
            {
                GUILayout.Label("Prefs " + fromRecord + " - " + toRecord + " from " + filteredRecords.Count);
            }

            scrollPosition = GUILayout.BeginScrollView(scrollPosition);
            for (var i = fromRecord; i < toRecord; i++)
            {
                bool recordRemoved;
                DrawRecord(i, out recordRemoved);
                if (recordRemoved)
                {
                    break;
                }
            }
            GUILayout.EndScrollView();

            if (recordsTotalPages <= 1)
            {
                return;
            }

            GUILayout.Space(5);
            using (ACTkEditorGUI.Horizontal())
            {
                GUILayout.FlexibleSpace();

                GUI.enabled = recordsCurrentPage > 0;
                if (GUILayout.Button("<<", GUILayout.Width(50)))
                {
                    RemoveNotification();
                    recordsCurrentPage = 0;
                    scrollPosition     = Vector2.zero;
                }
                if (GUILayout.Button("<", GUILayout.Width(50)))
                {
                    RemoveNotification();
                    recordsCurrentPage--;
                    scrollPosition = Vector2.zero;
                }
                GUI.enabled = true;
                GUILayout.Label(recordsCurrentPage + 1 + " of " + recordsTotalPages, ACTkEditorGUI.CenteredLabel, GUILayout.Width(100));
                GUI.enabled = recordsCurrentPage < recordsTotalPages - 1;
                if (GUILayout.Button(">", GUILayout.Width(50)))
                {
                    RemoveNotification();
                    recordsCurrentPage++;
                    scrollPosition = Vector2.zero;
                }
                if (GUILayout.Button(">>", GUILayout.Width(50)))
                {
                    RemoveNotification();
                    recordsCurrentPage = recordsTotalPages - 1;
                    scrollPosition     = Vector2.zero;
                }
                GUI.enabled = true;

                GUILayout.FlexibleSpace();
            }
        }
        // ----------------------------------------------------------------------------
        // GUI
        // ----------------------------------------------------------------------------

        private void OnGUI()
        {
            if (allRecords == null)
            {
                allRecords = new List <PrefsRecord>();
            }
            if (filteredRecords == null)
            {
                filteredRecords = new List <PrefsRecord>();
            }

            using (ACTkEditorGUI.Horizontal(ACTkEditorGUI.Toolbar))
            {
                if (GUILayout.Button(new GUIContent("+", "Create new prefs record."), EditorStyles.toolbarButton, GUILayout.Width(20)))
                {
                    addingNewRecord = true;
                }

                if (GUILayout.Button(new GUIContent("Refresh", "Re-read and re-parse all prefs."), EditorStyles.toolbarButton, GUILayout.Width(50)))
                {
                    RefreshData();
                    GUIUtility.keyboardControl = 0;
                    scrollPosition             = Vector2.zero;
                    recordsCurrentPage         = 0;
                }

                EditorGUI.BeginChangeCheck();
                sortingType = (SortingType)EditorGUILayout.EnumPopup(sortingType, EditorStyles.toolbarDropDown, GUILayout.Width(110));
                if (EditorGUI.EndChangeCheck())
                {
                    ApplySorting();
                }

                GUILayout.Space(10);

                EditorGUI.BeginChangeCheck();
                searchPattern = ACTkEditorGUI.SearchToolbar(searchPattern);
                if (EditorGUI.EndChangeCheck())
                {
                    ApplyFiltering();
                }

                EditorGUI.BeginChangeCheck();
                EditorGUIUtility.labelWidth = 80;
                GUILayout.Label(new GUIContent("Crypto key", "ObscuredPrefs crypto key to use."), ACTkEditorGUI.ToolbarLabel, GUILayout.ExpandWidth(false));

                var newKey = EditorGUILayout.TextField(ObscuredPrefs.CryptoKey, EditorStyles.toolbarTextField, GUILayout.ExpandWidth(true));
                EditorGUIUtility.labelWidth = 0;
                if (EditorGUI.EndChangeCheck())
                {
                    ObscuredPrefs.CryptoKey = newKey;
                }
            }

            if (addingNewRecord)
            {
                using (ACTkEditorGUI.Horizontal(ACTkEditorGUI.PanelWithBackground))
                {
                    string[] types = { "String", "Int", "Float" };
                    newRecordType = EditorGUILayout.Popup(newRecordType, types, GUILayout.Width(50));

                    newRecordEncrypted = GUILayout.Toggle(newRecordEncrypted, new GUIContent("E", "Create new pref as encrypted ObscuredPref?"), ACTkEditorGUI.CompactButton, GUILayout.Width(25));

                    var guiColor = GUI.color;
                    if (newRecordEncrypted)
                    {
                        GUI.color = obscuredColor;
                    }

                    GUILayout.Label("Key:", GUILayout.ExpandWidth(false));
                    newRecordKey = EditorGUILayout.TextField(newRecordKey);
                    GUILayout.Label("Value:", GUILayout.ExpandWidth(false));

                    if (newRecordType == 0)
                    {
                        newRecordStringValue = EditorGUILayout.TextField(newRecordStringValue);
                    }
                    else if (newRecordType == 1)
                    {
                        newRecordIntValue = EditorGUILayout.IntField(newRecordIntValue);
                    }
                    else
                    {
                        newRecordFloatValue = EditorGUILayout.FloatField(newRecordFloatValue);
                    }

                    GUI.color = guiColor;

                    if (GUILayout.Button("OK", ACTkEditorGUI.CompactButton, GUILayout.Width(30)))
                    {
                        if (string.IsNullOrEmpty(newRecordKey) ||
                            (newRecordType == 0 && string.IsNullOrEmpty(newRecordStringValue)) ||
                            (newRecordType == 1 && newRecordIntValue == 0) ||
                            (newRecordType == 2 && Math.Abs(newRecordFloatValue) < 0.00000001f))
                        {
                            ShowNotification(new GUIContent("Please fill in the pref first!"));
                        }
                        else
                        {
                            PrefsRecord newRecord;

                            if (newRecordType == 0)
                            {
                                newRecord = new PrefsRecord(newRecordKey, newRecordStringValue, newRecordEncrypted);
                            }
                            else if (newRecordType == 1)
                            {
                                newRecord = new PrefsRecord(newRecordKey, newRecordIntValue, newRecordEncrypted);
                            }
                            else
                            {
                                newRecord = new PrefsRecord(newRecordKey, newRecordFloatValue, newRecordEncrypted);
                            }

                            if (newRecord.Save())
                            {
                                allRecords.Add(newRecord);
                                ApplySorting();
                                CloseNewRecordPanel();
                            }
                        }
                    }

                    if (GUILayout.Button("Cancel", ACTkEditorGUI.CompactButton, GUILayout.Width(60)))
                    {
                        CloseNewRecordPanel();
                    }
                }
            }

            using (ACTkEditorGUI.Vertical(ACTkEditorGUI.PanelWithBackground))
            {
                GUILayout.Space(5);

                DrawRecordsPages();

                GUILayout.Space(5);

                GUI.enabled = filteredRecords.Count > 0;
                using (ACTkEditorGUI.Horizontal())
                {
                    if (GUILayout.Button("Encrypt ALL", ACTkEditorGUI.CompactButton))
                    {
                        if (EditorUtility.DisplayDialog("Obscure ALL prefs in list?", "This will apply obscuration to ALL unobscured prefs in the list.\nAre you sure you wish to do this?", "Yep", "Oh, no!"))
                        {
                            foreach (var record in filteredRecords)
                            {
                                record.Encrypt();
                            }
                            GUIUtility.keyboardControl = 0;
                            ApplySorting();
                        }
                    }

                    if (GUILayout.Button("Decrypt ALL", ACTkEditorGUI.CompactButton))
                    {
                        if (EditorUtility.DisplayDialog("UnObscure ALL prefs in list?", "This will remove obscuration from ALL obscured prefs in the list if possible.\nAre you sure you wish to do this?", "Yep", "Oh, no!"))
                        {
                            foreach (var record in filteredRecords)
                            {
                                record.Decrypt();
                            }
                            GUIUtility.keyboardControl = 0;
                            ApplySorting();
                        }
                    }

                    if (GUILayout.Button("Save ALL", ACTkEditorGUI.CompactButton))
                    {
                        if (EditorUtility.DisplayDialog("Save changes to ALL prefs in list?", "Are you sure you wish to save changes to ALL prefs in the list? This can't be undone!", "Yep", "Oh, no!"))
                        {
                            foreach (var record in filteredRecords)
                            {
                                record.Save();
                            }
                            GUIUtility.keyboardControl = 0;
                            ApplySorting();
                        }
                    }

                    if (GUILayout.Button("Delete ALL", ACTkEditorGUI.CompactButton))
                    {
                        if (EditorUtility.DisplayDialog("Delete ALL prefs in list?", "Are you sure you wish to delete the ALL prefs in the list? This can't be undone!", "Yep", "Oh, no!"))
                        {
                            foreach (var record in filteredRecords)
                            {
                                record.Delete();
                            }

                            RefreshData();
                            GUIUtility.keyboardControl = 0;
                        }
                    }
                }
                GUI.enabled = true;
            }
        }
        private void OnGUI()
        {
            if (whitelist == null)
            {
                whitelist = new List <AllowedAssembly>();
                LoadAndParseWhitelist();
            }

            var tmpStyle = new GUIStyle(EditorStyles.largeLabel)
            {
                alignment = TextAnchor.MiddleCenter,
                fontStyle = FontStyle.Bold
            };

            GUILayout.Label("User-defined Whitelist of Assemblies trusted by Injection Detector", tmpStyle);

            scrollPosition = EditorGUILayout.BeginScrollView(scrollPosition);
            var whitelistUpdated = false;

            var count = whitelist.Count;

            if (count > 0)
            {
                for (var i = 0; i < count; i++)
                {
                    var assembly = whitelist[i];
                    using (ACTkEditorGUI.Horizontal())
                    {
                        GUILayout.Label(assembly.ToString());
                        if (GUILayout.Button(new GUIContent("-", "Remove Assembly from Whitelist"), GUILayout.Width(30)))
                        {
                            whitelist.Remove(assembly);
                            whitelistUpdated = true;
                            break;
                        }
                    }
                }
            }
            else
            {
                tmpStyle = new GUIStyle(EditorStyles.largeLabel)
                {
                    alignment = TextAnchor.MiddleCenter
                };
                GUILayout.Label("- no Assemblies added so far (use buttons below to add) -", tmpStyle);
            }

            if (manualAssemblyWhitelisting)
            {
                manualAssemblyWhitelistingName = EditorGUILayout.TextField(manualAssemblyWhitelistingName);

                using (ACTkEditorGUI.Horizontal())
                {
                    if (GUILayout.Button("Save"))
                    {
                        try
                        {
                            if (manualAssemblyWhitelistingName.StartsWith("Cause:"))
                            {
                                throw new Exception("Please remove Cause: from the assembly name!");
                            }

                            var assName = new AssemblyName(manualAssemblyWhitelistingName.Trim());

                            var res = TryWhitelistAssemblyName(assName, true);
                            if (res != WhitelistingResult.Exists)
                            {
                                whitelistUpdated = true;
                            }
                            manualAssemblyWhitelisting     = false;
                            manualAssemblyWhitelistingName = InitialCustomName;
                        }
                        catch (Exception error)
                        {
                            ShowNotification(new GUIContent(error.Message));
                        }

                        GUI.FocusControl("");
                    }

                    if (GUILayout.Button("Cancel"))
                    {
                        manualAssemblyWhitelisting     = false;
                        manualAssemblyWhitelistingName = InitialCustomName;
                        GUI.FocusControl("");
                    }
                }
            }

            EditorGUILayout.EndScrollView();

            using (ACTkEditorGUI.Horizontal())
            {
                GUILayout.Space(20);
                if (GUILayout.Button("Add Assembly"))
                {
                    var assemblyPath = EditorUtility.OpenFilePanel("Choose an Assembly to add", "", "dll");
                    if (!string.IsNullOrEmpty(assemblyPath))
                    {
                        whitelistUpdated |= TryWhitelistAssemblies(new[] { assemblyPath }, true);
                    }
                }

                if (GUILayout.Button("Add Assemblies from folder"))
                {
                    var selectedFolder = EditorUtility.OpenFolderPanel("Choose a folder with Assemblies", "", "");
                    if (!string.IsNullOrEmpty(selectedFolder))
                    {
                        var libraries = ACTkEditorGlobalStuff.FindLibrariesAt(selectedFolder);
                        whitelistUpdated |= TryWhitelistAssemblies(libraries);
                    }
                }

                if (!manualAssemblyWhitelisting)
                {
                    if (GUILayout.Button("Add Assembly manually"))
                    {
                        manualAssemblyWhitelisting = true;
                    }
                }

                if (count > 0)
                {
                    if (GUILayout.Button("Clear"))
                    {
                        if (EditorUtility.DisplayDialog("Please confirm",
                                                        "Are you sure you wish to completely clear your Injection Detector whitelist?", "Yes", "No"))
                        {
                            whitelist.Clear();
                            whitelistUpdated = true;
                        }
                    }
                }
                GUILayout.Space(20);
            }

            GUILayout.Space(20);

            if (whitelistUpdated)
            {
                WriteWhitelist();
            }
        }
Example #5
0
        private void OnGUI()
        {
            using (ACTkEditorGUI.Vertical(ACTkEditorGUI.PanelWithBackground))
            {
                ACTkEditorGUI.DrawHeader("Injection Detector settings (global)");
                //GUILayout.Label("Injection Detector settings (global)", ACTkEditorGUI.LargeBoldLabel);

                var enableInjectionDetector = EditorPrefs.GetBool(ACTkEditorGlobalStuff.PrefsInjectionEnabled);

                EditorGUI.BeginChangeCheck();
                enableInjectionDetector = GUILayout.Toggle(enableInjectionDetector, "Enable Injection Detector");
                if (EditorGUI.EndChangeCheck())
                {
                    EditorPrefs.SetBool(ACTkEditorGlobalStuff.PrefsInjectionEnabled, enableInjectionDetector);
                    if (enableInjectionDetector && !ACTkPostprocessor.IsInjectionDetectorTargetCompatible())
                    {
                        Debug.LogWarning(ACTkEditorGlobalStuff.LogPrefix + "Injection Detector is not available on selected platform (" +
                                         EditorUserBuildSettings.activeBuildTarget + ")");
                    }

                    if (!enableInjectionDetector)
                    {
                        ACTkEditorGlobalStuff.CleanInjectionDetectorData();
                    }
                    else if (!File.Exists(ACTkEditorGlobalStuff.injectionDataPath))
                    {
                        ACTkPostprocessor.InjectionAssembliesScan();
                    }
                }

                EditorGUILayout.Space();

                if (GUILayout.Button("Edit Whitelist"))
                {
                    ACTkAssembliesWhitelist.ShowWindow();
                }

                GUILayout.Space(3);
            }

            EditorGUILayout.Space();

            using (ACTkEditorGUI.Vertical(ACTkEditorGUI.PanelWithBackground))
            {
                ACTkEditorGUI.DrawHeader("WallHack Detector settings (per-project)");
                GUILayout.Label("Wireframe module uses specific shader under the hood. Thus such shader should be included into the build to exist at runtime. To make sure it's get included, you may add it to the Always Included Shaders list using buttons below. You don't need to include it if you're not going to use Wireframe module.",
                                EditorStyles.wordWrappedLabel);

                ReadGraphicsAsset();

                if (graphicsSettingsAsset != null && includedShaders != null)
                {
                    // outputs whole included shaders list, use for debug
                    //EditorGUILayout.PropertyField(includedShaders, true);

                    var shaderIndex = GetWallhackDetectorShaderIndex();

                    EditorGUI.BeginChangeCheck();

                    if (shaderIndex != -1)
                    {
                        GUILayout.Label("Shader <b>is at</b> the Always Included Shaders list, you're good to go!", ACTkEditorGUI.RichLabel);
                        if (GUILayout.Button("Remove shader"))
                        {
                            includedShaders.DeleteArrayElementAtIndex(shaderIndex);
                            includedShaders.DeleteArrayElementAtIndex(shaderIndex);
                        }
                        EditorGUILayout.Space();
                    }
                    else
                    {
                        GUILayout.Label("Shader <b>is not</b> at the Always Included Shaders list.", ACTkEditorGUI.RichLabel);
                        using (ACTkEditorGUI.Horizontal())
                        {
                            if (GUILayout.Button("Include automatically", GUILayout.Width(minSize.x / 2f)))
                            {
                                var shader = Shader.Find(WireframeShaderName);
                                if (shader != null)
                                {
                                    includedShaders.InsertArrayElementAtIndex(includedShaders.arraySize);
                                    var newItem = includedShaders.GetArrayElementAtIndex(includedShaders.arraySize - 1);
                                    newItem.objectReferenceValue = shader;
                                }
                                else
                                {
                                    Debug.LogError("Can't find " + WireframeShaderName + " shader! Please report this to the  " +
                                                   ACTkEditorGlobalStuff.ReportEmail + " including your Unity version number.");
                                }
                            }

                            if (GUILayout.Button("Include manually (see readme.pdf)"))
                            {
#if UNITY_2018_3_OR_NEWER
                                SettingsService.OpenProjectSettings("Project/Graphics");
#else
                                EditorApplication.ExecuteMenuItem("Edit/Project Settings/Graphics");
#endif
                            }
                        }
                        GUILayout.Space(3);
                    }

                    if (EditorGUI.EndChangeCheck())
                    {
                        graphicsSettingsAsset.ApplyModifiedProperties();
                    }
                }
                else
                {
                    GUILayout.Label("Can't automatically control " + WireframeShaderName +
                                    " shader existence at the Always Included Shaders list. Please, manage this manually in Graphics Settings.");
                    if (GUILayout.Button("Open Graphics Settings"))
                    {
                        EditorApplication.ExecuteMenuItem("Edit/Project Settings/Graphics");
                    }
                }
            }

            EditorGUILayout.Space();

            using (ACTkEditorGUI.Vertical(ACTkEditorGUI.PanelWithBackground))
            {
                ACTkEditorGUI.DrawHeader("Conditional Compilation Symbols (per-project)");
                GUILayout.Label("Here you may switch conditional compilation symbols used in ACTk.\n" +
                                "Check Readme for more details on each symbol.", EditorStyles.wordWrappedLabel);
                EditorGUILayout.Space();
                if (symbolsData == null)
                {
                    symbolsData = GetSymbolsData();
                }

                /*if (GUILayout.Button("Reset"))
                 * {
                 *      var groups = (BuildTargetGroup[])Enum.GetValues(typeof(BuildTargetGroup));
                 *      foreach (BuildTargetGroup buildTargetGroup in groups)
                 *      {
                 *              PlayerSettings.SetScriptingDefineSymbolsForGroup(buildTargetGroup, string.Empty);
                 *      }
                 * }*/

                using (ACTkEditorGUI.Horizontal())
                {
                    using (ACTkEditorGUI.Vertical())
                    {
                        GUILayout.Label("Debug Symbols", ACTkEditorGUI.LargeBoldLabel);
                        ACTkEditorGUI.Separator();

                        DrawSymbol(ref symbolsData.injectionDebug, ACTkEditorGlobalStuff.ConditionalSymbols.InjectionDebug, "Switches the Injection Detector debug.");
                        DrawSymbol(ref symbolsData.injectionDebugVerbose, ACTkEditorGlobalStuff.ConditionalSymbols.InjectionDebugVerbose, "Switches the Injection Detector verbose debug level.");
                        DrawSymbol(ref symbolsData.injectionDebugParanoid, ACTkEditorGlobalStuff.ConditionalSymbols.InjectionDebugParanoid, "Switches the Injection Detector paranoid debug level.");
                        DrawSymbol(ref symbolsData.wallhackDebug, ACTkEditorGlobalStuff.ConditionalSymbols.WallhackDebug, "Switches the WallHack Detector debug - you'll see the WallHack objects in scene and get extra information in console.");
                        DrawSymbol(ref symbolsData.detectionBacklogs, ACTkEditorGlobalStuff.ConditionalSymbols.DetectionBacklogs, "Enables additional logs in some detectors to make it easier to debug false positives.");
                    }

                    using (ACTkEditorGUI.Vertical())
                    {
                        GUILayout.Label("Compatibility Symbols", ACTkEditorGUI.LargeBoldLabel);
                        ACTkEditorGUI.Separator();

                        DrawSymbol(ref symbolsData.exposeThirdPartyIntegrationSymbol, ACTkEditorGlobalStuff.ConditionalSymbols.ThirdPartyIntegration, "Enable to let other third-party code in project know you have ACTk added.");
                        DrawSymbol(ref symbolsData.excludeObfuscation, ACTkEditorGlobalStuff.ConditionalSymbols.ExcludeObfuscation, "Enable if you use Unity-unaware obfuscators which support ObfuscationAttribute to help avoid names corruption.");
                        DrawSymbol(ref symbolsData.preventReadPhoneState, ACTkEditorGlobalStuff.ConditionalSymbols.PreventReadPhoneState, "Disables ObscuredPrefs Lock To Device functionality.");
                        DrawSymbol(ref symbolsData.preventInternetPermission, ACTkEditorGlobalStuff.ConditionalSymbols.PreventInternetPermission, "Disables TimeCheatingDetector functionality.");
                        DrawSymbol(ref symbolsData.obscuredAutoMigration, ACTkEditorGlobalStuff.ConditionalSymbols.ObscuredAutoMigration, "Enables automatic migration of ObscuredFloat and ObscuredDouble instances from the ACTk 1.5.2.0-1.5.8.0 to the 1.5.9.0+ format. Reduces these types performance a bit.");
                    }
                }

                GUILayout.Space(3);
            }
        }
 protected virtual void DrawHeader(string text)
 {
     ACTkEditorGUI.DrawHeader(text);
 }