CodeSmile AssetDatabase 1.9
Unity's AssetDatabase in enjoyable, consistent, concise, convenient, comprehensible, safe, documented form.
Loading...
Searching...
No Matches
Asset.File.cs
1// Copyright (C) 2021-2024 Steffen Itterheim
2// Refer to included LICENSE file for terms and conditions.
3
4using System;
5using System.Collections.Generic;
6using System.Diagnostics.CodeAnalysis;
7using System.Linq;
8using System.Text;
9using UnityEditor;
10using Object = UnityEngine.Object;
11
12namespace CodeSmileEditor
13{
14 // This file contains asset 'file operations' related method groups, in that order:
15 // Create
16 // Save
17 // Import
18 // Load
19 // Find
20 // Copy
21 // Move
22 // Rename
23 // Open
24 // Delete
25 // Trash
26
27 public sealed partial class Asset
28 {
32 public static class File
33 {
34 private static List<String> s_PathsNotDeleted = new();
35
45 [ExcludeFromCodeCoverage] // trivial
46 public static IList<String> PathsNotDeleted => s_PathsNotDeleted;
47
77 public static void BatchEditing([NotNull] Action massAssetFileEditAction)
78 {
79 try
80 {
81 StartAssetEditing();
82
83 massAssetFileEditAction?.Invoke();
84 }
85 finally
86 {
87 StopAssetEditing();
88 }
89 }
90
103 public static Object Create([NotNull] Byte[] contents, [NotNull] Path path) => CreateInternal(contents, path);
104
118 public static Object CreateAsNew([NotNull] Byte[] contents, [NotNull] Path path) => CreateInternal(contents, path.UniqueFilePath);
119
132 public static Object Create([NotNull] String contents, [NotNull] Path path) => CreateInternal(contents, path);
133
147 public static Object CreateAsNew([NotNull] String contents, [NotNull] Path path) => CreateInternal(contents, path.UniqueFilePath);
148
163 public static Object Create([NotNull] Object instance, [NotNull] Path path) => CreateInternal(instance, path);
164
179 public static Object CreateAsNew([NotNull] Object instance, [NotNull] Path path) => CreateInternal(instance, path.UniqueFilePath);
180
199 public static T CreateOrLoad<T>([NotNull] Path path, [NotNull] Func<T> getInstance) where T : Object =>
200 LoadOrCreate(path, getInstance);
201
214 public static void Save([NotNull] Object asset) => SaveInternal(asset);
215
234 public static void ForceSave([NotNull] Object asset) => SaveInternal(asset, true);
235
245 public static void Save(GUID guid)
246 {
247 ThrowIf.NotAnAssetGuid(guid);
248
249 AssetDatabase.SaveAssetIfDirty(guid);
250 }
251
271 public static void Import([NotNull] Path path, ImportAssetOptions options = ImportAssetOptions.Default)
272 {
273 ThrowIf.ArgumentIsNull(path, nameof(path));
274 ThrowIf.DoesNotExistInFileSystem(path);
275
276 AssetDatabase.ImportAsset(path, options);
277 }
278
303 public static T ImportAndLoad<T>([NotNull] Path path,
304 ImportAssetOptions options = ImportAssetOptions.Default)
305 where T : Object => Load<T>(path);
306
320 public static void
321 Import([NotNull] IEnumerable<Path> paths, ImportAssetOptions options = ImportAssetOptions.Default) =>
322 Import(Path.ToStrings(paths.ToArray()), options);
323
337 public static void
338 Import([NotNull] IEnumerable<string> paths, ImportAssetOptions options = ImportAssetOptions.Default) => BatchEditing(
339 () =>
340 {
341 foreach (var path in paths)
342 AssetDatabase.ImportAsset(path, options);
343 });
344
366 public static T Load<T>([NotNull] Path path) where T : Object
367 {
368 ThrowIf.ArgumentIsNull(path, nameof(path));
369
370 ImportIfNotImported(path);
371 return AssetDatabase.LoadAssetAtPath<T>(path);
372 }
373
388 public static T LoadOrCreate<T>([NotNull] Path path, [NotNull] Func<T> getInstance) where T : Object
389 {
390 if (path.ExistsInFileSystem == false)
391 return Create(getInstance.Invoke(), path) as T;
392
393 return ImportAndLoad<T>(path);
394 }
395
411 public static T LoadMain<T>([NotNull] Path path) where T : Object
412 {
413 ThrowIf.ArgumentIsNull(path, nameof(path));
414 ThrowIf.DoesNotExistInFileSystem(path);
415
416 ImportIfNotImported(path);
417 return AssetDatabase.LoadMainAssetAtPath(path) as T;
418 }
419
435 public static T LoadMain<T>(GUID guid) where T : Object
436 {
437 ThrowIf.NotAnAssetGuid(guid);
438
439 var path = Path.Get(guid);
440 ImportIfNotImported(path);
441 return LoadMain<T>(path);
442 }
443
459 [ExcludeFromCodeCoverage] // simple relay
460 public static AssetDatabaseLoadOperation LoadAsync([NotNull] Path path, Int64 localFileId)
461 {
462#if UNITY_2022_2_OR_NEWER
463 return AssetDatabase.LoadObjectAsync(path, localFileId);
464#else
465 throw new NotSupportedException("AssetDatabase.LoadObjectAsync not available in this editor version");
466#endif
467 }
468
488 [ExcludeFromCodeCoverage] // simple relay
489 public static String[] Find([NotNull] String filter, String[] searchInFolders = null) => searchInFolders == null
490 ? AssetDatabase.FindAssets(filter)
491 : AssetDatabase.FindAssets(filter, searchInFolders);
492
513 [ExcludeFromCodeCoverage] // simple relay
514 public static GUID[] FindGuids([NotNull] String filter, String[] searchInFolders = null) =>
515 Find(filter, searchInFolders).Select(guid => new GUID(guid)).ToArray();
516
536 [ExcludeFromCodeCoverage] // simple relay
537 public static Path[] FindPaths([NotNull] String filter, String[] searchInFolders = null) =>
538 Find(filter, searchInFolders).Select(guid => Path.Get(new GUID(guid))).ToArray();
539
559 [ExcludeFromCodeCoverage] // simple relay
560 public static Path[] FindPaths([NotNull] String filter, Path[] searchInFolders = null) =>
561 FindPaths(filter, Path.ToStrings(searchInFolders));
562
580 public static Boolean Copy([NotNull] Path sourcePath, [NotNull] Path destinationPath) =>
581 CopyInternal(sourcePath, destinationPath, true);
582
601 public static Boolean CopyAsNew([NotNull] Path sourcePath, [NotNull] Path destinationPath) =>
602 CopyInternal(sourcePath, destinationPath.UniqueFilePath, false);
603
623 public static Boolean CanMove([NotNull] Path sourcePath, [NotNull] Path destinationPath)
624 {
625 if (sourcePath == null || destinationPath == null)
626 return false;
627
628 return Succeeded(AssetDatabase.ValidateMoveAsset(sourcePath, destinationPath));
629 }
630
649 public static Boolean Move([NotNull] Path sourcePath, [NotNull] Path destinationPath)
650 {
651 if (sourcePath == null || destinationPath == null)
652 return false;
653
654 destinationPath.CreateFolders();
655 return Succeeded(AssetDatabase.MoveAsset(sourcePath, destinationPath));
656 }
657
675 public static Boolean Rename([NotNull] Path path, String newFileName) => String.IsNullOrEmpty(newFileName) == false &&
676 Succeeded(AssetDatabase.RenameAsset(path, newFileName));
677
689 [ExcludeFromCodeCoverage] // simple relay
690 public static Boolean CanOpenInEditor([NotNull] Object instance) => CanOpenInEditor(instance.GetInstanceID());
691
703 [ExcludeFromCodeCoverage] // simple relay
704 public static Boolean CanOpenInEditor(Int32 instanceId) => AssetDatabase.CanOpenAssetInEditor(instanceId);
705
719 [ExcludeFromCodeCoverage] // cannot be tested
720 public static void OpenExternal([NotNull] Object asset, Int32 lineNumber = -1, Int32 columnNumber = -1) =>
721 AssetDatabase.OpenAsset(asset, lineNumber, columnNumber);
722
736 [ExcludeFromCodeCoverage] // cannot be tested
737 public static void OpenExternal(Int32 instanceId, Int32 lineNumber = -1, Int32 columnNumber = -1) =>
738 AssetDatabase.OpenAsset(instanceId, lineNumber, columnNumber);
739
753 [ExcludeFromCodeCoverage] // cannot be tested
754 public static void OpenExternal([NotNull] Path path, Int32 lineNumber = -1, Int32 columnNumber = -1) =>
755 OpenExternal(Load<Object>(path), lineNumber, columnNumber);
756
768 public static Boolean Delete([NotNull] Path path) =>
769 // path.Exists prevents Unity from spitting out an unnecessary warning message
770 path != null && path.Exists && AssetDatabase.DeleteAsset(path);
771
783 public static Boolean Delete([NotNull] Object asset) => Delete(Path.Get(asset));
784
798 public static Boolean Delete([NotNull] IEnumerable<Path> paths) => Delete(Path.ToStrings(paths));
799
813 public static Boolean Delete([NotNull] IEnumerable<String> paths) =>
814 AssetDatabase.DeleteAssets(paths.ToArray(), s_PathsNotDeleted = new List<String>());
815
831 public static Boolean Trash([NotNull] Path path) => path != null && AssetDatabase.MoveAssetToTrash(path);
832
848 public static Boolean Trash([NotNull] Object asset) => Trash(Path.Get(asset));
849
864 public static Boolean Trash([NotNull] IEnumerable<Path> paths) => Trash(Path.ToStrings(paths));
865
880 public static Boolean Trash([NotNull] IEnumerable<String> paths) =>
881 AssetDatabase.MoveAssetsToTrash(paths.ToArray(), s_PathsNotDeleted = new List<String>());
882
892 public static Type GetMainType([NotNull] Path path) => AssetDatabase.GetMainAssetTypeAtPath(path);
893
908 [ExcludeFromCodeCoverage] // simple relay
909 public static Type GetMainType(GUID guid)
910 {
911#if UNITY_2023_2_OR_NEWER // It's also available in 2022.2 but not in the early patch versions (eg 7f1 onwards)
912 return AssetDatabase.GetMainAssetTypeFromGUID(guid);
913#else
914 return GetMainType(Path.Get(guid));
915#endif
916 }
917
928 [ExcludeFromCodeCoverage] // simple relay
929 public static Type GetSubType([NotNull] Path path, Int64 fileId) => AssetDatabase.GetTypeFromPathAndFileID(path, fileId);
930
945
946 // ValueTuple makes doxygen accept it as documented, see: https://github.com/doxygen/doxygen/issues/9618
947 public static ValueTuple<GUID, Int64> GetGuidAndFileId([NotNull] Object asset)
948 {
949 if (asset == null)
950 return (new GUID(), 0L);
951
952 // explicit variable + assign because Unity 2021 has both long and int variants of the TryGetGUID* method
953 var localId = Int64.MaxValue;
954 return AssetDatabase.TryGetGUIDAndLocalFileIdentifier(asset, out var guid, out localId)
955 ? (new GUID(guid), localId)
956 : (new GUID(), 0L);
957 }
958
970 public static GUID GetGuid([NotNull] Object asset)
971 {
972 if (asset == null)
973 return new GUID();
974
975 // explicit variable + assign because Unity 2021 has both long and int variants of the TryGetGUID* method
976 var localId = Int64.MaxValue;
977 return AssetDatabase.TryGetGUIDAndLocalFileIdentifier(asset, out var guid, out localId)
978 ? new GUID(guid)
979 : new GUID();
980 }
981
993 public static Int64 GetFileId([NotNull] Object asset)
994 {
995 if (asset == null)
996 return 0L;
997
998 // explicit variable + assign because Unity 2021 has both long and int variants of the TryGetGUID* method
999 var localId = Int64.MaxValue;
1000 return AssetDatabase.TryGetGUIDAndLocalFileIdentifier(asset, out var _, out localId) ? localId : 0L;
1001 }
1002
1003 // Internal on purpose: use Asset.File.BatchEditing(Action) instead
1004 [ExcludeFromCodeCoverage] // untestable
1005 internal static void StartAssetEditing() => AssetDatabase.StartAssetEditing();
1006
1007 // Internal on purpose: use Asset.File.BatchEditing(Action) instead
1008 [ExcludeFromCodeCoverage] // untestable
1009 internal static void StopAssetEditing() => AssetDatabase.StopAssetEditing();
1010
1011 internal static Object CreateInternal([NotNull] Byte[] bytes, [NotNull] Path path)
1012 {
1013 ThrowIf.ArgumentIsNull(bytes, nameof(bytes));
1014 ThrowIf.ArgumentIsNull(path, nameof(path));
1015
1016 path.CreateFolders();
1017 System.IO.File.WriteAllBytes(path, bytes);
1018 return ImportAndLoad<Object>(path);
1019 }
1020
1021 internal static Object CreateInternal([NotNull] String contents, [NotNull] Path path)
1022 {
1023 ThrowIf.ArgumentIsNull(contents, nameof(contents));
1024 ThrowIf.ArgumentIsNull(path, nameof(path));
1025
1026 path.CreateFolders();
1027 System.IO.File.WriteAllText(path, contents, Encoding.UTF8); // string assets ought to be UTF8
1028 return ImportAndLoad<Object>(path);
1029 }
1030
1031 internal static Object CreateInternal([NotNull] Object instance, [NotNull] Path path)
1032 {
1033 ThrowIf.ArgumentIsNull(instance, nameof(instance));
1034 ThrowIf.ArgumentIsNull(path, nameof(path));
1035
1036 path.CreateFolders();
1037 AssetDatabase.CreateAsset(instance, path);
1038 return instance;
1039 }
1040
1041 internal static Boolean CopyInternal([NotNull] Path sourcePath, [NotNull] Path destinationPath,
1042 Boolean overwriteExisting)
1043 {
1044 ThrowIf.ArgumentIsNull(sourcePath, nameof(sourcePath));
1045 ThrowIf.ArgumentIsNull(destinationPath, nameof(destinationPath));
1046 ThrowIf.AssetPathNotInDatabase(sourcePath);
1047 ThrowIf.SourceAndDestPathAreEqual(sourcePath, destinationPath);
1048
1049 destinationPath.CreateFolders();
1050
1051#if UNITY_2022_1_OR_NEWER
1052 var success = AssetDatabase.CopyAsset(sourcePath, destinationPath);
1053 SetLastErrorMessage(success ? String.Empty : $"failed to copy {sourcePath} to {destinationPath}");
1054 return success;
1055#else
1056 // in Unity 2021 we have to load, clone and create instead
1057 // because object and file name have to match (likely a bug in that version)
1058 var original = LoadMain<Object>(sourcePath);
1059 var copy = Object.Instantiate(original);
1060 copy = Create(copy, destinationPath);
1061 return copy != null;
1062#endif
1063 }
1064
1065 private static void SaveInternal([NotNull] Object asset, Boolean forceSave = false)
1066 {
1067 ThrowIf.ArgumentIsNull(asset, nameof(asset));
1068 ThrowIf.NotInDatabase(asset);
1069
1070 if (forceSave)
1071 EditorUtility.SetDirty(asset);
1072
1073 AssetDatabase.SaveAssetIfDirty(asset);
1074 }
1075
1076 private static void ImportIfNotImported([NotNull] Path path,
1077 ImportAssetOptions options = ImportAssetOptions.Default)
1078 {
1079 // Not in database but on disk? => Import path
1080 // Cannot determine if existing file has been updated though.
1081 if (path.Exists == false && path.ExistsInFileSystem)
1082 Import(path, options);
1083 }
1084
1085#if !UNITY_2022_2_OR_NEWER // dummy for LoadAsync in earlier versions
1086 public class AssetDatabaseLoadOperation {}
1087#endif
1088 }
1089 }
1090}
static void OpenExternal(Int32 instanceId, Int32 lineNumber=-1, Int32 columnNumber=-1)
Opens the asset in the application associated with the file's extension.
static IList< String > PathsNotDeleted
The paths that failed to be deleted or trashed. Is an empty list if no failure occured on the last ca...
Definition Asset.File.cs:46
static void Save([NotNull] Object asset)
Saves the object to disk if it is dirty.
static ValueTuple< GUID, Int64 > GetGuidAndFileId([NotNull] Object asset)
static void Save(GUID guid)
Saves any changes to the asset to disk, by GUID.
static Boolean Delete([NotNull] IEnumerable< Path > paths)
Tries to delete multiple files/folders.
static void OpenExternal([NotNull] Path path, Int32 lineNumber=-1, Int32 columnNumber=-1)
Opens the asset in the application associated with the file's extension.
static AssetDatabaseLoadOperation LoadAsync([NotNull] Path path, Int64 localFileId)
Loads an object and its dependencies asynchronously.
static Int64 GetFileId([NotNull] Object asset)
Returns the local FileID of the object.
static Boolean CanMove([NotNull] Path sourcePath, [NotNull] Path destinationPath)
Tests if an asset can be moved to destination without moving the asset.
static Type GetMainType([NotNull] Path path)
static Boolean Rename([NotNull] Path path, String newFileName)
Renames an asset's file or folder name.
static Boolean Delete([NotNull] IEnumerable< String > paths)
Tries to delete multiple files/folders.
static Boolean CanOpenInEditor([NotNull] Object instance)
Returns true if the given object can be opened (edited) by the Unity editor.
static Path[] FindPaths([NotNull] String filter, Path[] searchInFolders=null)
Finds asset paths by the given filter criteria.
static T ImportAndLoad< T >([NotNull] Path path, ImportAssetOptions options=ImportAssetOptions.Default)
Imports a file at a given path that was created or modified 'externally', then loads and returns the ...
static Object Create([NotNull] String contents, [NotNull] Path path)
Writes the string to disk, then imports and loads the asset. Overwrites any existing file.
static Boolean Delete([NotNull] Path path)
Deletes an asset file or folder.
static Boolean Trash([NotNull] IEnumerable< String > paths)
Tries to move multiple files/folders to the OS trash.
static T CreateOrLoad< T >([NotNull] Path path, [NotNull] Func< T > getInstance)
Loads or creates an asset at path.
static Boolean Trash([NotNull] IEnumerable< Path > paths)
Tries to move multiple files/folders to the OS trash.
static Object Create([NotNull] Byte[] contents, [NotNull] Path path)
Writes the byte array to disk, then imports and loads the asset. Overwrites any existing file.
static Boolean Copy([NotNull] Path sourcePath, [NotNull] Path destinationPath)
Copies an asset from source to destination path. Overwrites any existing assets.
static GUID[] FindGuids([NotNull] String filter, String[] searchInFolders=null)
Finds asset GUIDs by the given filter criteria.
static Object CreateAsNew([NotNull] String contents, [NotNull] Path path)
Writes the string to disk, then imports and loads the asset. Generates a unique file name if an asset...
static Boolean CopyAsNew([NotNull] Path sourcePath, [NotNull] Path destinationPath)
Copies an asset from source to destination path. Generates a unique file name if an asset already exi...
static Boolean Trash([NotNull] Path path)
Moves an asset file or folder to the OS trash.
static Object CreateAsNew([NotNull] Object instance, [NotNull] Path path)
Writes the object to disk. Generates a unique file name if an asset exists at the path.
static Type GetMainType(GUID guid)
Returns the type of the main asset for the GUID.
static GUID GetGuid([NotNull] Object asset)
Returns the GUID of an object. Returns an empty GUID if the object is null or not an asset.
static T LoadOrCreate< T >([NotNull] Path path, [NotNull] Func< T > getInstance)
Loads an asset at path or creates the asset if needed.
static String[] Find([NotNull] String filter, String[] searchInFolders=null)
Finds asset GUIDs by the given filter criteria.
static Boolean Move([NotNull] Path sourcePath, [NotNull] Path destinationPath)
Moves an asset file to destination path.
static Boolean CanOpenInEditor(Int32 instanceId)
Returns true if the given object can be opened (edited) by the Unity editor.
static void OpenExternal([NotNull] Object asset, Int32 lineNumber=-1, Int32 columnNumber=-1)
Opens the asset in the application associated with the file's extension.
static Boolean Trash([NotNull] Object asset)
Moves an asset file or folder to the OS trash.
static void BatchEditing([NotNull] Action massAssetFileEditAction)
Batch multiple asset file operations to improve execution speed.
Definition Asset.File.cs:77
static Type GetSubType([NotNull] Path path, Int64 fileId)
Gets the type of a sub asset by the main asset's path and the local file ID of the sub-asset.
static Boolean Delete([NotNull] Object asset)
Deletes an asset file or folder.
static Object CreateAsNew([NotNull] Byte[] contents, [NotNull] Path path)
Writes the byte array to disk, then imports and loads the asset. Generates a unique file name if an a...
static Object Create([NotNull] Object instance, [NotNull] Path path)
Writes the object to disk. Overwrites any existing file.
static void Import([NotNull] Path path, ImportAssetOptions options=ImportAssetOptions.Default)
Imports a file at a given path that was created or modified 'externally'. Externally refers to any me...
static Path[] FindPaths([NotNull] String filter, String[] searchInFolders=null)
Finds asset paths by the given filter criteria.
static void ForceSave([NotNull] Object asset)
Forces the object to be saved to disk. Marks the object as dirty and then calls CodeSmileEditor....
Groups file related operations.
Definition Asset.File.cs:33
static String[] ToStrings([NotNull] IEnumerable< Path > paths)
Converts an IEnumerable collection of Path instances to a string array.
static Path Get([NotNull] Object asset)
Gets the relative path of an asset.
Represents a relative path to an asset file or folder, typically under 'Assets' or 'Packages'.
Definition Asset.Path.cs:25
T Load< T >()
Loads a (sub) object from the asset identified by type.