下一篇 AssetBundle(五) 关于SceneManager.LoadScene
ToLua虽然支持Bundle,但是其实现很难应用于实际项目。没有引用计数,不支持其他资源打包,而且还有WWW之类已经过时的Bundle技术。但,瑕不掩瑜,Tolua本身是很优秀的。如果项目有一套完善的支持bundle的资源管理模块,对接Tolua很方便,只需要改两点就能对接好。
在说对接步骤之前,先说下Lua如何存放和读取的问题。游戏包打好以后,本身就带lua的bundle。能想到有两种做法,一种是把包内的lua的bundle,读出来,放到沙盒目录,以后读取lua都从沙盒目录,更新也是更新沙盒目录。总之和包内的lua就没关系了。这样做不是不行,问题在于要把包内的lua写到沙盒去,这个过程时间有点长。这样首次运行时间太长了。而且lua更新和其他资源的更新流程不一致。
推荐第二种方案,就是包内的lua以bundle的形式存在,不用拷贝并解压到沙盒。我们只要做到能读取bundle中lua即可。至于lua的更新,还是走bundle更新,跟之前的博文讲的其他资源的bundle更新一个流程。这种方案相比第一种,无论是效率还是更新逻辑,整体统一性都是更好的选择。
对接只需要做2步
1.写一个Lua加载类,继承Tolua的LuaFileUtils,重载ReadFile,实现自己的lua加载
LuaFileUtils是Tolua中负责加载lua的一个类,Tolua本身也有几个其派生类,但都不是很理想,更多的是用于示范。我们要实现的这个派生类,只需要实现两点。即是开发模式下(非bundle)和发布模式(用bundle)。如果是开发模式和父类差不多,如果是发布模式用自己Bundle接口读出来,再返回bytes
2.根据需要重写ToLuaMenu类中关乎bundle生成的函数BuildNotJitBundles
[MenuItem("Lua/Build bundle files not jit", false, 55)]
public static void BuildNotJitBundles()
{
ClearAllLuaFiles();
CreateStreamDir(GetOS());
这个类是Tolua的菜单编辑器类。我们只需要修改其中打Bundle的函数即可。实际上我并没有改,而是另写了一个,相当于打bundle不走Tolua的菜单了,而走自己写的菜单。两个原因导致这个类需要自己实现
(1)实际项目中目录规则和Tolua可能不同
(2)最重要的一点是,这个只打Lua的Bundle,实际项目中还有其他资源需要打Bundle。难道我们需要打bundle的时候,资源和lua按不同的菜单打吗?
需要注意的是,bundle的名字不能带反斜杠目录分隔符。我的框架里是“_”代替"/" ,否则在打bundle时会出现不能创建目录的错误。这个错误不是必出,在Unity2017.1.0f3就会出现。
下面是我市的类,LuaLoader ,负责接管ToLua中的lua加载。
using UnityEngine;
using LuaInterface;
using System.IO;
using System.Text;
namespace UFrame.ToLua
{
/// <summary>
/// 接管Tolua的读取lua,从UFrame的资源管理模块读取lua
/// beZip 无效
/// </summary>
public class LuaLoader : LuaFileUtils
{
public LuaLoader()
{
instance = this;
beZip = false;
}
public override byte[] ReadFile(string fileName)
{
if (!fileName.EndsWith(".lua"))
{
fileName += ".lua";
}
#if !RES_AB
string path = FindFile(fileName);
byte[] str = null;
if (!string.IsNullOrEmpty(path) && File.Exists(path))
{
#if !UNITY_WEBPLAYER
str = File.ReadAllBytes(path);
#else
throw new LuaException("can't run in web platform, please switch to other platform");
#endif
}
return str;
#else
fileName += ".bytes";
var getter = ResHelper.LoadAsset(fileName);
var res = getter.Get<TextAsset>(ResHelper.GetPubAssetGetterGo());
return res.bytes;
#endif
}
}
}
上面代码的意思是,如果没有定义RES_AB,那属于开发模式,直接从项目目录读取lua;如果是Bundle模式,从ResHelper加载,然后返回TextAsset.bytes。ResHelper是我的框架中读取资源的帮助类。
代码中,如果不是以“.lua”结尾的要加上,因为require是不加.lua后缀的。如果是发布模式,在加了“.lua”的基础上又加了一个".bytes"的后缀,这是因为lua文件不能直接打bundle,加这个后缀就可以打,当然也可以选择加“.txt”。这一步在打包的代码中就要加上。相当于打包的不是".lua"文件,而是“.lua.bytes”文件。这种文件是个拷贝,不是直接改,主要是为了不影响开发模式。
不是Tolua做不好Bundle,而是Tolua不知道具体的项目需求是什么。因为lua加载在项目通常也是资管管理模块的,这个模块除了lua之外还有其他资源。在这种情况下,Tolua自己实现了一套bundle,相当于示范,也方便我们用自己的资源管理模块对接,将其替换掉。这实际上是很不错的设计。
本文介绍了如何使用Tolua对接AssetBundle,讨论了两种lua存储和读取的方案,并提供了对接的两个关键步骤:自定义Lua加载类以适应bundle加载,以及重写或扩展ToLuaMenu以符合项目需求。文章强调了bundle命名规范,以及在开发和发布模式下lua文件处理的差异。

956

被折叠的 条评论
为什么被折叠?



