xLua热更方案

前言:

一直没有做过Lua相关的商业项目,这次总算有机会得到这个机会,并且对游戏前端用xLua进行了实现。

之前在业余的时间里自己经常练手写一些关于uLua的东西,但真正工作用起来,发现业余玩一玩的练手方式其实还是不够的,需要多实践。

之前所了解的一些热更的方案有LuaJit、uLua、sLua、xLua、L#(C# Light)等,最终我们选了xLua的方案。

原因:

1、据我所知,LuaJit和Lua并不是同一门语言。

2、uLua:据我所知,uLua是当前速度最快的Lua,但它所存在的缺陷就是uLua的分支版本多,造成了不统一的现象。

3、sLua:不熟悉。

4、xLua:作者和云风撕了一场大逼,性能上可能并不如uLua,也可能会让大家产生撞大运编程的即视感,不过由企鹅主导维护,并且只有一个版本,对开发者还算比较友好。

5、L#:李中二是个懒虫,踏马赛克的都不维护了。

每种语言或者插件,都有各自的优势,所以它才会有人用。

xLua的优势:http://www.gad.qq.com/article/detail/24967

GitHub地址:https://github.com/Tencent/xLua

正题:

重点强调:不要在意我的实现方式,因为我还没去做优化,暂时只是简单的做出来,我也是完全靠个人领悟,目前我也没弄到可直接运行供我参考的可热更的Lua资源,我正在努力的做我的第一个关于Lua的商业作品,我也很纠结,说多了都是泪啊。

1、用法和uLua相似,导进来就行,具体用法大家看官方教程吧,xLua下载下来后里面有文档。

2、同样不支持JIT,今天就在通讯的泛型上面有一些困惑,最终问了作者,不支持JIT,原因:为了支持IOS而不能使用JIT

3、Lua调用C#的类型映射类似下图的方式,需要什么加什么(例子在官方工程的ExampleGenConfig.cs里面)。

4、C#调用xLua,观察者模式下传递委托会出现异常,有可能是因为这个委托的类型没有配置(例子在官方工程的ExampleGenConfig.cs里面)。

这个委托类型是我自己加上去的,我在观察者模式上用到这个委托的回调。

5、挂载xLua脚本。

xLua的方案中,unity挂脚本是通过一个LuaBehaviour.cs来作为主控挂载xLua的脚本,按照unity的思维,应该是可以同时挂载多个脚本,所以我对xLua的LuaBehaiour.cs做了一点点的调整。不要在意我的实现方式,因为我还没去做优化,暂时只是简单的做。

    void Awake()
    {
        LuaEnv luaenvScriptCtrl = new LuaEnv();
        if (luaAssetRoot == null)
        {
            luaAssetRoot = Assets.InstantiateTextAsset(GameData.gameInfos.selectGameInfo.resPathOf("LuaScriptList.lua"));
        }//获取一个Lua脚本LuaScriptList.lua,这个脚本里存放的是prefab的名字和脚本名字的键值对,一键可对多值,因为一个GameObject可以挂多个脚本。
        luaenvScriptCtrl.DoString(luaAssetRoot.text);
        string thisName = this.gameObject.name.Replace("(Clone)", "");
        thisName = thisName.Replace("(Clone)", "");//去掉克隆字样,括号可能是半角或者全角都作处理
        string scriptStrs = luaenvScriptCtrl.Global.Get<LuaTable>("LuaScriptTable").Get<string>(thisName);//从LuaScriptList.lua中取出自己的配置表
        string[] scriptArray = scriptStrs.Split(‘|‘);//解析我这个Prefab用哪些lua脚本。
        foreach (var s in scriptArray)
        {
            if (luaScripts == null)
            {
                luaScripts = new List<TextAsset>();
            }
            luaScripts.Add(Assets.InstantiateTextAsset(GameData.gameInfos.selectGameInfo.resPathOf(s)));
        } //将解析出来需要加上去的脚本统一加上去。
        #region 官方例子里的内容,我先括起来。
        scriptEnv = luaEnv.NewTable();

        LuaTable meta = luaEnv.NewTable();
        meta.Set("__index", luaEnv.Global);
        scriptEnv.SetMetaTable(meta);
        meta.Dispose();

        scriptEnv.Set("self", this);
        if (injections != null)
        {
            foreach (var injection in injections)
            {
                scriptEnv.Set(injection.name, injection.value);
            }
        }
        #endregion

        if (luaScripts != null)
        {
            foreach (var item in luaScripts)
            {
                luaEnv.DoString(item.text, "LuaBehaviour", scriptEnv);
                luaAwake += scriptEnv.Get<Action>("awake");
                luaStart += scriptEnv.Get<Action>("start");
                luaUpdate += scriptEnv.Get<Action>("update");
                luaOnDestroy += scriptEnv.Get<Action>("ondestroy");
                luaOnEnable += scriptEnv.Get<Action>("OnEnable");
                luaOnDisable += scriptEnv.Get<Action>("OnDisable");
            }//将xLua的运作方式改成和unity monobehaviour一致。
        }
        if (luaAwake != null)
        {
            luaAwake();
        }

    }

