附有道云笔记排版文档:自定义tolua加载ab模拟机制,完美解决?..
链接:http://note.youdao.com/noteshare?id=c6da58f8245888d33013b7c2aef6bc6c
之前用的AB模拟加载机制,自定义写了一套加载流程,但是无法调试lua或者或者概率性能调试,因此写了一个新的加载流程框架完美解决了AssetBundle模拟调试(修改lua代码后不需要实时打Bundle就能立刻看到lua代码的修改效果)但是tolua不能debug的问题
原理:lua文件是通过路径来加载的,
核心思路:
原框架逻辑梳理:
#region 自定义操作行为
///
/// 添加打入Lua代码的AssetBundle
///
///
public void AddBundle(string bundleName)
{
string url = ELUtil.DataPath + bundleName.ToLower();
Debug.LogError(url);
if (File.Exists(url))
{
var bytes = File.ReadAllBytes(url);
AssetBundle bundle = AssetBundle.LoadFromMemory(bytes);
if (bundle != null)
{
bundleName = bundleName.Replace("lua/", "").Replace(".unity3d", "");
base.AddSearchBundle(bundleName.ToLower(), bundle);
Debug.LogError("true:" + bundleName);
}
}
}
#endregion
///
/// 初始化LuaBundle
///
void InitLuaBundle()
{
if (_luaLoader.beZip)
{
_luaLoader.AddBundle("lua_lua.unity3d");
_luaLoader.AddBundle("lua_lua_math.unity3d");
_luaLoader.AddBundle("lua_lua_debug.unity3d");
...
}
}
tolua框架加载方法如果是开启zip走zip方法LuaInterface.LuaFileUtilsReadZipFile(string fileName) 否则走正常加载 File.ReadAllBytes(string fullPath);
public byte[] ReadFile(string fileName)
{
if (!beZip)
{
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
{
return ReadZipFile(fileName);
}
}
public virtual byte[] ReadZipFile(string fileName)
{
AssetBundle zipFile = null;
byte[] buffer = null;
string zipName = null;
using (CString.Block())
{
CString sb = CString.Alloc(256);
sb.Append("lua");
int pos = fileName.LastIndexOf('/');
if (pos > 0)
{
sb.Append("_");
sb.Append(fileName, 0, pos).ToLower().Replace('/', '_');
fileName = fileName.Substring(pos + 1);
}
if (!fileName.EndsWith(".lua"))
{
fileName += ".lua";
}
#if UNITY_5 || UNITY_5_3_OR_NEWER
fileName += ".bytes";
#endif
zipName = sb.ToString();
zipMap.TryGetValue(zipName, out zipFile);
}
if (zipFile != null)
{
#if UNITY_4_6 || UNITY_4_7
TextAsset luaCode = zipFile.Load(fileName, typeof(TextAsset)) as TextAsset;
#else
TextAsset luaCode = zipFile.LoadAsset<TextAsset>(fileName);
#endif
if (luaCode != null)
{
buffer = luaCode.bytes;
Resources.UnloadAsset(luaCode);
}
}
return buffer;
}
设置搜索路径 LuaFileUtils.Instance.AddSearchPath(path);
//格式: 路径/?.lua
public bool AddSearchPath(string path, bool front = false)
{
int index = searchPaths.IndexOf(path);
if (index >= 0)
{
return false;
}
if (front)
{
searchPaths.Insert(0, path);
}
else
{
searchPaths.Add(path);
}
return true;
}
Addbundle方法预加载走的是zip通道加载(注:addbundle之前必须保证bundle在StreamAsset文件夹中打包出来了,否则AddBundle失败)
那么我想法就是:之前为什么连不上,或者断断续续能断点
修正方案:
public override byte[] ReadZipFile(string fileName)
{
//暂时取消tolua默认配置文件走默认加载通道过程,全部切换为.txt走AssetBundles/Lua/ELTolua 路径(全自动生成后缀)]
//而且tolua.lua启动列表的require全部需要加前缀/eltolua/
return hash.Contains(fileName) ?
base.ReadZipFile(fileName) : ReadZipFileCustom(ref fileName);
//return ReadZipFileCustom(ref fileName);
}
d. 原有的加载路径匹配上了就走默认加载,不然走自定义加载渠道
#region 重写AB加载lua,但是默认tolua走原加载渠道
public HashSet<string> hash = new HashSet<string>()
{
"tolua.lua",
"misc/functions",
"misc/misc",
"misc/strict",
"misc/utf8",
...
};
e. 但是发现这样搞,Android.manifest会对不上啊,两套打包机制是不合理的
f. 那么我还是走了自己的打包流程,也就是需要手动把tolua里全部lua文件改成lua.txt后缀(有批量改名软件)
///
/// 自定义Lua为 AB加载渠道
///
///
///
private static byte[] ReadZipFileCustom(ref string fileName)
{
AssetBundle zipFile = null;
byte[] buffer = null;
string zipName = null;
StringBuilder sb = StringBuilderCache.Acquire();
int pos = fileName.LastIndexOf('/');
if (pos > 0)
{
sb.Append(fileName.Substring(0, pos).ToLower()); //shit, unity5 assetbund'name must lower
sb.Replace('/', '_');
fileName = fileName.Substring(pos + 1);
}
if (!fileName.EndsWith(".lua"))
{
fileName += ".lua";
}
#if UNITY_5_4_OR_NEWER
//fileName += ".bytes";
#endif
zipName = StringBuilderCache.GetStringAndRelease(sb);
string assetBundleName = string.Empty;
if (zipName.Equals(string.Empty))
{
assetBundleName = "lua.unity3d";
}
else
{
assetBundleName = "lua/" + zipName + ".unity3d";
}
TextAsset luaCode = ELAssetBundleManager.LoadAsset<TextAsset>(assetBundleName, fileName);
if (luaCode != null)
{
buffer = luaCode.bytes;
Resources.UnloadAsset(luaCode);
}
return buffer;
}
--------------------------分隔符-------------------------------------
g. 而且写了一套自动设置lua打包后缀的方法,以免出错,只设置.lua.txt文件,其他.lua文件呢就报错提示不匹配规则(暂不考虑变体,变体只需要改打包后缀.unity3d为其他)
i.打包后的路径为:一级路径:lua.unity3d
ii.二级和多级路径为:lua/文件夹小写/文件夹小写.unity3d
iii.因为lua/.unity3d是不允许的,在加载路径规则中.和/都是文件夹分隔符的意思
--------------------------分隔符-------------------------------------
h. 但是tolua的文件太过于零零散散,我就整合在AssetBundle/Lua/ElHotLua文件夹内,看起来完美,但是根据打包规则,需要把tolua内部的全部require路径加多elhotlua(不区分大小写,打包和加载机制自动变小写),也就是比如
3.打包完后,开始加载调试,发现socket连上了,逻辑正常了,但是就是不能断点
为什么呢?我们来看下lua的调试文件
调试规则是在启动文件中链接LuaDebug.jit(注意debug文件必须与启动文件在同一个文件夹内,否则有坑无法链接上)
钩子程序通过xpcall(function,function)调用
经过各种打印得到socket连接,但是钩子挂起始终不生效
经过询问LuaIDE的作者K大神得知,自定义加载渠道,如果不是DoFile的话,而是DoString()是需要附加上chunkName的(疏忽没检查这个了),而且luadebugjit和启动类必须在相同路径
总结如下:自定义AB热更加载框架,必须完完整整(重要的事情说三次)
剩下的就是自定义打包流程和加载流程了,预知后事如何,请关注下篇(如何实现AssetBundlea模拟加载)