青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

posts - 12,  comments - 6,  trackbacks - 0
這幾天搞了一個套lua與C++相互調用的框架,是之前單位項目中提取出來的,比較成型,在已上線的端游中使用,使用第三方庫tolua。
這里使用lua 5.1.5、tolua++ 1.0.92、boost 1.68.0、zlib。
開發環境:vs 2017 、lua調試插件 BabeLua。
lua-5.1.5.zip
toluapp-master.zip
BabeLua-For-2017-V3.2.2.0.zip
先貼圖,介紹一下工程目錄。

lua項目;lua代碼 —— 編譯lua.lib
tolua項目:tolua++代碼 —— 編譯 tolua.lib 和 tolua.exe
LuaProject項目:lua和c++相互交互工程。
LuaScript項目:插件BabeLua 創建,lua腳本編寫、調試使用。
lua項目 (vs2017中搭建lua5.1)
創建靜態鏈接庫的空工程、添加lua代碼文件。
修改工程配置如圖(竊取兩圖)
編輯生成 lua.lib
tolua項目
創建空工程、添加tolua代碼文件。
這里注意的是 tolua\src 目錄下有 bin 和 lib 路徑代碼。分別控制編譯 exe 和 lib文件。
我這里為了方便,將bin和lib代碼同時加入tolua工程。
然后控制 配置類型來生成 應用程序(.exe) 和 靜態庫(.lib)
修改工程配置
附加包含目錄:..\include;..\..\lua\src;
附加依賴項:lua.lib
預處理器定義:_CRT_SECURE_NO_WARNINGS
編譯生成 tolua.lib 和 tolua.exe
LuaProject項目
看一下工程代碼如圖
還挺多,不要慌,這里主要實現的讀取的文件可以是zip文件(壓縮以后的lua文件)。
主要類也就是 ScriptVmArgs類 和 ScriptVM類 來實現的 lua與c++ 的交互。
這里貼出代碼如下:


ScriptVmArgs.h
/*************************************************
vic.MINg        2018/09/18
***********************************************
*/

#pragma once
#include <string>
//  "boost/config/user.hpp" 取消 BOOST_ALL_NO_LIB 注釋
#define  BOOST_ALL_NO_LIB
#include "boost/tuple/tuple.hpp"



struct lua_State;

class ScriptVmArgs
{
    friend class ScriptVM;

    class Args
    {
    public:
        virtual int Size()const = 0;
    };

    class ArgsInput
        :public Args
    {
    public:
        virtual void Push(lua_State& lua)const = 0;
    };

    class ArgsOutput
        :public Args
    {
    public:
        virtual void Pop(lua_State& lua) = 0;
    };

    template<typename T>
    class ArgsInputImp
        :public ArgsInput
    {
    public:
        ArgsInputImp(const T& args) :m_args(args) {}
        virtual void Push(lua_State& lua)const
        {
            Push(lua, m_args);
        }
        virtual int Size()const
        {
            return boost::tuples::length<T>::value;
        }

    private:
        static void Push(lua_State& lua, const boost::tuples::null_type& args) {}
        template<typename Head, typename Tail>
        static void Push(lua_State& lua, const boost::tuples::cons<Head, Tail>& args)
        {
            // 這里巧妙的使用了 boost::tuple 的 args.get_head() 和  args.get_tail() 方法,兩行代碼實現了 自身的遞歸調用。
            DoPush(lua, args.get_head());
            Push(lua, args.get_tail());
        }

        const T& m_args;
    };

    template<typename T>
    class ArgsOutputImp
        :public ArgsOutput
    {
    public:
        ArgsOutputImp(T& args) :m_args(args) {}
        virtual void Pop(lua_State& lua)
        {
            Pop(lua, m_args, 0);
        }
        virtual int Size()const
        {
            return boost::tuples::length<T>::value;
        }

    private:
        static void Pop(lua_State& lua, const boost::tuples::null_type& args, int idx) {}
        template<typename Head, typename Tail>
        static void Pop(lua_State& lua, const boost::tuples::cons<Head, Tail>& args, int idx)
        {
            //if (args.get_head())
            DoPop(lua, args.get_head(), idx - boost::tuples::length<T>::value);
            Pop(lua, args.get_tail(), idx + 1);
        }

        T& m_args;
    };

    static void DoPush(lua_State& lua, const char* pcArg);
    static void DoPush(lua_State& lua, bool bArg);
    static void DoPush(lua_State& lua, float fArg);
    static void DoPush(lua_State& lua, int nArg);
    static void DoPush(lua_State& lua, unsigned uArg);
    static void DoPop(lua_State& lua, std::string& sArg, int idx);
    static void DoPop(lua_State& lua, bool& bArg, int idx);
    static void DoPop(lua_State& lua, float& fArg, int idx);
    static void DoPop(lua_State& lua, int& nArg, int idx);
    static void DoPop(lua_State& lua, unsigned& uArg, int idx);
};

ScriptVM.h
/*************************************************
vic.MINg        2018/09/18
***********************************************
*/

#pragma once

#include <vector>
#include <map>
#include <string>

#include "ScriptVmArgs.h"

struct lua_State;

struct lua_Debug;
typedef void(*lua_Hook) (lua_State *L, lua_Debug *ar);
typedef int(*lua_CFunction) (lua_State *L);


class ScriptVM
{
public:

    ScriptVM(void);
    virtual ~ScriptVM(void);

    bool    Init(void);
    void    Destroy(void);
    void    ExecuteScriptFile(const char * sScriptFileName, bool bForceReload = falsebool bAssertOnError = true);
    void    ExecuteScript(const char * sScript, bool bAssertOnError = true);
    bool    ExecuteScriptFunc(const std::vector<const char *>& modules, const char * func, bool bAllowNonexist, const char * sig = "", );
    template<typename InTuple, typename OutTuple>
    void ExecuteFunc(const char* func, bool bAllowNonexist, const InTuple& inTuple, OutTuple& outTuple, const std::vector<const char*>* pModuls = 0);
    void    ExposeGlobalUserdata(void * va, const char * name, const char * type);
    void *    GetGlobalUserdata(const char * name, const char * verify_type = NULL);
    void *    GetUserdata(const std::vector<const char *>& modules, const char * name, const char * verify_type = NULL);
    double    GetGlobalNumber(const char * name);
    // 是否存在某變量
    bool    ExistVariable(const std::vector<const char *>& modules, const char * name);

    // 得到某個Lua變量
    bool    GetNumber(const std::vector<const char *>& modules, const char * name, double& dValue);

    //void    OnEndofUpdate(); //call back function on end of game update
    void *    CreateObjectByTypeName(const char * sTypeName);//由tolua注冊過的類名創建對象
    double    GetGlobalTableNumber(const char *sTableName, const char* key);//Wang Hongliang:
    double ComputingFormula(const char* sFormula, const std::map<std::stringdouble>& kParams);// 計算數學公式
    lua_State * GetLuaState() { return m_pLua; }

    // 設置腳本鉤子,只在調試時可用。 
    void    SetHook(lua_Hook func, int nMask, int nCount);
    void    RegistGlobalFunction(const char* sFunctionName, lua_CFunction pFunction);


