如何评价腾讯在Unity下的xLua(开源)热更方案?

Github:Tencent/xLua Info:腾讯开源手游热更新方案,Unity3D下的Lua编程
关注者
1,491
被浏览
357,163

37 个回答

xLua的作者,关注这帖子一阵子了,一直犹豫作为作者回答这问题会不会有卖瓜之嫌。

回下大家关注的热补丁的overhead。

热补丁的基本原理其实非常简单,了解后任何程序员都很容易分析出开销,比如对于这个类

public class Calc
{
    int Add(int a, int b)
   {
        return a + b
   }
}

打了hotfix标签后,xLua会在il层面注入代码,注入之后这个类会类似这样:

public class Calc
{
    static Func<object, int, int, int> hotfix_Add = null;
    int Add(int a, int b)
   {
        if (hotfix_Add != null) return hotfix_Add(this, a, b);
        return a + b
   }
}

如果lua中执行了hotfix调用,hotfix_Add会指向一个lua的适配函数。

性能开销:

如果不打补丁,就一个if判断,比注入前多执行两条很轻量级的指令(Ldsfld,Brfalse),我在window下测试,这两指令加起来仅相当于空函数调用开销的十分之一到五分之一。

内存开销:

每个函数会多一个静态delegate引用,注意是静态的,和对象实例个数无关。(Stateful方式会略不同,后面单独分析)。

安装包影响:

一般情况,就一个if和delegate调用。如果泛化函数以及参数含非public类型参数或返回值的函数会多一点:每一个输入参数,每个输出参数,对应一次函数调用,外加三次函数调用。

很难有“增加百分之多少”的数据,因为这和你程序函数的粒度有关。有童鞋在尝试为NGUI全部类型加Hotfix标签来测试,有数据我可以更新上来。

Stateful方式

这个方式的开销和基本和Stateless一样,一个地方除外:内存开销上每个对象实例会增加一个LuaTable的引用(引用而已,不会帮你new一个LuaTable实例,你没在构造函数那返回一个table,这个引用为空)。

关于开源

当然,这决策来自领导,但我个人也有点小想法:

xLua在内部推广使用的过程中,深感项目的挑剔、指责和各种场景下的折腾才是一个通用组件快速进步和完善的动力。开源,无疑是把这放大化,也更加有利于xLua的健康发展。

有人邀请,我来谈谈我得看法,利益相关,slua作者,同时也是才去没多久的tencent员工。


之前没看过xlua代码,首先来分析xlua如何做到“平时用c#开发,需要热更新时用lua代码做热更新”,我粗略思考至少有2种方法。


1)代码生成cs stub函数,为每个hotfix标签的类,导出一个stub,形式类似这样:


namespace xlua.UnityEngine
{
public class GameObject {

UnityEngine.GameObject self;

GameObject() {
self = UnityEngine.GameObject()
}

static public GameObject Find(string s) {
if(hasHotFixFor("GameObject.Find"))
return runHotFix("GameObject.Find",s);
return UnityEngine.GameObject.Find(s)
}

public public string SomeFoo(params object[] args) {
if(hasHotFixFor("GameObject.SomeFoo"))
return runHotFix("GameObject.SomeFoo",self,args)
return self.SomeFoo(args);  
}
}
}

需要在il2cpp,或者别的什么地方,能切换 上层代码的 import UnityEngine为 import xlua.UnityEngine.

2)il2cpp 的cpp代码生成stub,这样仅需要stun function,不需要包装一个class,代码形式和上面类似,只不过是cpp的il2cpp调用写法。


下面谈谈我对lua的理解和xlua的看法

我认为xlua的概念很好,很多人用lua就是为了热更新,如果没有热更新的需求,大多数人是不喜欢lua,或者所谓的脚本开发的,xlua很好的解决了这部分人得需求。

但我有一点其他看法,我04年毕业在网易工作的时候,网易的游戏都是基于脚本的,不管是客户端,还是服务器端,那个时候不是lua,就是python,还有一种是类似c语法的脚本(我忘记名字了),这个是云风主导的,当时选择脚本作为逻辑开发语言的核心想法**不是为了热更新**,而是解决

1)划分引擎层和业务层,svn管理好权限,让新来的同学,接触不到核心引擎的代码权限,他们只能在脚本层做业务,等你对业务足够熟悉,对引擎足够了解,对公司足够忠诚后,才开放引擎层代码,这么做早年是为了解决私服问题,很多同学拿着全部源代码去架设私服,这多可怕,所以做业务的程序员只能拿到一个编译后的app和一份脚本接口文档,而编译出来的app会检查线上ip,报告非法服务器地址等,协助打击私服。