剩下的start、update等等函数也需要做一点处理。

   // Use this for initialization
    void Start ()
    {
        if (luaStart != null)
        {
            luaStart();
        }
    }

    // Update is called once per frame
    void Update ()
    {
        if (luaUpdate != null)
        {
            luaUpdate();
        }
        if (Time.time - LuaBehaviour.lastGCTime > GCInterval)
        {
            luaEnv.Tick();
            LuaBehaviour.lastGCTime = Time.time;
        }
    }

    void OnDestroy()
    {
        if (luaOnDestroy != null)
        {
            luaOnDestroy();
        }
        luaOnDestroy = null;
        luaUpdate = null;
        luaStart = null;
        if (scriptEnv != null)
        {
            scriptEnv.Dispose();
        }

        injections = null;
    }

    private void OnEnable()
    {
        if (luaOnEnable != null)
        {
            luaOnEnable();
        }
    }

    private void OnDisable()
    {
        //this.gameObject.SetActive(false);
        if (luaOnDisable != null)
        {
            luaOnDisable();
        }
    }

6、跑起来之前先要做一个wrap操作。

选项1、生成wrap等。

项选2、清除wrap等。

选项3、使用类或者方法的热更:该项功能主要是打补丁,比如替换C#的某个方法或者某个类。

7、跑起来时LuaBehaviour的效果。

使用热更的那个游戏服务器关了,游戏进不去了,下回再补上。

6点30下班都走了,服务端的走了没法开了,真的没加班。

另外公司招会unity+lua的熟手,有大神愿意来吗,薪资保证你满意,虽然薪资不是我说了算。

8、Lua代码

这种代码的写法我真的很难受GameLogic2007.lua.txt。

Singleton = {}
function Singleton:new(o)
    o = o or {}
    setmetatable(o,self)
    self.__index = self
    return o
end

function Singleton:Instance()
    if self.instance == nil then
        self.instance = self:new()
    end
    return self.instance
end

GameLogic2007 = Singleton:Instance()
-----以上代码表示我是个单例。
function awake()
    GameLogic2007.s = HandleGetClientSetting2007  --HandleGetClientSetting2007这里赋值的话也就是可以用GameLogic2007.s来调HandleGetClientSetting2007,
end--相当于unity的Awake

function start()
    print("startStart!")
    local nullBodyContract = CS.NullBodyContract
    CS.Game.Game2007.BJL.Logic.GameProtocolMgr.instance:SendClientLoadComplete(nullBodyContract)
    print("startOver!")
end--相当于unity的Start

function update()

end--相当于unity的update

function ondestroy()

end--相当于unity的ondestroy

