SLua 绑定 Protobuf-Lua (protoc-gen-lua) 在SLua中使用 Protobuf

游戏要迁移到Lua,选择了SLua这个开源库来做,SLua很干净,仅仅只提供 Unity 到 Lua 的支持,没有包含其它的库,比如 protoc-gen-lua ,既然没有,那我们就自己把 protoc-gen-lua 编译到 SLua 库中。

1、protoc-gen-lua 的编译安装使用

首先下载 protobuf-2.4.1 编译出 proto工具,然后下载 protoc-gen-lua 进行编译,具体步骤请看 protoc-gen-lua 编译、安装、使用教程

2、下载 slua-0.8.3 下载地址

https://github.com/pangweiwei/slua/releases/tag/v0.8.3

因为我这边用的是 slua-0.8.3 ,但是slua-0.8.3 压缩包里面并没有 编译需要的工程、makefile 文件这些,所以需要从 slua-0.8.5中拷贝过来。

所以再下载 slua-0.8.5

https://github.com/pangweiwei/slua/archive/v0.8.5.zip

SLua 绑定 Protobuf-Lua (protoc-gen-lua) 在SLua中使用 Protobuf_第1张图片

把 slua-0.8.5 中的 build 文件夹 拷贝一份到 slua-0.8.3 中。

然后删掉 slua-0.8.5 吧……

如果是直接用 slua-0.8.5 就直接用。

1、编译 SLua Windows 版

打开Vistual Studio 命令提示符,到 slua-0.8.3\build 中执行 make_win_with_2013.bat 。

编译出错

SLua 绑定 Protobuf-Lua (protoc-gen-lua) 在SLua中使用 Protobuf_第2张图片

是因为 slua.c 中有错误,打开 slua-0.8.3\Assets\slua_src\slua.c 进行如下修改

SLua 绑定 Protobuf-Lua (protoc-gen-lua) 在SLua中使用 Protobuf_第3张图片

再次编译,编译成功。

下面我们把 protoc-gen-lua 的 pb.c 加入编译。

把 protoc-gen-lua-master\protobuf\pb.c 拷贝到 slua-0.8.3\Assets\slua_src 中。

然后修改 slua-0.8.3\Assets\slua_src\msvcbuild.bat ,将 pb.c 加入编译

SLua 绑定 Protobuf-Lua (protoc-gen-lua) 在SLua中使用 Protobuf_第4张图片

再次编译,会提示 pb.c 中的一些错误,在上一篇 Luajit 2.0.4 绑定 protoc-gen-lua (Windows 平台)

中都解决了,参考上一篇即可。

修改了pb.c 中的几个错误后,编译成功。

脚本自动把 编译出来的 slua.dll 拷贝到了 slua-0.8.3\slua-0.8.3\Assets\Plugins\x86 和 x64 目录。

下面打开 Unity ,打开slua 中的实例工程。

从上一篇的测试工程中拷贝测试用的 protobuf 文件到 Unity中,注意要放到 SLua 的 存放 lua 文件的 目录中。

然后用SLua 的 Custom 场景做测试,修改下 Custom 的lua代码如下。添加测试Protobuf的代码

    require "Person_pb"
     
    MonoBehaviour = UnityEngine.MonoBehaviour
    GameObject = UnityEngine.MonoBehaviour
     
    --test Protobuf lua add
    local msg = Person_pb.Person()
    msg.id = 100
    msg.name = "foo"
    msg.email = "bar"
     
    local pb_data = msg:SerializeToString()  -- Parse Example
     
    print("create:", msg.id, msg.name, msg.email, pb_data)
     
    local msg1 = Person_pb.Person()
    msg1:ParseFromString(pb_data)
    print("parser:", msg1.id, msg1.name, msg1.email, pb_data) 
     
    --end
     
    function main()
     
    	local s,c=Custom.staticCustom();
    	print(s,c)
     
    	local a,b,x=c:instanceCustom()
    	print(a,b,x)
     
    	-- Type parameter can be pass in as string/type table
    	print(c:getTypeName("UnityEngine.MonoBehaviour,UnityEngine"))
    	print(c:getTypeName(MonoBehaviour))
    	print(c:getTypeName(Custom))
     
    	-- Test getItem setItem
    	print("---<"..c:getItem("test"))
    	c:setItem("test",10)
    	print("-->"..c:getItem("test"))
    	c:setItem("a",100)
    	print("-->"..c:getItem("test"))
    end

