2012-11-01

Lua Callback Function

底下在 Unity3D ( MAC OSX ) 環境下實作 Lua 呼叫 C# 函數 (tellMeNum) 並且同時把 Lua 的函數 (dispResult) 告訴 C#,待 C# 回呼此函數並告知數字 12345.678。
C# 端程式碼如下 :
using UnityEngine;
using System;
using System.Collections;
using System.Runtime.InteropServices;
 
public class luaTest : MonoBehaviour
{
    [DllImport("lua521")]
    public static extern IntPtr luaL_newstate();
    [DllImport("lua521")]
    public static extern void luaL_openlibs(IntPtr lua_State);
    [DllImport("lua521")]
    public static extern void lua_close(IntPtr lua_State);
    [DllImport("lua521")]
    public static extern void lua_pushcclosure(IntPtr lua_State, LuaFunction func, int n);
    [DllImport("lua521")]
    public static extern void lua_setglobal(IntPtr lua_State, string s);
    [DllImport("lua521")]
    public static extern int lua_pcallk(IntPtr lua_State, int nargs, int nresults, int errfunc, int ctx, LuaFunction func);
    [DllImport("lua521")]
    public static extern int luaL_loadfilex(IntPtr lua_State, string s, string mode);
    [DllImport("lua521")]
    public static extern int luaL_loadstring(IntPtr lua_State, string s);
    [DllImport("lua521")]
    public static extern IntPtr luaL_checklstring(IntPtr lua_State, int idx, IntPtr len);
 
    [DllImport("lua521")]
    public static extern int lua_rawgeti(IntPtr lua_State, int idx0, int idx1);
    [DllImport("lua521")]
    public static extern int luaL_ref(IntPtr lua_State, int idx);
    [DllImport("lua521")]
    public static extern int luaL_unref(IntPtr lua_State, int idx0, int idx1);
    [DllImport("lua521")]
    public static extern int lua_pushnumber(IntPtr lua_State, double num);
 
    //------------------------------------
    // Lua
    //
 
    //註冊 C# Function 讓 Lua 可以呼叫執行
    public delegate int LuaFunction(IntPtr pLuaState);
    public static void lua_register(IntPtr pLuaState, string strFuncName, LuaFunction pFunc)
    {
        lua_pushcclosure(pLuaState, pFunc, 0);
        lua_setglobal(pLuaState, strFuncName);
    }
 
    //執行 Lua 檔案
    public static int luaL_dofile(IntPtr lua_State, string s)
    {
        if (luaL_loadfilex(lua_State, s, null) != 0)
            return 1;
        return lua_pcallk(lua_State, 0, -1, 0, 0, null);
    }
 
    //執行 Lua Callback Function
    public static int luaL_doCallBackFromCBIdx(IntPtr lua_State, int idx, double num)
    {
        lua_rawgeti(lua_State, -1000000 - 1000, idx);
        lua_pushnumber(lua_State, num);
        int ret = lua_pcallk(lua_State, 1, 0, 0, 0, null);
        if (ret != 0)
        {
            //Error...
        }
        luaL_unref(lua_State, -1000000 - 1000, idx);
        return ret;
    }
 
 
    //------------------------------------
    // Application
    //
    public static int nLuaCBFuncIdx = -1;
    public static IntPtr m_luaState = IntPtr.Zero;
 
    public static int tellMeNum(IntPtr pLuaState)
    {
        //取得回呼函數堆疊上的 index
        nLuaCBFuncIdx = luaL_ref(pLuaState, -1000000 - 1000);
        return 0;
    }
 
    //讓 Lua 在 unity 裡顯示 log 訊息
    public static int msg(IntPtr pLuaState)
    {
        IntPtr retPtr = luaL_checklstring(pLuaState, 1, IntPtr.Zero);
        string retStr = System.Runtime.InteropServices.Marshal.PtrToStringAnsi(retPtr);
 
        Debug.Log(retStr);
        return 0;
    }
 
    //取得 unity 執行路徑
    public static string GetAppPath()
    {
        return Application.dataPath.Substring(0, Application.dataPath.Length - 6);
    }
 
    // Use this for initialization
    void Start()
    {
        //初始化 Lua
        m_luaState = luaL_newstate();
        luaL_openlibs(m_luaState);
 
        //註冊 C# Function
        lua_register(m_luaState, "tellMeNum", tellMeNum);
        lua_register(m_luaState, "msg", msg);
 
        //執行 Lua 檔案
        string strPath = GetAppPath() + "LuaScript/lua.txt";
        luaL_dofile(m_luaState, strPath);
    }
 
    // Update is called once per frame
    void Update()
    {
        if (nLuaCBFuncIdx != -1)
        {
            //回呼取得的 lua callback function, 並給予數字 12345.678
            luaL_doCallBackFromCBIdx(m_luaState, nLuaCBFuncIdx, 12345.678);
            nLuaCBFuncIdx = -1;
        }
    }
 
    void OnApplicationQuit()
    {
        lua_close(m_luaState);
    }
}
其中值得注意的是 luaL_doCallBackFromCBIdx 函數,其用來回呼 Lua Callback Function。

lua.txt 內容如下:
function dispResult(num)
   msg(num)
end
 
tellMeNum(dispResult)
此 lua script 呼叫 tellMeNum 並將 dispResult 以參數傳給 C#,待 C# 呼叫 dispResult,dispResult 接收到 num 之後呼叫 msg 使 num 顯示在 Unity Console。

完整範例程式可在此取得:https://github.com/phardera/unity3d_lua_callback_function.git

0 意見 :

張貼留言