2
0

ProjectLibrary.cs 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514
  1. using System;
  2. using System.Collections.Generic;
  3. using System.IO;
  4. using System.Runtime.CompilerServices;
  5. using BansheeEngine;
  6. namespace BansheeEditor
  7. {
  8. /// <summary>
  9. /// The primary location for interacting with all the resources in the current project. A complete hierarchy of
  10. /// resources is provided which can be interacted with by importing new ones, deleting them, moving, renaming and similar.
  11. /// </summary>
  12. public sealed class ProjectLibrary : ScriptObject
  13. {
  14. /// <summary>
  15. /// Root entry of the project library, referencing the top level resources folder.
  16. /// </summary>
  17. public static DirectoryEntry Root { get { return Internal_GetRoot(); } }
  18. /// <summary>
  19. /// Absolute path to the current project's project library resource folder.
  20. /// </summary>
  21. public static string ResourceFolder { get { return Internal_GetResourceFolder(); } }
  22. /// <summary>
  23. /// Triggered when a new entry is added to the project library. Provided path relative to the project library
  24. /// resources folder.
  25. /// </summary>
  26. public static event Action<string> OnEntryAdded;
  27. /// <summary>
  28. /// Triggered when an entry is removed from the project library. Provided path relative to the project library
  29. /// resources folder.
  30. /// </summary>
  31. public static event Action<string> OnEntryRemoved;
  32. /// <summary>
  33. /// Triggered when an entry is (re)imported in the project library. Provided path relative to the project library
  34. /// resources folder.
  35. /// </summary>
  36. public static event Action<string> OnEntryImported;
  37. private static HashSet<string> queuedForImport = new HashSet<string>();
  38. private static int numImportedFiles;
  39. private static int totalFilesToImport;
  40. private static bool importInProgress;
  41. private const float TIME_SLICE_SECONDS = 0.030f;
  42. /// <summary>
  43. /// Checks the project library folder for any modifications and reimports the required resources.
  44. /// </summary>
  45. /// <param name="synchronous">If true this method will block until the project library has done refreshing,
  46. /// otherwise the refresh will happen over the course of this and next frames.</param>
  47. public static void Refresh(bool synchronous = false)
  48. {
  49. string[] modifiedPaths = Internal_Refresh(ResourceFolder, synchronous);
  50. if (!synchronous)
  51. {
  52. foreach (var modifiedPath in modifiedPaths)
  53. {
  54. if (queuedForImport.Add(modifiedPath))
  55. totalFilesToImport++;
  56. }
  57. }
  58. else
  59. {
  60. foreach (var path in queuedForImport)
  61. Internal_Refresh(path, true);
  62. queuedForImport.Clear();
  63. numImportedFiles = 0;
  64. totalFilesToImport = 0;
  65. }
  66. }
  67. /// <summary>
  68. /// Checks the specified folder for any modifications and reimports the required resources.
  69. /// </summary>
  70. /// <param name="path">Path to a file or folder to refresh. Relative to the project library resources folder or
  71. /// absolute.</param>
  72. public static void Refresh(string path)
  73. {
  74. string[] modifiedPaths = Internal_Refresh(path, false);
  75. foreach (var modifiedPath in modifiedPaths)
  76. {
  77. if (queuedForImport.Add(modifiedPath))
  78. totalFilesToImport++;
  79. }
  80. }
  81. /// <summary>
  82. /// Registers a new resource in the library.
  83. /// </summary>
  84. /// <param name="resource">Resource instance to add to the library. A copy of the resource will be saved at the
  85. /// provided path.</param>
  86. /// <param name="path">Path where where to store the resource. Absolute or relative to the resources folder.</param>
  87. public static void Create(Resource resource, string path)
  88. {
  89. Internal_Create(resource, path);
  90. }
  91. /// <summary>
  92. /// Updates a resource that is already in the library.
  93. /// </summary>
  94. /// <param name="resource">Resource to save.</param>
  95. public static void Save(Resource resource)
  96. {
  97. Internal_Save(resource);
  98. }
  99. /// <summary>
  100. /// Loads a resource from the project library.
  101. /// </summary>
  102. /// <typeparam name="T">Type of the resource to load.</typeparam>
  103. /// <param name="path">Path of the resource to load. Absolute or relative to the resources folder.</param>
  104. /// <returns>Instance of the loaded resource, or null if not found.</returns>
  105. public static T Load<T>(string path) where T : Resource
  106. {
  107. return (T) Internal_Load(path);
  108. }
  109. /// <summary>
  110. /// Triggers a reimport of a resource using the provided import options, if needed.
  111. /// </summary>
  112. /// <param name="path">Path to the resource to reimport, absolute or relative to resources folder.</param>
  113. /// <param name="options">ptional import options to use when importing the resource. Caller must ensure the import
  114. /// options are of the correct type for the resource in question. If null is provided default
  115. /// import options are used.</param>
  116. /// <param name="force">Should the resource be reimported even if no changes are detected.</param>
  117. public static void Reimport(string path, ImportOptions options = null, bool force = false)
  118. {
  119. Internal_Reimport(path, options, force);
  120. }
  121. /// <summary>
  122. /// Checks does the project library contain a resource at the specified path.
  123. /// </summary>
  124. /// <param name="path">Path to the resource to check, absolute or relative to resources folder.</param>
  125. /// <returns>True if the resourc exists, false otherwise.</returns>
  126. public static bool Exists(string path)
  127. {
  128. return GetEntry(path) != null;
  129. }
  130. /// <summary>
  131. /// Attempts to locate a library entry that describes a file or a folder in the project library.
  132. /// </summary>
  133. /// <param name="path">Path to the entry to retrieve, absolute or relative to resources folder.</param>
  134. /// <returns>Library entry if found, null otherwise. This object can become invalid on the next library refresh
  135. /// and you are not meant to hold a permanent reference to it.</returns>
  136. public static LibraryEntry GetEntry(string path)
  137. {
  138. return Internal_GetEntry(path);
  139. }
  140. /// <summary>
  141. /// Searches the library for a pattern and returns all entries matching it.
  142. /// </summary>
  143. /// <param name="pattern">Pattern to search for. Use wildcard * to match any character(s).</param>
  144. /// <param name="types">Type of resources to search for. If null all entries will be searched.</param>
  145. /// <returns>A set of entries matching the pattern. These objects can become invalid on the next library refresh
  146. /// and you are not meant to hold a permanent reference to them.</returns>
  147. public static LibraryEntry[] Search(string pattern, ResourceType[] types = null)
  148. {
  149. return Internal_Search(pattern, types);
  150. }
  151. /// <summary>
  152. /// Returns a path to a resource stored in the project library.
  153. /// </summary>
  154. /// <param name="resource">Resource to find the path for.</param>
  155. /// <returns>Path to relative to the project library resources folder if resource was found, null otherwise.
  156. /// </returns>
  157. public static string GetPath(Resource resource)
  158. {
  159. return Internal_GetPath(resource);
  160. }
  161. /// <summary>
  162. /// Returns a path to a resource with the specified UUID stored in the project library.
  163. /// </summary>
  164. /// <param name="uuid">Unique identifier of the resources to retrieve the path of.</param>
  165. /// <returns>Path to relative to the project library resources folder if resource was found, null otherwise.
  166. /// </returns>
  167. public static string GetPath(string uuid)
  168. {
  169. return Internal_GetPathFromUUID(uuid);
  170. }
  171. /// <summary>
  172. /// Deletes a resource in the project library.
  173. /// </summary>
  174. /// <param name="path">Path to the entry to delete, absolute or relative to resources folder.</param>
  175. public static void Delete(string path)
  176. {
  177. Internal_Delete(path);
  178. }
  179. /// <summary>
  180. /// Creates a new folder in the library.
  181. /// </summary>
  182. /// <param name="path">Path of the folder to create. Absolute or relative to the resources folder.</param>
  183. public static void CreateFolder(string path)
  184. {
  185. Internal_CreateFolder(path);
  186. }
  187. /// <summary>
  188. /// Renames an entry in the project library.
  189. /// </summary>
  190. /// <param name="path">Path of the entry to rename, absolute or relative to resources folder.</param>
  191. /// <param name="name">New name of the entry with an extension.</param>
  192. /// <param name="overwrite">Determines should the entry be deleted if one with the provided name already exists. If
  193. /// this is false and an entry already exists, no rename operation will be performed.</param>
  194. public static void Rename(string path, string name, bool overwrite = false)
  195. {
  196. Internal_Rename(path, name, false);
  197. }
  198. /// <summary>
  199. /// Moves an entry in the project library from one path to another.
  200. /// </summary>
  201. /// <param name="oldPath">Source path of the entry, absolute or relative to resources folder.</param>
  202. /// <param name="newPath">Destination path of the entry, absolute or relative to resources folder.</param>
  203. /// <param name="overwrite">Determines should the entry be deleted if one at the destination path already exists. If
  204. /// this is false and an entry already exists, no move operation will be performed.</param>
  205. public static void Move(string oldPath, string newPath, bool overwrite = false)
  206. {
  207. Internal_Move(oldPath, newPath, overwrite);
  208. }
  209. /// <summary>
  210. /// Copies an entry in the project library from one path to another.
  211. /// </summary>
  212. /// <param name="source">Source path of the entry, absolute or relative to resources folder.</param>
  213. /// <param name="destination">Destination path of the entry, absolute or relative to resources folder.</param>
  214. /// <param name="overwrite">Determines should the entry be deleted if one at the destination path already exists. If
  215. /// this is false and an entry already exists, no copy operation will be performed.</param>
  216. public static void Copy(string source, string destination, bool overwrite = false)
  217. {
  218. Internal_Copy(source, destination, overwrite);
  219. }
  220. /// <summary>
  221. /// Controls should a resource be included an a build. All dependant resources will also be included.
  222. /// </summary>
  223. /// <param name="path">Path of the resource to include, absolute or relative to resources folder.</param>
  224. /// <param name="include">True if it should be included, false otherwise.</param>
  225. public static void SetIncludeInBuild(string path, bool include)
  226. {
  227. Internal_SetIncludeInBuild(path, include);
  228. }
  229. /// <summary>
  230. /// Triggers reimport for queued resource. Should be called once per frame.
  231. /// </summary>
  232. internal static void Update()
  233. {
  234. if (queuedForImport.Count > 0)
  235. {
  236. // Skip first frame to get the progress bar a chance to show up
  237. if (importInProgress)
  238. {
  239. UInt64 start = Time.Precise;
  240. List<string> toRemove = new List<string>();
  241. foreach (var entry in queuedForImport)
  242. {
  243. Internal_Refresh(entry, true);
  244. toRemove.Add(entry);
  245. numImportedFiles++;
  246. UInt64 end = Time.Precise;
  247. UInt64 elapsed = end - start;
  248. float elapsedSeconds = elapsed * Time.MicroToSecond;
  249. if (elapsedSeconds > TIME_SLICE_SECONDS)
  250. break;
  251. }
  252. foreach (var entry in toRemove)
  253. queuedForImport.Remove(entry);
  254. }
  255. if (queuedForImport.Count == 0)
  256. {
  257. numImportedFiles = 0;
  258. totalFilesToImport = 0;
  259. ProgressBar.Hide();
  260. }
  261. else
  262. {
  263. IEnumerator<string> enumerator = queuedForImport.GetEnumerator();
  264. enumerator.MoveNext();
  265. string displayName = enumerator.Current;
  266. displayName = displayName.Replace("\\", "\\\\");
  267. if (displayName.Length > 60)
  268. {
  269. displayName = displayName.Remove(0, displayName.Length - 60);
  270. displayName = "..." + displayName;
  271. }
  272. float pct = numImportedFiles / (float)totalFilesToImport;
  273. ProgressBar.Show("Importing (" + numImportedFiles + "/" + totalFilesToImport + ")", displayName, 0.5f);
  274. }
  275. importInProgress = true;
  276. }
  277. else
  278. importInProgress = false;
  279. }
  280. /// <summary>
  281. /// Triggered internally by the runtime when a new entry is added to the project library.
  282. /// </summary>
  283. /// <param name="path">Path relative to the project library resources folder.</param>
  284. private static void Internal_DoOnEntryAdded(string path)
  285. {
  286. if (OnEntryAdded != null)
  287. OnEntryAdded(path);
  288. }
  289. /// <summary>
  290. /// Triggered internally by the runtime when an entry is removed from the project library.
  291. /// </summary>
  292. /// <param name="path">Path relative to the project library resources folder.</param>
  293. private static void Internal_DoOnEntryRemoved(string path)
  294. {
  295. if (OnEntryRemoved != null)
  296. OnEntryRemoved(path);
  297. }
  298. /// <summary>
  299. /// Triggered internally by the runtime when an entry is (re)imported in the project library.
  300. /// </summary>
  301. /// <param name="path">Path relative to the project library resources folder.</param>
  302. private static void Internal_DoOnEntryImported(string path)
  303. {
  304. if (OnEntryImported != null)
  305. OnEntryImported(path);
  306. }
  307. [MethodImpl(MethodImplOptions.InternalCall)]
  308. private static extern string[] Internal_Refresh(string path, bool import);
  309. [MethodImpl(MethodImplOptions.InternalCall)]
  310. private static extern void Internal_Create(Resource resource, string path);
  311. [MethodImpl(MethodImplOptions.InternalCall)]
  312. private static extern Resource Internal_Load(string path);
  313. [MethodImpl(MethodImplOptions.InternalCall)]
  314. private static extern void Internal_Save(Resource resource);
  315. [MethodImpl(MethodImplOptions.InternalCall)]
  316. private static extern DirectoryEntry Internal_GetRoot();
  317. [MethodImpl(MethodImplOptions.InternalCall)]
  318. private static extern void Internal_Reimport(string path, ImportOptions options, bool force);
  319. [MethodImpl(MethodImplOptions.InternalCall)]
  320. private static extern LibraryEntry Internal_GetEntry(string path);
  321. [MethodImpl(MethodImplOptions.InternalCall)]
  322. private static extern LibraryEntry[] Internal_Search(string path, ResourceType[] types);
  323. [MethodImpl(MethodImplOptions.InternalCall)]
  324. private static extern string Internal_GetPath(Resource resource);
  325. [MethodImpl(MethodImplOptions.InternalCall)]
  326. private static extern string Internal_GetPathFromUUID(string uuid);
  327. [MethodImpl(MethodImplOptions.InternalCall)]
  328. private static extern void Internal_Delete(string path);
  329. [MethodImpl(MethodImplOptions.InternalCall)]
  330. private static extern void Internal_CreateFolder(string path);
  331. [MethodImpl(MethodImplOptions.InternalCall)]
  332. private static extern void Internal_Rename(string path, string name, bool overwrite);
  333. [MethodImpl(MethodImplOptions.InternalCall)]
  334. private static extern void Internal_Move(string oldPath, string newPath, bool overwrite);
  335. [MethodImpl(MethodImplOptions.InternalCall)]
  336. private static extern void Internal_Copy(string source, string destination, bool overwrite);
  337. [MethodImpl(MethodImplOptions.InternalCall)]
  338. private static extern string Internal_GetResourceFolder();
  339. [MethodImpl(MethodImplOptions.InternalCall)]
  340. private static extern void Internal_SetIncludeInBuild(string path, bool force);
  341. }
  342. /// <summary>
  343. /// Type of project library entries.
  344. /// </summary>
  345. public enum LibraryEntryType // Note: Must match the C++ enum ProjectLibrary::LibraryEntryType
  346. {
  347. File, Directory
  348. }
  349. /// <summary>
  350. /// Type of resources supported by the project library.
  351. /// </summary>
  352. public enum ResourceType // Note: Must match the C++ enum ScriptResourceType
  353. {
  354. Texture, SpriteTexture, Mesh, Font, Shader, ShaderInclude, Material, Prefab, PlainText,
  355. ScriptCode, StringTable, GUISkin, Undefined
  356. }
  357. /// <summary>
  358. /// A generic project library entry that may be a file or a folder.
  359. /// </summary>
  360. public class LibraryEntry : ScriptObject
  361. {
  362. /// <summary>
  363. /// Path of the library entry, relative to the project library resources folder.
  364. /// </summary>
  365. public string Path { get { return Internal_GetPath(mCachedPtr); } }
  366. /// <summary>
  367. /// Name of the library entry.
  368. /// </summary>
  369. public string Name { get { return Internal_GetName(mCachedPtr); } }
  370. /// <summary>
  371. /// Type of the library entry.
  372. /// </summary>
  373. public LibraryEntryType Type { get { return Internal_GetType(mCachedPtr); } }
  374. /// <summary>
  375. /// Directory entry that contains this entry. This may be null for the root entry.
  376. /// </summary>
  377. public DirectoryEntry Parent { get { return Internal_GetParent(mCachedPtr); } }
  378. [MethodImpl(MethodImplOptions.InternalCall)]
  379. private static extern string Internal_GetPath(IntPtr thisPtr);
  380. [MethodImpl(MethodImplOptions.InternalCall)]
  381. private static extern string Internal_GetName(IntPtr thisPtr);
  382. [MethodImpl(MethodImplOptions.InternalCall)]
  383. private static extern LibraryEntryType Internal_GetType(IntPtr thisPtr);
  384. [MethodImpl(MethodImplOptions.InternalCall)]
  385. private static extern DirectoryEntry Internal_GetParent(IntPtr thisPtr);
  386. }
  387. /// <summary>
  388. /// A project library entry representing a directory that contains other entries.
  389. /// </summary>
  390. public class DirectoryEntry : LibraryEntry
  391. {
  392. /// <summary>
  393. /// A set of entries contained in this entry.
  394. /// </summary>
  395. public LibraryEntry[] Children { get { return Internal_GetChildren(mCachedPtr); } }
  396. [MethodImpl(MethodImplOptions.InternalCall)]
  397. private static extern LibraryEntry[] Internal_GetChildren(IntPtr thisPtr);
  398. }
  399. /// <summary>
  400. /// A library entry representing a resource.
  401. /// </summary>
  402. public class FileEntry : LibraryEntry
  403. {
  404. /// <summary>
  405. /// Import options used for importing the resource.
  406. /// </summary>
  407. public ImportOptions Options { get { return Internal_GetImportOptions(mCachedPtr); } }
  408. /// <summary>
  409. /// Unique identifier of the resource.
  410. /// </summary>
  411. public string UUID { get { return Internal_GetUUID(mCachedPtr); } }
  412. /// <summary>
  413. /// Custom icon for the resource to display in the editor, if the resource has one.
  414. /// </summary>
  415. public Texture2D Icon { get { return Internal_GetIcon(mCachedPtr); } }
  416. /// <summary>
  417. /// Type of the resource referenced by this entry.
  418. /// </summary>
  419. public ResourceType ResType { get { return Internal_GetResourceType(mCachedPtr); } }
  420. /// <summary>
  421. /// Determines will the resource be included in the project build.
  422. /// </summary>
  423. public bool IncludeInBuild { get { return Internal_GetIncludeInBuild(mCachedPtr); } }
  424. [MethodImpl(MethodImplOptions.InternalCall)]
  425. private static extern ImportOptions Internal_GetImportOptions(IntPtr thisPtr);
  426. [MethodImpl(MethodImplOptions.InternalCall)]
  427. private static extern string Internal_GetUUID(IntPtr thisPtr);
  428. [MethodImpl(MethodImplOptions.InternalCall)]
  429. private static extern Texture2D Internal_GetIcon(IntPtr thisPtr);
  430. [MethodImpl(MethodImplOptions.InternalCall)]
  431. private static extern ResourceType Internal_GetResourceType(IntPtr thisPtr);
  432. [MethodImpl(MethodImplOptions.InternalCall)]
  433. private static extern bool Internal_GetIncludeInBuild(IntPtr thisPtr);
  434. }
  435. }