using System; using System.Collections.Generic; using System.Linq; using System.Text; using UnityEditor; using UnityEngine; using System.IO; using ResMgr; using GameEditor.AssetBundle; using GameEditor.Core; using GameCore; using ResUpdate; using GameLogic; namespace GameEditor.FrameTool { public class FrameTool { /// /// 初始化游戏环境 /// //[MenuItem("GameFrame/InitResEnvironment", false, 1)] //public static void InitResEnvironment() //{ // ResourcesPathEditor.InitIgnoreList(); //} /// /// 刷新资源配置文件 /// [MenuItem("GameFrame/刷新资源配置", false, 2)] public static void RefreshResPathConfigs() { ResourcesPathEditor.CreateResourcePathConfig(); EditorUtil.ShowSureDialog("资源配置文件生成完毕!"); } /// /// 检查资源循环依赖 /// [MenuItem("GameFrame/检查循环依赖", false, 2)] public static void CheckDependences() { ResourcesPathEditor.ForEachCheckDependences(); EditorUtil.ShowSureDialog("检查完毕!"); } /// /// 战斗服务端验证同步 /// [MenuItem("GameFrame/战斗逻辑同步", false, 2)] public static void BattleLogicSync() { string p = Application.dataPath; p = p.Substring(0, p.LastIndexOf('/')); string t1 = p.Substring(p.LastIndexOf('/'), p.Length - p.LastIndexOf('/')); p = p.Substring(0, p.LastIndexOf('/')); string t2 = p.Substring(p.LastIndexOf('/'), p.Length - p.LastIndexOf('/')); p = p.Substring(0, p.LastIndexOf('/')); string p2 = p + "/battleWeb" + t2 + t1; string[] files = Directory.GetFiles(AppConst.GameResRealPath + "/~Lua/Modules/Battle/Logic", "*.lua", SearchOption.AllDirectories); foreach (var s in files) { string s2 = s.Replace(Application.dataPath + "/ManagedResources/~Lua", p2); FileUtils.CopyFile(s, s2); } Debug.LogError("同步完成!"); } /// /// 获取所有游戏 /// /// public static string[] GetAllGames() { string fullPath = EditorUtil.GetFullPath(AppConst.GameResPath); string[] directorys = Directory.GetDirectories(fullPath); string[] games = new string[directorys.Length]; string game = string.Empty; for (int i = 0; i < directorys.Length; i++) { game = Path.GetFileName(directorys[i]); games[i] = game; } return games; } /// /// 刷新选中资源配置文件 /// [MenuItem("Assets/GameFrame/RefreshResPathConfig")] public static void RefreshResPathConfig() { try { ResourcesPathEditor.CreateResourcePathConfig(); EditorUtil.ShowSureDialog("资源配置文件生成完毕!"); } catch (Exception e) { Debug.LogErrorFormat("RefreshResPathConfigError:{0}", e.ToString()); } } /// /// 整体打包 /// public static void BuildAll() { AssetBundleBuilder.ClearMarks(); BuildGameAssetBundles(); } [MenuItem("AssetBundle/MarkAllGame")] /// /// 标记所有游戏 /// public static void MarkAllGame() { MarkGame(false); ResourcesPathEditor.CreateResourcePathConfig(); } /// /// 检查AB包的资源合法性 /// 1.AssetBundle的循环依赖 /// 2.AssetBundle的跨游戏依赖 /// public static void CheckAssetBundleStates() { AssetBundleBuilder.ClearMarks(); MarkAllGame(); } public static void AssetsDuplicatedInMultBundlesCache(int type) { string target; foreach(var path in AssetBundleBrowser.AssetBundleModel.Model.AssetsDuplicatedInMultBundlesCache) { if(type == 1) { Debug.LogError("path:" + path); } else { Debug.LogError("正在移动:" + path); string extension = Path.GetExtension(path).ToLower(); switch (extension) { case ".png": case ".tga": target = "Textures/"; break; case ".mat": target = "Materials/"; break; case ".fbx": target = "Models/"; break; case ".anim": case ".controller": target = "Animations/"; break; default: target = null; break; } if (target != null) { File.Move(Application.dataPath + path.Replace("Assets", ""), AppConst.GameResRealPath + "/PublicArtRes/" + target + Path.GetFileNameWithoutExtension(path) + extension); File.Move(Application.dataPath + path.Replace("Assets", "") + ".meta", AppConst.GameResRealPath + "/PublicArtRes/" + target + Path.GetFileNameWithoutExtension(path) + extension + ".meta"); } } } AssetDatabase.Refresh(); } /// /// 打包游戏 /// public static void BuildGameAssetBundles() { AssetBundleBuilder.ClearMarks(); MarkGame(true); string exportPath = AssetBundleConfig.GetExportPath(EditorUserBuildSettings.activeBuildTarget); if (Directory.Exists(exportPath)) Directory.Delete(exportPath, true); AssetBundleBuilder.BuildAssetBundleWithType(exportPath, AssetBundleConfig.LZ4Options, EditorUserBuildSettings.activeBuildTarget, CompressType.LZ4); AssetBundleBuilder.BuildAssetBundleWithType(exportPath, AssetBundleConfig.LZMAOptions, EditorUserBuildSettings.activeBuildTarget, CompressType.LZMA); CreateCRCFiles(exportPath); AssetBundleBuilder.ClearManifest(exportPath); EditorUtil.OpenFolderAndSelectFile(exportPath); } /// /// 拷贝AssetBundle到StreamingAssets /// /// public static void CopyAssetBundleToStreamingAssets() { string exportPath = AssetBundleConfig.GetExportPath(EditorUserBuildSettings.activeBuildTarget); string streamingPath = GetStreamingAssetPath(EditorUserBuildSettings.activeBuildTarget); //Debug.LogError(streamingPath); if (Directory.Exists(streamingPath)) Directory.Delete(streamingPath,true); Directory.CreateDirectory(streamingPath); FileUtils.ReplaceDir(exportPath, streamingPath); //CopyResourceFiles(); } /// /// 单打lua资源 /// public static bool BuildLuaAssetBundles() { AssetImporter ai = AssetImporter.GetAtPath(AppConst.GameResPath + "/LuaBytes"); if(ai == null) { Debug.LogError("lua资源不存在!请先打全包!"); return false; } AssetBundleBuilder.ClearMarks(); MarkGame(true); AssetBundleBuild build = new AssetBundleBuild(); build.assetBundleName = ai.assetBundleName; build.assetBundleVariant = ai.assetBundleVariant; build.assetNames = new string[] { ai.assetPath }; AssetImporter ai2 = AssetImporter.GetAtPath(AppConst.GameResPath + "/ResConfigs"); AssetBundleBuild build2 = new AssetBundleBuild(); build2.assetBundleName = ai2.assetBundleName; build2.assetBundleVariant = ai2.assetBundleVariant; build2.assetNames = new string[] { ai2.assetPath }; string exportPath = AssetBundleConfig.GetExportPath(EditorUserBuildSettings.activeBuildTarget); var manifest = BuildPipeline.BuildAssetBundles(exportPath, new AssetBundleBuild[] { build, build2 }, BuildAssetBundleOptions.DeterministicAssetBundle, EditorUserBuildSettings.activeBuildTarget); // 加密 文件前加入128个空字符 foreach (var name in manifest.GetAllAssetBundles()) { var uniqueSalt = Encoding.UTF8.GetBytes(name); string pn = Path.Combine(exportPath, name); byte[] oldData = File.ReadAllBytes(pn); int len = (int)GameLogic.AppConst.EncyptBytesLength; int newOldLen = len + oldData.Length;//定死了,128个空byte var newData = new byte[newOldLen]; for (int tb = 0; tb < oldData.Length; tb++) { newData[len + tb] = oldData[tb]; } FileStream fs = File.OpenWrite(pn);//打开写入进去 fs.Write(newData, 0, newOldLen); fs.Close(); } CreateCRCFiles(exportPath); AssetBundleBuilder.ClearManifest(exportPath); AssetDatabase.Refresh(); return true; } /// /// 数据目录 /// static string AppDataPath { get { return Application.dataPath.ToLower(); } } public static void CopyResourceFiles() { string AssetRoot = "StreamingAssets/Android"; if (BuildTarget.iOS == EditorUserBuildSettings.activeBuildTarget) { AssetRoot = "StreamingAssets/IOS"; } string ResourcePath = "Resources/"; string resPath = AppDataPath + "/" + AssetRoot + "/"; ///----------------------创建文件列表----------------------- string newFilePath = resPath + "/" + ResourcePath; if (Directory.Exists(newFilePath)) Directory.Delete(newFilePath, true); Directory.CreateDirectory(newFilePath); string sourcePath = Application.dataPath + "/Resources/"; string[] files = Directory.GetFiles(sourcePath, "*", SearchOption.AllDirectories); foreach (var file in files) { FileInfo info = new FileInfo(file); File.Copy(file, newFilePath + info.Name, true); } } public static void SaveVersionFile() { } /// /// 创建CRC文件 /// /// public static void CreateCRCFiles(string exportPath) { string fullPath = exportPath; if (!Directory.Exists(fullPath)) return; string[] files = Directory.GetFiles(fullPath, "*.unity3d", SearchOption.AllDirectories); string savePath = string.Format("{0}/CRC/game.asset", Application.dataPath); string saveAssetPath = EditorUtil.GetAssetsPath(savePath); ResourceFiles resourceFiles = null; if (File.Exists(savePath)) { resourceFiles = AssetDatabase.LoadAssetAtPath(saveAssetPath); } else { string directory = Path.GetDirectoryName(savePath); if (!Directory.Exists(directory)) Directory.CreateDirectory(directory); resourceFiles = ScriptableObject.CreateInstance(); AssetDatabase.CreateAsset(resourceFiles,saveAssetPath); } if (resourceFiles == null) { string message = string.Format("资源CRC信息列表文件{0}错误,请查看", savePath); EditorUtility.DisplayDialog("提示", message, "确定"); return; } if(resourceFiles.files==null) resourceFiles.files = new List(); resourceFiles.files.Clear(); FileInfo info = null; ResourceFile file = null; for (int i = 0; i < files.Length; i++) { files[i] = EditorUtil.FixedWindowsPath(files[i]); info = new FileInfo(files[i]); file = new ResourceFile(); file.id = i + 1; file.fileName = files[i].Replace(exportPath+"/",string.Empty); file.size = info.Length; file.crc = FileToCRC32.GetFileCRC32(files[i]); resourceFiles.files.Add(file); } EditorUtility.SetDirty(resourceFiles); AssetDatabase.SaveAssets(); AssetDatabase.Refresh(); AssetBundleBuilder.BuildAssetBundle(resourceFiles, "files", exportPath, AssetBundleConfig.LZMAOptions, EditorUserBuildSettings.activeBuildTarget); } /// /// 拷贝Lua文件 /// public static void CopyLuaFiles() { try { string luaBytesFullPath = EditorUtil.GetFullPath(string.Format("{0}/LuaBytes", AppConst.GameResPath)); if (!Directory.Exists(luaBytesFullPath)) { Directory.CreateDirectory(luaBytesFullPath); } List files = EditorUtil.GetFiles(luaBytesFullPath, "*", SearchOption.AllDirectories); for (int i = 0; i < files.Count; i++) { File.Delete(files[i]); } string luaFullPath = EditorUtil.GetFullPath(string.Format("{0}/~Lua", AppConst.GameResPath)); files = EditorUtil.GetFiles(luaFullPath, "*.lua", SearchOption.AllDirectories); string inPath = string.Empty; string outPath = string.Empty; for (int i = 0; i < files.Count; i++) { inPath = files[i]; outPath = inPath.Replace(luaFullPath+"/", string.Empty).Replace("/","%").Replace(".lua",".bytes"); outPath = luaBytesFullPath + "/" + outPath; //FileUtils.CopyFile(inPath, outPath); Packager.EncodeLuaFile(inPath, outPath); } Debug.LogFormat("拷贝Lua文件完成!"); AssetDatabase.Refresh(); } catch (Exception e) { Debug.LogErrorFormat("CopyLuaFiles error:{0}",e); } } /// /// 处理lua文件 /// /// /// public static void HandleLuaFile(string inpath, string outPath) { } /// /// 标记一个游戏 /// public static void MarkGame(bool refreshConfig = false) { try { //拷贝Lua文件 CopyLuaFiles(); //标记Lua string buildConfigPath = string.Format("{0}/EditorConfigs/BuildConfigs.asset", AppConst.GameResPath); AssetBundleBuildConfigs configs = AssetDatabase.LoadAssetAtPath(buildConfigPath); AssetBundleBuildConfig[] paths = configs.OneFloderOneBundle; for (int i = 0; i < paths.Length; i++) { if (string.IsNullOrEmpty(paths[i].Path)) { Debug.LogErrorFormat("MarkGame error:BuildConfigs contain null floder." + paths[i].Path); continue; } AssetBundleBuilder.MarkOneFloderOneBundle(paths[i].Path, paths[i].CompressType); } paths = configs.SubFloderOneBundle; for (int i = 0; i < paths.Length; i++) { if (string.IsNullOrEmpty(paths[i].Path)) { Debug.LogErrorFormat("MarkGame error:BuildConfigs contain null floder."); continue; } AssetBundleBuilder.MarkSubFloderOneBundle(paths[i].Path,paths[i].CompressType); } paths = configs.OneAssetOneBundle; for (int i = 0; i < paths.Length; i++) { if (string.IsNullOrEmpty(paths[i].Path)) { Debug.LogErrorFormat("MarkGame error:BuildConfigs contain null floder"); continue; } AssetBundleBuilder.MarkOneAssetOneBundle(paths[i].Path, true, paths[i].CompressType); } if (refreshConfig)ResourcesPathEditor.CreateResourcePathConfig(); Debug.LogFormat("标记游戏完成!"); } catch (Exception e) { Debug.LogErrorFormat("MarkGameError:{0}", e); } } /// /// 获取流媒体目录 /// /// /// public static string GetStreamingAssetPath(BuildTarget target) { string floder = "Other"; switch (target) { case BuildTarget.Android: floder = "Android"; break; case BuildTarget.iOS: floder = "IOS"; break; case BuildTarget.StandaloneWindows: floder = "Windows"; break; case BuildTarget.StandaloneWindows64: floder = "Windows"; break; } return Application.streamingAssetsPath + "/" + floder; } } }