Unity复制粘贴功能

 https://github.com/4000white/UnityCopyPaste

同一项目内,复制粘贴资源,不用打开文件夹操作,或者Dublicate再移动。可以批量复制。

复制文件夹时,文件夹内的资源引用了本文件夹内的其它资源,复制出来的资源的依赖会替换新复制出来的资源

using System.Collections.Generic;
using System.IO;
using System.Text.RegularExpressions;
using UnityEngine;
using System;
using Object = UnityEngine.Object;

namespace UnityEditor
{
    public class AssetCopyer
    {
        //复制粘贴一个文件夹时,如果有资源引用了文件夹里的其它资源,新复制出来的资源的引用会替换新文件夹里对应的文件,而不是继续引用旧文件夹里的资源
        //执行这种操作的资源的后缀
        private static List<string> includeList = new List<string> { ".prefab", ".mat", ".anim", ".controller" };

        private const string META = ".meta";
#if UNITY_EDITOR_OSX
        private const string DS_STORE = ".DS_Store";
        private static List<string> ignoreList = new List<string> { META, DS_STORE };
#else
        private static List<string> ignoreList = new List<string> {META};
#endif
        private static List<string> copyPaths = new List<string>();
        [MenuItem("Assets/Copy", false, -10000)]
        static void AssetCopy()
        {
            var objs = Selection.GetFiltered<Object>(SelectionMode.Assets);
            copyPaths.Clear();
            foreach (var obj in objs)
            {
                copyPaths.Add(AssetDatabase.GetAssetPath(obj));
            }
        }
        [MenuItem("Assets/Paste", true)]
        static bool ValidAssetPaste()
        {
            return copyPaths.Count > 0;
        }
        [MenuItem("Assets/Paste", false, -10000)]
        static void AssetPaste()
        {
            var pastePosition = AssetDatabase.GetAssetPath(Selection.activeObject);
            if (Path.HasExtension(pastePosition))
            {
                pastePosition = Path.GetDirectoryName(pastePosition);
            }
            foreach (var copyPath in copyPaths)
            {
                if (!string.IsNullOrEmpty(copyPath))
                {
                    var fileName = Path.GetFileName(copyPath);
                    var pastePath = pastePosition + "/" + fileName;
                    Copy(copyPath, pastePath);
                }
            }
        }

        public static void Copy(string copyPath, string pastePath)
        {
            Debug.Log("copy " + copyPath + " to " + pastePath);
            try
            {
                if (!string.IsNullOrEmpty(copyPath))
                {
                    if (Path.HasExtension(copyPath))
                    {
                        CopyFile(copyPath, pastePath);
                    }
                    else
                    {
                        CopyFolder(copyPath, pastePath);
                    }
                }
            }
            catch (Exception e)
            {
                Debug.Log(e);
            }
        }

        //复制单个文件
        private static void CopyFile(string copyPath, string pastePath)
        {
            if (!Path.HasExtension(copyPath) || !Path.HasExtension(pastePath))
            {
                throw new Exception();
            }
            pastePath = NextAvailableFilename(pastePath);
            File.Copy(copyPath, pastePath);
            AssetDatabase.Refresh();
            AssetDatabase.SaveAssets();
            Selection.activeObject = AssetDatabase.LoadMainAssetAtPath(pastePath);
        }
        //复制文件夹
        private static void CopyFolder(string copyPath, string pastePath)
        {
            if (Path.HasExtension(copyPath) || Path.HasExtension(pastePath))
            {
                throw new Exception();
            }
            pastePath = NextAvailableFilename(pastePath);
            Debug.Log("pastePath " + pastePath);
            RecursivelyCopyFolder(copyPath, pastePath);
            AssetDatabase.Refresh();
            ReplaceReferences(copyPath, pastePath);
            AssetDatabase.Refresh();
            AssetDatabase.SaveAssets();
            Selection.activeObject = AssetDatabase.LoadMainAssetAtPath(pastePath);
        }
        //刚复制出来的新文件夹里的资源还是会有对旧文件夹中资源的引用,通过替换guid的方式,把引用替换成对新文件夹中对应文件的引用
        private static void ReplaceReferences(string oldPath, string newPath)
        {
            var guidMap = new Dictionary<string, string>();
            var fullPath = Path.GetFullPath(oldPath);
            var filePaths = GetAllFiles(fullPath);
            var length = fullPath.Length + 1;
            foreach (var filePath in filePaths)
            {
                string extension = Path.GetExtension(filePath);
                if (!ignoreList.Contains(extension))
                {
                    string assetPath = GetRelativeAssetPath(filePath);
                    string relativePath = filePath.Remove(0, length);
                    string guid = AssetDatabase.AssetPathToGUID(assetPath);
                    string copyPath = newPath + "/" + relativePath;
                    string copyGuid = AssetDatabase.AssetPathToGUID(copyPath);
                    if (copyGuid != null)
                    {
                        guidMap[guid] = copyGuid;
                    }
                }
            }

            fullPath = Path.GetFullPath(newPath);
            filePaths = GetAllFiles(fullPath);
            foreach (var filePath in filePaths)
            {
                string extension = Path.GetExtension(filePath);
                if (includeList.Contains(extension))
                {
                    var assetPath = GetRelativeAssetPath(filePath);
                    string[] deps = AssetDatabase.GetDependencies(assetPath, true);
                    var fileString = File.ReadAllText(filePath);
                    bool bChanged = false;
                    foreach (var v in deps)
                    {
                        var guid = AssetDatabase.AssetPathToGUID(v);
                        if (guidMap.ContainsKey(guid))
                        {
                            if (Regex.IsMatch(fileString, guid))
                            {
                                fileString = Regex.Replace(fileString, guid, guidMap[guid]);
                                bChanged = true;
                                var oldFile = AssetDatabase.GUIDToAssetPath(guid);
                                var newFile = AssetDatabase.GUIDToAssetPath(guidMap[guid]);
                            }
                        }
                    }
                    if (bChanged)
                    {
                        File.WriteAllText(filePath, fileString);
                    }
                }
            }
        }

