Skip to content

Instantly share code, notes, and snippets.

@pacoelayudante
Created April 2, 2022 17:21
Show Gist options
  • Save pacoelayudante/74602f41ea81f2f901b9faa0dae1d95a to your computer and use it in GitHub Desktop.
Save pacoelayudante/74602f41ea81f2f901b9faa0dae1d95a to your computer and use it in GitHub Desktop.
Unity Decorator Drawer Attribute Display PlayerPrefs or EditorPrefs in the inspector (see comment for an example)
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
#if UNITY_EDITOR
using UnityEditor;
#endif
[System.AttributeUsage(System.AttributeTargets.Field, Inherited = true, AllowMultiple = true)]
public class PlayerPrefsInspector : PropertyAttribute
{
public enum ValueType
{
String,
Float,
Integer
}
public enum PrefType
{
PlayerPref,
EditorPref
}
protected PrefType prefType = PrefType.PlayerPref;
private string key = "";
private ValueType valueType;
private float defaultFloat = 0f;
private int defaultInteger = 0;
private string defaultString = "";
private float min = 0f;
private float max = 0f;
PlayerPrefsInspector(string keyName)
{
this.key = keyName;
}
public PlayerPrefsInspector(string keyName, int defaultValue) : this(keyName)
{
this.valueType = ValueType.Integer;
this.defaultInteger = defaultValue;
}
public PlayerPrefsInspector(string keyName, float defaultValue) : this(keyName)
{
this.valueType = ValueType.Float;
this.defaultFloat = defaultValue;
}
public PlayerPrefsInspector(string keyName, int defaultValue, int minValue, int maxValue) : this(keyName)
{
this.valueType = ValueType.Integer;
this.defaultInteger = defaultValue;
this.min = minValue;
this.max = maxValue;
}
public PlayerPrefsInspector(string keyName, float defaultValue, float minValue, float maxValue) : this(keyName)
{
this.valueType = ValueType.Float;
this.defaultFloat = defaultValue;
this.min = minValue;
this.max = maxValue;
}
public PlayerPrefsInspector(string keyName, string defaultValue) : this(keyName)
{
this.valueType = ValueType.String;
this.defaultString = defaultValue;
}
#if UNITY_EDITOR
[CustomPropertyDrawer(typeof(PlayerPrefsInspector), true)]
public class PlayerPrefsInspectorDrawer : DecoratorDrawer
{
PlayerPrefsInspector PrefsInspector => (PlayerPrefsInspector)attribute;
bool IsPlayerPref => PrefsInspector.prefType == PrefType.PlayerPref;
string Key => PrefsInspector.key;
ValueType ValueType => PrefsInspector.valueType;
bool ConstraintedValue => ValueType != ValueType.String && MaxValue > MinValue;
float MinValue => PrefsInspector.min;
float MaxValue => PrefsInspector.max;
float ResetButtonWidth => EditorGUIUtility.singleLineHeight * 2f;
public override void OnGUI(Rect position)
{
if (string.IsNullOrEmpty(Key))
{
EditorGUILayout.HelpBox("Player Prefs Inspector invalid key", MessageType.Error);
return;
}
position.width -= ResetButtonWidth;
if (ValueType == ValueType.Integer)
DrawIntegerInspector(position);
else if (ValueType == ValueType.Float)
DrawFloatInspector(position);
else if (ValueType == ValueType.String)
DrawStringInspector(position);
bool hasSetValue = IsPlayerPref ? PlayerPrefs.HasKey(Key) : EditorPrefs.HasKey(Key);
using (new EditorGUI.DisabledScope(!hasSetValue))
{
position.x += position.width;
position.width = ResetButtonWidth;
if (GUI.Button(position, "×"))
{
if (IsPlayerPref)
PlayerPrefs.DeleteKey(Key);
else
EditorPrefs.DeleteKey(Key);
}
}
}
private void DrawIntegerInspector(Rect position)
{
using (EditorGUI.ChangeCheckScope scope = new EditorGUI.ChangeCheckScope())
{
int currentValue = IsPlayerPref ? PlayerPrefs.GetInt(Key, PrefsInspector.defaultInteger) : EditorPrefs.GetInt(Key, PrefsInspector.defaultInteger);
if (ConstraintedValue)
currentValue = EditorGUI.IntSlider(position, Key, currentValue, (int)MinValue, (int)MaxValue);
else
currentValue = EditorGUI.IntField(position, Key, currentValue);
if (scope.changed)
{
if (IsPlayerPref)
PlayerPrefs.SetInt(Key, currentValue);
else
EditorPrefs.SetInt(Key, currentValue);
}
}
}
private void DrawFloatInspector(Rect position)
{
using (EditorGUI.ChangeCheckScope scope = new EditorGUI.ChangeCheckScope())
{
float currentValue = IsPlayerPref ? PlayerPrefs.GetFloat(Key, PrefsInspector.defaultFloat) : EditorPrefs.GetFloat(Key, PrefsInspector.defaultFloat);
if (ConstraintedValue)
currentValue = EditorGUI.Slider(position, Key, currentValue, MinValue, MaxValue);
else
currentValue = EditorGUI.FloatField(position, Key, currentValue);
if (scope.changed)
{
if (IsPlayerPref)
PlayerPrefs.SetFloat(Key, currentValue);
else
EditorPrefs.SetFloat(Key, currentValue);
}
}
}
private void DrawStringInspector(Rect position)
{
using (EditorGUI.ChangeCheckScope scope = new EditorGUI.ChangeCheckScope())
{
string currentValue = IsPlayerPref ? PlayerPrefs.GetString(Key, PrefsInspector.defaultString) : EditorPrefs.GetString(Key, PrefsInspector.defaultString);
currentValue = EditorGUI.TextField(position, Key, currentValue);
if (scope.changed)
{
if (IsPlayerPref)
PlayerPrefs.SetString(Key, currentValue);
else
EditorPrefs.SetString(Key, currentValue);
}
}
}
}
#endif
}
public class EditorPrefsInspector : PlayerPrefsInspector
{
public EditorPrefsInspector(string keyName, int defaultValue) : base(keyName, defaultValue)
{
this.prefType = PrefType.EditorPref;
}
public EditorPrefsInspector(string keyName, float defaultValue) : base(keyName, defaultValue)
{
this.prefType = PrefType.EditorPref;
}
public EditorPrefsInspector(string keyName, int defaultValue, int minValue, int maxValue) : base(keyName, defaultValue, minValue, maxValue)
{
this.prefType = PrefType.EditorPref;
}
public EditorPrefsInspector(string keyName, float defaultValue, float minValue, float maxValue) : base(keyName, defaultValue, minValue, maxValue)
{
this.prefType = PrefType.EditorPref;
}
public EditorPrefsInspector(string keyName, string defaultValue) : base(keyName, defaultValue)
{
this.prefType = PrefType.EditorPref;
}
}
@pacoelayudante
Copy link
Author

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PlayerPrefsInspectorSample : MonoBehaviour
{
    private const string KEY_USER_NAME = "LocalUserName";
    private static string LocalUserName => PlayerPrefs.GetString(KEY_USER_NAME, "unset");
    
    private const string KEY_SFX_VOLUME = "SfxVolume";
    private static float SfxVolume => PlayerPrefs.GetFloat(KEY_SFX_VOLUME, 1f);
    
    private const string KEY_LAST_SELECTED_SLOT = "LastSelectedSlot";
    private static float LastSelectedSlot => PlayerPrefs.GetInt(KEY_SFX_VOLUME, -1);

    private const string KEY_DEBUG_SERVER = "DebugServer";
    #if UNITY_EDITOR
    private static string DebugServer => UnityEditor.EditorPrefs.GetString(KEY_DEBUG_SERVER,"");
    #endif

    [PlayerPrefsInspector(KEY_USER_NAME,"unset")]
    [PlayerPrefsInspector(KEY_SFX_VOLUME,1f,0f,1f)]
    [PlayerPrefsInspector(KEY_LAST_SELECTED_SLOT,-1)]
    [EditorPrefsInspector(KEY_DEBUG_SERVER,"")]
    public string requiredFieldAfterAttributes = "sadly necessary field, since decorators can't exist in their own";
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment