xlua熱補丁筆記

這個是幾個月前記的,沒有整理。先暫時這樣吧,后面具體用到了再來整理吧。

1.使用xlua.hotfix替換方法,變量;xlua.hotfix(類名,{中間寫要替換的方法})

   xlua.hotfix(CS.HotfixCalc, {
             Test1 = function(self)
                print('Test1', self)
                return 1
             end;
             Test2 = function(self, a, b)
                 print('Test1', self, a, b)
                 return a + 10, 1024, b
             end;
             Test3 = function(a)
                print(a)
                return 10
             end;
             Test4 = function(a)
                print(a)
             end;
             Test5 = function(self, a, ...)
                print('Test4', self, a, ...)
             end
        })

打補丁

xlua可以用lua函數(shù)替換C#的構(gòu)造函數(shù),函數(shù),屬性,事件的替換。lua實現(xiàn)都是函數(shù),比如屬性對于一個getter函數(shù)和一個setter函數(shù),事件對應(yīng)一個add函數(shù)和一個remove函數(shù)。

  • 函數(shù)

method_name傳函數(shù)名,支持重載,不同重載都是轉(zhuǎn)發(fā)到同一個lua函數(shù)。

比如:


// 要fix的C#類
[Hotfix]
public class HotfixCalc
{
    public int Add(int a, int b)
    {
        return a - b;
    }

    public Vector3 Add(Vector3 a, Vector3 b)
    {
        return a - b;
    }
}


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

靜態(tài)函數(shù)和成員函數(shù)的區(qū)別是,成員函數(shù)會加一個self參數(shù),這個self在Stateless方式下是C#對象本身(對應(yīng)C#的this),Stateful方式下傳lua構(gòu)造函數(shù)實現(xiàn)的返回值(一個table或者nil)

普通參數(shù)對于lua的參數(shù),ref參數(shù)對應(yīng)lua的一個參數(shù)和一個返回值,out參數(shù)對于lua的一個返回值。

泛化函數(shù)的打補丁規(guī)則和普通函數(shù)一樣。

  • 構(gòu)造函數(shù)

構(gòu)造函數(shù)對應(yīng)的method_name是".ctor"。

如果是Stateful方式,你可以返回一個table作為這個對象的狀態(tài)。

和普通函數(shù)不一樣的是,構(gòu)造函數(shù)的熱補丁并不是替換,而是執(zhí)行原有邏輯后調(diào)用lua。

  • 屬性

對于名為“AProp”的屬性,會對應(yīng)一個getter,method_name等于get_AProp,setter的method_name等于set_AProp。

  • []操作符

賦值對應(yīng)set_Item,取值對應(yīng)get_Item。第一個參數(shù)是self,賦值后面跟key,value,取值只有key參數(shù),返回值是取出的值。

  • 其它操作符

C#的操作符都有一套內(nèi)部表示,比如+號的操作符函數(shù)名是op_Addition(其它操作符的內(nèi)部表示可以去請參照相關(guān)資料),覆蓋這函數(shù)就覆蓋了C#的+號操作符。

  • 事件

比如對于事件“AEvent”,+=操作符是add_AEvent,-=對應(yīng)的是remove_AEvent。這兩個函數(shù)均是第一個參數(shù)是self,第二個參數(shù)是操作符后面跟的delegate。

通過xlua.private_accessible來直接訪問事件對應(yīng)的私有delegate的直接訪問后,可以通過對象的"&事件名"字段直接觸發(fā)事件,例如self['&MyEvent'](),其中MyEvent是事件名。

  • 析構(gòu)函數(shù)

method_name是"Finalize",傳一個self參數(shù)。

和普通函數(shù)不一樣的是,析構(gòu)函數(shù)的熱補丁并不是替換,而是開頭調(diào)用lua函數(shù)后繼續(xù)原有邏輯。

  • 泛化類型

其它規(guī)則一致,需要說明的是,每個泛化類型實例化后都是一個獨立的類型,只能針對實例化后的類型分別打補丁。比如:

public class GenericClass<T>
{
}

你只能對GenericClass<double>,GenericClass<int>這些類,而不是對GenericClass打補丁。

另外值得一提的是,要注意泛化類型的命名方式,比如GenericClass<double>的命名是GenericClass`1[System.Double],具體可以看MSDN

對GenericClass<double>打補丁的實例如下:

luaenv.DoString(@"
    xlua.hotfix(CS['GenericClass`1[System.Double]'], {
        ['.ctor'] = function(obj, a)
            print('GenericClass<double>', obj, a)
        end;
        Func1 = function(obj)
            print('GenericClass<double>.Func1', obj)
        end;
        Func2 = function(obj)
            print('GenericClass<double>.Func2', obj)
            return 1314
        end
    })
");
  • Unity協(xié)程

通過util.cs_generator可以用一個function模擬一個IEnumerator,在里頭用coroutine.yield,就類似C#里頭的yield return。比如下面的C#代碼和對應(yīng)的hotfix代碼是等同效果的

[XLua.Hotfix]
public class HotFixSubClass : MonoBehaviour {
    IEnumerator Start()
    {
        while (true)
        {
            yield return new WaitForSeconds(3);
            Debug.Log("Wait for 3 seconds");
        }
    }
}
luaenv.DoString(@"
    local util = require 'xlua.util'
    xlua.hotfix(CS.HotFixSubClass,{
        Start = function(self)
            return util.cs_generator(function()
                while true do
                    coroutine.yield(CS.UnityEngine.WaitForSeconds(3))
                    print('Wait for 3 seconds')
                end             
            end
        end;
    })
");
  • 整個類

如果要替換整個類,不需要一次次的調(diào)用xlua.hotfix去替換,可以整個一次完成。只要給一個table,按method_name = function組織即可


xlua.hotfix(CS.StatefullTest, {
    ['.ctor'] = function(csobj)
        return {evt = {}, start = 0}
    end;
    set_AProp = function(self, v)
        print('set_AProp', v)
        self.AProp = v
    end;
    get_AProp = function(self)
        return self.AProp
    end;
    get_Item = function(self, k)
        print('get_Item', k)
        return 1024
    end;
    set_Item = function(self, k, v)
        print('set_Item', k, v)
    end;
    add_AEvent = function(self, cb)
        print('add_AEvent', cb)
        table.insert(self.evt, cb)
    end;
    remove_AEvent = function(self, cb)
       print('remove_AEvent', cb)
       for i, v in ipairs(self.evt) do
           if v == cb then
               table.remove(self.evt, i)
               break
           end
       end
    end;
    Start = function(self)
        print('Start')
        for _, cb in ipairs(self.evt) do
            cb(self.start, 2)
        end
        self.start = self.start + 1
    end;
    StaticFunc = function(a, b, c)
       print(a, b, c)
    end;
    Finalize = function(self)
       print('Finalize', self)
    end
})

其中self表示的是自身類,和this一個道理

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容