参与制作的游戏内部有导出sqlite数据为lua表的步骤,引擎用的cocos2d,但是每次都要启动游戏exe
坐旁边的策划小哥想在手机远程操作公司电脑配置提交数值表,他表示手机没法启动游戏exe,但我没有我们的游戏的工程文件,抄不了前人的代码就自己动手简单实现了一下
新建控制台工程,自己编译集成了sqlite与lua的lib导入,略过不写
sqlitedbtest.cpp
#include "pch.h"
#include "include/sqlite3.h"
#include <iostream>
#include <windows.h>
#include <stdlib.h>
#include <direct.h>
extern "C" {
#include <lua.h>
#include <lualib.h>
#include <lauxlib.h>
}
using namespace std;
sqlite3 * pDB = NULL;
lua_State *L;
string result = "";
int pram_count = 0;
char *path;
bool getWorkPath();
int getInfo();
bool dirExists(const std::string& dirName_in);
int luaGetDirExists(lua_State *L);
int SelectInfo(lua_State *L);
int luaTest();
int setFunc();
int clearFunc(lua_State *L);
char* func(char * const str);
static void print_error(lua_State *L);
int main()
{
getInfo();
system("pause");
}
bool getWorkPath()
{
//也可以将buffer作为输出参数
if ((path = _getcwd(NULL, 0)) == NULL)
{
perror("getcwd error");
return false;
}
else
{
printf("%s\n", path);
return true;
}
return false;
}
string GbkToUtf8(const char *src_str)
{
int len = MultiByteToWideChar(CP_ACP, 0, src_str, -1, NULL, 0);
wchar_t* wstr = new wchar_t[len + 1];
memset(wstr, 0, len + 1);
MultiByteToWideChar(CP_ACP, 0, src_str, -1, wstr, len);
len = WideCharToMultiByte(CP_UTF8, 0, wstr, -1, NULL, 0, NULL, NULL);
char* str = new char[len + 1];
memset(str, 0, len + 1);
WideCharToMultiByte(CP_UTF8, 0, wstr, -1, str, len, NULL, NULL);
string strTemp = str;
if (wstr) delete[] wstr;
if (str) delete[] str;
return strTemp;
}
int getInfo()
{
if (!getWorkPath())
{
printf("get path err");
return 0;
}
string db_path(path);
db_path = db_path + "\\data.db";
printf("%s\n",db_path.c_str());
db_path = GbkToUtf8(db_path.c_str());
int nRes = sqlite3_open(db_path.c_str(), &pDB);
//string db_path = path + "/data.db";
//int nRes = sqlite3_open("E:/test/sqlitedbtest/sqlitedbtest/data.db", &pDB);
if (nRes != SQLITE_OK)
{
cout << "Open database fail: " << sqlite3_errmsg(pDB);
goto QUIT;
}
setFunc();
QUIT:
sqlite3_close(pDB);
pDB = NULL;
return 0;
}
bool dirExists(const std::string& dirName_in)
{
DWORD ftyp = GetFileAttributesA(dirName_in.c_str());
if (ftyp == INVALID_FILE_ATTRIBUTES)
return false; //something is wrong with your path!
if (ftyp & FILE_ATTRIBUTE_DIRECTORY)
return true; // this is a directory!
return false; // this is not a directory!
}
int luaGetDirExists(lua_State *L)
{
int n = lua_gettop(L);
string _path = lua_tostring(L, 1);
bool ifExists = dirExists(_path);
lua_pushboolean(L,ifExists);
return 1;
}
static int UserResult(void *NotUsed, int argc, char **argv, char **azColName)
{
string s = "{";
string k, v;
for (int i = 0; i < argc; i++)
{
if (argv[i] != NULL)
{
v = func(argv[i]);
}
else
{
v = "";
}
if (azColName[i] != NULL)
{
k = azColName[i];
}
else
{
k = "";
}
//将key,value转换为字符串表现
s = s + "[\"" + k + "\"]" + "=\"" + v + "\"";
if (i != argc - 1)
{
s += ",";
}
else
{
s = s + "},\n";
}
//cout << azColName[i] << " = " << (argv[i] ? argv[i] : "NULL") << ", ";
}
result += s;
pram_count++;
return 0;
}
int SelectInfo(lua_State *L)
{
int n = lua_gettop(L);
string select = lua_tostring(L, 1);
select += ";";
char* cErrMsg;
int res = sqlite3_exec(pDB, select.c_str(), UserResult, 0, &cErrMsg);
if (res != SQLITE_OK)
{
cout << "select fail: " << cErrMsg << endl;
cout << "check db'size and change the correct db" << endl;
return false;
}
for (size_t i = 0; i < 2; i++)
{
result.pop_back();
}
result = "{" + result + "}";
lua_pushstring(L, result.c_str());
lua_pushnumber(L, pram_count);
return 2;
}
int luaTest()
{
/*
L = luaL_newstate();
lua_getglobal(L, "ruler"); //函数名为ruler
lua_pcall(L, 0, 0, 0); //用保护模式调用lua函数,入参个数为0、出参个数为0、无自定义错误处理
//b、有参函数
lua_getglobal(L, "add"); //函数名为add
lua_pushnumber(L, 1); //第一个入参
lua_pushnumber(L, 2); //第二个入参
lua_pcall(L, 2, 1, 0); lua_getglobal(L, "ruler"); //函数名为ruler
lua_pcall(L, 0, 0, 0); //用保护模式调用lua函数,入参个数为0、出参个数为0、无自定义错误处理
//b、有参函数
lua_getglobal(L, "add"); //函数名为add
lua_pushnumber(L, 1); //第一个入参
lua_pushnumber(L, 2); //第二个入参
lua_pcall(L, 2, 1, 0);
*/
//2、创建lua环境
L = luaL_newstate();
if (L == NULL)
{
cout << "Creat Lua State Error !" << endl;
return 1;
}
//如需在终端输出打印信息,库是必须加载的,否则看不到lua的print信息
luaL_openlibs(L);
//3、加载lua脚本
const string lua_path = "../sqlitedbtest/";
const string file = "mylua.lua";
string script = lua_path + file;
int ret = luaL_dofile(L, script.c_str());
if (ret)
{
cout << "Lua doFile Error !" << endl;
return 1;
}
//4、调用脚本中已写好的函数
//a、无参函数
lua_getglobal(L, "ruler"); //函数名为ruler
lua_pcall(L, 0, 0, 0); //用保护模式调用lua函数,入参个数为0、出参个数为0、无自定义错误处理
//b、有参函数
lua_getglobal(L, "add"); //函数名为add
lua_pushnumber(L, 1); //第一个入参
lua_pushnumber(L, 2); //第二个入参
lua_pcall(L, 2, 1, 0); //函数有两个入参,一个出参,所以函数形式为add(a,b)
//5、获得返回值,单回值情况下调用完成后lua会把结果放到栈顶,多返回值时,按照规则存放,具体查API
if (lua_isnumber(L, -1))
{
cout << "the result is :" << lua_tonumber(L, -1) << endl;
}
//6、销毁lua环境
lua_close(L);
return 0;
}
int setFunc()
{
L = lua_open();
luaL_openlibs(L);
//luaopen_base(L);
/* 往lua中注册函数
lua_pushvalue(L, LUA_GLOBALSINDEX);
lua_pushstring(L, "SelectInfo");
lua_pushcfunction(L, SelectInfo,1);
lua_rawset(L, -3);
lua_pop(L, 1);
*/
lua_register(L, "luaGetDirExists", luaGetDirExists);
lua_register(L, "SelectInfo", SelectInfo);
lua_register(L, "clearFunc", clearFunc);
const string file = "\\mylua.lua";
string script = path + file;
printf("%s\n", script.c_str());
int ret = luaL_dofile(L, script.c_str());
if (ret)
{
print_error(L);
cout << "Lua doFile Error !" + ret << endl;
return 1;
}
lua_close(L);
return 0;
}
int clearFunc(lua_State *L)
{
result = "";
pram_count = 0;
return 0;
}
//去掉行尾的'/r'
char *func(char * const str)
{
int i, j;
for (i = 0; str[i];) {
if (str[i] == '\n' || str[i] == '\r' || str[i] == '\t' || str[i] == ' ') {
for (j = i; str[j]; j++) {
str[j] = str[j + 1];
}
}
else i++;
}
return str;
}
static void print_error(lua_State *L)
{
fprintf(stderr, "\nFATAL ERROR:%s\n\n", lua_tostring(L, -1));
}
然后在lua里制定数据格式,导出lua文件
入口文件mylua.lua,ddinfo里初始化了所有的表为空表,如dd.equip = {}这样的,写得有点乱将就看一下
require "ddinfo"
require "getDBInfo"
function getPath()
-- print("this is some thing need to tell you !!!");
local info = debug.getinfo(1, "S") -- 第二个参数 "S" 表示仅返回 source,short_src等字段, 其他还可以 "n", "f", "I", "L"等 返回不同的字段信息
for k,v in pairs(info) do
print(k, ":", v)
end
local path = info.source
path = string.sub(path, 2, -1) -- 去掉开头的"@"
path = string.match(path, "^.*\\") -- 捕获最后一个 "/" 之前的部分 就是我们最终要的目录部分
print("dir=", path)
return path
end
function Split(str, delim)
-- Eliminate bad cases...
if str == "" or str == nil then
return {}
end
if string.find(str, delim) == nil then
return { str }
end
_,len = string.find(str, delim)
if len <= 0 then
return {str}
end
local result = {}
local pat = "(.-)" .. delim .. "()"
local nb = 0
local lastPos
for part, pos in string.gfind(str, pat) do
nb = nb + 1
result[nb] = part
lastPos = pos
end
-- Handle the last field
result[nb + 1] = string.sub(str, lastPos)
return result
end
function clearCfg()
-- local pathStr = cc.FileUtils:getInstance():fullPathForFilename("data.lua")
-- local relPathStr = string.gsub(pathStr, "data.lua","")
--将exe放到lua文件夹下
local cfg = io.open(getPath().."cfg/cfg.lua","w+")
io.close(cfg)
end
function makeLuaTableFile(tb,head,name,add)
if tb == nil then
return
end
if add == nil then
add = false
end
local relPathStr = getPath()
cclog("relPathStr:"..relPathStr)
-- if not file_exists(relPathStr.."cfg.lua") then
-- cclog("cfg not exists")
-- else
-- cclog("cfg exists")
-- end
if not luaGetDirExists(relPathStr.."cfg") then
os.execute("mkdir \"" .. relPathStr.."/cfg" .. "\"")
end
local file = nil
if add == true then
file = io.open(relPathStr.."cfg/"..name..".lua","a+")
else
file = io.open(relPathStr.."cfg/"..name..".lua","w+")
end
cclog(relPathStr.."cfg/"..name..".lua")
file:write(head.." = {}\n")
outFile(file,head,tb)
io.close(file)
if add == false then
local cfg = io.open(relPathStr.."cfg/cfg.lua","a+")
cfg:write("require \"cfg/"..name.."\"\n")
io.close(cfg)
end
end
function outFile(file,head,tb)
for k,v in pairs(tb) do
if type(v) == "table" then
if type(k) == "number" then
local line = head.."["..k.."] = {}\n"
file:write(line)
outFile(file,head.."["..k.."]",v)
else
local line = head.."['"..k.."'] = {}\n"
file:write(line)
outFile(file,head.."['"..k.."']",v)
end
elseif type(v) == "number" then
if type(k) == "number" then
local line = head.."["..k.."] = "..v.."\n"
file:write(line)
else
local line = head.."['"..k.."'] = "..v.."\n"
file:write(line)
end
else
if string.byte(v,-1) == 13 then
v = string.sub(v,1, string.len(v) - 1)
end
if type(k) == "number" then
local line = head.."["..k.."] = '"..v.."'\n"
file:write(line)
else
local line = head.."['"..k.."'] = '"..v.."'\n"
file:write(line)
end
end
end
end
cclog = function(...)
print(string.format(...))
end
function __G__TRACKBACK__(msg)
cclog("----------------------------------------")
cclog("LUA ERROR: " .. tostring(msg) .. "\n")
cclog(debug.traceback())
cclog("----------------------------------------")
end
data = {}
tb = {}
function data:getString(i,pram)
return tb[i][pram]
end
function data:clear()
clearFunc()
tb = {}
end
function main()
clearCfg()
initTablesOK()
end
xpcall(main, __G__TRACKBACK__)
getDBInfo.lua
function initTablesOK()
local str,count = SelectInfo("select * from tablename_in_db")
--用loadstring获取用数据制成的表
--loadstring 将字符串内容解读成一个方法,失败返回nil
--C++中已经将数据库查询到的数据转换成表的形式返回成str
local func = loadstring("return "..str)
tb = func()
for i=1,count do
local id = tonumber(data:getString(i,"F0"))
dd.cfgXXX[id] = {}
dd.cfgXXX[id]["name"] = tonumber(data:getString(i,"F1"))
end
makeLuaTableFile(dd.cfgXXX,"dd.cfgXXX","tablename_in_db")
data:clear()
end
读取data.db的数据,最后导出的lua配置表文件在exe所在文件夹下的cfg文件夹中