专栏首页帘卷西风的专栏修改lua的文件加载器,自定义lua文件加载

修改lua的文件加载器,自定义lua文件加载

Lua提供高级的require函数来加载运行库。

1. require会搜索目录加载文件

2. require会判断是否文件已经加载避免重复加载同一文件。

require使用的路径和普通我们看到的路径还有些区别,我们一般见到的路径都是一个目录列表。require的路径是一个模式列表,每一个模式指明一种由虚文件名(require的参数)转成实文件名的方法。更明确地说,每一个模式是一个包含可选的问号的文件名。匹配的时候Lua会首先将问号用虚文件名替换,然后看是否有这样的文件存在。如果不存在继续用同样的方法用第二个模式匹配。例如,路径如下:

?;?.lua;c:\windows\?;/usr/local/lua/?/?.lua

调用require "lili"时会试着打开这些文件:

lili
lili.lua
c:\windows\lili
/usr/local/lua/lili/lili.lua

require关注的问题只有分号(模式之间的分隔符)和问号,其他的信息(目录分隔符,文件扩展名)在路径中定义。

为了确定路径,Lua首先检查全局变量LUA_PATH是否为一个字符串,如果是则认为这个串就是路径;否则require检查环境变量LUA_PATH的值,如果两个都失败require使用固定的路径(典型的"?;?.lua")

我们在lua中加载文件只能配置LUA_PATH的值。但是我们在进行游戏开发的时候,脚本的路径可能是千变万化的,而且有可能是需要打包到一个专有的文件格式里面,这时候原生lua的加载就会出现很多问题了,有没有更好的方案来加载lua文件呢?接下来我介绍一种方案来解决这种问题。

自定义lua文件加载器

我们可以自定义一个lua文件的加载器,去替换原生lua的加载器,怎讲加载lua文件由我们自己决定。

首先我们应该有一个文件系统来加载资源文件,如果没有也没关系,可以自己写一个加载文件的接口。然后我们写一段代码来调用文件系统或者我们自己写的接口来加载文件到内存。

示例代码如下:

/** 载入lua文件
@param L lua状态机  
@param name 需要加载的文件名 
@return  加载成功返回0
*/
static int luaA_LoadFile(lua_State *L, const char *name)
{
	int status = -1;
	char filename[256];
	sprintf(filename, "%s.lua", name);
	FileSystem * pFileSystem = getFileSystem();
	if(pFileSystem != NULL)
	{
		Stream * pStream = pFileSystem->open(filename);
		if(pStream != NULL)
		{
			Uint32 nLength = pStream->getLength();
			if(nLength > 0)
			{
				// 把文件读进内存
				char * pData = new char[nLength + 1]; pData[nLength] = 0;
				pStream->read(pData, nLength);
				//pStream->close();
				// 通过内存加载文件
				status = luaL_loadbuffer(L, pData, nLength, pData);
				delete[] pData;
			}
			pStream->release();
		}
	}
	return status;
}

上面的加载文件的代码可以自己实现。

下一步我们就写一个函数上面的加载函数设置给lua,替换lua的原生加载器。

static int luaA_SetLoader(lua_State *L, lua_CFunction fn)
{
	lua_getglobal(L, LUA_LOADLIBNAME);
	if (lua_istable(L, -1)) 
	{
		lua_getfield(L, -1, "loaders");
		if (lua_istable(L, -1))
 		{
			lua_pushcfunction(L, fn);
			lua_rawseti(L, -2, 2);
			return 0;
		}
	}
	return -1;
}

做好上面两步基本上就已经完成了,有时候我们还用dofile来加载文件,所以我们需要为dofile也写一个类似的函数。

static int luaA_DoFile(lua_State * L)
{
	size_t l;
	const char* sFileName = luaL_checklstring(L, 1, &l);
	if(sFileName != NULL )
	{
		luaA_LoadFile(L, sFileName);
		return 1;
	}
	return 0;
}

最后,我们在初始化luaState的时候进行设置就行啦!

bool CLuaEngine::Create(bool bFromPackLoadLua)
{
	// 初始化LUA库
	m_pLuaState = lua_open();
	if(m_pLuaState == NULL)
	{
		return false;
	}
	// 初始化所有的标准库
	luaL_openlibs(m_pLuaState);
	// 替换缺省的Lua加载函数
	luaA_SetLoader(m_pLuaState, luaA_LoadFile);
	// 初始化一些基本的api
	lua_register(m_pLuaState, "dofile", luaA_DoFile);
	
	return true;
}

好了,这样无论lua文件放在那里,我们就可以随心所欲的加载lua文件啦,就像加载其他文件一样了。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 关于cocos2dx手游lua文件加密的解决方案

          很多使用cocos2dx+lua做游戏的同学,都会想到一个问题,我的游戏一旦发布,怎样才能保证的我脚本代码不被破解,不泄露代码。虽然这和开源、共享的...

    帘卷西风
  • 关于Excel到lua的转表工具

           关于游戏项目的配置文件,有很多的方案,有些项目有专业的工具,有些则是直接使用json、xml、csv之类的配置文件,使用lua做配置文件的项目也不...

    帘卷西风
  • 关于linux服务器进程监控及自动重启的简单方案

    转载请注明出处:帘卷西风的专栏(http://blog.csdn.net/ljxfblog)

    帘卷西风
  • 在LUA开发方式下,如何实现http下载LUA文件就可以实现升级Air202和ESP8266的LUA程序

    咱们用LUA开发 Air202或者ESP8266的时候是不是都希望可以直接升级lua文件

    杨奉武
  • golua虚拟机的使用

    之前一直想把openflow这样的分布式流程系统做起来,但是时间和应用场景的问题所以都是做了一个半拉子工程,而且之前想的也有点简单了,认为只要有同学愿意,在开发...

    黑光技术
  • Lua调用C++时打印堆栈信息

    公司的手游项目,使用的是基于cocos2d-x绑lua的解决方案(参数quick-x的绑定),虽然使用了lua进行开发,更新很爽了,但是崩溃依然较为严重,从后台...

    meteoric
  • Lua 中的常用API

    程序手艺人
  • ESP8266 LUA脚本语言开发: 准备工作-LUA文件加载与变量调用

    杨奉武
  • 如何选择一个合适的练手项目

    最近在组织编程擂台活动(前文:码上行动的同学,你有一个机会等待签收),会帮学员们挑选合适的项目,在实践中提升编程能力。

    Crossin先生
  • 对于程序员来说:“选择比努力更重要”对不对?

    经常有计算机专业的师弟师妹问我,“c++和java都上过课,可是学的都是皮毛,我现在是继续自学c++,还是java呢?哪个更有前景?pyhton和php好像也不...

    程序员互动联盟

扫码关注云+社区

领取腾讯云代金券