Unity复制资源目录并添加新的引用关系

有时候需要复制一个场景目录制作新的场景,打包场景也是独立资源,不希望资源复用。我们直接使用Ctrl+D复制资源,里面的预设,材质等都还是指向原有的,所以废话不多说,直接上代码。

操作窗口

首先是制作一个复制资源窗口
在这里插入图片描述

下面是脚本和菜单调用

在这里插入图片描述

using System.Collections;
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;

public class ResCopyWin : EditorWindow
{
    
    
    public static ResCopyWin copyWin;
    //[MenuItem("JFrameWork/Resources/复制文件夹(复制依赖关系) %#D", false, 0)] Ctrl+Shift+D
    [MenuItem("JFrameWork/Resources/复制文件夹(复制依赖关系)", false, 0)]


    public static void CopyIt()
    {
    
    
        //否则就弹出面板设置

        copyWin = EditorWindow.GetWindow(typeof(ResCopyWin), true, "复制资源目录") as ResCopyWin;

        copyWin.ShowModalUtility();

    }


    string sourcePath = "Assets/";
    string toPath = "Assets/";


    private void OnGUI()
    {
    
    
        using (new GUILayout.VerticalScope())
        {
    
    
            EditorGUILayout.Space(10);
            EditorGUILayout.LabelField("原始路径:");
            sourcePath = EditorGUILayout.TextField(sourcePath, GUILayout.Width(180));


            EditorGUILayout.Space(10);
            EditorGUILayout.LabelField("目标路径:");
            toPath = EditorGUILayout.TextField(toPath, GUILayout.Width(180));



            EditorGUILayout.Space(10);
            if (GUILayout.Button("开始复制", GUILayout.Width(150), GUILayout.Height(20)))
            {
    
    
                OnOk();
            }
        }
    }

    void OnOk()
    {
    
    

        CopyFolderKeepAssetsUsingEditor.CopyDirectoryDeep(sourcePath, toPath);
    }


}

原始路径就是要复制的目录,目标路径就是复制出来的目录。

复制函数


using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using UnityEditor;
using UnityEngine;

public class CopyFolderKeepAssetsUsingEditor
{
    
    
    //[MenuItem("Tools/复制文件夹(复制依赖关系) %#D", false, 0)]

    //public static void CopyIt()
    //{
    
    
    //    CopyDirectoryDeep("Assets/scenes/1", "Assets/scenes/2");
    //}

    public static void CopyDirectoryDeep(string sourcePath, string destinationPath)
    {
    
    
        CopyDirectoryRecursively(sourcePath, destinationPath);

        List<string> metaFiles = GetFilesRecursively(destinationPath, (f) => f.EndsWith(".meta"));
        List<(string originalGuid, string newGuid)> guidTable = new List<(string originalGuid, string newGuid)>();

        foreach (string metaFile in metaFiles)
        {
    
    
            StreamReader file = new StreamReader(metaFile);
            file.ReadLine();
            string guidLine = file.ReadLine();
            file.Close();
            string originalGuid = guidLine.Substring(6, guidLine.Length - 6);
            string newGuid = GUID.Generate().ToString().Replace("-", "");
            guidTable.Add((originalGuid, newGuid));
        }

        List<string> allFiles = GetFilesRecursively(destinationPath);

        foreach (string fileToModify in allFiles)
        {
    
    
            string content = File.ReadAllText(fileToModify);

            foreach (var guidPair in guidTable)
            {
    
    
                content = content.Replace(guidPair.originalGuid, guidPair.newGuid);
            }

            File.WriteAllText(fileToModify, content);
        }

        AssetDatabase.Refresh();
    }

    private static void CopyDirectoryRecursively(string sourceDirName, string destDirName)
    {
    
    
        DirectoryInfo dir = new DirectoryInfo(sourceDirName);

        DirectoryInfo[] dirs = dir.GetDirectories();

        if (!Directory.Exists(destDirName))
        {
    
    
            Directory.CreateDirectory(destDirName);
        }

        FileInfo[] files = dir.GetFiles();
        foreach (FileInfo file in files)
        {
    
    
            string temppath = Path.Combine(destDirName, file.Name);
            file.CopyTo(temppath, false);
        }

        foreach (DirectoryInfo subdir in dirs)
        {
    
    
            string temppath = Path.Combine(destDirName, subdir.Name);
            CopyDirectoryRecursively(subdir.FullName, temppath);
        }
    }

