最美情侣中文字幕电影,在线麻豆精品传媒,在线网站高清黄,久久黄色视频

歡迎光臨散文網(wǎng) 會員登陸 & 注冊

【UE4】利用反射調(diào)用UFunction

2022-07-07 16:00 作者:天空游蕩的魚  | 我要投稿

????前面簡單分析了元組(TTuple)是如何展開的,因為在UFunction的反射調(diào)用中會用到元組。在本文中,將會詳細講講反射的方式如何調(diào)用UFunction。

????假設(shè)有這樣的一種場景,需要編寫一個通用的函數(shù)調(diào)用框架。傳入函數(shù)名或者UFunction和對應(yīng)參數(shù)就可以調(diào)用到該UFunction,而不論它是C++中的函數(shù)還是藍圖中的事件或函數(shù)。并且框架并不知道對應(yīng)函數(shù)的參數(shù)有多少個,每個參數(shù)類型是什么。那么,就可能會用到本文中講到的反射調(diào)用了。

函數(shù)調(diào)用

????這是調(diào)用框架函數(shù)的部分,通用的函數(shù)為CallFunction2, 第一個參數(shù)是函數(shù)名(或者藍圖的事件名)。 TTuple存放的是函數(shù)的返回值。并且是支持多返回值的。通過TTuple的Get<index>方法獲取對應(yīng)的返回值。

????通過for (TFieldIterator<FProperty> ParamIt(Function); ParamIt; ++ParamIt)迭代器,可以訪問UFunction的所有屬性,包括參數(shù),返回值。他們都以FProperty表示。FProperty.PropertyFlags標(biāo)識了該屬性是什么類型的。例如:CPF_OutParm表示它為返回參數(shù)(返回值和非const的引用都是返回參數(shù))。CPF_ReturnParm特指返回值。CPF_Parm表示該屬性為參數(shù)。

? ? 同理,UFunction也有自己的標(biāo)識在Script.h的EFunctionFlags中定義。本文中只要用FUNC_Native檢查該Function是否C++實現(xiàn)。

反射調(diào)用函數(shù)CallFunction2實現(xiàn)

????這是一個模板函數(shù),定義類返回值和參數(shù)類型(TReturn, TArgs)。參數(shù)包含被調(diào)用函數(shù)名FunctionName, TTuple<TReturn...>&元組類型的返回參數(shù),不定長參數(shù)模板TArgs&& ...

????內(nèi)部代碼是通過FindObject查找對應(yīng)的UFunction實例,最后調(diào)用CallInternal2,該函數(shù)才是真正實現(xiàn)反射調(diào)用的地方。

反射實現(xiàn)細節(jié)

????函數(shù)定義與上面幾乎一致,多一個UClass*表示該函數(shù)屬于哪個對象。

????反射調(diào)用分為兩種方法

  1. 通過Invoke調(diào)用

  2. 通過ProcessEvent

????Invoke是更底層的方法,ProcessEvent內(nèi)部也會調(diào)用Invoke,后面會把兩種調(diào)用的完成代碼都貼上。

????接下來就正式進入反射的詳細流程啦。

  • 準(zhǔn)備參數(shù)

第一行,直接將參數(shù)的TTuple參數(shù)取地址,等到返回參數(shù)的首地址

第二行,將不定長的調(diào)用參數(shù)封裝到TTuple中

第三行,獲得TTuple不定長參數(shù)的首地址,函數(shù)要的參數(shù)都在這里啦

第四行,分配一塊UFunction參數(shù)一樣的大的內(nèi)存,用于存放調(diào)用參數(shù),參數(shù)總大小可以通過Function.ParamSize獲得

第五行,確定該函數(shù)是否有返回值

第六行,根據(jù)返回值的位置確定入?yún)⒖偞笮?/p>

第七行,將TTuple入?yún)⒅械闹礐opy到新分配的參數(shù)內(nèi)存塊中

