工業(yè)和信息化部官網(wǎng)合肥seo網(wǎng)站排名
C++ 調(diào)用lua
基礎(chǔ)調(diào)用
再來溫習(xí)一下
myName = “beauty girl”
- C++想要獲取myName的值,根據(jù)規(guī)則,它需要把myName壓入棧中,這樣lua就能看到;
- lua從堆棧中獲取myName的值,此時棧頂為空;
- lua拿著myName去全局表中查找與之對應(yīng)的字符串;
- 全局表找到,并返回"beauty girl";
- lua把"beauty girl"壓入棧中;
- C++從棧中獲取"beauty girl"
用代碼來實現(xiàn)
//創(chuàng)建一個statelua_State *L = luaL_newstate();// 重置棧頂索引 為了確認讓棧頂?shù)乃饕脼? 置0之后,我們?nèi)霔5牡谝粋€元素的索引就是1lua_settop(L, 0);// 把myName放入棧中,然后lua去全局表中查找,找到對應(yīng)的字段,再放回棧中lua_getglobal(L, "myName");// 判斷棧頂?shù)闹档念愋褪欠駷镾tring, 返回非0值代表成功int isstr = lua_isstring(L, 1);//獲取棧頂?shù)闹?/span>const char* str = lua_tostring(L, 1);lua_close(L);
C++獲取Lua的table
helloTable = {name = “xxx”, sex = “man”}
和上面一樣,要獲取就先把helloTable放到棧頂,讓Lua知道C++要獲取這個值
//創(chuàng)建一個statelua_State *L = luaL_newstate();// 重置棧頂索引 為了確認讓棧頂?shù)乃饕脼? 置0之后,我們?nèi)霔5牡谝粋€元素的索引就是1lua_settop(L, 0);//獲取helloTable的值 這個時候棧底 是 helloTablelua_getglobal(L, "helloTable");//我們想要獲取table中name的值,那么就把name壓入棧//這個時候棧中是 name,helloTable,其中name是棧頂lua_pushstring(L, "name");//lua api提供了一個獲取table的函數(shù) lua_gettable//該函數(shù)會從棧頂取得一個值,然后根據(jù)這個值去table中尋找對應(yīng)的值,最后把找到的值放到棧頂 第二個參數(shù)是指table變量所在棧中的位置lua_gettable(L, -2); // -1永遠是棧頂,那么helloTable就是-2,這里也可以用1//lua_gettable 會把值放到 棧頂 const char* sName = lua_tostring(pL, -1);
C++調(diào)用Lua函數(shù)
function helloAdd(num1, num2)return (num1 + num2)
end
這里有個新的函數(shù) lua_call
第一個參數(shù)表示函數(shù)的參數(shù)個數(shù),第二個參數(shù)表示函數(shù)返回值個數(shù)
Lua會先去堆棧取出參數(shù),然后再取出函數(shù)對象,開始執(zhí)行函數(shù)
//創(chuàng)建一個statelua_State *L = luaL_newstate();// 重置棧頂索引 為了確認讓棧頂?shù)乃饕脼? 置0之后,我們?nèi)霔5牡谝粋€元素的索引就是1lua_settop(L, 0);//把helloAdd函數(shù)對象放到棧中lua_getglobal(L, "helloAdd");//把函數(shù)所需要的參數(shù)入棧 lua_pushnumber(L, 10);lua_pushnumber(L, 5);//調(diào)用lua_calllua_call(L, 2, 1);int iResult = lua_tonumber(L, -1);
C++調(diào)用Lua table的函數(shù)
lua中table有兩種函數(shù)
mytable={}
function mytable.StaticFunc()print("mytable.StaticFunc called.")
end
function mytable:Func()print("mytable:Func self:", self)
end
其中StaticFunc可以理解成table的靜態(tài)函數(shù),Func為table的成員函數(shù)
// 調(diào)用mytable表的靜態(tài)函數(shù)
lua_getglobal(L, "mytable"); // 將名為mytable的全局table變量的值壓棧
lua_pushstring(L, "StaticFunc"); // 將函數(shù)名為StaticFunc壓棧
lua_gettable(L, -2); // 從索引為-2處的表中,讀取key(在棧頂處)為StaticFunc的函數(shù)名 讀取成功后,將key出棧,并將讀取到的函數(shù)名入棧
lua_call(L, 0, 0); // 執(zhí)行完后將StaticFunc彈出棧 注: 第一個0表示參數(shù)個數(shù)為0,第二個0表示無返回值// 調(diào)用mytable表的成員函數(shù) 采用新方法獲取函數(shù)名
lua_getfield(L, -1, "Func");// 從索引為-1處的表中,讀取key為Func的函數(shù)名 成功后將讀取到的函數(shù)名入棧
lua_pushvalue(L, -2); // 將索引為-2處的表復(fù)制一份并壓入棧頂
lua_call(L, 1, 0); // 執(zhí)行完后將Func彈出棧 注: 1表示參數(shù)個數(shù),即self指針,為當(dāng)前table,第二個0表示無返回值
唯一不同的是lua_call的時候,需要注意第二個的值,成員函數(shù)默認需要傳遞self。
這里獲取的時候,用到了函數(shù)lua_getfield
函數(shù)原型如下
void lua_getfield (lua_State *L, int index, const char *k);
Pushes onto the stack the value t[k], where t is the value at the given valid index. As in Lua, this function may trigger a metamethod for the “index” event
大概意思,將t[k]壓入堆棧,t由參數(shù)index指定在棧中的位置
Lua 調(diào)用C++
Lua調(diào)用C++ 函數(shù)
大概的步驟如下:
- 將C++的函數(shù)包裝成Lua環(huán)境認可的Lua_CFunction格式
- 將包裝好的函數(shù)注冊到Lua環(huán)境中
- 像使用普通Lua函數(shù)那樣使用注冊函數(shù)
簡單的C++函數(shù)
int add(int a,int b)
{return a+b;
}
包裝C++函數(shù)
int add(lua_state *L)
{int a = lua_tonumber(-1);int b = lua_tonumber(-2);int sum = a+b;// 將返回值壓入棧中lua_pushnumber(L,sum);// 返回返回值個數(shù)return 1;
}
- Lua腳本里會調(diào)用add(lua_state *L)
- 調(diào)用add(lua_state *L)函數(shù)的時候,會反過來進行之前的C++調(diào)用lua
- Lua調(diào)用add(lua_state *L)函數(shù)之后,有一個返回值,需要壓入棧中
- 最后return表示有多少個返回值,Lua支持多個返回值
最關(guān)鍵的一步,需要注冊C++的函數(shù),Lua才能調(diào)用
lua_register(L, "add", add);
Lua調(diào)用C++類
這里有兩種方式,一個是用luaL_newlib方式
luaL_newlib方式
大概步驟如下:
- 新建創(chuàng)建對象函數(shù),調(diào)用lua_newuserdata,創(chuàng)建一個對象指針,指向new出來的新的對象。
- 新建成員方法,調(diào)用lua_touserdata,得到從lua中傳入的對象指針,調(diào)用成員方法。
- 調(diào)用luaL_newlib,將需要封裝的C++函數(shù)放入到一個lua表中壓入棧里。
- 將自定義模塊,注冊到Lua環(huán)境中。
- 在lua中,會首先調(diào)用創(chuàng)建對象函數(shù),獲得Student對象指針。通過Student對象指針,調(diào)用成員方法
Student.h
#pragma once#include <iostream>
#include <string>
using namespace std;class Student
{
public://構(gòu)造/析構(gòu)函數(shù)Student();~Student();//get/set函數(shù)string get_name();void set_name(string name);unsigned get_age();void set_age(unsigned age);//打印函數(shù)void print();private:string _name;unsigned _age;
};
Student.cpp
#include "Student.h"
using namespace std;Student::Student():_name("Empty"),_age(0)
{cout << "Student Constructor" << endl;
}Student::~Student()
{cout << "Student Destructor" << endl;
}string Student::get_name()
{return _name;
}void Student::set_name(string name)
{_name = name;
}unsigned Student::get_age()
{return _age;
}void Student::set_age(unsigned age)
{_age = age;
}void Student::print()
{cout << "name :" << _name << " age : " << _age << endl;
}
StudentRegFunc.h
#pragma once#include "Student.h"
extern "C" {
#include "lua.h"
#include "lualib.h"
#include "lauxlib.h"
}//------定義相關(guān)的全局函數(shù)------
//創(chuàng)建對象
int lua_create_new_student(lua_State* L);//get/set函數(shù)
int lua_get_name(lua_State* L);
int lua_set_name(lua_State* L);
int lua_get_age(lua_State* L);
int lua_set_age(lua_State* L);//打印函數(shù)
int lua_print(lua_State* L);//------注冊全局函數(shù)供Lua使用------
static const luaL_Reg lua_reg_student_funcs[] = {{ "create", lua_create_new_student },{ "get_name", lua_get_name },{ "set_name", lua_set_name },{ "get_age", lua_get_age },{ "set_age", lua_set_age },{ "print", lua_print },{ NULL, NULL },
};int luaopen_student_libs(lua_State* L);
StudentRegFunc.cpp
#include "StudentRegFunc.h"int lua_create_new_student(lua_State* L)
{//創(chuàng)建一個對象指針放到stack里,返回給Lua中使用Student** s = (Student**)lua_newuserdata(L, sizeof(Student*));*s = new Student();return 1;
}int lua_get_name(lua_State* L)
{//得到第一個傳入的對象參數(shù)(在stack最底部)Student** s = (Student**)lua_touserdata(L, 1);luaL_argcheck(L, s != NULL, 1, "invalid user data");//清空stacklua_settop(L, 0);//將數(shù)據(jù)放入stack中,供Lua使用lua_pushstring(L, (*s)->get_name().c_str());return 1;
}int lua_set_name(lua_State* L)
{//得到第一個傳入的對象參數(shù)Student** s = (Student**)lua_touserdata(L, 1);luaL_argcheck(L, s != NULL, 1, "invalid user data");luaL_checktype(L, -1, LUA_TSTRING);std::string name = lua_tostring(L, -1);(*s)->set_name(name);return 0;
}int lua_get_age(lua_State* L)
{Student** s = (Student**)lua_touserdata(L, 1);luaL_argcheck(L, s != NULL, 1, "invalid user data");lua_pushinteger(L, (*s)->get_age());return 1;
}int lua_set_age(lua_State* L)
{Student** s = (Student**)lua_touserdata(L, 1);luaL_argcheck(L, s != NULL, 1, "invalid user data");luaL_checktype(L, -1, LUA_TNUMBER);(*s)->set_age((unsigned)lua_tointeger(L, -1));return 0;
}int lua_print(lua_State* L)
{Student** s = (Student**)lua_touserdata(L, 1);luaL_argcheck(L, s != NULL, 1, "invalid user data");(*s)->print();return 0;
}int luaopen_student_libs(lua_State* L)
{// 創(chuàng)建一張新的表,并把列表的函數(shù)注冊進去luaL_newlib(L, lua_reg_student_funcs);return 1;
}
main.cpp
#include <iostream>
using namespace std;extern "C" {
#include "lua.h"
#include "lualib.h"
#include "lauxlib.h"
}#include "Student.h"
#include "StudentRegFunc.h"static const luaL_Reg lua_reg_libs[] = {{ "base", luaopen_base }, //系統(tǒng)模塊{ "Student", luaopen_student_libs}, //模塊名字Student,注冊函數(shù)luaopen_student_libs{ NULL, NULL }
};int main(int argc, char* argv[])
{if (lua_State* L = luaL_newstate()) {//注冊讓lua使用的庫const luaL_Reg* lua_reg = lua_reg_libs;for (; lua_reg->func; ++lua_reg) {luaL_requiref(L, lua_reg->name, lua_reg->func, 1);lua_pop(L, 1);}//加載腳本,如果出錯,則打印錯誤if (luaL_dofile(L, "lua4.lua")) {cout << lua_tostring(L, -1) << endl;}lua_close(L);}else {cout << "luaL_newstate error !" << endl;}system("pause");return 0;
}
tolua
第二種方式是tolua,也就是tolua++
在cocos2dx中,基本都是用這種方式
//.h
class CMD_Data : public cocos2d::Ref
{
public:CMD_Data(unsigned short nlength);virtual ~CMD_Data();
public:void setMainCmdAndSubCmd(const unsigned short mainCmd, const unsigned short subCmd);unsigned short getMainCmd();unsigned short getSubCmd();
public:static CMD_Data *create(const int nLenth);//...
}//.cppvoid CMD_Data::setMainCmdAndSubCmd(const unsigned short mainCmd, const unsigned short subCmd)
{m_wMainCmd = mainCmd;m_wSubCmd = subCmd;
}CMD_Data * CMD_Data::create(const int nLenth)
{CMD_Data * pData = new(std::nothrow) CMD_Data(nLenth);if (pData){//pData->autorelease();return pData;}CC_SAFE_DELETE(pData);return nullptr;
}unsigned short CMD_Data::getMainCmd()
{return m_wMainCmd;
}unsigned short CMD_Data::getSubCmd()
{return m_wSubCmd;
}
注冊
.h
#pragma once
#include "base/ccConfig.h"
#ifdef __cplusplus
extern "C" {
#endif
#include "tolua++.h"
#ifdef __cplusplus
}
#endif
int register_all_Cmd_Data();
.cpp
int register_all_Cmd_Data()
{auto engine = LuaEngine::getInstance();ScriptEngineManager::getInstance()->setScriptEngine(engine);lua_State* tolua_S = engine->getLuaStack()->getLuaState();tolua_usertype(tolua_S, "CMD_Data");tolua_cclass(tolua_S, "CMD_Data", "CMD_Data", "cc.Node", nullptr);tolua_beginmodule(tolua_S, "CMD_Data");tolua_function(tolua_S, "create", tolua_Cmd_Data_create);tolua_function(tolua_S, "setCmdInfo", tolua_Cmd_Data_setMainCmdAndSubCmd);tolua_function(tolua_S, "getMainCmd", tolua_Cmd_Data_getMainCmd);tolua_function(tolua_S, "getSubCmd", tolua_Cmd_Data_getSubCmd);tolua_function(tolua_S, "getBufferLength", tolua_Cmd_Data_getBufferLength);tolua_function(tolua_S, "getCurIndex", tolua_Cmd_Data_getCurIndex);tolua_function(tolua_S, "setSendMessageLength", tolua_Cmd_Data_setSendMessageLength);tolua_endmodule(tolua_S);std::string typeName = typeid(CMD_Data).name();g_luaType[typeName] = "CMD_Data";g_typeCast["CMD_Data"] = "CMD_Data";return 1;
}int tolua_Cmd_Data_create(lua_State* tolua_S)
{int argc = lua_gettop(tolua_S);CMD_Data *data = nullptr;if (argc == 2){int nLength = lua_tointeger(tolua_S, 2);data = CMD_Data::create(nLength);}else{CCLOG("error CMD_Data create");}int nID = (data) ? data->_ID : -1;int *pLuaID = (data) ? &data->_luaID : nullptr;toluafix_pushusertype_ccobject(tolua_S, nID, pLuaID, (void*)data, "Cmd_Data");return 1;
}int tolua_Cmd_Data_setMainCmdAndSubCmd(lua_State* tolua_S)
{CMD_Data *cobj = (CMD_Data*)tolua_tousertype(tolua_S, 1, nullptr);if (cobj){int argc = lua_gettop(tolua_S);if (argc == 3){unsigned short mainCmd = (unsigned short)lua_tointeger(tolua_S, 2);unsigned short subCmd = (unsigned short)lua_tointeger(tolua_S, 3);cobj->setMainCmdAndSubCmd(mainCmd, subCmd);}}return 0;
}int tolua_Cmd_Data_getMainCmd(lua_State* tolua_S)
{CMD_Data *cobj = (CMD_Data*)tolua_tousertype(tolua_S, 1, nullptr);if (cobj){lua_pushinteger(tolua_S, cobj->getMainCmd());return 1;}return 0;
}int tolua_Cmd_Data_getSubCmd(lua_State* tolua_S)
{CMD_Data *cobj = (CMD_Data*)tolua_tousertype(tolua_S, 1, nullptr);if (cobj){lua_pushinteger(tolua_S, cobj->getSubCmd());return 1;}return 0;
}
cocos2dx 生成工具
方便的是,cocos2dx提供了一套轉(zhuǎn)換的工具。
在cocos2dx引擎目錄下有個tools的目錄,里面有tolua的文件夾。
它里面的大概結(jié)構(gòu)如下
可以看得出來,cocos2dx本身的類都是用這個方法去實現(xiàn)的。
隨便打開一個ini文件
[cocos2dx_ui]
# the prefix to be added to the generated functions. You might or might not use this in your own
# templates
prefix = cocos2dx_ui# create a target namespace (in javascript, this would create some code like the equiv. to `ns = ns || {}`)
# all classes will be embedded in that namespace
target_namespace = ccui# the native namespace in which this module locates, this parameter is used for avoid conflict of the same class name in different modules, as "cocos2d::Label" <-> "cocos2d::ui::Label".
cpp_namespace = cocos2d::uiandroid_headers = -I%(androidndkdir)s/platforms/android-14/arch-arm/usr/include -I%(androidndkdir)s/sources/cxx-stl/gnu-libstdc++/%(gnu_libstdc_version)s/libs/armeabi-v7a/include -I%(androidndkdir)s/sources/cxx-stl/gnu-libstdc++/%(gnu_libstdc_version)s/include
android_flags = -D_SIZE_T_DEFINED_ clang_headers = -I%(clangllvmdir)s/%(clang_lib_version)s/clang/%(clang_version)s/include
clang_flags = -nostdinc -x c++ -std=c++11 -U __SSE__cocos_headers = -I%(cocosdir)s/cocos -I%(cocosdir)s/cocos/editor-support -I%(cocosdir)s/cocos/platform/androidcocos_flags = -DANDROIDcxxgenerator_headers = # extra arguments for clang
extra_arguments = %(android_headers)s %(clang_headers)s %(cxxgenerator_headers)s %(cocos_headers)s %(android_flags)s %(clang_flags)s %(cocos_flags)s %(extra_flags)s # what headers to parse
headers = %(cocosdir)s/cocos/ui/CocosGUI.h# what classes to produce code for. You can use regular expressions here. When testing the regular
# expression, it will be enclosed in "^$", like this: "^Menu*$".
classes = Helper Widget Layout Button CheckBox ImageView Text TextAtlas TextBMFont LoadingBar Slider TextField ScrollView ListView PageView LayoutParameter LinearLayoutParameter RelativeLayoutParameter Rich.* HBox VBox RelativeBox Scale9Sprite EditBox LayoutComponent AbstractCheckButton RadioButton RadioButtonGroup TabControl TabHeader# what should we skip? in the format ClassName::[function function]
# ClassName is a regular expression, but will be used like this: "^ClassName$" functions are also
# regular expressions, they will not be surrounded by "^$". If you want to skip a whole class, just
# add a single "*" as functions. See bellow for several examples. A special class name is "*", which
# will apply to all class names. This is a convenience wildcard to be able to skip similar named
# functions from all classes.skip = *::[^visit$ copyWith.* onEnter.* onExit.* ^description$ getObjectType .*HSV onTouch.* onAcc.* onKey.* onRegisterTouchListener ccTouch.* (g|s)etDelegate],Widget::[addTouchEventListener addClickEventListener addCCSEventListener],LayoutParameter::[(s|g)etMargin],RichText::[setTagDescription removeTagDescription setOpenUrlHandler]rename_functions = rename_classes =# for all class names, should we remove something when registering in the target VM?
remove_prefix = # classes for which there will be no "parent" lookup
classes_have_no_parents = Helper# base classes which will be skipped when their sub-classes found them.
base_classes_to_skip =# classes that create no constructor
# Set is special and we will use a hand-written constructor
abstract_classes = Helper AbstractCheckButton# Determining whether to use script object(js object) to control the lifecycle of native(cpp) object or the other way around. Supported values are 'yes' or 'no'.
script_control_cpp = no
prefix : 輸出的前綴,會連接到tolua類型的函數(shù)名之前,例如 int cocos2dx_ui_xxx(lua_State* tolua_S);
target_namespace : 所有生成的類都屬于這個表下 例如這個里面的 ccui.xxx
cpp_namespace : C++中的命名空間,自動生成的代碼中會加上這個命名空間
android_headers : 這是安卓編譯的一些指令,不需要修改,照抄就行
android_flags : 這是安卓編譯的一些指令,不需要修改,照抄就行
clang_headers : 這是Clang的編譯指令,不需要修改,照抄就行
cocos_flags : 這是Clang的編譯指令,不需要修改,照抄就行
cocos_headers: cocos的頭文件搜索目錄
cocos_flags:照抄
cxxgenerator_headers : 不管
extra_arguments : 所有文件的搜索路徑
headers:這是需要解析的頭文件 會從這個文件中識別所有include的頭文件,并解析其中的類, 可以填多個文件 比如自己的文件的需要引用的頭文件
classes:需要生成哪些類的接口,這里支持正則表達式
skip:跳過哪些類和函數(shù),支持正則表達式,可以借鑒cocos的配置文件
rename_functions:重命名函數(shù)
rename_classes:重命名類
abstract_classes:哪些類沒有創(chuàng)建構(gòu)造函數(shù),需要手動重寫構(gòu)造函數(shù)
script_control_cpp:不管,一般都是no
可以生成自己的一個配置文件。
然后看下同樣目錄下的genbindings.py文件
需要將自己的ini文件填入進去。
然后運行這個python文件,便會自動生成。
一般如下
手寫調(diào)用
有人會說,為啥cocos里面還有類似
首先,工具腳本不是萬能的,有些無法導(dǎo)出,例如Lambda表達式,例如某些回調(diào)函數(shù)。
void GameNetWorkManager::resumSocketByIp(const int socketMark, const std::string &serverIp, const int serverPort, const std::function<void(bool)> &callback)
{callback(m_socketManage->resumSocket(socketMark,serverIp,serverPort));
}
比如這個方法。
無法生成,我們就需要手寫
int tolua_GameNetWorkManager_resumSocket(lua_State* tolua_S)
{int argc = 0;GameNetWorkManager* cobj = nullptr;bool ok = true;#if COCOS2D_DEBUG >= 1tolua_Error tolua_err;
#endif#if COCOS2D_DEBUG >= 1if (!tolua_isusertype(tolua_S, 1, "GameNetWorkManager", 0, &tolua_err)) goto tolua_lerror;
#endifcobj = (GameNetWorkManager*)tolua_tousertype(tolua_S, 1, 0);#if COCOS2D_DEBUG >= 1if (!cobj){tolua_error(tolua_S, "invalid 'cobj' in function 'tolua_GameNetWorkManager_resumSocket'", nullptr);return 0;}
#endifargc = lua_gettop(tolua_S) - 1;if (argc == 2){int arg1;ok &= luaval_to_int32(tolua_S, 2, (int *)&arg1, "GameNetWorkManager:resumSocket");
#if COCOS2D_DEBUG >= 1if (!toluafix_isfunction(tolua_S, 3, "LUA_FUNCTION", 0, &tolua_err)){goto tolua_lerror;}
#endifint handler = (toluafix_ref_function(tolua_S, 3, 0));if (!ok){tolua_error(tolua_S, "invalid arguments in function 'tolua_GameNetWorkManager_resumSocket'", nullptr);return 0;}cobj->resumSocket(arg1,[=](bool resum){LuaStack* stack = LuaEngine::getInstance()->getLuaStack();stack->pushBoolean(resum);stack->executeFunctionByHandler(handler, 1);stack->clean();return 0;});ScriptHandlerMgr::getInstance()->addCustomHandler((void*)cobj, handler);lua_settop(tolua_S, 1);return 1;}else if (argc == 4){int arg1;std::string arg2;int arg3;ok &= luaval_to_int32(tolua_S, 2, (int *)&arg1, "GameNetWorkManager:resumSocket");ok &= luaval_to_std_string(tolua_S, 3, &arg2, "GameNetWorkManager:resumSocket");ok &= luaval_to_int32(tolua_S, 4, (int *)&arg3, "GameNetWorkManager:resumSocket");
#if COCOS2D_DEBUG >= 1if (!toluafix_isfunction(tolua_S, 5, "LUA_FUNCTION", 0, &tolua_err)){goto tolua_lerror;}
#endifint handler = (toluafix_ref_function(tolua_S, 5, 0));if (!ok){tolua_error(tolua_S, "invalid arguments in function 'tolua_GameNetWorkManager_resumSocket'", nullptr);return 0;}cobj->resumSocketByIp(arg1, arg2, arg3, [=](bool resum){LuaStack* stack = LuaEngine::getInstance()->getLuaStack();stack->pushBoolean(resum);stack->executeFunctionByHandler(handler, 1);stack->clean();return 0;});ScriptHandlerMgr::getInstance()->addCustomHandler((void*)cobj, handler);lua_settop(tolua_S, 1);return 1;}return 0;
#if COCOS2D_DEBUG >= 1tolua_lerror:tolua_error(tolua_S, "#ferror in function 'tolua_GameNetWorkManager_resumSocket'.", &tolua_err);
#endifreturn 0;
}
最后
如果需要深入了解Lua,強烈建議閱讀《lua設(shè)計與實現(xiàn)》。