    // 這里通過 自己寫的io流來處理的 文件讀寫,把文件內容讀到了buff 中 
    
// 我這里支撐壓縮文件的讀寫,你可以自己實現一下文件讀寫方法 重寫該方法即可
    static bool LoadFileToBuffer(const char * filename, unsigned char *& buff, int& size, bool bAssertOnError);
    std::string GetScriptReturnString(std::string sScript);
    
    
    //static sigslot::signal1<const char*> LuaPrinted;

    
// 獲取腳本當前所占用的內存
    int        GetConsumeMemoryCount();

    // 打印所有全局變量
    void    PrintGlobalVariables();

protected:
    void DoExecuteFunc(const char* func, bool bAllowNonexist, const  ScriptVmArgs::ArgsInput& input, ScriptVmArgs::ArgsOutput& output, const std::vector<const char*>* pModuls);

    lua_State* m_pLua;
};

template<typename InTuple, typename OutTuple>
inline void ScriptVM::ExecuteFunc(const char* func, bool bAllowNonexist, const InTuple& inTuple, OutTuple& outTuple, const std::vector<const char*>* pModuls /* = 0 */)
{
    // Pass as ArgsInput and ArgsOutput, not ArgsInputImp and ArgsOutputImp. So that the body of DoExecuteFunc() can be placed in .cpp rather than .h.
    DoExecuteFunc(
        func,
        bAllowNonexist,
        ScriptVmArgs::ArgsInputImp<InTuple>(inTuple),
        (ScriptVmArgs::ArgsOutput&)ScriptVmArgs::ArgsOutputImp<OutTuple>(outTuple),            // 為啥子 必須強制轉換一下 ScriptVmArgs::ArgsOutput& 上面的代碼就不用轉換,沒整明白
        pModuls
    );
}

ScriptVM.cpp
#include "ScriptVM.h"
#include "IOServer.h"
#include "FileStream.h"

extern "C"
{
    #include "lua.h"  
    #include "lualib.h"  
    #include "lauxlib.h"  
}
#include "tolua++.h"

#include<stdio.h>
#include <assert.h>
#include <sstream>

#define DEBUG_STACK 0

//end of tolua bind declare
extern void tolua_open_binding(lua_State * pLua);
static void stackDump(lua_State *pLua);

//sigslot::signal1<const char*> ScriptVM::LuaPrinted;

//error_msg handling function
static void error_msg(bool bUseAssert, const char * pacFmt, )
{
    //#if defined(_DEBUG)
    char acTemp[2048];

    va_list args;
    va_start(args, pacFmt);
    vsprintf_s(acTemp, pacFmt, args);
    va_end(args);
    if (bUseAssert)
    {
        assert( acTemp);
    }
    //#endif
}

void report_last_error(lua_State *pLua, bool bUseAssert)
{
    lua_getglobal(pLua, "_ALERT");
    error_msg(bUseAssert, "%s\n", lua_tostring(pLua, -2));
    error_msg(bUseAssert, "%s\n", lua_tostring(pLua, -1));
    lua_pop(pLua, 2);  /* remove error_msg message and _ALERT */
}


std::string & std_string_format(std::string & _str, const char * _Format, ) {
    std::string tmp;

    va_list marker = NULL;
    va_start(marker, _Format);

    size_t num_of_chars = _vscprintf(_Format, marker);

    if (num_of_chars > tmp.capacity()) {
        tmp.resize(num_of_chars + 1);
    }

    vsprintf_s((char *)tmp.data(), tmp.capacity(), _Format, marker);

    va_end(marker);

    _str = tmp.c_str();
    return _str;
}


ScriptVM::ScriptVM(void)
{
}

ScriptVM::~ScriptVM(void)
{
}

static int PrintStringList(lua_State * pLua) {

    int n = lua_gettop(pLua);  /* number of arguments */
    int i;
    lua_getglobal(pLua, "tostring");
    std::string out;
    for (i = 1; i <= n; i++) {
        const char *s;
        lua_pushvalue(pLua, -1);  /* function to be called */
        lua_pushvalue(pLua, i);   /* value to print */
        lua_call(pLua, 1, 1);
        s = lua_tostring(pLua, -1);  /* get result */
        if (s == NULL)
            return luaL_error(pLua, "`tostring' must return a string to `print'");
        if (i > 1)
        {
            out += "\t";
            out += s;
        }
        else
            out += s;

        lua_pop(pLua, 1);  /* pop result */
    }
    out += "\n";

    return 0;
}

bool ScriptVM::Init(void)
{
    m_pLua = luaL_newstate();

    lua_cpcall(m_pLua, luaopen_base, 0);
    lua_cpcall(m_pLua, luaopen_io, 0);
    lua_cpcall(m_pLua, luaopen_string, 0);
    lua_cpcall(m_pLua, luaopen_table, 0);
    lua_cpcall(m_pLua, luaopen_math, 0);
    lua_cpcall(m_pLua, luaopen_debug, 0);
    lua_cpcall(m_pLua, luaopen_os, 0);
    lua_cpcall(m_pLua, luaopen_package, 0);

    //luaopen_base(m_pLua);
    
//luaopen_io(m_pLua);
    
//luaopen_table(m_pLua);
    
//luaopen_math(m_pLua);
    
//luaopen_string(m_pLua);
    
//luaopen_debug(m_pLua);

    
//tolua_open_binding(m_pLua);

    
//lua_setgcthreshold(m_pLua, 200); //200k garbage collection threshold
    lua_register(m_pLua, "print", PrintStringList);
    //lua_register(m_pLua, "dofile", OverrideDofile);

    return true;
}

void ScriptVM::Destroy(void)
{
    lua_close(m_pLua);
}

void ScriptVM::ExecuteScriptFile(const char * sScriptName, bool bForceReload /* = false*/bool bAssertOnError /*= true*/)
{
    int nSize1 = lua_gettop(m_pLua);
    //get chunk name as modified script name
    std::string sChunkName(sScriptName);
    for (unsigned int i = 0; i < sChunkName.length(); i++)
    {
        if (sChunkName[i] == '/' || sChunkName[i] == '.')
            sChunkName[i] = '_';
    }

    //get the chunk global
    lua_getglobal(m_pLua, sChunkName.c_str());
    if (bForceReload || !lua_isfunction(m_pLua, -1))//if force reload or not found
    {
        //load it first
        unsigned char * pBuff;
        int nSize;
        if (LoadFileToBuffer(sScriptName, pBuff, nSize, bAssertOnError))
        {
            luaL_loadbuffer(m_pLua, (char *)pBuff, nSize, sScriptName);

            delete[] pBuff;

//            luaL_loadfile(m_pLua, sScriptName);
            lua_setglobal(m_pLua, sChunkName.c_str());
            lua_getglobal(m_pLua, sChunkName.c_str());
        }
        else
            goto failed;
    }

    if (lua_pcall(m_pLua, 0, 0, 0) != 0)
    {
        error_msg(bAssertOnError, "error executing script file %s: ", sScriptName);
        report_last_error(m_pLua, bAssertOnError);
    }

failed:
    lua_settop(m_pLua, nSize1);
}

