using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Reflection; using System.Text; using System.Text.RegularExpressions; using UnityEditor; using UnityEngine; public class DllUtilities : EditorWindow { private static string guidPath { get { return Application.dataPath.MoveUp().Open("GuidList" + AssetConst.textExtension); } } private static string fileIdPath { get { return Application.dataPath.MoveUp().Open("FileIdList" + AssetConst.textExtension); } } private static string editorProjectRoot { get { return Application.dataPath.MoveUp().Open("JjbbDll/EditorDll/EditorDll/Code/"); } } private static string androidProjectRoot { get { return Application.dataPath.MoveUp().Open("JjbbDll/AndroidDll/AndroidDll/Code/"); } } private void OnGUI() { // if (GUILayout.Button("编译组件Guid")) // BuildGuidFile(); // GUILayout.Space(10f); // if (GUILayout.Button("编译组件FileId")) // BuildFileIdFile(); // GUILayout.Space(10f); if (GUILayout.Button("移动动态库代码")) { BuildGuidFile(); BuildFileIdFile(); MoveDllFiles(); } GUILayout.Space(10f); if (GUILayout.Button("替换全部组件")) ReplaceAllComponents(); } [MenuItem("Bundle V2/Dll Utilities/Open Window")] public static void Open() { GetWindow("动态库更新工具"); } private static Dictionary LoadFileAsDictionary(string path) { var list = File.ReadAllLines(path); var result = new Dictionary(); foreach (var line in list) if (!string.IsNullOrEmpty(line)) { var split = line.Trim().Split(';'); if (split.Length > 1) result[split[0]] = split[1]; } return result; } private static void ReplaceAllComponents() { var files = (from assetPath in AssetDatabase.GetAllAssetPaths() where assetPath.StartsWith(AssetConst.nonInternalHeader) where !assetPath.StartsWith(AssetConst.csAssetHeader) where AssetConst.prefabExtension.Equals(Path.GetExtension(assetPath), StringComparison.Ordinal) || AssetConst.sceneExtension.Equals(Path.GetExtension(assetPath), StringComparison.Ordinal) orderby assetPath select assetPath).ToArray(); var dllGuid = AssetDatabase.AssetPathToGUID("Assets/Project/Dll/JjbbDll.dll"); var guidRegex = new Regex("(?<=guid: ).+?(?=,)"); var fileIdRegex = new Regex("(?<=fileID: )11500000(?=\\D)"); const string header = " m_Script: {fileID: 11500000,"; var guidList = LoadFileAsDictionary(guidPath); var fileList = LoadFileAsDictionary(fileIdPath); var convertDict = new Dictionary(); foreach (var keyValue in fileList) { string guid; if (guidList.TryGetValue(keyValue.Key, out guid)) convertDict[guid] = keyValue.Value; } var count = 0; for (var i = 0; i < files.Length; i++) { EditorUtility.DisplayProgressBar("Replace Components", string.Format("{0} / {1}", i + 1, files.Length), (float) i / files.Length); var file = files[i]; var lines = File.ReadAllLines(file); var dirty = false; for (var j = 0; j < lines.Length; j++) { var line = lines[j]; if (line.Contains(header)) { var guid = guidRegex.Match(line); if (guid.Success) { var guidValue = guid.Value; string newFileId; if (convertDict.TryGetValue(guidValue, out newFileId)) { line = guidRegex.Replace(line, dllGuid); line = fileIdRegex.Replace(line, newFileId); lines[j] = line; dirty = true; } else { var assetPath = AssetDatabase.GUIDToAssetPath(guidValue); if (string.IsNullOrEmpty(assetPath)) Debug.LogWarning(string.Format("Empty component found at file: {0}!", file)); else if (IsProjectPath(assetPath) && IsProjectPath(file)) Debug.LogError(string.Format("Unable to found guid {0} at assetPath {1} at file {2}!", guidValue, assetPath, file)); } } else { Debug.LogError(string.Format("Unable to match line {0} with guid Regex!", line)); } } } if (dirty) { count++; var builder = new StringBuilder(); for (var j = 0; j < lines.Length; j++) { var line = lines[j]; if (j > 0) builder.Append('\n'); builder.Append(line); } File.WriteAllText(file, builder.ToString()); } } EditorUtility.ClearProgressBar(); Debug.LogWarning(string.Format("Total Conversion: {0}!", count)); } private static void CopyCodeToTarget(string assetPath, string targetProject) { assetPath = assetPath.Substring("Assets/".Length); var source = Application.dataPath.Open(assetPath); var target = targetProject.Open(assetPath); var dir = Path.GetDirectoryName(target); if (!Directory.Exists(dir)) Directory.CreateDirectory(dir); File.Copy(source, target); } private static void MoveDllFiles() { var assetPaths = (from assetPath in AssetDatabase.GetAllAssetPaths() where assetPath.StartsWith(AssetConst.nonInternalHeader) // 注:CsAsset里面会有特殊的初始化器,将会处于Android的非动态库Assembly中,用于驱动动态库 where IsProjectPath(assetPath) && !assetPath.StartsWith(AssetConst.csAssetHeader) where ".cs".Equals(Path.GetExtension(assetPath), StringComparison.Ordinal) orderby assetPath select assetPath).ToArray(); for (var i = 0; i < assetPaths.Length; i++) { EditorUtility.DisplayProgressBar("Copy Files", string.Format("{0} / {1}", i + 1, assetPaths.Length), (float) i / assetPaths.Length); CopyCodeToTarget(assetPaths[i], editorProjectRoot); CopyCodeToTarget(assetPaths[i], androidProjectRoot); } for (var i = 0; i < assetPaths.Length; i++) { EditorUtility.DisplayProgressBar("Delete Files", string.Format("{0} / {1}", i + 1, assetPaths.Length), (float) i / assetPaths.Length); var source = EditorCommonUtility.AssetToFilePath(assetPaths[i]); File.Delete(source); source += AssetConst.metaExtension; if (File.Exists(source)) File.Delete(source); } EditorUtility.ClearProgressBar(); } private static void BuildFileIdFile() { var assembly = Assembly.GetAssembly(typeof(LoginUILogic)); var types = assembly.GetTypes().Where(a => a.IsSubclassOf(typeof(MonoBehaviour))).ToArray(); var builder = new StringBuilder(); for (var i = 0; i < types.Length; i++) { EditorUtility.DisplayProgressBar("Compute FileId", string.Format("{0} / {1}", i + 1, types.Length), (float) i / types.Length); var type = types[i]; var fileId = FileIdUtility.Compute(type); var name = type.FullName; var dot = name.LastIndexOf('.'); if (dot > 0) name = name.Substring(dot); builder.AppendLine(string.Format("{0};{1}", name, fileId)); } EditorUtility.ClearProgressBar(); File.WriteAllText(Application.dataPath.MoveUp().Open("FileIdList.txt"), builder.ToString()); } private static bool IsProjectPath(string assetPath) { return !assetPath.Contains("/Editor/") && !assetPath.Contains("/Plugins/"); } private static void BuildGuidFile() { var allTargets = (from assetPath in AssetDatabase.GetAllAssetPaths() where assetPath.StartsWith(AssetConst.nonInternalHeader) where IsProjectPath(assetPath) where !assetPath.StartsWith("Assets/Project3D/BundleData/") let extension = Path.GetExtension(assetPath) where AssetConst.prefabExtension.Equals(extension, StringComparison.Ordinal) || AssetConst.sceneExtension.Equals(extension, StringComparison.Ordinal) select assetPath).ToArray(); var dict = new Dictionary(); var guidRegex = new Regex("(?<=guid: ).+?(?=,)"); var failedHash = new HashSet(); for (var i = 0; i < allTargets.Length; i++) { EditorUtility.DisplayProgressBar("Create Guid", string.Format("{0} / {1}", i + 1, allTargets.Length), (float) i / allTargets.Length); var assetPath = allTargets[i]; var lines = File.ReadAllLines(assetPath); foreach (var line in lines) if (line.Contains("m_Script: {fileID: 11500000,")) { var match = guidRegex.Match(line); if (!match.Success) { Debug.LogError(string.Format("Unable to match guid on line {0}!", line)); } else { var guid = match.Value; if (!dict.ContainsKey(guid)) dict[guid] = AssetDatabase.GUIDToAssetPath(guid); } } } EditorUtility.ClearProgressBar(); var builder = new StringBuilder(); foreach (var keyValue in dict) if (IsProjectPath(keyValue.Key)) builder.AppendLine(string.Format("{0};{1}", Path.GetFileNameWithoutExtension(keyValue.Value), keyValue.Key)); File.WriteAllText(guidPath, builder.ToString()); } }