    private static List<string> GetFilesRecursively(string path, Func<string, bool> criteria = null, List<string> files = null)
    {
    
    
        if (files == null)
        {
    
    
            files = new List<string>();
        }

        files.AddRange(Directory.GetFiles(path).Where(f => criteria == null || criteria(f)));

        foreach (string directory in Directory.GetDirectories(path))
        {
    
    
            GetFilesRecursively(directory, criteria, files);
        }

        return files;
    }
}

这里就结束了。

改进问题

使用了几次发现几个问题:
1,首先ReadAllText和Write的时候二进制非纯文本文件会出现问题,例如图片变大,所以我们判断是不是二进制文件再进行修改替换guid。
2,一些文件例如脚本不能复制了,例如cs文件两份会报错,inputactions文件也不需要两份。增加对一些扩展名进行排除。
输入复制也不方便,改为了拖动的方式复制。

在这里插入图片描述

直接贴上代码


using Sirenix.Utilities.Editor;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using UnityEditor;
using UnityEngine;

public class CopyFolderKeepAssetsUsingEditor
{
    
    
    //[MenuItem("Tools/复制文件夹(复制依赖关系) %#D", false, 0)]

    //public static void CopyIt()
    //{
    
    
    //    CopyDirectoryDeep("Assets/scenes/1", "Assets/scenes/2");
    //}

    //-------------文件操作---------------//
    public static bool CopyFileDeep(string sourceFile, string destinationFile)
    {
    
    
        FileInfo file;

        List<string> efile = new List<string>(ResCopyWin.efile.Split(';'));
        string expname = Path.GetExtension(sourceFile).Trim();
        if(efile.IndexOf(expname) != -1 )
        {
    
    
            Debug.LogError("这个文件被排除了类型:" + sourceFile + ",无法复制。");
            return false;
        }
        string toPath = Path.GetDirectoryName(destinationFile);
        if (!Directory.Exists(toPath))
        {
    
    
            Directory.CreateDirectory(toPath);
        }
        Debug.Log($"资源文件:{
      
      sourceFile} -> {
      
      destinationFile},准备开始复制。");
        if (File.Exists(sourceFile))
        {
    
    
            file = new FileInfo(sourceFile);
            file.CopyTo(destinationFile, true);
        }

        //拷贝meta
        string sourceFileMeta = sourceFile + ".meta";
        string destinationFileMeta = destinationFile + ".meta";
        if (File.Exists(sourceFileMeta))
        {
    
    
            file = new FileInfo(sourceFileMeta);
            file.CopyTo(destinationFileMeta, true);
        }

        //替换meta中的guid
        StreamReader filestream = new StreamReader(destinationFileMeta);
        filestream.ReadLine();
        string guidLine = filestream.ReadLine();
        filestream.Close();
        string originalGuid = guidLine.Substring(6, guidLine.Length - 6);
        string newGuid = GUID.Generate().ToString().Replace("-", "");


        string content = File.ReadAllText(destinationFileMeta);
        content = content.Replace(originalGuid, newGuid);
        File.WriteAllText(destinationFileMeta, content);

        Debug.Log($"资源文件复制完毕:{
      
      sourceFile} -> {
      
      destinationFile}");

        AssetDatabase.Refresh();
        return true;
    }

    //--------------文件夹操作-----------------//

