本文介绍如何在Editor下获取PlayerPrefs所有键值对,欢迎访问😁

本篇文章,如果有不懂,欢迎留言~click here!

PlayerPrefs官方文档,请戳这里~click here!

正文

关于PlayerPrefs使用细节就不介绍了,实际上,在开发中,已经没怎么使用PlayerPrefs了,这里只是单纯的介绍一下如何获取所有的键值对,毕竟Unity并没有提供直接的接口。

PlayerPrefs接口列表

只有DeleteAll接口,没有GetAll接口。

本篇文章的主要代码来源于PlayerPrefs Editor插件,插件自行下载。

数据存储

官方文档中有介绍,MacOS下存储在~/Library/Preferences文件夹下的unity.[company name].[product name].plist文件中,而Window下\Software[company name][product name]注册表中,因此待会儿获取代码中,MacOS下需要解析到plist文件,而Window下则需要读取注册表。

定义一个结构体PlayerPrefPair对应keyvalue键值对。

1
2
3
4
5
6
7
8
9
using System;

[Serializable]
public struct PlayerPrefPair
{
public string Key { get; set; }

public object Value { get; set; }
}

获取键值对的主要代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
using System;
using System.Collections.Generic;
using System.IO;
using Sabresaurus.PlayerPrefsExtensions;
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++;
}

// Return the results
return tempPlayerPrefs;
}
else
{
// No existing player prefs saved (which is valid), so just return an empty array
return new PlayerPrefPair[0];
}
}
else if (Application.platform == RuntimePlatform.WindowsEditor)
{
// From Unity docs: On Windows, PlayerPrefs are stored in the registry under HKCU\Software\[company name]\[product name] key, where company and product names are the names set up in Project Settings.
#if UNITY_5_5_OR_NEWER
// From Unity 5.5 editor player prefs moved to a specific location
Microsoft.Win32.RegistryKey registryKey =
Microsoft.Win32.Registry.CurrentUser.OpenSubKey("Software\\Unity\\UnityEditor\\" + companyName + "\\" + productName);
#else
Microsoft.Win32.RegistryKey registryKey = Microsoft.Win32.Registry.CurrentUser.OpenSubKey("Software\\" + companyName + "\\" + productName);
#endif

// Parse the registry if the specified registryKey exists
if (registryKey != null)
{
// Get an array of what keys (registry value names) are stored
string[] valueNames = registryKey.GetValueNames();

// Create the array of the right size to take the saved player prefs
PlayerPrefPair[] tempPlayerPrefs = new PlayerPrefPair[valueNames.Length];

// Parse and convert the registry saved player prefs into our array
int i = 0;
foreach (string valueName in valueNames)
{
string key = valueName;

// Remove the _h193410979 style suffix used on player pref keys in Windows registry
int index = key.LastIndexOf("_");
key = key.Remove(index, key.Length - index);

// Get the value from the registry
object ambiguousValue = registryKey.GetValue(valueName);

// Unfortunately floats will come back as an int (at least on 64 bit) because the float is stored as
// 64 bit but marked as 32 bit - which confuses the GetValue() method greatly!
if (ambiguousValue.GetType() == typeof(int))
{
// If the player pref is not actually an int then it must be a float, this will evaluate to true
// (impossible for it to be 0 and -1 at the same time)
if (PlayerPrefs.GetInt(key, -1) == -1 && PlayerPrefs.GetInt(key, 0) == 0)
{
// Fetch the float value from PlayerPrefs in memory
ambiguousValue = PlayerPrefs.GetFloat(key);
}
}
else if (ambiguousValue.GetType() == typeof(byte[]))
{
// On Unity 5 a string may be stored as binary, so convert it back to a string
ambiguousValue = System.Text.Encoding.Default.GetString((byte[]) ambiguousValue);
}

// Assign the key and value into the respective record in our output array
tempPlayerPrefs[i] = new PlayerPrefPair() {Key = key, Value = ambiguousValue};
i++;
}

// Return the results
return tempPlayerPrefs;
}
else
{
// No existing player prefs saved (which is valid), so just return an empty array
return new PlayerPrefPair[0];
}
}
else
{
throw new NotSupportedException("PlayerPrefsEditor doesn't support this Unity Editor platform");
}
}
}

其中关于MacOS下解析plist文件呢,PlayerPrefsEditor插件里使用的一个开源库:https://github.com/animetrics/PlistCS

最后,编写一点测试代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
using UnityEditor;

public class PlayerPrefsTool : Editor
{
[MenuItem("Tools/PrintAllPlayerPrefs")]
public static void LogAllPlayerPrefs()
{
PlayerPrefPair[] keyValues = PlayerPrefsExtension.GetAll();
for (int i = 0; i < keyValues.Length; i++)
{
UnityEngine.Debug.Log($"key={keyValues[i].Key} value={keyValues[i].Value}");
}
}
}

这里并不包含如何在移动端获取到所有键值对,个人建议自行编写一个数据本地存储,方便无坑无烦恼。。。

以上知识分享,如有错误,欢迎指出,共同学习,共同进步。如果有不懂,欢迎留言评论!