void ScriptVM::ExecuteScript(const char * sScript, bool bAssertOnError)
{
    int status = luaL_loadbuffer(m_pLua, sScript, strlen(sScript), sScript);
    if (status)
    {
        report_last_error(m_pLua, bAssertOnError);
    }
    else
    {
        status = lua_pcall(m_pLua, 0, LUA_MULTRET, 0);  /* call main */
        if (status)
            report_last_error(m_pLua, bAssertOnError);
    }
}

/*
*    Execute Script Function func in the script. copy/pasted from the book "programming in LUA"
*/
bool ScriptVM::ExecuteScriptFunc(const std::vector<const char *>&modules, const char * func, bool bAllowNonexist, const char * sig, )
{
    bool bIsSuccess = false;

    //PROFILE("ExecuteScriptFunc");
    int nSize1 = lua_gettop(m_pLua);

    //debug
#if DEBUG_STACK
    printf("debug lua: stack size before ExecuteScriptFunc = %d\n", nSize1);
#endif

    va_list    vl;
    int    narg, nres;    /* number of arguments and results */
    va_start(vl, sig);

    //get the actual function
    if (modules.empty()) //func is global
    {
        lua_getglobal(m_pLua, func);
        if (!lua_isfunction(m_pLua, -1))
        {
            if (!bAllowNonexist)
                error_msg(true, "ExecuteScriptFunc: Invalid function name: %s\n", func);
            goto failed;
        }
    }
    else
    {
        //trace down the modules
        std::vector<const char *>::const_iterator it = modules.begin();
        //get the global module name or the actual function name if there is no module
        lua_getglobal(m_pLua, *it);
        if (!lua_istable(m_pLua, -1))
        {
            if (!bAllowNonexist)
                error_msg(true, "ExecuteScriptFunc: Invalid table name: %s\n", *it);
            goto failed;
        }

        for (++it; it != modules.end(); ++it)
        {
            lua_pushstring(m_pLua, *it);
            lua_gettable(m_pLua, -2);
            if (!lua_istable(m_pLua, -1))
            {
                if (!bAllowNonexist)
                    error_msg(true, "ExecuteScriptFunc: Invalid table name: %s\n", *it);
                goto failed;
            }
        }
        //get the func
        lua_pushstring(m_pLua, func);
        lua_gettable(m_pLua, -2);
        if (!lua_isfunction(m_pLua, -1))
        {
            if (!bAllowNonexist)
                error_msg(true, "ExecuteScriptFunc: Invalid function name: %s\n", func);
            goto failed;
        }
    }

    /* push    arguments */
    narg = 0;
    while (*sig) { /* push arguments    */
        switch (*sig++) {
        case 'd': /* double    argument */
        case 'f': /* float    argument */    // NieXu: Treat float as double, same as printf()
            lua_pushnumber(m_pLua, va_arg(vl, double));
            break;
        case 'i': /* int argument */
            lua_pushnumber(m_pLua, va_arg(vl, int));
            break;
        case 's': /* string    argument */
            lua_pushstring(m_pLua, va_arg(vl, char *));
            break;
        case 'b': /* boolean argument */
            lua_pushboolean(m_pLua, va_arg(vl, bool));
            break;
        case 'u': /* light user data */
            lua_pushlightuserdata(m_pLua, va_arg(vl, void *));
            break;
        case 't': /* type user data */
        {
            void* pData = va_arg(vl, void *);
            const char* sType = va_arg(vl, const char*);
            tolua_pushusertype(m_pLua, pData, sType);
            break;
        }

        case '>':
            goto endwhile;
        default:
            error_msg(true, "invalid option (%c)\n", *(sig - 1));
            goto failed;
        }
        narg++;
        luaL_checkstack(m_pLua, 1, "too many    arguments");
    }endwhile:
    /* do the call */
    nres = strlen(sig);    /* number of expected results */
    if (lua_pcall(m_pLua, narg, nres, 0) != 0) /* do    the    call */
    {
        report_last_error(m_pLua, true);
        goto failed;
    }
    /* retrieve    results    */
    nres = -nres; /* stack index of    first result */
    while (*sig)
    { /* get results */
        switch (*sig++)
        {
        case 'd': /* double    result */
            if (!lua_isnumber(m_pLua, nres))
                error_msg(true, "wrong    result type,function name: %s\n", func);
            *va_arg(vl, double *) = lua_tonumber(m_pLua, nres);
            break;
        case 'f': /* float    result */
            if (!lua_isnumber(m_pLua, nres))
                error_msg(true, "wrong    result type,function name: %s\n", func);
            *va_arg(vl, float*) = (float)lua_tonumber(m_pLua, nres);
            break;
        case 'i': /* int result    */
            if (!lua_isnumber(m_pLua, nres))
                error_msg(true, "wrong    result type,function name: %s\n", func);
            *va_arg(vl, int    *) = (int)lua_tonumber(m_pLua, nres);
            break;
        case 's': /* string    result */
            if (!lua_isstring(m_pLua, nres))
                error_msg(true, "wrong    result type,function name: %s\n", func);
            *va_arg(vl, std::string*) = lua_tostring(m_pLua, nres);
            break;
        case 'b': /* boolean argument */
            if (!lua_isboolean(m_pLua, nres))
                error_msg(true, "wrong    result type,function name: %s\n", func);
            *va_arg(vl, bool *) = (0 != lua_toboolean(m_pLua, nres));
            break;
        case 'u': /* light user data */
            if (!lua_isuserdata(m_pLua, nres))
                error_msg(true, "wrong    result type,function name: %s\n", func);
            *va_arg(vl, void **) = lua_touserdata(m_pLua, nres);
            break;
        default:
            error_msg(true, "invalid option (%c)\n", *(sig - 1));
        }
        nres++;
    }

    bIsSuccess = true;
failed:
    va_end(vl);
    //clear the stack
    lua_settop(m_pLua, nSize1);

#if DEBUG_STACK
    //debug
    int nSize2 = lua_gettop(m_pLua);
    printf("debug lua: stack size after ExecuteScriptFunc = %d\n", nSize2);
    if (nSize1 != nSize2)
        stackDump(m_pLua);
#endif

    return bIsSuccess;
}

void ScriptVM::ExposeGlobalUserdata(void * va, const char * name, const char * type)
{
    int nSize1 = lua_gettop(m_pLua);
#if DEBUG_STACK
    //debug
    printf("debug lua: stack size before ExposeGlobalUserdata = %d\n", nSize1);
#endif

    tolua_pushusertype(m_pLua, va, type);
    lua_setglobal(m_pLua, name);

    //clear the stack
    lua_settop(m_pLua, nSize1);

#if DEBUG_STACK
    //debug
    int nSize2 = lua_gettop(m_pLua);
    printf("debug lua: stack size after ExposeGlobalUserdata = %d\n", nSize2);
    if (nSize1 != nSize2)
        stackDump(m_pLua);
#endif
}

