【HLSDK系列】服务端实体 edict_t 和 控制类
我們來了解一下引擎是怎么管理實體的吧!我們這里就說說服務端的實體(edict_t)
服務端用 edict_t 這個結構體來保存一個實體,可以說一個 edict_t 就是一個 服務端實體,下文簡稱實體。
我們在 mp.dll 的源碼里經常看到的那些 CBaseXXX 又和 edict_t 有什么關系呢?
引擎只管理小部分實體的功能,更多功能需要我們自己寫代碼去實現,這里就引入了 實體控制類 這個東西(就是那些 CBaseXXX),類就是C++的那個類。下文簡稱控制類。
接下來我們就分析 edict_t 到底是怎么跟 控制類 掛上勾的。
我們通常用 CREATE_NAMED_ENTITY( MAKE_STRING("weapon_mp5") ); 來創建一個 weapon_mp5 的武器實體,那我們就來分析這個函數到底做了什么吧!
1. 用戶調用 CREATE_NAMED_ENTITY。
2. 引擎在 mp.dll (的導出函數)里查找名為“weapon_mp5”的函數。(你可能會有疑問:我從來沒寫過這個函數啊?別急,下文分析)
3. 引擎調用“weapon_mp5”函數來創建出一個CMP5類實例。“weapon_mp5”還調用了 CREATE_ENTITY 來創建出一個 edict_t。(用數學老師的話說:CMP5就是實體weapon_mp5的控制類)
4. 引擎把類實例的指針賦值到 edict_t 的 pvPrivateData 成員變量里。
5. 引擎返回 edict_t 給用戶。
看了上面的步驟,你一定注意到非常關鍵的一步,“weapon_mp5”函數到底是怎么一回事。
打開 mp5.cpp 你會發現有一行
LINK_ENTITY_TO_CLASS( weapon_mp5, CMP5 );這行就是關鍵,它會生成一個函數,這個函數起了類似如下代碼的作用:
注:實際上不是這么簡單的,只是為了更容易理解。
CMP5 *weapon_mp5() {return new CMP5(); }再往回看上面的步驟3和4,能理解了吧。
引擎先創建一個 edict_t 然后又 new CMP5 把指針存到 pvPreivateData 這個變量里,到此一個實體就創建出來了。
?
然后我們還要了解控制類是怎么工作的。首先請你打開 cbase.cpp 你會看到一堆?Dispatch 開頭的函數,下文簡稱派遣函數。
派遣函數用來干嘛呢?當一個實體要 Think 的時候,引擎就會調用 mp.dll 里的?DispatchThink 這個函數,它有一個參數?edict_t *pent 就是要 Think 的實體!
接著才是關鍵!
我們來看 DispatchThink 的源碼:
void DispatchThink( edict_t *pent ) {CBaseEntity *pEntity = (CBaseEntity *)GET_PRIVATE(pent);if (pEntity){// ...pEntity->Think();} }順便還有 GET_PRIVATE 的源碼:
inline void *GET_PRIVATE( edict_t *pent ) {if ( pent )return pent->pvPrivateData;return NULL; }我們可以看到它獲取了 edict_t 里面的 pvPrivateData 變量,你一定還記得這個變量是怎么來的吧!不記得請馬上往回看!
沒錯,之前引擎創建實體的時候,把 控制類 的 指針 存這變量里了,我們這里就把這個 控制類 拿出來而已!
接著它檢查了一下 控制類 是不是 NULL,然后它在 if 里面調用了 控制類 的 Think 函數!
整個過程就是這樣的:引擎 -> 派遣函數 -> 控制類 也就是說,引擎是不管 控制類 的,為讓 控制類 工作,我們還需要在派遣函數里寫東西(雖然HLSDK已經寫好了,但是你一定要去看看他是怎么寫的)。
如果你寫過 AMXX 你肯定會認識 FM_Think FM_Spawn 這些東西,它們就是HOOK了這些派遣函數!
?
本來還想仔細講解?LINK_ENTITY_TO_CLASS 的,留到下一篇文章吧!
轉載于:https://www.cnblogs.com/crsky/p/6881146.html
總結
以上是生活随笔為你收集整理的【HLSDK系列】服务端实体 edict_t 和 控制类的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 关于程序员35岁的坎:年龄不是挡板,图灵
- 下一篇: 迅捷思维导图怎么画出来