Unity拷贝预制体并修改fileId和guid

复制预制体并把依赖的其他模块资源一起复制一份到指定模块

using System.Collections.Generic;
using System.IO;
using System.Text.RegularExpressions;
using UnityEditor;
using UnityEngine;

public class CopyModulePrefabUtil : EditorWindow
{
    private static CopyModulePrefabUtil editorWindow;
    [MenuItem("Tools/拷贝模块内预制体到其他模块")]
    public static void OpenView()
    {
        if (editorWindow == null)
        {
            editorWindow = GetWindow<CopyModulePrefabUtil>("拷贝模块内预制体到其他模块");
            editorWindow.position = new Rect(300, 300, 800, 500);
        }
    }

    public class PointerData
    {
        public long fileId = 0;
        public string GUID = string.Empty;
        public PointerData(long fileId, string GUID)
        {
            this.fileId = fileId;
            this.GUID = GUID;
        }
    }

    public class RecordData
    {
        public string originalPath = string.Empty;
        public string latestPath = string.Empty;
        public AssetType assetType = AssetType.other;
        public List<PointerData> oldPointerData = new List<PointerData>();
        public List<PointerData> newPointerData = new List<PointerData>();
    }

    public enum AssetType
    {
        isTexture,
        isSprite,
        isMaterial,
        isFBX,
        isPrefab,
        isAsset,
        other
    }

    //原始预制体路径
    private string _originalPrefabPath = string.Empty;

    //要拷贝到哪里
    private string _copyToPath = string.Empty;

    private bool _overwrite = false;

    private Regex _regex = new Regex("Assets/XAssets/GameModule/[a-zA-Z0-9]*/");


    private void OnGUI()
    {
        OnDropAreaGUI();
        OnDrawOtherGUI();

    }

    private void OnDestroy()
    {
        editorWindow = null;
    }


    private void OnDrawOtherGUI()
    {
        EditorGUILayout.Space();
        _copyToPath = EditorGUILayout.TextField("拷贝到哪里:", _copyToPath);
        EditorGUILayout.Space();
        _overwrite = EditorGUILayout.Toggle("拷贝时是否覆盖已有资源:", _overwrite);
        EditorGUILayout.Space();

        if (string.IsNullOrEmpty(_originalPrefabPath))
        {
            return;
        }
        if (!Regex.IsMatch(_originalPrefabPath, "Assets/XAssets/GameModule/[a-zA-Z0-9]*/"))
        {
            EditorGUILayout.LabelField("托进来的预制体路径不符合规范,只能拷贝模块中的预制体");
            return;
        }
        if (string.IsNullOrEmpty(_copyToPath))
        {
            return;
        }
        if (!Regex.IsMatch(_copyToPath, "Assets/XAssets/GameModule/[a-zA-Z0-9]*/"))
        {
            EditorGUILayout.LabelField("填写的路径不符合规范,如:Assets/XAssets/GameModule/aaaa/");
            return;
        }

        EditorGUILayout.Space();
        if (GUILayout.Button("开始拷贝"))
        {
            CopyDependencies(_originalPrefabPath, _overwrite);
            EditorUtility.DisplayDialog("提示", "已拷贝完成,请检查是否有报错", "确认");
        }

    }
    /// <summary>
    /// 获取一个预制体依赖了哪些资源
    /// </summary>
    /// <param name="prefabPath"></param>
    /// <returns></returns>
    private List<string> GetDependencies(string prefabPath)
    {
        string[] dependencies = AssetDatabase.GetDependencies(prefabPath, true);
        List<string> strs = new List<string>();
        for (int i = 0; i < dependencies.Length; i++)
        {
            string path = dependencies[i];
            if (Regex.IsMatch(path, "Assets/XAssets/GameModule/[a-zA-Z0-9]*/") && !path.Contains("Assets/XAssets/GameModule/Common/") && !path.Contains(".cs"))
            {
                strs.Add(path);
            }
        }
        return strs;
    }