void * ScriptVM::GetGlobalUserdata(const char * name, const char * verify_type /*= NULL*/)
{
    void * pRet = NULL;
    int nSize1 = lua_gettop(m_pLua);
    int nSize2 = 0;
#if DEBUG_STACK
    //debug
    printf("debug lua: stack size before GetGlobalUserdata = %d\n", nSize1);
#endif

    lua_getglobal(m_pLua, name);

    //verify type
    if (verify_type)
    {
        tolua_Error tolua_err;
        if (
            !tolua_isusertype(m_pLua, 1, verify_type, 0, &tolua_err) ||
            !tolua_isnoobj(m_pLua, 2, &tolua_err)
            )
        {
            tolua_error(m_pLua, "#ferror in function 'ScriptVM::GetGlobalUserdata'.", &tolua_err);
            goto failed;
        }
    }
    
         pRet = tolua_tousertype(m_pLua, -1, 0);
        //clear the stack
        lua_settop(m_pLua, nSize1);




#if DEBUG_STACK
    //debug
    nSize2 = lua_gettop(m_pLua);
    printf("debug lua: stack size after GetGlobalUserdata = %d\n", nSize2);
    if (nSize1 != nSize2)
        stackDump(m_pLua);
#endif
    return pRet;

failed:
        //lua_settop(m_pLua,0);
        lua_settop(m_pLua, nSize1);
        return NULL;

}

double ScriptVM::GetGlobalNumber(const char * name)
{
    int nSize1 = lua_gettop(m_pLua);
#if DEBUG_STACK
    //debug
    printf("debug lua: stack size before GetGlobalUserdata = %d\n", nSize1);
#endif

    lua_getglobal(m_pLua, name);

    double ret = tolua_tonumber(m_pLua, -1, 0);
    //clear the stack
    lua_settop(m_pLua, nSize1);

#if DEBUG_STACK
    //debug
    int nSize2 = lua_gettop(m_pLua);
    printf("debug lua: stack size after GetGlobalUserdata = %d\n", nSize2);
    if (nSize1 != nSize2)
        stackDump(m_pLua);
#endif
    return ret;
}

void * ScriptVM::GetUserdata(const std::vector<const char *>& modules, const char * name, const char * verify_type/*= NULL*/)
{
    void * pRet = NULL;
    int nSize1 = lua_gettop(m_pLua);
    int nSize2 = 0;
#if DEBUG_STACK
    printf("debug lua: stack size before GetUserdata = %d\n", nSize1);
#endif
    if (modules.empty()) //userdata is global
    {
        lua_getglobal(m_pLua, name);
    }
    else
    {
        //trace down the modules
        std::vector<const char *>::const_iterator it = modules.begin();
        //get the global module name or the actual function name if there is no module
        lua_getglobal(m_pLua, *it);
        if (!lua_istable(m_pLua, -1))
        {
            error_msg(true, "GetUserdata: Invalid table name: %s\n", *it);
            goto failed;
        }

        for (++it; it != modules.end(); ++it)
        {
            lua_pushstring(m_pLua, *it);
            lua_gettable(m_pLua, -2);
            if (!lua_istable(m_pLua, -1))
            {
                std::vector<const char *>::const_iterator itMsg = modules.begin();
                std::string sMsg;
                for (; itMsg <= it; ++itMsg)
                {
                    sMsg.append(*itMsg);
                    if (itMsg != it)
                    {
                        sMsg.append(".");
                    }
                }
                error_msg(true, "GetUserdata: Invalid table name: %s\n", sMsg.c_str());
                goto failed;
            }
        }
        //get the data
        lua_pushstring(m_pLua, name);
        lua_gettable(m_pLua, -2);
    }

    //verify type
    
//if(verify_type)
    
//{
    
//    tolua_Error tolua_err;
    
//    if (
    
//        !tolua_isusertype(m_pLua,1,verify_type,0,&tolua_err) ||
    
//        !tolua_isnoobj(m_pLua,2,&tolua_err)
    
//        )
    
//    {
    
//        error_msg(m_pLua,"#ferror in function 'ScriptVM:GetUserdata: %s\n", name);
    
//        goto failed;
    
//    }
    
//}

    pRet = tolua_tousertype(m_pLua, -1, 0);
    //clear the stack
    lua_settop(m_pLua, nSize1);

#if DEBUG_STACK
    //debug
    nSize2 = lua_gettop(m_pLua);
    printf("debug lua: stack size after GetUserdata = %d\n", nSize2);
    if (nSize1 != nSize2)
        stackDump(m_pLua);
#endif
    return pRet;

failed:
    lua_settop(m_pLua, nSize1);
    return NULL;
}

static void stackDump(lua_State *m_pLua) {
    int i;
    int top = lua_gettop(m_pLua);
    for (i = 1; i <= top; i++) { /* repeat for each level */
        int t = lua_type(m_pLua, i);
        switch (t) {
        case LUA_TSTRING: /* strings */
            printf("`%s'", lua_tostring(m_pLua, i));
            break;
        case LUA_TBOOLEAN: /* booleans */
            printf(lua_toboolean(m_pLua, i) ? "true" : "false");
            break;
        case LUA_TNUMBER: /* numbers */
            printf("%g", lua_tonumber(m_pLua, i));
            break;
        default/* other values */
            printf("%s", lua_typename(m_pLua, t));
            break;
        }
        printf(" "); /* put a separator */
    }
    printf("\n"); /* end the listing */
}

bool ScriptVM::LoadFileToBuffer(const char * filename, unsigned char *& buff, int& size, bool bAssertOnError)
{
    IO::Stream* pStream = IO::IOServer::Instance()->CreateReadStream(filename);
    if (pStream != NULL && pStream->Open())
    {
        size = pStream->GetSize();
        if (size == 0)
        {
            std::string sMsg;
            sMsg.append(filename).append("以上文件中無內容!");
            assert( sMsg.c_str());
        }

        buff = new unsigned char[size];
        pStream->Read(buff, size);

        pStream->Close();

        IO::IOServer::Instance()->ReleaseStream(pStream);

        return true;
    }
    else
    {
        std::string sMsg;
        sMsg.append("[").append(filename).append("]腳本文件不存在!");
        assert( sMsg.c_str());

        if (NULL != pStream)
        {
            IO::IOServer::Instance()->ReleaseStream(pStream);
        }
        return false;
    }
}

//由tolua注冊過的類名創建對象
void *    ScriptVM::CreateObjectByTypeName(const char * sTypeName)
{
    //處理lua腳本
    int nSize = (int)strlen(sTypeName) + 20;
    unsigned char* buffer = new unsigned char[nSize];
    sprintf_s((char*)buffer, nSize, "pMyCreatedObj=%s:new()", sTypeName);

    //執行腳本
    ExecuteScript((char*)buffer);

    void* ret = GetGlobalUserdata("pMyCreatedObj");

    return ret;
}

//獲得全局表中常量
double ScriptVM::GetGlobalTableNumber(const char *sTableName, const char* key)
{
    double ret = 0;
    int nSize1 = lua_gettop(m_pLua);
    int nSize2 = 0;
#if DEBUG_STACK
    //debug
    printf("debug lua: stack size before GetGlobalUserdata = %d\n", nSize1);
#endif
    lua_getglobal(m_pLua, sTableName);
    if (!lua_istable(m_pLua, -1))
    {
        error_msg(true, "GetGlobalTableNumber: %s isn't a Lua Table.", sTableName);
        goto failed;
    }

    lua_pushstring(m_pLua, key);
    lua_gettable(m_pLua, -2);
    if (!lua_isnumber(m_pLua, -1))
    {
        error_msg(true, "GetGlobalTableNumber: %s isn't a number.", key);
        goto failed;
    }
    ret = lua_tonumber(m_pLua, -1);
    lua_settop(m_pLua, nSize1);
#if DEBUG_STACK
    //debug
    nSize2 = lua_gettop(m_pLua);
    printf("debug lua: stack size after GetUserdata = %d\n", nSize2);
    if (nSize1 != nSize2)
        stackDump(m_pLua);
#endif

    return ret;

failed:
    lua_settop(m_pLua, nSize1);
    return 0;
}