运行Custom 场景后,会报错。

    [string "protobuf"]:31: module 'pb' not found:
    	no field package.preload['pb']
    	no file '.\pb.lua'
    	no file 'D:\Program Files (x86)\Unity4.6.7f1\Editor\lua\pb.lua'
    	no file 'D:\Program Files (x86)\Unity4.6.7f1\Editor\lua\pb\init.lua'
    	no file '.\pb.dll'
    	no file 'D:\Program Files (x86)\Unity4.6.7f1\Editor\pb.dll'
    	no file 'D:\Program Files (x86)\Unity4.6.7f1\Editor\loadall.dll'
    stack traceback:
    	[C]: in function 'require'
    	[string "protobuf"]:31: in main chunk
    	[C]: in function 'require'
    	[string "Person_pb"]:2: in main chunk
    	[C]: in function 'require'
    	[string "custom"]:1: in main chunk
    UnityEngine.Debug:LogError(Object)
    SLua.LuaState:errorReport(IntPtr) (at Assets/Slua/Script/LuaState.cs:606)
    LuaInterface.LuaDLL:lua_pcall(IntPtr, Int32, Int32, Int32)
    SLua.LuaState:doBuffer(Byte[], String, Object&) (at Assets/Slua/Script/LuaState.cs:770)
    SLua.LuaState:doFile(String) (at Assets/Slua/Script/LuaState.cs:759)
    SLua.LuaSvr:start(String) (at Assets/Slua/Script/LuaSvr.cs:86)
    Custom:Start() (at Assets/Slua/example/Custom.cs:20)

提示 pb 不存在,就是说 Protobuf 的库没有加载到嘛。
为什么没有加载到?
因为我们本来就没有去加载……
下面来加载

在 slua.c 最后添加函数,加载 Protobuf 的库

    //lua protobuf
    LUA_API void luaS_openepb(lua_State *L)
    {
    	luaopen_pb(L);                     //加载pb;
    }

然后重新编译slua