    /// <summary>
    /// 拷贝资源
    /// </summary>
    /// <param name="prefabPath"></param>
    /// <param name="overwrite"></param>
    private void CopyDependencies(string prefabPath, bool overwrite)
    {
        Dictionary<string, RecordData> recordDicts = new Dictionary<string, RecordData>();
        List<string> dependencies = GetDependencies(prefabPath);
        for (int i = 0; i < dependencies.Count; i++)
        {
            string originalPath = dependencies[i];
            string latestPath = _regex.Replace(originalPath, _copyToPath);
            FileInfo fileInfo = new FileInfo(latestPath);
            if (!Directory.Exists(fileInfo.Directory.FullName))
            {
                Directory.CreateDirectory(fileInfo.Directory.FullName);
            }
            if (!File.Exists(latestPath))
            {
                File.Copy(originalPath, latestPath);
            }
            else
            {
                if (overwrite)
                {
                    File.Copy(originalPath, latestPath, true);
                }
            }
            RecordData recordData = new RecordData();
            recordData.originalPath = originalPath;
            recordData.latestPath = latestPath;
            recordDicts.Add(originalPath, recordData);
        }
        AssetDatabase.Refresh();
        CollectOldFileIDAndGUID(recordDicts, prefabPath);
        ImporterSetting(recordDicts, prefabPath);
        CollectNewFileIDAndGUID(recordDicts, prefabPath);
        ReplaceDependencies(recordDicts, prefabPath);
    }
    
    /// <summary>
    /// 收集旧资源的FileID和GUID
    /// </summary>
    /// <param name="recordDicts"></param>
    /// <param name="prefabPath"></param>
    private void CollectOldFileIDAndGUID(Dictionary<string, RecordData> recordDicts, string prefabPath)
    {
        foreach (var item in recordDicts)
        {
            RecordData recordData = item.Value;
            if (File.Exists(recordData.originalPath))
            {
                AssetType assetType;
                List<PointerData> fileList = GetFileIdAndGUID(recordData.originalPath, out assetType);
                if (fileList.Count > 0)
                {
                    recordData.assetType = assetType;
                    for (int j = 0; j < fileList.Count; j++)
                    {
                        recordData.oldPointerData.Add(new PointerData(fileList[j].fileId, fileList[j].GUID));
                    }
                }
            }
            else
            {
                Debug.LogError($"获取FileID or GUID失败:{recordData.originalPath}");
            }
        }
    }

    /// <summary>
    /// 拷贝完资源后设置格式
    /// </summary>
    private void ImporterSetting(Dictionary<string, RecordData> recordDicts, string prefabPath)
    {
        foreach (var item in recordDicts)
        {
            RecordData recordData = item.Value;
            switch (recordData.assetType)
            {
                case AssetType.isTexture:
                case AssetType.isSprite:
                    TextureImporter textureImporter = (TextureImporter)TextureImporter.GetAtPath(recordData.latestPath);
                    textureImporter.alphaSource = TextureImporterAlphaSource.FromInput;
                    textureImporter.alphaIsTransparency = true;
                    textureImporter.isReadable = false;
                    if (recordData.assetType == AssetType.isSprite)
                    {
                        textureImporter.textureType = TextureImporterType.Sprite;
                    }
                    textureImporter.SaveAndReimport();
                    break;
                case AssetType.isMaterial:
                    break;
                case AssetType.isFBX:
                    break;
                case AssetType.isPrefab:
                    break;
                case AssetType.isAsset:
                    break;
                case AssetType.other:
                    break;
                default:
                    break;
            }
        }
        AssetDatabase.Refresh();
    }
    
