xLua学习之路(五) ------ 热更新API/标签/打包报错的坑

  • 前置步骤请参考:xLua学习之路(一) ------ 学习资料/准备工作

限制:

  1. 不支持静态构造函数。
  2. 目前只支持Assets下代码的热补丁,不支持引擎,c#系统库的热补丁。

API介绍:

     1. xlua.hotfix(class, [method_name], fix) : 注入lua补丁           
  • class : C#类,两种表示方法,CS.Namespace.TypeName或者字符串方式"Namespace.TypeName",字符串格式和C#的Type.GetType要求一致,如果是内嵌类型(Nested Type)是非Public类型的话,只能用字符串方式表示"Namespace.TypeName+NestedTypeName";
  • method_name : 方法名,可选;
  • fix : 如果传了method_name,fix将会是一个function,否则通过table提供一组函数。table的组织按key是method_name,value是function的方式。
      2. base(csobj) : 子类override函数通过base调用父类实现。
  • csobj : 对象
  • 返回值 : 新对象,可以通过该对象base上的方法

        示例:           

public class BaseTestBase : BaseTestHelper  //父类
{
    public virtual void Foo(int p)
    {
        Debug.Log("BaseTestBase<>.Foo, p = " + p);
    }
}
[Hotfix]
[LuaCallCSharp]
public class BaseTest : BaseTestBase  //子类重写
{
    public override void Foo(int p)
    {
        Debug.Log("BaseTest<>.Foo, p = " + p);
    }
}
      luaenv.DoString(@"
            xlua.hotfix(CS.BaseTest, 'Foo', function(self, p)
                    print('BaseTest', p)
                    base(self):Foo(p)             //调用父类的Foo函数,传参数为P
                end)
        ");
        bt.Foo(2);

输出:

                                        


      3. util.hotfix_ex(class, method_name, fix) : xlua.hotfix的增强版本,可以在fix函数里头执行原来的函数,缺点是fix的执行会略慢。     

  • method_name : 方法名;
  • fix : 用来替换C#方法的lua function。

标识要热更新的内容:

         

方式一:直接在类里头打Hotfix标签;

方式二:在一个static类的static字段或者属性里头配置一个列表。属性可以用于实现的比较复杂的配置,比如根据Namespace做白名单。

public static class HotfixCfg
{
    [Hotfix]
    public static List<Type> by_field = new List<Type>()
    {
        typeof(HotFixSubClass),
        typeof(GenericClass<>),
    };

    [Hotfix]
    public static List<Type> by_property
    {
        get
        {
            return (from type in Assembly.Load("Assembly-CSharp").GetTypes()
                    where type.Namespace == "XXXX"
                    select type).ToList();
        }
    }
}
Hotfix Flag        

   Hotfix标签可以设置一些标志位对生成代码及插桩定制化

  • Stateless、Stateful

遗留设置,Stateful方式在新版本已经删除,因为这种方式可以用xlua.util.hotfix_state接口达到类似的效果,该接口的使用可以看下HotfixTest2.cs里的示例代码。

由于没Stateful,默认就是Stateless,所以也没必要设置该标志位。

  • ValueTypeBoxing

值类型的适配delegate会收敛到object,好处是代码量更少,不好的是值类型会产生boxing及gc,适用于对text段敏感的业务。

  • IgnoreProperty

不对属性注入及生成适配代码,一般而言,大多数属性的实现都很简单,出错几率比较小,建议不注入。

  • IgnoreNotPublic

不对非public的方法注入及生成适配代码。除了像MonoBehaviour那种会被反射调用的私有方法必须得注入,其它仅被本类调用的非public方法可以不注入,只不过修复时会工作量稍大,所有引用到这个函数的public方法都要重写。

  • Inline

不生成适配delegate,直接在函数体注入处理代码。

  • IntKey

不生成静态字段,而是把所有注入点放到一个数组集中管理。

好处:对text段影响小。

坏处:使用不像默认方式那么方便,需要通过id来指明hotfix哪个函数,而这个id是代码注入工具时分配的,函数到id的映射会保存在Gen/Resources/hotfix_id_map.lua.txt,并且自动加时间戳备份到hotfix_id_map.lua.txt同级目录,发布手机版本后请妥善保存该文件。

该文件的格式大概如下(注意:该文件仅IntKey模式使用,当你没类型指定IntKey模式注入,该文件只返回个空表):

return {
    ["HotfixTest"] = {
        [".ctor"] = {
            5
        },
        ["Start"] = {
            6
        },
        ["Update"] = {
            7
        },
        ["FixedUpdate"] = {
            8
        },
        ["Add"] = {
            9,10
        },
        ["OnGUI"] = {
            11
        },
    },
}

想要替换HotfixTest的Update函数,你得

CS.XLua.HotfixDelegateBridge.Set(7, func)

如果是重载函数,将会一个函数名对应多个id,比如上面的Add函数。

能不能自动化一些呢?可以,xlua.util提供了auto_id_map函数,执行一次后你就可以像以前那样直接用类,方法名去指明修补的函数。

(require 'xlua.util').auto_id_map()
xlua.hotfix(CS.HotfixTest, 'Update', function(self)
        self.tick = self.tick + 1
        if (self.tick % 50) == 0 then
            print('<<<<<<<' .. self.tick)
        end
    end)

前提是hotfix_id_map.lua.txt放到可以通过require 'hotfix_id_map'引用到的地方。

打包报错的坑:

                      xLua学习之路(五) ------ 热更新API/标签/打包报错的坑_第1张图片

          这是由于带着xlua example一起打包才会有错,删除之后清理重新生成即可


开发过程:

          1.首先开发业务代码

          2.在所有可能出现问题的类上打上hotfix的标签,在所有lua调用CSharp的方法上打上LuaCallCSharp,在所有CSharp调用Lua的方法上打上CSharpCallLua

          3.打包发布

          4.修改bug时只需要更新Lua文件,修改资源时(声音,模型,贴图,图片,UI)只需要更新ab包。用户只需要去下载lua文件跟ab包。

  注意:

         1.在开发过程中尽量不要用明确的数字,最好使用变量,以便热更新修改,否则则每次函数都需在lua重写




你可能感兴趣的:(xLua学习之路(五) ------ 热更新API/标签/打包报错的坑)