這個是幾個月前記的,沒有整理。先暫時這樣吧,后面具體用到了再來整理吧。
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一個道理