hengyang_client/wb_unity_pro/Assets/Scripts/Editor/PackUtil.cs

769 lines
27 KiB
C#
Raw Normal View History

2025-06-10 16:11:48 +08:00

using UnityEditor;
using UnityEngine;
using System.IO;
using System.Collections.Generic;
using System.Security.Cryptography;
using System.Text;
using System;
using System.Text.RegularExpressions;
using LuaInterface;
using System.Collections;
using MiniJSON;
using System.Diagnostics;
using System.Threading;
using taurus.unity;
using taurus.client;
public class PackUtil
{
const string ART_DIR = "Assets/ART/";
const string RES_DIR = "Assets/Resources/";
public static string HOT_EXTEND_PATH = "";
public static string HOT_BASE_PATH = "";
static void __ClearAllAssetNames()
{
string[] assetBundleNames = AssetDatabase.GetAllAssetBundleNames();
if (assetBundleNames == null || assetBundleNames.Length <= 0)
return;
for (int i = 0; i < assetBundleNames.Length; ++i)
{
float process = ((float)i) / ((float)assetBundleNames.Length);
EditorUtility.DisplayProgressBar("清理Tag中...", assetBundleNames[i], process);
AssetDatabase.RemoveAssetBundleName(assetBundleNames[i], true);
}
EditorUtility.ClearProgressBar();
}
static string[] __GetBuildScenes()
{
List<string> names = new List<string>();
foreach (EditorBuildSettingsScene e in EditorBuildSettings.scenes)
{
if (e == null)
continue;
if (e.enabled)
names.Add(e.path);
}
return names.ToArray();
}
/// <summary>
/// 判断目标是文件夹还是目录(目录包括磁盘)
/// </summary>
/// <param name="filepath">文件名</param>
/// <returns></returns>
static bool __IsDir(string filepath)
{
FileInfo fi = new FileInfo(filepath);
if ((fi.Attributes & FileAttributes.Directory) != 0)
return true;
else
{
return false;
}
}
class HashFile
{
public string hash;
public string hash_path;
public string path;
public long fileSzie;
public HashFile()
{
}
public HashFile(string hash_path,string hash,string path)
{
this.hash_path = hash_path;
this.hash = hash;
this.path = path;
}
public override string ToString()
{
return hash_path + "|" + hash + "|" + path+"|"+ (fileSzie /1024)+"KB";
}
}
#region pack asset
static void PackAsset_Effect(string dir, string type, string path, BuildTarget target, List<AssetConfig> ncList)
{
var tem_path = dir + path + "/effect";
var _cr_all_prefab = AssetDatabase.FindAssets("", new string[] { tem_path });
StringBuilder sb = new StringBuilder();
for (int i = 0; i < _cr_all_prefab.Length; i++)
{
var guid = _cr_all_prefab[i];
string assetPath = AssetDatabase.GUIDToAssetPath(guid);
if (__IsDir(assetPath))
{
sb.Append(assetPath);
string[] files = Directory.GetFiles(assetPath, "*.prefab", SearchOption.TopDirectoryOnly);
assetPath = assetPath.Replace(dir, string.Empty);
var packPath = assetPath.Replace('/', '$');
packPath = type + "/" + MD5Str(packPath);
foreach (string str in files)
{
var tem_str = str.Replace('\\', '/');
sb.AppendLine();
sb.Append("--" + tem_str);
AssetImporter ai = AssetImporter.GetAtPath(tem_str);
ai.assetBundleName = packPath;
FileInfo fi = new FileInfo(tem_str);
tem_str = tem_str.Replace(dir, string.Empty);
var name = fi.Name.Replace(fi.Extension, string.Empty);
var ac = new AssetConfig()
{
Name = name,
Path = tem_str,
PackPath = packPath
};
ncList.Add(ac);
}
sb.AppendLine();
}
}
//UnityEngine.Debug.Log(StringBuilderCache.GetStringAndRelease(sb));
}
static void PackAsset_UI(string dir,string type,string path,BuildTarget target, List<AssetConfig> ncList)
{
var tem_path = dir + path + "/ui";
var _cr_allui = AssetDatabase.FindAssets("_fui", new string[] { tem_path });
List<string> _uipage_list = new List<string>();
List<string> _path_list = new List<string>();
for (int j = 0; j < _cr_allui.Length; j++)
{
var guid = _cr_allui[j];
string assetPath = AssetDatabase.GUIDToAssetPath(guid);
FileInfo fi = new FileInfo(assetPath);
if (fi.Extension != ".bytes") continue;
assetPath = assetPath.Replace(fi.Name, string.Empty);
_path_list.Add(assetPath);
_uipage_list.Add(fi.Name.Replace("_fui.bytes", string.Empty));
}
var fileCurNum = 0;
var fileNum = _uipage_list.Count * 2;
var i = 0;
foreach (string str in _uipage_list)
{
var _cr_ui = AssetDatabase.FindAssets(str + "_", new string[] { tem_path });
i++;
var packPath = (path + "/ui"+ str).Replace('/', '$');
packPath = type + "/" +MD5Str(packPath);
for (int j = 0; j < _cr_ui.Length; j++)
{
var guid = _cr_ui[j];
var assetPath = AssetDatabase.GUIDToAssetPath(guid);
FileInfo fi = new FileInfo(assetPath);
AssetImporter ai = AssetImporter.GetAtPath(assetPath);
ai.assetBundleName = packPath;
assetPath = assetPath.Replace(dir, string.Empty);
var name = fi.Name.Replace(fi.Extension, string.Empty);
fileCurNum++;
float process = ((float)fileCurNum) / (fileNum);
EditorUtility.DisplayProgressBar(path+"->设置UI资源Tag中...", assetPath, process);
AssetConfig ac = new AssetConfig()
{
Name = name,
Path = assetPath,
PackPath = packPath
};
ncList.Add(ac);
}
}
}
static void PackAsset_BG(string dir, string type,string path, BuildTarget target, List<AssetConfig> ncList)
{
var tem_path = dir + path + "/bg";
var _cr_allbg = AssetDatabase.FindAssets("t:Texture", new string[] { tem_path });
var fileNum = _cr_allbg.Length;
var fileCurNum = 0;
for (int j = 0; j < _cr_allbg.Length; j++)
{
var guid = _cr_allbg[j];
string assetPath = AssetDatabase.GUIDToAssetPath(guid);
FileInfo fi = new FileInfo(assetPath);
if (fi.Extension != ".png") continue;
AssetImporter ai = AssetImporter.GetAtPath(assetPath);
assetPath = assetPath.Replace(dir, string.Empty);
var name = fi.Name.Replace(fi.Extension, string.Empty);
var packPath = assetPath.Replace(fi.Extension, string.Empty).Replace('/', '$');
packPath = type + "/" + MD5Str(packPath.ToLower());
ai.assetBundleName = packPath;
fileCurNum++;
float process = ((float)fileCurNum) / (fileNum);
EditorUtility.DisplayProgressBar(path+"->设置背景Tag中...", assetPath, process);
AssetConfig ac = new AssetConfig()
{
Name = name,
Path = assetPath,
PackPath = packPath
};
ncList.Add(ac);
}
}
static void PackAsset_Sound(string dir, string type, string path, BuildTarget target, List<AssetConfig> ncList)
{
var tem_path = dir + path + "/sound";
var _cr_allsound = AssetDatabase.FindAssets("t:AudioClip", new string[] { tem_path });
var fileNum = _cr_allsound.Length;
var fileCurNum = 0;
for (int j = 0; j < _cr_allsound.Length; j++)
{
var guid = _cr_allsound[j];
string assetPath = AssetDatabase.GUIDToAssetPath(guid);
FileInfo fi = new FileInfo(assetPath);
AssetImporter ai = AssetImporter.GetAtPath(assetPath);
assetPath = assetPath.Replace(dir, string.Empty);
var name = fi.Name.Replace(fi.Extension, string.Empty);
var packPath = assetPath.Replace(fi.Extension, string.Empty).Replace('/', '$');
packPath = type + "/" + MD5Str(packPath);
ai.assetBundleName = packPath;
fileCurNum++;
float process = ((float)fileCurNum) / (fileNum);
EditorUtility.DisplayProgressBar("设置声音Tag中...", assetPath, process);
AssetConfig ac = new AssetConfig()
{
Name = name,
Path = assetPath,
PackPath = packPath
};
ncList.Add(ac);
}
}
static void PackAsset_Curve(string dir, string type, string path, BuildTarget target, List<AssetConfig> ncList)
{
var tem_path = dir + path + "/curve";
var _cr_allcurve = AssetDatabase.FindAssets("t", new string[] { tem_path });
var _curve_pack = type + "/" + MD5Str("curve$data");
for (int j = 0; j < _cr_allcurve.Length; j++)
{
var guid = _cr_allcurve[j];
string assetPath = AssetDatabase.GUIDToAssetPath(guid);
FileInfo fi = new FileInfo(assetPath);
if (fi.Extension != ".asset") continue;
AssetImporter ai = AssetImporter.GetAtPath(assetPath);
ai.assetBundleName = _curve_pack;
assetPath = assetPath.Replace(dir, string.Empty);
var name = fi.Name.Replace(fi.Extension, string.Empty);
AssetConfig ac = new AssetConfig()
{
Name = name,
Path = assetPath,
PackPath = _curve_pack
};
ncList.Add(ac);
}
}
static void PackAsset_Font(string dir, string type, string path, BuildTarget target, List<AssetConfig> ncList)
{
var tem_path = dir + path + "/fonts";
var _cr_allfont = AssetDatabase.FindAssets("t:Font", new string[] { tem_path });
var fileNum = _cr_allfont.Length;
var fileCurNum = 0;
for (int j = 0; j < _cr_allfont.Length; j++)
{
var guid = _cr_allfont[j];
string assetPath = AssetDatabase.GUIDToAssetPath(guid);
FileInfo fi = new FileInfo(assetPath);
AssetImporter ai = AssetImporter.GetAtPath(assetPath);
assetPath = assetPath.Replace(dir, string.Empty);
var name = fi.Name.Replace(fi.Extension, string.Empty);
var packPath = assetPath.Replace(fi.Extension, string.Empty).Replace('/', '$');
packPath = type + "/" + MD5Str(packPath);
ai.assetBundleName = packPath;
fileCurNum++;
float process = ((float)fileCurNum) / (fileNum);
EditorUtility.DisplayProgressBar("设置字体Tag中...", assetPath, process);
AssetConfig ac = new AssetConfig()
{
Name = name,
Path = assetPath,
PackPath = packPath
};
ncList.Add(ac);
}
}
static void PackAsset_All_Res(string type, string path, BuildTarget target, List<AssetConfig> ncList)
{
PackAsset_All(RES_DIR, type, path, target, ncList);
}
static void PackAsset_All(string type, string path, BuildTarget target, List<AssetConfig> ncList)
{
PackAsset_All(ART_DIR, type, path, target, ncList);
}
static void PackAsset_All(string dir,string type, string path, BuildTarget target, List<AssetConfig> ncList)
{
PackAsset_Effect(dir,type, path, target, ncList);
PackAsset_UI(dir, type, path, target, ncList);
PackAsset_BG(dir, type, path, target, ncList);
PackAsset_Sound(dir, type, path, target, ncList);
PackAsset_Curve(dir, type, path, target, ncList);
PackAsset_Font(dir, type, path, target, ncList);
}
static string WriteAssetConfig(List<AssetConfig> ncList, string pack_path, string type, Dictionary<string, HashFile> filehash)
{
var array = new ByteArray();
array.writeInt(ncList.Count);
foreach (AssetConfig config in ncList)
{
array.writeString(config.Name);
array.writeString(config.Path);
array.writeString(config.PackPath);
if (filehash != null && !filehash.ContainsKey(config.PackPath))
{
HashFile hf = new HashFile(config.PackPath, MD5file(pack_path + "/" + config.PackPath), config.Path);
FileInfo fileInfo = new FileInfo(pack_path + "/" + config.PackPath);
hf.fileSzie = fileInfo.Length;
filehash.Add(config.PackPath, hf);
}
}
var dir = pack_path + "/" + type + "/";
if (!Directory.Exists(dir))
{
Directory.CreateDirectory(dir);
}
//写入资源配置
var config_pack = dir + "asset_config.bytes";
File.WriteAllBytes(config_pack, array.bytes);
return config_pack;
}
#endregion
static bool isBuild = false;
public static void PackAsset(BuildTarget target,bool pack_test, ArrayList config_list = null)
{
if (!isBuild && EditorApplication.isCompiling)
{
EditorUtility.DisplayDialog("警告", "请等待编辑器完成编译再执行此功能", "确定");
return;
}
isBuild = true;
EditorUserBuildSettings.SwitchActiveBuildTarget(target);
AssetDatabase.Refresh();
__ClearAllAssetNames();
AssetDatabase.Refresh();
if (config_list == null)
{
return;
}
string fileName = Application.dataPath.Substring(0, Application.dataPath.Length - "Assets".Length) + "Pack/";
for (int i = 0; i < config_list.Count; ++i)
{
var tem = (Hashtable)config_list[i];
if (tem.ContainsKey("is_pack") && !(bool)tem["is_pack"]) continue;
var ver = tem["ver"];
var is_res = tem.ContainsKey("is_res") ? (bool)tem["is_res"] : false;
var p_name = (string)tem["name"];
UnityEngine.Debug.Log("base_name:" + p_name);
var asset_path = "base/"+ p_name;
string tempdir = ResourcesManager.OS_Dir;
if (BuildBaseWindow.build32Lua)
{
tempdir = tempdir + "32";
}
var version_path = string.Format("{0}/{1}/{2}/", fileName, tempdir, asset_path);
if (!Directory.Exists(version_path))
{
Directory.CreateDirectory(version_path);
}
//setp 1 创建资源包临时目录
var pack_path = fileName + "temp";
if (Directory.Exists(pack_path + "/"))
{
Directory.Delete(pack_path + "/", true);
}
Directory.CreateDirectory(pack_path + "/");
//setp 2 设置bundles配置
var ncList = new List<AssetConfig>();
if (is_res)
{
PackAsset_All_Res(asset_path, asset_path, target, ncList);
}
else
{
PackAsset_All(asset_path, asset_path, target, ncList);
}
if (ncList.Count > 0)
{
var option = BuildAssetBundleOptions.ChunkBasedCompression | BuildAssetBundleOptions.DeterministicAssetBundle |
BuildAssetBundleOptions.DisableWriteTypeTree;
BuildPipeline.BuildAssetBundles(pack_path, option, target);
//setp 3 生成MD5码
EditorUtility.DisplayProgressBar("", "正在生成MD5码", 0.5f);
//var filehash = new Dictionary<string, HashFile>();
var config_pack = WriteAssetConfig(ncList, pack_path, asset_path, null);
}
//setp 4 打包lua脚本
bool lua = false;
var tem_str = (string)tem["lua_path"];
if (!string.IsNullOrEmpty(tem_str))
{
var lua_paths = new List<string>();
var tem_arr = tem_str.Split(',');
foreach (string str in tem_arr)
{
lua_paths.Add(LuaConst.luaDir + str);
}
LuaBuildUtil.BuildLuaBundles(pack_path, lua_paths);
lua = lua_paths.Count > 0;
//filehash.Add("lua_pack", new HashFile("lua_pack", MD5file(pack_path + "/lua_pack"), "lua_pack"));
}
EditorUtility.DisplayProgressBar("", "正在压缩打包资源", 0.5f);
//setp 5 打包资源,无压缩
if(lua || ncList.Count > 0)
{
var file_name = string.Format("asset_pack{0}.bytes", (string)tem["ver"]);
var file = version_path + file_name;
CreateAssetPack(pack_path, file);
// #if UNITY_IPHONE
// if (tem.ContainsKey("check")&& (bool)tem["check"])
// {
// CopyStreamPath(file, asset_path,file_name);
// }
// #endif
if (!string.IsNullOrEmpty(HOT_BASE_PATH))
{
string tempdir1 = ResourcesManager.OS_Dir;
if (BuildBaseWindow.build32Lua)
{
tempdir1 = tempdir1 + "32";
}
var tem_path = string.Format("{0}/{1}/{2}/{3}", HOT_BASE_PATH, tempdir1, asset_path, file_name);
var dir = Path.GetDirectoryName(tem_path);
if (!Directory.Exists(dir))
{
Directory.CreateDirectory(dir);
}
if (File.Exists(tem_path)) File.Delete(tem_path);
File.Copy(file, tem_path);
}
}
else
{
Directory.Delete(version_path, true);
}
Directory.Delete(pack_path + "/", true);
__ClearAllAssetNames();
}
AssetDatabase.Refresh();
EditorUtility.ClearProgressBar();
EditorUtility.UnloadUnusedAssetsImmediate();
System.GC.Collect();
isBuild = false;
}
public static void PackAsset_Extend(BuildTarget target,bool pack_test,ArrayList config_list = null)
{
if (!isBuild && EditorApplication.isCompiling)
{
EditorUtility.DisplayDialog("警告", "请等待编辑器完成编译再执行此功能", "确定");
return;
}
isBuild = true;
EditorUserBuildSettings.SwitchActiveBuildTarget(target);
AssetDatabase.Refresh();
__ClearAllAssetNames();
if (config_list == null)
{
return;
}
string fileName = Application.dataPath.Substring(0, Application.dataPath.Length - "Assets".Length) + "Pack";
for (int i = 0; i < config_list.Count; ++i)
{
var tem = (Hashtable)config_list[i];
if (tem.ContainsKey("is_pack") && !(bool)tem["is_pack"]) continue;
UnityEngine.Debug.Log("id:" + tem["game_id"] + "name:" + tem["name"]);
var asset_path = (string)tem["bundle"];
asset_path = asset_path.Replace('.', '/');
string tempdir = ResourcesManager.OS_Dir;
if (BuildBaseWindow.build32Lua)
{
tempdir = tempdir + "32";
}
var version_path = string.Format("{0}/{1}/{2}/", fileName, tempdir, asset_path);
if (!Directory.Exists(version_path))
{
Directory.CreateDirectory(version_path);
}
//setp 3 创建资源包临时目录
var pack_path = fileName + "/temp";
if (Directory.Exists(pack_path + "/"))
{
Directory.Delete(pack_path + "/", true);
}
Directory.CreateDirectory(pack_path + "/");
var ncList = new List<AssetConfig>();
PackAsset_All(asset_path, asset_path, target, ncList);
var option = BuildAssetBundleOptions.ChunkBasedCompression | BuildAssetBundleOptions.DeterministicAssetBundle |
BuildAssetBundleOptions.DisableWriteTypeTree;
BuildPipeline.BuildAssetBundles(pack_path, option, target);
//正在生成MD5码
EditorUtility.DisplayProgressBar((string)tem["name"], "正在生成MD5码", 0.5f);
var config_pack = WriteAssetConfig(ncList, pack_path, asset_path, null);
var lua_dir = LuaConst.luaDir + "/extend_project/" + asset_path;
if (!string.IsNullOrEmpty(lua_dir))
{
//打包lua脚本
LuaBuildUtil.BuildLuaBundles(pack_path, new List<string>() { lua_dir },asset_path);
}
var file_name = string.Format("asset_pack{0}.bytes", (string)tem["version"]);
var file = version_path + file_name;
CreateAssetPack(pack_path, file);
Directory.Delete(pack_path + "/", true);
if (!string.IsNullOrEmpty (HOT_EXTEND_PATH))
{
var tem_path = string.Format("{0}/{1}/{2}/{3}",HOT_EXTEND_PATH ,ResourcesManager.OS_Dir,asset_path,file_name);
var dir = Path.GetDirectoryName(tem_path);
if (!Directory.Exists(dir))
{
Directory.CreateDirectory(dir);
}
if (File.Exists(tem_path)) File.Delete(tem_path);
File.Copy(file, tem_path);
}
__ClearAllAssetNames();
}
AssetDatabase.Refresh();
EditorUtility.ClearProgressBar();
EditorUtility.UnloadUnusedAssetsImmediate();
System.GC.Collect();
isBuild = false;
}
public static void DeleteFilesAndFoldersRecursively(string target_dir)
{
foreach (string file in Directory.GetFiles(target_dir))
{
File.Delete(file);
}
foreach (string subDir in Directory.GetDirectories(target_dir))
{
DeleteFilesAndFoldersRecursively(subDir);
}
Thread.Sleep(1); // This makes the difference between whether it works or not. Sleep(0) is not enough.
Directory.Delete(target_dir);
}
static MD5CryptoServiceProvider md5 = new MD5CryptoServiceProvider();
/// <summary>
/// 计算文件的MD5值
/// </summary>
static string MD5file(string file)
{
try
{
FileStream fs = new FileStream(file, FileMode.Open);
byte[] retVal = md5.ComputeHash(fs);
fs.Close();
StringBuilder sb = new StringBuilder();
for (int i = 0; i < retVal.Length; i++)
{
sb.Append(retVal[i].ToString("x2"));
}
return sb.ToString();
}
catch (Exception ex)
{
throw new Exception("md5file() fail, error:" + ex.Message);
}
}
static string MD5Str(string msg)
{
try
{
System.Security.Cryptography.MD5 md5 = System.Security.Cryptography.MD5.Create();
byte[] inputBytes = System.Text.Encoding.ASCII.GetBytes(msg);
byte[] hash = md5.ComputeHash(inputBytes);
StringBuilder sb = new StringBuilder();
for (int i = 0; i < hash.Length; i++)
{
sb.Append(hash[i].ToString("x2"));
}
return sb.ToString();
}
catch (Exception ex)
{
throw new Exception("md5str() fail, error:" + ex.Message);
}
}
static void CreateAssetPack(string dir, string filename)
{
IFilePack zf = null;
zf = new FilePack20(filename, PackMode.Write);
zf.PackFile(dir, ".meta|.manifest");
zf = null;
}
static void CopyStreamPath(string src_file, string base_path,string file_name)
{
var sap = Application.streamingAssetsPath + string.Format("/{0}/{1}", ResourcesManager.OS_Dir, base_path);
if (!Directory.Exists(sap))
{
Directory.CreateDirectory(sap);
}
var pack_path = sap + "/" + file_name;
if (File.Exists(pack_path)) File.Delete(pack_path);
File.Copy(src_file, pack_path);
}
static bool SetScriptingDefineSymbolsForGroup(BuildTargetGroup target, string symbolsForGroup)
{
PlayerSettings.SetScriptingDefineSymbolsForGroup(target, symbolsForGroup);
return true;
}
public static void BuildForAndroid_Test()
{
PlayerSettings.Android.keystoreName = Application.dataPath + "/../debug.keystore";
PlayerSettings.Android.keystorePass = "android";
PlayerSettings.keyaliasPass = "androiddebugkey";
PlayerSettings.keyaliasPass = "android";
}
[MenuItem("BuildTools/Opt-App(Pro)")]
static void BuildForApp_Pro()
{
if (!isBuild && EditorApplication.isCompiling)
{
EditorUtility.DisplayDialog("警告", "请等待编辑器完成编译再执行此功能", "确定");
return;
}
BuildTargetGroup target = BuildTargetGroup.Standalone;
#if UNITY_IPHONE
target = BuildTargetGroup.iOS;
#elif UNITY_ANDROID
target = BuildTargetGroup.Android;
#endif
isBuild = SetScriptingDefineSymbolsForGroup(target, "FAIRYGUI_TOLUA;Build_App;NOT_ACCOUT_TEST;NOT_HOUSE_TEST");
#if UNITY_ANDROID
BuildForAndroid_Test();
#endif
UnityEngine.Debug.Log("set pro...");
isBuild = false;
}
[MenuItem("BuildTools/Opt-App(Test)")]
static void BuildForApp_Test()
{
if (!isBuild && EditorApplication.isCompiling)
{
EditorUtility.DisplayDialog("警告", "请等待编辑器完成编译再执行此功能", "确定");
return;
}
BuildTargetGroup target = BuildTargetGroup.Standalone;
#if UNITY_IPHONE
target = BuildTargetGroup.iOS;
#elif UNITY_ANDROID
target = BuildTargetGroup.Android;
#endif
isBuild = SetScriptingDefineSymbolsForGroup(target, "FAIRYGUI_TOLUA;Build_App;NOT_ACCOUT_TEST;NOT_HOUSE_TEST;INIT_JSON_TEST");
#if UNITY_ANDROID
BuildForAndroid_Test();
#endif
UnityEngine.Debug.Log("set test...");
isBuild = false;
}
static BuildTarget GetBuildTarget()
{
BuildTarget target = BuildTarget.StandaloneWindows64;
#if UNITY_IPHONE
target = BuildTarget.iOS;
#elif UNITY_ANDROID
target = BuildTarget.Android;
#endif
return target;
}
public static void Specify_Pack_Custom(BuildTarget target,ArrayList config_list)
{
PackAsset_Extend(target, true,config_list);
}
public static void Base_Pack_Custom(BuildTarget target,ArrayList config_list)
{
PackAsset(target, true, config_list);
}
}