function OnEnable()
    print("OnEnableStart!")
    self.LuaCSAddListener(self,"GameState2007", HandleGameState2007)
    self.LuaCSAddListener(self,"GetClientSetting2007",GameLogic2007.s)
    self.LuaCSAddListener(self,"SetGameResult2007", HandleSetGameResult2007)
    print("OnEnableOver!")
end--相当于unity的 OnEnable,观察者模式下我的监听放于此。

function OnDisable()
    print("OnDisableStart!")
    self.LuaCSRemoveListener(self,"GameState2007", HandleGameState2007)
    self.LuaCSRemoveListener(self,"GetClientSetting2007", GameLogic2007.s)
    self.LuaCSRemoveListener(self,"SetGameResult2007", HandleSetGameResult2007)
    print("OnDisableOver!")
end--相当于unity的 OnDisable,观察者模式下我的释放监听放于此。
 HandleGameState2007 = function (f1,f2,f3)
    print("HandleGameState2007-------------获取到了游戏状态,如果TXT为UTF8,则显示中文------")
end--监听的回调函数
local s
 function HandleGetClientSetting2007(f1,f2,f3)
    print("HandleGetClientSetting--------我是威少,我获取到了游戏信息-----------")
end--监听的调函数
 HandleSetGameResult2007 =  function (f1,f2,f3)
    print("HandleSetGameResult2007---------------------!")
end--监听的回调函数。

9、更热不支持调用泛型,因为泛型需要JIT的支持。

A:通讯协议这一块,还是需要改的,现在我们只是在游戏前端的逻辑上用xLua实现,实现完了后我们一步一步的改过来,因为我们现在用的泛型,T类型在热更上肯定是不行的。

B:对于通信这一块,我们目前用的是短连接,我个人的想法是数据的传递用字典来传递,反正都是要序列化的,前后端将字典一致就行了。这样就免除了T类型的麻烦。

C:我一个朋友那边通讯是在socket上做了封装,取服务端数据是lua调安卓,安卓调ndk,然后由ndk去对接服务端,好像很高端,但是我们现在这么改肯定费时费力。

下图方式在热更上肯定是不行的,不要泛型,不要泛型,不要泛型,重要的事情说三遍还标红。

10、未完待续,下班回家,下次再继续写。

----------------------------我一直在装逼,却少有装逼成功,请容我继续装逼。

时间: 2024-10-14 16:48:02

xLua热更方案的相关文章

ILRuntime热更方案坑点

在热更工程中: 1.AddComponent需要限定好类型,不能用Type类型,会报错 2.GetComponent无法获取基类组件类型,无法找到时,需要在MonoBehaviorAdapter中添加遍历获取基类逻辑3.Hotfix调用Unity中带参数的委托,需要注册委托参 RegisterMethodDelegate4.强转Action委托类型as报错,使用(Action)XXX的方式去转换5.尽可能不过多使用特性,反射,容易出问题.6.继承自MonoBehavior的脚本声明处初始化不起作

lua热更框架之XLua

框架介绍 xLua是当下最流行的unity热更方案之一,作者是腾讯的车雄生前辈,自2016年初推出以来,已经在腾讯的多款游戏项目上应用,目前xLua已经开源到了GitHub.xLua最大的特色是不仅支持纯lua脚本热更,更是可以做 C# 代码的bug hotfix,即平时开发时使用C#,项目上线后,如果突然发现有bug,可以直接用lua去修复出bug的地方,原理就是通过[Hotfix]特性标记然后在IL逻辑层判断修改逻辑,使程序去执行更新后的lua逻辑代码而不是走之前的C#逻辑. 框架优势 与别

移动端热更新方案(iOS+Android)

PPT资源包含iOS+Android 各种方案分析:https://github.com/qiyer/Share/blob/master/%E7%83%AD%E6%9B%B4%E6%96%B0%E5%88%86%E4%BA%ABPPT.pptx 一 .热更新(热修复)产品背景 这里谈到的热更新都是指APP(不包含网页).APP按大类别可以粗略分为 应用 和 游戏.APP的开发周期是极其快速的,在实际开发流程中,我们总会有一些需求迫使我们短时间内快速上线,比如需求流程出错,程序员主观导致的一些bu

