lua调用C#:反射(性能低),Wrap(将C#类变量函数映射到lua,形成一个个静态函数)
Lua->Wrap(luaState将C#类的变量函数注册到luaVM,lua就可以调用了)->C#
C#调用lua,通过Pinvoke调用lua的dll,执行lua脚本(lua,luajit,luaInterface)
转:https://blog.csdn.net/pengdongwei/article/details/50420612
上次已经搭建好了框架,这里开始使用框架,本文会比较长~~因为我搞了一天,也遇到了好多坑
今天主要记录一下 c# 与 lua 的交互~~ 然后配以demo
C# 调用 lua 这个很简单,之前也有说过,这里不废话,直接贴
- LuaScriptMgr mgr = new LuaScriptMgr ();
- mgr.Start ();
- mgr.DoFile ("LoginUI.lua");
难点其实是Lua调用c#,以及效率问题
>> 最古老的是使用反射调用,不过由于反射的性能问题,目前基本上不怎么用了
>>wrap调用提升了反射在效率上的不足,但是必须自己去wrap,所以大版本更新是可以用到的,小版本更新目前还是得用到反射
ok~~ 肯定一头雾水,什么是wrap,怎么生成wrap,wrap工作原理是怎样的?(在今天之前我也是如此多的疑惑)
什么是wrap: wrap是对c#类的成员函数,成员变量,通过映射的方式。这里对比一下两个文件
这个是c#文件
- using UnityEngine;
- using System.Collections;
- public class LoginData {
- public string username;
- public string password;
- public int id;
- public LoginData(){
- }
- public LoginData(string username, string password, int id){
- this.username = username;
- this.password = password;
- this.id = id;
- }
- public void Equip(string username, string password, int id){
- Debug.Log ("logindata equip log");
- if (this.username.Equals (username) && password.Equals (password) && this.id == id) {
- Debug.Log ("C# >>> LoginData = {username = " + this.username + ", password =" + this.password + ", id = " + this.id + " check ok!!!");
- } else {
- Debug.Log ("C# >>> LoginData = {username = " + this.username + ", password =" + this.password + ", id = " + this.id + " check error!!!");
- }
- }
- }
- using System;
- using LuaInterface;
- public class LoginDataWrap
- {
- public static void Register(IntPtr L)
- {
- LuaMethod[] regs = new LuaMethod[]
- {
- new LuaMethod("Equip", Equip),
- new LuaMethod("New", _CreateLoginData),
- new LuaMethod("GetClassType", GetClassType),
- };
- LuaField[] fields = new LuaField[]
- {
- new LuaField("username", get_username, set_username),
- new LuaField("password", get_password, set_password),
- new LuaField("id", get_id, set_id),
- };
- LuaScriptMgr.RegisterLib(L, "LoginData", typeof(LoginData), regs, fields, typeof(object));
- }
- [MonoPInvokeCallbackAttribute(typeof(LuaCSFunction))]
- static int _CreateLoginData(IntPtr L)
- {
- int count = LuaDLL.lua_gettop(L);
- if (count == 0)
- {
- LoginData obj = new LoginData();
- LuaScriptMgr.PushObject(L, obj);
- return 1;
- }
- else if (count == 3)
- {
- string arg0 = LuaScriptMgr.GetString(L, 1);
- string arg1 = LuaScriptMgr.GetString(L, 2);
- int arg2 = (int)LuaScriptMgr.GetNumber(L, 3);
- LoginData obj = new LoginData(arg0,arg1,arg2);
- LuaScriptMgr.PushObject(L, obj);
- return 1;
- }
- else
- {
- LuaDLL.luaL_error(L, "invalid arguments to method: LoginData.New");
- }
- return 0;
- }
- static Type classType = typeof(LoginData);
- [MonoPInvokeCallbackAttribute(typeof(LuaCSFunction))]
- static int GetClassType(IntPtr L)
- {
- LuaScriptMgr.Push(L, classType);
- return 1;
- }
- [MonoPInvokeCallbackAttribute(typeof(LuaCSFunction))]
- static int get_username(IntPtr L)
- {
- object o = LuaScriptMgr.GetLuaObject(L, 1);
- LoginData obj = (LoginData)o;
- if (obj == null)
- {
- LuaTypes types = LuaDLL.lua_type(L, 1);
- if (types == LuaTypes.LUA_TTABLE)
- {
- LuaDLL.luaL_error(L, "unknown member name username");
- }
- else
- {
- LuaDLL.luaL_error(L, "attempt to index username on a nil value");
- }
- }
- LuaScriptMgr.Push(L, obj.username);
- return 1;
- }
- [MonoPInvokeCallbackAttribute(typeof(LuaCSFunction))]
- static int get_password(IntPtr L)
- {
- object o = LuaScriptMgr.GetLuaObject(L, 1);
- LoginData obj = (LoginData)o;
- if (obj == null)
- {
- LuaTypes types = LuaDLL.lua_type(L, 1);
- if (types == LuaTypes.LUA_TTABLE)
- {
- LuaDLL.luaL_error(L, "unknown member name password");
- }
- else
- {
- LuaDLL.luaL_error(L, "attempt to index password on a nil value");
- }
- }
- LuaScriptMgr.Push(L, obj.password);
- return 1;
- }
- [MonoPInvokeCallbackAttribute(typeof(LuaCSFunction))]
- static int get_id(IntPtr L)
- {
- object o = LuaScriptMgr.GetLuaObject(L, 1);
- LoginData obj = (LoginData)o;
- if (obj == null)
- {
- LuaTypes types = LuaDLL.lua_type(L, 1);
- if (types == LuaTypes.LUA_TTABLE)
- {
- LuaDLL.luaL_error(L, "unknown member name id");
- }
- else
- {
- LuaDLL.luaL_error(L, "attempt to index id on a nil value");
- }
- }
- LuaScriptMgr.Push(L, obj.id);
- return 1;
- }
- [MonoPInvokeCallbackAttribute(typeof(LuaCSFunction))]
- static int set_username(IntPtr L)
- {
- object o = LuaScriptMgr.GetLuaObject(L, 1);
- LoginData obj = (LoginData)o;
- if (obj == null)
- {
- LuaTypes types = LuaDLL.lua_type(L, 1);
- if (types == LuaTypes.LUA_TTABLE)
- {
- LuaDLL.luaL_error(L, "unknown member name username");
- }
- else
- {
- LuaDLL.luaL_error(L, "attempt to index username on a nil value");
- }
- }
- obj.username = LuaScriptMgr.GetString(L, 3);
- return 0;
- }
- [MonoPInvokeCallbackAttribute(typeof(LuaCSFunction))]
- static int set_password(IntPtr L)
- {
- object o = LuaScriptMgr.GetLuaObject(L, 1);
- LoginData obj = (LoginData)o;
- if (obj == null)
- {
- LuaTypes types = LuaDLL.lua_type(L, 1);
- if (types == LuaTypes.LUA_TTABLE)
- {
- LuaDLL.luaL_error(L, "unknown member name password");
- }
- else
- {
- LuaDLL.luaL_error(L, "attempt to index password on a nil value");
- }
- }
- obj.password = LuaScriptMgr.GetString(L, 3);
- return 0;
- }
- [MonoPInvokeCallbackAttribute(typeof(LuaCSFunction))]
- static int set_id(IntPtr L)
- {
- object o = LuaScriptMgr.GetLuaObject(L, 1);
- LoginData obj = (LoginData)o;
- if (obj == null)
- {
- LuaTypes types = LuaDLL.lua_type(L, 1);
- if (types == LuaTypes.LUA_TTABLE)
- {
- LuaDLL.luaL_error(L, "unknown member name id");
- }
- else
- {
- LuaDLL.luaL_error(L, "attempt to index id on a nil value");
- }
- }
- obj.id = (int)LuaScriptMgr.GetNumber(L, 3);
- return 0;
- }
- [MonoPInvokeCallbackAttribute(typeof(LuaCSFunction))]
- static int Equip(IntPtr L)
- {
- LuaScriptMgr.CheckArgsCount(L, 4);
- LoginData obj = (LoginData)LuaScriptMgr.GetNetObjectSelf(L, 1, "LoginData");
- string arg0 = LuaScriptMgr.GetLuaString(L, 2);
- string arg1 = LuaScriptMgr.GetLuaString(L, 3);
- int arg2 = (int)LuaScriptMgr.GetNumber(L, 4);
- obj.Equip(arg0,arg1,arg2);
- return 0;
- }
- }
当lua虚拟机启动的时候,会将此wrap文件加载进lua虚拟机,然后lua就可以识别此调用了,最后就形成了
Lua 调用 Wrap , Wrap调用C#的模式,实现了Lua调用C#
那么我们怎么来生成Wrap 呢 ?
生成Wrap文件需要使用者自己手动的去WrapFile 文件填写需要Wrap的文件,大概像下面这个样子
_GT(typeof(LoginData)),
为啥需要添加这个呢? 其实很简单,这个要从Wrap文件是生成说起。
来到BindLua.cs 文件,你会发现里面有个叫Binding的函数,函数大概是这样的
生成的Wrap文件会放到Lua/Source/LuaWrap 这个目录下面, 具体可以参考生成过程。
/
Lua文件如下,并没有什么特别的,只是一个简单的验证,并回调C#
- local transform;
- local gameObject;
- LoginUI = {};
- local this = LoginUI;
- -- c# 向lua 传入参数, 然后lua创建c#对象,并调用c#方法(wrap方式调用)
- function LoginUI.CheckUserName(username)
- if username=="pdw" then
- local loginData = LoginData.New();
- loginData:Equip(username, "123456", 1);
- else
- return "unknown username" end;
- end
- -- c# 向 lua传入对象,然后lua 调用本对象
- function LoginUI.CheckUserNameByData(data)
- data:Equip("pdw", "123456", 1);
- end
- using UnityEngine;
- using System.Collections;
- public class LoginUIPanel : MonoBehaviour {
- void OnGUI(){
- if (GUILayout.Button ("login")) {
- LoginData data = new LoginData ("pdw", "123456", 1);
- LuaScriptMgr mgr = new LuaScriptMgr ();
- mgr.Start ();
- mgr.DoFile ("LoginUI.lua");
- //mgr.CallLuaFunction ("LoginUI.CheckUserName", "pdw"); //传入lua字符串,并通过Wrap 创建对象返回
- mgr.CallLuaFunction ("LoginUI.CheckUserNameByData", data); //传入lua对象
- }
- }
- }