游戏要迁移到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-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.c 中有错误,打开 slua-0.8.3\Assets\slua_src\slua.c 进行如下修改
再次编译,编译成功。
下面我们把 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 加入编译
再次编译,会提示 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
[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 的库没有加载到嘛。
为什么没有加载到?
因为我们本来就没有去加载……
下面来加载
//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");