游戏要迁移到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");