    public static bool CopyDirectoryDeep(string sourcePath, string destinationPath)
    {
    
    
        Debug.Log($"资源目录复制开始:{
      
      sourcePath} -> {
      
      destinationPath}");
        CopyDirectoryRecursively(sourcePath, destinationPath);

        List<string> metaFiles = GetFilesRecursively(destinationPath, (f) => f.ToLower().EndsWith(".meta"));
        List<(string originalGuid, string newGuid)> guidTable = new List<(string originalGuid, string newGuid)>();

        foreach (string metaFile in metaFiles)
        {
    
    
            StreamReader file = new StreamReader(metaFile);
            file.ReadLine();
            string guidLine = file.ReadLine();
            file.Close();
            string originalGuid = guidLine.Substring(6, guidLine.Length - 6);
            string newGuid = GUID.Generate().ToString().Replace("-", "");
            guidTable.Add((originalGuid, newGuid));
        }


        List<string> allFiles = GetFilesRecursively(destinationPath);
        foreach (string fileToModify in allFiles)
        {
    
    
            bool binfile = CheckForBinary(fileToModify);
            if (binfile)
            {
    
    
                Debug.Log("<color=#111111>二进制文件不用修改引用</color>:" + fileToModify);
                continue;
            }
            //string newname = fileToModify.ToLower();
            //if (newname.EndsWith(".png"))
            //    continue;
            //if (newname.EndsWith(".jpg"))
            //    continue;
            //if (newname.EndsWith(".bmp"))
            //    continue;
            //if (newname.EndsWith(".tif"))
            //    continue;
            //if (newname.EndsWith(".tga"))
            //    continue;
            //if (newname.EndsWith(".psd"))
            //    continue;
            string content = File.ReadAllText(fileToModify);
            foreach (var guidPair in guidTable)
            {
    
    
                string oldstr = guidPair.originalGuid;
                string newstr = guidPair.newGuid;
                //Debug.Log(content.Length+","+ oldstr + ":" + newstr);
                content = content.Replace(oldstr, newstr);
                //Debug.Log(content.Length );
            }
            Debug.Log("修改文件引用:" + fileToModify);
            File.WriteAllText(fileToModify, content);

            
        }
        Debug.Log($"<color=#d9f5d6>目录文件复制完毕</color>:{
      
      sourcePath} -> {
      
      destinationPath}。");
        /// <summary>
        /// This method checks whether selected file is Binary file or not.
        /// </summary>     
        static bool CheckForBinary(string file)
        {
    
    

            Stream objStream = new FileStream(file, FileMode.Open, FileAccess.Read);
            bool bFlag = true;

            // Iterate through stream & check ASCII value of each byte.
            for (int nPosition = 0; nPosition < objStream.Length; nPosition++)
            {
    
    
                int a = objStream.ReadByte();

                if (!(a >= 0 && a <= 127))
                {
    
    
                    break;            // Binary File
                }
                else if (objStream.Position == (objStream.Length))
                {
    
    
                    bFlag = false;    // Text File
                }
            }
            objStream.Dispose();

            return bFlag;
        }


        //AssetDatabase.Refresh();
        return true;
    }

    private static void CopyDirectoryRecursively(string sourceDirName, string destDirName)
    {
    
    
        DirectoryInfo dir = new DirectoryInfo(sourceDirName);
        List<string> efile = new List<string>(ResCopyWin.efile.Split(';'));
        DirectoryInfo[] dirs = dir.GetDirectories();

        if (!Directory.Exists(destDirName))
        {
    
    
            Directory.CreateDirectory(destDirName);
        }

        FileInfo[] files = dir.GetFiles();
        foreach (FileInfo file in files)
        {
    
    
            
            string expname = file.Extension.Trim().ToLower();
            if (efile.IndexOf(expname) != -1)
            {
    
    
                Debug.Log("这个文件被排除了类型:" + file.FullName + "");
                continue;
            }
            if (expname == ".meta")
            {
    
    
                string newname =  file.FullName.Replace(".meta", "");
                expname = Path.GetExtension(newname).ToLower();
                if (efile.IndexOf(expname) != -1)
                {
    
    
                    Debug.Log("这个文件被排除了类型:" + file.FullName + "");
                    continue;
                }
            }
            string temppath = Path.Combine(destDirName, file.Name);
            file.CopyTo(temppath, true);
            Debug.Log("复制文件:" + temppath + "");
        }

        foreach (DirectoryInfo subdir in dirs)
        {
    
    
            string temppath = Path.Combine(destDirName, subdir.Name);
            CopyDirectoryRecursively(subdir.FullName, temppath);
        }
    }

    private static List<string> GetFilesRecursively(string path, Func<string, bool> criteria = null, List<string> files = null)
    {
    
    
        if (files == null)
        {
    
    
            files = new List<string>();
        }

        files.AddRange(Directory.GetFiles(path).Where(f => criteria == null || criteria(f)));

        foreach (string directory in Directory.GetDirectories(path))
        {
    
    
            GetFilesRecursively(directory, criteria, files);
        }

        return files;
    }
}
using JFrameWork.ResEditor;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using UnityEditor;
using UnityEditor.IMGUI.Controls;
using UnityEngine;
using UnityEngine.Rendering.Universal;