    /// <summary>
    /// 收集新拷贝资源的FileID和GUID
    /// </summary>
    /// <param name="recordDicts"></param>
    /// <param name="prefabPath"></param>
    private void CollectNewFileIDAndGUID(Dictionary<string, RecordData> recordDicts, string prefabPath)
    {
        foreach (var item in recordDicts)
        {
            RecordData recordData = item.Value;
            if (File.Exists(recordData.latestPath))
            {
                AssetType assetType;
                List<PointerData> fileList = GetFileIdAndGUID(recordData.latestPath, out assetType);
                if (fileList.Count > 0)
                {
                    for (int j = 0; j < fileList.Count; j++)
                    {
                        recordData.newPointerData.Add(new PointerData(fileList[j].fileId, fileList[j].GUID));
                    }
                }
            }
            else
            {
                Debug.LogError($"获取FileID or GUID失败:{recordData.latestPath}");
            }
        }
    }

    /// <summary>
    /// 替换资源引用
    /// </summary>
    private void ReplaceDependencies(Dictionary<string, RecordData> recordDicts, string prefabPath)
    {
        List<string> prefabPaths = new List<string>();
        foreach (var item in recordDicts)
        {
            RecordData recordData = item.Value;
            if (recordData.assetType == AssetType.isMaterial || recordData.assetType == AssetType.isAsset)
            {
                ReplaceFileIdAndGUID(recordDicts, recordData.latestPath);
            }
            else if (recordData.assetType == AssetType.isPrefab)
            {
                prefabPaths.Add(recordData.latestPath);
            }
        }
        foreach (var item in recordDicts)
        {
            RecordData recordData = item.Value;
            if (recordData.assetType == AssetType.isMaterial || recordData.assetType == AssetType.isAsset)
            {
                ReplaceGUID(recordDicts, recordData.latestPath);
            }
        }

        string relativePrefabPath = _regex.Replace(prefabPath, "");
        ReplaceFileIdAndGUID(recordDicts, $"{_copyToPath}{relativePrefabPath}");
        ReplaceGUID(recordDicts, $"{_copyToPath}{relativePrefabPath}");
        AssetDatabase.Refresh();
        for (int i = 0; i < prefabPaths.Count; i++)
        {
            string path = prefabPaths[i];
            if (!path.Contains(relativePrefabPath))
            {
                CopyDependencies(path, false);
            }
        }
        AssetDatabase.Refresh();
    }
    
    /// <summary>
    /// 替换FileID和GUID
    /// </summary>
    /// <param name="recordDicts"></param>
    /// <param name="path"></param>
    private void ReplaceFileIdAndGUID(Dictionary<string, RecordData> recordDicts, string path)
    {
        string content = File.ReadAllText(path);
        foreach (var item in recordDicts)
        {
            RecordData recordData = item.Value;
            //数量不同则表示拷贝资源出错,不进行替换
            if (recordData.oldPointerData.Count == recordData.newPointerData.Count)
            {
                for (int j = 0; j < recordData.oldPointerData.Count; j++)
                {
                    string oldStr = $"fileID: {recordData.oldPointerData[j].fileId}, guid: {recordData.oldPointerData[j].GUID}";
                    string newStr = $"fileID: {recordData.newPointerData[j].fileId}, guid: {recordData.newPointerData[j].GUID}";
                    content = ReplaceStr(content, oldStr, newStr);
                }
            }
            else
            {
                Debug.LogError($"替换FileId和GUID失败:\n{recordData.originalPath}\n{recordData.latestPath}");
            }
        }
        File.WriteAllText(path, content);
    }
    
    /// <summary>
    /// 替换GUID
    /// </summary>
    /// <param name="recordDicts"></param>
    /// <param name="path"></param>
    private void ReplaceGUID(Dictionary<string, RecordData> recordDicts, string path)
    {
        string content = File.ReadAllText(path);
        foreach (var item in recordDicts)
        {
            RecordData recordData = item.Value;
            //数量不同则表示拷贝资源出错,不进行替换
            if (recordData.oldPointerData.Count == recordData.newPointerData.Count)
            {
                for (int j = 0; j < recordData.oldPointerData.Count; j++)
                {
                    switch (recordData.assetType)
                    {
                        case AssetType.isFBX:
                        case AssetType.isPrefab:
                            content = ReplaceStr(content, $"guid: {recordData.oldPointerData[j].GUID}", $"guid: {recordData.newPointerData[j].GUID}");
                            break;
                    }
                }
            }
            else 
            {  
                Debug.LogError($"替换GUID失败:\n{recordData.originalPath}\n{recordData.latestPath}"); 
            }
        }
        File.WriteAllText(path, content);
    }

