cocos2d中的脚本加载一:优先加载下载目录中的脚本。

上一篇文章说到,要在lua层实现,下载目录中的lua脚本优加载,只需要:
package.path = download/scripts/?.lua;+package.path即可。

但是这个做法,在android下却无法工作,于是,没有办法,只好硬啃一下cocos2d中android下面的脚本加载的源码,以求破!

 
bool CCLuaEngine::init(void) 

 m_state = lua_open(); 
 luaL_openlibs(m_state); 
 tolua_Cocos2d_open(m_state); 
 tolua_prepare_ccobject_table(m_state); 
 #if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID) 
  //android平台的话,添加一个lua脚本加载器。然后,加载脚本时就是通过这个加载器来加载。
      addLuaLoader(cocos2dx_lua_loader)
 #endif 
     return true; 
}

于是乎,开始啃addLuaLoader的源码,在啃addLuaLoader的源码之前,先来科普一下lua中的package.loaders:
static const lua_CFunction package_loaders[] =

{
  lj_cf_package_loader_preload,
  lj_cf_package_loader_lua,
  lj_cf_package_loader_c,
  lj_cf_package_loader_croot,
  NULL
};
loaders中,存有各种lua的加载器,当lua require一个文件里,将按升序的顺序,遂一调用loaders中的加载器去加载。
通过名字也可以猜得到:
lj_cf_package_loader_preload,  加载预加载的文件
lj_cf_package_loader_lua,      正常的lua文件加载
lj_cf_package_loader_c,        加载c库

对loaders有所了解之后,可以来啃addLuaLoader的源码了。

void CCLuaStack::addLuaLoader(lua_CFunction func)
{
    if (!func) return;
   
    lua_getglobal(m_state, "package");                                  /* L: package */
    lua_getfield(m_state, -1, "loaders");                               /* L: package, loaders */
    lua_pushcfunction(m_state, func);                                   /* L: package, loaders, func */
    for (int i = lua_objlen(m_state, -2) + 1; i > 2; --i)
    {
        lua_rawgeti(m_state, -2, i - 1);                                /* L: package, loaders, func, function */
        lua_rawseti(m_state, -3, i);                                    /* L: package, loaders, func */
    }
    lua_rawseti(m_state, -2, 2);                                        /* L: package, loaders */
    lua_setfield(m_state, -2, "loaders");                               /* L: package */
   
    lua_pop(m_state, 1);
}

不熟lua api的同学可以遂个去谷歌。这个接口做的事情无非是:
实现
pacakge.loaders ={ preload, cocos2dx_lua_loader, loader_lua, loader_c, loader_croot, ...}

然后可知道,CCLuaStack::addLuaLoader的功能实际上就是把cocos2dx_lua_loader塞在lj_cf_package_loader_lua前面,这样子,

当require一个脚本时,就会优先使用cocos2dx_lua_loader做为加载器来加载,然后再使用正常的lj_cf_package_loader_lua加载

器来加载。 

cocos2d为什么要这么做呢?我想,大概是与apk包中的asset目录有关吧。cocos2dx_lua_loader这个加载器可能是具有从apk中的

asset中去正确地加载脚本的功能。有兴趣的同学可以去啃cocos2dx_lua_loader的源码了。

了解了这么底层的原理之后,回归一最原始的问题上来,如何实现,优先加载下载下来的lua脚本呢。

如果前面所说的,package.loader变成这样子:

{ preload,  loader_lua, cocos2dx_lua_loader,loader_c, loader_croot, ...}就可以了,也就是把cocos2dx_lua_loader,

塞在lj_cf_package_loader_lua的后面,而非前面。

原理就是,在本文最开始时说到
“要在lua层实现,下载目录中的lua脚本优加载,只需要:
package.path = download/scripts/?.lua;+package.path即可。”
也就是,下载目录,已经拼在package.path的前头了,但是因为,优先使用了cocos2dx_lua_loader做为加载器,而

cocos2dx_lua_loader并非源生的lua加载器,所以并不理会pacakge.path,而是直接在初如包asset中去加载脚本,所以就会优先在

初始包asset中找到老的脚本文件。

那么当cocos2dx_lua_loader,排在lj_cf_package_loader_lua,后面之时,lua的源生加载器lj_cf_package_loader_lua,会遵循lua

的加载之道,按package.path中列出的顺搜寻目顺序去遂一查找脚本。这样,就会优先从拼在package.path前头的,

download/scripts/中查找脚本,如有下载下来的新脚本,那么就会优先被查找到。

当没有下载下来的新脚本时,在download/scripts/就会查找失败。然后,会继续用排在后面的cocos2dx_lua_loader加载器去初始

包asset中去查找脚本,这样初始包中的老脚本就会被查找到。


但是,如何实现,packaget.loader ={ preload,  loader_lua, cocos2dx_lua_loader,loader_c, loader_croot, ...}呢。小

伙伴们对比CCLuaStack::addLuaLoader(lua_CFunction func)的源码稍为改动一下就可以了。

然后重新编译,运行。android工程里面,也已经是优先加载下载目录里面的脚本了。

PS:这只是cocos2d里面的原理。对比了一下quick cocos的源码,cocos2dx_lua_loader已经自己会去处理pakcage.path时面的内容

了。直接拼pacakge.path路径就可以了。但是,看了一下实现过程,就是遂个searchpath中搜寻。所以会有两种弊端:
1,加载脚本会耗时,搜寻时间增长了
2,当不同两个文件夹下面,有两个文件同名时,并且require时没有指定目录,而是让加载器在整个大目录中搜找时。就不知道会

发生什么事情,先找到那个,就加载那个了。

 

如有转载,还望标明出处:http://www.cnblogs.com/WaterWithAir/p/3568165.html

Copyright © 2024 水善气和
Powered by .NET 9.0 on Kubernetes