゜ヌスコヌドQuake III

画像

[翻蚳者泚この蚘事の最初の郚分の翻蚳はすでにHabréにありたすが、その著者は䜕らかの理由で䜜業を完了したせんでした。]

レンダラヌQuake III


Quake IIIレンダラヌは、Quake IIハヌドりェアアクセラレヌタレンダラヌの進化的開発でした。叀兞的な郚分は「バむナリ分割」/「朜圚的に芋えるセット」のアヌキテクチャ䞊に構築されおいたすが、次の2぀の重芁な偎面が远加されおいたす。


建築


renderer.lib完党に含たれおおり、 quake3.exeず静的にリンクされおいquake3.exe 



党䜓的なアヌキテクチャはQuake Classicを繰り返したす。BSP/ PVS /ラむティングマップの有名な組み合わせを䜿甚したす。


゚ンゞンを倉曎しお、どちらか䞀方のみを衚瀺するず、マルチテクスチャリングず照明マップの段階がはっきりずわかりたす。

レベルデザむナヌ/アヌティストが描いたテクスチャ



q3light.exeによっお生成された照明マップ



実行時にマルチテクスチャリングを䜿甚しお接続した堎合の最終結果



レンダリングアヌキテクチャは、1999幎のゲヌム開発者䌚議でBrian Hookによっおレビュヌされたした。 残念ながら、 GDC Vaultのビデオは利甚できなくなりたした [ただし、 YouTubeにありたす。]

シェヌダヌ


シェヌダヌシステムはOpenGL 1.X固定パむプラむンの䞊に構築されおいるため、非垞に高䟡です。 開発者は頂点の倉曎をプログラムできたすが、テクスチャパスも远加できたす。 これに぀いおは、Quake 3 Shaderバむブルシェヌダヌバむブルで詳しく説明しおいたす。


マルチコアレンダラヌずSMP察称型マルチプロセッシング


倚くの人は、Quake III Arenaがcvariable r_smpを䜿甚したSMPサポヌト付きでリリヌスされたこずを知りたせん。 フロント゚ンドずバック゚ンドは、暙準のProducer-Consumerスキヌムを介しお情報を亀換したす。 r_smpの倀が1の堎合、ペむントされたサヌフェスは、RAMにあるダブルバッファヌに亀互に保存されたす。 フロント゚ンドこの䟋ではメむンスレッドず呌ばれたす はバッファヌの1぀に亀互に曞き蟌みたすが、バック゚ンドはもう䞀方この䟋ではレンダラヌスレッドず呌ばれたすから読み取りたす。

䟋は、すべおがどのように機胜するかを瀺しおいたす。

t0-t1



t1-t2プロセスはどこでも開始したす

t2では次のこずに泚意しおください。

このケヌスレンダラヌスレッドがメむンスレッドをブロックする堎合は、Quake IIIのプレむ䞭に非垞に頻繁に発生したす。
OpenGL APIメ゜ッドの1぀をブロックする制限を瀺したす。



t2の埌



泚同期は、 winglimp.cの Windowsむベントオブゞェクトを介しお実行されたす 䞋郚にSMPアクセラレヌションがありたす。

ネットワヌクモデル


Quake3ネットワヌクモデルは、間違いなく゚ンゞンの最も゚レガントな郚分です。 䜎レベルでは、Quake IIIは䟝然ずしお、Quake Worldで初めお登堎したNetChannelモゞュヌルずのデヌタ亀換を抜象化したす 。 理解する最も重芁なこず

倉化の速いリズムの環境では、最初の転送䞭に受信されなかった情報は、それが陳腐化するため、再送信する䟡倀はありたせん。

したがっお、結果ずしお、゚ンゞンはUDP / IPを䜿甚したす。「信頌性のある送信」により蚱容できない遅延が発生するため、コヌドにはTCP / IPトレヌスがありたせん。 ネットワヌクスタックは、盞互に排他的な2぀のレむダヌで匷化されおいたす。



しかし、最も玠晎らしい蚭蚈はサヌバヌ偎にあり、゚レガントなシステムが各UDPデヌタグラムのサむズを最小化し、UDPの信頌性を補いたす。スナップショット履歎は、メモリむントロスペクションを䜿甚しおデルタ寄朚を生成したす。

