SplitPacket_Main - woodelf-treetop/rcwiki GitHub Wiki
先说一下当时设计分包的思路。
我们分包的需求只是将多语言图片和CV做了分包处理,其中CV占大部分内存。
所以在打bundle资源的时候,就需要将这些资源打成单独的bundle。
由于和bundle相关,所以我将一些基础的设置放在了【Utility.cs】脚本里。
首先是分包的类型,这里用了枚举。
我们所有不需要分包的资源(会打进包体里的资源)是默认资源包——DefaultPacket。
枚举值的value为1/2/3/4/5的是CV资源包,6/7/8/9/10的是图片资源包。这里的分包都是基于语言的。
上图写了两个分包的帮助类,做数据初始化,方便使用的。
这里我们建立了两个Get方法。
GetAllPacketEnum()方法是根据枚举值OtherPacket得到PacketEnumInfo类。
GetPacketAccordingToLanguageInt()方法是根据语言Id得到改语言所属的CV和Pic分包。
接下来就是对打包时候的处理。
这里是在原有的打包规则基础上进行了打包后的资源路径修改,使我们的分包打在想要的位置。
上图代码块(BuildRule.cs)中是在原有的路径基础上增加了规划后的名称。理论上是找路径中有没有存在该枚举值字段名,从而确定是属于哪种分包,所以分包名称不要用于其他文件的文件夹名。
Utility.PacketBundlesOutPutName = "PacketBundles"
enumInfo.Value.nameToLower是枚举值转成string后再做ToLower的值。
用上面两个值拼在路径最开头,从而得到我们想要的结果。
我们在Project中也会设置相应的文件夹,文件夹的名称我们用的是枚举 OtherPacket 转化成String的名称。所以这里要注意名称的统一,否则打包得不到正确的结果。
总之是在new AssetBundleBuild的时候,将assetBundleName包了一层。注意这里只做了基于文件夹和基于文件的打包模式,如果要还要支持别的模式,请后续自己添加就行。
这样我们打完包之后就是下图的样子了。
bundle已经打出来了,接下来我们需要的是将bundle资源copy到streamingassets文件夹下,并做资源分析。
这一步主要是在Packager.cs中的BuildFileIndex()方法实现的。
而我们也是做了两套资源分析文件——files.txt 和 otherPacket.txt
static void OpFiles()
{
//files.txt 是正常的资源路径文件
//otherPacket.txt 是分包的资源路径文件
string resPath = AppDataPath + "/StreamingAssets/";
string newFilePath = resPath + "/files.txt";
if (File.Exists(newFilePath)) File.Delete(newFilePath);
string otherLFilePath = resPath + "/otherPacket.txt";
if (File.Exists(otherLFilePath)) File.Delete(otherLFilePath);
paths.Clear(); files.Clear();
Recursive(resPath);
FileStream fs = new FileStream(newFilePath, FileMode.CreateNew);
StreamWriter sw = new StreamWriter(fs);
FileStream ots = new FileStream(otherLFilePath, FileMode.CreateNew);
StreamWriter otSw = new StreamWriter(ots);
float allFilesSize = 0;
for (int i = 0; i < files.Count; i++)
{
string file = files[i];
//这一部分是:不记录分包的数据大小
if (file.StartsWith(Utility.PacketBundlesOutPutName)) continue;
FileInfo fileIF = new FileInfo(file);
long fileSize = fileIF.Length;
allFilesSize += fileSize;
}
sw.WriteLine(allFilesSize);
var enumInfos = Utility.GetAllPacketEnum();
for (int i = 0; i < files.Count; i++) {
string file = files[i];
FileInfo fileIF = new FileInfo(file);
long fileSize = fileIF.Length;
if (file.EndsWith(".meta") || file.EndsWith(".manifest")) continue;
string md5 = Util.md5file(file);
string value = file.Replace(resPath, string.Empty);
OtherPacket packetEnum = OtherPacket.DefaultPacket;
foreach (var enumInfo in enumInfos)
{
if (enumInfo.Key == OtherPacket.DefaultPacket) continue;
if (file.Contains(enumInfo.Value.nameToLower))
{
packetEnum = enumInfo.Key;
break;
}
}
if (packetEnum.Equals(OtherPacket.DefaultPacket))
{
sw.WriteLine(value + "|" + md5 + "|" + fileSize + "|" + packetEnum.ToString().ToLower());
}
else
{
otSw.WriteLine(value + "|" + md5 + "|" + fileSize + "|" + packetEnum.ToString().ToLower());
}
}
sw.Close(); fs.Close();
otSw.Close(); ots.Close();
}这里是将默认资源和分包资源的信息文件分开,因为我们在解压资源的时候是依赖files文件。
这里说一下信息文件里的格式:
他们两个的信息格式基本一样:资源路径 | Md5码 | 文件大小 | 包体类型
他们主要的区别在于包体类型上。在最初始的这两个文件里,files文件的包体类型都是默认类型——defaultpacket,otherPacket文件里的包体类型就是其他分包类型。为什么说是最初,因为在热更分包资源的时候,我们为了资源的正确性和操作性,就将下载的分包资源的信息写在了本地files里面,这样filse文件里是我游戏里所有资源的信息,以确保下次需要热更分包资源的正确性。具体可以看看热更模块。
主要逻辑在C#代码中 SplitPacketManager.cs。
Lua中的 LuaSplitPacketManager.lua主要是接收处理来自C#的数据以及做UI的协调。
这个脚本主要参照了热更逻辑进行了改写。
说明一下,我们现在的pic的分包不在游戏运行的时候下载,cv的分包只在游戏运行的时候下载。
我们的下载逻辑在起初设计的时候没有用到多线程,所以在下载的时候,只能一个类型一个类型的下载。
-
设置packet的下载:这里主要是通过写入PlayerPrefs的int值来确定在游戏启动的时候是否需要下载对应的分包。但是策划说不能在游戏启动的时候热更CV,所以设置CV下载的这个代码给注掉了 SetCvPlayerPrefabs()
-
通过语言id,检测CV资源是否需要下载:这个主要是通过不同条件检测是否需要下载资源。
-
设置游戏开启时,是否进行热更检测:这个主要是用于分包的热更。因为分包的热更不依赖clientVersion.txt文件的热更号,所以有可能在开始检测时没有热更,但是我们需要下载分包资源,所以在热更的时候,加了两个判断。
-
开始下载更新:这里面就是下载的主逻辑,包含了资源检测、资源下载、下载信息回调、由于各种原因导致的资源下载损坏的重新下载。这个由上到下自己看吧。
-
各种原因下载失败时,需要调用和这个函数:这个主要是用于在下载过程中,网络中断后需要调用的函数。
-
packet资源检测、数据收集:这个是一些支持函数。其中BeginCollectPacket()是用于分包资源的信息收集,这个函数在初始化之前调用,主要在lua层做显示分析用的。
注意的是,这里面穿插着各种PacketLoadState的情况,这些情况都会通知给lua层。
Lua的SplitPacketManager,Lua层又对SplitPacketManager封装了一层,所以用的时候直接调用Lua的SplitPacketManager,不用关心C#的。
- LuaSplitPacketManager.Init():这个是一个初始化,注册了Timer,监听了网络重连和网络中断。
- LuaSplitPacketManager.DownLoadPacket(...):资源包的下载入口,这里目前只用于下来Cv资源。当然,Pic资源也能下,看需求。
- LuaSplitPacketManager.UpdatePicPacketAccordingToLanguage(language):这个是跟随游戏的语言设置的,我们在设置语言的时候会进行重启,所以这里标记一下,在重启的时候有下载的资源会进行下载。
- LuaSplitPacketManager.LoadStateCallBack(state):处理来自下载时候的各种状态
我们在界面写下载的时候,需要注册下面两个事件,用来数据支持。具体如何交互使用,请参照CvChangeCtrlPanel.lua文件
LuaSplitPacketManager.Event = {
UpdateState = "LuaSplitPacketManager_UpdateState", --通知state的变化
UpdateDownLoadData = "LuaSplitPacketManager_UpdateDownLoadData" --通知下载的数据变化
}