├── .gitignore ├── Editor.meta ├── Editor ├── ME.ResourceCollector.asmdef ├── ME.ResourceCollector.asmdef.meta ├── ResourceCollector.cs └── ResourceCollector.cs.meta ├── LICENSE ├── LICENSE.meta ├── README.md ├── README.md.meta ├── package.json └── package.json.meta /.gitignore: -------------------------------------------------------------------------------- 1 | # This .gitignore file should be placed at the root of your Unity project directory 2 | # 3 | # Get latest from https://github.com/github/gitignore/blob/master/Unity.gitignore 4 | # 5 | /[Ll]ibrary/ 6 | /[Tt]emp/ 7 | /[Oo]bj/ 8 | /[Bb]uild/ 9 | /[Bb]uilds/ 10 | /[Ll]ogs/ 11 | /[Mm]emoryCaptures/ 12 | 13 | # Asset meta data should only be ignored when the corresponding asset is also ignored 14 | !/[Aa]ssets/**/*.meta 15 | 16 | # Uncomment this line if you wish to ignore the asset store tools plugin 17 | # /[Aa]ssets/AssetStoreTools* 18 | 19 | # Autogenerated Jetbrains Rider plugin 20 | [Aa]ssets/Plugins/Editor/JetBrains* 21 | 22 | # Visual Studio cache directory 23 | .vs/ 24 | 25 | # Gradle cache directory 26 | .gradle/ 27 | 28 | # Autogenerated VS/MD/Consulo solution and project files 29 | ExportedObj/ 30 | .consulo/ 31 | *.csproj 32 | *.unityproj 33 | *.sln 34 | *.suo 35 | *.tmp 36 | *.user 37 | *.userprefs 38 | *.pidb 39 | *.booproj 40 | *.svd 41 | *.pdb 42 | *.mdb 43 | *.opendb 44 | *.VC.db 45 | 46 | # Unity3D generated meta files 47 | *.pidb.meta 48 | *.pdb.meta 49 | *.mdb.meta 50 | 51 | # Unity3D generated file on crash reports 52 | sysinfo.txt 53 | 54 | # Builds 55 | *.apk 56 | *.unitypackage 57 | 58 | # Crashlytics generated file 59 | crashlytics-build.properties 60 | 61 | -------------------------------------------------------------------------------- /Editor.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: e950e4b32fb44d249c92811cbdc4b19f 3 | timeCreated: 1630479740 -------------------------------------------------------------------------------- /Editor/ME.ResourceCollector.asmdef: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ME.ResourceCollector", 3 | "rootNamespace": "", 4 | "references": [], 5 | "includePlatforms": [ 6 | "Editor" 7 | ], 8 | "excludePlatforms": [], 9 | "allowUnsafeCode": false, 10 | "overrideReferences": false, 11 | "precompiledReferences": [], 12 | "autoReferenced": true, 13 | "defineConstraints": [], 14 | "versionDefines": [], 15 | "noEngineReferences": false 16 | } -------------------------------------------------------------------------------- /Editor/ME.ResourceCollector.asmdef.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 2be60d3b2f3234a1e96bef9c90e1af1a 3 | AssemblyDefinitionImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Editor/ResourceCollector.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using System.Collections.Generic; 3 | 4 | namespace ME.ResourceCollector { 5 | 6 | using System.Linq; 7 | using UnityEngine; 8 | using UnityEditor; 9 | 10 | #region MAIN 11 | public class ResourceCollector : ScriptableObject { 12 | 13 | public static ResourceCollector GetData() { 14 | 15 | var dataPath = "Assets/ME.ResourceCollector/Editor/EditorData.asset"; 16 | var data = AssetDatabase.LoadAssetAtPath(dataPath); 17 | if (data == null) { 18 | var instance = ResourceCollector.CreateInstance(); 19 | AssetDatabase.CreateAsset(instance, dataPath); 20 | AssetDatabase.ImportAsset(dataPath); 21 | data = AssetDatabase.LoadAssetAtPath(dataPath); 22 | } 23 | return data; 24 | 25 | } 26 | 27 | [System.Serializable] 28 | public struct DependencyInfo { 29 | 30 | public Object obj; 31 | public int depth; 32 | 33 | public DependencyInfo(Object obj, int depth) { 34 | 35 | this.obj = obj; 36 | this.depth = depth; 37 | 38 | } 39 | 40 | } 41 | 42 | [System.Serializable] 43 | public struct Item { 44 | 45 | public Object obj; 46 | public string guid; 47 | public long size; 48 | 49 | public System.Collections.Generic.List deps; 50 | public System.Collections.Generic.List references; 51 | 52 | } 53 | 54 | public System.Collections.Generic.List items = new System.Collections.Generic.List(); 55 | private readonly System.Collections.Generic.Dictionary cacheSizes = new System.Collections.Generic.Dictionary(); 56 | private readonly System.Collections.Generic.Dictionary cacheSizesStr = new System.Collections.Generic.Dictionary(); 57 | 58 | public void Save() { 59 | 60 | EditorUtility.SetDirty(this); 61 | 62 | } 63 | 64 | public bool Delete(string guid) { 65 | 66 | for (int i = 0; i < this.items.Count; ++i) { 67 | 68 | var item = this.items[i]; 69 | if (item.guid == guid) { 70 | 71 | this.cacheSizes.Remove(guid); 72 | this.cacheSizesStr.Remove(guid); 73 | this.items.RemoveAt(i); 74 | return true; 75 | 76 | } 77 | 78 | } 79 | 80 | return false; 81 | 82 | } 83 | 84 | public bool Refresh(string guid, bool addOnFail = true) { 85 | 86 | var visited = new System.Collections.Generic.HashSet(); 87 | for (int i = 0; i < this.items.Count; ++i) { 88 | 89 | var item = this.items[i]; 90 | if (item.guid == guid) { 91 | 92 | this.cacheSizes.Remove(guid); 93 | this.cacheSizesStr.Remove(guid); 94 | 95 | this.cacheSizes.Add(guid, default); 96 | 97 | if (item.deps != null) item.deps.Clear(); 98 | if (item.deps == null) item.deps = new System.Collections.Generic.List(); 99 | this.UpdateSize(ref item, visited); 100 | this.UpdateReferences(ref item); 101 | this.items[i] = item; 102 | this.Save(); 103 | 104 | var str = UnityEditor.EditorUtility.FormatBytes(item.size); 105 | if (this.cacheSizes.ContainsKey(guid) == false) this.cacheSizes.Add(guid, item); 106 | this.cacheSizesStr.Add(guid, str); 107 | return true; 108 | 109 | } 110 | 111 | } 112 | 113 | if (addOnFail == false) return false; 114 | 115 | var asset = UnityEditor.AssetDatabase.LoadAssetAtPath(UnityEditor.AssetDatabase.GUIDToAssetPath(guid)); 116 | this.Add(asset); 117 | return this.Refresh(guid, addOnFail: false); 118 | 119 | } 120 | 121 | public void UpdateReferences(ref Item item) { 122 | 123 | if (item.references == null) item.references = new List(); 124 | item.references.Clear(); 125 | for (int i = 0; i < this.items.Count; ++i) { 126 | 127 | var data = this.items[i]; 128 | if (data.guid == item.guid) continue; 129 | 130 | for (int j = 0; j < data.deps.Count; ++j) { 131 | 132 | if (data.deps[j].obj == item.obj && data.deps[j].depth == 0) { 133 | 134 | item.references.Add(data.obj); 135 | break; 136 | 137 | } 138 | 139 | } 140 | 141 | } 142 | 143 | } 144 | 145 | public System.Collections.Generic.List GetDependencies(string guid) { 146 | 147 | for (int i = 0; i < this.items.Count; ++i) { 148 | 149 | if (this.items[i].guid == guid) return this.items[i].deps; 150 | 151 | } 152 | 153 | return null; 154 | 155 | } 156 | 157 | public System.Collections.Generic.List GetReferences(string guid) { 158 | 159 | for (int i = 0; i < this.items.Count; ++i) { 160 | 161 | if (this.items[i].guid == guid) return this.items[i].references; 162 | 163 | } 164 | 165 | return null; 166 | 167 | } 168 | 169 | public string GetSizeStr(string guid) { 170 | 171 | if (this.cacheSizesStr.Count != this.items.Count) this.BuildCache(); 172 | 173 | if (this.cacheSizesStr.TryGetValue(guid, out var str) == true) return str; 174 | return string.Empty; 175 | 176 | } 177 | 178 | public void BuildCache() { 179 | 180 | this.cacheSizesStr.Clear(); 181 | for (int i = 0; i < this.items.Count; ++i) { 182 | 183 | var item = this.items[i]; 184 | if (this.cacheSizesStr.ContainsKey(item.guid) == false) { 185 | 186 | this.cacheSizesStr.Add(item.guid, UnityEditor.EditorUtility.FormatBytes(item.size)); 187 | 188 | } 189 | 190 | } 191 | 192 | this.cacheSizes.Clear(); 193 | for (int i = 0; i < this.items.Count; ++i) { 194 | 195 | var item = this.items[i]; 196 | if (this.cacheSizes.ContainsKey(item.guid) == false) { 197 | 198 | this.cacheSizes.Add(item.guid, item); 199 | 200 | } 201 | 202 | } 203 | 204 | } 205 | 206 | private void UpdateSize(ref Item item, System.Collections.Generic.HashSet visited = null) { 207 | 208 | Utils.CollectAtlases(item.obj is UnityEngine.U2D.SpriteAtlas); 209 | item.size = Utils.GetObjectSize(this, null, item.obj, visited, item.deps, collectUnityObjects: true); 210 | var obj = item.obj; 211 | item.deps.RemoveAll(x => x.obj == obj); 212 | 213 | } 214 | 215 | public void CalculateSizes() { 216 | 217 | this.cacheSizes.Clear(); 218 | 219 | var visited = new System.Collections.Generic.HashSet(); 220 | for (int i = 0; i < this.items.Count; ++i) { 221 | 222 | var item = this.items[i]; 223 | UnityEditor.EditorUtility.DisplayProgressBar("Calculate Sizes", item.obj != null ? item.obj.ToString() : "Null", i / (float)this.items.Count); 224 | 225 | { 226 | visited.Clear(); 227 | if (item.deps == null) item.deps = new System.Collections.Generic.List(); 228 | this.UpdateSize(ref item, visited); 229 | } 230 | this.items[i] = item; 231 | 232 | } 233 | 234 | for (int i = 0; i < this.items.Count; ++i) { 235 | 236 | var item = this.items[i]; 237 | this.UpdateReferences(ref item); 238 | this.items[i] = item; 239 | 240 | } 241 | 242 | this.BuildCache(); 243 | this.Save(); 244 | 245 | UnityEditor.EditorUtility.ClearProgressBar(); 246 | 247 | } 248 | 249 | public long UpdateSize(object obj, long size) { 250 | 251 | if (obj is Object tObj) { 252 | 253 | var p = UnityEditor.AssetDatabase.GetAssetPath(tObj); 254 | var guid = UnityEditor.AssetDatabase.AssetPathToGUID(p); 255 | if (this.cacheSizes.TryGetValue(guid, out _) == true) { 256 | 257 | var item = this.cacheSizes[guid]; 258 | item.size = size; 259 | this.cacheSizes[guid] = item; 260 | 261 | } else { 262 | 263 | this.cacheSizes.Add(guid, this.GetItem(guid)); 264 | 265 | } 266 | 267 | } 268 | 269 | return size; 270 | 271 | } 272 | 273 | public Item GetItem(string guid) { 274 | 275 | for (int i = 0; i < this.items.Count; ++i) { 276 | 277 | var item = this.items[i]; 278 | if (item.guid == guid) { 279 | 280 | return item; 281 | 282 | } 283 | 284 | } 285 | 286 | return default; 287 | 288 | } 289 | 290 | public bool GetItemCached(string guid, out Item item) { 291 | 292 | return this.cacheSizes.TryGetValue(guid, out item); 293 | 294 | } 295 | 296 | public bool GetSize(object obj, out long size) { 297 | 298 | size = -1L; 299 | if (obj is Object tObj) { 300 | 301 | var p = UnityEditor.AssetDatabase.GetAssetPath(tObj); 302 | var guid = UnityEditor.AssetDatabase.AssetPathToGUID(p); 303 | if (this.cacheSizes.TryGetValue(guid, out var item) == true) { 304 | 305 | size = item.size; 306 | return size > 0L; 307 | 308 | } 309 | 310 | size = this.GetItem(guid).size; 311 | if (size > 0L) { 312 | size = this.UpdateSize(obj, size); 313 | return true; 314 | } 315 | 316 | } 317 | 318 | return false; 319 | 320 | } 321 | 322 | public void Add(Object obj) { 323 | 324 | if (obj == this) return; 325 | 326 | this.items.Add(new Item() { 327 | obj = obj, 328 | guid = UnityEditor.AssetDatabase.AssetPathToGUID(UnityEditor.AssetDatabase.GetAssetPath(obj)), 329 | size = 0L, 330 | }); 331 | this.Save(); 332 | 333 | } 334 | 335 | /*public string testGuid; 336 | [ContextMenu("Test")] 337 | public void Test() { 338 | 339 | var visited = new System.Collections.Generic.HashSet(); 340 | var item = this.items.FirstOrDefault(x => x.guid == this.testGuid); 341 | if (item.deps == null) item.deps = new System.Collections.Generic.List(); 342 | item.size = Utils.GetObjectSize(this, item.obj, visited, item.deps, collectUnityObjects: true); 343 | Debug.Log("Obj size: " + item.size); 344 | foreach (var obj in visited) { 345 | Debug.Log(obj); 346 | } 347 | 348 | }*/ 349 | 350 | } 351 | #endregion 352 | 353 | #region MENU 354 | public static class Menu { 355 | 356 | [UnityEditor.MenuItem("Tools/ME.ResourceCollector/Recalculate Resource Sizes...")] 357 | public static void CalculateSizes() { 358 | 359 | var data = ResourceCollector.GetData(); 360 | if (data == null) return; 361 | 362 | try { 363 | 364 | data.CalculateSizes(); 365 | 366 | } catch (System.Exception ex) { 367 | Debug.LogException(ex); 368 | } 369 | 370 | EditorUtility.SetDirty(data); 371 | EditorUtility.ClearProgressBar(); 372 | 373 | Debug.Log("Done"); 374 | 375 | } 376 | 377 | [UnityEditor.MenuItem("Tools/ME.ResourceCollector/Update Resources...")] 378 | public static void Collect() { 379 | 380 | var data = ResourceCollector.GetData(); 381 | if (data == null) return; 382 | 383 | data.items.Clear(); 384 | 385 | var searches = new string[] { 386 | "t:Texture", 387 | "t:Material", 388 | "t:Sprite", 389 | "t:ScriptableObject", 390 | "t:prefab", 391 | "t:spriteatlas", 392 | }; 393 | 394 | try { 395 | 396 | var collected = new HashSet(); 397 | for (int i = 0; i < searches.Length; ++i) { 398 | 399 | EditorUtility.DisplayProgressBar("Collect Objects", searches[i], i / (float)searches.Length); 400 | 401 | var objs = AssetDatabase.FindAssets(searches[i]); 402 | foreach (var guid in objs) { 403 | 404 | var path = AssetDatabase.GUIDToAssetPath(guid); 405 | var obj = AssetDatabase.LoadAssetAtPath(path); 406 | if (obj != null) { 407 | 408 | if (collected.Contains(guid) == false) data.Add(obj); 409 | collected.Add(guid); 410 | 411 | } 412 | 413 | } 414 | 415 | } 416 | 417 | EditorUtility.SetDirty(data); 418 | 419 | data.CalculateSizes(); 420 | 421 | } catch (System.Exception ex) { 422 | Debug.LogException(ex); 423 | } 424 | 425 | EditorUtility.SetDirty(data); 426 | EditorUtility.ClearProgressBar(); 427 | 428 | Debug.Log("Done"); 429 | 430 | } 431 | 432 | } 433 | #endregion 434 | 435 | #region AssetsImporter 436 | public static class AssetsImporterMenu { 437 | 438 | [MenuItem("Tools/ME.ResourceCollector/Refresh Assets on Import")] 439 | public static void AutoImport() { 440 | 441 | var state = EditorPrefs.GetBool("ME.ResourceCollector.AutoImport", false); 442 | EditorPrefs.SetBool("ME.ResourceCollector.AutoImport", !state); 443 | 444 | } 445 | 446 | [MenuItem("Tools/ME.ResourceCollector/Refresh Assets on Import", isValidateFunction: true)] 447 | public static bool AutoImportValidation() { 448 | 449 | var state = EditorPrefs.GetBool("ME.ResourceCollector.AutoImport", false); 450 | UnityEditor.Menu.SetChecked("Tools/ME.ResourceCollector/Refresh Assets on Import", state); 451 | return true; 452 | 453 | } 454 | 455 | } 456 | 457 | public class AssetsImporter : AssetPostprocessor { 458 | 459 | public static void OnPostprocessAllAssets(string[] importedAssets, string[] deletedAssets, string[] movedAssets, string[] movedFromAssetPaths) { 460 | 461 | if (EditorPrefs.GetBool("ME.ResourceCollector.AutoImport", false) == false) return; 462 | 463 | var data = ResourceCollector.GetData(); 464 | if (data == null) return; 465 | 466 | foreach (var path in importedAssets) { 467 | 468 | data.Refresh(AssetDatabase.AssetPathToGUID(path)); 469 | 470 | } 471 | 472 | foreach (var path in deletedAssets) { 473 | 474 | data.Delete(AssetDatabase.AssetPathToGUID(path)); 475 | 476 | } 477 | 478 | } 479 | 480 | } 481 | #endregion 482 | 483 | #region GUI:Hierarchy 484 | [InitializeOnLoad] 485 | public static class HierarchyGUIEditor { 486 | 487 | static HierarchyGUIEditor() { 488 | 489 | HierarchyGUIEditor.Reassign(); 490 | 491 | } 492 | 493 | [UnityEditor.Callbacks.DidReloadScripts] 494 | public static void OnAssemblyReload() { 495 | 496 | HierarchyGUIEditor.Reassign(); 497 | 498 | EditorApplication.delayCall += () => { 499 | 500 | HierarchyGUIEditor.Reassign(); 501 | 502 | }; 503 | 504 | } 505 | 506 | [InitializeOnLoadMethod] 507 | public static void Reassign() { 508 | 509 | EditorApplication.projectWindowItemOnGUI -= HierarchyGUIEditor.OnElementGUI; 510 | EditorApplication.projectWindowItemOnGUI += HierarchyGUIEditor.OnElementGUI; 511 | 512 | } 513 | 514 | private static GUIStyle buttonStyle; 515 | private static ResourceCollector resourceCollector; 516 | public static void OnElementGUI(string guid, UnityEngine.Rect rect) { 517 | 518 | if (HierarchyGUIEditor.buttonStyle == null) { 519 | HierarchyGUIEditor.buttonStyle = new GUIStyle(EditorStyles.miniPullDown); 520 | HierarchyGUIEditor.buttonStyle.fontSize = 10; 521 | HierarchyGUIEditor.buttonStyle.alignment = TextAnchor.MiddleRight; 522 | } 523 | 524 | if (HierarchyGUIEditor.resourceCollector == null) HierarchyGUIEditor.resourceCollector = ResourceCollector.GetData(); 525 | if (HierarchyGUIEditor.resourceCollector == null) return; 526 | 527 | var size = HierarchyGUIEditor.resourceCollector.GetSizeStr(guid); 528 | if (string.IsNullOrEmpty(size) == false) { 529 | 530 | var selectionRect = new Rect(rect); 531 | var s = HierarchyGUIEditor.buttonStyle.CalcSize(new GUIContent(size)); 532 | selectionRect.width = s.x; 533 | selectionRect.height = EditorGUIUtility.singleLineHeight; 534 | selectionRect.x = rect.x + rect.width - selectionRect.width; 535 | 536 | if (GUI.Button(selectionRect, size, HierarchyGUIEditor.buttonStyle) == true) { 537 | 538 | var item = HierarchyGUIEditor.resourceCollector.GetItem(guid); 539 | var p = GUIUtility.GUIToScreenPoint(selectionRect.min); 540 | selectionRect.x = p.x; 541 | selectionRect.y = p.y; 542 | DependenciesPopup.Show(selectionRect, new Vector2(200f, 500f), HierarchyGUIEditor.resourceCollector, item); 543 | 544 | } 545 | 546 | if (HierarchyGUIEditor.resourceCollector.GetItemCached(guid, out var itemCached) == true && itemCached.references != null && itemCached.references.Count == 0) { 547 | 548 | var r = selectionRect; 549 | r.x += r.width - 1f; 550 | r.width = 1f; 551 | r.y += 2f; 552 | r.height -= 4f; 553 | var prevColor = GUI.color; 554 | GUI.color = Color.cyan; 555 | GUI.DrawTexture(r, Texture2D.whiteTexture, ScaleMode.StretchToFill); 556 | GUI.color = prevColor; 557 | 558 | } 559 | 560 | } 561 | 562 | } 563 | 564 | } 565 | 566 | public class DependenciesPopup : EditorWindow { 567 | 568 | public Vector2 scrollPositionReferences; 569 | public Vector2 scrollPositionDependencies; 570 | public Rect rect; 571 | public Vector2 size; 572 | private ResourceCollector data; 573 | private ResourceCollector.Item item; 574 | 575 | private float height; 576 | private bool heightCalc; 577 | 578 | public static void Show(Rect buttonRect, Vector2 size, ResourceCollector data, ResourceCollector.Item item) { 579 | 580 | var popup = DependenciesPopup.CreateInstance(); 581 | popup.data = data; 582 | popup.item = item; 583 | popup.size = size; 584 | popup.rect = buttonRect; 585 | popup.UpdateDeps(); 586 | popup.UpdateReferences(); 587 | popup.ShowAsDropDown(buttonRect, size); 588 | 589 | } 590 | 591 | private void UpdateDeps() { 592 | 593 | this.item.deps = this.data.GetDependencies(this.item.guid).Where(x => { 594 | 595 | return x.depth == 0; 596 | 597 | }).OrderByDescending(x => { 598 | 599 | return this.data.GetSizeStr(AssetDatabase.AssetPathToGUID(AssetDatabase.GetAssetPath(x.obj))); 600 | /*if (this.data.GetSize(x.obj, out var size) == true) { 601 | 602 | return size; 603 | 604 | } 605 | 606 | return 0L;*/ 607 | 608 | }).ToList(); 609 | this.heightCalc = false; 610 | 611 | } 612 | 613 | private void UpdateReferences() { 614 | 615 | this.item.references = this.data.GetReferences(this.item.guid).OrderByDescending(x => { 616 | 617 | if (this.data.GetSize(x, out var size) == true) { 618 | 619 | return size; 620 | 621 | } 622 | 623 | return 0L; 624 | 625 | }).ToList(); 626 | this.heightCalc = false; 627 | 628 | } 629 | 630 | private void OnGUI() { 631 | 632 | this.height = 0f; 633 | 634 | if (this.item.references != null) { 635 | 636 | GUILayout.BeginHorizontal(GUILayout.Height(20f)); 637 | GUILayout.BeginVertical(); 638 | GUILayout.FlexibleSpace(); 639 | GUILayout.Label("Referenced by: " + this.item.references.Count, EditorStyles.miniLabel); 640 | GUILayout.FlexibleSpace(); 641 | GUILayout.EndVertical(); 642 | GUILayout.FlexibleSpace(); 643 | if (GUILayout.Button("Refresh", EditorStyles.miniButton) == true) { 644 | 645 | if (this.data.Refresh(this.item.guid) == true) { 646 | 647 | this.UpdateReferences(); 648 | 649 | } 650 | 651 | } 652 | GUILayout.EndHorizontal(); 653 | if (this.heightCalc == false) { 654 | 655 | var rect = GUILayoutUtility.GetLastRect(); 656 | this.height += rect.height; 657 | 658 | } 659 | 660 | this.scrollPositionReferences = GUILayout.BeginScrollView(this.scrollPositionReferences); 661 | foreach (var dep in this.item.references) { 662 | 663 | EditorGUI.BeginDisabledGroup(true); 664 | EditorGUILayout.ObjectField(dep, typeof(Object), allowSceneObjects: true); 665 | EditorGUI.EndDisabledGroup(); 666 | var rect = GUILayoutUtility.GetLastRect(); 667 | HierarchyGUIEditor.OnElementGUI(AssetDatabase.AssetPathToGUID(AssetDatabase.GetAssetPath(dep)), rect); 668 | if (this.heightCalc == false) { 669 | 670 | this.height += rect.height + 2f; 671 | 672 | } 673 | 674 | } 675 | GUILayout.EndScrollView(); 676 | 677 | } 678 | 679 | if (this.item.deps != null) { 680 | 681 | GUILayout.BeginHorizontal(GUILayout.Height(20f)); 682 | GUILayout.BeginVertical(); 683 | GUILayout.FlexibleSpace(); 684 | GUILayout.Label("Reference to: " + this.item.deps.Count, EditorStyles.miniLabel); 685 | GUILayout.FlexibleSpace(); 686 | GUILayout.EndVertical(); 687 | GUILayout.FlexibleSpace(); 688 | if (GUILayout.Button("Refresh", EditorStyles.miniButton) == true) { 689 | 690 | if (this.data.Refresh(this.item.guid) == true) { 691 | 692 | this.UpdateDeps(); 693 | 694 | } 695 | 696 | } 697 | GUILayout.EndHorizontal(); 698 | if (this.heightCalc == false) { 699 | 700 | var rect = GUILayoutUtility.GetLastRect(); 701 | this.height += rect.height; 702 | 703 | } 704 | 705 | this.scrollPositionDependencies = GUILayout.BeginScrollView(this.scrollPositionDependencies); 706 | foreach (var dep in this.item.deps) { 707 | 708 | EditorGUI.BeginDisabledGroup(true); 709 | EditorGUILayout.ObjectField(dep.obj, typeof(Object), allowSceneObjects: true); 710 | EditorGUI.EndDisabledGroup(); 711 | var rect = GUILayoutUtility.GetLastRect(); 712 | HierarchyGUIEditor.OnElementGUI(AssetDatabase.AssetPathToGUID(AssetDatabase.GetAssetPath(dep.obj)), rect); 713 | if (this.heightCalc == false) { 714 | 715 | this.height += rect.height + 2f; 716 | 717 | } 718 | 719 | } 720 | GUILayout.EndScrollView(); 721 | 722 | } 723 | 724 | if (Event.current.type == EventType.Repaint && this.heightCalc == false) { 725 | 726 | this.height += 10f; 727 | if (this.size.y > this.height) { 728 | this.size.y = this.height; 729 | this.ShowAsDropDown(this.rect, this.size); 730 | } 731 | 732 | this.heightCalc = true; 733 | 734 | } 735 | 736 | } 737 | 738 | } 739 | #endregion 740 | 741 | #region GUI:ObjectFieldDrawer 742 | [CustomPropertyDrawer(typeof(Object), true)] 743 | public class ObjectFieldDrawer : PropertyDrawer { 744 | 745 | public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) { 746 | 747 | EditorGUI.PropertyField(position, property, label); 748 | 749 | var obj = property.objectReferenceValue; 750 | if (obj != null) { 751 | 752 | var path = AssetDatabase.GetAssetPath(obj); 753 | var guid = AssetDatabase.AssetPathToGUID(path); 754 | position.width -= 20f; 755 | HierarchyGUIEditor.OnElementGUI(guid, position); 756 | 757 | } 758 | 759 | } 760 | 761 | } 762 | #endregion 763 | 764 | #region Parser 765 | public static class Utils { 766 | 767 | private static System.Reflection.MethodInfo getTextureSizeMethod; 768 | 769 | public static long GetAtlasSize(AtlasData atlas) { 770 | 771 | var atlasSize = 0L; 772 | foreach (var tex in atlas.previews) { 773 | 774 | atlasSize += GetTextureSize(tex); 775 | 776 | } 777 | 778 | return atlasSize; 779 | 780 | } 781 | 782 | public static long GetTextureSize(UnityEngine.Texture texture) { 783 | 784 | if (Utils.getTextureSizeMethod == null) { 785 | 786 | var textureUtils = typeof(UnityEditor.Editor).Assembly.GetType("UnityEditor.TextureUtil"); 787 | Utils.getTextureSizeMethod = textureUtils.GetMethod("GetStorageMemorySize", System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static); 788 | 789 | } 790 | 791 | return (int)Utils.getTextureSizeMethod.Invoke(null, new[] { texture }); 792 | 793 | } 794 | 795 | public static long GetMeshSize(UnityEngine.Mesh mesh) { 796 | 797 | var size = 0L; 798 | 799 | var attributes = mesh.GetVertexAttributes(); 800 | var vertexSize = attributes.Sum(attr => Utils.ConvertFormatToSize(attr.format) * attr.dimension); 801 | size += mesh.vertexCount * vertexSize; 802 | 803 | var indexCount = Utils.CalcTotalIndices(mesh); 804 | var indexSize = mesh.indexFormat == UnityEngine.Rendering.IndexFormat.UInt16 ? 2 : 4; 805 | size += indexCount * indexSize; 806 | 807 | return size; 808 | 809 | } 810 | 811 | public struct AtlasData { 812 | 813 | public UnityEngine.U2D.SpriteAtlas atlas; 814 | public Texture2D[] previews; 815 | 816 | } 817 | 818 | private static Dictionary listAtlases; 819 | public static void CollectAtlases(bool force = false) { 820 | 821 | if (Utils.listAtlases != null) { 822 | 823 | foreach (var atlas in Utils.listAtlases) { 824 | 825 | if (atlas.Key == null) { 826 | 827 | force = true; 828 | break; 829 | 830 | } 831 | 832 | } 833 | 834 | } 835 | 836 | if (force == false && listAtlases != null && listAtlases.Count > 0) { 837 | 838 | return; 839 | 840 | } 841 | 842 | listAtlases = new Dictionary(); 843 | var atlasesGUID = AssetDatabase.FindAssets("t:spriteatlas"); 844 | foreach (var atlasGUID in atlasesGUID) { 845 | 846 | var atlas = AssetDatabase.LoadAssetAtPath(AssetDatabase.GUIDToAssetPath(atlasGUID)); 847 | if (atlas != null) { 848 | 849 | var previews = typeof(UnityEditor.U2D.SpriteAtlasExtensions).GetMethod("GetPreviewTextures", System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic); 850 | listAtlases.Add(atlas, new AtlasData() { 851 | atlas = atlas, 852 | previews = (Texture2D[])previews.Invoke(null, new [] { atlas }), 853 | }); 854 | 855 | } 856 | 857 | } 858 | 859 | } 860 | 861 | public static long GetObjectSize(ResourceCollector data, 862 | object root, 863 | object obj, 864 | System.Collections.Generic.HashSet visited, 865 | System.Collections.Generic.List deps, 866 | bool collectUnityObjects, 867 | int depth = 0) { 868 | 869 | if (visited == null) { 870 | visited = new System.Collections.Generic.HashSet(); 871 | } 872 | 873 | var ptr = obj; 874 | if (visited.Contains(ptr) == true) { 875 | return 0L; 876 | } 877 | 878 | visited.Add(ptr); 879 | 880 | var pointerSize = System.IntPtr.Size; 881 | var size = 0L; 882 | if (obj == null) { 883 | return pointerSize; 884 | } 885 | 886 | var charSize = Unity.Collections.LowLevel.Unsafe.UnsafeUtility.SizeOf(); 887 | 888 | var type = obj.GetType(); 889 | if (typeof(UnityEngine.Renderer).IsAssignableFrom(type) == true) { 890 | 891 | var typedObj = (UnityEngine.Renderer)obj; 892 | if (typedObj == null) { 893 | return pointerSize; 894 | } 895 | 896 | if (typedObj.sharedMaterials != null) { 897 | 898 | foreach (var mat in typedObj.sharedMaterials) { 899 | 900 | if (mat == null) { 901 | continue; 902 | } 903 | 904 | size += Utils.GetObjectSize(data, obj, mat, visited, deps, collectUnityObjects, depth); 905 | 906 | } 907 | 908 | } else { 909 | 910 | size += Utils.GetObjectSize(data, obj, typedObj.sharedMaterial, visited, deps, collectUnityObjects, depth); 911 | 912 | } 913 | 914 | } 915 | 916 | if (type == typeof(UnityEngine.Mesh)) { 917 | 918 | var typedObj = (UnityEngine.Mesh)obj; 919 | if (typedObj == null) { 920 | return pointerSize; 921 | } 922 | 923 | var mesh = typedObj; 924 | deps.Add(new ResourceCollector.DependencyInfo(mesh, depth)); 925 | if (data.GetSize(mesh, out var s) == true) { 926 | size += s; 927 | } else { 928 | size += data.UpdateSize(mesh, Utils.GetMeshSize(mesh)); 929 | } 930 | 931 | } 932 | 933 | if (type == typeof(UnityEngine.MeshFilter)) { 934 | 935 | var typedObj = (UnityEngine.MeshFilter)obj; 936 | if (typedObj == null) { 937 | return pointerSize; 938 | } 939 | 940 | var mesh = typedObj.sharedMesh; 941 | if (mesh == null) { 942 | return pointerSize; 943 | } 944 | 945 | deps.Add(new ResourceCollector.DependencyInfo(mesh, depth)); 946 | 947 | if (data.GetSize(mesh, out var s) == true) { 948 | size += s; 949 | } else { 950 | size += data.UpdateSize(mesh, Utils.GetMeshSize(mesh)); 951 | } 952 | 953 | } 954 | 955 | if (type == typeof(UnityEngine.SpriteRenderer)) { 956 | 957 | var typedObj = (UnityEngine.SpriteRenderer)obj; 958 | if (typedObj == null) { 959 | return pointerSize; 960 | } 961 | 962 | size += Utils.GetObjectSize(data, obj, typedObj.sprite, visited, deps, collectUnityObjects, depth); 963 | 964 | } 965 | 966 | if (typeof(UnityEngine.Component).IsAssignableFrom(type) == true) { 967 | 968 | var comp = (UnityEngine.Component)obj; 969 | if (comp == null) { 970 | return pointerSize; 971 | } 972 | 973 | var go = ((UnityEngine.Component)obj).gameObject; 974 | if (go == null) { 975 | return pointerSize; 976 | } 977 | 978 | if (GetPrefabRoot(go) != GetPrefabRoot(root)) { 979 | 980 | deps.Add(new ResourceCollector.DependencyInfo(go, depth)); 981 | 982 | } 983 | 984 | var tempResults = new System.Collections.Generic.List(); 985 | tempResults.AddRange(go.GetComponents()); 986 | foreach (var item in tempResults) { 987 | 988 | size += Utils.GetObjectSize(data, obj, item, visited, deps, collectUnityObjects, depth); 989 | 990 | } 991 | 992 | } 993 | 994 | if (type == typeof(UnityEngine.U2D.SpriteAtlas)) { 995 | 996 | var atlas = (UnityEngine.U2D.SpriteAtlas)obj; 997 | if (atlas == null) { 998 | return pointerSize; 999 | } 1000 | 1001 | deps.Add(new ResourceCollector.DependencyInfo(atlas, depth)); 1002 | if (listAtlases.TryGetValue(atlas, out var atlasData) == true) { 1003 | 1004 | size += data.UpdateSize(atlasData.atlas, Utils.GetAtlasSize(atlasData)); 1005 | 1006 | } 1007 | 1008 | } 1009 | 1010 | if (type == typeof(UnityEngine.GameObject)) { 1011 | 1012 | var go = (UnityEngine.GameObject)obj; 1013 | var tempResults = new System.Collections.Generic.List(); 1014 | var nextGo = go; 1015 | 1016 | if (go == null) { 1017 | return pointerSize; 1018 | } 1019 | 1020 | tempResults.AddRange(go.GetComponents()); 1021 | 1022 | if (GetPrefabRoot(go) != GetPrefabRoot(root)) { 1023 | 1024 | deps.Add(new ResourceCollector.DependencyInfo(go, depth)); 1025 | 1026 | } 1027 | 1028 | System.Action collectGo = null; 1029 | collectGo = (UnityEngine.GameObject goRoot) => { 1030 | 1031 | if (goRoot == null) { 1032 | return; 1033 | } 1034 | 1035 | for (var i = 0; i < goRoot.transform.childCount; ++i) { 1036 | 1037 | var child = goRoot.transform.GetChild(i); 1038 | tempResults.AddRange(child.GetComponents()); 1039 | collectGo.Invoke(child.gameObject); 1040 | 1041 | } 1042 | 1043 | }; 1044 | collectGo.Invoke(nextGo); 1045 | 1046 | foreach (var item in tempResults) { 1047 | 1048 | size += Utils.GetObjectSize(data, obj, item, visited, deps, collectUnityObjects, depth); 1049 | 1050 | } 1051 | 1052 | } else if (type == typeof(UnityEngine.Material)) { 1053 | 1054 | var mat = (UnityEngine.Material)obj; 1055 | if (mat == null) { 1056 | return pointerSize; 1057 | } 1058 | 1059 | deps.Add(new ResourceCollector.DependencyInfo(mat, depth)); 1060 | var props = mat.GetTexturePropertyNames(); 1061 | foreach (var prop in props) { 1062 | 1063 | var tex = mat.GetTexture(prop); 1064 | if (tex == null) { 1065 | continue; 1066 | } 1067 | 1068 | if (root == null) deps.Add(new ResourceCollector.DependencyInfo(tex, depth)); 1069 | size += Utils.GetObjectSize(data, obj, tex, visited, deps, collectUnityObjects, depth + 1); 1070 | 1071 | } 1072 | 1073 | } else if (type == typeof(UnityEngine.Sprite)) { 1074 | 1075 | var sprite = (UnityEngine.Sprite)obj; 1076 | if (sprite == null) { 1077 | return pointerSize; 1078 | } 1079 | 1080 | var useAtlas = false; 1081 | foreach (var atlas in listAtlases) { 1082 | 1083 | if (atlas.Value.atlas.CanBindTo(sprite) == true) { 1084 | 1085 | size += GetObjectSize(data, root, atlas.Value.atlas, visited, deps, collectUnityObjects, depth); 1086 | useAtlas = true; 1087 | break; 1088 | 1089 | } 1090 | 1091 | } 1092 | 1093 | if (useAtlas == false) { 1094 | 1095 | var tex = sprite.texture; 1096 | deps.Add(new ResourceCollector.DependencyInfo((UnityEngine.Sprite)obj, depth)); 1097 | if (data.GetSize(tex, out var s) == true) { 1098 | size += s; 1099 | } else { 1100 | size += data.UpdateSize(tex, Utils.GetTextureSize(tex)); 1101 | } 1102 | 1103 | } 1104 | 1105 | } else if (type == typeof(UnityEngine.Texture) || 1106 | type == typeof(UnityEngine.Texture2D) || 1107 | type == typeof(UnityEngine.RenderTexture) || 1108 | typeof(UnityEngine.Texture).IsAssignableFrom(type) == true) { 1109 | 1110 | var tex = (UnityEngine.Texture)obj; 1111 | if (tex == null) { 1112 | return pointerSize; 1113 | } 1114 | 1115 | deps.Add(new ResourceCollector.DependencyInfo(tex, depth)); 1116 | if (data.GetSize(tex, out var s) == true) { 1117 | size += s; 1118 | } else { 1119 | size += data.UpdateSize(tex, Utils.GetTextureSize(tex)); 1120 | } 1121 | 1122 | } else if (collectUnityObjects == false && typeof(UnityEngine.Object).IsAssignableFrom(type) == true) { 1123 | 1124 | size += pointerSize; 1125 | 1126 | } else if (type.IsEnum == true) { 1127 | 1128 | size += sizeof(int); 1129 | 1130 | } else if (type.IsPointer == true) { 1131 | 1132 | size += pointerSize; 1133 | 1134 | } else if (type.IsArray == false && type.IsValueType == true && 1135 | (type.IsPrimitive == true || Unity.Collections.LowLevel.Unsafe.UnsafeUtility.IsBlittable(type) == true)) { 1136 | 1137 | size += System.Runtime.InteropServices.Marshal.SizeOf(obj); 1138 | 1139 | } else { 1140 | 1141 | var fields = type.GetFields(System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.NonPublic); 1142 | if (fields.Length == 0 && type.IsValueType == true) { 1143 | 1144 | size += System.Runtime.InteropServices.Marshal.SizeOf(obj); 1145 | 1146 | } else { 1147 | 1148 | System.Action deferred = null; 1149 | foreach (var fieldInfo in fields) { 1150 | 1151 | var field = fieldInfo; 1152 | var fieldType = field.FieldType; 1153 | if (collectUnityObjects == false && typeof(UnityEngine.Object).IsAssignableFrom(fieldType) == true) { 1154 | 1155 | size += pointerSize; 1156 | continue; 1157 | 1158 | } 1159 | 1160 | if (fieldType.IsEnum == true) { 1161 | 1162 | size += sizeof(int); 1163 | 1164 | } else if (fieldType.IsPointer == true) { 1165 | 1166 | size += pointerSize; 1167 | 1168 | } else if (fieldType.IsArray == false && fieldType.IsValueType == true && 1169 | (fieldType.IsPrimitive == true || Unity.Collections.LowLevel.Unsafe.UnsafeUtility.IsBlittable(fieldType) == true)) { 1170 | 1171 | size += System.Runtime.InteropServices.Marshal.SizeOf(fieldType); 1172 | 1173 | } else if (fieldType == typeof(string)) { 1174 | 1175 | var str = (string)field.GetValue(obj); 1176 | if (str != null) { 1177 | 1178 | size += charSize * str.Length; 1179 | 1180 | } 1181 | 1182 | } else if (fieldType.IsValueType == true) { 1183 | 1184 | size += Utils.GetObjectSize(data, obj, field.GetValue(obj), visited, deps, 1185 | collectUnityObjects, depth); 1186 | 1187 | } else if (fieldType.IsArray == true && fieldType.GetArrayRank() == 1) { 1188 | 1189 | var arr = (System.Array)field.GetValue(obj); 1190 | if (arr != null) { 1191 | 1192 | for (var i = 0; i < arr.Length; ++i) { 1193 | var d = depth + GetDepth(obj, arr.GetValue(i), deps, depth); 1194 | if (d > depth) { 1195 | var idx = i; 1196 | deferred += () => { 1197 | size += Utils.GetObjectSize(data, obj, arr.GetValue(idx), visited, deps, collectUnityObjects, d); 1198 | }; 1199 | } else { 1200 | size += Utils.GetObjectSize(data, obj, arr.GetValue(i), visited, deps, collectUnityObjects, d); 1201 | } 1202 | } 1203 | 1204 | } 1205 | 1206 | } else { 1207 | 1208 | var d = depth + GetDepth(obj, field.GetValue(obj), deps, depth); 1209 | if (d > depth) { 1210 | deferred += () => { 1211 | size += Utils.GetObjectSize(data, obj, field.GetValue(obj), visited, deps, collectUnityObjects, d); 1212 | }; 1213 | } else { 1214 | size += Utils.GetObjectSize(data, obj, field.GetValue(obj), visited, deps, collectUnityObjects, d); 1215 | } 1216 | 1217 | } 1218 | 1219 | } 1220 | deferred?.Invoke(); 1221 | 1222 | } 1223 | 1224 | } 1225 | 1226 | return size; 1227 | 1228 | } 1229 | 1230 | private static int GetDepth(object root, object obj, List deps, int depth) { 1231 | 1232 | if (obj is ScriptableObject so) { 1233 | 1234 | deps.Add(new ResourceCollector.DependencyInfo(so, depth)); 1235 | return 1; 1236 | 1237 | } 1238 | 1239 | var v1 = GetPrefabRoot(root); 1240 | var v2 = GetPrefabRoot(obj); 1241 | if (v1 != null && v2 != null) { 1242 | 1243 | if (v1 != v2) { 1244 | 1245 | deps.Add(new ResourceCollector.DependencyInfo((Object)obj, depth)); 1246 | return 1; 1247 | 1248 | } 1249 | 1250 | return 0; 1251 | 1252 | } 1253 | 1254 | return 0; 1255 | 1256 | } 1257 | 1258 | private static Transform GetPrefabRoot(object obj) { 1259 | 1260 | if (obj == null) return null; 1261 | 1262 | var type = obj.GetType(); 1263 | if (typeof(GameObject) == type || 1264 | typeof(Component).IsAssignableFrom(type) == true) { 1265 | 1266 | var o = (Object)obj; 1267 | if (o == null) return null; 1268 | 1269 | if (typeof(GameObject) == type) { 1270 | 1271 | return ((GameObject)obj).transform.root; 1272 | 1273 | } 1274 | 1275 | return ((Component)obj).transform.root; 1276 | 1277 | } 1278 | 1279 | return null; 1280 | 1281 | } 1282 | 1283 | private static int CalcTotalIndices(UnityEngine.Mesh mesh) { 1284 | var totalCount = 0; 1285 | for (var i = 0; i < mesh.subMeshCount; i++) { 1286 | totalCount += (int)mesh.GetIndexCount(i); 1287 | } 1288 | 1289 | return totalCount; 1290 | } 1291 | 1292 | private static int ConvertFormatToSize(UnityEngine.Rendering.VertexAttributeFormat format) { 1293 | switch (format) { 1294 | case UnityEngine.Rendering.VertexAttributeFormat.Float32: 1295 | case UnityEngine.Rendering.VertexAttributeFormat.UInt32: 1296 | case UnityEngine.Rendering.VertexAttributeFormat.SInt32: 1297 | return 4; 1298 | 1299 | case UnityEngine.Rendering.VertexAttributeFormat.Float16: 1300 | case UnityEngine.Rendering.VertexAttributeFormat.UNorm16: 1301 | case UnityEngine.Rendering.VertexAttributeFormat.SNorm16: 1302 | case UnityEngine.Rendering.VertexAttributeFormat.UInt16: 1303 | case UnityEngine.Rendering.VertexAttributeFormat.SInt16: 1304 | return 2; 1305 | 1306 | case UnityEngine.Rendering.VertexAttributeFormat.UNorm8: 1307 | case UnityEngine.Rendering.VertexAttributeFormat.SNorm8: 1308 | case UnityEngine.Rendering.VertexAttributeFormat.UInt8: 1309 | case UnityEngine.Rendering.VertexAttributeFormat.SInt8: 1310 | return 1; 1311 | 1312 | default: 1313 | throw new System.ArgumentOutOfRangeException(nameof(format), format, $"Unknown vertex format {format}"); 1314 | } 1315 | } 1316 | 1317 | } 1318 | #endregion 1319 | 1320 | } 1321 | -------------------------------------------------------------------------------- /Editor/ResourceCollector.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 0d7367b88635b4b37a21a2212913f85b 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Alex Silaev 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /LICENSE.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: ce12a0be82ad0466993ffc9b6c16eb04 3 | DefaultImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ME.ResourceCollector 2 | 3 | 4 |