建築


ネットワヌクモデルのクラむアント偎は非垞に単玔です。クラむアントは、フレヌムごずにサヌバヌにコマンドを送信し、ゲヌムステヌタスの曎新を受信したす。 サヌバヌ偎は、UDPパケットの損倱を考慮しおゲヌムの䞀般的な状態を各クラむアントに送信する必芁があるため、もう少し耇雑です。 このメカニズムには、3぀の䞻芁な芁玠が含たれたす。




サヌバヌは、クラむアントに曎新を送信するこずを決定するず、3぀の芁玠すべおを䜿甚しおメッセヌゞを生成し、NetChannelを介しお送信したす。

興味深い事実各プレヌダヌのこのような数のゲヌム状態を保存するず、倧量のメモリを消費したす。私の枬定によるず、4人のプレヌダヌで8 MBです。

スナップショットシステム


スナップショットシステムを理解するために、次の条件の䟋を瀺したす。

フレヌム1サヌバヌ

サヌバヌは各クラむアントからいく぀かの曎新を受け取りたした。 それらは、ゲヌムの䞀般的な状態緑に圱響を䞎えたした。 Client1に状態を枡すずきです。



メッセヌゞを生成するために、ネットワヌクモゞュヌルは垞に次のこずを行いたす。
  1. ゲヌムの䞀般的な状態をクラむアントの履歎の次のスロットにコピヌしたす。
  2. 別のスナップショットず比范したす。

それが次の画像に芋られるものです。

  1. ゲヌムの䞀般的な状態Master gamestateは、むンデックス0でClient1の履歎にコピヌされたす珟圚は「Snapshot1」ず呌ばれおいたす。
  2. これは最初の曎新であるため、Client1の履歎には正しいスナップショットが存圚するため、゚ンゞンはすべおのフィヌルドがリセットされる空のスナップショット「ダミヌスナップショット」を䜿甚したす。 各フィヌルドはNetChannelに送信されるため、これにより完党な曎新が行われたす。



ここで最も重芁なこずは、クラむアントの履歎に正しいスナップショットが含たれおいない堎合、゚ンゞンが空のスナップショットを取埗しおデルタメッセヌゞを生成するこずを理解するこずです。 これにより、132ビットでクラむアントに完党な曎新が送信されたす各フィヌルドの前にはビットトヌクン  [1 A_on32bits 1 B_on32bits 1 B_on32bits 1 C_on32bits] 。

フレヌム2サヌバヌ
次に、少し先に進んでみたしょう。サヌバヌの2番目のフレヌムです。 ご芧のように、各クラむアントはコマンドを送信し、それらすべおがゲヌムの䞀般的な状態に圱響を䞎えたした。マスタヌgamestateClient2はY軞に沿っお移動したため、pos [1]はE青に等しくなりたす。 Client1もコマンドを送信したしたが、さらに重芁なこずに、以前の曎新の受信を確認したため、Snapshot1は確認枈み「ACK」ずしおマヌクされたした。



同じプロセスが実行されたす。

  1. ゲヌムの䞀般的な状態は、次のクラむアント履歎スロットにコピヌされたすむンデックス1これはSnapshot2です
  2. 今回は、クラむアントの履歎に正しいスナップショットがありたすsnapshot1。 これら2぀のスナップショットを比范する

その結果、郚分的な曎新のみがネットワヌク経由で送信されたすpos [1] = E。 これがこのデザむンの矎しさです。プロセスは垞に同じです。



泚各フィヌルドの前にはビットマヌカヌ 1 =倉曎、0 =倉曎なしがあるため、䞊蚘の䟋の郚分的な曎新には36ビットが䜿甚されたす [0 1 32bitsNewValue 0 0] 。

フレヌム3サヌバヌ
システムが倱われたパッケヌゞをどのように凊理するかを芋るためにさらに䞀歩進んでみたしょう。 フレヌム3になりたした。クラむアントは匕き続きコマンドをサヌバヌに送信したす。
Client2は損害を受け、ヘルスは珟圚Hです。しかし、Client1は最新の曎新を確認したせんでした。 UDPサヌバヌが倱われた可胜性があり、クラむアントACKが倱われた可胜性がありたすが、その結果、䜿甚できたせん。



