使用xlua 进行Unity3D 热更新

之前一直在纠结项目的某些运营界面使用全Lua来写,这样可以热更新上线不同的活动,而不需要上架不同的版本,虽然可以通过资源更新加载xml的方式来实现,但是要通过xml来组合一些新的活动逻辑会很困难.

然后听了很多朋友最近都在推荐xlua, 不但可以做纯lua的逻辑更新,还可以做 C# 代码的bug hotfix.
就是可以在保持项目使用C#逻辑开发的前提下,出现bug后使用lua来修复.听起来很棒棒.

github地址 : xlua

试用一下之后,发现xlua的hotfix原理也很简单, 就是通过反射取出打上了 [hotfix] 标记的类,
然后对需要fix的函数执行下列伪代码

void Start()
{
  if(_hotfix)
   _lua_add(a,b);
  else
   _csharp_add(a,b);
}

那么思路就来了.
设定一个全局 hotfix管理类, 在游戏初始化的时候拉取服务器的 hotfix 版本号, 看看服务器上是否有新的补丁需要下载, 如果有,将补丁存到本地. 之后加载 补丁, 打补丁. 最后进入游戏.

正好以前自己写过好几个lua项目比如 : PrompaLua, lua还没忘记..正好用上 哈哈

首先是一个范例:
一个有bug的类

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using XLua;

[Hotfix]
public class FuckYouSelf : MonoBehaviour {

    private int A;
    private int B;

    void Init() {

    }
    // Use this for initialization
    void Start () {
        Init();
        UnityEngine.Debug.Log(Add(A, B));
    }

    int Add(int a, int b) {
        return a - b;
    }
   
    // Update is called once per frame
    void Update () {
       
    }
}

错误有 A,B 没有初始化
Add函数被写成了减法

好在类的开头被打上了 [Hotfix] 标记,让我们有机会热修复他.

然后是HotFix类

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using XLua;


public class HotFix : MonoBehaviour {

    public GameObject StartUp;

    [Serializable]
    struct VersionData {
        public string Version;
        public string FixUrl;
    }

    LuaEnv luaevn = new LuaEnv();
    // Use this for initialization
    void Awake () {

        StartCoroutine(LoadVersion("http://www.dreamfairy.cn/xlua/test/version.txt"));
    }

    IEnumerator LoadVersion(string versionUrl) {
        WWW versionData = new WWW(versionUrl);

        yield return versionData;

        if(null != versionData.error) {
            Debug.LogError(versionData.error);
        } else {
            VersionData data = JsonUtility.FromJson<VersionData>(versionData.text);
            StartCoroutine(LoadFix(data.FixUrl, data.Version));
        }
    }
   
    IEnumerator LoadFix(string fixUrl, string version) {

        //todo: check storage hotfix version

        WWW fixData = new WWW(fixUrl);

        yield return fixData;

        if (null != fixData.error) {
            Debug.LogError(fixData.error);
        } else {
            ApplyHotFix(fixData.text);
            SaveToStorage(fixData.text, version);
        }
    }

    void ApplyHotFix(string luastr) {
        luaevn.DoString(luastr);

        if(null != StartUp) {
            StartUp.SetActive(true);
        }
    }

    void SaveToStorage(string luastr, string version) {
        //todo
    }

    private void OnDestroy() {
       
    }
}

他会在游戏启动的时候去下载 http://www.dreamfairy.cn/xlua/test/version.txt 版本号数据
之后去补丁地址下载补丁文件 http://www.dreamfairy.cn/xlua/test/hotfix.lua

下载完毕后,缓存到本地, 然后调用游戏启动 StartUp

启动游戏后, 原本控制台输出 0 的结构, 热更新后 控制台输出 600

最后是lua部分的代码

xlua.private_accessible(CS.FuckYouSelf)

xlua.hotfix(CS.FuckYouSelf, 'Init',
function(self)
    self.A = 300
    self.B = 300
end
)

xlua.hotfix(CS.FuckYouSelf, 'Add',
function(self, a, b)
    return a + b
end
)

lua部分的代码,就3段 第一段 xlua.private_accessible(CS.FuckYouSelf)
让lua可以访问私有字段, 目的是为了改成员变量 A,B 他们是私有的

第二段是修改 类中的 Init函数, 来初始化A,B

第三段是修改 类中的 Add函数,让他正确执行加法