PackageSettingsRepository.cs 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205
  1. using System;
  2. using System.IO;
  3. using UnityEngine;
  4. namespace UnityEditor.SettingsManagement
  5. {
  6. /// <inheritdoc />
  7. /// <summary>
  8. /// A settings repository that stores data local to a Unity project.
  9. /// </summary>
  10. [Serializable]
  11. public sealed class PackageSettingsRepository : ISettingsRepository
  12. {
  13. const string k_PackageSettingsDirectory = "ProjectSettings/Packages";
  14. const bool k_PrettyPrintJson = true;
  15. bool m_Initialized;
  16. [SerializeField]
  17. string m_Name;
  18. [SerializeField]
  19. string m_Path;
  20. [SerializeField]
  21. SettingsDictionary m_Dictionary = new SettingsDictionary();
  22. string m_cachedJson;
  23. /// <summary>
  24. /// Constructor sets the serialized data path.
  25. /// </summary>
  26. /// <param name="package">
  27. /// The package name.
  28. /// </param>
  29. /// <param name="name">
  30. /// A name for this settings file. Settings are saved in `ProjectSettings/Packages/{package}/{name}.json`.
  31. /// </param>
  32. public PackageSettingsRepository(string package, string name)
  33. {
  34. m_Name = name;
  35. m_Path = GetSettingsPath(package, name);
  36. m_Initialized = false;
  37. AssemblyReloadEvents.beforeAssemblyReload += Save;
  38. EditorApplication.quitting += Save;
  39. }
  40. void Init()
  41. {
  42. if (m_Initialized)
  43. return;
  44. m_Initialized = true;
  45. if (File.Exists(path))
  46. {
  47. m_Dictionary = null;
  48. m_cachedJson = File.ReadAllText(path);
  49. EditorJsonUtility.FromJsonOverwrite(m_cachedJson, this);
  50. if (m_Dictionary == null)
  51. m_Dictionary = new SettingsDictionary();
  52. }
  53. }
  54. /// <value>
  55. /// This repository implementation is relevant to the Project scope.
  56. /// </value>
  57. /// <inheritdoc cref="ISettingsRepository.scope"/>
  58. public SettingsScope scope
  59. {
  60. get { return SettingsScope.Project; }
  61. }
  62. /// <value>
  63. /// The full path to the settings file.
  64. /// This corresponds to `Unity Project/Project Settings/Packages/com.unity.package/name`.
  65. /// </value>
  66. /// <inheritdoc cref="ISettingsRepository.path"/>
  67. public string path
  68. {
  69. get { return m_Path; }
  70. }
  71. /// <summary>
  72. /// The name of this settings file.
  73. /// </summary>
  74. public string name
  75. {
  76. get { return m_Name; }
  77. }
  78. // Cannot call FindFromAssembly from a constructor or field initializer
  79. // static string CreateSettingsPath(Assembly assembly, string name)
  80. // {
  81. // var info = PackageManager.PackageInfo.FindForAssembly(assembly);
  82. // return string.Format("{0}/{1}/{2}.json", k_PackageSettingsDirectory, info.name, name);
  83. // }
  84. /// <summary>
  85. /// Get a path for a settings file relative to the calling assembly package directory.
  86. /// </summary>
  87. /// <param name="packageName">The name of the package requesting this setting.</param>
  88. /// <param name="name">An optional name for the settings file. Default is "Settings."</param>
  89. /// <returns>A package-scoped path to the settings file within Project Settings.</returns>
  90. public static string GetSettingsPath(string packageName, string name = "Settings")
  91. {
  92. return string.Format("{0}/{1}/{2}.json", k_PackageSettingsDirectory, packageName, name);
  93. }
  94. /// <summary>
  95. /// Save all settings to their serialized state.
  96. /// </summary>
  97. /// <inheritdoc cref="ISettingsRepository.Save"/>
  98. public void Save()
  99. {
  100. Init();
  101. if (!File.Exists(path))
  102. {
  103. var directory = Path.GetDirectoryName(path);
  104. Directory.CreateDirectory(directory);
  105. }
  106. string newSettingsJson = EditorJsonUtility.ToJson(this, k_PrettyPrintJson);
  107. bool areJsonsEqual = newSettingsJson == m_cachedJson;
  108. #if UNITY_2019_3_OR_NEWER
  109. if (!AssetDatabase.IsOpenForEdit(path) && areJsonsEqual == false)
  110. {
  111. if (!AssetDatabase.MakeEditable(path))
  112. {
  113. Debug.LogWarning($"Could not save package settings to {path}");
  114. return;
  115. }
  116. }
  117. #endif
  118. try
  119. {
  120. if (!areJsonsEqual)
  121. {
  122. File.WriteAllText(path, newSettingsJson);
  123. m_cachedJson = newSettingsJson;
  124. }
  125. }
  126. catch (UnauthorizedAccessException)
  127. {
  128. Debug.LogWarning($"Could not save package settings to {path}");
  129. }
  130. }
  131. /// <summary>
  132. /// Set a value for key of type T.
  133. /// </summary>
  134. /// <param name="key">The settings key.</param>
  135. /// <param name="value">The value to set. Must be serializable.</param>
  136. /// <typeparam name="T">Type of value.</typeparam>
  137. /// <inheritdoc cref="ISettingsRepository.Set{T}"/>
  138. public void Set<T>(string key, T value)
  139. {
  140. Init();
  141. m_Dictionary.Set<T>(key, value);
  142. }
  143. /// <summary>
  144. /// Get a value with key of type T, or return the fallback value if no matching key is found.
  145. /// </summary>
  146. /// <param name="key">The settings key.</param>
  147. /// <param name="fallback">If no key with a value of type T is found, this value is returned.</param>
  148. /// <typeparam name="T">Type of value to search for.</typeparam>
  149. /// <inheritdoc cref="ISettingsRepository.Get{T}"/>
  150. public T Get<T>(string key, T fallback = default(T))
  151. {
  152. Init();
  153. return m_Dictionary.Get<T>(key, fallback);
  154. }
  155. /// <summary>
  156. /// Does the repository contain a setting with key and type.
  157. /// </summary>
  158. /// <param name="key">The settings key.</param>
  159. /// <typeparam name="T">The type of value to search for.</typeparam>
  160. /// <returns>True if a setting matching both key and type is found, false if no entry is found.</returns>
  161. /// <inheritdoc cref="ISettingsRepository.ContainsKey{T}"/>
  162. public bool ContainsKey<T>(string key)
  163. {
  164. Init();
  165. return m_Dictionary.ContainsKey<T>(key);
  166. }
  167. /// <summary>
  168. /// Remove a key value pair from the settings repository.
  169. /// </summary>
  170. /// <param name="key"></param>
  171. /// <typeparam name="T"></typeparam>
  172. /// <inheritdoc cref="ISettingsRepository.Remove{T}"/>
  173. public void Remove<T>(string key)
  174. {
  175. Init();
  176. m_Dictionary.Remove<T>(key);
  177. }
  178. }
  179. }