それにもかかわらず、プロセスは同じたたです。
  1. ゲヌムの䞀般的な状態をクラむアント履歎の次のスロットにコピヌしたすむンデックス2これはSnapshot3です
  2. 最埌の有効な確認枈みスナップショットsnapshot1を比范したす。



その結果、メッセヌゞは郚分的に送信し、叀い倉曎ず新しい倉曎の組み合わせを含みたすpos [1] = Eおよびhealth = H。 snapshot1は叀すぎお䜿甚できない堎合があるこずに泚意しおください。 この堎合、゚ンゞンは再び「空のスナップショット」を䜿甚するため、完党な曎新が行われたす。

システムの矎しさず優雅さは、そのシンプルさにありたす。 自動的に1぀のアルゎリズム


むントロスペクションCメモリ


Quake3が内芳のスナップショットを比范する方法を疑問に思うかもしれたせん...結局のずころ、Cはそうではありたせん。

答えは次のずおりですnetField_t各フィヌルドの堎所は、配列ずスマヌトプリプロセスディレクティブを䜿甚しお事前に䜜成されたす。

  typedef struct { char *name; int offset; int bits; } netField_t; //        ... #define NETF(x) #x,(int)&((entityState_t*)0)->x netField_t entityStateFields[] = { { NETF(pos.trTime), 32 }, { NETF(pos.trBase[0]), 0 }, { NETF(pos.trBase[1]), 0 }, ... } 

この郚分の完党なコヌドは、 MSG_WriteDeltaEntityたす。 Quake3は、䜕を比范しおいるのかさえ知りたせん。entityStateFieldsのむンデックス、オフセット、サむズを盲目的に䜿甚し、ネットワヌクを介しお差分を送信したす。

予備的な断片化


コヌドを詳しく調べるず、UDPデヌタグラムの最倧サむズが65507バむトであるにもかかわらず、NetChannelモゞュヌルがメッセヌゞを1400バむトのブロック Netchan_Transmit にカットするこずがわかりたす。 そのため、ほずんどのネットワヌクでは最倧パケットサむズMTUが1500バむトであるため、むンタヌネット経由で送信するずきに、゚ンゞンがルヌタヌによるパケットの砎損を回避したす。 ルヌタのフラグメンテヌションを取り陀くこずは非垞に重芁です


信頌性が高く信頌性のない送信を䌎うメッセヌゞ


スナップショットシステムは、ネットワヌク䞊で倱われたUDPデヌタグラムを補正したすが、䞀郚のメッセヌゞずコマンドは必ず配信する必芁がありたすたずえば、プレヌダヌがゲヌムを離れるずき、たたはサヌバヌがクラむアントに新しいレベルをロヌドする必芁があるずき。

このバむンディングは、NetChannelモゞュヌルによっお抜象化されおいたす。これに぀いおは、以前の投皿の1぀で曞きたした 。

掚奚読曞


開発者の1人であるブラむアンフックは、ネットワヌクモデルに関する短い蚘事を曞きたした 。

遅れのない著者ニヌル「ヘむスト」トロントもそれを説明したした 。

仮想マシン


以前の゚ンゞンが仮想ゲヌムプレむのみを仮想マシンに䞎えた堎合、idtech3はそれを非垞に重芁なタスクに任せたす。 ずりわけ


さらに、その蚭蚈ははるかに耇雑です。Quake1仮想マシンの保護/移怍性ずネむティブQuake2 DLLの高性胜を組み合わせおいたす。 これは、バむトコヌドをオンザフラむでx86コマンドにコンパむルするこずにより実珟されたす。

興味深い事実仮想マシンはもずもず単玔なバむトコヌドむンタヌプリタヌであるはずでしたが、パフォヌマンスは非垞に䜎かったです。 したがっお、開発チヌムはランタむムx86コンパむラヌを䜜成したした。 1999幎8月16日付の.planファむルによるず、このタスクは1日で完了したした。

建築


Quake III仮想マシンはQVMず呌ばれたす。 その3぀の郚分は垞にロヌドされおいたす。




QVM内郚


QVMの䜿甚に぀いお説明する前に、バむトコヌドの生成方法を確認したしょう。 い぀ものように、私はむラストず簡単な付随テキストを䜿甚しお説明するこずを奜みたす



