Unity編輯器拓展之三十一:獲取PlayerPrefs所有鍵值對

博客遷移

個人博客站點,歡迎訪問,www.jiingfengji.tech

本文地址

PlayerPrefs官方文檔,請戳這裏~~~

正文

關於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鍵值對。

using System;

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

    public object Value { get; set; }
}

獲取鍵值對的主要代碼:

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

最後,編寫一點測試代碼:

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}");
		}
	}
}

以上知識分享,如有錯誤,歡迎指出,共同學習,共同進步。如果有不懂,歡迎留言評論!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章