1.Unity加载Lua文件的流程

Unity中我们要加载Lua文件调用的函数是:LuaState类中的DoFile("xxx").我们可以看到流程是:

LuaState:DoFile()->LuaState:LoadFileBuffer()->LuaFileUtils:ReadFile()->FindFile()

        public void DoFile(string fileName){byte[] buffer = LoadFileBuffer(fileName);fileName = LuaChunkName(fileName);LuaLoadBuffer(buffer, fileName);}
        byte[] LoadFileBuffer(string fileName){
#if UNITY_EDITORif (!beStart){throw new LuaException("you must call Start() first to initialize LuaState");}
#endifbyte[] buffer = LuaFileUtils.Instance.ReadFile(fileName);if (buffer == null){string error = string.Format("cannot open {0}: No such file or directory", fileName);error += LuaFileUtils.Instance.FindFileError(fileName);throw new LuaException(error);}return buffer;}
        public virtual byte[] ReadFile(string fileName){if (!beZip){string path = FindFile(fileName);byte[] str = null;if (!string.IsNullOrEmpty(path) && File.Exists(path)){
#if !UNITY_WEBPLAYERstr = File.ReadAllBytes(path);
#elsethrow new LuaException("can't run in web platform, please switch to other platform");
#endif}return str;}else{return ReadZipFile(fileName);}}
   public string FindFile(string fileName){if (fileName == string.Empty){return string.Empty;}if (Path.IsPathRooted(fileName)){if (!fileName.EndsWith(".lua")){fileName += ".lua";}return fileName;}if (fileName.EndsWith(".lua")){fileName = fileName.Substring(0, fileName.Length - 4);}string fullPath = null;for (int i = 0; i < searchPaths.Count; i++){fullPath = searchPaths[i].Replace("?", fileName);if (File.Exists(fullPath)){return fullPath;}}return null;}

最后会在searchPaths的路径中进行搜索,是否存在指定的lua文件,来进行加载与否。那这个searchPaths变量在哪里初始化呢?

第一处是AddSearchPath:

我们获取lua中的package.path来初始化我们的搜索路径。

        public void InitPackagePath(){LuaGetGlobal("package");LuaGetField(-1, "path");string current = LuaToString(-1);string[] paths = current.Split(';');for (int i = 0; i < paths.Length; i++){if (!string.IsNullOrEmpty(paths[i])){string path = paths[i].Replace('\\', '/');LuaFileUtils.Instance.AddSearchPath(path);}}LuaPushString("");            LuaSetField(-3, "path");LuaPop(2);}

第二处是LuaState类中的AddSearchPath:

InitLuaPath是在LuaState构造函数中调用的。

        void InitLuaPath(){InitPackagePath();if (!LuaFileUtils.Instance.beZip){
#if UNITY_EDITORif (!Directory.Exists(LuaConst.luaDir)){string msg = string.Format("luaDir path not exists: {0}, configer it in LuaConst.cs", LuaConst.luaDir);throw new LuaException(msg);}if (!Directory.Exists(LuaConst.toluaDir)){string msg = string.Format("toluaDir path not exists: {0}, configer it in LuaConst.cs", LuaConst.toluaDir);throw new LuaException(msg);}AddSearchPath(LuaConst.toluaDir);AddSearchPath(LuaConst.luaDir);
#endifif (LuaFileUtils.Instance.GetType() == typeof(LuaFileUtils)){AddSearchPath(LuaConst.luaResDir);}}}

2.lua中加载其他lua文件

lua中我们是使用require来进行加载其他lua文件的,首先require的伪代码实现如下:

function require(name)if not package.loaded[name] thenlocal loader = findloader(name)if loader == nil thenerror("unable to load module" .. name)endpackage.loaded[name] = truelocal res = loader(name)if res ~= nil thenpackage.loaded[name] = resendendreturn package.loaded[name]
end

lua源码(在loadlib.c中):

1.首先是初始化require搜索路径流程

static const luaL_Reg pk_funcs[] = {{"loadlib", ll_loadlib},{"searchpath", ll_searchpath},
#if defined(LUA_COMPAT_MODULE){"seeall", ll_seeall},
#endif/* placeholders */{"preload", NULL},{"cpath", NULL},{"path", NULL},{"searchers", NULL},{"loaded", NULL},{NULL, NULL}
};static const luaL_Reg ll_funcs[] = {
#if defined(LUA_COMPAT_MODULE){"module", ll_module},
#endif{"require", ll_require},{NULL, NULL}
};static void createsearcherstable (lua_State *L) {static const lua_CFunction searchers[] ={searcher_preload, searcher_Lua, searcher_C, searcher_Croot, NULL};int i;/* create 'searchers' table */lua_createtable(L, sizeof(searchers)/sizeof(searchers[0]) - 1, 0);/* fill it with predefined searchers */for (i=0; searchers[i] != NULL; i++) {lua_pushvalue(L, -2);  /* set 'package' as upvalue for all searchers */lua_pushcclosure(L, searchers[i], 1);lua_rawseti(L, -2, i+1);}
#if defined(LUA_COMPAT_LOADERS)lua_pushvalue(L, -1);  /* make a copy of 'searchers' table */lua_setfield(L, -3, "loaders");  /* put it in field 'loaders' */
#endiflua_setfield(L, -2, "searchers");  /* put it in field 'searchers' */
}/*
** create table CLIBS to keep track of loaded C libraries,
** setting a finalizer to close all libraries when closing state.
*/
static void createclibstable (lua_State *L) {lua_newtable(L);  /* create CLIBS table */lua_createtable(L, 0, 1);  /* create metatable for CLIBS */lua_pushcfunction(L, gctm);lua_setfield(L, -2, "__gc");  /* set finalizer for CLIBS table */lua_setmetatable(L, -2);lua_rawsetp(L, LUA_REGISTRYINDEX, &CLIBS);  /* set CLIBS table in registry */
}LUAMOD_API int luaopen_package (lua_State *L) {createclibstable(L);luaL_newlib(L, pk_funcs);  /* create 'package' table */createsearcherstable(L);/* set paths */setpath(L, "path", LUA_PATH_VAR, LUA_PATH_DEFAULT);setpath(L, "cpath", LUA_CPATH_VAR, LUA_CPATH_DEFAULT);/* store config information */lua_pushliteral(L, LUA_DIRSEP "\n" LUA_PATH_SEP "\n" LUA_PATH_MARK "\n"LUA_EXEC_DIR "\n" LUA_IGMARK "\n");lua_setfield(L, -2, "config");/* set field 'loaded' */luaL_getsubtable(L, LUA_REGISTRYINDEX, LUA_LOADED_TABLE);lua_setfield(L, -2, "loaded");/* set field 'preload' */luaL_getsubtable(L, LUA_REGISTRYINDEX, LUA_PRELOAD_TABLE);lua_setfield(L, -2, "preload");lua_pushglobaltable(L);lua_pushvalue(L, -2);  /* set 'package' as upvalue for next lib */luaL_setfuncs(L, ll_funcs, 1);  /* open lib into global table */lua_pop(L, 1);  /* pop global table */return 1;  /* return 'package' table */
}

2.require的源码

static int ll_require (lua_State *L) {const char *name = luaL_checkstring(L, 1);lua_settop(L, 1);  /* LOADED table will be at index 2 */lua_getfield(L, LUA_REGISTRYINDEX, LUA_LOADED_TABLE);lua_getfield(L, 2, name);  /* LOADED[name] */if (lua_toboolean(L, -1))  /* is it there? */return 1;  /* package is already loaded *//* else must load package */lua_pop(L, 1);  /* remove 'getfield' result */findloader(L, name);lua_pushstring(L, name);  /* pass name as argument to module loader */lua_insert(L, -2);  /* name is 1st argument (before search data) */lua_call(L, 2, 1);  /* run loader to load module */if (!lua_isnil(L, -1))  /* non-nil return? */lua_setfield(L, 2, name);  /* LOADED[name] = returned value */if (lua_getfield(L, 2, name) == LUA_TNIL) {   /* module set no value? */lua_pushboolean(L, 1);  /* use true as result */lua_pushvalue(L, -1);  /* extra copy to be returned */lua_setfield(L, 2, name);  /* LOADED[name] = true */}return 1;
}static void findloader (lua_State *L, const char *name) {int i;luaL_Buffer msg;  /* to build error message */luaL_buffinit(L, &msg);/* push 'package.searchers' to index 3 in the stack */if (lua_getfield(L, lua_upvalueindex(1), "searchers") != LUA_TTABLE)luaL_error(L, "'package.searchers' must be a table");/*  iterate over available searchers to find a loader */for (i = 1; ; i++) {if (lua_rawgeti(L, 3, i) == LUA_TNIL) {  /* no more searchers? */lua_pop(L, 1);  /* remove nil */luaL_pushresult(&msg);  /* create error message */luaL_error(L, "module '%s' not found:%s", name, lua_tostring(L, -1));}lua_pushstring(L, name);lua_call(L, 1, 2);  /* call it */if (lua_isfunction(L, -2))  /* did it find a loader? */return;  /* module loader found */else if (lua_isstring(L, -2)) {  /* searcher returned error message? */lua_pop(L, 1);  /* remove extra return */luaL_addvalue(&msg);  /* concatenate error message */}elselua_pop(L, 2);  /* remove both returns */}
}

根据源码知道,将所有的loader:

1.searcher_preload

搜索:package.preload 表中是否有指定lua

2.searcher_Lua

搜索:path 路径中是否有指定lua

3.searcher_C

搜索路径:cpath路径中是否有指定lua

4.searcher_Croot

搜索路径:cpath路径中是否有指定lua

都加入到了searchers表中,然后require(ll_requre)调用的时候,会先判断这个lua是否加载过,如果没有加载过那么就会调用

findloader,这个函数会遍历searchers表,依次在上面的4个函数中去找寻是否有对应的lua文件。

3.tolua中如何在lua中require其他lua

根据2我们知道require是遍历所有loader函数来所有lua文件,于是tolua中在searchers中加入了loader函数来进行搜索我们的lua文件,源码如下:

LuaState构造函数->ToLua.OpenLibs(L)->AddLuaLoader

        static void AddLuaLoader(IntPtr L){LuaDLL.lua_getglobal(L, "package");LuaDLL.lua_getfield(L, -1, "loaders");LuaDLL.tolua_pushcfunction(L, Loader);for (int i = LuaDLL.lua_objlen(L, -2) + 1; i > 2; i--){LuaDLL.lua_rawgeti(L, -2, i - 1);LuaDLL.lua_rawseti(L, -3, i);}LuaDLL.lua_rawseti(L, -2, 2);LuaDLL.lua_pop(L, 2);}[MonoPInvokeCallbackAttribute(typeof(LuaCSFunction))]static int Loader(IntPtr L){try{string fileName = LuaDLL.lua_tostring(L, 1);fileName = fileName.Replace(".", "/");byte[] buffer = LuaFileUtils.Instance.ReadFile(fileName);if (buffer == null){string error = LuaFileUtils.Instance.FindFileError(fileName);LuaDLL.lua_pushstring(L, error);return 1;}if (LuaConst.openLuaDebugger){fileName = LuaFileUtils.Instance.FindFile(fileName);}                if (LuaDLL.luaL_loadbuffer(L, buffer, buffer.Length, "@"+ fileName) != 0){string err = LuaDLL.lua_tostring(L, -1);throw new LuaException(err, LuaException.GetLastError());}return 1;}catch (Exception e){return LuaDLL.toluaL_exception(L, e);}}

可以看到这个loader函数最后会调用LuaFileUtils.Instance.ReadFile(fileName);来找寻要加载的文件,于是根据1中的介绍,我们知道也就是要在searchPaths中根据路径来找对应的lua文件。

Unity toLua加载lua的流程相关推荐

  1. Unity资源加载入门

    写在前面 本文转载自:https://gameinstitute.qq.com/community/detail/123460,供自己学习用,如有疑问,请移步原创. 引言 Unity的资源加载及管理, ...

  2. Unity资源加载管理

    转载链接: https://bbs.gameres.com/thread_800362_1_1.html 我理解的资源管理 举一个不恰当的例子来描述我所理解的资源管理(因为我实在想不出更合适的例子了) ...

  3. unity保存加载慢_掌握Unity 5中的保存和加载功能

    unity保存加载慢 Thanks to Vincent Quarles for kindly helping to peer review this article. 感谢Vincent Quarl ...

  4. HTML页面加载和解析流程详细介绍

    浏览器加载和渲染html的顺序.如何加快HTML页面加载速度.HTML页面加载和解析流程等等,在本文将为大家详细介绍下,感兴趣的朋友不要错过 浏览器加载和渲染html的顺序 1. IE下载的顺序是从上 ...

  5. linux优化网页加载过程,HTML页面加载和解析流程 介绍

    1.浏览器加载和渲染html的顺序 1.1.IE下载的顺序是从上到下,渲染的顺序也是从上到下,下载和渲染是同时进行的. 1.2.在渲染到页面的某一部分时,其上面的所有部分都已经下载完成(并不是说所有相 ...

  6. html中加载解析,HTML页面加载和解析流程详细介绍

    序言: 我一直都认为"网页制作"这个词是一个不怎么高端的词,在我的印象中网页制作的词是没有生命力的一个制作,我喜欢用HTML 这样简单直接,这词凸显高端,有大气漂亮的UI.一套完美 ...

  7. android主动显示流程,Activity加载显示基本流程

    本文章是基于Android源码6.0讲解Activity加载显示基本流程 首先上一张图给大家一个直观的了解 首先一个布局页面的加载是在Activity中的setContentView(R.layout ...

  8. 【安卓开机启动】安卓JVM加载so库流程

    安卓JVM加载so库流程 好久没有写点东西发了,工作中的事情有点杂,也找不到整块东西可以写的. 最近调查了一个问题,稍微追了一下流程,这里记录一下. 1. 问题背景 由于我们支持的设备相对比竞品,zy ...

  9. Unity资源加载发布到移动端iphone/ipad

    Unity资源加载发布到iOS平台的特殊路径 using UnityEngine; using System.Collections; public class TestLoad : MonoBeha ...

最新文章

  1. [云炬创业学笔记]第一章创业是什么测试12
  2. oracle where order by,ORACLE SQL WHERE和ORDER BY
  3. java linkedhashset_java之LinkedHashSet
  4. 【C++深度剖析教程33】C++中的构造函数与析构函数是否可以为虚函数
  5. oracle中取反_oracle正则表达式regexp_like的用法详解
  6. awk java_Linux三剑客之awk
  7. 联系人字段中增加生日字段
  8. python华为认证_HCIA-AI华为认证AI工程师在线课程题目及参考答案
  9. Qt视频播放器界面Demo
  10. html左侧浮动广告代码,Html+CSS浮动的广告条实现分解
  11. CCA分析图如何解读_BI报表控件Wyn使用教程:如何使用网状/雷达图进行数据分析...
  12. 2021智能仓储物流之最全AGV企业供应商名录整理分享~
  13. 领存Xeon E5 6U VPX高性能计算刀片上市
  14. 【LaTeX】论文写作之参考文献(数模、美赛、学位论文、英文SCI论文写作通用)
  15. 「需求广场」需求词更新明细(十二)
  16. 干货 | 应用打包还是测试团队老大难问题?
  17. 推荐几款炫酷的 MySQL 可视化管理工具!好用到爆!!
  18. 博士申请 | 香港理工大学招收机器学习全奖博士生/博士后/研究助理
  19. 数据结构与算法A实验六图论---7-10 邻接矩阵表示法创建无向图
  20. 数据库———数据查询

热门文章

  1. 华为交换机stp原理透析及实战
  2. Java8新特性学习_001_(Lambda表达式,函数式接口,方法引用,Stream类,Optional类)
  3. Mysql导出数据 (windows Linux)
  4. 使用bat将数据连续写入文件中
  5. 【Oracle】ORA-55610: Invalid DDL statement on history-tracked table
  6. 【Oracle】创建角色
  7. 解决MVC运行controller的时候只有有参构造函数但是程序一定要走无参构造函数的方法
  8. Python UnicodeEncodeError: ‘gbk‘ codec can‘t encode character 解决方法
  9. Eclipse properties.config.yml 配置文件中文编码问题。Eclipse 配置文件插件解决方案
  10. Project facet Java version 1.7 is not supported.解决方法