上个Demo主要写了C++类的各种参数传入,然而这些参数并不包括函数,后面又改了部分,加入callback:
#include <iostream>
#include <functional>
using namespace std;
extern "C" {
#include <lua.h>
#include <lauxlib.h>
#include <lualib.h>
#include "tolua/tolua++.h"
}
class Fish{
public:
Fish() :_positionX(0), _positionY(0), _positionZ(0), _name("defaule"){ cout << "the name is " << _name.c_str() << endl; }
~Fish(){};
std::string getName(){ _callBack(); return _name; }
void setCallBack(const std::function<void()>& callBack){ _callBack = callBack; }
void setName(std::string name){ _name = name; }
private:
std::string _name;
float _positionX;
float _positionY;
float _positionZ;
std::function<void()> _callBack;
};
template <class T>
void object_to_luaval(lua_State* L, const char* type, T* ret)
{
if (nullptr != ret)
{
tolua_pushusertype(L, (void*)ret, getLuaTypeName(ret, type));
}
else
{
lua_pushnil(L);
}
}
// __declspec(dllexport)
static int ding_sum2(lua_State *L){
double d1 = luaL_checknumber(L, 1);
double d2 = luaL_checknumber(L, 2);
lua_pushnumber(L, d1 + d2);
return 1;
}
static const struct luaL_Reg global_lib[] = {
{ "global_lib", ding_sum2 },
{ NULL, NULL }
};
static int s_function_ref_id = 0;
int lua_Fish_constructor(lua_State* L)//__cdecl
{
Fish* cobj = nullptr;
cobj = new Fish();
tolua_pushusertype_and_addtoroot(L, cobj, "Fish");
return 1;
}
// check lua value is function
TOLUA_API int toluafix_isfunction(lua_State* L, int lo, const char* type, int def, tolua_Error* err)
{
if (lua_gettop(L) >= abs(lo) && lua_isfunction(L, lo))
{
return 1;
}
err->index = lo;
err->array = 0;
err->type = "[not function]";
return 0;
}
bool luaval_to_std_string(lua_State* L, int lo, std::string* outValue, const char* funcName)
{
if (NULL == L || NULL == outValue)
return false;
bool ok = true;
tolua_Error tolua_err;
if (!tolua_iscppstring(L, lo, 0, &tolua_err))
{
ok = false;
}
if (ok)
{
size_t size;
auto rawString = lua_tolstring(L, lo, &size);
*outValue = std::string(rawString, size);
}
return ok;
}
TOLUA_API int toluafix_ref_function(lua_State* L, int lo, int def)
{
// function at lo
if (!lua_isfunction(L, lo)) return 0;
s_function_ref_id++;
int top = lua_gettop(L);
//lua_newtable(L);
lua_pushstring(L, "toluafix_refid_function_mapping");
lua_rawget(L, LUA_REGISTRYINDEX); /* stack: fun ... refid_fun */
//lua_newtable(L);
lua_pushinteger(L, s_function_ref_id); /* stack: fun ... refid_fun refid */
lua_pushvalue(L, lo); /* stack: fun ... refid_fun refid fun */
lua_rawset(L, -3); /* refid_fun[refid] = fun, stack: fun ... refid_ptr */
lua_pop(L, 1); /* stack: fun ... */
return s_function_ref_id;
//return s_function_ref_id;
// lua_pushvalue(L, lo); /* stack: ... func */
// return luaL_ref(L, LUA_REGISTRYINDEX);
}
TOLUA_API void toluafix_get_function_by_refid(lua_State* L, int refid)
{
lua_pushstring(L, "toluafix_refid_function_mapping");
lua_rawget(L, LUA_REGISTRYINDEX); /* stack: ... refid_fun */
lua_pushinteger(L, refid); /* stack: ... refid_fun refid */
lua_rawget(L, -2); /* stack: ... refid_fun fun */
lua_remove(L, -2); /* stack: ... fun */
}
bool pushFunctionByHandler(lua_State* L, int nHandler)
{
toluafix_get_function_by_refid(L, nHandler); /* L: ... func */
if (!lua_isfunction(L, -1))
{
//CCLOG("[LUA ERROR] function refid '%d' does not reference a Lua function", nHandler);
lua_pop(L, 1);
return false;
}
return true;
}
int executeFunction(lua_State* L,int numArgs)
{
int functionIndex = -(numArgs + 1);
if (!lua_isfunction(L, functionIndex))
{
//CCLOG("value at stack [%d] is not function", functionIndex);
lua_pop(L, numArgs + 1); // remove function and arguments
return 0;
}
int traceback = 0;
lua_getglobal(L, "__G__TRACKBACK__"); /* L: ... func arg1 arg2 ... G */
if (!lua_isfunction(L, -1))
{
lua_pop(L, 1); /* L: ... func arg1 arg2 ... */
}
else
{
lua_insert(L, functionIndex - 1); /* L: ... G func arg1 arg2 ... */
traceback = functionIndex - 1;
}
int error = 0;
//++_callFromLua;
error = lua_pcall(L, numArgs, 1, traceback); /* L: ... [G] ret */
//callFromLua;
if (error)
{
if (traceback == 0)
{
// CCLOG("[LUA ERROR] %s", lua_tostring(_state, -1)); /* L: ... error */
lua_pop(L, 1); // remove error message from stack
}
else /* L: ... G error */
{
lua_pop(L, 2); // remove __G__TRACKBACK__ and error message from stack
}
return 0;
}
// get return value
int ret = 0;
if (lua_isnumber(L, -1))
{
ret = (int)lua_tointeger(L, -1);
}
else if (lua_isboolean(L, -1))
{
ret = (int)lua_toboolean(L, -1);
}
// remove return value from stack
lua_pop(L, 1); /* L: ... [G] */
if (traceback)
{
lua_pop(L, 1); // remove __G__TRACKBACK__ from stack /* L: ... */
}
return ret;
}
int executeFunctionByHandler(lua_State* L,int nHandler, int numArgs)
{
int ret = 0;
if (pushFunctionByHandler(L,nHandler)) /* L: ... arg1 arg2 ... func */
{
if (numArgs > 0)
{
lua_insert(L, -(numArgs + 1)); /* L: ... func arg1 arg2 ... */
}
ret = executeFunction(L,numArgs);
}
lua_settop(L, 0);
return ret;
}
int lua_Fish_Set_Name(lua_State* L)//__cdecl
{
int argc = 0;
Fish* cobj = nullptr;
tolua_Error tolua_err;
bool ok = true;
if (!tolua_isusertype(L, 1, "Fish", 0, &tolua_err)) goto tolua_lerror;
cobj = (Fish*)tolua_tousertype(L, 1, 0);
if (!cobj)
{
tolua_error(L, "invalid 'cobj' in function 'lua_Fish_Set_Name'", nullptr);
return 0;
}
argc = lua_gettop(L) - 1;
if (argc == 1)
{
std::string arg0;
ok &= luaval_to_std_string(L, 2, &arg0, "Fish:setName");
if (!ok)
{
tolua_error(L, "invalid arguments in function 'lua_Fish_Set_Name'", nullptr);
return 0;
}
cobj->setName(arg0);
lua_settop(L, 1);
return 1;
}
tolua_lerror:
tolua_error(L, "#ferror in function 'lua_Fish_Set_Name'.", &tolua_err);
return 1;
}
int lua_Fish_set_callBack(lua_State* L)
{
if (L == NULL)
return 0;
int argc = 0;
Fish* cobj = nullptr;
tolua_Error tolua_err;
bool ok = true;
if (!tolua_isusertype(L, 1, "Fish", 0, &tolua_err)) goto tolua_lerror;
cobj = (Fish*)tolua_tousertype(L, 1, 0);
if (!cobj)
{
tolua_error(L, "invalid 'cobj' in function 'lua_Fish_set_callBack'", nullptr);
return 0;
}
argc = lua_gettop(L) - 1;
do {
if (argc == 1)
{
if (!toluafix_isfunction(L, 2, "LUA_FUNCTION", 0, &tolua_err)) {
goto tolua_lerror;
}
int handler = toluafix_ref_function(L, 2, 0);
cout << "handler is " << handler<< endl;
cobj->setCallBack([=](){
cout << "do the callBak" << handler<< endl;
executeFunctionByHandler(L, handler, 1);
});
//toluafix_pushusertype_ccobject(L, id, luaID, (void*)sprite, "cc.Sprite3D");
//cobj->setName(arg0);
lua_settop(L, 1);
return 1;
}
} while (0);
tolua_lerror:
tolua_error(L, "#ferror in function 'lua_Fish_Set_Name'.", &tolua_err);
return 1;
}
int lua_Fish_Get_Name(lua_State* L)//__cdecl
{
int argc = 0;
Fish* cobj = nullptr;
bool ok = true;
tolua_Error tolua_err;
if (!tolua_isusertype(L, 1, "Fish", 0, &tolua_err)) goto tolua_lerror;
cobj = (Fish*)tolua_tousertype(L, 1, 0);
if (!cobj)
{
tolua_error(L, "invalid 'cobj' in function 'lua_cocos2dx_Node_getChildByName'", nullptr);
return 0;
}
argc = lua_gettop(L) - 1;
if (argc == 0)
{
std::string arg0;
std::string ret = cobj->getName();
lua_pushlstring(L, ret.c_str(), ret.length());
return 1;
}
luaL_error(L, "%s has wrong number of arguments: %d, was expecting %d \n", "cc.Node:getChildByName", argc, 1);
return 0;
tolua_lerror:
tolua_error(L, "#ferror in function 'lua_cocos2dx_Node_getChildByName'.", &tolua_err);
return 0;
}
extern "C" {
int __declspec(dllexport) luaopen_fish(lua_State *L){
//luaL_newlib(L, ding_lib); // 5.2
//L = lua_open();
luaL_openlibs(L);
lua_pushstring(L, "toluafix_refid_function_mapping");
lua_newtable(L);
lua_rawset(L, LUA_REGISTRYINDEX);
tolua_open(L);
#ifndef Mtolua_typeid
#define Mtolua_typeid(L,TI,T)
#endif
tolua_usertype(L, "Fish");
Mtolua_typeid(L, typeid(CCSprite), "Fish");
tolua_open(L);
tolua_module(L, nullptr, 0);
tolua_beginmodule(L, nullptr);
//tolua_usertype(L, "Fish");
tolua_cclass(L, "Fish", "Fish", "", nullptr);
tolua_beginmodule(L, "Fish");
tolua_function(L, "new", lua_Fish_constructor);
tolua_function(L, "getName", lua_Fish_Get_Name);
tolua_function(L, "setName", lua_Fish_Set_Name);
tolua_function(L, "setCallBack", lua_Fish_set_callBack);
tolua_endmodule(L);
tolua_endmodule(L);
luaL_register(L, "global_lib", global_lib); // lua 5.1
return 1;
}
}