public class ResCopyWin : EditorWindow
{
    
    
    public static ResCopyWin copyWin;
    //[MenuItem("JFrameWork/Resources/复制文件夹(复制依赖关系) %#D", false, 0)] Ctrl+Shift+D
    [MenuItem("JFrameWork/Resources/复制文件夹(复制依赖关系)", false, 0)]

    
    public static void CopyIt()
    {
    
    
        //否则就弹出面板设置

        copyWin = EditorWindow.GetWindow(typeof(ResCopyWin), true, "复制资源目录") as ResCopyWin;

        copyWin.ShowUtility();

    }


    string sourcePath = "Assets/";
    string toPath = "Assets/";
    public static string efile = ".cs;.shader;.inputactions";

    string sOut = "";

    Object targetGo;
    int copytype = 0;

    private void OnGUI()
    {
    
    
        copytype = 0;
        using (new GUILayout.VerticalScope())
        {
    
    
            EditorGUILayout.LabelField("拖入要复制的目录或者Prefab:");
            EditorGUILayout.Space(10);
            GUILayout.BeginHorizontal();
            EditorGUILayout.LabelField("资源:", GUILayout.Width(50));
            targetGo = (Object)EditorGUILayout.ObjectField(targetGo, typeof(Object), true);
            GUILayout.EndHorizontal();

            EditorGUILayout.Space(10);
            GUILayout.BeginHorizontal();
            EditorGUILayout.LabelField("排除:", GUILayout.Width(50));
            efile = EditorGUILayout.TextField(efile.ToLower());
            GUILayout.EndHorizontal();
            


            if (targetGo != null) 
            {
    
    
                sourcePath = AssetDatabase.GetAssetPath(targetGo);

                
                if (File.Exists(sourcePath))
                {
    
    
                    copytype = 1;
                    string filename = Path.GetFileName(sourcePath);
                    //string expname = Path.GetFileNameWithoutExtension(sourcePath);
                    toPath = sourcePath.Replace(filename, "") +"_Copy/";
                    
                    toPath +=  filename;
                }
                else if (Directory.Exists(sourcePath))
                {
    
    
                    copytype = 2;
                    toPath = sourcePath + "_Copy";
                }

                EditorGUILayout.Space(10);
                if (copytype > 0)
                {
    
    
                    string showtxt = copytype == 1 ? "开始复制资源" : "开始复制文件夹";
                    if (GUILayout.Button(showtxt, GUILayout.Width(150), GUILayout.Height(20)))
                    {
    
    
                        OnOk();
                    }
                }
                EditorGUILayout.Space(10);
                EditorGUILayout.LabelField(sOut);
            }

            //sourcePath = EditorGUILayout.TextField(sourcePath, GUILayout.Width(180));
            //GUILayout.EndHorizontal();

            //EditorGUILayout.Space(10);
            //EditorGUILayout.LabelField("目标路径:");
            //toPath = EditorGUILayout.TextField(toPath, GUILayout.Width(180));



            
        }
    }

    void OnOk()
    {
    
    
        sOut = "";
        if (copytype == 1)
        {
    
    
            bool bok = CopyFolderKeepAssetsUsingEditor.CopyFileDeep(sourcePath, toPath);
            if (bok)
            {
    
    
                sOut = "复制完成 !!!";
            }
            else
            {
    
    
                sOut = "复制失败,请检查日志 !!!";
            }
        }
        else if (copytype == 2)
        {
    
    
            bool bok = CopyFolderKeepAssetsUsingEditor.CopyDirectoryDeep(sourcePath, toPath);
            if (bok)
            {
    
    
                sOut = "复制完成 !!!";
            }
            else
            {
    
    
                sOut = "复制失败,请检查日志 !!!";
            }
        }
    }


}

参考

https://discussions.unity.com/t/can-i-duplicate-folder-with-internal-dependencies-between-objects/119179/5

猜你喜欢

转载自blog.csdn.net/thinbug/article/details/140931438