Android 热修复方案分析

绝大部分的APP项目其实都需要一个动态化方案,来应对线上紧急bug修复发新版本的高成本.之前有利用加壳,分拆两个dex结合DexClassLoader实现了一套全量更新的热更方案.实现原理在Android 基于Proxy/Delegate 实现bug热修复这篇博客中有分解.因为这套方案是在Java端实现,并且是全量更新所以兼容性较好,成功率较高.但是在线上跑了几个月之后就碰到了瓶颈,因为随着业务的增长分拆过之后的dex文件方法数也超过65535个,更换拆包方案的话维护成本太高.同时由于没有做差异

Unity3D热更新方案网摘总结

参考:http://blog.csdn.net/guofeng526/article/details/52662994 http://blog.csdn.net/u010019717/article/details/50853207 "热更新"这个词,在Unity3D的应用下,是有些语义错误的,但是作为大家都熟知的一项技术,我们姑且这么叫它,相信很长时间内,大家依然还会这么叫,甚至有人叫它"暖更新". 一.什么是热更新? 广义定义 无需关闭服务器,不停机状态下修复漏

各大热补丁方案分析和比较

最近开源界涌现了很多热补丁项目,但从方案上来说,主要包括Dexposed.AndFix.ClassLoader(来源是原QZone,现淘宝的工程师陈钟,在15年年初就已经开始实现)三种.前两个都是阿里巴巴内部的不同团队做的(淘宝和支付宝),后者则来自腾讯的QQ空间团队. 开源界往往一个方案会有好几种实现(比如ClassLoader方案已经有不下三种实现了),但这三种方案的原理却徊然不同,那么让我们来看看它们三者的原理和各自的优缺点吧. Dexposed 基于Xposed的AOP框架,方法级粒度,

实现iOS图片等资源文件的热更新化(五): 一个简单完整的资源热更新页面

简介 一个简单的关于页面,有一个图片,版本号,App名称等,着重演示各个系列的文章完整集成示例. 动机与意义 这是系列文章的最后一篇.今天抽空写下,收下尾.文章本身会在第四篇的基础上,简单扩充下代码,实现在线下载与重置更改的功能. 如果能较为仔细地阅读前四篇文章,第五篇给出的示例,应当是可以理解为无足轻重的.但是,大多数时候,我们更多的可能只是需要一个简易的解决方案,就是那种拿来就可以用的东西,那种我们需要先能看到一个简要的示例来看下效果再解决是否再继续阅读的方案.如此,对于很久以后,由于各种原

Unity官方公布热更新方案性能对比

孙广东  2016.3.11 Unity应用的iOS热更新 作者:丁治宇 Unity TechnologiesChina Agenda ?  什么是热更新 ?  为何要热更新 ?  如何在iOS 上对Unity 应用进行热更新 ?  支持Unity iOS 热更新的各种Lua 插件的对比 什么是热更新 ? 广义定义 ? 无需关闭服务器,不停机状态下修复漏洞,更新资源等,重点是更新逻辑代码. ? 狭义定义( iOS热更新) ? 无需将代码重新打包提交至AppStore,即可更新客户端的执行代码,即

Unity官方发布热更新方案性能对照

孙广东  2016.3.11 Unity应用的iOS热更新 作者:丁治宇 Unity TechnologiesChina Agenda ?  什么是热更新 ?  为何要热更新 ?  怎样在iOS 上对Unity 应用进行热更新 ?  支持Unity iOS 热更新的各种Lua 插件的对照 什么是热更新 ? 广义定义 ? 无需关闭server,不停机状态下修复漏洞,更新资源等,重点是更新逻辑代码. ? 狭义定义( iOS热更新) ? 无需将代码又一次打包提交至AppStore,就可以更新clien