ME.ResourceCollector - it's a simple tool to measure assets and gather dependencies to avoid AssetBundle/Addressables duplicates.

5 | 6 | [![License: MIT](https://img.shields.io/badge/License-MIT-brightgreen.svg)](https://github.com/chromealex/ecs/blob/master/LICENSE) 7 | 8 |
9 |
10 |
11 |
12 | 13 | ## Install 14 | 15 | ### Using submodule 16 | 17 | Add as a submodule this repository https://github.com/chromealex/ME.ResourceCollector and choose target directory ```Assets/ME.ResourceCollector```. 18 | 19 | ### Using Unity Package Manager 20 | 21 | 1. Open Packages/manifest.json file. 22 | 2. Add ```ME.ResourceCollector``` to your dependencies section: 23 | ``` 24 | { 25 | "dependencies": { 26 | [HERE ARE OTHER PACKAGES] 27 | "com.me.resourcecollector": "https://github.com/chromealex/ME.ResourceCollector.git" 28 | } 29 | } 30 | ``` 31 | 32 | ## Run 33 | 34 | Choose ```Tools/ME.ResourceCollector/Update Resources``` menu to collect assets data.
35 | If you want to recalculate all asset sizes, choose ```Tools/ME.ResourceCollector/Recalculate Resource Sizes``` menu. 36 | -------------------------------------------------------------------------------- /README.md.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 9e909c18cb79147c6858440c2676e673 3 | TextScriptImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "com.me.resourcecollector", 3 | "version": "1.0.0", 4 | "displayName": "ME.ResourceCollector", 5 | "description": "ME.ResourceCollector - it's a simple tool to measure assets and gather dependencies to avoid AssetBundle/Addressables duplicates.", 6 | "unity": "2020.3", 7 | "dependencies": {}, 8 | "scopedRegistries": [ 9 | { 10 | "name": "General", 11 | "url": "https://github.com/chromealex/ME.ResourceCollector.git", 12 | "scopes": [ 13 | "com.me.resourcecollector" 14 | ] 15 | } 16 | ], 17 | "keywords": [ 18 | "unity", 19 | "resources", 20 | "addressables", 21 | "bundles", 22 | "memory", 23 | "editor", 24 | "profiling" 25 | ], 26 | "author": { 27 | "name": "Alex Silaev", 28 | "email": "chrome.alex@gmail.com" 29 | } 30 | } -------------------------------------------------------------------------------- /package.json.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 763a802d26eee4137bf2ab9b785ada42 3 | TextScriptImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | --------------------------------------------------------------------------------