然后要在C# 中去调用这个添加的函数
首先修改 LuaDLLWrapper.cs ,添加 接口

    namespace LuaInterface
    {
        using System;
        using System.Runtime.InteropServices;
        using System.Reflection;
        using System.Collections;
        using System.Text;
        using System.Security;
     
        /**     Modify Record:
     
        lua_xmove:        return void
        //lua_gc:           LuaDLLWrapper: enum->int。 
     
        lua_objlen:     lua 5.1:  luaS_objlen size_t->int
        lua_rawlen:        lua 5.3:  luaS_rawlen size_t->int
     
        lua_setmetatable: lua 5.1 return int
                           lua 5.3 return void
     
        //lua_type:         LuaDLLWrapper:  return int->enum
        lua_isnumber:    LuaDLLWrapper: return bool->int
        lua_isstring:      LuaDLLWrapper: return bool->int
        lua_iscfunction:   LuaDLLWrapper: return bool->int
     
        lua_call:          5.1 return int->void
     
        lua_toboolean:     LuaDLLWrapper:   return bool->int
     
        lua_atpanic:       return void->intptr 
     
        lua_pushboolean:   LuaDLLWrapper: bool ->int
        lua_pushlstring:   LuaDLLWrapper: luaS_pushlstring. size_t->int
     
        luaL_getmetafield:  LuaDLLWrapper: return bool->int
        luaL_loadbuffe:     LuaDLLWrapper  luaLS_loadbuffer  size_t  CharSet
     
        lua_error:         return void->int
        lua_checkstack:  LuaDLLWrapper return bool->int
     
        **/
     
        public class LuaDLLWrapper
        {
     
    #if UNITY_IPHONE && !UNITY_EDITOR
    		const string LUADLL = "__Internal";
    #else
     
            const string LUADLL = "slua";
    #endif
     
    #if LUA_5_3
            [DllImport(LUADLL, CallingConvention = CallingConvention.Cdecl)]
            public static extern int luaS_rawlen(IntPtr luaState, int index);
    #else
    		[DllImport(LUADLL, CallingConvention = CallingConvention.Cdecl)]
            public static extern int luaS_objlen(IntPtr luaState, int stackPos);
    #endif
     
            //[DllImport(LUADLL, CallingConvention = CallingConvention.Cdecl)]
            //public static extern int lua_gc(IntPtr luaState, int what, int data);
     
            //[DllImport(LUADLL,CallingConvention=CallingConvention.Cdecl)]
            //public static extern int lua_type(IntPtr luaState, int index);
     
            [DllImport(LUADLL,CallingConvention=CallingConvention.Cdecl)]
    		public static extern int lua_isnumber(IntPtr luaState, int index);
     
            [DllImport(LUADLL,CallingConvention=CallingConvention.Cdecl)]
    		public static extern int lua_isstring(IntPtr luaState, int index);
     
            [DllImport(LUADLL,CallingConvention=CallingConvention.Cdecl)]
    		public static extern int lua_iscfunction(IntPtr luaState, int index);
     
            [DllImport(LUADLL,CallingConvention=CallingConvention.Cdecl)]
    		public static extern int lua_toboolean(IntPtr luaState, int index);
     
            [DllImport(LUADLL, CallingConvention = CallingConvention.Cdecl)]
            public static extern void lua_pushboolean(IntPtr luaState, int value);
     
            [DllImport(LUADLL, CallingConvention = CallingConvention.Cdecl)]
            public static extern void luaS_pushlstring(IntPtr luaState, byte[] str, int size);
     
            [DllImport(LUADLL, CallingConvention = CallingConvention.Cdecl)]
            public static extern int luaL_getmetafield(IntPtr luaState, int stackPos, string field);
     
            [DllImport(LUADLL, CallingConvention = CallingConvention.Cdecl)]
            public static extern int luaLS_loadbuffer(IntPtr luaState, byte[] buff, int size, string name);
     
            [DllImport(LUADLL, CallingConvention = CallingConvention.Cdecl)]
            public static extern int lua_checkstack(IntPtr luaState, int extra);
     
    		//add to openpb
    		[DllImport(LUADLL, CallingConvention = CallingConvention.Cdecl)]
            public static extern void luaS_openepb(IntPtr luaState);
        }
     
    }

然户在 LuaState.cs 的
[MonoPInvokeCallbackAttribute(typeof(LuaCSFunction))]
static int init(IntPtr L)

这个函数里调用上面添加的函数,修改如下

    [MonoPInvokeCallbackAttribute(typeof(LuaCSFunction))]
            static int init(IntPtr L)
            {
                LuaDLL.luaL_openlibs(L);
     
                //加载protobuf;
                LuaDLLWrapper.luaS_openepb(L);
     
                LuaDLL.lua_pushlightuserdata(L, L);
                LuaDLL.lua_setglobal(L, "__main_state");
     
                LuaDLL.lua_pushcfunction(L, print);
                LuaDLL.lua_setglobal(L, "print");
     
                LuaDLL.lua_pushcfunction(L, pcall);
                LuaDLL.lua_setglobal(L, "pcall");
     
                LuaDLL.lua_pushcfunction(L, import);
                LuaDLL.lua_setglobal(L, "import");

运行游戏,输出下面的log,说明成功了。

SLua 绑定 Protobuf-Lua (protoc-gen-lua) 在SLua中使用 Protobuf_第5张图片

你可能感兴趣的:(Unity3d热更新,--,SLua)