void ScriptVM::SetHook(lua_Hook func, int nMask, int nCount)
{
    if (!m_pLua)
        return;

    //lua_sethook(m_pLua, func, nMask, nCount);
}

bool ScriptVM::ExistVariable(const std::vector<const char *>& modules, const char * name)
{
    int nSize1 = lua_gettop(m_pLua);

    if (modules.empty()) //userdata is global
    {
        lua_getglobal(m_pLua, name);
    }
    else
    {
        //trace down the modules
        std::vector<const char *>::const_iterator it = modules.begin();
        //get the global module name or the actual function name if there is no module
        lua_getglobal(m_pLua, *it);
        if (!lua_istable(m_pLua, -1))
        {
            error_msg(true, "GetUserdata: Invalid table name: %s\n", *it);
            goto failed;
        }

        for (++it; it != modules.end(); ++it)
        {
            lua_pushstring(m_pLua, *it);
            lua_gettable(m_pLua, -2);
            if (!lua_istable(m_pLua, -1))
            {
                error_msg(true, "GetUserdata: Invalid table name: %s\n", *it);
                goto failed;
            }
        }
        //get the data
        lua_pushstring(m_pLua, name);
        lua_gettable(m_pLua, -2);
    }

    if (lua_isnil(m_pLua, -1))
    {
        goto failed;
    }
    else
    {
        goto success;
    }

failed:
    lua_settop(m_pLua, nSize1);
    return false;

success:
    lua_settop(m_pLua, nSize1);
    return true;
}

// 替換字符串
void string_replace(std::string &strBig, const std::string &strsrc, const std::string &strdst)
{
    std::string::size_type pos = 0;
    std::string::size_type srclen = strsrc.size();
    std::string::size_type dstlen = strdst.size();

    while ((pos = strBig.find(strsrc, pos)) != std::string::npos)
    {
        strBig.replace(pos, srclen, strdst);
        pos += dstlen;
    }
}

double ScriptVM::ComputingFormula(const char* sFormula, const std::map<std::stringdouble>& kParams)
{
    std::string sRealFormula = sFormula;
    if (sRealFormula == "")
    {
        assert(false && "公式錯誤");
        return 0.0;
    }

    std::string sParamValue = "0";
    std::stringstream kStrStream;

    // 替換參數
    for (std::map<std::stringdouble>::const_iterator it(kParams.begin()); it != kParams.end(); it++)
    {// 得到公式
     
//         kStrStream<<it->second;    
     
//         sParamValue = kStrStream.str();
        sParamValue = std_string_format(sParamValue, "%f", it->second);
        string_replace(sRealFormula, it->first, sParamValue);

        /*
        // 支持在公式中包含的腳本函數調用可以有字符串參數,避免以當前屬性名為字符串的參數被屬性值替換 [2/18/2011 shuaiwang]
        if (sRealFormula.find('\'') != 0xffffffff)
        {
            std::string sProParam = std::string("\'").append(it->first).append("\'");
            sRealFormula.replace(sProParam, "????");
            sRealFormula.replace(it->first, sParamValue);
            sProParam = std::string("\"").append(it->first).append("\"");
            sRealFormula.replace("????", sProParam);
        }
        else
        {
            sRealFormula.replace(it->first, sParamValue);
        }
        
*/
        
//sRealFormula.Replace(it->first, sParamValue);
    }

    std::string sReturn = "return ";

    if (sRealFormula.find(sReturn) == std::string::npos)
    {
        sRealFormula = sReturn.append(sRealFormula);
    }

    /*std::stringstream kFunStream;

    kFunStream<<"computing_formula_teamfunction = function()\n"
    << sRealFormula << "\n"
    << "end";
*/

    std::string sTempFunction = std::string("computing_formula_teamfunction = function()\n").append(sRealFormula).append("\nend")/*kFunStream.str()*/;

    ExecuteScript(sTempFunction.c_str(), true);

    std::vector<const char *> modules;
    double dValue = 0.0;
    if (ExecuteScriptFunc(modules, "computing_formula_teamfunction", false, ">d", &dValue) == false)
    {
        //_logError2("computing_formula_teamfunction這個問題的來源是:", sFormula << ",請在數據表中修改相應公式!");
    }

    ExecuteScript("computing_formula_teamfunction = nil", true);

    return dValue;
}

std::string ScriptVM::GetScriptReturnString(std::string sScript)
{
    std::string sReturn = "return ";

    if (sScript.find(sReturn) == 0xffffffff)
    {
        sScript = sReturn.append("\"").append(sScript).append("\"");
    }

    std::string sTempFunction = std::string("string_function = function()\n").append(sScript).append("\nend");
    ExecuteScript(sTempFunction.c_str(), true);

    std::vector<const char *> modules;
    std::string sReturnString;
    ExecuteScriptFunc(modules, "string_function", false, ">s", &sReturnString);

    ExecuteScript("string_function = nil", true);
    return sReturnString.c_str();
}

void ScriptVM::RegistGlobalFunction(const char* sFunctionName, lua_CFunction pFunction)
{
    lua_register(m_pLua, sFunctionName, pFunction);
}

bool ScriptVM::GetNumber(const std::vector<const char *>& modules, const char * name, double& dValue)
{
    int nSize1 = lua_gettop(m_pLua);

    if (modules.empty()) //userdata is global
    {
        lua_getglobal(m_pLua, name);
    }
    else
    {
        //trace down the modules
        std::vector<const char *>::const_iterator it = modules.begin();
        //get the global module name or the actual function name if there is no module
        lua_getglobal(m_pLua, *it);
        if (!lua_istable(m_pLua, -1))
        {
            error_msg(true, "GetUserdata: Invalid table name: %s\n", *it);
            lua_settop(m_pLua, nSize1);
            return false;
        }

        for (++it; it != modules.end(); ++it)
        {
            lua_pushstring(m_pLua, *it);
            lua_gettable(m_pLua, -2);
            if (!lua_istable(m_pLua, -1))
            {
                error_msg(true, "GetUserdata: Invalid table name: %s\n", *it);
                lua_settop(m_pLua, nSize1);
                return false;
            }
        }
        //get the data
        lua_pushstring(m_pLua, name);
        lua_gettable(m_pLua, -2);
    }

    if (lua_isnumber(m_pLua, -1))
    {
        dValue = tolua_tonumber(m_pLua, -1, 0);
        lua_settop(m_pLua, nSize1);
        return true;
    }
    else
    {
        lua_settop(m_pLua, nSize1);
        return false;
    }
}