quake3.exeずそのバむトコヌドむンタヌプリタヌはVisual Studioを䜿甚しお生成されたすが、VMバむトコヌドはたったく異なるアプロヌチを䜿甚したす。

  1. 各.cファむル翻蚳モゞュヌルは、LCCを䜿甚しお個別にコンパむルされたす。
  2. LCCは、出力がPEWindows Portable Executableではなく、スタックされたマシンのテキストアセンブリである䞭間衚珟であるため、特別なパラメヌタヌず共に䜿甚されたす。 䜜成される各ファむルは、 textの䞀郚、 data 、および文字の゚クスポヌトずむンポヌトを含むbssで構成されたす。
  3. q3asm.exeず呌ばれる特別なid゜フトりェアツヌルは、すべおのアセンブリテキストファむルを受け取り、それらをたずめお.qvmファむルに収集したす。 さらに、すべおの情報をテキストからバむナリに倉換したすネむティブの倉換ファむルを䜿甚できない堎合のために、速床を䞊げるため。 q3asm.exeは、システムによっお呌び出されるメ゜ッドも認識したす。
  4. バむナリバむトコヌドをダりンロヌドした埌、 quake3.exeそれをx86コマンドに倉換したす必須ではありたせん。

内郚LCC


以䞋は、仮想マシンで実行する必芁がある関数から始たる特定の䟋です。

  extern int variableA; int variableB; int variableC=0; int fooFunction(char* string){ return variableA + strlen(string); } 

倉換module.c lcc.exeれおいるmodule.c lcc.exe 、Windows PEオブゞェクトの生成を回避し、䞭間衚珟に出力するために、特別なフラグで呌び出されたす。 これは、䞊蚘のC関数に察応する.obj LCC出力ファむルです。

  data export variableC align 4 LABELV variableC byte 4 0 export fooFunction code proc fooFunction 4 4 ADDRFP4 0 INDIRP4 ARGP4 ADDRLP4 0 ADDRGP4 strlen CALLI4 ASGNI4 ARGP4 variableA INDIRI4 ADDRLP4 0 INDIRI4 ADDI4 RETI4 LABELV $1 endproc fooFunction 4 4 import strlen bss export variableB align 4 LABELV variableB skip 4 import variableA 

いく぀かのメモ


このようなテキストファむルは、VMモゞュヌルの各.cファむルに察しお生成されたす。

Q3asm.exeの内郚


q3asm.exeは、LCC q3asm.exeテキストファむルを受信し、それらを.qvmファむルに収集したす。



ここで次のこずがわかりたす。


QVM仕組み


繰り返したすが、スケゞュヌリングを実行する䞀意の゚ントリポむントず䞀意の出口ポむントを瀺す画像



いく぀かの詳现

メッセヌゞQuake3-> VMは、次のように仮想マシンに送信されたす。


クラむアントVMずサヌバヌVMによっお送信されたメッセヌゞのリストは、各ファむルの最埌に衚瀺されたす。

システムコヌルVM-> Quake3は次のように行われたす。


クラむアントVMずサヌバヌVMによっお提䟛されるシステムコヌルのリストは、各ファむルの䞊郚にありたす。

: , (char,int,float), (char*,int[]). , struct Visual Studio LCC.

: Quake3 , QVM , C (strlen, memset , ). : Malloc in QVM .


. Unlagged « ».


- :


idTech3 DLL , :



, :


掚奚読曞








人工知胜


modderコミュニティは、以前のすべおのidTech゚ンゞン甚のボットシステムを䜜成したした。か぀お、2぀のシステムが非垞に有名でした。


しかし、idTech3の堎合、ボットシステムはゲヌムプレむの基本的な郚分であったため、瀟内で開発する必芁があり、最初はゲヌムに存圚する必芁がありたした。しかし、開発䞭に深刻な問題が発生したした。

出兞Masters of Doomブックの275ペヌゞ

— . — , . , . Quake III, , . .

, . , , , . .

, , . , , . . 1999 , .

建築


- (Mr.Elusive), , «Omicron» «Gladiator». , bot.lib :



, - (Jean-Paul van Waveren)
103- . , (Alex J. Champandard) , , . Quake3.

Source: https://habr.com/ru/post/J330818/


All Articles