unity 自动删除未引用的Assets下的资源
随着时间的堆积,项目中Assets文件夹下的资源会变得越来越繁杂,有些贴图、材质啥的可能压根没有使用过,但是又不敢轻易去删除。
这里分享两个插件,用于管理这些资源。
一、ResourceChecker
这个插件的强大之处就在于它能够查找当前场景中的所有引用个资源,并快速定位,然后把未定位到的资源手动删掉就行了。
代码
1 // Resource Checker 2 // (c) 2012 Simon Oliver / HandCircus / hello@handcircus.com 3 // (c) 2015 Brice Clocher / Mangatome / hello@mangatome.net 4 // Public domain, do with whatever you like, commercial or not 5 // This comes with no warranty, use at your own risk! 6 // https://github.com/handcircus/Unity-Resource-Checker 7 8 using System; 9 using System.Linq; 10 using UnityEngine; 11 using UnityEngine.UI; 12 using UnityEditor; 13 using System.Collections.Generic; 14 using System.Reflection; 15 using Object = UnityEngine.Object; 16 17 public class TextureDetails : IEquatable<TextureDetails> 18 { 19 public bool isCubeMap; 20 public int memSizeKB; 21 public Texture texture; 22 public TextureFormat format; 23 public int mipMapCount; 24 public List<Object> FoundInMaterials=new List<Object>(); 25 public List<Object> FoundInRenderers=new List<Object>(); 26 public List<Object> FoundInAnimators = new List<Object>(); 27 public List<Object> FoundInScripts = new List<Object>(); 28 public List<Object> FoundInGraphics = new List<Object>(); 29 public bool isSky; 30 public bool instance; 31 public bool isgui; 32 public TextureDetails() 33 { 34 35 } 36 37 public bool Equals(TextureDetails other) 38 { 39 return texture != null && other.texture != null && 40 texture.GetNativeTexturePtr() == other.texture.GetNativeTexturePtr(); 41 } 42 43 public override int GetHashCode() 44 { 45 return (int)texture.GetNativeTexturePtr(); 46 } 47 48 public override bool Equals(object obj) 49 { 50 return Equals(obj as TextureDetails); 51 } 52 }; 53 54 public class MaterialDetails 55 { 56 57 public Material material; 58 59 public List<Renderer> FoundInRenderers=new List<Renderer>(); 60 public List<Graphic> FoundInGraphics=new List<Graphic>(); 61 public bool instance; 62 public bool isgui; 63 public bool isSky; 64 65 public MaterialDetails() 66 { 67 instance = false; 68 isgui = false; 69 isSky = false; 70 } 71 }; 72 73 public class MeshDetails 74 { 75 76 public Mesh mesh; 77 78 public List<MeshFilter> FoundInMeshFilters=new List<MeshFilter>(); 79 public List<SkinnedMeshRenderer> FoundInSkinnedMeshRenderer=new List<SkinnedMeshRenderer>(); 80 public bool instance; 81 82 public MeshDetails() 83 { 84 instance = false; 85 } 86 }; 87 88 public class MissingGraphic{ 89 public Transform Object; 90 public string type; 91 public string name; 92 } 93 94 public class ResourceChecker : EditorWindow { 95 96 97 string[] inspectToolbarStrings = {"Textures", "Materials","Meshes"}; 98 string[] inspectToolbarStrings2 = {"Textures", "Materials","Meshes", "Missing"}; 99 100 enum InspectType 101 { 102 Textures,Materials,Meshes,Missing 103 }; 104 105 bool IncludeDisabledObjects=true; 106 bool IncludeSpriteAnimations=true; 107 bool IncludeScriptReferences=true; 108 bool IncludeGuiElements=true; 109 bool thingsMissing = false; 110 111 InspectType ActiveInspectType=InspectType.Textures; 112 113 float ThumbnailWidth=40; 114 float ThumbnailHeight=40; 115 116 List<TextureDetails> ActiveTextures=new List<TextureDetails>(); 117 List<MaterialDetails> ActiveMaterials=new List<MaterialDetails>(); 118 List<MeshDetails> ActiveMeshDetails=new List<MeshDetails>(); 119 List<MissingGraphic> MissingObjects = new List<MissingGraphic> (); 120 121 Vector2 textureListScrollPos=new Vector2(0,0); 122 Vector2 materialListScrollPos=new Vector2(0,0); 123 Vector2 meshListScrollPos=new Vector2(0,0); 124 Vector2 missingListScrollPos = new Vector2 (0,0); 125 126 int TotalTextureMemory=0; 127 int TotalMeshVertices=0; 128 129 bool ctrlPressed=false; 130 131 static int MinWidth=475; 132 Color defColor; 133 134 bool collectedInPlayingMode; 135 136 [MenuItem ("Window/Resource Checker")] 137 static void Init () 138 { 139 ResourceChecker window = (ResourceChecker) EditorWindow.GetWindow (typeof (ResourceChecker)); 140 window.CheckResources(); 141 window.minSize=new Vector2(MinWidth,475); 142 } 143 144 void OnGUI () 145 { 146 defColor = GUI.color; 147 IncludeDisabledObjects = GUILayout.Toggle(IncludeDisabledObjects, "Include disabled objects", GUILayout.Width(300)); 148 IncludeSpriteAnimations = GUILayout.Toggle(IncludeSpriteAnimations, "Look in sprite animations", GUILayout.Width(300)); 149 GUI.color = new Color (0.8f, 0.8f, 1.0f, 1.0f); 150 IncludeScriptReferences = GUILayout.Toggle(IncludeScriptReferences, "Look in behavior fields", GUILayout.Width(300)); 151 GUI.color = new Color (1.0f, 0.95f, 0.8f, 1.0f); 152 IncludeGuiElements = GUILayout.Toggle(IncludeGuiElements, "Look in GUI elements", GUILayout.Width(300)); 153 GUI.color = defColor; 154 GUILayout.BeginArea(new Rect(position.width-85,5,100,65)); 155 if (GUILayout.Button("Calculate",GUILayout.Width(80), GUILayout.Height(40))) 156 CheckResources(); 157 if (GUILayout.Button("CleanUp",GUILayout.Width(80), GUILayout.Height(20))) 158 Resources.UnloadUnusedAssets(); 159 GUILayout.EndArea(); 160 RemoveDestroyedResources(); 161 162 GUILayout.Space(30); 163 if (thingsMissing == true) { 164 EditorGUI.HelpBox (new Rect(8,75,300,25),"Some GameObjects are missing graphical elements.", MessageType.Error); 165 } 166 GUILayout.BeginHorizontal(); 167 GUILayout.Label("Textures "+ActiveTextures.Count+" - "+FormatSizeString(TotalTextureMemory)); 168 GUILayout.Label("Materials "+ActiveMaterials.Count); 169 GUILayout.Label("Meshes "+ActiveMeshDetails.Count+" - "+TotalMeshVertices+" verts"); 170 GUILayout.EndHorizontal(); 171 if (thingsMissing == true) { 172 ActiveInspectType = (InspectType)GUILayout.Toolbar ((int)ActiveInspectType, inspectToolbarStrings2); 173 } else { 174 ActiveInspectType = (InspectType)GUILayout.Toolbar ((int)ActiveInspectType, inspectToolbarStrings); 175 } 176 177 ctrlPressed=Event.current.control || Event.current.command; 178 179 switch (ActiveInspectType) 180 { 181 case InspectType.Textures: 182 ListTextures(); 183 break; 184 case InspectType.Materials: 185 ListMaterials(); 186 break; 187 case InspectType.Meshes: 188 ListMeshes(); 189 break; 190 case InspectType.Missing: 191 ListMissing(); 192 break; 193 } 194 } 195 196 private void RemoveDestroyedResources() 197 { 198 if (collectedInPlayingMode != Application.isPlaying) 199 { 200 ActiveTextures.Clear(); 201 ActiveMaterials.Clear(); 202 ActiveMeshDetails.Clear(); 203 MissingObjects.Clear (); 204 thingsMissing = false; 205 collectedInPlayingMode = Application.isPlaying; 206 } 207 208 ActiveTextures.RemoveAll(x => !x.texture); 209 ActiveTextures.ForEach(delegate(TextureDetails obj) { 210 obj.FoundInAnimators.RemoveAll(x => !x); 211 obj.FoundInMaterials.RemoveAll(x => !x); 212 obj.FoundInRenderers.RemoveAll(x => !x); 213 obj.FoundInScripts.RemoveAll(x => !x); 214 obj.FoundInGraphics.RemoveAll(x => !x); 215 }); 216 217 ActiveMaterials.RemoveAll(x => !x.material); 218 ActiveMaterials.ForEach(delegate(MaterialDetails obj) { 219 obj.FoundInRenderers.RemoveAll(x => !x); 220 obj.FoundInGraphics.RemoveAll(x => !x); 221 }); 222 223 ActiveMeshDetails.RemoveAll(x => !x.mesh); 224 ActiveMeshDetails.ForEach(delegate(MeshDetails obj) { 225 obj.FoundInMeshFilters.RemoveAll(x => !x); 226 obj.FoundInSkinnedMeshRenderer.RemoveAll(x => !x); 227 }); 228 229 TotalTextureMemory = 0; 230 foreach (TextureDetails tTextureDetails in ActiveTextures) TotalTextureMemory += tTextureDetails.memSizeKB; 231 232 TotalMeshVertices = 0; 233 foreach (MeshDetails tMeshDetails in ActiveMeshDetails) TotalMeshVertices += tMeshDetails.mesh.vertexCount; 234 } 235 236 int GetBitsPerPixel(TextureFormat format) 237 { 238 switch (format) 239 { 240 case TextureFormat.Alpha8: // Alpha-only texture format. 241 return 8; 242 case TextureFormat.ARGB4444: // A 16 bits/pixel texture format. Texture stores color with an alpha channel. 243 return 16; 244 case TextureFormat.RGBA4444: // A 16 bits/pixel texture format. 245 return 16; 246 case TextureFormat.RGB24: // A color texture format. 247 return 24; 248 case TextureFormat.RGBA32: //Color with an alpha channel texture format. 249 return 32; 250 case TextureFormat.ARGB32: //Color with an alpha channel texture format. 251 return 32; 252 case TextureFormat.RGB565: // A 16 bit color texture format. 253 return 16; 254 case TextureFormat.DXT1: // Compressed color texture format. 255 return 4; 256 case TextureFormat.DXT5: // Compressed color with alpha channel texture format. 257 return 8; 258 /* 259 case TextureFormat.WiiI4: // Wii texture format. 260 case TextureFormat.WiiI8: // Wii texture format. Intensity 8 bit. 261 case TextureFormat.WiiIA4: // Wii texture format. Intensity + Alpha 8 bit (4 + 4). 262 case TextureFormat.WiiIA8: // Wii texture format. Intensity + Alpha 16 bit (8 + 8). 263 case TextureFormat.WiiRGB565: // Wii texture format. RGB 16 bit (565). 264 case TextureFormat.WiiRGB5A3: // Wii texture format. RGBA 16 bit (4443). 265 case TextureFormat.WiiRGBA8: // Wii texture format. RGBA 32 bit (8888). 266 case TextureFormat.WiiCMPR: // Compressed Wii texture format. 4 bits/texel, ~RGB8A1 (Outline alpha is not currently supported). 267 return 0; //Not supported yet 268 */ 269 case TextureFormat.PVRTC_RGB2:// PowerVR (iOS) 2 bits/pixel compressed color texture format. 270 return 2; 271 case TextureFormat.PVRTC_RGBA2:// PowerVR (iOS) 2 bits/pixel compressed with alpha channel texture format 272 return 2; 273 case TextureFormat.PVRTC_RGB4:// PowerVR (iOS) 4 bits/pixel compressed color texture format. 274 return 4; 275 case TextureFormat.PVRTC_RGBA4:// PowerVR (iOS) 4 bits/pixel compressed with alpha channel texture format 276 return 4; 277 case TextureFormat.ETC_RGB4:// ETC (GLES2.0) 4 bits/pixel compressed RGB texture format. 278 return 4; 279 case TextureFormat.ATC_RGB4:// ATC (ATITC) 4 bits/pixel compressed RGB texture format. 280 return 4; 281 case TextureFormat.ATC_RGBA8:// ATC (ATITC) 8 bits/pixel compressed RGB texture format. 282 return 8; 283 case TextureFormat.BGRA32:// Format returned by iPhone camera 284 return 32; 285 #if !UNITY_5 && !UNITY_5_3_OR_NEWER 286 case TextureFormat.ATF_RGB_DXT1:// Flash-specific RGB DXT1 compressed color texture format. 287 case TextureFormat.ATF_RGBA_JPG:// Flash-specific RGBA JPG-compressed color texture format. 288 case TextureFormat.ATF_RGB_JPG:// Flash-specific RGB JPG-compressed color texture format. 289 return 0; //Not supported yet 290 #endif 291 } 292 return 0; 293 } 294 295 int CalculateTextureSizeBytes(Texture tTexture) 296 { 297 298 int tWidth=tTexture.width; 299 int tHeight=tTexture.height; 300 if (tTexture is Texture2D) 301 { 302 Texture2D tTex2D=tTexture as Texture2D; 303 int bitsPerPixel=GetBitsPerPixel(tTex2D.format); 304 int mipMapCount=tTex2D.mipmapCount; 305 int mipLevel=1; 306 int tSize=0; 307 while (mipLevel<=mipMapCount) 308 { 309 tSize+=tWidth*tHeight*bitsPerPixel/8; 310 tWidth=tWidth/2; 311 tHeight=tHeight/2; 312 mipLevel++; 313 } 314 return tSize; 315 } 316 if (tTexture is Texture2DArray) 317 { 318 Texture2DArray tTex2D=tTexture as Texture2DArray; 319 int bitsPerPixel=GetBitsPerPixel(tTex2D.format); 320 int mipMapCount=10; 321 int mipLevel=1; 322 int tSize=0; 323 while (mipLevel<=mipMapCount) 324 { 325 tSize+=tWidth*tHeight*bitsPerPixel/8; 326 tWidth=tWidth/2; 327 tHeight=tHeight/2; 328 mipLevel++; 329 } 330 return tSize*((Texture2DArray)tTex2D).depth; 331 } 332 if (tTexture is Cubemap) { 333 Cubemap tCubemap = tTexture as Cubemap; 334 int bitsPerPixel = GetBitsPerPixel (tCubemap.format); 335 return tWidth * tHeight * 6 * bitsPerPixel / 8; 336 } 337 return 0; 338 } 339 340 341 void SelectObject(Object selectedObject,bool append) 342 { 343 if (append) 344 { 345 List<Object> currentSelection=new List<Object>(Selection.objects); 346 // Allow toggle selection 347 if (currentSelection.Contains(selectedObject)) currentSelection.Remove(selectedObject); 348 else currentSelection.Add(selectedObject); 349 350 Selection.objects=currentSelection.ToArray(); 351 } 352 else Selection.activeObject=selectedObject; 353 } 354 355 void SelectObjects(List<Object> selectedObjects,bool append) 356 { 357 if (append) 358 { 359 List<Object> currentSelection=new List<Object>(Selection.objects); 360 currentSelection.AddRange(selectedObjects); 361 Selection.objects=currentSelection.ToArray(); 362 } 363 else Selection.objects=selectedObjects.ToArray(); 364 } 365 366 void ListTextures() 367 { 368 textureListScrollPos = EditorGUILayout.BeginScrollView(textureListScrollPos); 369 370 foreach (TextureDetails tDetails in ActiveTextures) 371 { 372 373 GUILayout.BeginHorizontal (); 374 Texture tex = new Texture(); 375 tex = tDetails.texture; 376 if(tDetails.texture.GetType() == typeof(Texture2DArray) || tDetails.texture.GetType() == typeof(Cubemap)){ 377 tex = AssetPreview.GetMiniThumbnail(tDetails.texture); 378 } 379 GUILayout.Box(tex, GUILayout.Width(ThumbnailWidth), GUILayout.Height(ThumbnailHeight)); 380 381 if (tDetails.instance == true) 382 GUI.color = new Color (0.8f, 0.8f, defColor.b, 1.0f); 383 if (tDetails.isgui == true) 384 GUI.color = new Color (defColor.r, 0.95f, 0.8f, 1.0f); 385 if (tDetails.isSky) 386 GUI.color = new Color (0.9f, defColor.g, defColor.b, 1.0f); 387 if(GUILayout.Button(tDetails.texture.name,GUILayout.Width(150))) 388 { 389 SelectObject(tDetails.texture,ctrlPressed); 390 } 391 GUI.color = defColor; 392 393 string sizeLabel=""+tDetails.texture.width+"x"+tDetails.texture.height; 394 if (tDetails.isCubeMap) sizeLabel+="x6"; 395 if (tDetails.texture.GetType () == typeof(Texture2DArray)) 396 sizeLabel+= "[]\n" + ((Texture2DArray)tDetails.texture).depth+"depths"; 397 sizeLabel+=" - "+tDetails.mipMapCount+"mip\n"+FormatSizeString(tDetails.memSizeKB)+" - "+tDetails.format; 398 399 GUILayout.Label (sizeLabel,GUILayout.Width(120)); 400 401 if(GUILayout.Button(tDetails.FoundInMaterials.Count+" Mat",GUILayout.Width(50))) 402 { 403 SelectObjects(tDetails.FoundInMaterials,ctrlPressed); 404 } 405 406 HashSet<Object> FoundObjects = new HashSet<Object>(); 407 foreach (Renderer renderer in tDetails.FoundInRenderers) FoundObjects.Add(renderer.gameObject); 408 foreach (Animator animator in tDetails.FoundInAnimators) FoundObjects.Add(animator.gameObject); 409 foreach (Graphic graphic in tDetails.FoundInGraphics) FoundObjects.Add(graphic.gameObject); 410 foreach (MonoBehaviour script in tDetails.FoundInScripts) FoundObjects.Add(script.gameObject); 411 if (GUILayout.Button(FoundObjects.Count+" GO",GUILayout.Width(50))) 412 { 413 SelectObjects(new List<Object>(FoundObjects),ctrlPressed); 414 } 415 416 GUILayout.EndHorizontal(); 417 } 418 if (ActiveTextures.Count>0) 419 { 420 EditorGUILayout.Space(); 421 GUILayout.BeginHorizontal (); 422 //GUILayout.Box(" ",GUILayout.Width(ThumbnailWidth),GUILayout.Height(ThumbnailHeight)); 423 if(GUILayout.Button("Select \n All",GUILayout.Width(ThumbnailWidth*2))) 424 { 425 List<Object> AllTextures=new List<Object>(); 426 foreach (TextureDetails tDetails in ActiveTextures) AllTextures.Add(tDetails.texture); 427 SelectObjects(AllTextures,ctrlPressed); 428 } 429 EditorGUILayout.EndHorizontal(); 430 } 431 EditorGUILayout.EndScrollView(); 432 } 433 434 void ListMaterials() 435 { 436 materialListScrollPos = EditorGUILayout.BeginScrollView(materialListScrollPos); 437 438 foreach (MaterialDetails tDetails in ActiveMaterials) 439 { 440 if (tDetails.material!=null) 441 { 442 GUILayout.BeginHorizontal (); 443 444 GUILayout.Box(AssetPreview.GetAssetPreview(tDetails.material), GUILayout.Width(ThumbnailWidth), GUILayout.Height(ThumbnailHeight)); 445 446 if (tDetails.instance == true) 447 GUI.color = new Color (0.8f, 0.8f, defColor.b, 1.0f); 448 if (tDetails.isgui == true) 449 GUI.color = new Color (defColor.r, 0.95f, 0.8f, 1.0f); 450 if (tDetails.isSky) 451 GUI.color = new Color (0.9f, defColor.g, defColor.b, 1.0f); 452 if(GUILayout.Button(tDetails.material.name,GUILayout.Width(150))) 453 { 454 SelectObject(tDetails.material,ctrlPressed); 455 } 456 GUI.color = defColor; 457 458 string shaderLabel = tDetails.material.shader != null ? tDetails.material.shader.name : "no shader"; 459 GUILayout.Label (shaderLabel, GUILayout.Width(200)); 460 461 if(GUILayout.Button((tDetails.FoundInRenderers.Count + tDetails.FoundInGraphics.Count) +" GO",GUILayout.Width(50))) 462 { 463 List<Object> FoundObjects=new List<Object>(); 464 foreach (Renderer renderer in tDetails.FoundInRenderers) FoundObjects.Add(renderer.gameObject); 465 foreach (Graphic graphic in tDetails.FoundInGraphics) FoundObjects.Add(graphic.gameObject); 466 SelectObjects(FoundObjects,ctrlPressed); 467 } 468 469 470 GUILayout.EndHorizontal(); 471 } 472 } 473 EditorGUILayout.EndScrollView(); 474 } 475 476 void ListMeshes() 477 { 478 meshListScrollPos = EditorGUILayout.BeginScrollView(meshListScrollPos); 479 480 foreach (MeshDetails tDetails in ActiveMeshDetails) 481 { 482 if (tDetails.mesh!=null) 483 { 484 GUILayout.BeginHorizontal (); 485 string name = tDetails.mesh.name; 486 if (name == null || name.Count() < 1) 487 name = tDetails.FoundInMeshFilters[0].gameObject.name; 488 if (tDetails.instance == true) 489 GUI.color = new Color (0.8f, 0.8f, defColor.b, 1.0f); 490 if(GUILayout.Button(name,GUILayout.Width(150))) 491 { 492 SelectObject(tDetails.mesh,ctrlPressed); 493 } 494 GUI.color = defColor; 495 string sizeLabel=""+tDetails.mesh.vertexCount+" vert"; 496 497 GUILayout.Label (sizeLabel,GUILayout.Width(100)); 498 499 500 if(GUILayout.Button(tDetails.FoundInMeshFilters.Count + " GO",GUILayout.Width(50))) 501 { 502 List<Object> FoundObjects=new List<Object>(); 503 foreach (MeshFilter meshFilter in tDetails.FoundInMeshFilters) FoundObjects.Add(meshFilter.gameObject); 504 SelectObjects(FoundObjects,ctrlPressed); 505 } 506 if (tDetails.FoundInSkinnedMeshRenderer.Count > 0) { 507 if (GUILayout.Button (tDetails.FoundInSkinnedMeshRenderer.Count + " skinned mesh GO", GUILayout.Width (140))) { 508 List<Object> FoundObjects = new List<Object> (); 509 foreach (SkinnedMeshRenderer skinnedMeshRenderer in tDetails.FoundInSkinnedMeshRenderer) 510 FoundObjects.Add (skinnedMeshRenderer.gameObject); 511 SelectObjects (FoundObjects, ctrlPressed); 512 } 513 } else { 514 GUI.color = new Color (defColor.r, defColor.g, defColor.b, 0.5f); 515 GUILayout.Label(" 0 skinned mesh"); 516 GUI.color = defColor; 517 } 518 519 520 GUILayout.EndHorizontal(); 521 } 522 } 523 EditorGUILayout.EndScrollView(); 524 } 525 526 void ListMissing(){ 527 missingListScrollPos = EditorGUILayout.BeginScrollView(missingListScrollPos); 528 foreach (MissingGraphic dMissing in MissingObjects) { 529 GUILayout.BeginHorizontal (); 530 if (GUILayout.Button (dMissing.name, GUILayout.Width (150))) 531 SelectObject (dMissing.Object, ctrlPressed); 532 GUILayout.Label ("missing ", GUILayout.Width(48)); 533 switch (dMissing.type) { 534 case "mesh": 535 GUI.color = new Color (0.8f, 0.8f, defColor.b, 1.0f); 536 break; 537 case "sprite": 538 GUI.color = new Color (defColor.r, 0.8f, 0.8f, 1.0f); 539 break; 540 case "material": 541 GUI.color = new Color (0.8f, defColor.g, 0.8f, 1.0f); 542 break; 543 } 544 GUILayout.Label (dMissing.type); 545 GUI.color = defColor; 546 GUILayout.EndHorizontal (); 547 } 548 EditorGUILayout.EndScrollView(); 549 } 550 551 string FormatSizeString(int memSizeKB) 552 { 553 if (memSizeKB<1024) return ""+memSizeKB+"k"; 554 else 555 { 556 float memSizeMB=((float)memSizeKB)/1024.0f; 557 return memSizeMB.ToString("0.00")+"Mb"; 558 } 559 } 560 561 562 TextureDetails FindTextureDetails(Texture tTexture) 563 { 564 foreach (TextureDetails tTextureDetails in ActiveTextures) 565 { 566 if (tTextureDetails.texture==tTexture) return tTextureDetails; 567 } 568 return null; 569 570 } 571 572 MaterialDetails FindMaterialDetails(Material tMaterial) 573 { 574 foreach (MaterialDetails tMaterialDetails in ActiveMaterials) 575 { 576 if (tMaterialDetails.material==tMaterial) return tMaterialDetails; 577 } 578 return null; 579 580 } 581 582 MeshDetails FindMeshDetails(Mesh tMesh) 583 { 584 foreach (MeshDetails tMeshDetails in ActiveMeshDetails) 585 { 586 if (tMeshDetails.mesh==tMesh) return tMeshDetails; 587 } 588 return null; 589 590 } 591 592 593 void CheckResources() 594 { 595 ActiveTextures.Clear(); 596 ActiveMaterials.Clear(); 597 ActiveMeshDetails.Clear(); 598 MissingObjects.Clear (); 599 thingsMissing = false; 600 601 Renderer[] renderers = FindObjects<Renderer>(); 602 603 MaterialDetails skyMat = new MaterialDetails (); 604 skyMat.material = RenderSettings.skybox; 605 skyMat.isSky = true; 606 ActiveMaterials.Add (skyMat); 607 608 //Debug.Log("Total renderers "+renderers.Length); 609 foreach (Renderer renderer in renderers) 610 { 611 //Debug.Log("Renderer is "+renderer.name); 612 foreach (Material material in renderer.sharedMaterials) 613 { 614 615 MaterialDetails tMaterialDetails = FindMaterialDetails(material); 616 if (tMaterialDetails == null) 617 { 618 tMaterialDetails = new MaterialDetails(); 619 tMaterialDetails.material = material; 620 ActiveMaterials.Add(tMaterialDetails); 621 } 622 tMaterialDetails.FoundInRenderers.Add(renderer); 623 } 624 625 if (renderer is SpriteRenderer) 626 { 627 SpriteRenderer tSpriteRenderer = (SpriteRenderer)renderer; 628 629 if (tSpriteRenderer.sprite != null) { 630 var tSpriteTextureDetail = GetTextureDetail (tSpriteRenderer.sprite.texture, renderer); 631 if (!ActiveTextures.Contains (tSpriteTextureDetail)) { 632 ActiveTextures.Add (tSpriteTextureDetail); 633 } 634 } else if (tSpriteRenderer.sprite == null) { 635 MissingGraphic tMissing = new MissingGraphic (); 636 tMissing.Object = tSpriteRenderer.transform; 637 tMissing.type = "sprite"; 638 tMissing.name = tSpriteRenderer.transform.name; 639 MissingObjects.Add (tMissing); 640 thingsMissing = true; 641 } 642 } 643 } 644 645 if (IncludeGuiElements) 646 { 647 Graphic[] graphics = FindObjects<Graphic>(); 648 649 foreach(Graphic graphic in graphics) 650 { 651 if (graphic.mainTexture) 652 { 653 var tSpriteTextureDetail = GetTextureDetail(graphic.mainTexture, graphic); 654 if (!ActiveTextures.Contains(tSpriteTextureDetail)) 655 { 656 ActiveTextures.Add(tSpriteTextureDetail); 657 } 658 } 659 660 if (graphic.materialForRendering) 661 { 662 MaterialDetails tMaterialDetails = FindMaterialDetails(graphic.materialForRendering); 663 if (tMaterialDetails == null) 664 { 665 tMaterialDetails = new MaterialDetails(); 666 tMaterialDetails.material = graphic.materialForRendering; 667 tMaterialDetails.isgui = true; 668 ActiveMaterials.Add(tMaterialDetails); 669 } 670 tMaterialDetails.FoundInGraphics.Add(graphic); 671 } 672 } 673 } 674 675 foreach (MaterialDetails tMaterialDetails in ActiveMaterials) 676 { 677 Material tMaterial = tMaterialDetails.material; 678 if (tMaterial != null) 679 { 680 var dependencies = EditorUtility.CollectDependencies(new UnityEngine.Object[] { tMaterial }); 681 foreach (Object obj in dependencies) 682 { 683 if (obj is Texture) 684 { 685 Texture tTexture = obj as Texture; 686 var tTextureDetail = GetTextureDetail(tTexture, tMaterial, tMaterialDetails); 687 tTextureDetail.isSky = tMaterialDetails.isSky; 688 tTextureDetail.instance = tMaterialDetails.instance; 689 tTextureDetail.isgui = tMaterialDetails.isgui; 690 ActiveTextures.Add(tTextureDetail); 691 } 692 } 693 694 //if the texture was downloaded, it won't be included in the editor dependencies 695 if (tMaterial.HasProperty ("_MainTex")) { 696 if (tMaterial.mainTexture != null && !dependencies.Contains (tMaterial.mainTexture)) { 697 var tTextureDetail = GetTextureDetail (tMaterial.mainTexture, tMaterial, tMaterialDetails); 698 ActiveTextures.Add (tTextureDetail); 699 } 700 } 701 } 702 } 703 704 705 MeshFilter[] meshFilters = FindObjects<MeshFilter>(); 706 707 foreach (MeshFilter tMeshFilter in meshFilters) 708 { 709 Mesh tMesh = tMeshFilter.sharedMesh; 710 if (tMesh != null) 711 { 712 MeshDetails tMeshDetails = FindMeshDetails(tMesh); 713 if (tMeshDetails == null) 714 { 715 tMeshDetails = new MeshDetails(); 716 tMeshDetails.mesh = tMesh; 717 ActiveMeshDetails.Add(tMeshDetails); 718 } 719 tMeshDetails.FoundInMeshFilters.Add(tMeshFilter); 720 } else if (tMesh == null && tMeshFilter.transform.GetComponent("TextContainer")== null) { 721 MissingGraphic tMissing = new MissingGraphic (); 722 tMissing.Object = tMeshFilter.transform; 723 tMissing.type = "mesh"; 724 tMissing.name = tMeshFilter.transform.name; 725 MissingObjects.Add (tMissing); 726 thingsMissing = true; 727 } 728 729 var meshRenderrer = tMeshFilter.transform.GetComponent<MeshRenderer>(); 730 731 if (meshRenderrer == null || meshRenderrer.sharedMaterial == null) { 732 MissingGraphic tMissing = new MissingGraphic (); 733 tMissing.Object = tMeshFilter.transform; 734 tMissing.type = "material"; 735 tMissing.name = tMeshFilter.transform.name; 736 MissingObjects.Add (tMissing); 737 thingsMissing = true; 738 } 739 } 740 741 SkinnedMeshRenderer[] skinnedMeshRenderers = FindObjects<SkinnedMeshRenderer>(); 742 743 foreach (SkinnedMeshRenderer tSkinnedMeshRenderer in skinnedMeshRenderers) 744 { 745 Mesh tMesh = tSkinnedMeshRenderer.sharedMesh; 746 if (tMesh != null) 747 { 748 MeshDetails tMeshDetails = FindMeshDetails(tMesh); 749 if (tMeshDetails == null) 750 { 751 tMeshDetails = new MeshDetails(); 752 tMeshDetails.mesh = tMesh; 753 ActiveMeshDetails.Add(tMeshDetails); 754 } 755 tMeshDetails.FoundInSkinnedMeshRenderer.Add(tSkinnedMeshRenderer); 756 } else if (tMesh == null) { 757 MissingGraphic tMissing = new MissingGraphic (); 758 tMissing.Object = tSkinnedMeshRenderer.transform; 759 tMissing.type = "mesh"; 760 tMissing.name = tSkinnedMeshRenderer.transform.name; 761 MissingObjects.Add (tMissing); 762 thingsMissing = true; 763 } 764 if (tSkinnedMeshRenderer.sharedMaterial == null) { 765 MissingGraphic tMissing = new MissingGraphic (); 766 tMissing.Object = tSkinnedMeshRenderer.transform; 767 tMissing.type = "material"; 768 tMissing.name = tSkinnedMeshRenderer.transform.name; 769 MissingObjects.Add (tMissing); 770 thingsMissing = true; 771 } 772 } 773 774 if (IncludeSpriteAnimations) 775 { 776 Animator[] animators = FindObjects<Animator>(); 777 foreach (Animator anim in animators) 778 { 779 #if UNITY_4_6 || UNITY_4_5 || UNITY_4_4 || UNITY_4_3 780 UnityEditorInternal.AnimatorController ac = anim.runtimeAnimatorController as UnityEditorInternal.AnimatorController; 781 #elif UNITY_5 || UNITY_5_3_OR_NEWER 782 UnityEditor.Animations.AnimatorController ac = anim.runtimeAnimatorController as UnityEditor.Animations.AnimatorController; 783 #endif 784 785 //Skip animators without layers, this can happen if they don't have an animator controller. 786 if (!ac || ac.layers == null || ac.layers.Length == 0) 787 continue; 788 789 for (int x = 0; x < anim.layerCount; x++) 790 { 791 #if UNITY_4_6 || UNITY_4_5 || UNITY_4_4 || UNITY_4_3 792 UnityEditorInternal.StateMachine sm = ac.GetLayer(x).stateMachine; 793 int cnt = sm.stateCount; 794 #elif UNITY_5 || UNITY_5_3_OR_NEWER 795 UnityEditor.Animations.AnimatorStateMachine sm = ac.layers[x].stateMachine; 796 int cnt = sm.states.Length; 797 #endif 798 799 for (int i = 0; i < cnt; i++) 800 { 801 #if UNITY_4_6 || UNITY_4_5 || UNITY_4_4 || UNITY_4_3 802 UnityEditorInternal.State state = sm.GetState(i); 803 Motion m = state.GetMotion(); 804 #elif UNITY_5 || UNITY_5_3_OR_NEWER 805 UnityEditor.Animations.AnimatorState state = sm.states[i].state; 806 Motion m = state.motion; 807 #endif 808 if (m != null) 809 { 810 AnimationClip clip = m as AnimationClip; 811 812 if (clip != null) 813 { 814 EditorCurveBinding[] ecbs = AnimationUtility.GetObjectReferenceCurveBindings(clip); 815 816 foreach (EditorCurveBinding ecb in ecbs) 817 { 818 if (ecb.propertyName == "m_Sprite") 819 { 820 foreach (ObjectReferenceKeyframe keyframe in AnimationUtility.GetObjectReferenceCurve(clip, ecb)) 821 { 822 Sprite tSprite = keyframe.value as Sprite; 823 824 if (tSprite != null) 825 { 826 var tTextureDetail = GetTextureDetail(tSprite.texture, anim); 827 if (!ActiveTextures.Contains(tTextureDetail)) 828 { 829 ActiveTextures.Add(tTextureDetail); 830 } 831 } 832 } 833 } 834 } 835 } 836 } 837 } 838 } 839 840 } 841 } 842 843 if (IncludeScriptReferences) 844 { 845 MonoBehaviour[] scripts = FindObjects<MonoBehaviour>(); 846 foreach (MonoBehaviour script in scripts) 847 { 848 BindingFlags flags = BindingFlags.Public | BindingFlags.Instance; // only public non-static fields are bound to by Unity. 849 FieldInfo[] fields = script.GetType().GetFields(flags); 850 851 foreach (FieldInfo field in fields) 852 { 853 System.Type fieldType = field.FieldType; 854 if (fieldType == typeof(Sprite)) 855 { 856 Sprite tSprite = field.GetValue(script) as Sprite; 857 if (tSprite != null) 858 { 859 var tSpriteTextureDetail = GetTextureDetail(tSprite.texture, script); 860 if (!ActiveTextures.Contains(tSpriteTextureDetail)) 861 { 862 ActiveTextures.Add(tSpriteTextureDetail); 863 } 864 } 865 }if (fieldType == typeof(Mesh)) 866 { 867 Mesh tMesh = field.GetValue(script) as Mesh; 868 if (tMesh != null) 869 { 870 MeshDetails tMeshDetails = FindMeshDetails(tMesh); 871 if (tMeshDetails == null) 872 { 873 tMeshDetails = new MeshDetails(); 874 tMeshDetails.mesh = tMesh; 875 tMeshDetails.instance = true; 876 ActiveMeshDetails.Add(tMeshDetails); 877 } 878 } 879 }if (fieldType == typeof(Material)) 880 { 881 Material tMaterial = field.GetValue(script) as Material; 882 if (tMaterial != null) 883 { 884 MaterialDetails tMatDetails = FindMaterialDetails(tMaterial); 885 if (tMatDetails == null) 886 { 887 tMatDetails = new MaterialDetails(); 888 tMatDetails.instance = true; 889 tMatDetails.material = tMaterial; 890 if(!ActiveMaterials.Contains(tMatDetails)) 891 ActiveMaterials.Add(tMatDetails); 892 } 893 if (tMaterial.mainTexture) 894 { 895 var tSpriteTextureDetail = GetTextureDetail(tMaterial.mainTexture); 896 if (!ActiveTextures.Contains(tSpriteTextureDetail)) 897 { 898 ActiveTextures.Add(tSpriteTextureDetail); 899 } 900 } 901 var dependencies = EditorUtility.CollectDependencies(new UnityEngine.Object[] { tMaterial }); 902 foreach (Object obj in dependencies) 903 { 904 if (obj is Texture) 905 { 906 Texture tTexture = obj as Texture; 907 var tTextureDetail = GetTextureDetail(tTexture, tMaterial, tMatDetails); 908 if(!ActiveTextures.Contains(tTextureDetail)) 909 ActiveTextures.Add(tTextureDetail); 910 } 911 } 912 } 913 } 914 } 915 } 916 } 917 918 TotalTextureMemory = 0; 919 foreach (TextureDetails tTextureDetails in ActiveTextures) TotalTextureMemory += tTextureDetails.memSizeKB; 920 921 TotalMeshVertices = 0; 922 foreach (MeshDetails tMeshDetails in ActiveMeshDetails) TotalMeshVertices += tMeshDetails.mesh.vertexCount; 923 924 // Sort by size, descending 925 ActiveTextures.Sort(delegate(TextureDetails details1, TextureDetails details2) { return details2.memSizeKB - details1.memSizeKB; }); 926 ActiveTextures = ActiveTextures.Distinct().ToList(); 927 ActiveMeshDetails.Sort(delegate(MeshDetails details1, MeshDetails details2) { return details2.mesh.vertexCount - details1.mesh.vertexCount; }); 928 929 collectedInPlayingMode = Application.isPlaying; 930 } 931 932 private static GameObject[] GetAllRootGameObjects() 933 { 934 #if !UNITY_5 && !UNITY_5_3_OR_NEWER 935 return UnityEngine.SceneManagement.SceneManager.GetActiveScene().GetRootGameObjects().ToArray(); 936 #else 937 List<GameObject> allGo = new List<GameObject>(); 938 for (int sceneIdx = 0; sceneIdx < UnityEngine.SceneManagement.SceneManager.sceneCount; ++sceneIdx){ 939 allGo.AddRange( UnityEngine.SceneManagement.SceneManager.GetSceneAt(sceneIdx).GetRootGameObjects().ToArray() ); 940 } 941 return allGo.ToArray(); 942 #endif 943 } 944 945 private T[] FindObjects<T>() where T : Object 946 { 947 if (IncludeDisabledObjects) { 948 List<T> meshfilters = new List<T> (); 949 GameObject[] allGo = GetAllRootGameObjects(); 950 foreach (GameObject go in allGo) { 951 Transform[] tgo = go.GetComponentsInChildren<Transform> (true).ToArray (); 952 foreach (Transform tr in tgo) { 953 if (tr.GetComponent<T> ()) 954 meshfilters.Add (tr.GetComponent<T> ()); 955 } 956 } 957 return (T[])meshfilters.ToArray (); 958 } 959 else 960 return (T[])FindObjectsOfType(typeof(T)); 961 } 962 963 private TextureDetails GetTextureDetail(Texture tTexture, Material tMaterial, MaterialDetails tMaterialDetails) 964 { 965 TextureDetails tTextureDetails = GetTextureDetail(tTexture); 966 967 tTextureDetails.FoundInMaterials.Add(tMaterial); 968 foreach (Renderer renderer in tMaterialDetails.FoundInRenderers) 969 { 970 if (!tTextureDetails.FoundInRenderers.Contains(renderer)) tTextureDetails.FoundInRenderers.Add(renderer); 971 } 972 return tTextureDetails; 973 } 974 975 private TextureDetails GetTextureDetail(Texture tTexture, Renderer renderer) 976 { 977 TextureDetails tTextureDetails = GetTextureDetail(tTexture); 978 979 tTextureDetails.FoundInRenderers.Add(renderer); 980 return tTextureDetails; 981 } 982 983 private TextureDetails GetTextureDetail(Texture tTexture, Animator animator) 984 { 985 TextureDetails tTextureDetails = GetTextureDetail(tTexture); 986 987 tTextureDetails.FoundInAnimators.Add(animator); 988 return tTextureDetails; 989 } 990 991 private TextureDetails GetTextureDetail(Texture tTexture, Graphic graphic) 992 { 993 TextureDetails tTextureDetails = GetTextureDetail(tTexture); 994 995 tTextureDetails.FoundInGraphics.Add(graphic); 996 return tTextureDetails; 997 } 998 999 private TextureDetails GetTextureDetail(Texture tTexture, MonoBehaviour script) 1000 { 1001 TextureDetails tTextureDetails = GetTextureDetail(tTexture); 1002 1003 tTextureDetails.FoundInScripts.Add(script); 1004 return tTextureDetails; 1005 } 1006 1007 private TextureDetails GetTextureDetail(Texture tTexture) 1008 { 1009 TextureDetails tTextureDetails = FindTextureDetails(tTexture); 1010 if (tTextureDetails == null) 1011 { 1012 tTextureDetails = new TextureDetails(); 1013 tTextureDetails.texture = tTexture; 1014 tTextureDetails.isCubeMap = tTexture is Cubemap; 1015 1016 int memSize = CalculateTextureSizeBytes(tTexture); 1017 1018 TextureFormat tFormat = TextureFormat.RGBA32; 1019 int tMipMapCount = 1; 1020 if (tTexture is Texture2D) 1021 { 1022 tFormat = (tTexture as Texture2D).format; 1023 tMipMapCount = (tTexture as Texture2D).mipmapCount; 1024 } 1025 if (tTexture is Cubemap) 1026 { 1027 tFormat = (tTexture as Cubemap).format; 1028 memSize = 8 * tTexture.height * tTexture.width; 1029 } 1030 if(tTexture is Texture2DArray){ 1031 tFormat = (tTexture as Texture2DArray).format; 1032 tMipMapCount = 10; 1033 } 1034 1035 tTextureDetails.memSizeKB = memSize / 1024; 1036 tTextureDetails.format = tFormat; 1037 tTextureDetails.mipMapCount = tMipMapCount; 1038 1039 } 1040 1041 return tTextureDetails; 1042 } 1043 1044 }
下载地址:https://github.com/handcircus/Unity-Resource-Checker
使用:Unity导航菜单栏中选择 Windows -> Resource Checker ,点击即可
二、UnityAssetCleaner
超级diao炸天的插件,强烈推荐使用,有三种清理资源的模式,更重要的是,它把assets下的资源删除后,
自动将删除的文件备份一个package包,这样再也不用担心误删有用的资源啦,误删了,大不了再把package包导进来呗。
代码:
1 /** 2 asset cleaner 3 Copyright (c) 2015 Tatsuhiko Yamamura 4 5 This software is released under the MIT License. 6 http://opensource.org/licenses/mit-license.php 7 */ 8 using UnityEngine; 9 using System.Collections; 10 using System.Collections.Generic; 11 using System.Linq; 12 using UnityEditor; 13 using System.IO; 14 using System.Text.RegularExpressions; 15 16 namespace AssetClean 17 { 18 public class AssetCollector 19 { 20 public List<string> deleteFileList = new List<string> (); 21 ClassReferenceCollection classCollection = new ClassReferenceCollection (); 22 ShaderReferenceCollection shaderCollection = new ShaderReferenceCollection (); 23 24 public bool useCodeStrip = true; 25 public bool saveEditorExtensions = true; 26 27 public void Collection () 28 { 29 try { 30 deleteFileList.Clear (); 31 32 if( useCodeStrip ){ 33 classCollection.Collection (); 34 } 35 shaderCollection.Collection (); 36 37 // Find assets 38 var files = Directory.GetFiles ("Assets", "*.*", SearchOption.AllDirectories) 39 .Where (item => Path.GetExtension (item) != ".meta") 40 .Where (item => Path.GetExtension (item) != ".js") 41 .Where (item => Path.GetExtension (item) != ".dll") 42 .Where (item => Regex.IsMatch (item, "[\\/\\\\]Gizmos[\\/\\\\]") == false) 43 .Where (item => Regex.IsMatch (item, "[\\/\\\\]Plugins[\\/\\\\]Android[\\/\\\\]") == false) 44 .Where (item => Regex.IsMatch (item, "[\\/\\\\]Plugins[\\/\\\\]iOS[\\/\\\\]") == false) 45 .Where (item => Regex.IsMatch (item, "[\\/\\\\]Resources[\\/\\\\]") == false); 46 47 if( useCodeStrip == false ){ 48 files = files.Where( item => Path.GetExtension(item) != ".cs"); 49 } 50 51 foreach (var path in files) { 52 var guid = AssetDatabase.AssetPathToGUID (path); 53 deleteFileList.Add (guid); 54 } 55 EditorUtility.DisplayProgressBar ("checking", "collection all files", 0.2f); 56 UnregistReferenceFromResources(); 57 58 EditorUtility.DisplayProgressBar ("checking", "check reference from resources", 0.4f); 59 UnregistReferenceFromScenes(); 60 61 EditorUtility.DisplayProgressBar ("checking", "check reference from scenes", 0.6f); 62 if( saveEditorExtensions ){ 63 UnregistEditorCodes(); 64 } 65 } finally { 66 EditorUtility.ClearProgressBar (); 67 } 68 } 69 void UnregistReferenceFromResources() 70 { 71 var resourcesFiles = Directory.GetFiles ("Assets", "*.*", SearchOption.AllDirectories) 72 .Where (item => Regex.IsMatch (item, "[\\/\\\\]Resources[\\/\\\\]") == true) 73 .Where (item => Path.GetExtension (item) != ".meta") 74 .ToArray (); 75 foreach (var path in AssetDatabase.GetDependencies (resourcesFiles)) { 76 UnregistFromDelteList (AssetDatabase.AssetPathToGUID(path)); 77 } 78 } 79 80 void UnregistReferenceFromScenes() 81 { 82 // Exclude objects that reference from scenes. 83 var scenes = EditorBuildSettings.scenes 84 .Where (item => item.enabled == true) 85 .Select (item => item.path) 86 .ToArray (); 87 foreach (var path in AssetDatabase.GetDependencies (scenes)) { 88 if( saveEditorExtensions == false ){ 89 Debug.Log(path); 90 } 91 UnregistFromDelteList (AssetDatabase.AssetPathToGUID(path)); 92 } 93 } 94 95 void UnregistEditorCodes() 96 { 97 // Exclude objects that reference from Editor API 98 var editorcodes = Directory.GetFiles ("Assets", "*.cs", SearchOption.AllDirectories) 99 .Where (item => Regex.IsMatch (item, "[\\/\\\\]Editor[\\/\\\\]") == true) 100 .ToArray (); 101 102 var undeleteClassList = classCollection.codeFileList 103 .Where (codefile => codefile.Value.Any( guid => deleteFileList.Contains(guid)) == false) 104 .Select( item => item.Key ); 105 106 EditorUtility.DisplayProgressBar ("checking", "check reference from editor codes", 0.8f); 107 108 foreach (var path in editorcodes) { 109 var code = File.ReadAllText (path); 110 code = Regex.Replace(code, "//.*[\\n\\r]", ""); 111 code = Regex.Replace(code, "/\\*.*[\\n\\r]\\*/", ""); 112 if (Regex.IsMatch (code, "(\\[MenuItem|AssetPostprocessor|EditorWindow)")) { 113 UnregistFromDelteList ( AssetDatabase.AssetPathToGUID(path)); 114 continue; 115 } 116 117 foreach (var undeleteClass in undeleteClassList) { 118 if (Regex.IsMatch (code, string.Format ("\\[CustomEditor.*\\(\\s*{0}\\s*\\).*\\]", undeleteClass.Name))) { 119 UnregistFromDelteList (path); 120 continue; 121 } 122 } 123 } 124 } 125 126 void UnregistFromDelteList (string guid) 127 { 128 if (deleteFileList.Contains (guid) == false) { 129 return; 130 } 131 deleteFileList.Remove (guid); 132 133 if (classCollection.references.ContainsKey (guid) == true) { 134 135 foreach (var type in classCollection.references[guid]) { 136 var codePaths = classCollection.codeFileList [type]; 137 foreach( var codePath in codePaths){ 138 UnregistFromDelteList (codePath); 139 } 140 } 141 } 142 143 if (shaderCollection.shaderFileList.ContainsValue (guid)) { 144 var shader = shaderCollection.shaderFileList.First (item => item.Value == guid); 145 var shaderAssets = shaderCollection.shaderReferenceList [shader.Key]; 146 foreach (var shaderPath in shaderAssets) { 147 UnregistFromDelteList (shaderPath); 148 } 149 } 150 } 151 } 152 }
1 /** 2 asset cleaner 3 Copyright (c) 2015 Tatsuhiko Yamamura 4 5 This software is released under the MIT License. 6 http://opensource.org/licenses/mit-license.php 7 */ 8 using UnityEngine; 9 using System.Collections; 10 using System.Collections.Generic; 11 using System.Text.RegularExpressions; 12 using UnityEditor; 13 using System.IO; 14 using System.Reflection; 15 using System.Linq; 16 17 namespace AssetClean 18 { 19 public class ClassReferenceCollection 20 { 21 // type : guid 22 public Dictionary<System.Type, List<string>> codeFileList = new Dictionary<System.Type, List<string>> (); 23 // guid : types 24 public Dictionary<string, List<System.Type>> references = new Dictionary<string, List<System.Type>> (); 25 26 public void Collection () 27 { 28 references.Clear (); 29 EditorUtility.DisplayProgressBar ("checking", "collection all type", 0); 30 31 // Connect the files and class. 32 var codes = Directory.GetFiles ("Assets", "*.cs", SearchOption.AllDirectories); 33 // connect each classes. 34 var firstPassList = new List<string>(); 35 if( Directory.Exists ("Assets/Plugins") ) 36 firstPassList.AddRange( Directory.GetFiles ("Assets/Plugins", "*.cs", SearchOption.AllDirectories)); 37 if( Directory.Exists ("Assets/Standard Assets") ) 38 firstPassList.AddRange( Directory.GetFiles ("Assets/Standard Assets", "*.cs", SearchOption.AllDirectories)); 39 40 var allFirstpassTypes = collectionAllFastspassClasses (); 41 CollectionCodeFileDictionary (allFirstpassTypes, firstPassList.ToArray()); 42 43 44 var alltypes = CollectionAllClasses (); 45 CollectionCodeFileDictionary (alltypes, codes.ToArray()); 46 alltypes.AddRange (allFirstpassTypes); 47 48 int count = 0; 49 foreach (var codepath in firstPassList) { 50 CollectionReferenceClasses (AssetDatabase.AssetPathToGUID (codepath), allFirstpassTypes); 51 EditorUtility.DisplayProgressBar ("checking", "analytics codes", ((float)++count / codes.Length) * 0.5f + 0.5f); 52 } 53 count = 0; 54 foreach (var codepath in codes) { 55 CollectionReferenceClasses (AssetDatabase.AssetPathToGUID (codepath), alltypes); 56 EditorUtility.DisplayProgressBar ("checking", "analytics codes", ((float)++count / codes.Length) * 0.5f); 57 } 58 } 59 60 void CollectionCodeFileDictionary (List<System.Type> alltypes, string[] codes) 61 { 62 float count = 1; 63 foreach (var codePath in codes) { 64 EditorUtility.DisplayProgressBar ("checking", "search files", count++ / codes.Length); 65 66 // connect file and classes. 67 var code = System.IO.File.ReadAllText (codePath); 68 code = Regex.Replace(code, "//.*[\\n\\r]", ""); 69 code = Regex.Replace(code, "/\\*.*[\\n\\r]\\*/", ""); 70 71 foreach (var type in alltypes) { 72 73 if( codeFileList.ContainsKey(type ) == false ){ 74 codeFileList.Add(type, new List<string>()); 75 } 76 var list = codeFileList[type]; 77 78 if (string.IsNullOrEmpty (type.Namespace) == false) { 79 var namespacepattern = string.Format ("namespace[\\s.]{0}[{{\\s\\n]", type.Namespace); 80 if (Regex.IsMatch (code, namespacepattern) == false) { 81 continue; 82 } 83 } 84 85 string typeName = type.IsGenericTypeDefinition ? type.GetGenericTypeDefinition ().Name.Split ('`') [0] : type.Name; 86 if (Regex.IsMatch (code, string.Format ("class\\s*{0}?[\\s:<{{]", typeName))) { 87 list.Add( AssetDatabase.AssetPathToGUID(codePath) ); 88 continue; 89 } 90 91 if (Regex.IsMatch (code, string.Format ("struct\\s*{0}[\\s:<{{]", typeName))) { 92 list.Add( AssetDatabase.AssetPathToGUID(codePath) ); 93 continue; 94 } 95 96 if (Regex.IsMatch (code, string.Format ("enum\\s*{0}[\\s{{]", type.Name))) { 97 list.Add( AssetDatabase.AssetPathToGUID(codePath) ); 98 continue; 99 } 100 101 if (Regex.IsMatch (code, string.Format ("delegate\\s*{0}\\s\\(", type.Name))) { 102 list.Add( AssetDatabase.AssetPathToGUID(codePath) ); 103 continue; 104 } 105 } 106 } 107 } 108 109 List<System.Type> CollectionAllClasses () 110 { 111 List<System.Type> alltypes = new List<System.Type> (); 112 113 if (File.Exists ("Library/ScriptAssemblies/Assembly-CSharp.dll")) 114 alltypes.AddRange (Assembly.LoadFile ("Library/ScriptAssemblies/Assembly-CSharp.dll").GetTypes ()); 115 if (File.Exists ("Library/ScriptAssemblies/Assembly-CSharp-Editor.dll")) 116 alltypes.AddRange (Assembly.LoadFile ("Library/ScriptAssemblies/Assembly-CSharp-Editor.dll").GetTypes ()); 117 118 return alltypes .ToList (); 119 } 120 121 List<System.Type> collectionAllFastspassClasses() 122 { 123 List<System.Type> alltypes = new List<System.Type> (); 124 if (File.Exists ("Library/ScriptAssemblies/Assembly-CSharp-firstpass.dll")) 125 alltypes.AddRange (Assembly.LoadFile ("Library/ScriptAssemblies/Assembly-CSharp-firstpass.dll").GetTypes ()); 126 if (File.Exists ("Library/ScriptAssemblies/Assembly-CSharp-Editor-firstpass.dll")) 127 alltypes.AddRange (Assembly.LoadFile ("Library/ScriptAssemblies/Assembly-CSharp-Editor-firstpass.dll").GetTypes ()); 128 return alltypes; 129 } 130 131 void CollectionReferenceClasses (string guid, List<System.Type> types) 132 { 133 var codePath = AssetDatabase.GUIDToAssetPath(guid); 134 if (string.IsNullOrEmpty (codePath) || references.ContainsKey (guid) || File.Exists(codePath)==false) { 135 return; 136 } 137 138 var code = System.IO.File.ReadAllText (codePath); 139 code = Regex.Replace(code, "//.*[\\n\\r]", ""); 140 code = Regex.Replace(code, "/\\*.*[\\n\\r]\\*/", ""); 141 142 var list = new List<System.Type> (); 143 references [guid] = list; 144 145 foreach (var type in types) { 146 147 if (string.IsNullOrEmpty (type.Namespace) == false) { 148 var namespacepattern = string.Format ("[namespace|using][\\s\\.]{0}[{{\\s\\r\\n\\r;]", type.Namespace); 149 if (Regex.IsMatch (code, namespacepattern) == false) { 150 continue; 151 } 152 } 153 154 if (codeFileList.ContainsKey (type) == false) { 155 continue; 156 } 157 158 string match = string.Empty; 159 if (type.IsGenericTypeDefinition) { 160 string typeName = type.GetGenericTypeDefinition ().Name.Split ('`') [0]; 161 match = string.Format ("[\\]\\[\\.\\s<(]{0}[\\.\\s\\n\\r>,<(){{]", typeName); 162 } else { 163 match = string.Format ("[\\]\\[\\.\\s<(]{0}[\\.\\s\\n\\r>,<(){{\\]]", type.Name.Replace("Attribute", "")); 164 } 165 if (Regex.IsMatch (code, match)) { 166 list.Add (type); 167 var typeGuid = codeFileList[type]; 168 foreach( var referenceGuid in typeGuid){ 169 CollectionReferenceClasses (referenceGuid, types); 170 } 171 } 172 } 173 } 174 } 175 }
1 /** 2 asset cleaner 3 Copyright (c) 2015 Tatsuhiko Yamamura 4 5 This software is released under the MIT License. 6 http://opensource.org/licenses/mit-license.php 7 */ 8 using UnityEngine; 9 using System.Collections; 10 using System.Collections.Generic; 11 using UnityEditor; 12 using System.IO; 13 using System.Linq; 14 15 namespace AssetClean 16 { 17 public class FindUnusedAssets : EditorWindow 18 { 19 AssetCollector collection = new AssetCollector (); 20 List<DeleteAsset> deleteAssets = new List<DeleteAsset> (); 21 Vector2 scroll; 22 23 [MenuItem("Assets/Delete Unused Assets/only resource", false, 50)] 24 static void InitWithoutCode () 25 { 26 var window = FindUnusedAssets.CreateInstance<FindUnusedAssets> (); 27 window.collection.useCodeStrip = false; 28 window.collection.Collection (); 29 window.CopyDeleteFileList (window.collection.deleteFileList); 30 31 window.Show (); 32 } 33 34 [MenuItem("Assets/Delete Unused Assets/unused by editor", false, 51)] 35 static void InitWithout () 36 { 37 var window = FindUnusedAssets.CreateInstance<FindUnusedAssets> (); 38 window.collection.Collection (); 39 window.CopyDeleteFileList (window.collection.deleteFileList); 40 41 window.Show (); 42 } 43 44 [MenuItem("Assets/Delete Unused Assets/unused by game", false, 52)] 45 static void Init () 46 { 47 var window = FindUnusedAssets.CreateInstance<FindUnusedAssets> (); 48 window.collection.saveEditorExtensions = false; 49 window.collection.Collection (); 50 window.CopyDeleteFileList (window.collection.deleteFileList); 51 52 window.Show (); 53 } 54 55 void OnGUI () 56 { 57 using (var horizonal = new EditorGUILayout.HorizontalScope("box")) { 58 EditorGUILayout.LabelField ("delete unreference assets from buildsettings and resources"); 59 60 if (GUILayout.Button ("Delete", GUILayout.Width (120), GUILayout.Height (40)) && deleteAssets.Count != 0) { 61 RemoveFiles (); 62 Close (); 63 } 64 } 65 66 using (var scrollScope = new EditorGUILayout.ScrollViewScope(scroll)) { 67 scroll = scrollScope.scrollPosition; 68 foreach (var asset in deleteAssets) { 69 if (string.IsNullOrEmpty (asset.path)) { 70 continue; 71 } 72 73 using (var horizonal = new EditorGUILayout.HorizontalScope()) { 74 asset.isDelete = EditorGUILayout.Toggle (asset.isDelete, GUILayout.Width (20)); 75 var icon = AssetDatabase.GetCachedIcon (asset.path); 76 GUILayout.Label (icon, GUILayout.Width (20), GUILayout.Height (20)); 77 if (GUILayout.Button (asset.path, EditorStyles.largeLabel)) { 78 Selection.activeObject = AssetDatabase.LoadAssetAtPath<Object> (asset.path); 79 } 80 } 81 } 82 } 83 84 } 85 86 static void CleanDir() 87 { 88 RemoveEmptyDirectry ("Assets"); 89 AssetDatabase.Refresh (); 90 } 91 92 void CopyDeleteFileList(IEnumerable<string> deleteFileList) 93 { 94 foreach (var asset in deleteFileList) { 95 var filePath = AssetDatabase.GUIDToAssetPath (asset); 96 if (string.IsNullOrEmpty (filePath) == false) { 97 deleteAssets.Add (new DeleteAsset (){ path = filePath}); 98 } 99 } 100 } 101 102 void RemoveFiles () 103 { 104 try { 105 string exportDirectry = "BackupUnusedAssets"; 106 Directory.CreateDirectory (exportDirectry); 107 var files = deleteAssets.Where (item => item.isDelete == true).Select (item => item.path).ToArray (); 108 string backupPackageName = exportDirectry + "/package" + System.DateTime.Now.ToString ("yyyyMMddHHmmss") + ".unitypackage"; 109 EditorUtility.DisplayProgressBar ("export package", backupPackageName, 0); 110 AssetDatabase.ExportPackage (files, backupPackageName); 111 112 int i = 0; 113 int length = deleteAssets.Count; 114 115 foreach (var assetPath in files) { 116 i++; 117 EditorUtility.DisplayProgressBar ("delete unused assets", assetPath, (float)i / length); 118 AssetDatabase.DeleteAsset (assetPath); 119 } 120 121 EditorUtility.DisplayProgressBar ("clean directory", "", 1); 122 foreach (var dir in Directory.GetDirectories("Assets")) { 123 RemoveEmptyDirectry (dir); 124 } 125 126 System.Diagnostics.Process.Start (exportDirectry); 127 128 AssetDatabase.Refresh (); 129 } 130 catch( System.Exception e ){ 131 Debug.Log(e.Message); 132 }finally { 133 EditorUtility.ClearProgressBar (); 134 } 135 } 136 137 static void RemoveEmptyDirectry (string path) 138 { 139 var dirs = Directory.GetDirectories (path); 140 foreach (var dir in dirs) { 141 RemoveEmptyDirectry (dir); 142 } 143 144 var files = Directory.GetFiles (path, "*", SearchOption.TopDirectoryOnly).Where (item => Path.GetExtension (item) != ".meta"); 145 if (files.Count () == 0 && Directory.GetDirectories (path).Count () == 0) { 146 var metaFile = AssetDatabase.GetTextMetaFilePathFromAssetPath(path); 147 UnityEditor.FileUtil.DeleteFileOrDirectory (path); 148 UnityEditor.FileUtil.DeleteFileOrDirectory (metaFile); 149 } 150 } 151 152 class DeleteAsset 153 { 154 public bool isDelete = true; 155 public string path; 156 } 157 } 158 }
1 /** 2 asset cleaner 3 Copyright (c) 2015 Tatsuhiko Yamamura 4 5 This software is released under the MIT License. 6 http://opensource.org/licenses/mit-license.php 7 */ 8 using UnityEngine; 9 using System.Collections; 10 using System.Collections.Generic; 11 using System.IO; 12 using System.Text.RegularExpressions; 13 using UnityEditor; 14 15 namespace AssetClean 16 { 17 public class ShaderReferenceCollection 18 { 19 // shader name / shader file guid 20 public Dictionary<string, string> shaderFileList = new Dictionary<string, string> (); 21 public Dictionary<string, List<string> > shaderReferenceList = new Dictionary<string, List<string>> (); 22 23 public void Collection () 24 { 25 CollectionShaderFiles (); 26 CheckReference (); 27 } 28 29 void CollectionShaderFiles () 30 { 31 var shaderFiles = Directory.GetFiles ("Assets", "*.shader", SearchOption.AllDirectories); 32 foreach (var shaderFilePath in shaderFiles) { 33 var code = File.ReadAllText (shaderFilePath); 34 var match = Regex.Match (code, "Shader \"(?<name>.*)\""); 35 if (match.Success) { 36 var shaderName = match.Groups ["name"].ToString (); 37 if (shaderFileList.ContainsKey (shaderName) == false) { 38 shaderFileList.Add (shaderName, AssetDatabase.AssetPathToGUID(shaderFilePath)); 39 } 40 } 41 } 42 43 var cgFiles = Directory.GetFiles ("Assets", "*.cg", SearchOption.AllDirectories); 44 foreach (var cgFilePath in cgFiles) { 45 var file = Path.GetFileName (cgFilePath); 46 shaderFileList.Add (file, cgFilePath); 47 } 48 49 var cgincFiles = Directory.GetFiles ("Assets", "*.cginc", SearchOption.AllDirectories); 50 foreach (var cgincPath in cgincFiles) { 51 var file = Path.GetFileName (cgincPath); 52 shaderFileList.Add (file, cgincPath); 53 } 54 } 55 56 void CheckReference () 57 { 58 foreach (var shader in shaderFileList) { 59 var shaderFilePath = AssetDatabase.GUIDToAssetPath(shader.Value); 60 var shaderName = shader.Key; 61 62 List<string> referenceList = new List<string> (); 63 shaderReferenceList.Add (shaderName, referenceList); 64 65 var code = File.ReadAllText (shaderFilePath); 66 67 foreach (var checkingShaderName in shaderFileList.Keys) { 68 if (Regex.IsMatch (code, string.Format ("{0}", checkingShaderName))) { 69 var filePath = shaderFileList [checkingShaderName]; 70 referenceList.Add (filePath); 71 } 72 } 73 } 74 } 75 } 76 }
下载地址:https://github.com/unity-cn/Tool-UnityAssetCleaner
使用:Unity导航菜单栏中选择 Assets-> Delete Unused Assets
三种模式,选择一个合适的,然后点击Delete,轻松搞定
博客园Jason_c微信打赏码
如果本篇文档对你有帮助,打赏Jason_c根华子吧,他的私房钱被老婆没收了,呜呜!