Able
Askowl Base Library Enabler
AssetDb.cs
1 // Copyright 2019 (C) paul@marrington.net http://www.askowl.net/unity-packages
2 
3 using System;
4 using System.IO;
5 using UnityEditor;
6 using UnityEngine;
7 using Object = UnityEngine.Object;
8 
9 namespace Askowl {
10  public class AssetDb : IDisposable {
11  #if UNITY_EDITOR
12  public static AssetDb Instance => Cache<AssetDb>.Instance;
13  public bool Error;
14 
15  #region Find
16  public AssetDb Find(string path, out Object asset) {
17  path = AbsoluteFolder(path);
18  asset = AssetDatabase.LoadAssetAtPath(path, typeof(Object));
19  Error = asset == null;
20  if (!Error) CurrentFolder = path;
21  return this;
22  }
23 
24  public static string[] FindByFilter(string filter) {
25  string[] list = AssetDatabase.FindAssets(filter);
26 
27  for (int i = 0; i < list.Length; i++) list[i] = (AssetDatabase.GUIDToAssetPath(list[i]));
28  return list;
29  }
30 
31  public static string[] FindByType<T>() where T : Object => FindByFilter($"t:{typeof(T)}");
32  public static string[] FindByLabel(string label) => FindByFilter($"l:{label}");
33  public static string[] FindByName(string name) => FindByFilter($"name");
34  #endregion
35 
36  public void Dispose() {
37  CurrentFolder = "";
38  Error = false;
39  Cache<AssetDb>.Dispose(this);
40  }
41 
42  #region Selection
43  public string CurrentFolder = "";
44 
45  public static string ProjectFolder() {
46  EditorUtility.FocusProjectWindow();
47  foreach (Object asset in Selection.GetFiltered(typeof(Object), SelectionMode.Assets)) {
48  var path = SetFolderFor(asset);
49  if (path != null) return path;
50  }
51  return "Assets";
52  }
53 
54  public AssetDb ProjectFolder(out string path) {
55  path = ProjectFolder();
56  return this;
57  }
58  private static string SetFolderFor(Object asset) {
59  var path = AssetDatabase.GetAssetPath(asset);
60  if (!string.IsNullOrEmpty(path))
61  if (Directory.Exists(path)) {
62  return path;
63  } else if (File.Exists(path)) {
64  return Path.GetDirectoryName(path);
65  }
66  return null;
67  }
68  public AssetDb Select(Object asset) {
69  if (Error) return this;
70  EditorUtility.FocusProjectWindow();
71  CurrentFolder = SetFolderFor(Selection.activeObject = asset);
72  EditorGUIUtility.PingObject(asset);
73  return this;
74  }
75  public AssetDb Selected(out Object asset) {
76  asset = Selection.activeObject;
77  return this;
78  }
79  public AssetDb Select(string path = null) => Find(path ?? CurrentFolder, out var asset).Select(asset);
80  #endregion
81 
82  #region Folders
83  public AssetDb CreateFolders(string path) {
84  if (Error) return this;
85  if (!path.StartsWith("./")) CurrentFolder = "";
86 
87  var folders = path.Split('/');
88  for (int i = 0; i < folders.Length; i++) {
89  if ((folders[i].Length != 0) && (folders[i] != ".")) {
90  Find($"./{folders[i]}", out Object _);
91  if (Error) {
92  Error = AssetDatabase.CreateFolder(CurrentFolder, folders[i]) == null;
93  if (Error) return this;
94  CurrentFolder = CurrentFolder.Length == 0 ? folders[i] : $"{CurrentFolder}/{folders[i]}";
95  }
96  }
97  }
98  return this;
99  }
100  public AssetDb Delete(string path) {
101  if (Error) return this;
102  Error = AssetDatabase.MoveAssetToTrash(AbsoluteFolder(path));
103  return this;
104  }
105  public AssetDb SubFolders(out string[] subFolders) {
106  subFolders = AssetDatabase.GetSubFolders(CurrentFolder);
107  return this;
108  }
109 
110  private string AbsoluteFolder(string path) {
111  if (path.StartsWith("./")) {
112  path = path.Substring(2);
113  return (CurrentFolder == "") ? path : $"{CurrentFolder}/{path}";
114  }
115  return (path == "Assets") || path.StartsWith("Assets/") ? path : $"Assets/{path}";
116  }
117  #endregion
118 
119  #region Labels
120  public static void Labels(Object asset, params string[] labels) => AssetDatabase.SetLabels(asset, labels);
121  public static string[] Labels(Object asset) => AssetDatabase.GetLabels(asset);
122  #endregion
123 
124  #region Asset Creation and Loading (Editor only)
125  public static Object Load(string path, Type type) {
126  path = Objects.FindFile(path);
127  return (path == null) ? null : AssetDatabase.LoadAssetAtPath(path, type);
128  }
129 
130  public static T Load<T>(string path) where T : Object => (T) Load(path, typeof(T));
131 
132  public AssetDb Load(string path, out Object asset, Type type) {
133  asset = Load(path, type);
134  Error = asset == null;
135  return this;
136  }
137 
138  public AssetDb Load<T>(string path, out T asset) where T : Object {
139  asset = Load<T>(path);
140  return this;
141  }
142 
143  /// Warning: Changes path in project window. Get old path first with
144  /// var activeObject = Selection.activeObject;
145  /// var selectedPathInProjectView = AssetDatabase.GetAssetPath(Selection.activeObject);
146  /// afterwards you can return with
147  /// EditorGUIUtility.PingObject(activeObject);
148  /// but it is not perfect. Left project pane returns correctly, but right pane still points elsewhere
149  public static Object LoadOrCreate(string path, Type type) {
150  var asset = Load(path, type);
151  if (asset != null) return asset;
152  AssetDatabase.CreateAsset(asset = ScriptableObject.CreateInstance(type), $"Assets/{path}");
153  AssetDatabase.SaveAssets();
154  AssetDatabase.Refresh();
155  return asset;
156  }
157 
158  public AssetDb LoadOrCreate(string path, out Object asset, Type type) {
159  asset = LoadOrCreate(path, type);
160  return this;
161  }
162 
163  public static T LoadOrCreate<T>(string path) where T : ScriptableObject => (T) LoadOrCreate(path, typeof(T));
164 
165  public AssetDb LoadOrCreate<T>(string path, out T asset) where T : ScriptableObject {
166  asset = LoadOrCreate<T>(path);
167  return this;
168  }
169  #endregion
170 
171  #endif
172  }
173 }
Definition: Clock.cs:3
Instance caching
Definition: Cache.cs:9