void ScriptVM::DoExecuteFunc(const char* func, bool bAllowNonexist, const ScriptVmArgs::ArgsInput& input, ScriptVmArgs::ArgsOutput& output, const std::vector<const char*>* pModuls)
{

    //get the actual function
    const int nOrgSize = lua_gettop(m_pLua);
    int nInputSize = input.Size();
    int nOutputSize = output.Size();

    if (!pModuls || (pModuls && pModuls->empty())) //func is global
    {
        lua_getglobal(m_pLua, func);
        if (!lua_isfunction(m_pLua, -1))
        {
            if (!bAllowNonexist)
                error_msg(true, "ExecuteScriptFunc: Invalid function name: %s\n", func);
            goto failed;
        }
    }
    else
    {
        //trace down the modules
        std::vector<const char *>::const_iterator it = pModuls->begin();
        //get the global module name or the actual function name if there is no module
        lua_getglobal(m_pLua, *it);
        if (!lua_istable(m_pLua, -1))
        {
            if (!bAllowNonexist)
                error_msg(true, "ExecuteScriptFunc: Invalid table name: %s\n", *it);
            goto failed;
        }

        for (++it; it != pModuls->end(); ++it)
        {
            lua_pushstring(m_pLua, *it);
            lua_gettable(m_pLua, -2);
            if (!lua_istable(m_pLua, -1))
            {
                if (!bAllowNonexist)
                    error_msg(true, "ExecuteScriptFunc: Invalid table name: %s\n", *it);
                goto failed;
            }
        }

        //get the func
        lua_pushstring(m_pLua, func);
        lua_gettable(m_pLua, -2);
        if (!lua_isfunction(m_pLua, -1))
        {
            if (!bAllowNonexist)
                error_msg(true, "ExecuteScriptFunc: Invalid function name: %s\n", func);
            goto failed;
        }
    }

    /* push    arguments */
    input.Push(*m_pLua);

    /* do the call */
    if (lua_pcall(m_pLua, nInputSize, nOutputSize, 0) != 0) /* do    the    call */
    {
        report_last_error(m_pLua, true);
        goto failed;
    }

    /* retrieve    results    */
    output.Pop(*m_pLua);

failed:
    //clear the stack
    lua_settop(m_pLua, nOrgSize);
}

int ScriptVM::GetConsumeMemoryCount()
{
    int nCount = 0;
    if (m_pLua)
    {
        nCount = lua_getgccount(m_pLua);
    }

    return nCount;
}

void ScriptVM::PrintGlobalVariables()
{
    ExecuteScript("for n in pairs(_G) do print(n) end", true);
}

void ScriptVmArgs::DoPush(lua_State& lua, const char* pcArg)
{
    lua_pushstring(&lua, pcArg);
}

void ScriptVmArgs::DoPush(lua_State& lua, const bool bArg)
{
    lua_pushboolean(&lua, bArg);
}

void ScriptVmArgs::DoPush(lua_State& lua, const float fArg)
{
    lua_pushnumber(&lua, fArg);
}

void ScriptVmArgs::DoPush(lua_State& lua, const int nArg)
{
    lua_pushnumber(&lua, nArg);
}

void ScriptVmArgs::DoPush(lua_State& lua, unsigned uArg)
{
    lua_pushinteger(&lua, uArg);
}

void ScriptVmArgs::DoPop(lua_State& lua, bool& bArg, int idx)
{
    bArg = lua_toboolean(&lua, idx) != 0;
}

void ScriptVmArgs::DoPop(lua_State& lua, std::string& sArg, int idx)
{
    sArg = lua_tostring(&lua, idx);
}

void ScriptVmArgs::DoPop(lua_State& lua, float& fArg, int idx)
{
    fArg = (float)lua_tonumber(&lua, idx);
}

void ScriptVmArgs::DoPop(lua_State& lua, int& nArg, int idx)
{
    nArg = (int)lua_tonumber(&lua, idx);
}

void ScriptVmArgs::DoPop(lua_State& lua, unsigned& uArg, int idx)
{
    uArg = lua_tointeger(&lua, idx);
}


OK,下面來實現一下測試代碼,來看看如何 lua 和 c++進行交互的。


我們來簡單編寫幾個文件。

函數調用:
ScriptFunction.h
/**************************************************************************************
        vic.MINg            2018/09/19
**************************************************************************************
*/

#pragma once

namespace Script {
    //tolua_begin
    void show_luaproject_info();
    //tolua_end
}

ScriptFunction.cpp
#include "ScriptFunction.h"
#include <stdio.h>

namespace Script {

    void show_luaproject_info()
    {
        printf("Show LuaProject C++ Info.\n");
    }

}

結構體
Hag.h
/***********************************************************************
        vic. MINg        2018/09/25
**********************************************************************
*/

#pragma once
#include <string>

//tolua_begin
struct Hag        
{
    int            hag_id;
    std::string hag_name;
    bool             is_valid;
    int            hag_score;

    Hag() { }
    virtual ~Hag() {}
};
//tolua_end


Student.h
#pragma once

#include<iostream>
using namespace std;

//tolua_begin
class Student
{
public:

    Student();
    virtual ~Student();

    void Run();
    void Run(int a);
    
};
//tolua_end

Student.cpp
#include "Student.h"


Student::Student()
{
}

void Student::Run()
{
    //cout << "Student Run" << endl;
    printf("Student Student Run.\n");
}

void Student::Run(int a)
{
    //cout << "Student Run" <<a<< endl;
    printf("Student Student Run with %d.\n", a);
}

Student::~Student()
{
}

非常簡單的測試代碼。不言語。繼續往下。
我們需要編寫一份 LuaScript.pkg 文件來導出這些文件,讓lua可以調用他們。

LuaScript.pkg
#include "tolua++.h"

$#pragma warning(disable : 4800) //forcing value to bool warning


// script functions
$cfile "ScriptFunction.h"
$using namespace Script;


// class
$cfile "Hag.h"
$cfile "Student.h"

做一個實行腳本 glue.bat 來通過 LuaScript.pkg 編譯 lua 的cpp文件。

glue.bat
..\..\Debug\tolua -o l_LuaScript.cpp LuaScript.pkg
pause

這樣會生成 l_LuaScript.cpp 來實行lua和c++ 之間的相互調用,這里由于是生成出來的 就不粘代碼了

值得注意的幾個方面:
使用 boost 的時候為了方便 我們使用了 BOOST_ALL_NO_LIB ,這樣 就不用編譯 boost了
//  "boost/config/user.hpp" 取消 BOOST_ALL_NO_LIB 注釋
#define  BOOST_ALL_NO_LIB

注意 tolua中 注釋的使用,如果沒使用
   //tolua_export、//tolua_begin、//tolua_end 是無法在實行 glue.bat 時生成的 l_LuaScript.cpp 中生成關聯映射的。

工程配置:
附加包含目錄:..;..\include;..\..\lua\src;..\..\tolua\include;
附加依賴項:lua.lib;tolua.lib;
預處理器定義:WIN32;_CRT_SECURE_NO_WARNINGS;


main.cpp
#include "ScriptVM.h"
#include "ScriptVmArgs.h"
#include <stdio.h>
#include <string>
#include <assert.h>
#include <iostream>

extern "C" {
    #include "lua.h"
    #include "lualib.h"
    #include "lauxlib.h"
}


