当前位置: 首页 > article >正文

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的,根据项目情况来进行处理。


http://www.kler.cn/a/2084.html

相关文章:

  • 让汉语和英语一样长的字符编码
  • 【计算机网络2】计算机网络的性能能指标
  • 【游戏设计原理】20 - 囚徒困境
  • Intel-ECI之Codesys PLC + Ethercat 远端IO + Codesys IDE编程
  • 全速下载 50M/S,不限速下载就是香
  • 【C语言】库函数常见的陷阱与缺陷(一):字符串处理函数[3]--strlen
  • Kaggle实战入门:泰坦尼克号生还预测(进阶版)
  • Qt cmake 资源文件的加载
  • LeetCode:27. 移除元素
  • ini配置文件
  • Boosting(XGBoost、LightGBM以及CatBoost)
  • 栈、队列、优先级队列的模拟实现
  • 【计算机组成原理】:计算机系统概述
  • 鸟哥的Linux私房菜 Shell脚本
  • 【Leetcode】队列实现栈和栈实现队列
  • 【三维几何学习】从零开始网格上的深度学习-3:Transformer篇(Pytorch)
  • 【Zabbix实战之部署篇】docker部署Zabbix+grafana监控平台
  • 【C++初阶】四、类和对象(下)
  • 沁恒CH32V307使用记录:使用TIM输出PWM信号
  • C++笔记——第六篇 list的简介和使用
  • 多线程 (六) 单例模式
  • 蓝桥杯备赛经验 pythonA组(非科班选手)
  • 拯救会议纪要!快用这三个音频转文字方法,让领导对你刮目相看
  • FLEXPART拉格朗日粒子扩散模式建模技术及研究大气污染物源-汇关系中的实践经验
  • 【Java】i++和++i的实现原理
  • 函数(上)——“Python”