unity3d游戏运行时lua热重载

上个项目体验到了关掉界面修改lua代码就会生效的便捷,这两天趁没什么紧急事项就在现在项目也加上了这个支持。

核心思想

核心思想就是

package.loaded[fileName]=nil;
require(fileName)

过程

当前项目lua文件引用有好几种:
第一种是路径作为参数传入一个叫luawindom或luaitem的cs文件,通过slua的luastate的start方法引用,也就是dofile.
第二种是传统的写在固定文件里,登录的时候统一require,
第三种是分布在各个业务系统里自己require的一些文件,也就是没按照规则放在统一加载地方的文件。

首先重载第一种方式载入的lua文件,由于当前项目目前关闭界面只是隐藏界面,并不是销毁,不好跟之前项目一样搞成按关闭界面就重载,那个载入lua文件的start函数也只会执行一次,由于每次都是隐藏,所以不会正常程序是不会再执行的,那个luaitem也是这样。我选择的方案是加一个重载按钮,点了重载就加一个标志位,如果这个界面是标志过的那就直接destroy,由于它destroy也会遍历本身包含的luaitem,所以这两个就一并解决了,非常简单。

接着,如果不是作为路径传给luaWindow或luaitem的lua文件所有人都是按照规则把require写在固定文件夹那就好办了,直接通过重载按钮传参重新require指定的文件就行,但固定文件里只有部分文件,只require那部分得不到想要的效果,所以我把第二种和第三种情况合并处理。

我观察项目目录,发现那些不按规则require的文件基本都是在对应功能的目录或者子目录下,例如活动界面require了一个item1,item2,他们目录通常都是act/item1或者act/sub/item2。所以当重载界面时,选择重载这个界面所在目录的所有lua文件是一个不错的方案,能保证跟这个界面相关的文件都重载(如果有奇葩把其他功能模块的lua文件在不对应的界面require这种情况就不理了)。

接下来就很简单了,在重载按钮里调用lua重载就可以了,slua是这么写:

LuaTable luaData = luastate.start("你的目录/hotRequire.lua");
LuaFunction f = (LuaFunction)luaData["RefreshLua"];
if (f == null)
{
	return;
}
/*path为当前文件所在目录,得根据自己项目目录做处理,要保证它是当前模块的父目录,
例如lua/activity,保证当前活动相关的文件都在这下面*/
f.call(path);

接着是全文的重点,这次遇到的坑。

1.这个项目用不了lfs,require “lfs”会报字符串无法转换,查了下说是.netframework版本问题或编码问题,我试了下设置package.cpath和重新换一个lfs库都不行,我不知道怎么改dll编码,也不能因为我这个东西而修改项目.netframewrok设置,所以只能不用lfs来遍历文件夹,能用的情况就不会有下面的坑。
2.在不能用lfs的情况,你去查资料会查到可以用os.execute或者io.popen函数来执行系统命令进行遍历,这里有个特别坑的地方,就是windows下的路径“/”要替换成“||”,不然执行遍历目录的命令根本不会生效,我是在cmd运行命令才发现这一点的,我查到所有资料都没说,我真不怀疑他们是不是能真的运行,这卡了我一整天时间,这个问题解决后还要找到正确的系统指令,网上搜的系统指令乱七八糟的,经过一番搜索和尝试才找到了正确的指令,至此就能遍历整个lua文件夹里的lua文件,然后利用核心思想重载他们。
代码:

hotReqire = {}
function main()
	return hotReqire
end

hotRequire.RefreshLua = function(path)
	hotRequire:FindPath(path)
end

function hotRequire:FindPath(path)
	--只输出文件
	local cmd1 = "dir"..string.gsub(path,"/","\\").." /b /a-d"
	--只输出目录
	local cmd2 = "dir"..string.gsub(path,"/","\\").." /b /ad"
	local handle1 = io.popen(cmd1)
	local handle2 = io.popen(cmd2)
	if handle then
		for line in handle:lines() do
			if string.find(line,"lua") and not string.find(line,"meta") then
				package.loaded[line]=nil;
				require(line)
			end
		end
	end
	if handle2 then
		for line in handle2:lines() do
			local subPath = string.gsub(path,"/","\\").."\\"..line
			hotRequire:FindPath(subPath)
		end
	end
	handle1:close()
	handle2:close()
end

这就是所有代码,按实际项目做路径拼接对应修改应该就能生效。

我踩的坑是用不了lfs,然后不用lfs遍历在lua遍历文件夹,这个东西并不复杂,主要还是要了解自己当前项目是怎么载入lua的,根据项目情况来进行处理。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值