zoukankan      html  css  js  c++  java
  • XLUA

    原文 转载请注明保留原文链接:http://www.jianshu.com/p/dc4de5612d9e

    作者:Jumbo

    在Unity3D项目中,逻辑代码热更新这一块,现在有很多实现解决方案,基本都是借助Lua来实现的,在这众多之中,最后还是选择xLua,最早了解xLua是在腾讯的手游项目中,腾讯Apollo通用组件中,只是涉及的项目中,并没有xLua的源码及文档相关的说明。可能当时xLua还在改进当中。直到2017年1月3日,腾讯Github开源项目中,出现xLua的身影。xLua优势:1、集成快 (几乎不用改变原本项目的代码) 2、专职人员负责维护(企鹅还是有这个实力·~~·),说再多也不如自己切身体验一番。下面就帮大家,快速入门下。

    一、xLua源码: https://github.com/Tencent/xLua/ 没有帐号或者下载不了的同学,可以邮箱留言,发一份给大伙;

    二、获取到源码后,首先认真阅读README.md内容,可以更好的帮大家了解xLua,是否项目中遇到的问题,可以通过xLua来帮忙处理?;

    三、根据提供的示例:
    01_Helloworld: 快速入门的例子。
    02_U3DScripting: 展示怎么用lua来写MonoBehaviour。
    03_UIEvent: 展示怎么用lua来写UI逻辑。
    04_LuaObjectOrented: 展示lua面向对象和C#的配合。
    05_NoGc: 展示怎么去避免值类型的GC。
    06_Coroutine: 展示lua协程怎么和Unity协程相配合。
    07_AsyncTest: 展示怎么用lua协程来把异步逻辑同步化。
    08_Hotfix: 热补丁的示例(需要开启热补丁特性,如何开启请看指南)。
    配合文档:
    XLua教程.doc:教程,其配套代码这里
    XLua的配置.doc:介绍如何配置xLua。
    XLua增加删除第三方lua库.doc:如何增删第三方lua扩展库。
    XLua API.doc:API文档。
    可以更好的了解xLua具备那些特性,如何便捷使用。

    四、最重要的功能:热补丁
    xLua支持热补丁,这意味着你可以:
    1、开发只用C#;
    2、运行也是C#,性能可以秒杀lua;
    3、出问题了才用Lua来改掉C#出问题的部位,下次整体更新时换回正确的C#;能做到用户不重启程序fix bug;

    如果你仅仅希望用热更新来fix bug,这是强烈建议的做法。这里是使用指南。
    这个文档说明一定要仔细阅读https://github.com/Tencent/xLua/blob/master/Assets/XLua/Doc/hotfix.md

    很多刚开始接触的同学,因为没有认真看文档说明,容易出现一些问题,这边列举下:
    注意:a、HOTFIX_ENABLE宏是否在Unity3D的File->Build Setting->Scripting Define Symbols下添加
    b、Mono.Cecil.是否拷贝:OSX命令行 cp /Applications/Unity/Unity.app/Contents/Managed/Mono.Cecil.Project/Assets/XLua/Src/Editor/

    Win命令行 copy UnityPathEditorDataManagedMono.Cecil.* ProjectAssetsXLuaSrcEditor

    c、菜单栏中,执行xLua/Generat Code, 会在新建Gen文件夹,下面生成一些wrap文件

     
     


    具体生成那些类型对应的wrap文件,需要自己配置,详见:https://github.com/Tencent/xLua/blob/master/Assets/XLua/Examples/ExampleGenConfig.cs
    在项目中集成,最好自己写一份配置,替换ExampleGenConfig,比如取名CustomGenConfig.cs,加入了[Hotfix]标签

      //需要热更新的类型
        [Hotfix]
        public static List<Type> by_field = new List<Type>()
        {
    
        };
    

    d、要等打印了hotfix inject finish!后才运行例子,否则会类似xlua.access, no field __Hitfix0_Update的错误

    五、整合xLua进项目
    1、

     
     

    2、

     
     

    3、

     
     

    先贴上代码(myHotfix.lua 编写fixbug逻辑):

    using UnityEngine;
    using System.Collections;
    using XLua;
    
    /// <summary>
    /// 先判断更新热补丁文件,然后再执行Fixing
    /// </summary>
    public class xLuaInstance : MonoSingleton<xLuaInstance>{
    
        LuaEnv luaenv;
    
        const string fixFile = "myHotfix.lua";
    
        public string FixFilePath
        {
            get
            {
                return FileUtils.GetFullPath(null, fixFile, FileUtils.StorageType.Persistent);
            }
        }
    
        /// <summary>
        /// 热补丁修复中。。。
        /// </summary>
        public void Fixing()
        {
    
            byte[] bytes = System.IO.File.ReadAllBytes(FixFilePath);
    
            if (bytes != null)
            {
                luaenv = new LuaEnv();
                luaenv.AddLoader((ref string filename) =>
                {
                    if (filename == "myHotfix")
                    {
                        filename = FixFilePath;
                        return bytes;
                    }
    
                    return null;
                });
    
                luaenv.DoString(@"require 'myHotfix'");
            }
        }
    
        void Update()
        {
            if (luaenv != null)
                luaenv.Tick();
        }
    
        void OnDestroy()
        {
            if (luaenv != null)
                luaenv.Dispose();
        }
    }
    

    4、大致流程
    i、游戏一开始启动时,检查远程服务器上是否有新的myHotfix.lua文件(例如:md5比对,自己加解密),有的话,下载下来,放在指定目录,没有的话,读取本地已有的myHotfix.lua文件,若文件不存在,则说明不需要热修复,一般这种情况是在项目刚发布的早起,没有进行打补丁;

    ii、项目发布版本前,需要在CustomGenConfig.cs中 加入需要添加[Hotfix]标签的类型,想要更灵活使用的话,可以自己写个配置表,读取配置中的类型,自动添加,***只有加入[Hotfix]标签的类型,才可以调用xlua.hotfix()

     
     

    ,不然会报错,切记!!!

    iii、如果你的项目是自动化发布版本,需要在调用打包之前,生成wrap, 调用这个CSObjectWrapEditor.Generator.GenAll();

    MonoSingleton.cs

    //非线程安全
    using UnityEngine;
    
        /// <summary>
        ///     基类继承树中有MonoBehavrour类的单件实现,这种单件实现有利于减少对场景树的查询操作
        /// </summary>
        /// <typeparam name="T"></typeparam>
        public class MonoSingleton<T> : MonoBehaviour where T : Component
        {
            // 单件子类实例
            private static T _instance;
    
            // 在单件中,每个物件的destroyed标志设计上应该分割在不同的存储个空间中,因此,忽略R#的这个提示
            // ReSharper disable once StaticFieldInGenericType
            private static bool _destroyed;
    
            /// <summary>
            ///     获得单件实例,查询场景中是否有该种类型,如果有存储静态变量,如果没有,构建一个带有这个component的gameobject
            ///     这种单件实例的GameObject直接挂接在bootroot节点下,在场景中的生命周期和游戏生命周期相同,创建这个单件实例的模块
            ///     必须通过DestroyInstance自行管理单件的生命周期
            /// </summary>
            /// <returns>返回单件实例</returns>
            public static T Instance
            {
                get{
    
                     if (_instance == null && !_destroyed)
                     {
                         _instance = (T) FindObjectOfType(typeof (T));
                         if (_instance == null)
                        {
                           GameObject go = new GameObject(typeof (T).Name);
                           _instance =  go.AddComponent<T>();
    
                            DontDestroyOnLoad(_instance);
    
                           var singletonRootGo = GameObject.Find("MonoSingletonRoot");
                           if (singletonRootGo != null)
                           {
                               go.transform.parent = singletonRootGo.transform;
                             }
                        }
                     }
                    return _instance;
                }
               
             }
    
            /// <summary>
            ///     删除单件实例,这种继承关系的单件生命周期应该由模块显示管理
            /// </summary>
            public static void DestroyInstance()
            {
                if (_instance != null)
                    Destroy(_instance.gameObject);
    
                _destroyed = true;
                _instance = null;
            }
    
            /// <summary>
            ///     Awake消息,确保单件实例的唯一性
            /// </summary>
            protected virtual void Awake()
            {
                if (_instance != null && _instance.gameObject != gameObject) Destroy(gameObject);
                else if(_instance == null)
                    _instance = GetComponent<T>();
    
                DontDestroyOnLoad(_instance);
            }
    
            /// <summary>
            ///     OnDestroy消息,确保单件的静态实例会随着GameObject销毁
            /// </summary>
            protected virtual void OnDestroy()
            {
                if (_instance != null && _instance.gameObject == gameObject)
                {
                    _instance = null;                
                }
            }
    
            /// <summary>
            ///     Have Instance
            /// </summary>
            /// <returns></returns>
            public static bool HaveInstance()
            {
                return _instance != null;
            }
        }
    

    如何调试Lua脚步,接下来,我会写一篇关于ZeroBrane这个工具。

    在此感谢xLua作者:车雄生 chexiongsheng!!!
    期待大家的支持!!!
    祝大家在17年万事如意,身体健康!!!



    作者:JumboWu
    链接:https://www.jianshu.com/p/dc4de5612d9e
    來源:简书
    简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。

  • 相关阅读:
    pat甲级 1155 Heap Paths (30 分)
    pat甲级 1152 Google Recruitment (20 分)
    蓝桥杯 基础练习 特殊回文数
    蓝桥杯 基础练习 十进制转十六进制
    蓝桥杯 基础练习 十六进制转十进制
    蓝桥杯 基础练习 十六进制转八进制
    51nod 1347 旋转字符串
    蓝桥杯 入门训练 圆的面积
    蓝桥杯 入门训练 Fibonacci数列
    链表相关
  • 原文地址:https://www.cnblogs.com/hpu001/p/10111168.html
Copyright © 2011-2022 走看看