创建一个PlayerPrefsKey查看器
效果图
前言
PlayerPrefsKey现在其实用得并不多,不过也有一些应用场景。
最近开发过程中,发现要删除一个PlayerPrefsKey,有点麻烦。可以写代码删除 或者 去注册表删除。都是都感觉有点麻烦,而且也没法知道当前已经设置了哪些PlayerPrefsKey。 所以就想做一个窗口来查看当前所有key,并可以支持搜索和删除。
tip:修改功能就不添加了,因为一般删除PlayerPrefsKey让其恢复默认值是安全OK的。但是如果直接不知道它的用处或值域,直接修改,就可能有问题。所以不增加修改功能。
开发
开发分两步:
- 第一步获取所有PlayerPrefsKey数据;
- 第二步根据数据写编辑器窗口;
一、获取数据
获取数据我是直接在网上搜了一下获取方法,找到了这篇博客,获取所有PlayerPrefsKey windows下测试可以拿到所有key. 获取数据可以直接看这个链接。这里我们主要讲一下编辑器窗口。
目录结构
看文章可以知道需要两个工具类: PlayerPrefsExtension.cs 和 Plist.cs.
目录结构如下,包含上面两个工具类,和窗口编辑器PlayerPrefsWindow。工具类代码会在最后提供
二、开发编辑器窗口
效果图
思路
看效果图,可以知道大体分为两部分:最上面的搜索栏 和 下面的主框体。
怎么实现搜索呢:
- 首先,我们可以通过工具类获取到所有的key
- 如果搜索框是空的,我们就把所有数据交给主框体渲染;
- 如果搜索框有数据,我们就把第一步拿到的数据过滤一下,再交给主框体渲染。这样就可以了。
一、绘制搜索栏
private void DrawSearchBar()
{
//绘制label:
GUIStyle labelStyle = new GUIStyle(EditorStyles.boldLabel);
labelStyle.normal.textColor = Color.cyan;
EditorGUILayout.LabelField("输入要搜索的key:",labelStyle,GUILayout.Width(120));
//绘制输入框:
var style = new GUIStyle(EditorStyles.textField);
style.fontStyle = FontStyle.Bold;
searchKey = GUILayout.TextField(searchKey,style,GUILayout.ExpandWidth(true));
//绘制 清空输入 按钮
if (GUILayout.Button("x",btnWidthOpt))
{
searchKey = string.Empty;
}
//绘制 删除所有Key 按钮
if (GUILayout.Button("删除所有",btnWidthOpt))
{
if (EditorUtility.DisplayDialog("删除提示", "确认删除所有key吗?", "确定", "取消"))
{
PlayerPrefs.DeleteAll();
};
}
}
二、定义PlayerPrefs数据结构体
我们用这个结构体来描述每一个PlayerPrefs
[Serializable]
public struct PlayerPrefPair
{
public string Key { get; set; }
public object Value { get; set; }
}
三、根据搜索框过滤数据
searchKey就是搜索框输入的内容,如果有输入,我们就过滤数据
private void FillDataList(ref List<PlayerPrefPair> list)
{
list.Clear();
list = PlayerPrefsExtension.GetAll().ToList();
if (!string.IsNullOrEmpty(searchKey))
{
for (int i = 0; i < list.Count; i++)
{
if (!list[i].Key.ToLower().Contains(searchKey.ToLower()))
{
list.RemoveAt(i);
i--;
}
}
}
}
四、绘制主框体
因为内容有可能超过窗口,所以这里用了ScrollView,当内容超出时,可以滑动窗口
private void DrawMainWindow(List<PlayerPrefPair> dataList)
{
Rect rect = new Rect(0,searchBarHeight + 10,position.width,position.height);
GUILayout.BeginArea(rect);
scrollViewPos = GUILayout.BeginScrollView(scrollViewPos,false,true,GUILayout.Height(1000));
GUILayout.BeginVertical();
foreach (PlayerPrefPair pair in dataList)
{
if (!PlayerPrefs.HasKey(pair.Key))
{
continue;
}
GUILayout.BeginHorizontal();
EditorGUILayout.TextField(pair.Key+":",pair.Value.ToString());
GUILayout.ExpandWidth(true);
if (GUILayout.Button("删除Key",btnWidthOpt))
{
if (PlayerPrefs.HasKey(pair.Key))
{
PlayerPrefs.DeleteKey(pair.Key);
Debug.Log($"{
GetType()} delete key success,key:{
pair.Key}");
}
}
GUILayout.EndHorizontal();
}
GUILayout.EndVertical();
GUILayout.EndScrollView();
GUILayout.EndArea();
}
五、完整代码
PlayerPrefsWindow.cs
using UnityEditor;
using UnityEngine;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using UnityEditor;
using UnityEngine;
[Serializable]
public struct PlayerPrefPair
{
public string Key {
get; set; }
public object Value {
get; set; }
}
public class PlayerPrefsWindow : EditorWindow
{
private Vector2 scrollViewPos;
private string searchKey = string.Empty;
private List<PlayerPrefPair> dataList = new List<PlayerPrefPair>();
private float searchBarHeight = 30;
private GUILayoutOption btnWidthOpt = GUILayout.Width(125);
[MenuItem("Tool/PlayerPrefsWindow %q")]
public static void OpenWindow()
{
PlayerPrefsWindow window = UnityEditor.EditorWindow.GetWindow<PlayerPrefsWindow>();
window.name = "PlayerPrefs窗口";
}
public void OnGUI()
{
GUILayout.BeginVertical();
Rect rect = new Rect(0, 0, position.width, searchBarHeight);
GUILayout.BeginArea(rect);
{
GUI.Box(rect,"");
//搜索
GUILayout.BeginHorizontal();
DrawSearchBar();
GUILayout.EndHorizontal();
}
GUILayout.EndArea();
//数据
FillDataList(ref dataList);
//主框体
DrawMainWindow(dataList);
GUILayout.EndVertical();
}
private void DrawSearchBar()
{
//绘制label:
GUIStyle labelStyle = new GUIStyle(EditorStyles.boldLabel);
labelStyle.normal.textColor = Color.cyan;
EditorGUILayout.LabelField("输入要搜索的key:",labelStyle,GUILayout.Width(120));
//绘制输入框:
var style = new GUIStyle(EditorStyles.textField);
style.fontStyle = FontStyle.Bold;
searchKey = GUILayout.TextField(searchKey,style,GUILayout.ExpandWidth(true));
//绘制 清空输入 按钮
if (GUILayout.Button("x",btnWidthOpt))
{
searchKey = string.Empty;
}
//绘制 删除所有Key 按钮
if (GUILayout.Button("删除所有",btnWidthOpt))
{
if (EditorUtility.DisplayDialog("删除提示", "确认删除所有key吗?", "确定", "取消"))
{
PlayerPrefs.DeleteAll();
};
}
}
private void FillDataList(ref List<PlayerPrefPair> list)
{
list.Clear();
list = PlayerPrefsExtension.GetAll().ToList();
if (!string.IsNullOrEmpty(searchKey))
{
for (int i = 0; i < list.Count; i++)
{
if (!list[i].Key.ToLower().Contains(searchKey.ToLower()))
{
list.RemoveAt(i);
i--;
}
}
}
}
private void DrawMainWindow(List<PlayerPrefPair> dataList)
{
Rect rect = new Rect(0,searchBarHeight + 10,position.width,position.height);
GUILayout.BeginArea(rect);
scrollViewPos = GUILayout.BeginScrollView(scrollViewPos,false,true,GUILayout.Height(1000));
GUILayout.BeginVertical();
foreach (PlayerPrefPair pair in dataList)
{
if (!PlayerPrefs.HasKey(pair.Key))
{
continue;
}
GUILayout.BeginHorizontal();
EditorGUILayout.TextField(pair.Key+":",pair.Value.ToString());
GUILayout.ExpandWidth(true);
if (GUILayout.Button("删除Key",btnWidthOpt))
{
if (PlayerPrefs.HasKey(pair.Key))
{
PlayerPrefs.DeleteKey(pair.Key);
Debug.Log($"{
GetType()} delete key success,key:{
pair.Key}");
}
}
GUILayout.EndHorizontal();
}
GUILayout.EndVertical();
GUILayout.EndScrollView();
GUILayout.EndArea();
}
}
PlayerPrefsExtension.cs
using UnityEditor;
using UnityEngine;
using System;
using System.Collections.Generic;
using System.IO;
using PlistCS;
using UnityEditor;
using UnityEngine;
public static class PlayerPrefsExtension
{
public static PlayerPrefPair[] GetAll()
{
return GetAll(PlayerSettings.companyName, PlayerSettings.productName);
}
public static PlayerPrefPair[] GetAll(string companyName, string productName)
{
if (Application.platform == RuntimePlatform.OSXEditor)
{
// From Unity docs: On Mac OS X PlayerPrefs are stored in ~/Library/Preferences folder, in a file named unity.[company name].[product name].plist, where company and product names are the names set up in Project Settings. The same .plist file is used for both Projects run in the Editor and standalone players.
// Construct the plist filename from the project's settings
string plistFilename = string.Format("unity.{0}.{1}.plist", companyName, productName);
// Now construct the fully qualified path
string playerPrefsPath = Path.Combine(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Personal), "Library/Preferences"),
plistFilename);
// Parse the player prefs file if it exists
if (File.Exists(playerPrefsPath))
{
// Parse the plist then cast it to a Dictionary
object plist = Plist.readPlist(playerPrefsPath);
Dictionary<string, object> parsed = plist as Dictionary<string, object>;
// Convert the dictionary data into an array of PlayerPrefPairs
PlayerPrefPair[] tempPlayerPrefs = new PlayerPrefPair[parsed.Count];
int i = 0;
foreach (KeyValuePair<string, object> pair in parsed)
{
if (pair.Value.GetType() == typeof(double))
{
// Some float values may come back as double, so convert them back to floats
tempPlayerPrefs[i] = new PlayerPrefPair() {
Key = pair.Key, Value = (float) (double) pair.Value};
}
else
{
tempPlayerPrefs[i] = new PlayerPrefPair() {
Key = pair.Key, Value = pair.Value};
}
i++;