예제 #1
0
    /// <summary>
    /// Encrypted version of EditorPrefs.SetBool(), stored key and value is encrypted in player prefs
    /// </summary>
    public static void SetEncryptedBool(string key, bool value)
    {
        string encryptedKey   = SimpleEncryption.EncryptString(key);
        string encryptedValue = SimpleEncryption.EncryptBool(value);

        // Store the encrypted key and value (with relevant identifying prefixes) in PlayerPrefs
        PlayerPrefs.SetString(KEY_PREFIX + encryptedKey, VALUE_BOOL_PREFIX + encryptedValue);
    }
예제 #2
0
    private void DrawAddEntry()
    {
        // Create a GUIStyle that can be manipulated for the various text fields
        GUIStyle textFieldStyle = new GUIStyle(GUI.skin.textField);

        // Create a space
        EditorGUILayout.Space();

        // Heading
        GUILayout.Label(showEditorPrefs ? "Add EditorPref" : "Add PlayerPref", EditorStyles.boldLabel);

        // UI for whether the new PlayerPref is encrypted and what type it is
        EditorGUILayout.BeginHorizontal();
        newEntryIsEncrypted = GUILayout.Toggle(newEntryIsEncrypted, "Encrypt");

        if (showEditorPrefs)
        {
            newEntryType = (PlayerPrefType)GUILayout.Toolbar((int)newEntryType, new string[] { "float", "int", "string", "bool" });
        }
        else
        {
            if (newEntryType == PlayerPrefType.Bool)
            {
                newEntryType = PlayerPrefType.String;
            }

            newEntryType = (PlayerPrefType)GUILayout.Toolbar((int)newEntryType, new string[] { "float", "int", "string" });
        }

        EditorGUILayout.EndHorizontal();

        // Key and Value headings
        EditorGUILayout.BeginHorizontal();
        GUILayout.Label("Key", EditorStyles.boldLabel);
        GUILayout.Label("Value", EditorStyles.boldLabel);
        EditorGUILayout.EndHorizontal();

        // If the new value will be encrypted tint the text boxes blue (in line with the display style for existing
        // encrypted PlayerPrefs)
        if (newEntryIsEncrypted)
        {
            if (UsingProSkin)
            {
                textFieldStyle.normal.textColor  = new Color(0.5f, 0.5f, 1);
                textFieldStyle.focused.textColor = new Color(0.5f, 0.5f, 1);
            }
            else
            {
                textFieldStyle.normal.textColor  = new Color(0, 0, 1);
                textFieldStyle.focused.textColor = new Color(0, 0, 1);
            }
        }

        EditorGUILayout.BeginHorizontal();

        // Track the next control so we can detect key events in it
        GUI.SetNextControlName("newEntryKey");
        // UI for the new key text box
        newEntryKey = EditorGUILayout.TextField(newEntryKey, textFieldStyle);

        // Track the next control so we can detect key events in it
        GUI.SetNextControlName("newEntryValue");

        // Display the correct UI field editor based on what type of PlayerPref is being created
        if (newEntryType == PlayerPrefType.Float)
        {
            newEntryValueFloat = EditorGUILayout.FloatField(newEntryValueFloat, textFieldStyle);
        }
        else if (newEntryType == PlayerPrefType.Int)
        {
            newEntryValueInt = EditorGUILayout.IntField(newEntryValueInt, textFieldStyle);
        }
        else if (newEntryType == PlayerPrefType.Bool)
        {
            newEntryValueBool = EditorGUILayout.Toggle(newEntryValueBool);
        }
        else
        {
            newEntryValueString = EditorGUILayout.TextField(newEntryValueString, textFieldStyle);
        }

        // If the user hit enter while either the key or value fields were being edited
        bool keyboardAddPressed = Event.current.isKey && Event.current.keyCode == KeyCode.Return && Event.current.type == EventType.KeyUp && (GUI.GetNameOfFocusedControl() == "newEntryKey" || GUI.GetNameOfFocusedControl() == "newEntryValue");

        // If the user clicks the Add button or hits return (and there is a non-empty key), create the PlayerPref
        if ((GUILayout.Button("Add", GUILayout.Width(40)) || keyboardAddPressed) && !string.IsNullOrEmpty(newEntryKey))
        {
            // If the PlayerPref we're creating is encrypted
            if (newEntryIsEncrypted)
            {
                // Encrypt the key
                string encryptedKey = PlayerPrefsUtility.KEY_PREFIX + SimpleEncryption.EncryptString(newEntryKey);

                // Note: All encrypted values are stored as string
                string encryptedValue;

                // Calculate the encrypted value
                if (newEntryType == PlayerPrefType.Float)
                {
                    encryptedValue = PlayerPrefsUtility.VALUE_FLOAT_PREFIX + SimpleEncryption.EncryptFloat(newEntryValueFloat);
                }
                else if (newEntryType == PlayerPrefType.Int)
                {
                    encryptedValue = PlayerPrefsUtility.VALUE_INT_PREFIX + SimpleEncryption.EncryptInt(newEntryValueInt);
                }
                else if (newEntryType == PlayerPrefType.Bool)
                {
                    encryptedValue = PlayerPrefsUtility.VALUE_BOOL_PREFIX + SimpleEncryption.EncryptBool(newEntryValueBool);
                }
                else
                {
                    encryptedValue = PlayerPrefsUtility.VALUE_STRING_PREFIX + SimpleEncryption.EncryptString(newEntryValueString);
                }

                // Record the new PlayerPref in PlayerPrefs
                SetString(encryptedKey, encryptedValue);

                // Cache the addition
                CacheRecord(encryptedKey, encryptedValue);
            }
            else
            {
                if (newEntryType == PlayerPrefType.Float)
                {
                    // Record the new PlayerPref in PlayerPrefs
                    SetFloat(newEntryKey, newEntryValueFloat);
                    // Cache the addition
                    CacheRecord(newEntryKey, newEntryValueFloat);
                }
                else if (newEntryType == PlayerPrefType.Int)
                {
                    // Record the new PlayerPref in PlayerPrefs
                    SetInt(newEntryKey, newEntryValueInt);
                    // Cache the addition
                    CacheRecord(newEntryKey, newEntryValueInt);
                }
                else if (newEntryType == PlayerPrefType.Bool)
                {
                    // Record the new PlayerPref in PlayerPrefs
                    SetBool(newEntryKey, newEntryValueBool);
                    // Cache the addition
                    CacheRecord(newEntryKey, newEntryValueBool);
                }
                else
                {
                    // Record the new PlayerPref in PlayerPrefs
                    SetString(newEntryKey, newEntryValueString);
                    // Cache the addition
                    CacheRecord(newEntryKey, newEntryValueString);
                }
            }

            // Tell Unity to save the PlayerPrefs
            Save();

            // Force a repaint since hitting the return key won't invalidate layout on its own
            Repaint();

            // Reset the values
            newEntryKey         = "";
            newEntryValueFloat  = 0;
            newEntryValueInt    = 0;
            newEntryValueString = "";

            // Deselect
            GUI.FocusControl("");
        }

        EditorGUILayout.EndHorizontal();
    }
예제 #3
0
    private void DrawMainList()
    {
        // The bold table headings
        EditorGUILayout.BeginHorizontal();
        GUILayout.Label("Key", EditorStyles.boldLabel);
        GUILayout.Label("Value", EditorStyles.boldLabel);
        GUILayout.Label("Type", EditorStyles.boldLabel, GUILayout.Width(37));
        GUILayout.Label("Del", EditorStyles.boldLabel, GUILayout.Width(25));
        EditorGUILayout.EndHorizontal();

        // Create a GUIStyle that can be manipulated for the various text fields
        GUIStyle textFieldStyle = new GUIStyle(GUI.skin.textField);

        // Could be dealing with either the full list or search results, so get the right list
        List <PlayerPrefPair> activePlayerPrefs = deserializedPlayerPrefs;

        if (!string.IsNullOrEmpty(searchFilter))
        {
            activePlayerPrefs = filteredPlayerPrefs;
        }

        // Cache the entry count
        int entryCount = activePlayerPrefs.Count;

        // Record the last scroll position so we can calculate if the user has scrolled this frame
        lastScrollPosition = scrollPosition;

        // Start the scrollable area
        scrollPosition = EditorGUILayout.BeginScrollView(scrollPosition);
        // Ensure the scroll doesn't go below zero
        if (scrollPosition.y < 0)
        {
            scrollPosition.y = 0;
        }

        // The following code has been optimised so that rather than attempting to draw UI for every single PlayerPref
        // it instead only draws the UI for those currently visible in the scroll view and pads above and below those
        // results to maintain the right size using GUILayout.Space(). This enables us to work with thousands of
        // PlayerPrefs without slowing the interface to a halt.

        // Fixed height of one of the rows in the table
        float rowHeight = 18;

        // Determine how many rows are visible on screen. For simplicity, use Screen.height (the overhead is negligible)
        int visibleCount = Mathf.CeilToInt(Screen.height / rowHeight);

        // Determine the index of the first PlayerPref that should be drawn as visible in the scrollable area
        int firstShownIndex = Mathf.FloorToInt(scrollPosition.y / rowHeight);

        // Determine the bottom limit of the visible PlayerPrefs (last shown index + 1)
        int shownIndexLimit = firstShownIndex + visibleCount;

        // If the actual number of PlayerPrefs is smaller than the caculated limit, reduce the limit to match
        if (entryCount < shownIndexLimit)
        {
            shownIndexLimit = entryCount;
        }

        // If the number of displayed PlayerPrefs is smaller than the number we can display (like we're at the end
        // of the list) then move the starting index back to adjust
        if (shownIndexLimit - firstShownIndex < visibleCount)
        {
            firstShownIndex -= visibleCount - (shownIndexLimit - firstShownIndex);
        }

        // Can't have a negative index of a first shown PlayerPref, so clamp to 0
        if (firstShownIndex < 0)
        {
            firstShownIndex = 0;
        }

        // Pad above the on screen results so that we're not wasting draw calls on invisible UI and the drawn player
        // prefs end up in the same place in the list
        GUILayout.Space(firstShownIndex * rowHeight);

        // For each of the on screen results
        for (int i = firstShownIndex; i < shownIndexLimit; i++)
        {
            // Detect if it's an encrypted PlayerPref (these have key prefixes)
            bool isEncryptedPair = PlayerPrefsUtility.IsEncryptedKey(activePlayerPrefs[i].Key);

            // Colour code encrypted PlayerPrefs blue
            if (isEncryptedPair)
            {
                if (UsingProSkin)
                {
                    textFieldStyle.normal.textColor  = new Color(0.5f, 0.5f, 1);
                    textFieldStyle.focused.textColor = new Color(0.5f, 0.5f, 1);
                }
                else
                {
                    textFieldStyle.normal.textColor  = new Color(0, 0, 1);
                    textFieldStyle.focused.textColor = new Color(0, 0, 1);
                }
            }
            else
            {
                // Normal PlayerPrefs are just black
                textFieldStyle.normal.textColor  = GUI.skin.textField.normal.textColor;
                textFieldStyle.focused.textColor = GUI.skin.textField.focused.textColor;
            }

            // The full key is the key that's actually stored in PlayerPrefs
            string fullKey = activePlayerPrefs[i].Key;

            // Display key is used so in the case of encrypted keys, we display the decrypted version instead (in
            // auto-decrypt mode).
            string displayKey = fullKey;

            // Used for accessing the type information stored against the PlayerPref
            object deserializedValue = activePlayerPrefs[i].Value;

            // Track whether the auto decrypt failed, so we can instead fallback to encrypted values and mark it red
            bool failedAutoDecrypt = false;

            // If this is an encrypted play pref and we're attempting to decrypt them, try to decrypt it!
            if (isEncryptedPair && automaticDecryption)
            {
                // This may throw exceptions (e.g. if private key changes), so wrap in a try-catch
                try
                {
                    deserializedValue = PlayerPrefsUtility.GetEncryptedValue(fullKey, (string)deserializedValue);
                    displayKey        = PlayerPrefsUtility.DecryptKey(fullKey);
                }
                catch
                {
                    // Change the colour to red to highlight the decrypt failed
                    textFieldStyle.normal.textColor  = Color.red;
                    textFieldStyle.focused.textColor = Color.red;

                    // Track that the auto decrypt failed, so we can prevent any editing
                    failedAutoDecrypt = true;
                }
            }

            EditorGUILayout.BeginHorizontal();

            // The type of PlayerPref being stored (in auto decrypt mode this works with the decrypted values too)
            Type valueType;

            // If it's an encrypted playerpref, we're automatically decrypting and it didn't fail the earlier
            // auto decrypt test
            if (isEncryptedPair && automaticDecryption && !failedAutoDecrypt)
            {
                // Get the encrypted string
                string encryptedValue = GetString(fullKey);
                // Set valueType appropiately based on which type identifier prefix the encrypted string starts with
                if (encryptedValue.StartsWith(PlayerPrefsUtility.VALUE_FLOAT_PREFIX))
                {
                    valueType = typeof(float);
                }
                else if (encryptedValue.StartsWith(PlayerPrefsUtility.VALUE_INT_PREFIX))
                {
                    valueType = typeof(int);
                }
                else if (encryptedValue.StartsWith(PlayerPrefsUtility.VALUE_BOOL_PREFIX))
                {
                    valueType = typeof(bool);
                }
                else if (encryptedValue.StartsWith(PlayerPrefsUtility.VALUE_STRING_PREFIX) || string.IsNullOrEmpty(encryptedValue))
                {
                    // Special case here, empty encrypted values will also report as strings
                    valueType = typeof(string);
                }
                else
                {
                    throw new InvalidOperationException("Could not decrypt item, no match found in known encrypted key prefixes");
                }
            }
            else
            {
                // Otherwise fallback to the type of the cached value (for non-encrypted values this will be
                // correct). For encrypted values when not in auto-decrypt mode, this will return string type
                valueType = deserializedValue.GetType();
            }

            // Display the PlayerPref key
            EditorGUILayout.TextField(displayKey, textFieldStyle);

            // Value display and user editing
            // If we're dealing with a float
            if (valueType == typeof(float))
            {
                float initialValue;
                if (isEncryptedPair && automaticDecryption)
                {
                    // Automatically decrypt the value if encrypted and in auto-decrypt mode
                    initialValue = PlayerPrefsUtility.GetEncryptedFloat(displayKey);
                }
                else
                {
                    // Otherwise fetch the latest plain value from PlayerPrefs in memory
                    initialValue = GetFloat(fullKey);
                }

                // Display the float editor field and get any changes in value
                float newValue = EditorGUILayout.FloatField(initialValue, textFieldStyle);

                // If the value has changed
                if (newValue != initialValue)
                {
                    // Store the changed value in PlayerPrefs, encrypting if necessary
                    if (isEncryptedPair)
                    {
                        string encryptedValue = PlayerPrefsUtility.VALUE_FLOAT_PREFIX + SimpleEncryption.EncryptFloat(newValue);
                        SetString(fullKey, encryptedValue);
                    }
                    else
                    {
                        SetFloat(fullKey, newValue);
                    }
                    // Save PlayerPrefs
                    Save();
                }
                // Display the PlayerPref type
                GUILayout.Label("float", GUILayout.Width(37));
            }
            else if (valueType == typeof(int)) // if we're dealing with an int
            {
                int initialValue;
                if (isEncryptedPair && automaticDecryption)
                {
                    // Automatically decrypt the value if encrypted and in auto-decrypt mode
                    initialValue = PlayerPrefsUtility.GetEncryptedInt(displayKey);
                }
                else
                {
                    // Otherwise fetch the latest plain value from PlayerPrefs in memory
                    initialValue = GetInt(fullKey);
                }

                // Display the int editor field and get any changes in value
                int newValue = EditorGUILayout.IntField(initialValue, textFieldStyle);

                // If the value has changed
                if (newValue != initialValue)
                {
                    // Store the changed value in PlayerPrefs, encrypting if necessary
                    if (isEncryptedPair)
                    {
                        string encryptedValue = PlayerPrefsUtility.VALUE_INT_PREFIX + SimpleEncryption.EncryptInt(newValue);
                        SetString(fullKey, encryptedValue);
                    }
                    else
                    {
                        SetInt(fullKey, newValue);
                    }
                    // Save PlayerPrefs
                    Save();
                }
                // Display the PlayerPref type
                GUILayout.Label("int", GUILayout.Width(37));
            }
            else if (valueType == typeof(bool)) // if we're dealing with a bool
            {
                bool initialValue;
                if (isEncryptedPair && automaticDecryption)
                {
                    // Automatically decrypt the value if encrypted and in auto-decrypt mode
                    initialValue = PlayerPrefsUtility.GetEncryptedBool(displayKey);
                }
                else
                {
                    // Otherwise fetch the latest plain value from PlayerPrefs in memory
                    initialValue = GetBool(fullKey);
                }

                // Display the bool toggle editor field and get any changes in value
                bool newValue = EditorGUILayout.Toggle(initialValue);

                // If the value has changed
                if (newValue != initialValue)
                {
                    // Store the changed value in PlayerPrefs, encrypting if necessary
                    if (isEncryptedPair)
                    {
                        string encryptedValue = PlayerPrefsUtility.VALUE_BOOL_PREFIX + SimpleEncryption.EncryptBool(newValue);
                        SetString(fullKey, encryptedValue);
                    }
                    else
                    {
                        SetBool(fullKey, newValue);
                    }
                    // Save PlayerPrefs
                    Save();
                }
                // Display the PlayerPref type
                GUILayout.Label("bool", GUILayout.Width(37));
            }
            else if (valueType == typeof(string)) // if we're dealing with a string
            {
                string initialValue;
                if (isEncryptedPair && automaticDecryption && !failedAutoDecrypt)
                {
                    // Automatically decrypt the value if encrypted and in auto-decrypt mode
                    initialValue = PlayerPrefsUtility.GetEncryptedString(displayKey);
                }
                else
                {
                    // Otherwise fetch the latest plain value from PlayerPrefs in memory
                    initialValue = GetString(fullKey);
                }

                // Display the text (string) editor field and get any changes in value
                string newValue = EditorGUILayout.TextField(initialValue, textFieldStyle);

                // If the value has changed
                if (newValue != initialValue && !failedAutoDecrypt)
                {
                    // Store the changed value in PlayerPrefs, encrypting if necessary
                    if (isEncryptedPair)
                    {
                        string encryptedValue = PlayerPrefsUtility.VALUE_STRING_PREFIX + SimpleEncryption.EncryptString(newValue);
                        SetString(fullKey, encryptedValue);
                    }
                    else
                    {
                        SetString(fullKey, newValue);
                    }
                    // Save PlayerPrefs
                    Save();
                }
                if (isEncryptedPair && !automaticDecryption && !string.IsNullOrEmpty(initialValue))
                {
                    // Because encrypted values when not in auto-decrypt mode are stored as string, determine their
                    // encrypted type and display that instead for these encrypted PlayerPrefs
                    PlayerPrefType playerPrefType = (PlayerPrefType)(int)char.GetNumericValue(initialValue[0]);
                    GUILayout.Label(playerPrefType.ToString().ToLower(), GUILayout.Width(37));
                }
                else
                {
                    // Display the PlayerPref type
                    GUILayout.Label("string", GUILayout.Width(37));
                }
            }

            // Delete button
            if (GUILayout.Button("X", GUILayout.Width(25)))
            {
                // Delete the key from PlayerPrefs
                DeleteKey(fullKey);
                // Tell Unity to Save PlayerPrefs
                Save();
                // Delete the cached record so the list updates immediately
                DeleteCachedRecord(fullKey);
            }
            EditorGUILayout.EndHorizontal();
        }

        // Calculate the padding at the bottom of the scroll view (because only visible PlayerPref rows are drawn)
        float bottomPadding = (entryCount - shownIndexLimit) * rowHeight;

        // If the padding is positive, pad the bottom so that the layout and scroll view size is correct still
        if (bottomPadding > 0)
        {
            GUILayout.Space(bottomPadding);
        }

        EditorGUILayout.EndScrollView();

        // Display the number of PlayerPrefs
        GUILayout.Label("Entry Count: " + entryCount);

        Rect rect = GUILayoutUtility.GetLastRect();

        rect.height = 1;
        rect.y     -= 4;
        EditorGUI.DrawRect(rect, new Color(0.5f, 0.5f, 0.5f, 0.5f));
    }