复制预制体并把依赖的其他模块资源一起复制一份到指定模块
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
}