595 lines
21 KiB
C#
595 lines
21 KiB
C#
using System;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using BundleV2;
|
|
using UnityEditor;
|
|
using UnityEngine;
|
|
using UnityEngine.SceneManagement;
|
|
using Object = UnityEngine.Object;
|
|
|
|
/// <summary>
|
|
/// 通用的资源配置清理以及资源修改的类型
|
|
/// </summary>
|
|
public static class PurgeAssets
|
|
{
|
|
[MenuItem("Bundle V2/Purge/Audio")]
|
|
public static void PurgeAudio()
|
|
{
|
|
var audioList = (from assetPath in AssetDatabase.GetAllAssetPaths()
|
|
where assetPath.StartsWith(AssetConst.nonInternalHeader)
|
|
where EditorAssetConst.audioExtensions.Contains(Path.GetExtension(assetPath))
|
|
let importer = AssetImporter.GetAtPath(assetPath) as AudioImporter
|
|
where importer
|
|
select importer).ToArray();
|
|
var count = 0;
|
|
for (var i = 0; i < audioList.Length; i++)
|
|
{
|
|
EditorUtility.DisplayProgressBar("Purge Audio", string.Format("{0} / {1}", i + 1, audioList.Length),
|
|
(float) i / audioList.Length);
|
|
var audioImporter = audioList[i];
|
|
var dirty = false;
|
|
var defaultSettings = audioImporter.defaultSampleSettings;
|
|
var audioClip = AssetDatabase.LoadAssetAtPath<AudioClip>(audioImporter.assetPath);
|
|
// 音乐或者环境音效
|
|
if (audioClip.length > 10f)
|
|
{
|
|
if (defaultSettings.compressionFormat != AudioCompressionFormat.Vorbis)
|
|
{
|
|
dirty = true;
|
|
defaultSettings.compressionFormat = AudioCompressionFormat.Vorbis;
|
|
}
|
|
|
|
if (defaultSettings.loadType != AudioClipLoadType.Streaming)
|
|
{
|
|
dirty = true;
|
|
defaultSettings.loadType = AudioClipLoadType.Streaming;
|
|
}
|
|
}
|
|
// 持续类技能或者语音
|
|
else if (audioClip.length > 3f)
|
|
{
|
|
if (defaultSettings.compressionFormat != AudioCompressionFormat.ADPCM)
|
|
{
|
|
dirty = true;
|
|
defaultSettings.compressionFormat = AudioCompressionFormat.ADPCM;
|
|
}
|
|
|
|
if (defaultSettings.loadType != AudioClipLoadType.CompressedInMemory)
|
|
{
|
|
dirty = true;
|
|
defaultSettings.loadType = AudioClipLoadType.CompressedInMemory;
|
|
}
|
|
}
|
|
// 瞬发技能
|
|
else
|
|
{
|
|
if (defaultSettings.compressionFormat != AudioCompressionFormat.ADPCM)
|
|
{
|
|
dirty = true;
|
|
defaultSettings.compressionFormat = AudioCompressionFormat.ADPCM;
|
|
}
|
|
|
|
if (defaultSettings.loadType != AudioClipLoadType.DecompressOnLoad)
|
|
{
|
|
dirty = true;
|
|
defaultSettings.loadType = AudioClipLoadType.DecompressOnLoad;
|
|
}
|
|
}
|
|
|
|
if (defaultSettings.quality != 0.7f)
|
|
{
|
|
dirty = true;
|
|
defaultSettings.quality = 0.7f;
|
|
}
|
|
|
|
if (dirty)
|
|
{
|
|
count++;
|
|
audioImporter.defaultSampleSettings = defaultSettings;
|
|
audioImporter.SaveAndReimport();
|
|
}
|
|
}
|
|
|
|
EditorUtility.ClearProgressBar();
|
|
Debug.LogWarning(string.Format("Purge Audio process on {0} files!", count));
|
|
}
|
|
|
|
[MenuItem("ProTool/PurgeAssets/NormalMap", false, 4)]
|
|
public static void PurgeNormalMaps()
|
|
{
|
|
FixRgb();
|
|
}
|
|
|
|
[MenuItem("Bundle V2/Purge/Materials")]
|
|
public static void PurgeMaterials()
|
|
{
|
|
var materialPaths = (from materialPath in AssetDatabase.GetAllAssetPaths()
|
|
where materialPath.IsCommonAssetPath()
|
|
where ".mat".Equals(Path.GetExtension(materialPath), StringComparison.OrdinalIgnoreCase)
|
|
select materialPath).ToArray();
|
|
for (var i = 0; i < materialPaths.Length; i++)
|
|
{
|
|
var materialPath = materialPaths[i];
|
|
EditorUtility.DisplayProgressBar("Purge Material " + materialPath,
|
|
string.Format("{0} / {1}", i, materialPaths.Length), (float) i / materialPaths.Length);
|
|
var material = AssetDatabase.LoadAssetAtPath<Material>(materialPath);
|
|
if (material != null)
|
|
PurgeOneMaterial(material);
|
|
}
|
|
|
|
EditorUtility.ClearProgressBar();
|
|
AssetDatabase.SaveAssets();
|
|
AssetDatabase.Refresh();
|
|
}
|
|
|
|
[MenuItem("ProTool/PurgeAssets/Components/Start", false, 4)]
|
|
public static void PurgeComponentsStart()
|
|
{
|
|
var action = new PurgeComponentAction(false);
|
|
action.Start();
|
|
}
|
|
|
|
[MenuItem("ProTool/PurgeAssets/Components/Continue", false, 4)]
|
|
public static void PurgeComponentsDelta()
|
|
{
|
|
var action = new PurgeComponentAction(true);
|
|
action.Start();
|
|
}
|
|
|
|
[MenuItem("ProTool/PurgeAssets/PlatformSettings", false, 4)]
|
|
public static void PurgePlatformSettings()
|
|
{
|
|
var action = new PurgeTexturePlatform();
|
|
action.Start();
|
|
}
|
|
|
|
[MenuItem("ProTool/PurgeAssets/AssetNames", false, 4)]
|
|
public static void PurgeAssetNames()
|
|
{
|
|
var assetPaths = (from assetPath in AssetDatabase.GetAllAssetPaths()
|
|
where assetPath.IsCommonAssetPath()
|
|
let extension = Path.GetExtension(assetPath)
|
|
where !string.IsNullOrEmpty(extension) &&
|
|
!extension.Equals(".cs")
|
|
let fileName = Path.GetFileName(assetPath)
|
|
where !string.IsNullOrEmpty(fileName) &&
|
|
fileName.Contains(' ')
|
|
select fileName).ToArray();
|
|
for (var i = 0; i < assetPaths.Length; i++)
|
|
{
|
|
var assetPath = assetPaths[i];
|
|
var dir = assetPath.MoveUp();
|
|
var fileName = assetPath.Substring(dir.Length);
|
|
fileName = fileName.Replace(' ', '_');
|
|
fileName = dir.Open(fileName);
|
|
AssetDatabase.MoveAsset(assetPath, fileName);
|
|
}
|
|
}
|
|
|
|
[MenuItem("Bundle V2/Purge/Mesh Materials")]
|
|
public static void PurgeMeshMaterials()
|
|
{
|
|
var meshMaterialAction = new PurgeMeshMaterialAction();
|
|
meshMaterialAction.Start();
|
|
}
|
|
|
|
[MenuItem("Scene/Purge Components", false, 4)]
|
|
public static void PurgeSceneComponents()
|
|
{
|
|
var rootObjects = SceneManager.GetActiveScene().GetRootGameObjects();
|
|
for (var i = 0; i < rootObjects.Length; i++)
|
|
{
|
|
var rootObject = rootObjects[i];
|
|
PurgeOneGameObject(rootObject.transform);
|
|
}
|
|
}
|
|
|
|
private static bool ParticleHasExtraMaterial(ParticleSystemRenderer particle)
|
|
{
|
|
var result = false;
|
|
for (var i = 2; i < particle.sharedMaterials.Length; i++)
|
|
if (particle.sharedMaterials[i] == null)
|
|
{
|
|
result = true;
|
|
break;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
private static bool ParticleNotFunctional(ParticleSystemRenderer renderer, ParticleSystem particle)
|
|
{
|
|
var result = renderer.sharedMaterial == null;
|
|
if (result)
|
|
result = !particle.emission.enabled;
|
|
return result;
|
|
}
|
|
|
|
public static bool PurgeOneGameObject(string assetPath)
|
|
{
|
|
var result = false;
|
|
var prefab = AssetDatabase.LoadAssetAtPath<GameObject>(assetPath);
|
|
if (prefab != null)
|
|
{
|
|
var instance = Object.Instantiate(prefab);
|
|
if (PurgeOneGameObject(instance.transform))
|
|
{
|
|
result = true;
|
|
Debug.LogWarning("Purge Successful at " + assetPath);
|
|
PrefabUtility.ReplacePrefab(instance, prefab, ReplacePrefabOptions.ReplaceNameBased);
|
|
}
|
|
else
|
|
{
|
|
EditorUtility.SetDirty(prefab);
|
|
}
|
|
|
|
Object.DestroyImmediate(instance);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
public static bool PurgeOneGameObject(Transform root)
|
|
{
|
|
var components = root.GetComponents<Component>();
|
|
var componentDirty = false;
|
|
for (var i = 0; i < components.Length; i++)
|
|
if (components[i] == null)
|
|
{
|
|
componentDirty = true;
|
|
break;
|
|
}
|
|
|
|
if (componentDirty)
|
|
{
|
|
var serializedObject = new SerializedObject(root.gameObject);
|
|
var property = serializedObject.FindProperty("m_Component");
|
|
if (property.isArray && property.arraySize == components.Length)
|
|
{
|
|
for (var i = components.Length - 1; i >= 0; i--)
|
|
if (components[i] == null)
|
|
property.DeleteArrayElementAtIndex(i);
|
|
}
|
|
else
|
|
{
|
|
Debug.LogError("异常情况 - 序列化组件数目同实际组件不匹配!");
|
|
}
|
|
|
|
serializedObject.ApplyModifiedProperties();
|
|
}
|
|
|
|
var particleDirty = false;
|
|
var particleRenderer = root.GetComponent<ParticleSystemRenderer>();
|
|
var particleSystem = root.GetComponent<ParticleSystem>();
|
|
if (particleRenderer != null && particleSystem != null)
|
|
{
|
|
if (ParticleNotFunctional(particleRenderer, particleSystem))
|
|
{
|
|
particleDirty = true;
|
|
Object.DestroyImmediate(particleSystem);
|
|
}
|
|
else
|
|
{
|
|
if (ParticleHasExtraMaterial(particleRenderer))
|
|
{
|
|
particleDirty = true;
|
|
var count = Mathf.Min(particleRenderer.sharedMaterials.Length, 2);
|
|
var array = new Material[count];
|
|
for (var j = 0; j < count; j++)
|
|
array[j] = particleRenderer.sharedMaterials[j];
|
|
particleRenderer.sharedMaterials = array;
|
|
}
|
|
|
|
if (particleRenderer.renderMode != ParticleSystemRenderMode.Mesh && particleRenderer.mesh != null)
|
|
{
|
|
particleDirty = true;
|
|
particleRenderer.mesh = null;
|
|
}
|
|
}
|
|
}
|
|
|
|
var dirty = componentDirty || particleDirty;
|
|
foreach (Transform child in root)
|
|
if (PurgeOneGameObject(child))
|
|
dirty = true;
|
|
return dirty;
|
|
}
|
|
|
|
public static void PurgeOneMaterial(Material material)
|
|
{
|
|
if (material.shader != null)
|
|
{
|
|
var shaderPropertiesCount = ShaderUtil.GetPropertyCount(material.shader);
|
|
var shaderProperties = new string[shaderPropertiesCount];
|
|
for (var i = 0; i < shaderPropertiesCount; i++)
|
|
shaderProperties[i] = ShaderUtil.GetPropertyName(material.shader, i);
|
|
var serializedObject = new SerializedObject(material);
|
|
// ReSharper disable once ReplaceWithSingleAssignment.False
|
|
var dirty = false;
|
|
if (PurgeOneMaterialProperty(serializedObject, shaderProperties, "m_SavedProperties.m_TexEnvs"))
|
|
dirty = true;
|
|
if (PurgeOneMaterialProperty(serializedObject, shaderProperties, "m_SavedProperties.m_Floats"))
|
|
dirty = true;
|
|
if (PurgeOneMaterialProperty(serializedObject, shaderProperties, "m_SavedProperties.m_Colors"))
|
|
dirty = true;
|
|
if (dirty)
|
|
{
|
|
Debug.LogWarning("Purge Material " + AssetDatabase.GetAssetPath(material));
|
|
serializedObject.ApplyModifiedProperties();
|
|
}
|
|
|
|
EditorUtility.SetDirty(material);
|
|
}
|
|
}
|
|
|
|
private static bool PurgeOneMaterialProperty(SerializedObject serializedObject, string[] allowProperties,
|
|
string propertyName)
|
|
{
|
|
var dirty = false;
|
|
var properties = serializedObject.FindProperty(propertyName);
|
|
if (properties != null && properties.isArray)
|
|
for (var i = properties.arraySize - 1; i >= 0; i--)
|
|
{
|
|
var propName = properties.GetArrayElementAtIndex(i).displayName;
|
|
var exist = allowProperties.Contain(propName);
|
|
if (!exist)
|
|
{
|
|
dirty = true;
|
|
properties.DeleteArrayElementAtIndex(i);
|
|
}
|
|
}
|
|
|
|
return dirty;
|
|
}
|
|
|
|
public static void FixRgb()
|
|
{
|
|
var pngPaths = (from path in AssetDatabase.GetAllAssetPaths()
|
|
let extension = Path.GetExtension(path)
|
|
where !string.IsNullOrEmpty(extension) &&
|
|
extension.Equals(".png", StringComparison.InvariantCultureIgnoreCase)
|
|
select path).ToArray();
|
|
var helper = new DtxNormalFix(pngPaths);
|
|
helper.Start();
|
|
}
|
|
|
|
private class DtxNormalFix
|
|
{
|
|
private readonly string[] _pngPaths;
|
|
private int _index;
|
|
|
|
public DtxNormalFix(string[] paths)
|
|
{
|
|
_pngPaths = paths;
|
|
}
|
|
|
|
public void Start()
|
|
{
|
|
_index = 0;
|
|
EditorApplication.update += OnEditorUpdate;
|
|
}
|
|
|
|
private void OnEditorUpdate()
|
|
{
|
|
try
|
|
{
|
|
if (_index < _pngPaths.Length)
|
|
{
|
|
var path = _pngPaths[_index];
|
|
NormalConvert.ConvertOneNormal(path);
|
|
_index++;
|
|
Debug.LogWarning("Finish " + _index + " / " + _pngPaths.Length);
|
|
}
|
|
else
|
|
{
|
|
Debug.LogWarning("Finish All");
|
|
EditorApplication.update = null;
|
|
}
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
Debug.LogError(e.ToString());
|
|
EditorApplication.update = null;
|
|
}
|
|
}
|
|
}
|
|
|
|
private class PurgeComponentAction : EditorPerFrameActionBase
|
|
{
|
|
private const string _deltaKey = "PurgeComponent";
|
|
private readonly string[] _assetPaths;
|
|
private int _index;
|
|
|
|
public PurgeComponentAction(bool useDelta)
|
|
{
|
|
_assetPaths = (from assetPath in AssetDatabase.GetAllAssetPaths()
|
|
where assetPath.IsCommonAssetPath()
|
|
where ".prefab".Equals(Path.GetExtension(assetPath))
|
|
orderby assetPath
|
|
select assetPath).ToArray();
|
|
if (useDelta)
|
|
_index = PlayerPrefs.GetInt(_deltaKey, default(int));
|
|
else
|
|
PlayerPrefs.SetInt(_deltaKey, _index);
|
|
}
|
|
|
|
protected override int GetCurrentIndex()
|
|
{
|
|
return _index;
|
|
}
|
|
|
|
protected override int GetTotalCount()
|
|
{
|
|
return _assetPaths.Length;
|
|
}
|
|
|
|
protected override void PerFrameAction()
|
|
{
|
|
var assetPath = _assetPaths[_index];
|
|
if (PurgeOneGameObject(assetPath))
|
|
{
|
|
AssetDatabase.SaveAssets();
|
|
AssetDatabase.Refresh();
|
|
// 需要高密度的清空,防止溢出
|
|
Resources.UnloadUnusedAssets();
|
|
}
|
|
|
|
PlayerPrefs.SetInt(_deltaKey, _index);
|
|
_index++;
|
|
}
|
|
}
|
|
|
|
private class PurgeTexturePlatform : EditorPerFrameActionBase
|
|
{
|
|
private readonly string[] _assetPaths;
|
|
private int _index;
|
|
|
|
public PurgeTexturePlatform()
|
|
{
|
|
_assetPaths = (from assetPath in AssetDatabase.GetAllAssetPaths()
|
|
where assetPath.IsCommonAssetPath()
|
|
let assetType = AssetDatabase.GetMainAssetTypeAtPath(assetPath)
|
|
where assetType == typeof(Texture2D) || assetType == typeof(Sprite)
|
|
select assetPath).ToArray();
|
|
}
|
|
|
|
protected override int GetCurrentIndex()
|
|
{
|
|
return _index;
|
|
}
|
|
|
|
protected override int GetTotalCount()
|
|
{
|
|
return _assetPaths.Length;
|
|
}
|
|
|
|
protected override void PerFrameAction()
|
|
{
|
|
var assetPath = _assetPaths[_index];
|
|
_index++;
|
|
var importer = AssetImporter.GetAtPath(assetPath) as TextureImporter;
|
|
if (importer != null)
|
|
{
|
|
importer.ClearPlatformTextureSettings(PlatformName.GetCurrentPlatformName());
|
|
importer.SaveAndReimport();
|
|
}
|
|
}
|
|
}
|
|
|
|
private class PurgeMeshMaterialAction : EditorPerFrameActionBase
|
|
{
|
|
private readonly string[] _assetPaths;
|
|
private readonly Material _dummy;
|
|
private int _count;
|
|
private int _index;
|
|
|
|
public PurgeMeshMaterialAction()
|
|
{
|
|
_assetPaths = (from assetPath in AssetDatabase.GetAllAssetPaths()
|
|
where assetPath.StartsWith(AssetConst.nonInternalHeader)
|
|
where AssetConst.modelExtension.Equals(Path.GetExtension(assetPath),
|
|
StringComparison.OrdinalIgnoreCase)
|
|
select assetPath).ToArray();
|
|
_dummy = AssetDatabase.LoadAssetAtPath<Material>("Assets/Project/GameRes/Material/shadow1" +
|
|
AssetConst.materialExtension);
|
|
}
|
|
|
|
protected override int GetCurrentIndex()
|
|
{
|
|
return _index;
|
|
}
|
|
|
|
protected override int GetTotalCount()
|
|
{
|
|
return _assetPaths.Length;
|
|
}
|
|
|
|
protected override void PerFrameAction()
|
|
{
|
|
var assetPath = _assetPaths[_index];
|
|
var importer = AssetImporter.GetAtPath(assetPath) as ModelImporter;
|
|
if (importer && !importer.importMaterials)
|
|
{
|
|
_count++;
|
|
importer.importMaterials = true;
|
|
importer.materialName = ModelImporterMaterialName.BasedOnMaterialName;
|
|
importer.materialLocation = ModelImporterMaterialLocation.InPrefab;
|
|
importer.materialSearch = ModelImporterMaterialSearch.Local;
|
|
// 刷新数据,以便或者真实的材质名词
|
|
importer.SaveAndReimport();
|
|
AddRemapMaterials(importer);
|
|
Debug.LogWarning("Purge Fbx Material from not import for " + assetPath);
|
|
importer.SaveAndReimport();
|
|
Resources.UnloadUnusedAssets();
|
|
}
|
|
// else if (importer.materialLocation == ModelImporterMaterialLocation.InPrefab)
|
|
// {
|
|
// var update = false;
|
|
// if (importer.materialName != ModelImporterMaterialName.BasedOnMaterialName ||
|
|
// importer.materialSearch != ModelImporterMaterialSearch.Local)
|
|
// {
|
|
// update = true;
|
|
// }
|
|
// else
|
|
// {
|
|
// var external = importer.GetExternalObjectMap();
|
|
// foreach (var keyValue in external)
|
|
// if (keyValue.Key.type == typeof(Material))
|
|
// {
|
|
// var material = keyValue.Value as Material;
|
|
// if (material)
|
|
// {
|
|
// if (!material.shader)
|
|
// {
|
|
// update = true;
|
|
// break;
|
|
// }
|
|
//
|
|
// if (material.shader.name == "Standard")
|
|
// {
|
|
// update = true;
|
|
// break;
|
|
// }
|
|
// }
|
|
// }
|
|
// }
|
|
//
|
|
// if (update)
|
|
// {
|
|
// importer.materialName = ModelImporterMaterialName.BasedOnMaterialName;
|
|
// importer.materialSearch = ModelImporterMaterialSearch.Local;
|
|
// importer.materialLocation = ModelImporterMaterialLocation.InPrefab;
|
|
// importer.SaveAndReimport();
|
|
// AddRemapMaterials(importer);
|
|
// Debug.LogWarning("Purge Fbx Material from not dummy for " + assetPath);
|
|
// importer.SaveAndReimport();
|
|
// Resources.UnloadUnusedAssets();
|
|
// }
|
|
// }
|
|
_index++;
|
|
}
|
|
|
|
private void AddRemapMaterials(ModelImporter importer)
|
|
{
|
|
var prefab = AssetDatabase.LoadAssetAtPath<GameObject>(importer.assetPath);
|
|
var rendererArray = prefab.GetComponentsInChildren<Renderer>(true);
|
|
foreach (var renderer in rendererArray)
|
|
{
|
|
var materials = renderer.sharedMaterials;
|
|
for (var i = 0; i < materials.Length; i++)
|
|
if (materials[i])
|
|
{
|
|
var name = materials[i].name;
|
|
importer.AddRemap(
|
|
new AssetImporter.SourceAssetIdentifier(typeof(Material), name), _dummy);
|
|
}
|
|
}
|
|
}
|
|
|
|
protected override void OnFinish()
|
|
{
|
|
Debug.LogWarning("Purge Fbx Count: " + _count);
|
|
base.OnFinish();
|
|
}
|
|
}
|
|
} |