摘要:
此系列是为经手的项目介绍编译和使用,以及项目开发过程中遇到的bug解决方案或项目开发过程中有意思的需求设计等等项目相关的博文。
此篇是为开发自定义界面项目过程中系统页面与脚本交互的一个小需求,系统导入用户自己编写的.lua脚本文件,需要页面获取.lua文件内用户自定义的函数名称,并保存到系统供控件后续绑定调用。
(开发环境:VSCode,cmake,Qt5)
关键词
: C++,lua,项目,开发问题,需求分析
声明:
本文作者原创,转载请附上文章出处与本文链接。
正文:
print("lua load")
function Example1()
print("lua load1")
end
function Example2()
print("lua load2")
end
function Example3()
print("lua load3")
end
function Example4()
print("lua load4")
end
用户定义的.lua文件类似这样,系统页面需要获取到Example1,Example2,Example3,Example4。难点在于用户需要高自定义性,不能过多限制用户编写的.lua文件,又需要精确识别,不能多也不能少。
解决方案
通过internet,以及stackoverflow1、stackoverflow2找到四种解决方案:
- 第一种就是给用户做点小限制,让用户把需要导入的脚本函数归类到一个表(例如functions),然后系统页面迭代这个函数包也行,比较方便,效率也高。
- 第二种不做限制,系统页面找.lua文件的"_G"的全局函数表,表内包括用户定义的全局对象和默认函数例如print之类的,不过如果用户导包了,默认函数会更多, 获取_G集合后减去默认函数集合得到用户定义的函数集合,效率比较低准确度也不好把握容易出错。
- 第三种C++逐行获取字符串匹配function关键字后在" “和”(" 之间的就是函数名保存下来即可,效率20行大概0.2ms ,不过也要考虑local和print-function相关字符串等,参考:https://www.cnblogs.com/dechinphy/p/cppio.html。
- 第四种使用第三方lbci lua字节编码检测器,没深入了解,感觉很麻烦,要解析运行后的编码。
解决
综合考虑使用第一种,限制小准确度高开发也比较方便,那么本质上也只是C++ 与 lua数据交互的问题。
-- .lua文件
print("lua load")
functions = {}
function functions.Example1()
print("lua load1")
end
function functions.Example2()
print("lua load2")
end
function functions.Example3()
print("lua load3")
end
function Example4()
print("lua load4")
end
// 识别.lua CCustomLuaBridge.cpp
// lua_State *Lua Lua状态机
// QString luaPath ./lua文件路径
// bool openSuccess 是否成功载入.lua文件
......
{
QStringList nameList;
// 加载Lua脚本
if (luaL_loadfile(Lua, luaPath.toStdString().c_str()) != LUA_OK || lua_pcall(Lua, 0, LUA_MULTRET, 0)) {
qDebug() << "Error loading/running Lua script: " << lua_tostring(Lua, -1);
lua_pop(Lua, 1); // 移除错误消息
lua_close(Lua); // 关闭Lua状态机
openSuccess = false;
return QStringList();
}
openSuccess = true;
// 将全局环境functions压入栈顶
lua_getglobal(Lua, "functions");
// 检查栈顶functions是否是一个表
if (!lua_istable(Lua, -1)) {
qDebug() << "Error: functions is not a table";
lua_pop(Lua, 1); // 移除栈顶元素
lua_close(Lua); // 关闭Lua状态机
return QStringList();
}
// 遍历functions表
lua_pushnil(Lua); // 第一个key
while (lua_next(Lua, -2)) {
// -1 是值,-2 是键
// 检查值是否是一个函数
if (lua_isfunction(Lua, -1)) {
// 获取键(函数名)
const char* functionName = lua_tostring(Lua, -2);
qDebug() << "Found function: " << functionName;
nameList << functionName;
}
// 移除值(保留键用于下一次迭代)
lua_pop(Lua, 1);
}
nameList.sort(); // 排序一下
// 移除表
lua_pop(Lua, 1);
lua_close(Lua); // 关闭Lua状态机
return nameList;
}
......
主体功能完成,后续就是完善需求细节部分,导入脚本以及刷新机制等等。
推荐阅读
博客主页:https://blog.csdn.net/weixin_45068267
(客官逛一逛,有许多其它有趣的专栏博文)