ScriptableSignleton.cs 2.6 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788
  1. using System;
  2. using System.IO;
  3. using System.Linq;
  4. using UnityEditor;
  5. using UnityEditorInternal;
  6. using UnityEngine;
  7. namespace HybridCLR.Editor.Settings
  8. {
  9. public class ScriptableSingleton<T> : ScriptableObject where T : ScriptableObject
  10. {
  11. private static T s_Instance;
  12. public static T Instance
  13. {
  14. get
  15. {
  16. if (!s_Instance)
  17. {
  18. LoadOrCreate();
  19. }
  20. return s_Instance;
  21. }
  22. }
  23. public static T LoadOrCreate()
  24. {
  25. string filePath = GetFilePath();
  26. if (!string.IsNullOrEmpty(filePath))
  27. {
  28. var arr = InternalEditorUtility.LoadSerializedFileAndForget(filePath);
  29. s_Instance = arr.Length > 0 ? arr[0] as T : s_Instance??CreateInstance<T>();
  30. }
  31. else
  32. {
  33. Debug.LogError($"save location of {nameof(ScriptableSingleton<T>)} is invalid");
  34. }
  35. return s_Instance;
  36. }
  37. public static void Save(bool saveAsText = true)
  38. {
  39. if (!s_Instance)
  40. {
  41. Debug.LogError("Cannot save ScriptableSingleton: no instance!");
  42. return;
  43. }
  44. string filePath = GetFilePath();
  45. if (!string.IsNullOrEmpty(filePath))
  46. {
  47. string directoryName = Path.GetDirectoryName(filePath);
  48. if (!Directory.Exists(directoryName))
  49. {
  50. Directory.CreateDirectory(directoryName);
  51. }
  52. UnityEngine.Object[] obj = new T[1] { s_Instance };
  53. InternalEditorUtility.SaveToSerializedFileAndForget(obj, filePath, saveAsText);
  54. }
  55. }
  56. protected static string GetFilePath()
  57. {
  58. return typeof(T).GetCustomAttributes(inherit: true)
  59. .Cast<FilePathAttribute>()
  60. .FirstOrDefault(v => v != null)
  61. ?.filepath;
  62. }
  63. }
  64. [AttributeUsage(AttributeTargets.Class)]
  65. public class FilePathAttribute : Attribute
  66. {
  67. internal string filepath;
  68. /// <summary>
  69. /// 单例存放路径
  70. /// </summary>
  71. /// <param name="path">相对 Project 路径</param>
  72. public FilePathAttribute(string path)
  73. {
  74. if (string.IsNullOrEmpty(path))
  75. {
  76. throw new ArgumentException("Invalid relative path (it is empty)");
  77. }
  78. if (path[0] == '/')
  79. {
  80. path = path.Substring(1);
  81. }
  82. filepath = path;
  83. }
  84. }
  85. }