#include "tolua++.h"

#include "IOServer.h"
#include "Stream.h"
#include "Hag.h"

#include "FSWrapper.h"

#include "boost/ref.hpp"


extern void report_last_error(lua_State *L, bool bUseAssert);
extern int  tolua_LuaScript_open(lua_State* tolua_S);

static int OverrideDofile(lua_State * L) {

    int n = lua_gettop(L);  /* number of arguments */
    lua_getglobal(L, "tostring");

    if (n != 1)
        return luaL_error(L, "'dofile' param error!");

    std::string sFileName = "";
    lua_pushvalue(L, -1);  /* function to be called */
    lua_pushvalue(L, 1);   /* value to print */
    lua_call(L, 1, 1);
    sFileName = lua_tostring(L, -1);  /* get result */
    if (sFileName == "")
        return luaL_error(L, "'dofile' param error!");

    sFileName = Internal::FSWrapper::GetBinDirectory().c_str();
    sFileName.append("/Scripts/test.lua");
    lua_pop(L, 1);  /* pop result */

                    //get chunk name as modified script name
    std::string sChunkName(sFileName.c_str());
    for (unsigned int i = 0; i < sChunkName.length(); i++)
    {
        if (sChunkName[i] == '/' || sChunkName[i] == '.')
            sChunkName[i] = '_';
    }

    //load it first
    unsigned char * pBuff;
    int nSize;
    if (ScriptVM::LoadFileToBuffer(sFileName.c_str(), pBuff, nSize, true))
    {
        luaL_loadbuffer(L, (char *)pBuff, nSize, sFileName.c_str());

        delete[] pBuff;

        //luaL_loadfile(L, sScriptName);
        lua_setglobal(L, sChunkName.c_str());
        lua_getglobal(L, sChunkName.c_str());

        if (lua_pcall(L, 0, 0, 0) != 0)
        {
            //printf("文件 " << sFileName.c_str() << " 執行錯誤!");
            std::string sErrorMsg = "error executing script file %s: ";
            sErrorMsg += sFileName;
            assert(sErrorMsg.c_str());
            //error_msg(true, "error executing script file %s: ", sFileName.AsCharPtr());
            report_last_error(L, true);
        }
    }
    else
    {

        lua_settop(L, n);
        return luaL_error(L, "error in the file!");
    }

    return 0;
}

int main(int argc, char** argv) 
{
    ScriptVM* pScriptVM = new ScriptVM;
    if (!pScriptVM->Init())
    {
        printf("ScriptVM Init failed! \n");
        return -1;
    }

    pScriptVM->RegistGlobalFunction("dofile", OverrideDofile);
     //  注意調用 tolua_LuaScript_open ,使lua和c++可以相互調用
    tolua_LuaScript_open(pScriptVM->GetLuaState());

    //  加載一個lua腳本
    pScriptVM->ExecuteScriptFile("scripts/hello.lua");

    
    // 調用 lua 中的 student_run 方法 , ("i", 20) 表示傳參, i 表示傳一個參數 為int型
    
// 假設要傳 兩個參數 一個是 double 一個是 std::string 可以寫成 ("ds", 3.14, "vic.MINg")
    std::vector<const char *>modules;
    pScriptVM->ExecuteScriptFunc(modules, "student_run", false, "i", 20);

    
    // 調用 lua 中的 add 方法
    
// inTuple 為進參、 outTuple 為出參
    
//  調用方法如下 
    int a = 20, b = 10;
    int  sum = 0;
    boost::tuple<intint> inTuple = boost::tuples::make_tuple(a, b);
    boost::tuple<int&> outTuple = boost::tuples::make_tuple(boost::ref(sum));
    pScriptVM->ExecuteFunc("add", false, inTuple, outTuple);
    printf("Lua Func Add %d + %d = %d \n", a, b, sum);


    // 這里我們 傳一個字符串 來在lua中 new一個 新類
    
// 看似比較平庸,我們可以通過某些文件來動態生成一個類 
    
// 比如  我們在 xml 中定義一個 <HagType>PlayerHag</HagType>
    
//  然后 讀取該項 然后 類型下面代碼 生成 PlayerHag, 然后通過 RTTI 來判斷 應用該類 
    std::string strHag = "english_hag = nil english_hag = Hag:new()";
    pScriptVM->ExecuteScript(strHag.c_str());
    Hag* pEnglish_hag = static_cast<Hag*>(pScriptVM->GetGlobalUserdata("english_hag"));
    if (pEnglish_hag)
    {
        pEnglish_hag->hag_id = 1;
        pEnglish_hag->hag_name = "English";
        pEnglish_hag->is_valid = true;
        pEnglish_hag->hag_score = 94;    
    }


    // 通過 lua 快速公式計算
    std::string strFormula = "1.8586*level + 8.7842  +50+(level-1)*5/3";
    std::map<std::stringdouble> mapParams;
    mapParams.insert(std::make_pair( "level", 3));
    double dValue = pScriptVM->ComputingFormula(strFormula.c_str(), mapParams);
    printf("Lua ComputingFormula level = %d, 1.8586*level + 8.7842  +50+(level-1)*5/3 =  %lf \n", 3, dValue);

    system("pause");

    return 0;
}

/*        下面的代碼 是處理 原生的 lua腳本的
using namespace std;

void main()
{
    //1.創建Lua狀態  
    lua_State *L = luaL_newstate();
    if (L == NULL)
    {
        return;
    }

    //2.加載Lua文件  
    int bRet = luaL_loadfile(L, "E:\\hello.lua");
    if (bRet)
    {
        cout << "load file error" << endl;
        return;
    }

    //3.運行Lua文件  
    bRet = lua_pcall(L, 0, 0, 0);
    if (bRet)
    {
        cout << "pcall error" << endl;
        return;
    }

    //4.讀取變量  
    lua_getglobal(L, "str");
    string str = lua_tostring(L, -1);
    cout << "str = " << str.c_str() << endl;        //str = I am so cool~  

                                                    //5.讀取table  
    lua_getglobal(L, "tbl");
    lua_getfield(L, -1, "name");
    str = lua_tostring(L, -1);
    cout << "tbl:name = " << str.c_str() << endl; //tbl:name = shun  

                                                  //6.讀取函數  
    lua_getglobal(L, "add");        // 獲取函數,壓入棧中  
    lua_pushnumber(L, 10);          // 壓入第一個參數  
    lua_pushnumber(L, 20);          // 壓入第二個參數  
    int iRet = lua_pcall(L, 2, 1, 0);// 調用函數,調用完成以后,會將返回值壓入棧中,2表示參數個數,1表示返回結果個數。  
    if (iRet)                       // 調用出錯  
    {
        const char *pErrorMsg = lua_tostring(L, -1);
        cout << pErrorMsg << endl;
        lua_close(L);
        return;
    }
    if (lua_isnumber(L, -1))        //取值輸出  
    {
        double fValue = lua_tonumber(L, -1);
        cout << "Result is " << fValue << endl;
    }

    system("pause");
    //至此,棧中的情況是:  
    //=================== 棧頂 ===================   
    //  索引  類型      值  
    //   4   int:      30   
    //   3   string:   shun   
    //   2   table:     tbl  
    //   1   string:    I am so cool~  
    //=================== 棧底 ===================   

    //7.關閉state  
    lua_close(L);
    return;
}
*/

