unity 自动删除未引用的Assets下的资源
随着时间的堆积,项目中Assets文件夹下的资源会变得越来越繁杂,有些贴图、材质啥的可能压根没有使用过,但是又不敢轻易去删除。
这里分享两个插件,用于管理这些资源。
一、ResourceChecker
这个插件的强大之处就在于它能够查找当前场景中的所有引用个资源,并快速定位,然后把未定位到的资源手动删掉就行了。
代码
// Resource Checker
// (c) 2012 Simon Oliver / HandCircus / hello@handcircus.com
// (c) 2015 Brice Clocher / Mangatome / hello@mangatome.net
// Public domain, do with whatever you like, commercial or not
// This comes with no warranty, use at your own risk!
// https://github.com/handcircus/Unity-Resource-Checker using System;
using System.Linq;
using UnityEngine;
using UnityEngine.UI;
using UnityEditor;
using System.Collections.Generic;
using System.Reflection;
using Object = UnityEngine.Object; public class TextureDetails : IEquatable<TextureDetails>
{
public bool isCubeMap;
public int memSizeKB;
public Texture texture;
public TextureFormat format;
public int mipMapCount;
public List<Object> FoundInMaterials=new List<Object>();
public List<Object> FoundInRenderers=new List<Object>();
public List<Object> FoundInAnimators = new List<Object>();
public List<Object> FoundInScripts = new List<Object>();
public List<Object> FoundInGraphics = new List<Object>();
public bool isSky;
public bool instance;
public bool isgui;
public TextureDetails()
{ } public bool Equals(TextureDetails other)
{
return texture != null && other.texture != null &&
texture.GetNativeTexturePtr() == other.texture.GetNativeTexturePtr();
} public override int GetHashCode()
{
return (int)texture.GetNativeTexturePtr();
} public override bool Equals(object obj)
{
return Equals(obj as TextureDetails);
}
}; public class MaterialDetails
{ public Material material; public List<Renderer> FoundInRenderers=new List<Renderer>();
public List<Graphic> FoundInGraphics=new List<Graphic>();
public bool instance;
public bool isgui;
public bool isSky; public MaterialDetails()
{
instance = false;
isgui = false;
isSky = false;
}
}; public class MeshDetails
{ public Mesh mesh; public List<MeshFilter> FoundInMeshFilters=new List<MeshFilter>();
public List<SkinnedMeshRenderer> FoundInSkinnedMeshRenderer=new List<SkinnedMeshRenderer>();
public bool instance; public MeshDetails()
{
instance = false;
}
}; public class MissingGraphic{
public Transform Object;
public string type;
public string name;
} public class ResourceChecker : EditorWindow { string[] inspectToolbarStrings = {"Textures", "Materials","Meshes"};
string[] inspectToolbarStrings2 = {"Textures", "Materials","Meshes", "Missing"}; enum InspectType
{
Textures,Materials,Meshes,Missing
}; bool IncludeDisabledObjects=true;
bool IncludeSpriteAnimations=true;
bool IncludeScriptReferences=true;
bool IncludeGuiElements=true;
bool thingsMissing = false; InspectType ActiveInspectType=InspectType.Textures; float ThumbnailWidth=;
float ThumbnailHeight=; List<TextureDetails> ActiveTextures=new List<TextureDetails>();
List<MaterialDetails> ActiveMaterials=new List<MaterialDetails>();
List<MeshDetails> ActiveMeshDetails=new List<MeshDetails>();
List<MissingGraphic> MissingObjects = new List<MissingGraphic> (); Vector2 textureListScrollPos=new Vector2(,);
Vector2 materialListScrollPos=new Vector2(,);
Vector2 meshListScrollPos=new Vector2(,);
Vector2 missingListScrollPos = new Vector2 (,); int TotalTextureMemory=;
int TotalMeshVertices=; bool ctrlPressed=false; static int MinWidth=;
Color defColor; bool collectedInPlayingMode; [MenuItem ("Window/Resource Checker")]
static void Init ()
{
ResourceChecker window = (ResourceChecker) EditorWindow.GetWindow (typeof (ResourceChecker));
window.CheckResources();
window.minSize=new Vector2(MinWidth,);
} void OnGUI ()
{
defColor = GUI.color;
IncludeDisabledObjects = GUILayout.Toggle(IncludeDisabledObjects, "Include disabled objects", GUILayout.Width());
IncludeSpriteAnimations = GUILayout.Toggle(IncludeSpriteAnimations, "Look in sprite animations", GUILayout.Width());
GUI.color = new Color (0.8f, 0.8f, 1.0f, 1.0f);
IncludeScriptReferences = GUILayout.Toggle(IncludeScriptReferences, "Look in behavior fields", GUILayout.Width());
GUI.color = new Color (1.0f, 0.95f, 0.8f, 1.0f);
IncludeGuiElements = GUILayout.Toggle(IncludeGuiElements, "Look in GUI elements", GUILayout.Width());
GUI.color = defColor;
GUILayout.BeginArea(new Rect(position.width-,,,));
if (GUILayout.Button("Calculate",GUILayout.Width(), GUILayout.Height()))
CheckResources();
if (GUILayout.Button("CleanUp",GUILayout.Width(), GUILayout.Height()))
Resources.UnloadUnusedAssets();
GUILayout.EndArea();
RemoveDestroyedResources(); GUILayout.Space();
if (thingsMissing == true) {
EditorGUI.HelpBox (new Rect(,,,),"Some GameObjects are missing graphical elements.", MessageType.Error);
}
GUILayout.BeginHorizontal();
GUILayout.Label("Textures "+ActiveTextures.Count+" - "+FormatSizeString(TotalTextureMemory));
GUILayout.Label("Materials "+ActiveMaterials.Count);
GUILayout.Label("Meshes "+ActiveMeshDetails.Count+" - "+TotalMeshVertices+" verts");
GUILayout.EndHorizontal();
if (thingsMissing == true) {
ActiveInspectType = (InspectType)GUILayout.Toolbar ((int)ActiveInspectType, inspectToolbarStrings2);
} else {
ActiveInspectType = (InspectType)GUILayout.Toolbar ((int)ActiveInspectType, inspectToolbarStrings);
} ctrlPressed=Event.current.control || Event.current.command; switch (ActiveInspectType)
{
case InspectType.Textures:
ListTextures();
break;
case InspectType.Materials:
ListMaterials();
break;
case InspectType.Meshes:
ListMeshes();
break;
case InspectType.Missing:
ListMissing();
break;
}
} private void RemoveDestroyedResources()
{
if (collectedInPlayingMode != Application.isPlaying)
{
ActiveTextures.Clear();
ActiveMaterials.Clear();
ActiveMeshDetails.Clear();
MissingObjects.Clear ();
thingsMissing = false;
collectedInPlayingMode = Application.isPlaying;
} ActiveTextures.RemoveAll(x => !x.texture);
ActiveTextures.ForEach(delegate(TextureDetails obj) {
obj.FoundInAnimators.RemoveAll(x => !x);
obj.FoundInMaterials.RemoveAll(x => !x);
obj.FoundInRenderers.RemoveAll(x => !x);
obj.FoundInScripts.RemoveAll(x => !x);
obj.FoundInGraphics.RemoveAll(x => !x);
}); ActiveMaterials.RemoveAll(x => !x.material);
ActiveMaterials.ForEach(delegate(MaterialDetails obj) {
obj.FoundInRenderers.RemoveAll(x => !x);
obj.FoundInGraphics.RemoveAll(x => !x);
}); ActiveMeshDetails.RemoveAll(x => !x.mesh);
ActiveMeshDetails.ForEach(delegate(MeshDetails obj) {
obj.FoundInMeshFilters.RemoveAll(x => !x);
obj.FoundInSkinnedMeshRenderer.RemoveAll(x => !x);
}); TotalTextureMemory = ;
foreach (TextureDetails tTextureDetails in ActiveTextures) TotalTextureMemory += tTextureDetails.memSizeKB; TotalMeshVertices = ;
foreach (MeshDetails tMeshDetails in ActiveMeshDetails) TotalMeshVertices += tMeshDetails.mesh.vertexCount;
} int GetBitsPerPixel(TextureFormat format)
{
switch (format)
{
case TextureFormat.Alpha8: // Alpha-only texture format.
return ;
case TextureFormat.ARGB4444: // A 16 bits/pixel texture format. Texture stores color with an alpha channel.
return ;
case TextureFormat.RGBA4444: // A 16 bits/pixel texture format.
return ;
case TextureFormat.RGB24: // A color texture format.
return ;
case TextureFormat.RGBA32: //Color with an alpha channel texture format.
return ;
case TextureFormat.ARGB32: //Color with an alpha channel texture format.
return ;
case TextureFormat.RGB565: // A 16 bit color texture format.
return ;
case TextureFormat.DXT1: // Compressed color texture format.
return ;
case TextureFormat.DXT5: // Compressed color with alpha channel texture format.
return ;
/*
case TextureFormat.WiiI4: // Wii texture format.
case TextureFormat.WiiI8: // Wii texture format. Intensity 8 bit.
case TextureFormat.WiiIA4: // Wii texture format. Intensity + Alpha 8 bit (4 + 4).
case TextureFormat.WiiIA8: // Wii texture format. Intensity + Alpha 16 bit (8 + 8).
case TextureFormat.WiiRGB565: // Wii texture format. RGB 16 bit (565).
case TextureFormat.WiiRGB5A3: // Wii texture format. RGBA 16 bit (4443).
case TextureFormat.WiiRGBA8: // Wii texture format. RGBA 32 bit (8888).
case TextureFormat.WiiCMPR: // Compressed Wii texture format. 4 bits/texel, ~RGB8A1 (Outline alpha is not currently supported).
return 0; //Not supported yet
*/
case TextureFormat.PVRTC_RGB2:// PowerVR (iOS) 2 bits/pixel compressed color texture format.
return ;
case TextureFormat.PVRTC_RGBA2:// PowerVR (iOS) 2 bits/pixel compressed with alpha channel texture format
return ;
case TextureFormat.PVRTC_RGB4:// PowerVR (iOS) 4 bits/pixel compressed color texture format.
return ;
case TextureFormat.PVRTC_RGBA4:// PowerVR (iOS) 4 bits/pixel compressed with alpha channel texture format
return ;
case TextureFormat.ETC_RGB4:// ETC (GLES2.0) 4 bits/pixel compressed RGB texture format.
return ;
case TextureFormat.ATC_RGB4:// ATC (ATITC) 4 bits/pixel compressed RGB texture format.
return ;
case TextureFormat.ATC_RGBA8:// ATC (ATITC) 8 bits/pixel compressed RGB texture format.
return ;
case TextureFormat.BGRA32:// Format returned by iPhone camera
return ;
#if !UNITY_5 && !UNITY_5_3_OR_NEWER
case TextureFormat.ATF_RGB_DXT1:// Flash-specific RGB DXT1 compressed color texture format.
case TextureFormat.ATF_RGBA_JPG:// Flash-specific RGBA JPG-compressed color texture format.
case TextureFormat.ATF_RGB_JPG:// Flash-specific RGB JPG-compressed color texture format.
return ; //Not supported yet
#endif
}
return ;
} int CalculateTextureSizeBytes(Texture tTexture)
{ int tWidth=tTexture.width;
int tHeight=tTexture.height;
if (tTexture is Texture2D)
{
Texture2D tTex2D=tTexture as Texture2D;
int bitsPerPixel=GetBitsPerPixel(tTex2D.format);
int mipMapCount=tTex2D.mipmapCount;
int mipLevel=;
int tSize=;
while (mipLevel<=mipMapCount)
{
tSize+=tWidth*tHeight*bitsPerPixel/;
tWidth=tWidth/;
tHeight=tHeight/;
mipLevel++;
}
return tSize;
}
if (tTexture is Texture2DArray)
{
Texture2DArray tTex2D=tTexture as Texture2DArray;
int bitsPerPixel=GetBitsPerPixel(tTex2D.format);
int mipMapCount=;
int mipLevel=;
int tSize=;
while (mipLevel<=mipMapCount)
{
tSize+=tWidth*tHeight*bitsPerPixel/;
tWidth=tWidth/;
tHeight=tHeight/;
mipLevel++;
}
return tSize*((Texture2DArray)tTex2D).depth;
}
if (tTexture is Cubemap) {
Cubemap tCubemap = tTexture as Cubemap;
int bitsPerPixel = GetBitsPerPixel (tCubemap.format);
return tWidth * tHeight * * bitsPerPixel / ;
}
return ;
} void SelectObject(Object selectedObject,bool append)
{
if (append)
{
List<Object> currentSelection=new List<Object>(Selection.objects);
// Allow toggle selection
if (currentSelection.Contains(selectedObject)) currentSelection.Remove(selectedObject);
else currentSelection.Add(selectedObject); Selection.objects=currentSelection.ToArray();
}
else Selection.activeObject=selectedObject;
} void SelectObjects(List<Object> selectedObjects,bool append)
{
if (append)
{
List<Object> currentSelection=new List<Object>(Selection.objects);
currentSelection.AddRange(selectedObjects);
Selection.objects=currentSelection.ToArray();
}
else Selection.objects=selectedObjects.ToArray();
} void ListTextures()
{
textureListScrollPos = EditorGUILayout.BeginScrollView(textureListScrollPos); foreach (TextureDetails tDetails in ActiveTextures)
{ GUILayout.BeginHorizontal ();
Texture tex = new Texture();
tex = tDetails.texture;
if(tDetails.texture.GetType() == typeof(Texture2DArray) || tDetails.texture.GetType() == typeof(Cubemap)){
tex = AssetPreview.GetMiniThumbnail(tDetails.texture);
}
GUILayout.Box(tex, GUILayout.Width(ThumbnailWidth), GUILayout.Height(ThumbnailHeight)); if (tDetails.instance == true)
GUI.color = new Color (0.8f, 0.8f, defColor.b, 1.0f);
if (tDetails.isgui == true)
GUI.color = new Color (defColor.r, 0.95f, 0.8f, 1.0f);
if (tDetails.isSky)
GUI.color = new Color (0.9f, defColor.g, defColor.b, 1.0f);
if(GUILayout.Button(tDetails.texture.name,GUILayout.Width()))
{
SelectObject(tDetails.texture,ctrlPressed);
}
GUI.color = defColor; string sizeLabel=""+tDetails.texture.width+"x"+tDetails.texture.height;
if (tDetails.isCubeMap) sizeLabel+="x6";
if (tDetails.texture.GetType () == typeof(Texture2DArray))
sizeLabel+= "[]\n" + ((Texture2DArray)tDetails.texture).depth+"depths";
sizeLabel+=" - "+tDetails.mipMapCount+"mip\n"+FormatSizeString(tDetails.memSizeKB)+" - "+tDetails.format; GUILayout.Label (sizeLabel,GUILayout.Width()); if(GUILayout.Button(tDetails.FoundInMaterials.Count+" Mat",GUILayout.Width()))
{
SelectObjects(tDetails.FoundInMaterials,ctrlPressed);
} HashSet<Object> FoundObjects = new HashSet<Object>();
foreach (Renderer renderer in tDetails.FoundInRenderers) FoundObjects.Add(renderer.gameObject);
foreach (Animator animator in tDetails.FoundInAnimators) FoundObjects.Add(animator.gameObject);
foreach (Graphic graphic in tDetails.FoundInGraphics) FoundObjects.Add(graphic.gameObject);
foreach (MonoBehaviour script in tDetails.FoundInScripts) FoundObjects.Add(script.gameObject);
if (GUILayout.Button(FoundObjects.Count+" GO",GUILayout.Width()))
{
SelectObjects(new List<Object>(FoundObjects),ctrlPressed);
} GUILayout.EndHorizontal();
}
if (ActiveTextures.Count>)
{
EditorGUILayout.Space();
GUILayout.BeginHorizontal ();
//GUILayout.Box(" ",GUILayout.Width(ThumbnailWidth),GUILayout.Height(ThumbnailHeight));
if(GUILayout.Button("Select \n All",GUILayout.Width(ThumbnailWidth*)))
{
List<Object> AllTextures=new List<Object>();
foreach (TextureDetails tDetails in ActiveTextures) AllTextures.Add(tDetails.texture);
SelectObjects(AllTextures,ctrlPressed);
}
EditorGUILayout.EndHorizontal();
}
EditorGUILayout.EndScrollView();
} void ListMaterials()
{
materialListScrollPos = EditorGUILayout.BeginScrollView(materialListScrollPos); foreach (MaterialDetails tDetails in ActiveMaterials)
{
if (tDetails.material!=null)
{
GUILayout.BeginHorizontal (); GUILayout.Box(AssetPreview.GetAssetPreview(tDetails.material), GUILayout.Width(ThumbnailWidth), GUILayout.Height(ThumbnailHeight)); if (tDetails.instance == true)
GUI.color = new Color (0.8f, 0.8f, defColor.b, 1.0f);
if (tDetails.isgui == true)
GUI.color = new Color (defColor.r, 0.95f, 0.8f, 1.0f);
if (tDetails.isSky)
GUI.color = new Color (0.9f, defColor.g, defColor.b, 1.0f);
if(GUILayout.Button(tDetails.material.name,GUILayout.Width()))
{
SelectObject(tDetails.material,ctrlPressed);
}
GUI.color = defColor; string shaderLabel = tDetails.material.shader != null ? tDetails.material.shader.name : "no shader";
GUILayout.Label (shaderLabel, GUILayout.Width()); if(GUILayout.Button((tDetails.FoundInRenderers.Count + tDetails.FoundInGraphics.Count) +" GO",GUILayout.Width()))
{
List<Object> FoundObjects=new List<Object>();
foreach (Renderer renderer in tDetails.FoundInRenderers) FoundObjects.Add(renderer.gameObject);
foreach (Graphic graphic in tDetails.FoundInGraphics) FoundObjects.Add(graphic.gameObject);
SelectObjects(FoundObjects,ctrlPressed);
} GUILayout.EndHorizontal();
}
}
EditorGUILayout.EndScrollView();
} void ListMeshes()
{
meshListScrollPos = EditorGUILayout.BeginScrollView(meshListScrollPos); foreach (MeshDetails tDetails in ActiveMeshDetails)
{
if (tDetails.mesh!=null)
{
GUILayout.BeginHorizontal ();
string name = tDetails.mesh.name;
if (name == null || name.Count() < )
name = tDetails.FoundInMeshFilters[].gameObject.name;
if (tDetails.instance == true)
GUI.color = new Color (0.8f, 0.8f, defColor.b, 1.0f);
if(GUILayout.Button(name,GUILayout.Width()))
{
SelectObject(tDetails.mesh,ctrlPressed);
}
GUI.color = defColor;
string sizeLabel=""+tDetails.mesh.vertexCount+" vert"; GUILayout.Label (sizeLabel,GUILayout.Width()); if(GUILayout.Button(tDetails.FoundInMeshFilters.Count + " GO",GUILayout.Width()))
{
List<Object> FoundObjects=new List<Object>();
foreach (MeshFilter meshFilter in tDetails.FoundInMeshFilters) FoundObjects.Add(meshFilter.gameObject);
SelectObjects(FoundObjects,ctrlPressed);
}
if (tDetails.FoundInSkinnedMeshRenderer.Count > ) {
if (GUILayout.Button (tDetails.FoundInSkinnedMeshRenderer.Count + " skinned mesh GO", GUILayout.Width ())) {
List<Object> FoundObjects = new List<Object> ();
foreach (SkinnedMeshRenderer skinnedMeshRenderer in tDetails.FoundInSkinnedMeshRenderer)
FoundObjects.Add (skinnedMeshRenderer.gameObject);
SelectObjects (FoundObjects, ctrlPressed);
}
} else {
GUI.color = new Color (defColor.r, defColor.g, defColor.b, 0.5f);
GUILayout.Label(" 0 skinned mesh");
GUI.color = defColor;
} GUILayout.EndHorizontal();
}
}
EditorGUILayout.EndScrollView();
} void ListMissing(){
missingListScrollPos = EditorGUILayout.BeginScrollView(missingListScrollPos);
foreach (MissingGraphic dMissing in MissingObjects) {
GUILayout.BeginHorizontal ();
if (GUILayout.Button (dMissing.name, GUILayout.Width ()))
SelectObject (dMissing.Object, ctrlPressed);
GUILayout.Label ("missing ", GUILayout.Width());
switch (dMissing.type) {
case "mesh":
GUI.color = new Color (0.8f, 0.8f, defColor.b, 1.0f);
break;
case "sprite":
GUI.color = new Color (defColor.r, 0.8f, 0.8f, 1.0f);
break;
case "material":
GUI.color = new Color (0.8f, defColor.g, 0.8f, 1.0f);
break;
}
GUILayout.Label (dMissing.type);
GUI.color = defColor;
GUILayout.EndHorizontal ();
}
EditorGUILayout.EndScrollView();
} string FormatSizeString(int memSizeKB)
{
if (memSizeKB<) return ""+memSizeKB+"k";
else
{
float memSizeMB=((float)memSizeKB)/1024.0f;
return memSizeMB.ToString("0.00")+"Mb";
}
} TextureDetails FindTextureDetails(Texture tTexture)
{
foreach (TextureDetails tTextureDetails in ActiveTextures)
{
if (tTextureDetails.texture==tTexture) return tTextureDetails;
}
return null; } MaterialDetails FindMaterialDetails(Material tMaterial)
{
foreach (MaterialDetails tMaterialDetails in ActiveMaterials)
{
if (tMaterialDetails.material==tMaterial) return tMaterialDetails;
}
return null; } MeshDetails FindMeshDetails(Mesh tMesh)
{
foreach (MeshDetails tMeshDetails in ActiveMeshDetails)
{
if (tMeshDetails.mesh==tMesh) return tMeshDetails;
}
return null; } void CheckResources()
{
ActiveTextures.Clear();
ActiveMaterials.Clear();
ActiveMeshDetails.Clear();
MissingObjects.Clear ();
thingsMissing = false; Renderer[] renderers = FindObjects<Renderer>(); MaterialDetails skyMat = new MaterialDetails ();
skyMat.material = RenderSettings.skybox;
skyMat.isSky = true;
ActiveMaterials.Add (skyMat); //Debug.Log("Total renderers "+renderers.Length);
foreach (Renderer renderer in renderers)
{
//Debug.Log("Renderer is "+renderer.name);
foreach (Material material in renderer.sharedMaterials)
{ MaterialDetails tMaterialDetails = FindMaterialDetails(material);
if (tMaterialDetails == null)
{
tMaterialDetails = new MaterialDetails();
tMaterialDetails.material = material;
ActiveMaterials.Add(tMaterialDetails);
}
tMaterialDetails.FoundInRenderers.Add(renderer);
} if (renderer is SpriteRenderer)
{
SpriteRenderer tSpriteRenderer = (SpriteRenderer)renderer; if (tSpriteRenderer.sprite != null) {
var tSpriteTextureDetail = GetTextureDetail (tSpriteRenderer.sprite.texture, renderer);
if (!ActiveTextures.Contains (tSpriteTextureDetail)) {
ActiveTextures.Add (tSpriteTextureDetail);
}
} else if (tSpriteRenderer.sprite == null) {
MissingGraphic tMissing = new MissingGraphic ();
tMissing.Object = tSpriteRenderer.transform;
tMissing.type = "sprite";
tMissing.name = tSpriteRenderer.transform.name;
MissingObjects.Add (tMissing);
thingsMissing = true;
}
}
} if (IncludeGuiElements)
{
Graphic[] graphics = FindObjects<Graphic>(); foreach(Graphic graphic in graphics)
{
if (graphic.mainTexture)
{
var tSpriteTextureDetail = GetTextureDetail(graphic.mainTexture, graphic);
if (!ActiveTextures.Contains(tSpriteTextureDetail))
{
ActiveTextures.Add(tSpriteTextureDetail);
}
} if (graphic.materialForRendering)
{
MaterialDetails tMaterialDetails = FindMaterialDetails(graphic.materialForRendering);
if (tMaterialDetails == null)
{
tMaterialDetails = new MaterialDetails();
tMaterialDetails.material = graphic.materialForRendering;
tMaterialDetails.isgui = true;
ActiveMaterials.Add(tMaterialDetails);
}
tMaterialDetails.FoundInGraphics.Add(graphic);
}
}
} foreach (MaterialDetails tMaterialDetails in ActiveMaterials)
{
Material tMaterial = tMaterialDetails.material;
if (tMaterial != null)
{
var dependencies = EditorUtility.CollectDependencies(new UnityEngine.Object[] { tMaterial });
foreach (Object obj in dependencies)
{
if (obj is Texture)
{
Texture tTexture = obj as Texture;
var tTextureDetail = GetTextureDetail(tTexture, tMaterial, tMaterialDetails);
tTextureDetail.isSky = tMaterialDetails.isSky;
tTextureDetail.instance = tMaterialDetails.instance;
tTextureDetail.isgui = tMaterialDetails.isgui;
ActiveTextures.Add(tTextureDetail);
}
} //if the texture was downloaded, it won't be included in the editor dependencies
if (tMaterial.HasProperty ("_MainTex")) {
if (tMaterial.mainTexture != null && !dependencies.Contains (tMaterial.mainTexture)) {
var tTextureDetail = GetTextureDetail (tMaterial.mainTexture, tMaterial, tMaterialDetails);
ActiveTextures.Add (tTextureDetail);
}
}
}
} MeshFilter[] meshFilters = FindObjects<MeshFilter>(); foreach (MeshFilter tMeshFilter in meshFilters)
{
Mesh tMesh = tMeshFilter.sharedMesh;
if (tMesh != null)
{
MeshDetails tMeshDetails = FindMeshDetails(tMesh);
if (tMeshDetails == null)
{
tMeshDetails = new MeshDetails();
tMeshDetails.mesh = tMesh;
ActiveMeshDetails.Add(tMeshDetails);
}
tMeshDetails.FoundInMeshFilters.Add(tMeshFilter);
} else if (tMesh == null && tMeshFilter.transform.GetComponent("TextContainer")== null) {
MissingGraphic tMissing = new MissingGraphic ();
tMissing.Object = tMeshFilter.transform;
tMissing.type = "mesh";
tMissing.name = tMeshFilter.transform.name;
MissingObjects.Add (tMissing);
thingsMissing = true;
} var meshRenderrer = tMeshFilter.transform.GetComponent<MeshRenderer>(); if (meshRenderrer == null || meshRenderrer.sharedMaterial == null) {
MissingGraphic tMissing = new MissingGraphic ();
tMissing.Object = tMeshFilter.transform;
tMissing.type = "material";
tMissing.name = tMeshFilter.transform.name;
MissingObjects.Add (tMissing);
thingsMissing = true;
}
} SkinnedMeshRenderer[] skinnedMeshRenderers = FindObjects<SkinnedMeshRenderer>(); foreach (SkinnedMeshRenderer tSkinnedMeshRenderer in skinnedMeshRenderers)
{
Mesh tMesh = tSkinnedMeshRenderer.sharedMesh;
if (tMesh != null)
{
MeshDetails tMeshDetails = FindMeshDetails(tMesh);
if (tMeshDetails == null)
{
tMeshDetails = new MeshDetails();
tMeshDetails.mesh = tMesh;
ActiveMeshDetails.Add(tMeshDetails);
}
tMeshDetails.FoundInSkinnedMeshRenderer.Add(tSkinnedMeshRenderer);
} else if (tMesh == null) {
MissingGraphic tMissing = new MissingGraphic ();
tMissing.Object = tSkinnedMeshRenderer.transform;
tMissing.type = "mesh";
tMissing.name = tSkinnedMeshRenderer.transform.name;
MissingObjects.Add (tMissing);
thingsMissing = true;
}
if (tSkinnedMeshRenderer.sharedMaterial == null) {
MissingGraphic tMissing = new MissingGraphic ();
tMissing.Object = tSkinnedMeshRenderer.transform;
tMissing.type = "material";
tMissing.name = tSkinnedMeshRenderer.transform.name;
MissingObjects.Add (tMissing);
thingsMissing = true;
}
} if (IncludeSpriteAnimations)
{
Animator[] animators = FindObjects<Animator>();
foreach (Animator anim in animators)
{
#if UNITY_4_6 || UNITY_4_5 || UNITY_4_4 || UNITY_4_3
UnityEditorInternal.AnimatorController ac = anim.runtimeAnimatorController as UnityEditorInternal.AnimatorController;
#elif UNITY_5 || UNITY_5_3_OR_NEWER
UnityEditor.Animations.AnimatorController ac = anim.runtimeAnimatorController as UnityEditor.Animations.AnimatorController;
#endif //Skip animators without layers, this can happen if they don't have an animator controller.
if (!ac || ac.layers == null || ac.layers.Length == )
continue; for (int x = ; x < anim.layerCount; x++)
{
#if UNITY_4_6 || UNITY_4_5 || UNITY_4_4 || UNITY_4_3
UnityEditorInternal.StateMachine sm = ac.GetLayer(x).stateMachine;
int cnt = sm.stateCount;
#elif UNITY_5 || UNITY_5_3_OR_NEWER
UnityEditor.Animations.AnimatorStateMachine sm = ac.layers[x].stateMachine;
int cnt = sm.states.Length;
#endif for (int i = ; i < cnt; i++)
{
#if UNITY_4_6 || UNITY_4_5 || UNITY_4_4 || UNITY_4_3
UnityEditorInternal.State state = sm.GetState(i);
Motion m = state.GetMotion();
#elif UNITY_5 || UNITY_5_3_OR_NEWER
UnityEditor.Animations.AnimatorState state = sm.states[i].state;
Motion m = state.motion;
#endif
if (m != null)
{
AnimationClip clip = m as AnimationClip; if (clip != null)
{
EditorCurveBinding[] ecbs = AnimationUtility.GetObjectReferenceCurveBindings(clip); foreach (EditorCurveBinding ecb in ecbs)
{
if (ecb.propertyName == "m_Sprite")
{
foreach (ObjectReferenceKeyframe keyframe in AnimationUtility.GetObjectReferenceCurve(clip, ecb))
{
Sprite tSprite = keyframe.value as Sprite; if (tSprite != null)
{
var tTextureDetail = GetTextureDetail(tSprite.texture, anim);
if (!ActiveTextures.Contains(tTextureDetail))
{
ActiveTextures.Add(tTextureDetail);
}
}
}
}
}
}
}
}
} }
} if (IncludeScriptReferences)
{
MonoBehaviour[] scripts = FindObjects<MonoBehaviour>();
foreach (MonoBehaviour script in scripts)
{
BindingFlags flags = BindingFlags.Public | BindingFlags.Instance; // only public non-static fields are bound to by Unity.
FieldInfo[] fields = script.GetType().GetFields(flags); foreach (FieldInfo field in fields)
{
System.Type fieldType = field.FieldType;
if (fieldType == typeof(Sprite))
{
Sprite tSprite = field.GetValue(script) as Sprite;
if (tSprite != null)
{
var tSpriteTextureDetail = GetTextureDetail(tSprite.texture, script);
if (!ActiveTextures.Contains(tSpriteTextureDetail))
{
ActiveTextures.Add(tSpriteTextureDetail);
}
}
}if (fieldType == typeof(Mesh))
{
Mesh tMesh = field.GetValue(script) as Mesh;
if (tMesh != null)
{
MeshDetails tMeshDetails = FindMeshDetails(tMesh);
if (tMeshDetails == null)
{
tMeshDetails = new MeshDetails();
tMeshDetails.mesh = tMesh;
tMeshDetails.instance = true;
ActiveMeshDetails.Add(tMeshDetails);
}
}
}if (fieldType == typeof(Material))
{
Material tMaterial = field.GetValue(script) as Material;
if (tMaterial != null)
{
MaterialDetails tMatDetails = FindMaterialDetails(tMaterial);
if (tMatDetails == null)
{
tMatDetails = new MaterialDetails();
tMatDetails.instance = true;
tMatDetails.material = tMaterial;
if(!ActiveMaterials.Contains(tMatDetails))
ActiveMaterials.Add(tMatDetails);
}
if (tMaterial.mainTexture)
{
var tSpriteTextureDetail = GetTextureDetail(tMaterial.mainTexture);
if (!ActiveTextures.Contains(tSpriteTextureDetail))
{
ActiveTextures.Add(tSpriteTextureDetail);
}
}
var dependencies = EditorUtility.CollectDependencies(new UnityEngine.Object[] { tMaterial });
foreach (Object obj in dependencies)
{
if (obj is Texture)
{
Texture tTexture = obj as Texture;
var tTextureDetail = GetTextureDetail(tTexture, tMaterial, tMatDetails);
if(!ActiveTextures.Contains(tTextureDetail))
ActiveTextures.Add(tTextureDetail);
}
}
}
}
}
}
} TotalTextureMemory = ;
foreach (TextureDetails tTextureDetails in ActiveTextures) TotalTextureMemory += tTextureDetails.memSizeKB; TotalMeshVertices = ;
foreach (MeshDetails tMeshDetails in ActiveMeshDetails) TotalMeshVertices += tMeshDetails.mesh.vertexCount; // Sort by size, descending
ActiveTextures.Sort(delegate(TextureDetails details1, TextureDetails details2) { return details2.memSizeKB - details1.memSizeKB; });
ActiveTextures = ActiveTextures.Distinct().ToList();
ActiveMeshDetails.Sort(delegate(MeshDetails details1, MeshDetails details2) { return details2.mesh.vertexCount - details1.mesh.vertexCount; }); collectedInPlayingMode = Application.isPlaying;
} private static GameObject[] GetAllRootGameObjects()
{
#if !UNITY_5 && !UNITY_5_3_OR_NEWER
return UnityEngine.SceneManagement.SceneManager.GetActiveScene().GetRootGameObjects().ToArray();
#else
List<GameObject> allGo = new List<GameObject>();
for (int sceneIdx = ; sceneIdx < UnityEngine.SceneManagement.SceneManager.sceneCount; ++sceneIdx){
allGo.AddRange( UnityEngine.SceneManagement.SceneManager.GetSceneAt(sceneIdx).GetRootGameObjects().ToArray() );
}
return allGo.ToArray();
#endif
} private T[] FindObjects<T>() where T : Object
{
if (IncludeDisabledObjects) {
List<T> meshfilters = new List<T> ();
GameObject[] allGo = GetAllRootGameObjects();
foreach (GameObject go in allGo) {
Transform[] tgo = go.GetComponentsInChildren<Transform> (true).ToArray ();
foreach (Transform tr in tgo) {
if (tr.GetComponent<T> ())
meshfilters.Add (tr.GetComponent<T> ());
}
}
return (T[])meshfilters.ToArray ();
}
else
return (T[])FindObjectsOfType(typeof(T));
} private TextureDetails GetTextureDetail(Texture tTexture, Material tMaterial, MaterialDetails tMaterialDetails)
{
TextureDetails tTextureDetails = GetTextureDetail(tTexture); tTextureDetails.FoundInMaterials.Add(tMaterial);
foreach (Renderer renderer in tMaterialDetails.FoundInRenderers)
{
if (!tTextureDetails.FoundInRenderers.Contains(renderer)) tTextureDetails.FoundInRenderers.Add(renderer);
}
return tTextureDetails;
} private TextureDetails GetTextureDetail(Texture tTexture, Renderer renderer)
{
TextureDetails tTextureDetails = GetTextureDetail(tTexture); tTextureDetails.FoundInRenderers.Add(renderer);
return tTextureDetails;
} private TextureDetails GetTextureDetail(Texture tTexture, Animator animator)
{
TextureDetails tTextureDetails = GetTextureDetail(tTexture); tTextureDetails.FoundInAnimators.Add(animator);
return tTextureDetails;
} private TextureDetails GetTextureDetail(Texture tTexture, Graphic graphic)
{
TextureDetails tTextureDetails = GetTextureDetail(tTexture); tTextureDetails.FoundInGraphics.Add(graphic);
return tTextureDetails;
} private TextureDetails GetTextureDetail(Texture tTexture, MonoBehaviour script)
{
TextureDetails tTextureDetails = GetTextureDetail(tTexture); tTextureDetails.FoundInScripts.Add(script);
return tTextureDetails;
} private TextureDetails GetTextureDetail(Texture tTexture)
{
TextureDetails tTextureDetails = FindTextureDetails(tTexture);
if (tTextureDetails == null)
{
tTextureDetails = new TextureDetails();
tTextureDetails.texture = tTexture;
tTextureDetails.isCubeMap = tTexture is Cubemap; int memSize = CalculateTextureSizeBytes(tTexture); TextureFormat tFormat = TextureFormat.RGBA32;
int tMipMapCount = ;
if (tTexture is Texture2D)
{
tFormat = (tTexture as Texture2D).format;
tMipMapCount = (tTexture as Texture2D).mipmapCount;
}
if (tTexture is Cubemap)
{
tFormat = (tTexture as Cubemap).format;
memSize = * tTexture.height * tTexture.width;
}
if(tTexture is Texture2DArray){
tFormat = (tTexture as Texture2DArray).format;
tMipMapCount = ;
} tTextureDetails.memSizeKB = memSize / ;
tTextureDetails.format = tFormat;
tTextureDetails.mipMapCount = tMipMapCount; } return tTextureDetails;
} }
ResourceChecker
下载地址:https://github.com/handcircus/Unity-Resource-Checker
使用:Unity导航菜单栏中选择 Windows -> Resource Checker ,点击即可
二、UnityAssetCleaner
超级diao炸天的插件,强烈推荐使用,有三种清理资源的模式,更重要的是,它把assets下的资源删除后,
自动将删除的文件备份一个package包,这样再也不用担心误删有用的资源啦,误删了,大不了再把package包导进来呗。
代码:
/**
asset cleaner
Copyright (c) 2015 Tatsuhiko Yamamura This software is released under the MIT License.
http://opensource.org/licenses/mit-license.php
*/
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEditor;
using System.IO;
using System.Text.RegularExpressions; namespace AssetClean
{
public class AssetCollector
{
public List<string> deleteFileList = new List<string> ();
ClassReferenceCollection classCollection = new ClassReferenceCollection ();
ShaderReferenceCollection shaderCollection = new ShaderReferenceCollection (); public bool useCodeStrip = true;
public bool saveEditorExtensions = true; public void Collection ()
{
try {
deleteFileList.Clear (); if( useCodeStrip ){
classCollection.Collection ();
}
shaderCollection.Collection (); // Find assets
var files = Directory.GetFiles ("Assets", "*.*", SearchOption.AllDirectories)
.Where (item => Path.GetExtension (item) != ".meta")
.Where (item => Path.GetExtension (item) != ".js")
.Where (item => Path.GetExtension (item) != ".dll")
.Where (item => Regex.IsMatch (item, "[\\/\\\\]Gizmos[\\/\\\\]") == false)
.Where (item => Regex.IsMatch (item, "[\\/\\\\]Plugins[\\/\\\\]Android[\\/\\\\]") == false)
.Where (item => Regex.IsMatch (item, "[\\/\\\\]Plugins[\\/\\\\]iOS[\\/\\\\]") == false)
.Where (item => Regex.IsMatch (item, "[\\/\\\\]Resources[\\/\\\\]") == false); if( useCodeStrip == false ){
files = files.Where( item => Path.GetExtension(item) != ".cs");
} foreach (var path in files) {
var guid = AssetDatabase.AssetPathToGUID (path);
deleteFileList.Add (guid);
}
EditorUtility.DisplayProgressBar ("checking", "collection all files", 0.2f);
UnregistReferenceFromResources(); EditorUtility.DisplayProgressBar ("checking", "check reference from resources", 0.4f);
UnregistReferenceFromScenes(); EditorUtility.DisplayProgressBar ("checking", "check reference from scenes", 0.6f);
if( saveEditorExtensions ){
UnregistEditorCodes();
}
} finally {
EditorUtility.ClearProgressBar ();
}
}
void UnregistReferenceFromResources()
{
var resourcesFiles = Directory.GetFiles ("Assets", "*.*", SearchOption.AllDirectories)
.Where (item => Regex.IsMatch (item, "[\\/\\\\]Resources[\\/\\\\]") == true)
.Where (item => Path.GetExtension (item) != ".meta")
.ToArray ();
foreach (var path in AssetDatabase.GetDependencies (resourcesFiles)) {
UnregistFromDelteList (AssetDatabase.AssetPathToGUID(path));
}
} void UnregistReferenceFromScenes()
{
// Exclude objects that reference from scenes.
var scenes = EditorBuildSettings.scenes
.Where (item => item.enabled == true)
.Select (item => item.path)
.ToArray ();
foreach (var path in AssetDatabase.GetDependencies (scenes)) {
if( saveEditorExtensions == false ){
Debug.Log(path);
}
UnregistFromDelteList (AssetDatabase.AssetPathToGUID(path));
}
} void UnregistEditorCodes()
{
// Exclude objects that reference from Editor API
var editorcodes = Directory.GetFiles ("Assets", "*.cs", SearchOption.AllDirectories)
.Where (item => Regex.IsMatch (item, "[\\/\\\\]Editor[\\/\\\\]") == true)
.ToArray (); var undeleteClassList = classCollection.codeFileList
.Where (codefile => codefile.Value.Any( guid => deleteFileList.Contains(guid)) == false)
.Select( item => item.Key ); EditorUtility.DisplayProgressBar ("checking", "check reference from editor codes", 0.8f); foreach (var path in editorcodes) {
var code = File.ReadAllText (path);
code = Regex.Replace(code, "//.*[\\n\\r]", "");
code = Regex.Replace(code, "/\\*.*[\\n\\r]\\*/", "");
if (Regex.IsMatch (code, "(\\[MenuItem|AssetPostprocessor|EditorWindow)")) {
UnregistFromDelteList ( AssetDatabase.AssetPathToGUID(path));
continue;
} foreach (var undeleteClass in undeleteClassList) {
if (Regex.IsMatch (code, string.Format ("\\[CustomEditor.*\\(\\s*{0}\\s*\\).*\\]", undeleteClass.Name))) {
UnregistFromDelteList (path);
continue;
}
}
}
} void UnregistFromDelteList (string guid)
{
if (deleteFileList.Contains (guid) == false) {
return;
}
deleteFileList.Remove (guid); if (classCollection.references.ContainsKey (guid) == true) { foreach (var type in classCollection.references[guid]) {
var codePaths = classCollection.codeFileList [type];
foreach( var codePath in codePaths){
UnregistFromDelteList (codePath);
}
}
} if (shaderCollection.shaderFileList.ContainsValue (guid)) {
var shader = shaderCollection.shaderFileList.First (item => item.Value == guid);
var shaderAssets = shaderCollection.shaderReferenceList [shader.Key];
foreach (var shaderPath in shaderAssets) {
UnregistFromDelteList (shaderPath);
}
}
}
}
}
AssetCollector
/**
asset cleaner
Copyright (c) 2015 Tatsuhiko Yamamura This software is released under the MIT License.
http://opensource.org/licenses/mit-license.php
*/
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System.Text.RegularExpressions;
using UnityEditor;
using System.IO;
using System.Reflection;
using System.Linq; namespace AssetClean
{
public class ClassReferenceCollection
{
// type : guid
public Dictionary<System.Type, List<string>> codeFileList = new Dictionary<System.Type, List<string>> ();
// guid : types
public Dictionary<string, List<System.Type>> references = new Dictionary<string, List<System.Type>> (); public void Collection ()
{
references.Clear ();
EditorUtility.DisplayProgressBar ("checking", "collection all type", ); // Connect the files and class.
var codes = Directory.GetFiles ("Assets", "*.cs", SearchOption.AllDirectories);
// connect each classes.
var firstPassList = new List<string>();
if( Directory.Exists ("Assets/Plugins") )
firstPassList.AddRange( Directory.GetFiles ("Assets/Plugins", "*.cs", SearchOption.AllDirectories));
if( Directory.Exists ("Assets/Standard Assets") )
firstPassList.AddRange( Directory.GetFiles ("Assets/Standard Assets", "*.cs", SearchOption.AllDirectories)); var allFirstpassTypes = collectionAllFastspassClasses ();
CollectionCodeFileDictionary (allFirstpassTypes, firstPassList.ToArray()); var alltypes = CollectionAllClasses ();
CollectionCodeFileDictionary (alltypes, codes.ToArray());
alltypes.AddRange (allFirstpassTypes); int count = ;
foreach (var codepath in firstPassList) {
CollectionReferenceClasses (AssetDatabase.AssetPathToGUID (codepath), allFirstpassTypes);
EditorUtility.DisplayProgressBar ("checking", "analytics codes", ((float)++count / codes.Length) * 0.5f + 0.5f);
}
count = ;
foreach (var codepath in codes) {
CollectionReferenceClasses (AssetDatabase.AssetPathToGUID (codepath), alltypes);
EditorUtility.DisplayProgressBar ("checking", "analytics codes", ((float)++count / codes.Length) * 0.5f);
}
} void CollectionCodeFileDictionary (List<System.Type> alltypes, string[] codes)
{
float count = ;
foreach (var codePath in codes) {
EditorUtility.DisplayProgressBar ("checking", "search files", count++ / codes.Length); // connect file and classes.
var code = System.IO.File.ReadAllText (codePath);
code = Regex.Replace(code, "//.*[\\n\\r]", "");
code = Regex.Replace(code, "/\\*.*[\\n\\r]\\*/", ""); foreach (var type in alltypes) { if( codeFileList.ContainsKey(type ) == false ){
codeFileList.Add(type, new List<string>());
}
var list = codeFileList[type]; if (string.IsNullOrEmpty (type.Namespace) == false) {
var namespacepattern = string.Format ("namespace[\\s.]{0}[{{\\s\\n]", type.Namespace);
if (Regex.IsMatch (code, namespacepattern) == false) {
continue;
}
} string typeName = type.IsGenericTypeDefinition ? type.GetGenericTypeDefinition ().Name.Split ('`') [] : type.Name;
if (Regex.IsMatch (code, string.Format ("class\\s*{0}?[\\s:<{{]", typeName))) {
list.Add( AssetDatabase.AssetPathToGUID(codePath) );
continue;
} if (Regex.IsMatch (code, string.Format ("struct\\s*{0}[\\s:<{{]", typeName))) {
list.Add( AssetDatabase.AssetPathToGUID(codePath) );
continue;
} if (Regex.IsMatch (code, string.Format ("enum\\s*{0}[\\s{{]", type.Name))) {
list.Add( AssetDatabase.AssetPathToGUID(codePath) );
continue;
} if (Regex.IsMatch (code, string.Format ("delegate\\s*{0}\\s\\(", type.Name))) {
list.Add( AssetDatabase.AssetPathToGUID(codePath) );
continue;
}
}
}
} List<System.Type> CollectionAllClasses ()
{
List<System.Type> alltypes = new List<System.Type> (); if (File.Exists ("Library/ScriptAssemblies/Assembly-CSharp.dll"))
alltypes.AddRange (Assembly.LoadFile ("Library/ScriptAssemblies/Assembly-CSharp.dll").GetTypes ());
if (File.Exists ("Library/ScriptAssemblies/Assembly-CSharp-Editor.dll"))
alltypes.AddRange (Assembly.LoadFile ("Library/ScriptAssemblies/Assembly-CSharp-Editor.dll").GetTypes ()); return alltypes .ToList ();
} List<System.Type> collectionAllFastspassClasses()
{
List<System.Type> alltypes = new List<System.Type> ();
if (File.Exists ("Library/ScriptAssemblies/Assembly-CSharp-firstpass.dll"))
alltypes.AddRange (Assembly.LoadFile ("Library/ScriptAssemblies/Assembly-CSharp-firstpass.dll").GetTypes ());
if (File.Exists ("Library/ScriptAssemblies/Assembly-CSharp-Editor-firstpass.dll"))
alltypes.AddRange (Assembly.LoadFile ("Library/ScriptAssemblies/Assembly-CSharp-Editor-firstpass.dll").GetTypes ());
return alltypes;
} void CollectionReferenceClasses (string guid, List<System.Type> types)
{
var codePath = AssetDatabase.GUIDToAssetPath(guid);
if (string.IsNullOrEmpty (codePath) || references.ContainsKey (guid) || File.Exists(codePath)==false) {
return;
} var code = System.IO.File.ReadAllText (codePath);
code = Regex.Replace(code, "//.*[\\n\\r]", "");
code = Regex.Replace(code, "/\\*.*[\\n\\r]\\*/", ""); var list = new List<System.Type> ();
references [guid] = list; foreach (var type in types) { if (string.IsNullOrEmpty (type.Namespace) == false) {
var namespacepattern = string.Format ("[namespace|using][\\s\\.]{0}[{{\\s\\r\\n\\r;]", type.Namespace);
if (Regex.IsMatch (code, namespacepattern) == false) {
continue;
}
} if (codeFileList.ContainsKey (type) == false) {
continue;
} string match = string.Empty;
if (type.IsGenericTypeDefinition) {
string typeName = type.GetGenericTypeDefinition ().Name.Split ('`') [];
match = string.Format ("[\\]\\[\\.\\s<(]{0}[\\.\\s\\n\\r>,<(){{]", typeName);
} else {
match = string.Format ("[\\]\\[\\.\\s<(]{0}[\\.\\s\\n\\r>,<(){{\\]]", type.Name.Replace("Attribute", ""));
}
if (Regex.IsMatch (code, match)) {
list.Add (type);
var typeGuid = codeFileList[type];
foreach( var referenceGuid in typeGuid){
CollectionReferenceClasses (referenceGuid, types);
}
}
}
}
}
}
ClassReferenceCollection
/**
asset cleaner
Copyright (c) 2015 Tatsuhiko Yamamura This software is released under the MIT License.
http://opensource.org/licenses/mit-license.php
*/
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using UnityEditor;
using System.IO;
using System.Linq; namespace AssetClean
{
public class FindUnusedAssets : EditorWindow
{
AssetCollector collection = new AssetCollector ();
List<DeleteAsset> deleteAssets = new List<DeleteAsset> ();
Vector2 scroll; [MenuItem("Assets/Delete Unused Assets/only resource", false, )]
static void InitWithoutCode ()
{
var window = FindUnusedAssets.CreateInstance<FindUnusedAssets> ();
window.collection.useCodeStrip = false;
window.collection.Collection ();
window.CopyDeleteFileList (window.collection.deleteFileList); window.Show ();
} [MenuItem("Assets/Delete Unused Assets/unused by editor", false, )]
static void InitWithout ()
{
var window = FindUnusedAssets.CreateInstance<FindUnusedAssets> ();
window.collection.Collection ();
window.CopyDeleteFileList (window.collection.deleteFileList); window.Show ();
} [MenuItem("Assets/Delete Unused Assets/unused by game", false, )]
static void Init ()
{
var window = FindUnusedAssets.CreateInstance<FindUnusedAssets> ();
window.collection.saveEditorExtensions = false;
window.collection.Collection ();
window.CopyDeleteFileList (window.collection.deleteFileList); window.Show ();
} void OnGUI ()
{
using (var horizonal = new EditorGUILayout.HorizontalScope("box")) {
EditorGUILayout.LabelField ("delete unreference assets from buildsettings and resources"); if (GUILayout.Button ("Delete", GUILayout.Width (), GUILayout.Height ()) && deleteAssets.Count != ) {
RemoveFiles ();
Close ();
}
} using (var scrollScope = new EditorGUILayout.ScrollViewScope(scroll)) {
scroll = scrollScope.scrollPosition;
foreach (var asset in deleteAssets) {
if (string.IsNullOrEmpty (asset.path)) {
continue;
} using (var horizonal = new EditorGUILayout.HorizontalScope()) {
asset.isDelete = EditorGUILayout.Toggle (asset.isDelete, GUILayout.Width ());
var icon = AssetDatabase.GetCachedIcon (asset.path);
GUILayout.Label (icon, GUILayout.Width (), GUILayout.Height ());
if (GUILayout.Button (asset.path, EditorStyles.largeLabel)) {
Selection.activeObject = AssetDatabase.LoadAssetAtPath<Object> (asset.path);
}
}
}
} } static void CleanDir()
{
RemoveEmptyDirectry ("Assets");
AssetDatabase.Refresh ();
} void CopyDeleteFileList(IEnumerable<string> deleteFileList)
{
foreach (var asset in deleteFileList) {
var filePath = AssetDatabase.GUIDToAssetPath (asset);
if (string.IsNullOrEmpty (filePath) == false) {
deleteAssets.Add (new DeleteAsset (){ path = filePath});
}
}
} void RemoveFiles ()
{
try {
string exportDirectry = "BackupUnusedAssets";
Directory.CreateDirectory (exportDirectry);
var files = deleteAssets.Where (item => item.isDelete == true).Select (item => item.path).ToArray ();
string backupPackageName = exportDirectry + "/package" + System.DateTime.Now.ToString ("yyyyMMddHHmmss") + ".unitypackage";
EditorUtility.DisplayProgressBar ("export package", backupPackageName, );
AssetDatabase.ExportPackage (files, backupPackageName); int i = ;
int length = deleteAssets.Count; foreach (var assetPath in files) {
i++;
EditorUtility.DisplayProgressBar ("delete unused assets", assetPath, (float)i / length);
AssetDatabase.DeleteAsset (assetPath);
} EditorUtility.DisplayProgressBar ("clean directory", "", );
foreach (var dir in Directory.GetDirectories("Assets")) {
RemoveEmptyDirectry (dir);
} System.Diagnostics.Process.Start (exportDirectry); AssetDatabase.Refresh ();
}
catch( System.Exception e ){
Debug.Log(e.Message);
}finally {
EditorUtility.ClearProgressBar ();
}
} static void RemoveEmptyDirectry (string path)
{
var dirs = Directory.GetDirectories (path);
foreach (var dir in dirs) {
RemoveEmptyDirectry (dir);
} var files = Directory.GetFiles (path, "*", SearchOption.TopDirectoryOnly).Where (item => Path.GetExtension (item) != ".meta");
if (files.Count () == && Directory.GetDirectories (path).Count () == ) {
var metaFile = AssetDatabase.GetTextMetaFilePathFromAssetPath(path);
UnityEditor.FileUtil.DeleteFileOrDirectory (path);
UnityEditor.FileUtil.DeleteFileOrDirectory (metaFile);
}
} class DeleteAsset
{
public bool isDelete = true;
public string path;
}
}
}
FindUnusedAssets
/**
asset cleaner
Copyright (c) 2015 Tatsuhiko Yamamura This software is released under the MIT License.
http://opensource.org/licenses/mit-license.php
*/
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Text.RegularExpressions;
using UnityEditor; namespace AssetClean
{
public class ShaderReferenceCollection
{
// shader name / shader file guid
public Dictionary<string, string> shaderFileList = new Dictionary<string, string> ();
public Dictionary<string, List<string> > shaderReferenceList = new Dictionary<string, List<string>> (); public void Collection ()
{
CollectionShaderFiles ();
CheckReference ();
} void CollectionShaderFiles ()
{
var shaderFiles = Directory.GetFiles ("Assets", "*.shader", SearchOption.AllDirectories);
foreach (var shaderFilePath in shaderFiles) {
var code = File.ReadAllText (shaderFilePath);
var match = Regex.Match (code, "Shader \"(?<name>.*)\"");
if (match.Success) {
var shaderName = match.Groups ["name"].ToString ();
if (shaderFileList.ContainsKey (shaderName) == false) {
shaderFileList.Add (shaderName, AssetDatabase.AssetPathToGUID(shaderFilePath));
}
}
} var cgFiles = Directory.GetFiles ("Assets", "*.cg", SearchOption.AllDirectories);
foreach (var cgFilePath in cgFiles) {
var file = Path.GetFileName (cgFilePath);
shaderFileList.Add (file, cgFilePath);
} var cgincFiles = Directory.GetFiles ("Assets", "*.cginc", SearchOption.AllDirectories);
foreach (var cgincPath in cgincFiles) {
var file = Path.GetFileName (cgincPath);
shaderFileList.Add (file, cgincPath);
}
} void CheckReference ()
{
foreach (var shader in shaderFileList) {
var shaderFilePath = AssetDatabase.GUIDToAssetPath(shader.Value);
var shaderName = shader.Key; List<string> referenceList = new List<string> ();
shaderReferenceList.Add (shaderName, referenceList); var code = File.ReadAllText (shaderFilePath); foreach (var checkingShaderName in shaderFileList.Keys) {
if (Regex.IsMatch (code, string.Format ("{0}", checkingShaderName))) {
var filePath = shaderFileList [checkingShaderName];
referenceList.Add (filePath);
}
}
}
}
}
}
ShaderReferenceCollection
下载地址:https://github.com/unity-cn/Tool-UnityAssetCleaner
使用:Unity导航菜单栏中选择 Assets-> Delete Unused Assets
三种模式,选择一个合适的,然后点击Delete,轻松搞定
unity 自动删除未引用的Assets下的资源的更多相关文章
- android中拷贝assets下的资源文件到SD卡中(可以超过1M)
很多手机游戏,在安装APK之后都得需要下载相应的资源包,然后才能进入游戏. 有这样一个需求:就是游戏中需要的资源包打在APK内,随apk一起进行安装到手机中. 这样就不需要,在安装APK之后,去下载资 ...
- Android -- 拷贝assets下的资源文件到SD卡中(可以超过1M)
很多手机游戏,在安装APK之后都得需要下载相应的资源包,然后才能进入游戏. 有这样一个需求:就是游戏中需要的资源包打在APK内,随apk一起进行安装到手机中. 这样就不需要,在安装APK之后,去下载资 ...
- Android 读取Assets下的资源文件
做Android开发近半年了,东西越学越多,硬盘容量越来越小.很多东西找起来也不方便,为此,我打算从今天起把工作中学到的东西整理起来,写成日记.也希望与广大网友分享我的经验.一同进步.今天主要介绍文件 ...
- WordPress教程之如何批量删除未引用(无用)的TAG标签
WordPress文章与标签的关系 在WordPress中添加标签是非常方便的,只需要在写文章时在侧栏标签处添加一下就会自动在后台增加标签(所以你是不是也跟缙哥哥一样每篇文章都增加标签呢),不像分类目 ...
- 自动删除Android工程中无用的资源
开发时间久了, 几个版本迭代之后, 工程中难免留下很多垃圾资源, 造成apk的包很大, 这里介绍一个工具, 可以自动扫描工程中, 没有使用的资源, 然后自动删除: 包括图片, xml, 文本等. 采用 ...
- Qt之QTemporaryFile(文件名唯一,且可以自动删除)
简述 QTemporaryFile类是操作临时文件的I/O设备. QTemporaryFile用于安全地创建一个独一无二的临时文件.临时文件通过调用open()来创建,并且名称是唯一的(即:保证不覆盖 ...
- assets下的文件复制到SD卡
由于assets和res下的文件都只可以读不可以写,那么在程序初始化后,将后期需要使用并且需要修改的文件复制到SD卡.下面代码提供一个工具类,将assets下的任意资源复制到SD卡下. assets下 ...
- Android(java)学习笔记135:Android中assets文件夹资源的访问
Android资源文件分类: Android资源文件大致可以分为两种: 第一种是res目录下存放的可编译的资源文件: 这种资源文件系统会在R.java里面自动生成该资源文件的ID,所以访问这种资源文件 ...
- Android(java)学习笔记77:Android中assets文件夹资源的访问
Android资源文件分类: Android资源文件大致可以分为两种: 第一种是res目录下存放的可编译的资源文件: 这种资源文件系统会在R.java里面自动生成该资源文件的ID,所以访问这种资源文件 ...
随机推荐
- 终于意识到BIM确实火了
碰巧遇到一个BIM会议.一大帮国内的老师桠桠叉叉坐了一大屋.听了半天感觉都是在吹BIM如何火.第一次听到这个概念感觉这个能火吗. 昨天雄安新区用BIM建设的新闻出来后,一下子惊了.看来BIM进入计算机 ...
- 浅谈Android和IOS系统的差异
总结:事件响应级别.GPU加速.进程前后台.代码运行速度.内存管理机制. 进程管理机制.内存管理机制.cpu效率.GPU加速.事件响应级别. 1. 渲染机制不同 IOS的UI渲染采用实时优先级, ...
- swift语言点评五-Function
一.函数类型 Every function in Swift has a type, consisting of the function’s parameter types and return t ...
- 人工智能,你到底是天使or魔鬼?
人工智能的概念早在60多年前就被提出,但又一度沉寂.随着谷歌人工智能程序AlphaGo(阿尔法狗)战胜围棋世界冠军李世石,再次为世人瞩目.然而,与无限风光一起相伴而来的,还有关于人工智能的种种争议! ...
- ubuntu 装tensorflow出现 conda install ERROR missing write permission错误
通过搜索tensorflow然后运行,例如:$ conda install --channel https://conda.anaconda.org/jjh_cio_testing tensorflo ...
- tree 核心命令参数
常用参数: -a 显示所有文件 包括隐藏文件 -d 只显示目录 -f 显示每个文件的全路径 -i 不显示树枝 常与-f一起搭配 -L 显示的层数 -F 区分哪个文件是目录 [root@ftp:/va ...
- /lib64和/usr/lib64和/usr/local/lib64的区别
简单说,/lib64是内核级的,/usr/lib64是系统级的,/usr/local/lib64是用户级的. /lib/ — 包含许多被 /bin/ 和 /sbin/ 中的程序使用的库文件.目录 /u ...
- 每个人都能实现的vue自定义指令
前文 先来bb一堆废话哈哈.. 用vue做项目也有一年多了.除了用别人的插件之外.自己也没尝试去封装指令插件之类的东西来用. 刚好最近在项目中遇到一个问题.(快速点击按钮多次触发多次绑定的方法),于是 ...
- [luogu] P2787 语文1(chin1)- 理理思维(分块)
P2787 语文1(chin1)- 理理思维 题目背景 蒟蒻HansBug在语文考场上,挠了无数次的头,可脑子里还是一片空白. 题目描述 考试开始了,可是蒟蒻HansBug脑中还是一片空白.哦不!准确 ...
- 小A点菜 水题 dp 背包
基本上还是01背包,首先注意必须正好花光钱,所以初始化时除了dp[0]以外其他都要设置成inf,然后因为求方案数,所以基本方程为dp[i] = dp[i-x] + dp[i],再根据inf进行一些特殊 ...