用odin实现了一个资源复制编辑器,使用要安装odin,功能是把要复制的资源路径一个个添加设置,点copy能把列表里的资源全部复制,支持目录复制到目录,文件复制到目录,文件复制替换。提升效率,让自己有更多的时间研究其他东西或者休息,需要注意的是只有一个目标路径的情况下,不能同时填源文件路径和源文件夹路径,不然不知道要拷贝文件还是文件夹,这个应该很好理解吧。代码如下:
csharp
using UnityEditor;
using UnityEngine;
using Sirenix.OdinInspector.Editor;
using Sirenix.OdinInspector;
using System;
using System.IO;
using System.Collecttions.Generic;
public class PathTableListWindow : OdinEditorWindow
{
[MenuItem("Window/Open Path Table List")]
private static void OpenWindow()
{
// GetExistingOrCreateNewWindow 是一个用于创建或获取已存在窗口的辅助方法
var window = GetWindow<PathTableListWindow>();
window.Show();
}
// 示例数据,用于在编辑器窗口中显示
[TableList]
public List<Item> PathItems = new List<Item>();
[Button("Copy")]
private void CopyAssets()
{
foreach(var item in PathItems)
{
if (Directory.Exists(item.SourcePath))
{
// 如果源路径是文件夹,则递归复制所有文件和子文件夹
CopyDirectory(item.SourcePath, item.TargetPath);
}
else if (File.Exists(item.SourcePath))
{
// 如果源路径是文件,则直接复制文件
string destDir = Path.GetDirectoryName(item.TargetPath);
if (!Directory.Exists(destDir))
{
Directory.CreateDirectory(destDir);
}
File.Copy(item.SourcePath, item.TargetPath, true);
}
if(!string.IsNullOrEmpty(item.SourceFilePath))
{
if(string.IsNullOrEmpty(item.TargetFilePath)
{
var destFile = Path.Combine(item.TargetPath,Path.GetFileName(item.TargetFilePath));
File.Copy(item.SourceFilePath, destFile, true);
}
else
{
File.Copy(item.SourceFilePath, item.TargetFilePath, true);
}
}
}
}
private void CopyDirectory(string source, string destination)
{
if(File.GetAttributes(source).HasFlag(FileAttributes.Directory))
{
string targetDest = Path.Combine(destination,Path.GetFileName(source));
if(!Directory.Exists(targetDest))
{
// 创建目标目录
Directory.CreateDirectory(targetDest );
}
// 递归复制子目录
string[] dirs = Directory.GetDirectories(source);
foreach (string dir in dirs)
{
string destDir = Path.Combine(targetDest, Path.GetFileName(dir));
CopyDirectory(dir, destDir);
}
// 获取源目录下的所有文件
string[] files = Directory.GetFiles(source);
foreach (string file in files)
{
string destFile = Path.Combine(targetDest, Path.GetFileName(file));
File.Copy(file, destFile, true);
}
}
else
{
// 获取源目录下的所有文件
string[] files = Directory.GetFiles(source);
foreach (string file in files)
{
string destFile = Path.Combine(destination, Path.GetFileName(file));
File.Copy(file, destFile, true);
}
}
}
[System.Serializable]
public class Item
{
[TableColumnWidth(60)]
[FolderPath, PropertyOrder(-1),HorizontalGroup("资源路径列表",0.25f)]
public string SourcePath;
[FolderPath, PropertyOrder(-1),HorizontalGroup("资源路径列表",0.25f)]
public string TargetPath;
[FilePath, PropertyOrder(-2),HorizontalGroup("资源路径列表",0.25f)]
public string TargeFiletPath;
[FilePath, PropertyOrder(-2),HorizontalGroup("资源路径列表",0.25f)]
public string SourceFilePath;
}
}
扩展:odin本身的floderpath并不支持项目外的文件夹拖拽,只能点按钮选择路径,为了更加方便的支持拖拽,我新增了一个属性拓展了它的功能,代码如下:
csharp
public class DraggableFloderPath:Attribute
{
}
public class DraggableFolderPathAttributeProcessor : OdinAttributeProcessor<DraggableFloderPath>
{
public override void ProcessSelfAttributes(InspectorProperty property, List<Attribute> attributes)
{
base.ProcessSelfAttributes(property,attributes);
attributes.Add(new FolderPathAttribute());
}
}
public class DraggableFolderPathDrawer : OdinAttributeDrawer<DraggableFloderPath, string>
{
protected override void DrawPropertyLayout(GUIContent label)
{
EditorGUILayout.BeginHorizontal();
// 创建输入框和拖拽区域
Rect dragArea= EditorGUILayout.GetControlRect();
ValueEntry.SmartValue = EditorGUI.TextField(dragArea, label, ValueEntry.SmartValue);
// 拖拽功能
if ((Event.current.type == EventType.DragUpdated || Event.current.type == EventType.DragPerform) && dragArea.Contains(Event.current.mousePosition))
{
DragAndDrop.visualMode = DragAndDropVisualMode.Copy;
if (Event.current.type == EventType.DragPerform)
{
DragAndDrop.AcceptDrag();
foreach (var path in DragAndDrop.paths)
{
if(File.GetAttributes(source).HasFlag(FileAttributes.Directory))
{
if (!string.IsNullOrEmpty(path) && Directory.Exists(path))
{
this.ValueEntry.SmartValue = path;
break;
}
}
else
{
this.ValueEntry.SmartValue = path;
break;
}
}
Event.current.Use();
}
}
// 绘制一个按钮
if (GUILayout.Button(EditorGUIUtility.IconContent("Folder Icon"),GUILayout.Width(30),GUILayout.Height(20)))
{
string selectedPath = EditorUtility.OpenFolderPanel("Select Folder", "", "");
if (!string.IsNullOrEmpty(selectedPath))
{
this.ValueEntry.SmartValue = selectedPath;
}
}
EditorGUILayout.EndHorizontal();
}
}
//然后就可以直接使用了
[System.Serializable]
public class Item
{
[TableColumnWidth(60)]
[DraggableFloderPath, PropertyOrder(-1),HorizontalGroup("资源路径列表",0.25f)]
public string SourcePath;
[DraggableFloderPath, PropertyOrder(-1),HorizontalGroup("资源路径列表",0.25f)]
public string TargetPath;
[DraggableFloderPath, PropertyOrder(-2),HorizontalGroup("资源路径列表",0.25f)]
public string TargeFiletPath;
[DraggableFloderPath, PropertyOrder(-2),HorizontalGroup("资源路径列表",0.25f)]
public string SourceFilePath;
}
这样生成出来的样式几乎跟floderpath一样,但是text区域可以支持拖拽,拷贝不同项目的文件更加方便。