在使用ToLua的LuaFramework作为代码热更框架,进行AssetBundle打包的时候,有时会莫名其妙出现Lua文件读不出来的问题,即require了某个Lua文件,且文件确实存在,却报出该文件的全局变量为nil的error。
问题分析
经过仔细的查看和debug,发现是同一个文件夹下存在两个Lua文件的文件名发生了尾部包含的关系,例如文件b.lua
和aaaaaab.lua
,当require文件b.lua
时,实际获取出来的却是aaaaaab.lua
。
原因所在
发现了这个问题之后(鬼知道我经历了什么才查出来……),就去翻了一下LuaFramework的代码,发现在ToLua/Core/LuaFileUtils.cs中,读取bundle中的文件的函数是这样写的:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| byte[] ReadZipFile(string fileName) { ……
if (pos > 0) { zipName = fileName.Substring(0, pos); zipName = zipName.Replace('/', '_'); zipName = string.Format("Lua_{0}", zipName); fileName = fileName.Substring(pos + 1); }
zipMap.TryGetValue(zipName.ToLower(), out zipFile);
if (zipFile != null) { #if UNITY_5 string[] names = zipFile.GetAllAssetNames(); for (int i = 0; i < names.Length; i++) { if (names[i].EndsWith(fileName.ToLower() + ".bytes")) { fileName = names[i]; break; } } TextAsset luaCode = zipFile.LoadAsset<TextAsset>(fileName); #else TextAsset luaCode = zipFile.Load(fileName, typeof(TextAsset)) as TextAsset; #endif
……
return buffer; }
|
注意中间的for循环,使用了names[i].EndsWith(fileName.ToLower() + “.bytes”)。
首先要明确一点,LuaFramework在对Lua文件进行打包时,会把每个文件夹打成一个bundle,因此上述代码中的zipFile就是某个文件夹的bundle。在对names和fileName进行匹配时,使用了EndsWith,而bundle内的文件是按字母表顺序排列的。因此require "b.lua"
时,EndsWith(“b.lua”),就读到了aaaaaab.lua
。
解决方案
一,这个问题存在于LuaFramework 1.0.5.203之前的版本,最新的版本已经修改了Lua文件的打包和读取的方式,所以直接升级框架版本即可解决这个巨坑。
二,升级框架版本本身可能存在隐患,导致代码不稳定。既然已经定位到问题,其实直接修改就可以了。
虽然不是很清楚为什么使用EndsWith来做文件的匹配,大概可以猜到,应该是为了适配多平台导致的bundle内部文件路径不统一的问题。以下修改代码暂时只在PC和Android平台做了测试:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
| byte[] ReadZipFile(string fileName) { ……
if (pos > 0) { zipName = fileName.Substring(0, pos); zipName = zipName.Replace('/', '_'); zipName = string.Format("Lua_{0}", zipName); }
if (!fileName.EndsWith(".lua")) { fileName += ".lua"; }
fileName = "assets/luatemp/" + fileName;
zipMap.TryGetValue(zipName.ToLower(), out zipFile);
if (zipFile != null) { #if UNITY_5 fileName = fileName.ToLower() + ".bytes"; TextAsset luaCode = zipFile.LoadAsset<TextAsset>(fileName); #else TextAsset luaCode = zipFile.Load(fileName, typeof(TextAsset)) as TextAsset; #endif
……
return buffer; }
|
小结
LuaFramework本身提供了Lua和C#交互的基础功能,并且扩展了热更新、诸多管理器、消息分发器等功能,当然作为一款开源工具,仍存在些许问题,我踩过其中一些坑,这篇总结的坑连踩了两次,本着事不过三的原则,记录下来,也是一劳永逸地解决了这个问题。