    /// <summary>
    /// 字符串替换
    /// </summary>
    /// <param name="content"></param>
    /// <param name="oldStr"></param>
    /// <param name="newStr"></param>
    /// <returns></returns>
    private string ReplaceStr(string content, string oldStr, string newStr)
    {
        if (Regex.IsMatch(content, oldStr))
        {
            content = content.Replace(oldStr, newStr);
        }
        return content;
    }

    /// <summary>
    /// 获取fileId和GUID
    /// </summary>
    /// <param name="path"></param>
    /// <param name="fileId"></param>
    /// <param name="guid"></param>
    /// <param name="assetType"></param>
    /// <returns></returns>
    private List<PointerData> GetFileIdAndGUID(string path, out AssetType assetType)
    {
        List<PointerData> fileList = new List<PointerData>();    
        string guid = string.Empty;
        long fileId = 0;
        assetType = AssetType.other;
        if (path.Contains(".png"))
        {
            //图片类型资源有两个fileId和两个guid
            assetType = AssetType.isTexture;
            AssetDatabase.TryGetGUIDAndLocalFileIdentifier(AssetDatabase.LoadMainAssetAtPath(path), out guid, out fileId);
            fileList.Add(new PointerData(fileId, guid));

            var obj = AssetDatabase.LoadAssetAtPath<Sprite>(path);
            if (obj != null)
            {
                assetType = AssetType.isSprite;
                AssetDatabase.TryGetGUIDAndLocalFileIdentifier<Sprite>(obj, out guid, out fileId);
                fileList.Add(new PointerData(fileId, guid));
            }
        }
        else
        {
            if (path.Contains(".mat"))
            {
                assetType = AssetType.isMaterial;
            }
            else if (path.Contains(".prefab"))
            {
                assetType = AssetType.isPrefab;
            }
            else if (path.Contains(".FBX") || path.Contains(".fbx"))
            {
                assetType = AssetType.isFBX;
            }
            AssetDatabase.TryGetGUIDAndLocalFileIdentifier(AssetDatabase.LoadMainAssetAtPath(path), out guid, out fileId);
            fileList.Add(new PointerData(fileId, guid));
        }
        return fileList;
    }



    #region 拖拽部分代码
    private void DropEnd(string path)
    {
        _originalPrefabPath = path;
        Debug.Log(path);
    }

    private void OnDropAreaGUI()
    {
        var evt = Event.current;
        if (_originalPrefabPath == "")
        {
            GUILayout.Box("把要拷贝预制体拖拽至此", GUILayout.Height(50), GUILayout.ExpandWidth(true));
        }
        else
        {
            GUILayout.Box("当前预制体路径: " + _originalPrefabPath, GUILayout.Height(50), GUILayout.ExpandWidth(true));
        }
        //上次渲染的那个方块
        Rect dropArea = GUILayoutUtility.GetLastRect();
        switch (evt.type)
        {
            case EventType.DragUpdated:
            case EventType.DragPerform:
                if (!dropArea.Contains(evt.mousePosition))
                    return;
                DragAndDrop.visualMode = DragAndDropVisualMode.Link;
                if (evt.type == EventType.DragPerform)
                {
                    DragAndDrop.AcceptDrag();
                    evt.Use();
                    foreach (var draggedObject in DragAndDrop.objectReferences)
                    {
                        if (draggedObject)
                        {
                            var path = AssetDatabase.GetAssetPath(draggedObject);

                            DropEnd(path);
                            break;
                        }
                    }
                }
                break;
        }
    }
    #endregion
}


最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容