這些操作都是在為調(diào)用Invoke或ProcessEvent做準(zhǔn)備,如果是調(diào)用Invoke還需要準(zhǔn)備調(diào)用Frame。下面我們就來看看。

  • 如果是NativeFunc

    繼續(xù)準(zhǔn)備參數(shù)

第一行,構(gòu)建一個調(diào)用Frame,第二個參數(shù)為要調(diào)用的UFunction,第三個參數(shù)為入?yún)?在前面已經(jīng)準(zhǔn)備好了)

第二行,取出Frame.OutParams的地址,這里將向Frame的OutParam中放入非const類的引用參數(shù)。

????for循環(huán)中迭代UFunction的所有屬性(包含參數(shù)和返回值),如果參數(shù)為CPF_OutParm類型且不為CPF_ReturnParm就將入?yún)⒅袑?yīng)的值復(fù)制到FuncParamsStructAddr中。在這里為每個需要的屬性分配了FOutParmRec,從而去構(gòu)建Frame.OutParam的屬性鏈表。

????通過Property->ContainerPtrToValuePtr<void*>(FuncParamsStructAddr)可以得到該屬性的指針偏移,從而把入?yún)⒅蟹莄onst 引用參數(shù)復(fù)制到參數(shù)內(nèi)存。FProperty有Property->GetOffset_ForInternal(), Property->GetSize()等方法可以確定對應(yīng)參數(shù)內(nèi)存大小。

????參數(shù)準(zhǔn)備完成之后,開始調(diào)用方法并處理返回值。

? ? Invoke第一個參數(shù)為Function所在的UClass,第二個參數(shù)為上面構(gòu)建的Frame,第三個參數(shù)為接收返回值的內(nèi)存地址。在本代碼中,統(tǒng)一用參數(shù)內(nèi)存的返回值部分進行接收。ReturnValueAddress是內(nèi)存參數(shù)偏移到返回值部分的首地址。

  • 如果不是NativeFunc

    將調(diào)用ProcessEvent進行函數(shù)調(diào)用。準(zhǔn)備參數(shù)階段是一樣的。

  • 處理返回值

????第一行,取調(diào)用者傳入的返回值地址(TTuple)

????第二行,遍歷Function的屬性

????第四行,判斷是否為CPF_OutParm

????第五行,根據(jù)屬性的地址偏移,取到參數(shù)內(nèi)存中,該參數(shù)對應(yīng)的內(nèi)存地址

????第六行,將該內(nèi)存地址的值復(fù)制到返回參數(shù)中

????第七行,返回參數(shù)地址偏移屬性大小

????循環(huán)完成之后,已經(jīng)將所有的返回值復(fù)制到調(diào)用者傳入的TTuple中。

問題:

  • 實測中發(fā)現(xiàn),如果有非const 類型的FString引用,當(dāng)處理函數(shù)中修改了引用值,可能會導(dǎo)致異常。

  • 注意,調(diào)用時,最好加上Forward,否則會出問題。當(dāng)被調(diào)用的參數(shù)為引用類型時,TTuple展開之后也是引用,將會把數(shù)值的內(nèi)存地址傳給執(zhí)行函數(shù)而不是值本身。例如:

????上面定義的函數(shù),npcType和OutType為引用類型。通過下面的代碼去調(diào)用,會得到正確的結(jié)果,如果不加Forward,傳入?yún)?shù)就不為101和202

????

下面是兩種調(diào)用的完整代碼

? ??


【UE4】利用反射調(diào)用UFunction的評論 (共 條)

分享到微博請遵守國家法律
张家口市| 项城市| 江山市| 陵水| 灵丘县| 宝应县| 阿克苏市| 沁水县| 黔南| 盐边县| 澳门| 河池市| 宣汉县| 镇安县| 罗定市| 滁州市| 开封市| 万荣县| 武胜县| 且末县| 赤峰市| 界首市| 平乐县| 丹寨县| 长顺县| 屏山县| 陇川县| 体育| 博兴县| 桂林市| 剑河县| 奉新县| 志丹县| 应用必备| 潼南县| 铜陵市| 搜索| 昭苏县| 改则县| 专栏| 安泽县|