自从用了ulua框架 unity3d ulua 教程就卡死 还卡系统

uLua最新的Unity+Lua热更新解决方案!!!【技术综合贴】
精华热门加亮
看了坛子上同学用Kopilua,以为真的跨平台没问题,就实验了安卓手机,然后就开始铺游戏框架,干了一星期到昨晚想起来到ipad上跑跑,然后我跟我的小Demo一起崩溃了。今天搜索luajit,终于在u3d官方论坛终于发现了真正支持IOS+安卓(老外说web也支持,没测试)的插件,有些小兴奋,还是半信半疑的心态测试了下,果不其然运行在我的ipad2上面了,至少我运行代码非常正常。免费给大家上传我测试过的工程,有问题一起研究吧。补上:安卓也测试了游戏框架么问题,能正常使用的。今天在IOS上测试下更新的游戏框架了,问题不大。最近太忙了,没时间过来,为了方便技术交流,有问题请加群:
最新版本下载地址:
& 目前已有众多上线商业游戏使用ulua技术,查看案例 : 势不可挡啊~~~谁与争锋
针对大家的需求,我从当前游戏里剥离出一个迷你游戏框架,传送门:
uLua&SimpleFramework入门视频教程网盘地址(更新中...)
本部分内容设定了隐藏,需要回复后才能看到
感谢大家群策群力,ulua的使用越来越多。我以后会在帖子上贴一些同学们的经验思路,分享给大家。供借鉴。
“”同学基于ulua开发的tolua c#版,co2dx同学懂得。极大提升ulua的效率的插件,懂的入,传送门:
“”同学共享出来的ulua bug fix解决方案,大家不要错过,遇到了直接穿越吧,传送:
“”同学再次共享的Unity3D Lua中使用协程coroutine和计时器timer 传送门:
&&同学深入ulua编译文章uLua运行LuaJIT编译后的bytecode文件 传送门:
来自UnityLua群里“赵欣悦”同学无私奉献的热更新思路:我从最开始说下我的思路吧。通过版本号来判断是大更新还是小更新,游戏初始化的时候,先下载最新版本号和当前版本号比对。如果需要小更新,那么下载一个需要更新的表,通过表去下载各种资源和脚本的AssetsBundle。其中包括了一个数据文件,是当前版本中,会被lua托管的函数列表。然后以函数名作为key存在一个字典中,准确的说是 类名_函数名,这个也是我们所有lua脚本的文件名。在程序运行的时候,每个函数调用最开始判断一下这个函数是否存在于字典中。如果不存在,执行C#脚本。如果存在,判断字典中当前项的TextAsset是否为空,为空的话,从AB中加载,并DoString。如果不为空,直接DoString。这样就执行了更新上去的Lua脚本了,函数就return掉,不执行C#脚本了。新增的所有面板都用同一个C#脚本去管理,这个C#脚本只是lua的入口,可以通过管理器去赋值。
----------------------------------------------------------------------------------------------------------------------------------------------------
但是,发现一些地方需要注意下:
(1)
&local button = child(&buttonName&).gameO
&UIEventListener.Get(button).onClick = OnC
这个事件关联代码在iOS下是报错的,不能够正确执行(安卓没事),感谢同学提示:“这个事件关联代码在iOS下是报错的,不能够正确执行(安卓没事)” ulua的README.txt里最后一段有说明。 所以,只要在CheckType.cs的第一行定义#define __NOGEN__,那么所有平台使用这种代码都会报错了。如果要发布ios平台的话,建议定义上去,方便日常开发。
后发现坛子同学找到添加托管的方法,抄袭一下,希望不介意哈:uLua扩充对delegate的绑定支持
参考nlua中的做法,只需要注册一个委托类型即可,作者将这部分代码合并入了ulua
c#:
&& &class LuaBoolDelegateEventArgsHandler : LuaInterface.LuaDelegate {
&& & & &bool CallFunction(GameObject go) {
&& & & & & &object[] args = new object[] { go };
&& & & & & &object[] inArgs = new object[] { go };
&& & & & & &int[] outArgs = new int[] { };
&& & & & & &return (bool)base.callFunction(args, inArgs, outArgs);
&& & & &}
&& &} & &
& &public delegate bool BoolDelegate(GameObject go);
& &public BoolDelegate OnS
& &RegisterLuaDelegateType(typeof(CallbackTest.BoolDelegate), typeof(LuaBoolDelegateEventArgsHandler));
&& & &public static void RegisterLuaDelegateType(Type delegateType, Type luaDelegateType) &{
&& & & & & &m_LuaState.RegisterLuaDelegateType(delegateType, luaDelegateType);
&& & &}
lua:
&local callbackTest = test:AddComponent(&CallbackTest&);
&callbackTest.OnStart = function (gameObject)
&& & print(&callback sucess!&);
&& & return gameObject.Name ==
&end
但是我们通过Lua通知C#的添加方式,绕过了这个问题。PS:非常感谢同学的下述代码贡献!!!!解决了此问题。
public static void AddClick(GameObject go,object lua){
& UIEventListener.Get(go).onClick += delegate(GameObject o){
& LuaFunction func = (LuaFunction)
& func.Call();
(2)刚才发现一个有关注释的问题,也一并记录下。Lua代码与注释不用同行,否则lua执行会出错,估计跟中文注释有关系。我们的做法是,最终打包之前把所有txt里面的单独行注释铲除掉,即可运行正常了。(如果你的lua代码有中文,打包之前千万删除掉,今天我们测试print里面也不能有中文)
非常感谢同学搞定了中文编码的解决办法呢,非常棒!~,以下是解决方案(借花献佛啦):
Lua.cs Line159
if (LuaDLL.luaL_loadbuffer(L, chunk, chunk.Length, name) != 0)
if (LuaDLL.luaL_loadbuffer(L, chunk, System.Text.Encoding.UTF8.GetByteCount (chunk), name) != 0)
if (LuaDLL.luaL_loadbuffer(L, chunk, chunk.Length, chunkName) == 0)
if (LuaDLL.luaL_loadbuffer(L, chunk, System.Text.Encoding.UTF8.GetByteCount (chunk), chunkName) == 0)
原因就是对于中文等双字节字符,string.Length的返回值是把一个汉字当一个计数的,这样底层的库去parser时候就等于没读完整啦~
这样一个简单的修改就可以让ulua支持中文了,在楼主给的包里修改出中文输入输出已测试通过。 至于其他的读取接口比如读文件啥的貌似直接都用的bytes.Length,理论上没有问题的。 当然,大前提是lua文件本身的编码要存成UTF8。
(3)看到大家很多人开始使用ulua,觉得自己辛苦没白费,当然ulua作者我也不认识,我就是想把新的插件介绍给大家使用,填补上u3d不能热更新的坑。希望大家把ulua还不是很好的地方跟想法报出来,有种贡献,将来你遇到问题了,别人才能也反过来帮你。lua里面是没有等待时间的,至少我比较笨,没有用lua的协同怎么实现等待时间,但是觉得应该可以。我就用lua通知c#等待一段时间后,再反过来调用lua协调的继续函数,来模拟。可能效率会不好,但是没别的想法,有办法的朋友贴上来,补在这后面也好。
(4)关于有些网友问有了unilua,为啥还需要这个?我在这里回答下,别问了哈。unilua是云风团队阿南的作品,想必云大神的技术必然不会差了,尤其在运行效率下,但是,关于怎么通过unilua调用附加在gameobject上的自定义c#脚步一直闹不明白,而且也跑到他们的开源地址问过了,阿南回答我说他也不清楚。有一个运行lua代码的入口的开发方式使用传统的开发模式应该可以,也就是说要全部用lua开发逻辑,目前我还没想到怎么弄,但是想必大家用ngui或者其他组件的人不少,比如我们的《Q灵三国》就是基于ngui开发的,假如修改一个uilabel的text的内容,就不知道怎么办了,即使你是用lua动态创建的文本框,你也改不了,除非你完全不用ngui,而是用u3d的gui来做。ulua解决了我这个难题,导入一下使用的自定义类(导入类之前先载入命名空间:luanet.load_assembly('Assembly-CSharp')才可以的),比如下面的demo类,或者导入一些ngui的组件类(uilabel或者uisprite等),就能让我能顺利的走下去。所以才用ulua来开发。
(5)kopilua跟ulua都是用的luainterface,所以基本上兼容,可是kopilua没有提供错误堆栈跟踪,导致我们的前端跟我抱怨查错很麻烦,对于一个开发的中大型项目来说很累,也经常混淆弄错的地方,ulua提供了错误堆栈跟踪,所以一出错就能看到在什么地方,出了什么问题,减轻了很多不必要的麻烦。
(6)有朋友问怎么用NGUI实现动态界面,这个属于公司技术细节,我不好说太详细,说个大概的思路吧,看大家自由发挥,我们的也未必就是最好的技术解决方案。我们也就是用的Assetbundle,把每个面板Prefab跟与其相对应的lua脚本都打包成一个Assetbudle(相对应的NGUI的Atlas跟材质、纹理都会被打包进去,记得使用关联素材,否则你的资源会重复,而且很大,浪费玩家流量跟内存),然后使用了《Q灵三国》的动态更新系统代码,把最新的面板资源下载到本地,从Assetbundle里面读取Prefab资源出来,然后上面附加一个公用的C#脚本,并且这个C#脚本会启动lua脚本,这样,每个面板都可以自动更新,附加在上面的lua脚本也能动态更新,即可实现对UI的控制。
(7)其实有个很简单的require的替代方案:把lua代码打包进Assetbundle里面的吧,那好,可以在面板的c#桥里面写个函数,就2行代码即可完成了,比如:
void RequireLua(string name) {
& TextAsset luaCode = bundle.Load(name, typeof(TextAsset)) as TextA
& lua.DoString(luaCode.text);
}
每次Lua代码里面需要其他lua,RequireLua('lua2.lua'),然后就可以调用了。这样lua2.lua照样可以动态更新!
(8)感谢Unity Lua群里的“康”同学发现再补充的一个坑:最新发现luainterface还有个bug
local v1=Vector3(1,1,1)
local v2=Vector3(1,1,1)
v1.x = 100
print(v1.x, v2.x)
你会发现v2.x也变成100了。原因是luainterface用dictionary存储的vector, 而dict是用的object.hashcode()
所有的c# object都是存储在dict里的,任何对象的hashcode一样,都可能导致obj是同一个,而Vector的hash实现刚好是用x,y,z的值来计算的726 || this.offsetHeight>700){if(this.offsetWidth/726 > this.offsetHeight/700){this.width=726;}else{this.height=700;}}" style="max-width:726max-height:700" onclick="if(this.parentNode.tagName!='A'&&this.width>screen.width-461) window.open(this.src);" />726 || this.offsetHeight>700){if(this.offsetWidth/726 > this.offsetHeight/700){this.width=726;}else{this.height=700;}}" style="max-width:726max-height:700" title="点击查看原图" onclick="if(this.parentNode.tagName!='A') window.open('http://www.ceeger.com/forum/attachment/1408/thread/16_725_51f569ddf4e5c27.jpg');" />
(9)EntryPointNotFoundException: luaL_newstate是大家遇到最多的错误,这个错误我遇到过,但是有些忘记怎么过它的了,当时没记录下来,后面就没遇到。解决办法:把除了Assets跟ProjectSettings目录之外的都删除掉,重新打开工程。
感谢同学找到问题所在:EntryPointNotFoundException: luaL_newstate这个错误是因为在如果在Unity中是设置了iPhone平台,但是uLua的代码没有排除Editor环境,DllImport错误造成的。
(10)一个是DLL没有找到的问题(DllNotFoundException: ulua),目前得到的结论是,真机没有打包libulua.so进包导致,或者模拟器也有些设置不对。打包的时候把libulua.so打包进libs\armeabi-v7a
(11)关于性能评测问题,很多朋友表达出担心,今天唠叨两句,本身lua就是解释型语言,效率不高,如果非要追求那种跟C++那样极致的编译效率是不现实的,只能靠开发者自己通过各种注意、技巧接近最高性能。就算是Flash Air以及cos2dx也不可能做到百分百的性能相等。那这种热更新(内更新)的代价与换来的运营上的价值,大家可以自己衡量一下的,还有如果过多担心效率问题的话,推荐核心算法可以放在C#里面完成,lua只做单纯单次调用,我觉得即使lua再慢,ulua再垃圾,单次调用c#的一个函数也不可能会慢到大家吃顿饭的时间吧,高强度循环的东东(各种Update)就不要放在lua里面了,这种可以避免很多不必要的性能忧虑,比如我们的Socket消息,有单个消息通知才会push给lua,这样不会慢到家的,放心!更详细的请参考同学帖子
(12)ulua只能适用于PRO版本,免费版没有办法访问原生码。还有就是尽量使用最新的U3D4.3以上+NGUI3.5+版本,最近在做《Q灵三国》的新版更新,计划把活动部分用ulua实现,我们U3D用4.1.2,NGUI用的是2.7,都是老版本的,好多问题,Sharder丢失、强类型Load素材等,因为项目很大,全部升级新版不太简单。新的游戏框架用的U3D4.3以上+NGUI3.5,所以开发起来非常的方便顺利。这个注意的地方,记录一下。
(13)上午完成了《Q灵三国》里面对ulua的限时活动移植工作,在2011年买的HTC G11(单核)手机上测试到现在,总体来说还行,但是的确没有原始版(C#)的流畅。尽量在游戏初始化的时候把所有的lua脚本都初始化好,然后放入一个公共的对象池,游戏进去以后就不要再产生DoString操作了,需要的时候从lua池里面获取早已初始化好的对象,否则性能比较差,体验很糟糕,这个希望大家注意下哈。【经过一天的优化,限时活动的面板弹出(包含Lua逻辑)已经很接近原始性能了,但是还是有些体验差异,不过真的跟ulua关系不大,主要是原来直接从Resource.Load出Prefab,这一次是从AssetBundle文件里载入,性能会有所不同,如果为了缩小更小的差距,可以提前预加载进游戏,但是要管理好内存占用,这是资源管理器的事情】
(13)我觉得哈,反射没有直接在lua里面声明性能来得好,LuaInterface使用的是反射机制,但是有部分反射机制IOS不认可,这也是有些是可以运行的。反射的性能不是最好的,我对cos2dx不是很懂,但是读过一少部分功能lua代码,他就是有些很常用的方法用lua重写了,如果非要用反射实际上是需要付出性能代价的,不是什么都尽量用反射,尽量lua内部能实现的就别用反射,大家慎用吧。
(14)真的是大家群策群力,坛子上的朋友借助ulua开发了flashx利用uLua转成u3d程序的功能,地址:“4.运行unity3d模式可将AS项目轻松转换为u3d项目”从flash转过来的朋友需要学习的话,可以多多参考哈。欢迎更多的网友把自己的框架贴出来,汇总起来。目前很期待同学的quick-unity框架呢!!!
(15)最近很忙,终于有ulua功能的《Q灵》1.4.0版本提审了,有兴趣的可以试一下,目前有2个地方使用了ulua,一个是“活动”-》“限时活动”里面所有的面板程序都是ulua完成的,包括接收消息等,面板打包资源等。第二个地方没有具体的表现,当进入主场景的时候,ulua会得到一次执行机会,有可能新版活动提示啊,会做相应的提示信息。有问题告诉我一声哈。多谢!!
苹果版: & & 安卓版:
726 || this.offsetHeight>700){if(this.offsetWidth/726 > this.offsetHeight/700){this.width=726;}else{this.height=700;}}" style="max-width:726max-height:700" title="点击查看原图" onclick="if(this.parentNode.tagName!='A') window.open('http://www.ceeger.com/forum/attachment/1404/thread/2_725_cc198b259a22b53.jpg');" />
本部分内容设定了隐藏,需要回复后才能看到
共6条评分,
看下,我也试试去
看下,我也试试去
不知效率如何
有空的研究下看看
要评论请先&或者&
好啊,谢谢贡献。
学习学习!!!
kankan......................................................
看着怎么像是广告啊。。。
不错的,了解下
不错的,了解下
看下,我也试试去
什么情况/?
给力啊!楼主~分类目录 (4) (1) (3) (5) (6) (12) (11) (21) (7) (9) (29) (13) (27) (9) (12) (5) (4) (10) (2) (21) (8) (1) (5)腾讯开源手游热更新方案,Unity3D下的Lua编程
作者|车雄生
编辑|木环
腾讯最近在开源方面的动作不断:先是微信跨平台基础组件Mars宣布开源,腾讯手游又于近期开源了Unity3D下Lua编程解决方案——xLua。xLua,何方神圣?有哪些技术细节可以说道说道?
xLua是Unity3D下Lua编程解决方案,自2016年初推广以来,已经应用于十多款腾讯自研游戏,因其良好性能、易用性、扩展性而广受好评。现在 腾讯已经将xLua开源到GitHub。
2016年12月末,xLua刚刚实现新的突破:全平台支持用Lua修复C#代码bug。目前Unity下的Lua热更新方案大多都是要求要热更新的部分一开始就要用Lua语言实现,不足之处在于:
接入成本高,有的项目已经用C#写完了,这时要接入需要把需要热更的地方用Lua重新实现;
即使一开始就接入了,也存在同时用两种语言开发难度较大的问题;
Lua性能不如C#;
xLua热补丁技术支持在运行时把一个C#实现(函数,操作符,属性,事件,或者整个类)替换成Lua实现,意味着你可以:
平时用C#开发;
运行也是C#,性能秒杀Lua;
有bug的地方下发个Lua脚本fix了,下次整体更新时可以把Lua的实现换回正确的C#实现,更新时甚至可以做到不重启游戏;
这个新特性iOS,Android,Windows,Mac都测试通过了,目前在做一些易用性优化。那么,腾讯开源的xLua究竟是怎样的技术?它是为何如此设计的?更令人关心的是,xLua的性能如何?带着这些问题,InfoQ对其作者进行了采访并将内容整理成文。
腾讯自研手游,就我了解的项目来说,大多数游戏引擎都是Unity3D,少数用coco2d。
xLua这个插件具体用到了哪些游戏中?虽说xLua是2015年3月就完成了第一个版本,但由于当时项目组热更的意识并没有很普遍,需求不是很强烈,xLua的开发资源都调到更紧急的项目了。直到15年年底正式集成到我们的apollo手游开发框架,才迎来xLua的第一个项目。到目前为止,我们已知的应用了xLua的项目有十多个,其中不乏一些重量级IP,或者按星级标准打造的产品。
在xLua之前,面对iOS无法热更新的问题,有用ulua的,有用slua的,也有项目用自研的脚本语言,不过当时用人更新的项目也不多。
热更新流程
手游的热更新流程很简单,只是启动时检测下是否有新版本文件,有的话就下载覆盖老文件,然后启动。
下载的文件如果是图片,模型这些是没问题的,但如果是Unity原生的代码逻辑,无论是以前的Mono AOT或者后来的il2cpp,都是编译成native code,iOS下是跑不了的。解决办法就一个,别用native code,别用jit,解析执行就可以了。包括xLua在内的所有热更新支持方案都是通过“解析执行”来实现代码逻辑热更新。
来自xLua的 Hello world
三行代码跑lua脚本
一个完整的例子仅需3行代码:
下载xLua后解压到Unity工程Assets目录下,建一个MonoBehaviour拖到场景,在Start里头加上这么三行:
XLua.LuaEnv luaenv = new XLua.LuaEnv();luaenv.DoString("CS.UnityEngine.Debug.Log('hello world')");luaenv.Dispose();
运行就可以看到Console打印的hello world。
第一和第三行分别LuaEnv的创建以及销毁,所谓LuaEnv可以理解为lua虚拟机,往往整个工程一个虚拟机即可:
DoString里头可以是任意合法的lua代码,例子中调用了UnityEngine.Debug.Log接口打印了一个log(C#的静态函数在CS下直接可用);
C#调用lua系统函数math.max
xLua支持把一个Lua函数绑定到C# delegate。
我们先声明一个delegate,并为它加上CSharpCallLua标签:
[XLua.CSharpCallLua]public delegate double LuaMax(double a, double b);
然后在上面那例子加上这么两行(luaenv销毁前):
var max = luaenv.Global.GetInPath&LuaMax&("math.max");Debug.Log("max:" + max(32, 12));
就那么简单,把lua的math.max绑定到C#的max变量后,调用就和一个C#函数调用差不多了,而且,最最重要的是,执行了“XLua/Generate Code”后,max(32, 12)调用是不产生(C#)gc alloc的,既优雅,又高效!(更详细的可以看XLuaDoc下的文档。)
xLua全局观
易用性:编辑器下无需生成代码支持所有特性
xLua的易用不仅仅体现在编程,还体现在方方面面的细节考虑,甚至考虑到团队配合工作流。xLua仅有两个菜单选择,分别是生成代码和清除生成代码。在菜单之外,甚至只需要在build手机版本前执行一下“Generate Code”即可(这也有API可集成到项目的自动化打包流程)。
这就是xLua的特色功能之一:编辑器下无需生成代码支持所有特性。之所以做这个功能,是因为有的项目反馈,“生成代码”对于策划美术太过遥远,教了很久还是老忘;还有个大项目反馈说由于代码很多,每次生成代码后,Unity3D都要转很久。
扩展性:授之以鱼,不如授之以渔
开发中我们往往要用到很多东西,比如用PB和后台交互,解析json格式的配置文件等等。虽说我们都可以在C#那找到相应的库,然后通过xLua去使用这些库,但这效率不高,最好能有相应Lua的库。
不少方案是直接集成一些常用的Lua库,但这带来些新问题:这些库不一定用到,却增大安装包;集成的库也不一定符合项目习惯:json解析有人喜欢rapidjson,有人爱用cjson,所谓众口难调;对于某些项目,这些库还是不够,还是得自己去想办法加;
腾讯团队的设计原则是授之以鱼,不如授之以渔,因此xLua:
提供了接口、教程,在不修改xLua代码的情况下,开发者可以根据个人喜好加入库;
通过cmake实现跨平台编译,可以选择伴随xLua一起编译,修改一个makefile文件,搞定各平台编译。
除了很方便加入第三方Lua插件,xLua的生成引擎支持二次开发,可以编写生成插件,生成自己所需的一些代码以及配置。
性能的保证
游戏的性能备受关注,因此任何模块的变化都需要尽可能不降低甚至调优游戏整体的性能。xLua设计原则是在保证运行效率的前提下,尽量的保证开发效率。
对于性能这块,有几个至关重要的版本:
第一个版本1.0.0在05年3月份发布,当时delegate,interface作为最主要的C#访问Lua的设定,从接口层面避免了boxing、unboxing、gc alloc,这是一个良好的起点。做一个通用组件的都知道,接口一开始设计不合理导致的问题很难解决,别人已经用了,甚至已经养成习惯了,很难纠正。
ps:说起这习惯,有的从别的lua插件转为使用xLua的童鞋,一开始习惯用LuaFunction.Call去调用lua(xLua也保留了这接口,可用于性能要求不高的场合),他们后期就痛苦了,还得一个个地方的改回来。
第二个很重要的版本是2.0.0(06年3月发布),这版本主要目标就性能优化,因为当时有个对性能要求极其严苛的项目想用lua,严苛到什么程度呢?他们觉得C#性能都不放心,战斗系统打算用C++写。那版本我们把虚拟机切换到luajit,加入了lazyload技术,逐行语句的优化,甚至关键地方不用C#提供的容器,自己写专用的(比Dictionary实测性能高4倍)。。。可以认为我们重做了一个xLua。最终他们的选型测试结论是选xLua。
后来和一些项目的交流发现,项目组很关注gc alloc这指标,甚至比lua和C#间的互调性能指标还要看重。于是有了2.1.0版本(06年7月发布),这版本主要目标是gc优化,我们重写了反射,反射调用的gc减少到原来的几分之一,性能提高了3倍左右。我们设计了一个全新的复杂值类型支持方案,该方案支持的类型更多(只要struct的字段都是值类型即可),包括用户自定义的struct(别的方案都不支持),也更省内存(Vector3为例,内存占用只有别的方案的30%)。
但也有劣势的地方,比如你调用Vector3上的一些方法,会比ulua、slua要差,因为后面两个把Vector3用lua重新实现了,这类耗时不大的运算相比lua和C#直接的适配成本小太多了,直接在lua做更划算,不过这差距仅限于那几个ulua、slua完全重新实现的类。
上面只是三个重大节点,我们觉得性能是一个需要持续关注的点:平时想到一个好点子,就会改改,测试下,有提升就加入;建立性能基线,防止某个新功能的加入,某个bug的修改把性能给改坏了。
xLua内置Lua代码profiler;支持真机调试。目前lua profiler只是一个小工具,所以没有做图形化界面,典型的一个报告如下:
网上也有类似的工具,我们这个的优势是对C#函数的支持以及luajit下更为准确。
真机调试支持各lua插件都一样,就是把ZeroBraneStudio调试需要用到的luasocket库预先编译进去而已,没什么值得介绍的地方。
技术实现的细节
泛型类型除了运行时动态实例化之外都支持,而运行时动态实例化需要jit的支持,iOS下行不通。举个例子,如果你配了对Dictionary 生成代码,那这个类型是可以用的,但如果你新更新的lua代码,想用一个Dictionary ,这个类型之前没生成代码,而且C#里头也没任何地方使用过,这就不支持。静态实例化的泛型,其实和非泛型类型处理上没区别。
委托事件的封装
委托封装是根据委托的接口生成一段操作lua栈的代码作为委托的实现。举个例子就很好懂了。比如对于委托:delegate double Add(double a, double b),我们生成如下代码:
public double SystemDouble(double a, double b){ RealStatePtr L = luaEnv.L; int err_func =LuaAPI.load_error_func(L, errorFuncRef); LuaAPI.lua_getref(L, luaReference); LuaAPI.lua_pushnumber(L, a); LuaAPI.lua_pushnumber(L, b); int __gen_error = LuaAPI.lua_pcall(L, 2, 1, err_func);if (__gen_error != 0) luaEnv.ThrowExceptionFromError(err_func - 1); double __gen_ret = LuaAPI.lua_tonumber(L, err_func + 1); LuaAPI.lua_settop(L, err_func - 1); return __gen_}
这代码把调用转给lua函数,调用委托就是调用这函数。
其它方案都有delegate的支持,一般仅用于在lua侧主动传递/设置一个lua函数到C#,而xLua支持更为完整,比如:
支持C#主动用delegate来引用一个lua函数。用delegate代替类似object[] Call(params object[] args)的接口调用lua最大的好处是可以避免值类型传递时的boxing/unboxing,还有参数数组,返回值数组的gc alloc;
支持返回delegate的delegate,可对应到lua的高阶函数;
作为这技术的一个延伸,xLua支持用一个c# interface引用一个lua table,这个特性和一些IOC框架配合可以实现C#和Lua间无感知(模块间都通过interface耦合,然后由框架去组装)。
无缝支持生成代码及反射
生成代码固然重要,已然是各大主流方案的标配。
反射有的方案明确不支持,但从项目的反馈来说,也是至关重要的:有的项目代码很多,已经接近苹果的80M Text段的限制,对他们来说,代码量大小关乎到能否发布,反射方式性能不如生成代码,但对安装包影响小。
这的无缝有两个含义:
两者在支持的特性以及特性的使用方式都是一致的,两者方式间切换,业务逻辑代码不用修改,改改配置就可以了;
两者无缝配合,比如一个继承链上,任意一个类都可以选择生成代码或者反射,比如子类选择生成代码,父类由于不常用选择了反射,还是可以在子类对象上调用父类的方法;
对于il2cpp的stripping,xLua也考虑到了,只要你对一个类配置了ReflectionUse,会自动生成Unity的link.xml配置文件,将该类型列为不剪裁。
其他Lua插件一览
在xLua之外,还有其他的Lua插件,如 uLua、SLua、C#light等。
(1) ulua应用项目是最多的,由于开源得早,名气也最大,这是它很大的优势。腾讯也有项目用ulua,反馈比较多的问题是它版本的前后兼容问题:
ulua最早是一个叫LuaInterface开源库的Unity移植,在2015年初换成cs2lua,又在2016年初换成tolua c#,只所以说“换”,是因为这从API角度看可认为三个不同的产品,它们间很难升级,而且是每换一次,之前的版本就彻底不维护了,这给项目带来很大的困扰。
ulua的第一个版本纯反射,并不实用,已经淡出市场,现存应用用后两个版本居多。cstolua版本接口比较混乱:它保留了第一版ulua接口之余,搞了一套新接口,这两套接口之间并不正交,也不是后者完全替代前者,让人有点无所适从。到了tolua c#版本,这问题解决了,但同时也把反射特性(老接口)给废了。不过总体来说,ulua在向好的方向走。
(2) slua代码质量比cstolua好很多(很多人当时选slua的理由),部分支持反射。性能按我们的测试用例整体比tolua c#略低,另外代码质量对比tolua c#已经形成不了明显优势。
(3) C#light,个人觉得主要有两个不足:
按其实现原理来说,性能不会靠谱,到不了手机上实用的地步;
由于不完整支持C#,本质上只是另一种叫C#light的语言(C# like?名字倒很贴切),这两者代码配合起来也复杂,甚至它能做到比C#和lua配合更复杂些
事实也证明了,C# light基本淡出市场,可以忽略不计了。
(4) LSharp是C# light作者的后续作品,倒是可以期盼些,从il层面执行,这两个问题有望改善,可惜后面没了下文(不维护了)。
相比之下,腾讯在设计xLua时,实现的功能更全,这“全”体现在C#的特性支持得更全些,lua虚拟机版本支持更全;更易用些,比如编辑器下不用生成代码;另外,性能也不比它们差。
说到功能更全,可能有人抱怨并没有pb,json,sqlite等等功能。其实稍熟悉lua的人都知道,那只是把一些现成lua扩展编译进去而已,算不上是它做了这些功能。预集成好处是方便,坏处是没选择的余地,用不上的东西会占空间,用得上的东西也不一定是你喜欢的库。
xLua的lua库基于cmake编译,要加这些库门槛很低,有教程,改一个Makefile搞定各平台编译。在C#测也提供了api来初始化这些库。总而言之,xLua的原则是授之以渔。
xLua的灵感来源
xLua立项当初,考察了当时能找到的所有方案,并分析各方案优劣,定出第一个版本的特性,大体是基于NLua基础上加上代码生成。介绍下NLua,NLua的作者就是LuaInterface的作者,NLua可以认为是LuaInterface的升级版,而前面也说了,第一版uLua是LuaInterface的Unity移植版本,也不能算原创。
因为是“站在”生成代码当时有看过cstolua的实现(那时还没挂ulua的牌),觉得它通过硬编码字符串拼接的方式维护性不太好,就用模版来做。感觉这步是走对了,后续生成代码调整起来比较简单,这对性能调优很有好处。
经过十多个版本的迭代,优化,现在NLua的影子比较淡了(NLua仅支持反射,而xLua的反射在2.1.0版本已经完全重写),就剩下C#引用类型对象在lua的表达的思路没变。
此外,遇到需要调整较大的bug,我们也会先看同类插件是不是已经解决了,对比他们的修改方案和我们的,选更适合的。
xLua背后的研发与团队
xLua目前迭代了十多个版本,从第一个项目开始,平均一个月一个版本。研发团队人员目前有一个全职开发。测试使用的是腾讯互娱的公有资源,很规范:有一套不断补充的功能自动化用例,性能测试也建立了基线,确保不会因为功能迭代而影响性能。腾讯互娱有专门的客户端兼容性测试实验室,至少中版本号以上的变动我们会提交给他们针对top 100的机型进行兼容性测试。
至于lua,luajit的更新跟进,先说luajit吧,luajit变动不大,我第一次用luajit是11年,那时支持到lua5.1,现在也还是lua5.1,中间只是一些bug的修复,性能优化,或者新平台支持等,我们要做事情不多。而lua中版本间差别还是蛮大的,但中版本变动并不频繁,从5.1到5.2用了6年,从5.2到5.3用了3年,5.3是2015年初发布的,我个人觉得到下一次中版本变动会很久,不亚于甚至大于5.1到5.2的时间跨度(5.2个人认为只是一个过渡版本)。
小版本一般改改bug,等稳定后直接升级就可以了,不需要做很多事情,目前xLua的lua版本用的是lua的最新版本5.3.3。
聊聊C#,谈谈Lua
C#在开发效率和运行效率平衡得很好,语言特性也比较全,个人觉得是很优秀的一门语言。在Unity3D上的缺憾主要是其mono版本太低,一些很古老的bug,比如著名的foreach性能问题很多个版本都没解决,新的特性,比如await又不支持。
另外在手机平台iOS不允许应用下载native code运行,jit,刚好把mono应用的热更新给堵死了,要是mono虚拟机能够做到像luajit那样,jit走不通就用interpret模式,其实就没lua或者其它热更新方案什么事了。
而lua被称为游戏脚本之王,在游戏领域应用比较广泛,它设计之初就考虑到嵌入式领域,比如相对它提供的特性来说,它体积非常小,启动一个vm占资源也不多,性能也是脚本里头的佼佼者。
lua相对C#而言,首先是它支持解析执行,进而支持热更新。而免编译对开发效率提升也是蛮大的,特别是较大的项目。
lua的动态类型有利有弊,好的是没有编译期的类型检查,快速开发比较有优势,特别在需求三天两头就变的游戏领域。缺点是要做出健壮的软件得有大量的测试来保证,还有由于要做运行期检查,性能会比静态类型语言低。
lua的一大特色是语言级的协程(coroutine)的支持,比Unity3D基于generator模拟的协程要好很多,对于复杂异步业务逻辑编写很有帮助,xLua的配套例子有范例(ps一下,Unity3D的mono版本升级到支持await的话,是更理想的异步方案)。
至于C#和lua间如何配合,可能每个人都有不同的看法,但至少有一点是确定的:需求变更大,预计很可能需要热更的地方,用lua。当然,也可以尝试最新的开发模式,全C#开发,lua fix bug。
xLua应该还有不足,我们会在发现的第一时间去修改。腾讯xLua团队极度欢迎大家在发现不足之后提出反馈。
车雄生,05年毕业,在华为工作了6年,跟着先后在两游戏创业公司待了几年,15年进入腾讯互娱公共组件中心。目前专注于一些游戏公共组件的开发。
QCon是由InfoQ主办的全球顶级技术盛会,每年在伦敦、北京、东京、纽约、圣保罗、上海、旧金山召开。
QCon北京2017将于4月16日~18日在北京·国家会议中心举行,精心设计了支撑海量业务的互联网架构、大规模网关系统、微服务实践、快速进化的容器生态、智能化运维、互联网广告系统实践、大数据实时计算与流处理和金融科技转型与未来等30来个专题,涵盖架构、大数据、云计算、移动、前端、人工智能等热点领域,将邀请来自Google、Facebook、阿里巴巴、腾讯、百度、美团点评、爱奇艺等典型互联网公司的技术专家,分享技术领域最新成果。 戳「 阅读原文 」,直通官网了解更多!
点击下方图片即可阅读
投行交易系统的定海神针——金融市场数据平台的架构设计之道
责任编辑:
声明:该文观点仅代表作者本人,搜狐号系信息发布平台,搜狐仅提供信息存储空间服务。
今日搜狐热点}

我要回帖

更多关于 unity ulua下载 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信