【Unity】用于Unity Editor的本地配置管理器
之前一直在使用 EditorPrefs 存储编辑器扩展数据等本地配置,但这种方式会向注册表中写入大量数据,查看和清理的时候都不方便,所以我不太喜欢这种方式。没有使用 ScriptableObject 来保存配置是因为它生成的配置文件要放到 Assets 文件夹中,每次生成这种配置文件,都要在版本控制系统中添加忽略项,容易被遗忘,导致本地设置扩散到整个团队(其实也可以在Assets中创建一个专门放本地配置的不在版本控制中的文件夹,然后将所有本地配置都放在这个文件夹中,但是我不想,哈哈)。
后来在浏览项目工程时,发现工程目录中多了个 UserSettings 文件夹,论坛上查了下,这个文件夹就是用来放本地配置文件的,可以将整个文件夹从版本控制系统中忽略掉。如果可以用这个文件夹来放置自定义编辑器扩展时产生的本地配置文件,可以完美地解决 EditorPrefs 和 ScriptableObject 所带有的问题。但可惜的是,Unity没有提供内置的读写 UserSettings 文件夹中内容的接口,所以这里手动实现了一个用来读写此文件夹中的文件的工具类,提供了配置文件创建和删除、配置项增删查改等方法。
下面是工具类的源代码和一些使用注意事项:
- 依赖JSON .NET For Unity
- 只能用于Unity Editor,不能用于构建后的Unity Player
- 只经过简单测试,性能和可靠性需要进一步验证,如果发现Bug或者有改进建议,请多指教
- 只在Unity 2019.4版本中进行过测试,理论上能够支持更高和更低版本的Unity编辑器
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using Newtonsoft.Json;
public static class CustomUserSettings
{
public static TValue GetValue<TValue>(string settingsName, string valueKey, TValue defaultValue)
{
if (TryGetValue(settingsName, valueKey, out TValue value))
{
return value;
}
return defaultValue;
}
public static bool TryGetValue<TValue>(string settingsName, string valueKey, out TValue value)
{
var settingsDict = GetSettingsDict(settingsName, false);
if (settingsDict != null && settingsDict.TryGetValue(valueKey, out var rawValue))
{
var type = typeof(TValue);
if (type.IsPrimitive)
{
value = (TValue)Convert.ChangeType(rawValue, type);
}
else if (type.IsEnum)
{
value = (TValue)Enum.Parse(type, rawValue.ToString());
}
else if(rawValue is TValue typedValue)
{
value = typedValue;
}
else
{
value = default;
return false;
}
return true;
}
value = default;
return false;
}
public static void SetValue(string settingsName, string valueKey, object value)
{
var settingsDict = GetSettingsDict(settingsName, true);
settingsDict[valueKey] = value;
if (!_internedSettingsDict.ContainsKey(settingsName))
{
var settingsContent = JsonConvert.SerializeObject(settingsDict, Formatting.Indented, _jsonSerializerSettings);
SaveSettingsContent(settingsName, settingsContent);
}
}
public static void DeleteValue(string settingsName, string valueKey)
{
var settingsDict = GetSettingsDict(settingsName, false);
if (settingsDict == null)
{
return;
}
var result = settingsDict.Remove(valueKey);
if (result && !_internedSettingsDict.ContainsKey(settingsName))
{
var settingsContent = JsonConvert.SerializeObject(settingsDict, Formatting.Indented, _jsonSerializerSettings);
SaveSettingsContent(settingsName, settingsContent);
}
}
public static void DeleteSettings(string settingsName)
{
_internedSettingsDict.Remove(settingsName);
var settingsFilePath = GetSettingsFilePath(settingsName);
if (File.Exists(settingsFilePath))
{
File.Delete(settingsFilePath);
}
}
public static void InternSettings(string settingsName)
{
var settingsDict = GetSettingsDict(settingsName, true);
if (!_internedSettingsDict.TryGetValue(settingsName, out var internedSettingsDict))
{
internedSettingsDict = new InternedSettingsDict(settingsDict);
_internedSettingsDict[settingsName] = internedSettingsDict;
}
internedSettingsDict.InternCounter++;
}
public static void ReleaseAndSaveSettings(string settingsName)
{
if (_internedSettingsDict.TryGetValue(settingsName, out var internedSettingsDict))
{
var settingsContent = JsonConvert.SerializeObject(internedSettingsDict.SettingsDict, Formatting.Indented, _jsonSerializerSettings);
SaveSettingsContent(settingsName, settingsContent);
internedSettingsDict.InternCounter--;
if (internedSettingsDict.InternCounter == 0)
{
_internedSettingsDict.Remove(settingsName);
}
}
}
private static Dictionary<string, object> GetSettingsDict(string settingsName, bool createNewIfNotExist)
{
if (_internedSettingsDict.TryGetValue(settingsName, out var internedSettingsDict))
{
return internedSettingsDict.SettingsDict;
}
var settingsContent = LoadSettingsContent(settingsName);
if (string.IsNullOrWhiteSpace(settingsContent))
{
if (createNewIfNotExist)
{
return new Dictionary<string, object>();
}
return null;
}
var settingsDict = JsonConvert.DeserializeObject<Dictionary<string, object>>(settingsContent, _jsonSerializerSettings);
return settingsDict;
}
private static void SaveSettingsContent(string settingsName, string settingsContent)
{
if (string.IsNullOrEmpty(settingsContent))
{
settingsContent = "";
}
var settingsFilePath = GetSettingsFilePath(settingsName);
if (!File.Exists(settingsFilePath))
{
if (!Directory.Exists("UserSettings/"))
Directory.CreateDirectory("UserSettings/");
}
File.WriteAllText(settingsFilePath, settingsContent, Encoding.UTF8);
}
private static string LoadSettingsContent(string settingsName)
{
var settingsFilePath = GetSettingsFilePath(settingsName);
if (!File.Exists(settingsFilePath))
{
return null;
}
var settingsContent = File.ReadAllText(settingsFilePath, Encoding.UTF8);
return settingsContent;
}
private static string GetSettingsFilePath(string settingsName, string fileExtension = ".json")
{
return $"UserSettings/{settingsName}{fileExtension}";
}
private static readonly JsonSerializerSettings _jsonSerializerSettings = new JsonSerializerSettings
{
TypeNameHandling = TypeNameHandling.All,
ReferenceLoopHandling = ReferenceLoopHandling.Ignore,
PreserveReferencesHandling = PreserveReferencesHandling.Objects
};
private static readonly Dictionary<string, InternedSettingsDict> _internedSettingsDict = new Dictionary<string, InternedSettingsDict>();
private class InternedSettingsDict
{
public int InternCounter { get; set; }
public Dictionary<string, object> SettingsDict { get; }
public InternedSettingsDict(Dictionary<string, object> settingsDict)
{
SettingsDict = settingsDict;
}
}
}
|