        private static string GetRelativeAssetPath(string fullPath)
        {
            fullPath = fullPath.Replace("\\", "/");
            int index = fullPath.IndexOf("Assets");
            string relativePath = fullPath.Substring(index);
            return relativePath;
        }

        private static string[] GetAllFiles(string fullPath)
        {
            List<string> files = new List<string>();
            foreach (string file in GetFiles(fullPath))
            {
                files.Add(file);
            }
            return files.ToArray();
        }

        private static IEnumerable<string> GetFiles(string path)
        {
            Queue<string> queue = new Queue<string>();
            queue.Enqueue(path);
            while (queue.Count > 0)
            {
                path = queue.Dequeue();
                try
                {
                    foreach (string subDir in Directory.GetDirectories(path))
                    {
                        queue.Enqueue(subDir);
                    }
                }
                catch (Exception ex)
                {
                    Console.Error.WriteLine(ex);
                }
                string[] files = null;
                try
                {
                    files = Directory.GetFiles(path);
                }
                catch (Exception ex)
                {
                    Console.Error.WriteLine(ex);
                }
                if (files != null)
                {
                    for (int i = 0; i < files.Length; i++)
                    {
                        yield return files[i];
                    }
                }
            }
        }

        static void RecursivelyCopyFolder(string sourcePath, string destPath)
        {
            if (sourcePath == destPath)
            {
                throw new Exception("sourcePath == destPath");
            }
            if (Directory.Exists(sourcePath))
            {
                if (!Directory.Exists(destPath))
                {
                    try
                    {
                        Directory.CreateDirectory(destPath);
                    }
                    catch (Exception ex)
                    {
                        Debug.LogError(ex);
                    }
                }

                List<string> files = new List<string>(Directory.GetFiles(sourcePath));
                files.ForEach(c =>
                {
#if UNITY_EDITOR_OSX
                    if (!c.EndsWith(META) && !c.EndsWith(DS_STORE))
#else
                    if (!c.EndsWith(META))
#endif
                    {
                        string destFile = Path.Combine(destPath, Path.GetFileName(c));
                        File.Copy(c, destFile, true);
                    }
                });
                List<string> folders = new List<string>(Directory.GetDirectories(sourcePath));
                folders.ForEach(c =>
                {
                    string destDir = Path.Combine(destPath, Path.GetFileName(c));
                    RecursivelyCopyFolder(c, destDir);
                });
            }
            else
            {
                throw new Exception("sourcePath is not exist!");
            }
        }

        private static string numberPattern = " ({0})";
        private static bool FileExist(string filePath, bool isFolder)
        {
            if (isFolder)
            {
                return Directory.Exists(filePath);
            }
            else
            {
                return File.Exists(filePath);
            }
        }
        //获取一个不重复的文件名,如 aa (1).prefab
        public static string NextAvailableFilename(string path)
        {
            bool isFolder = !Path.HasExtension(path);
            if (!FileExist(path, isFolder))
            {
                return path;
            }
            string tmp;
            if (Path.HasExtension(path))
            {
                tmp = path.Insert(path.LastIndexOf(Path.GetExtension(path)), numberPattern);
            }
            else
            {
                tmp = path + numberPattern;
            }
            return GetNextFilename(tmp, isFolder);
        }
        private static string GetNextFilename(string pattern, bool isFolder)
        {
            string tmp = string.Format(pattern, 1);
            if (tmp == pattern)
            {
                throw new ArgumentException("The pattern must include an index place-holder", "pattern");
            }

            if (!FileExist(tmp, isFolder))
            {
                return tmp;
            }

            int min = 1, max = 2;
            while (FileExist(string.Format(pattern, max), isFolder))
            {
                min = max;
                max *= 2;
            }

            while (max != min + 1)
            {
                int pivot = (max + min) / 2;

                if (FileExist(string.Format(pattern, pivot), isFolder))
                    min = pivot;
                else
                    max = pivot;
            }

            return string.Format(pattern, max);
        }
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值