ProjectLibrary.cs 25 KB

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