LuaScript項目

這個項目 使用BabeLua插件創建,方便lua腳本的編寫和調試。

hello.lua
str = "I am so cool"  
tbl = {name = "shun", id = 20114442}  

function add(a,b)  
    return a + b 
end

function student_run(n)
    local st = Student:new() 
    st:Run(n)
    st:delete()
    show_luaproject_info()
end 
OK 這樣一套完善的lua與c++相互交互體系就這樣實現了,運行結果如下~~~~~~~~~~~




posted on 2018-09-26 15:53 vic.MINg 閱讀(4658) 評論(0)  編輯 收藏 引用 所屬分類: C/C++

<2018年9月>
2627282930311
2345678
9101112131415
16171819202122
23242526272829
30123456

常用鏈接

留言簿(1)

隨筆分類(13)

隨筆檔案(12)

搜索

  •  

最新評論

閱讀排行榜

評論排行榜

青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            亚洲欧洲在线视频| 亚洲永久视频| 亚洲性视频网址| 一本到高清视频免费精品| 亚洲国产岛国毛片在线| 亚洲国产国产亚洲一二三| 亚洲福利专区| 一本到12不卡视频在线dvd| 亚洲伊人网站| 久久精品国产综合精品| 欧美高清hd18日本| 日韩视频精品在线| 欧美一站二站| 欧美激情国产精品| 国产精品日韩在线播放| 狠狠色丁香婷综合久久| 91久久精品久久国产性色也91| 一本色道久久88精品综合| 性8sex亚洲区入口| 欧美成人综合一区| 一区二区三区日韩精品| 久久国产精品99国产精| 欧美伦理在线观看| 国产日韩av在线播放| 亚洲精品免费一区二区三区| 欧美一区午夜精品| 亚洲人成7777| 亚洲综合首页| 欧美精品久久一区| 一区二区三区在线看| 亚洲一区二区三区视频播放| 欧美在线资源| 亚洲国产成人在线| 亚洲自拍偷拍网址| 欧美激情无毛| 在线观看国产精品淫| 亚洲欧美久久久久一区二区三区| 毛片基地黄久久久久久天堂| 中文亚洲视频在线| 免费欧美高清视频| 国产一区二区在线免费观看| 亚洲视频精品| 亚洲高清久久久| 久久九九热免费视频| 国产欧美短视频| 亚洲视频欧洲视频| 欧美国产一区视频在线观看 | 久久精品视频在线观看| 日韩小视频在线观看| 美女视频黄免费的久久| 伊人精品成人久久综合软件| 久久久久一区二区三区| 亚洲一区日本| 国产乱码精品一区二区三区av| 在线视频一区观看| 亚洲乱亚洲高清| 欧美成人一区二区在线 | 国产情人节一区| 欧美一区二区三区婷婷月色| 亚洲图片在区色| 国产精品99一区| 亚洲欧美日韩国产综合精品二区| 亚洲精品视频在线看| 欧美精品一区二区在线观看| 99re66热这里只有精品3直播| 亚洲第一成人在线| 欧美成人性网| 99精品视频免费全部在线| 亚洲麻豆av| 国产精品久久九九| 欧美在线啊v一区| 久久av一区二区三区漫画| 狠狠色丁香久久综合频道| 欧美成人国产| 欧美日韩成人在线播放| 亚洲一二三区精品| 亚洲综合视频一区| 国产自产v一区二区三区c| 免费在线欧美视频| 欧美日本三区| 欧美在线播放| 欧美成人国产一区二区| 亚洲性视频h| 欧美有码在线观看视频| 亚洲日本免费| 亚洲影院免费观看| 亚洲激情第一区| 一区二区三区不卡视频在线观看| 午夜久久资源| 欧美在线不卡| 91久久精品国产91久久| 亚洲女人av| 亚洲黄色视屏| 亚洲女人天堂av| 亚洲国产精品久久久久秋霞影院| 亚洲免费高清视频| 激情综合电影网| 一区二区免费在线观看| 在线看国产一区| 正在播放欧美一区| 91久久久亚洲精品| 亚洲欧美中文另类| 日韩一级精品| 久久精品中文字幕一区| 亚洲一区视频在线观看视频| 美女国产精品| 久久―日本道色综合久久| 欧美日本中文| 欧美高清视频在线| 国产欧美精品国产国产专区| 亚洲精品美女在线观看| 伊人成人在线视频| 亚洲自拍啪啪| 中文精品视频| 欧美激情在线免费观看| 久久综合一区| 国产一区清纯| 欧美一区二区三区免费大片| 亚洲性感美女99在线| 欧美极品一区二区三区| 欧美黄色一区| 1000部精品久久久久久久久| 午夜视频精品| 欧美一区二区免费| 欧美性猛交视频| 日韩一区二区精品葵司在线| 日韩视频精品在线观看| 欧美第十八页| 亚洲高清视频一区二区| 亚洲激情专区| 麻豆成人av| 亚洲国产精品成人一区二区| 亚洲高清网站| 你懂的视频一区二区| 欧美1级日本1级| 一区久久精品| 欧美α欧美αv大片| 欧美激情一区二区三区在线视频 | 亚洲欧美日韩一区二区三区在线观看| 欧美激情91| 日韩西西人体444www| 亚洲性感激情| 国产人久久人人人人爽| 欧美在线观看一区二区三区| 欧美一区二区在线播放| 国产性色一区二区| 久久精品亚洲一区二区| 免费欧美电影| 亚洲区第一页| 欧美日韩在线视频一区二区| 一区二区成人精品| 久久成人一区| 亚洲国产成人久久| 欧美另类女人| 亚洲综合欧美日韩| 亚洲黄色精品| 亚洲人午夜精品免费| 一本大道久久a久久综合婷婷| 欧美日韩午夜视频在线观看| 亚洲尤物在线视频观看| 久久综合激情| 亚洲精品欧美专区| 国产精品久久久久久户外露出| 亚洲欧美一区二区三区在线| 久久女同互慰一区二区三区| 亚洲精品一区久久久久久| 欧美午夜在线观看| 久久久噜噜噜久久| 99精品欧美| 免费一区二区三区| 亚洲影院免费观看| ●精品国产综合乱码久久久久| 欧美大片在线看| 午夜精品久久| 亚洲精品久久久久久久久| 欧美中文在线观看| 日韩午夜激情av| 国产主播精品| 欧美日韩在线影院| 久久久综合网| 亚洲欧美日韩精品久久久| 亚洲高清激情| 久久久综合网| 亚洲自拍另类| 亚洲人成网站777色婷婷| 国产日韩欧美制服另类| 欧美日本二区| 美日韩丰满少妇在线观看| 亚洲欧美影院| 一二三区精品福利视频| 欧美激情一区二区三区蜜桃视频| 欧美一区高清| 亚洲在线观看视频| 日韩视频―中文字幕| 在线播放不卡| 国产在线高清精品| 国产欧美精品国产国产专区| 国产精品激情偷乱一区二区∴| 欧美h视频在线| 乱码第一页成人|