2)避免书写不好的c、cpp代码崩溃整个进程,脚本代码出错了,最多影响局部逻辑,还可以上报脚本错误,方便后续解决问题,现在unity里也一样,如果c#代码书写不好,就直接闪退了,不如用lua做一个安全的调用层。

3)快速修改代码,快速跑起来,早年cpp代码编译速度比较慢,修改一行代码调试运行等半天,脚本代码方便修改,方便跑起来,不用等,放到今天也一样,同时iOS还有text size大小的限制,太多的stub function会撑大text size,而lua脚本再多的代码也不会有这个问题,不用再为了text size取舍代码怎么写,功能去留的问题。

4)反外挂,对,你没看错,反外挂,早年PE各种脱壳、反编译工具,使得一个exe几乎没有秘密,外挂作者很容易做外挂,而用脚本后,几乎所有逻辑都是中间代码,这部分中间代码可以通过修改opcode,加密,一边run,一边解密等技术,保证在进程空间内基本没有完成代码存在,对外挂作者是个很大挑战,所以网易的游戏反外挂历来做的都是最好的;

5)最后才是所谓的“热更新”, 当年也不是现在这种热更新,就是每次客户端启动的时候,有一个launcher去服务器下载一个update,然后应用这个update而已。

说了这么多,我想说啥呢,我想说,其实用脚本开发是另外一种架构设计的方法,不是简单为了热更新,当你习惯了用脚本开发作为第一语言开发时,你会自然爱上lua这种设计精巧的语言,无论从设计范式,语言和数据无缝整合,到lua语言强大的描述能力等等,你都自然不自然的把身边所有东西都lua化,而不是为了热更新,即便lua跑起来不如native code快。

最后还想说一个,lua架构的优势

6)远程调试,你可以在获得玩家授权后,随时连线调试线上玩家的运行状态,方便最直接的定位问题和分析现场,比打log更直接,更快速。


关于运行效率

之前在网易,前端后端都是脚本,甚至是更慢的python,网易最新的天下手游引擎,也是基于python的;腾讯这边,服务器几乎清一色cpp,客户端也是这2年才部分lua脚本化的,之前都是native开发,服务器脚本化,我估计是不可能了(其实服务器对coredump的要求更高,脚本化获得的好处更大),究其原因,回答几乎都是担心效率。

以我多年游戏开发经验来说,脚本的运行效率绝对不是游戏运行效率的瓶颈,经过良好的设计的游戏引擎,都是思考过什么应该引擎层做,什么应该脚本化,如何优化脚本效率,如此这样后,即可以获得上面提到的优势,又不会影响运行效率,一般游戏运行效率都是渲染、加载、裁剪等导致的,和脚本半毛钱关系没有,真得需要速度的代码,可以cpp实现了,导出给lua使用,比如寻路,但不熟悉的开发人员,都会把这个锅推给脚本,因为这样他们什么也不用修改,什么也不用优化。


最后来谈谈对xlua提出的概念的看法

xlua提出的概念,是平时开发用c#,需要热更新时用lua来更新对应的函数,这个概念很好,但我对其实际使用中表示疑虑:

1)如果c#代码都是10行左右的小函数,还好,如果是上百行的大函数,需要更新的时候,首先要把上百行的c#代码转换为lua代码,在fix lua代码里的bug,这个过程本来fix c#代码或者已经存在的lua代码可能只需要2分钟,但临时转换上百行lua代码的时间,我估计1天都搞不定,除非再配合一个自动c# -》lua代码的转换器,不过,确实有cs to lua的转换器,也是tencent内部搞出来的,参考这里dreamanlan/Cs2Lua ,目前该项目默认转换为slua 代码。

2)即便存在c#-》lua代码转换器,也不意味着所有c#代码都可以无缝转换为lua代码,有太多c#支持的特性,lua不支持,这势必要在c#代码层面,规定若干规范,否则无法hotfix,但再没试图hotfix前,很难了解该方法是否可以hotfix。

3)一周一更新的高频维护怎么办?貌似使用c#开发,lua hotfix,仅适合周期较长的大版本更新。


综上我认为xlua提出了一个好的概念,但存在一些问题,但瑕不掩瑜,xlua开源也为游戏开发作出了贡献,腾讯在开源领域更进一步,可喜可贺。