XLua原理(一)

项目中活动都是用xlua开发的,项目周更热修也是用xlua的hotfix特性来做的。现研究底层原理,对于项目性能有个更好的把控。

本文认为看到该文章的人已具备使用xlua开发的能力,只研究介绍下xlua的底层实现原理。

一.luac#交互原理

概括:

通过栈来实现。lua调用c#就是将lua层的参数和c#导出函数入栈,然后执行函数。c#调用lua就是将c#层的参数和lua函数入栈,然后执行函数

1.1 C#访问lua

直接上代码:

 private void Demo1(){IntPtr L = LuaAPI.luaL_newstate();if (LuaAPI.luaL_loadbuffer(L, @"function addandsub(x,y) return x+y , x-y end", "selfTagChunk") != 0){Debug.LogError(LuaAPI.lua_tostring(L,-1));}//LuaAPI.lua_pushnumber(L,20);//LuaAPI.lua_pushnumber(L,21);LuaAPI.lua_pcall(L, 0, 0, 0);LuaAPI.xlua_getglobal(L, "addandsub");LuaAPI.lua_pushnumber(L,10);LuaAPI.lua_pushnumber(L,7);int valueB = LuaAPI.xlua_tointeger(L, -1);//7int valueB2 = LuaAPI.xlua_tointeger(L, -2);//10LuaTypes luaTypeB3 = LuaAPI.lua_type(L, -3);//functionint valueC4 = LuaAPI.xlua_tointeger(L, 3);//7int valueC3 = LuaAPI.xlua_tointeger(L, 2);//10LuaTypes luaTypeC2 = LuaAPI.lua_type(L, 1);//functionif (LuaAPI.lua_pcall(L, 2, 2, 0) != 0){Debug.LogError(LuaAPI.lua_tostring(L,-1));}int value = LuaAPI.xlua_tointeger(L, -1); //3int value2 = LuaAPI.xlua_tointeger(L, -2); //17LuaAPI.lua_close(L);}

Api备注:

LuaAPI.luaL_newstate:开辟lua虚拟机,执行lua程序
LuaAPI.lua_close:关闭lua虚拟机,释放资源
LuaAPI.luaL_loadbuffer:编译一段lua代码,但没执行
LuaAPI.lua_pcall:执行lua代码,这时候可以用

这里:先把addandsub方法压栈,然后把10和7分别压栈。所以看到的内存里的数据如批注所示。

在执行第2个lua_pcall。会把之前的堆栈信息清空,把函数执行返回的结果进行压栈操作

1.2 lua访问C#

[UnmanagedFunctionPointer(CallingConvention.Cdecl)]public delegate void TestCSFunction(IntPtr L);[MonoPInvokeCallback(typeof(TestCSFunction))]public static void TestLuaCallCSharp(IntPtr L){Debug.Log("TestLuaCallCSharp");}private void Demo2(){IntPtr L = LuaAPI.luaL_newstate();//Marshal 提供对非托管类型的操作IntPtr function = Marshal.GetFunctionPointerForDelegate(new TestCSFunction(TestLuaCallCSharp));//函数入栈LuaAPI.lua_pushcclosure(L,function,0);LuaAPI.lua_pcall(L, 0, 0, 0);LuaAPI.lua_close(L);}

UnmanagedFunctionPointer:定义为了让其不受C#托管管理
MonoPInvokeCallback:标记可以使其用C或C++调用

上述可以看到是把C#函数包装成指针,然后进行压栈操作供lua调用

二.xlua中的LuaEnv

  private void Demo3(){LuaEnv luaenv = new LuaEnv();luaenv.DoString("CS.UnityEngine.Debug.Log('hello world')");luaenv.Dispose();}

LuaEnv:是xlua封装好的lua环境,类似上面的luaL_newstate。

具体的事情:

XLua框架中最重要的一个类,那就是LuaEnv。它包含了lua中的状态机RealStatePrt。lua的G表,还有注册表LuaIndexes.LUA_REGISTRYINDEX等等,下面从LuaEnv的构造函数开始,看看这个类做了些什么事情

//节选LuaEnv构造函数部分代码//拿到Lua中的注册表
LuaIndexes.LUA_REGISTRYINDEX = LuaAPI.xlua_get_registry_index//创建Lua状态机
rawL = LuaAPI.luaL_newstate()//十分重要的一个对象,用于c#和lua的交互
translator = new ObjectTranslator(this, rawL); 
translator.createFunctionMetatable(rawL);	//添加_gc元方法到注册表
translator.OpenLib(rawL);	//将init_xlua中会用到的方法,全部定义出来//添加搜索路径
AddSearcher(StaticLuaCallbacks.LoadBuiltinLib, 2); 
//添加自定义解析Lua文件的方法,对应的是LuaEnv.CustomLoader
AddSearcher(StaticLuaCallbacks.LoadFromCustomLoaders, 3);
#if !XLUA_GENERAL
AddSearcher(StaticLuaCallbacks.LoadFromResource, 4);
AddSearcher(StaticLuaCallbacks.LoadFromStreamingAssetsPath, -1);
#endif//十分重要!! 初始化xLua
DoString(init_xlua, "Init");#if !UNITY_SWITCH || UNITY_EDITOR
AddBuildin("socket.core", StaticLuaCallbacks.LoadSocketCore);
AddBuildin("socket", StaticLuaCallbacks.LoadSocketCore);
#endif
AddBuildin("CS", StaticLuaCallbacks.LoadCS);

调用Init方法:

private string init_xlua = @" local metatable = {}local rawget = rawgetlocal setmetatable = setmetatablelocal import_type = xlua.import_typelocal import_generic_type = xlua.import_generic_typelocal load_assembly = xlua.load_assembly--fqn就是类型和命名空间名,通过import_type去获取对应的udata并且入栈function metatable:__index(key) --查询key不调用元方法,更简单的表达只在自己的表内查询local fqn = rawget(self,'.fqn')fqn = ((fqn and fqn .. '.') or '') .. key--查询C#类型local obj = import_type(fqn)--如果不是 再次查询C#命名空间if obj == nil then-- It might be an assembly, so we load it too.obj = { ['.fqn'] = fqn }setmetatable(obj, metatable)elseif obj == true thenreturn rawget(self, key)end-- Cache this lookuprawset(self, key, obj)return objend--既然是C#对象 就不要再newindex了,避免产生未知的错误function metatable:__newindex()error('No such type: ' .. rawget(self,'.fqn'), 2)end-- A non-type has been called; e.g. foo = System.Foo()function metatable:__call(...)local n = select('#', ...)local fqn = rawget(self,'.fqn')if n > 0 thenlocal gt = import_generic_type(fqn, ...)if gt thenreturn rawget(CS, gt)endenderror('No such type: ' .. fqn, 2)endCS = CS or {}setmetatable(CS, metatable)--定义typeof 这下知道了 typeof是xlua自己搞的,不是lua本身语言特性typeof = function(t) return t.UnderlyingSystemType endcast = xlua.castif not setfenv or not getfenv thenlocal function getfunction(level)local info = debug.getinfo(level + 1, 'f')return info and info.funcendfunction setfenv(fn, env)if type(fn) == 'number' then fn = getfunction(fn + 1) endlocal i = 1while true dolocal name = debug.getupvalue(fn, i)if name == '_ENV' thendebug.upvaluejoin(fn, i, (function()return envend), 1)breakelseif not name thenbreakendi = i + 1endreturn fnendfunction getfenv(fn)if type(fn) == 'number' then fn = getfunction(fn + 1) endlocal i = 1while true dolocal name, val = debug.getupvalue(fn, i)if name == '_ENV' thenreturn valelseif not name thenbreakendi = i + 1endendendxlua.hotfix = function(cs, field, func)if func == nil then func = false endlocal tbl = (type(field) == 'table') and field or {[field] = func}for k, v in pairs(tbl) dolocal cflag = ''if k == '.ctor' thencflag = '_c'k = 'ctor'endlocal f = type(v) == 'function' and v or nilxlua.access(cs, cflag .. '__Hotfix0_'..k, f) -- at least onepcall(function()for i = 1, 99 doxlua.access(cs, cflag .. '__Hotfix'..i..'_'..k, f)endend)endxlua.private_accessible(cs)endxlua.getmetatable = function(cs)return xlua.metatable_operation(cs)endxlua.setmetatable = function(cs, mt)return xlua.metatable_operation(cs, mt)endxlua.setclass = function(parent, name, impl)impl.UnderlyingSystemType = parent[name].UnderlyingSystemTyperawset(parent, name, impl)endlocal base_mt = {__index = function(t, k)local csobj = t['__csobj']local func = csobj['<>xLuaBaseProxy_'..k]return function(_, ...)return func(csobj, ...)endend}base = function(csobj)return setmetatable({__csobj = csobj}, base_mt)end";

设置了metatble扩充原方法,并且设置CS的元表示metatable:

__index:会把C#没有缓存的命名空间下的元数据导入进来。

__call:与index同理,这里能看出来了为什么在lua里调C#方法是CS.UnityEngine.Vector3(x,x,x)。

这步是让lua可以去访问C#对象。

因为在Lua中定义了全局的CS表,并且在lua中调用CS的时候,会先调用StaticLuaCallbacks.LoadCS获取到注册表中的CS表,然后在调用XXX的时候,如果访问到了CS表中不存在的元素,则会调用其元表,在元表中通过映射到c#的StaticLuaCallbacks.ImportType方法完成查找。

lua在查找时调用了import_type进行查找调用,提前在OpenLib里把方法进行注册:

而importType会从中转器查询,查询的过程就是从一个维护的字典里看能不能取到,取不到就加载命名空间并注入到lua虚拟机中。

后面介绍lua与C#之间通信会详解介绍

参考:

Lua与C#交互原理(转)_lua与c#的交互原理-CSDN博客

https://zhuanlan.zhihu.com/p/441169478

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/380664.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Github报错:Kex_exchange_identification: Connection closed by remote host

文章目录 1. 背景介绍2. 排查和解决方案 1. 背景介绍 Github提交或者拉取代码时&#xff0c;报错如下&#xff1a; Kex_exchange_identification: Connection closed by remote host fatal: Could not read from remote repository.Please make sure you have the correct ac…

【Qt】常用控件 Q widget的enabled属性,geometry属性

Qt是一个实现图形化程序的程序。为了便于我们开发&#xff0c;Qt为我们提供了许多“控件”。我们需要熟悉并掌握这些控件的使用。 一.什么是控件 控件是构成⼀个图形化界⾯的基本要素. 示例一&#xff1a; 像上述⽰例一中的,按钮,列表视图,树形视图,单⾏输⼊框,多⾏输⼊框,滚动…

OPC UA边缘计算耦合器BL205工业通信的最佳解决方案

OPC UA耦合器BL205是钡铼技术基于下一代工业互联网技术推出的分布式、可插拔、结构紧凑、可编程的IO系统&#xff0c;可直接接入SCADA、MES、MOM、ERP等IT系统&#xff0c;无缝链接OT与IT层&#xff0c;是工业互联网、工业4.0、智能制造、数字化转型解决方案中IO系统最佳方案。…

硅谷裸机云多IP服务器怎么样?

硅谷裸机云多IP服务器是一种在硅谷地区提供的、具有多个IP地址的裸机云服务器。这种服务器结合了裸机服务器的高性能和云服务器的灵活性&#xff0c;同时提供了多个IP地址&#xff0c;为用户的各种需求提供了支持。以下是关于硅谷裸机云多IP服务器的一些详细信息&#xff0c;ra…

智能硬件——0-1开发流程

文章目录 流程图1. 市场分析具体分析 2. 团队组建2. 团队组建早期团队配置建议配置一&#xff1a;基础型团队 (4人)配置二&#xff1a;扩展型团队 (6人)配置三&#xff1a;全面型团队 (7人) 3. 产品需求分析4. ID设计&#xff08;Industrial Design, 工业设计&#xff09;5. 结…

智慧监狱整体解决方案

智慧监狱整体解决方案摘要&#xff1a; 对智慧监狱的理解 智慧监狱通过集成监控图像资源、报警信息、安防信息和业务信息&#xff0c;实现资源共享和信息互通。构建三级警戒架构&#xff0c;实现分监区、监狱和局级监狱管理局的应急指挥和管理。 发展历程 从2006年至2021年&am…

华为云.VPC关联概念与对等连接实践

云计算.华为云 VPC关联概念与对等连接实践 - 文章信息 - Author: 李俊才 (jcLee95) Visit me at CSDN: https://jclee95.blog.csdn.netMy WebSite&#xff1a;http://thispage.tech/Email: 291148484163.com. Shenzhen ChinaAddress of this article:https://blog.csdn.net/q…

LeNet实验 四分类 与 四分类变为多个二分类

目录 1. 划分二分类 2. 训练独立的二分类模型 3. 二分类预测结果代码 4. 二分类预测结果 5 改进训练模型 6 优化后 预测结果代码 7 优化后预测结果 8 训练四分类模型 9 预测结果代码 10 四分类结果识别 1. 划分二分类 可以根据不同的类别进行多个划分&#xff0c;以…

新时代多目标优化【数学建模】领域的极致探索——数学规划模型

目录 例1 1.问题重述 2.基本模型 变量定义&#xff1a; 目标函数&#xff1a; 约束条件&#xff1a; 3.模型分析与假设 4.模型求解 5.LINGO代码实现 6.结果解释 ​编辑 7.敏感性分析 8.结果解释 例2 奶制品的销售计划 1.问题重述 ​编辑 2.基本模型 3.模…

Python酷库之旅-第三方库Pandas(036)

目录 一、用法精讲 111、pandas.Series.item方法 111-1、语法 111-2、参数 111-3、功能 111-4、返回值 111-5、说明 111-6、用法 111-6-1、数据准备 111-6-2、代码示例 111-6-3、结果输出 112、pandas.Series.xs方法 112-1、语法 112-2、参数 112-3、功能 112-…

基于Centos7搭建rsyslog服务器

一、配置rsyslog可接收日志 1、准备新的Centos7环境 2、部署lnmp环境 # 安装扩展源 wget -O /etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/epel-7.repo# 安装扩展源 yum install nginx -y# 安装nginx yum install -y php php-devel php-fpm php-mysql php-co…

mac二进制安装operator-sdk

0. 前置条件 1. 安装go 安装步骤略。 1. 下载operator-sdk源码包 https://github.com/operator-framework/operator-sdk 1.1 选择适合当前go版本的operator版本&#xff0c;在operator-sdk/go.mod文件中可以查看Operator-sdk使用的go版本。 2. 编译 源码包下载后&#x…

【从零开始实现stm32无刷电机FOC】【实践】【5/7 stm32 adc外设的高级用法】

目录 采样时刻触发采样同步采样 点击查看本文开源的完整FOC工程 本节介绍的adc外设高级用法用于电机电流控制。 从前面几节可知&#xff0c;电机力矩来自于转子的q轴受磁力&#xff0c;而磁场强度与电流成正比&#xff0c;也就是说电机力矩与q轴电流成正相关&#xff0c;控制了…

UDP网口(1)概述

文章目录 1.计算机网络知识在互联网中的应用2.认识FPGA实现UDP网口通信3.FPGA实现UDP网口通信的方案4.FPGA实现UDP网口文章安排5.传送门 1.计算机网络知识在互联网中的应用 以在浏览器中输入淘宝网为例&#xff0c;介绍数据在互联网是如何传输的。我们将要发送的数据包称作A&a…

SpringAI简单使用(本地模型+自定义知识库)

Ollama 简介 Ollama是一个开源的大型语言模型服务工具&#xff0c;它允许用户在本地机器上构建和运行语言模型&#xff0c;提供了一个简单易用的API来创建、运行和管理模型&#xff0c;同时还提供了丰富的预构建模型库&#xff0c;这些模型可以轻松地应用在多种应用场景中。O…

为 android编译 luajit库、 交叉编译

时间&#xff1a;20200719 本机环境&#xff1a;iMac2017 macOS11.4 参考: 官方的文档&#xff1a;Use the NDK with other build systems 写在前边&#xff1a;交叉编译跟普通编译类似&#xff0c;无非是利用特殊的编译器、链接器生成动态或静态库; make 本质上是按照 Make…

哈默纳科HarmonicDrive减速机组装注意事项

在机械行业中&#xff0c;精密传动设备HarmonicDrive减速机对于维持机械运作的稳定性和高效性起着至关重要的作用。然而在减速机的组装过程中&#xff0c;任何一个细微的错误都可能导致其运转时出现振动、异响等不良现象&#xff0c;严重时甚至可能影响整机的性能。因此&#x…

Python+Django+MySQL的新闻发布管理系统【附源码,运行简单】

PythonDjangoMySQL的新闻发布管理系统【附源码&#xff0c;运行简单】 总览 1、《新闻发布管理系统》1.1 方案设计说明书设计目标工具列表 2、详细设计2.1 登录2.2 程序主页面2.3 新闻新增界面2.4 文章编辑界面2.5 新闻详情页2.7 其他功能贴图 3、下载 总览 自己做的项目&…

Flink调优详解:案例解析(第42天)

系列文章目录 一、Flink-任务参数配置 二、Flink-SQL调优 三、阿里云Flink调优 文章目录 系列文章目录前言一、Flink-任务参数配置1.1 运行时参数1.2 优化器参数1.3 表参数 二、Flink-SQL调优2.1 mini-batch聚合2.2 两阶段聚合2.3 分桶2.4 filter去重&#xff08;了解&#xf…

代码解读:Diffusion Models中的长宽桶技术(Aspect Ratio Bucketing)

Diffusion Models专栏文章汇总&#xff1a;入门与实战 前言&#xff1a;自从SDXL提出了长宽桶技术之后&#xff0c;彻底解决了不同长宽比的图像输入问题&#xff0c;现在已经成为训练扩散模型必选的方案。这篇博客从代码详细解读如何在模型训练的时候运用长宽桶技术(Aspect Rat…