Quake是Id Software公司推出一款風迷全球的FPS遊戲.至今為止已經發展到了第三代,而且作為一個優良的遊戲引擎,它也被大量的運用到其他公司開發的遊戲當中.例如我們所熟知的CS,它就是在Quake2引擎上改良而來的.雖然裡面的代碼實現並不完全相同,但是整體框架還是Quake2的,只要是稍微接觸過Quake引擎的人都很容易看得出來.(它是那麼的經典,以至於一直沿用到今天,個人認為它是遊戲領域大型結構化設計最好的一個典範.現在很多遊戲已經改用面向對象的程序設計方法來編寫,但Quake的影響卻是深遠的.包括前段時間洩露CS2源碼,它的架構仍然保留著些許Quake的風貌.)
很多人告述我Id Software 很早之前就已經公開了 Quake 全部源碼.這裡我要告述你們,其實Id公開的並不是所有的源代碼,而僅僅是邏輯層代碼,你想想看哪個公司會笨到將自己的核心技術傾囊倒出,這些可是他們吃飯的本錢啊!邏輯層的代碼只包括了UI,AI等實現.像圖像渲染,網絡傳輸部分卻沒有給出.你看到的唯有函數的聲明部分.因此要徹底研究Quake就必須獲得這部分的源代碼,可上哪去找呢?令人興奮的是,早前已經有牛人通過逆向工程的方法將Quake核心代碼整理出來,做了一個仿Quake引擎.我下面的分析就是根據他的代碼來寫的,雖然跟真實的Quake引擎比較也許會有些出入,但我相信那並不影響我們去理解Quake.
類如大多數Win32應用程序,Quake的Win32部分也是從WinMain函數進入的.邏輯層被分成了cggame,ui兩個主要的模塊.(這兩個模塊被編譯成dll程序,然後由引擎載入它們,為了讓邏輯層的代碼能過訪問核心層的函數,引擎部分會將一個叫SV_GameSystemCalls的函數傳給cggame和ui內部使用.註:SV_GameSystemCalls管理著所有可能被邏輯層應用到的核心函數)在Quake引擎中dll之間,以及dll與exe之間的交互都是通過vmMain和dllEntry這兩函數完成的.dll引出這兩函數函數的用意是用vmMain作為其他dll或exe程序訪問這個dll的接口,只要提供訪問函數的索引號以及函數的原形,那麼你就可以獲得那個函數的實現.而dllEntry則是調用者給它所調用的dll一個接口,被調用的dll就能夠使用這個接口呼叫調用者的內部函數了.邏輯層的dll就是使用dllEntry來接收SV_GameSystemCalls的.以下是dllEntry函數的實現:
static int (CDECL *syscall)( int arg, ... ) = (int (CDECL *)( int, ...))-1;
void dllEntry( int (CDECL *syscallptr)( int arg,... ) ) {
syscall = syscallptr;
}
我們常見的trap打頭的函數實際上是調用了引擎代碼的,具體如下:
void trap_Printf( const char *fmt ) {
syscall( G_PRINT, fmt );
}
了解了上述的調用規則後,我們就可以比較輕鬆地跟蹤調試Quake源碼啦.