先看一下最终效果
这是ProjectSetting窗口效果,我实际存储了TBCEditorSetting.asset这个资源的GUID,这里只是重写了GUI
数据存储在ProjectSettings/TBCFrameworkSettings.asset
这里要注意的是这个asset文件不在Assets文件夹下,所以不能使用AssetDatabase来加载,需要使用InternalEditorUtility的LoadSerializedFileAndForget与SaveToSerializedFileAndForget接口进行加载与创建/保存
另一个注意点是继承ScriptableObject的类的文件夹要与类名保存一致,和Momobehaivor脚本一样
using System.Collections; using System.Collections.Generic; using UnityEditor; using UnityEditorInternal; using UnityEngine; using UnityEngine.UIElements; namespace TBC.Editor { class TBCProjectSettings: ScriptableObject { [System.Serializable] class SerializeProperty { public string Key; public string Value; } //serialize cache [SerializeField] List<SerializeProperty> m_Cache = new List<SerializeProperty>(); //runtime cache Dictionary<string, string> m_RTCache = new Dictionary<string, string>(); //save path const string s_AssetPath = "ProjectSettings/TBCFrameworkSettings.asset"; static TBCProjectSettings s_Instance; static TBCProjectSettings Instance { get { if (s_Instance == null) { var objs = InternalEditorUtility.LoadSerializedFileAndForget(s_AssetPath); if (objs != null && objs.Length > 0) { s_Instance = objs[0] as TBCProjectSettings; Debug.LogError(objs[0]); } if (s_Instance == null) { s_Instance = ScriptableObject.CreateInstance<TBCProjectSettings>(); s_Instance.hideFlags = HideFlags.HideAndDontSave; } Init(); } return s_Instance; } } static void Init() { Instance.m_RTCache.Clear(); foreach (var v in Instance.m_Cache) Instance.m_RTCache.Add(v.Key, v.Value); } internal static string GetValue(string key) { string v; Instance.m_RTCache.TryGetValue(key, out v); return v; } internal static void SetValue(string key,string value) { if (Instance.m_RTCache.ContainsKey(key)) { Instance.m_RTCache[key] = value; } else { Instance.m_RTCache.Add(key, value); Instance.m_Cache.Add(new SerializeProperty() { Key = key, Value = value }); } } internal static void Save() { InternalEditorUtility.SaveToSerializedFileAndForget(new Object[] { Instance }, s_AssetPath, true); } } }
扩展ProjectSetting窗口需要用到SettingsProvider,详情参见官方文档,很详细
这里简单总结一下,SettingsProvider有两种用法,第一种是通过一个静态函数加标签创建SettingsProvider对象,然后通过里面的回调函数进行扩展
第二种是自己写一个类,继承SettingsProvider,然后通过override接口的方式进行扩展
这里我用的第一种方法,代码如下,供参考
using System.Collections; using System.Collections.Generic; using UnityEditor; using UnityEditorInternal; using UnityEngine; using UnityEngine.UIElements; namespace TBC.Editor { internal static class TBCProjectSettingsWindow { static GUIContent m_EditorSettingLabel = new GUIContent("Scriptable TBC Editor Settings"); static string m_EditorSettingAssetGUID = "_TBCFramework(EditorSettingAssetGUID)"; static Object m_EditorSettingAsset; [SettingsProvider] static SettingsProvider CreateTBCFrameworkSettingsProvider() { var provider = new SettingsProvider("Project/TBC Framework", SettingsScope.Project) { guiHandler = (searchContext) => { EditorGUI.BeginChangeCheck(); EditorGUILayout.BeginVertical(GUI.skin.box); EditorGUILayout.BeginVertical(EditorStyles.helpBox); EditorGUILayout.LabelField(m_EditorSettingLabel); var lastAsset = m_EditorSettingAsset; m_EditorSettingAsset = EditorGUILayout.ObjectField(m_EditorSettingAsset, typeof(TBCEditorSetting), false); if (m_EditorSettingAsset != lastAsset) { var path = m_EditorSettingAsset != null ? AssetDatabase.GetAssetPath(m_EditorSettingAsset) : null; var guid = !string.IsNullOrEmpty(path) ? AssetDatabase.AssetPathToGUID(path) : null; TBCProjectSettings.SetValue(m_EditorSettingAssetGUID, guid); } EditorGUILayout.EndVertical(); EditorGUILayout.EndVertical(); if (EditorGUI.EndChangeCheck()) TBCProjectSettings.Save(); }, activateHandler = (string a, VisualElement b) => { var scriptableGuid = TBCProjectSettings.GetValue(m_EditorSettingAssetGUID); if (!string.IsNullOrEmpty(scriptableGuid)) { var path = AssetDatabase.GUIDToAssetPath(scriptableGuid); m_EditorSettingAsset = !string.IsNullOrEmpty(path) ? AssetDatabase.LoadAssetAtPath<Object>(path) : null; } }, keywords = new HashSet<string>(new[] { "TBC", "TBCEditorSetting" }) }; return provider; } } }
如果要扩展Preferences只需要将枚举改成SettingsScope.User即可
文章评论