Demo analisis kode Realitas Kedua


Pada 23 Juli 2013, kode sumber untuk demo Realitas Kedua (1993) diterbitkan . Seperti banyak orang, saya sangat ingin melihat bagian dalam demo yang telah menginspirasi kami selama ini.

Saya berharap untuk melihat kekacauan monolitik dari assembler, tetapi alih-alih mengejutkan saya, saya menemukan arsitektur kompleks yang menggabungkan beberapa bahasa dengan anggun. Saya belum pernah melihat kode seperti itu sebelumnya, dengan sempurna mewakili dua aspek integral dari pengembangan demo:

  • Kerja tim.
  • Kebingungan.

Seperti biasa, saya membentuk artikel untuk catatan saya: Saya harap ini menyelamatkan seseorang beberapa jam, dan mungkin menginspirasi orang lain untuk membaca lebih banyak kode sumber dan menjadi insinyur yang lebih berpengalaman.

Bagian 1: Pendahuluan


Demo


Sebelum memulai kodenya, saya akan memberikan tautan untuk menangkap demo legendaris dalam video HD (Michael Hut). Hari ini, ini adalah satu-satunya cara untuk sepenuhnya mengevaluasi demo tanpa gangguan grafis (bahkan DOSBox tidak dapat meluncurkannya dengan benar).


Kontak pertama dengan kode


Kode sumber diposting di GitHub. Cukup masukkan satu perintah git:

git clone git@github.com:mtuomi/SecondReality.git

Pada awalnya, konten membingungkan: 32 folder dan misterius U2.EXEyang tidak dimulai di DosBox.


Demo tersebut memiliki judul kerja "Unreal 2" (yang pertama "Unreal" adalah demo Future Crew sebelumnya, dirilis untuk Majelis pertama pada tahun 1992). Dan hanya selama proses pengembangan nama diubah menjadi "Realitas Kedua". Ini menjelaskan nama file "U2.EXE", tetapi bukan mengapa file tidak berfungsi ...

Jika Anda menjalankan CLOC , kami akan mendapatkan metrik yang menarik:

    -------------------------------------------------------------------------------
                                                   
    -------------------------------------------------------------------------------
    Assembly                        99           3029           1947          33350
    C++                            121           1977            915          24551
    C/C++ Header                     8             86            240            654
    make                            17            159             25            294
    DOS Batch                       71              3              1            253
    -------------------------------------------------------------------------------
    SUM:                           316           5254           3128          59102
    -------------------------------------------------------------------------------

  • «» 50% .
  • Doom.
  • Ia memiliki tujuh belas makefile. Kenapa tidak satu saja?

Luncurkan demo


Sulit untuk mengetahuinya, tetapi demo yang dirilis dapat diluncurkan di DosBox: Anda perlu mengubah nama U2.EXEdan menjalankannya dari tempat yang tepat.

Ketika saya belajar tentang cara kerja kode, itu mulai terlihat sangat logis:

        CD MAIN
        PINDAHKAN DATA U2.EXE / SECOND.EXE
        DATA CD
        SECOND.EXE

Dan voila!


Arsitektur


Pada 90-an, demo sebagian besar didistribusikan di floppy disk. Setelah membongkar, perlu menginstal dua file besar: SECOND.EXEdan REALITY.FC:

    . <DIR> 08/08/2013 16:40
    .. <DIR> 08/01/2013 16:40
    FCINFO10 TXT 48.462 04-10-1993 11:48
    FILE_ID DIZ 378 04-10-1993 11:30
    README 1ST 4.222 04-10-1993 12:59
    REALITY FC 992.188 07-10-1993 12:59 
    EXE KEDUA 1.451.093 07-10-1993 13:35
        5 File 2.496.343 Bytes.
        2 Dir (s) 262.111.744 Bytes gratis.

Berdasarkan pengalaman saya dalam pengembangan game, saya selalu berharap bahwa keseluruhan gambar akan terlihat seperti ini:

  • SECOND.EXE: engine dengan semua efek dalam file yang dapat dieksekusi.
  • REALITY.FC: Aset (musik, efek suara, gambar) dalam format berpemilik / terenkripsi ala WADDoom.

Tetapi setelah membacanya, MAIN/PACK.Csaya menemukan bahwa saya sangat keliru: mesin Reality Kedua hanyalah Loader dan server Interrupt (disebut DIS). Setiap adegan (juga disebut "BAGIAN") demo adalah executable DOS yang berfungsi penuh. Setiap bagian dimuat oleh Loader loader dan diluncurkan satu demi satu. Bagian disimpan dalam bentuk terenkripsi pada akhirnya SECOND.EXE:


  • REALITY.FC berisi dua komposisi musik yang dimainkan selama demo (untuk mengisi kebingungan ditambahkan pengisian dan spidol di awal).
  • SECOND.EXE berisi bootloader dan Demo Interrupt Server (DIS).
  • Setelah akhir SECOND.EXE, 32 bagian (BAGIAN) dari demo ditambahkan sebagai file DOS yang dapat dieksekusi (dienkripsi).

Arsitektur seperti itu memberikan banyak keuntungan:

  • : PART , _start (450 ).
  • EXE SECOND.EXE -.
  • : Loader DIS 20 . DOS .
  • : PART PART .
  • / : , PART ( ), : EXE , .
  • Bahasa apa pun dapat digunakan untuk pemrograman PART: dalam kode kita menemukan C, Assembly ... dan Pascal.

Bacaan yang Disarankan


Tiga pilar untuk memahami kode sumber Realitas Kedua adalah VGA, assembler, dan arsitektur PC (pemrograman PIC dan PIT). Berikut ini beberapa tautan yang sangat berguna:


Bagian 2: Mesin Realitas Kedua


Sebagaimana dibahas dalam Bagian 1, fondasi Realitas Kedua terdiri dari:

  • Bootloader sebagai executable DOS.
  • Manajer memori (kumpulan tumpukan sederhana)
  • Demo Interrupt Server (DIS).

Pada bagian ini saya akan memberikan rekomendasi kepada programmer yang ingin membaca engine dan bootloader (DIS akan dibahas pada bagian selanjutnya).

Kode mesin


Kode mesin adalah 100% ASM, tetapi ditulis dengan sangat baik dan didokumentasikan dengan cukup baik:


Dalam pseudo-code dapat ditulis seperti ini:

    exemus  db 'STARTMUS.EXE',0
    exe0    db 'START.EXE',0
    ...
    exe23   db 'ENDSCRL.EXE',0

    start:
       cli                         ; Disable all interrupts
       mov     ah,4ah              ; Deallocate all memory
       call checkall               ; Check for 570,000 bytes of mem, 386 CPU and VGA
       call file_getexepath        
       call dis_setint             ; Install Demo Interrupt Server on Interrupt 0fch
       call file_initpacking       ; Check exe signature (no tempering) !
       call file_setint            ; Replace DOS routines (only OPENFILE, SEEK and READ) on Interrupt 021h
       call flushkbd               ; Flush the keyboard buffer
       
       call  checkcmdline          ; check/process commandline

       ;======== Here we go! ========
       call vmode_init             ; Init VGA (not necessarly Mode13h or ModeX), each PARTs had its own resolution

       mov si,OFFSET exe0
       call executehigh            ; loaded to high in memory. Used for loading music loaders and stuff.
   
       call  _zinit ; Start music
       call  restartmus

       mov   si,OFFSET exe1     ;Parameter for partexecute: Offset to exec name
       call  partexecute
       ; Execute all parts until exe23

       call fademusic
       ;======== And Done! (or fatal exit) ========

    fatalexit:
       mov cs:notextmode,0
       call vmode_deinit

Semua langkah cukup mudah dibaca:

  1. Atur DIS interrupt server sebagai interrupt 0fch.
  2. Mengganti panggilan sistem DOS dengan interupsi 021h(untuk lebih jelasnya, lihat bagian "Dev and Prod Mode" ).
  3. Unduh musik ke kartu suara melalui memori EMS.
  4. Menjalankan musik.
  5. Melakukan setiap bagian dari demo.
  6. Selesai!

Detail prosedur execute:

 execute:
      cld
      call  openfile ; Open the DOS executable for this PART
      call  loadexe  ; loads the specified exe file to memory, does relocations and creates psp
      call  closefile
      call  runexe   ;runs the exe file loaded previously with loadexe.
                     ; returns after exe executed, and frees the memory
                     ; it uses.

Manajer memori


Ada banyak legenda bahwa Realitas Kedua menggunakan manajer memori yang kompleks melalui MMU, tidak ada jejak di mesin. Manajemen memori sebenarnya ditransfer ke DOS: mesin mulai dengan membebaskan semua RAM dan kemudian mendistribusikannya berdasarkan permintaan . Satu-satunya trik rumit adalah kemampuan untuk mengalokasikan RAM dari akhir heap: itu dilakukan dengan menggunakan nilai pengembalian DOS malloc ketika terlalu banyak RAM diminta .

Bagian 3: DIS


Demo Interrupt Server (DIS) menyediakan berbagai layanan untuk setiap BAGIAN: dari pertukaran data antara BAGIAN yang berbeda hingga sinkronisasi dengan VGA.

Layanan DIS


Pada saat run-time, PART, server DIS menyediakan layanan untuk itu. Daftar fitur dapat ditemukan di DIS/DIS.H.

Layanan yang paling penting:

  • Pertukaran antara PART yang berbeda ( dis_msgarea): DIS menyediakan tiga buffer masing-masing 64 byte sehingga PART dapat menerima parameter dari loader PART sebelumnya.
  • Emulation Copper ( dis_setcopper): Amiga Copper simulator yang memungkinkan Anda untuk melakukan operasi yang diaktifkan oleh keadaan VGA.
  • Mode Dev / Prod ( dis_indemo): memungkinkan PART mengetahui bahwa ia sedang berjalan dalam mode DEV (yang berarti harus menginisialisasi video) atau diluncurkan dari bootloader dalam mode PROD.
  • Jumlah Bingkai VGA ( _dis_getmframe)
  • Menunggu backstop VGA ( dis_waitb).

Demo Server Interupsi Kode


Kode sumber DIS juga ASM 100% ... dan cukup dikomentari:


Bagaimana itu bekerja


DIS diatur sebagai pengendali interupsi untuk int terprogram 0fch. Hal yang hebat tentang itu adalah bahwa ia dapat berjalan secara internal SECOND.EXEketika demo sedang berjalan, atau sebagai program penduduk ( TSR ) dalam mode Dev. Fleksibilitas ini memungkinkan Anda untuk secara individual menguji berbagai demo PART selama pengembangan:

                          // Mari kita berpura-pura bahwa kita adalah pengembang FC dan ingin memulai bagian STAR secara langsung.
  C: \> CD DDSTARS            
  C: \ DDSTARS> K

  GALAT: DIS tidak dimuat. 

                          // Ups, BAGIAN itu tidak dapat menemukan DIS di int 0fch.
  C: \ DDSTARS> CD .. \ DIS
  C: \ DIS> DIS

  Demo Int Server (DIS) V1.0 Hak Cipta (C) 1993 The Future Crew
  BETA VERSION - Disusun: 07/26/93 03:15:53 
  Terpasang (int fc).
  CATATAN: Server DIS ini tidak mendukung sinkronisasi tembaga atau musik!
                          // DIS terinstal, mari kita coba lagi.

  C: \ DIS> CD ../DDSTARS
  C: \ DDSTARS> K

Dan voila!


Tembaga



"Copper" adalah coprocessor yang sangat disukai oleh para pengembang demo untuk Amiga. Itu adalah bagian dari Kumpulan Chip Asli dan memungkinkan Anda untuk menjalankan aliran perintah yang dapat diprogram yang disinkronkan dengan peralatan video. Tidak ada coprocessor seperti itu di PC, dan Future Crew harus menulis simulator Copper yang berjalan di dalam DIS.

Tim FC menggunakan chipset perangkat keras PC 8254-PIT dan 8259-PIC untuk mensimulasikan Tembaga. Dia menciptakan sistem yang disinkronkan dengan frekuensi VGA , yang mampu memulai prosedur di tiga tempat sinar mundur vertikal :

  • Tempat 0: setelah menyalakan layar (kira-kira pada garis pindai 25)
  • Tempat 1: segera setelah sapuan sinar terbalik (MUNGKIN UNTUK MENGHINDARI IT MUNGKIN)
  • Tempat 2: di balok terbalik dari berkas pindai

Cara ini dilakukan dapat dibaca MAIN/COPPER.ASM(dan lihat pada diagram di bawah):

  1. Timer dari chip 8254 dikonfigurasi untuk memicu IRQ0 dengan frekuensi yang diinginkan.
  2. The 8h interrupt handler (yang disebut oleh 8259 PIC setelah menerima IRQ0) adalah diganti dengan prosedur di sini intti8.

Catatan: Layanan jumlah bingkai DIS sebenarnya disediakan oleh simulator tembaga.

Bagian 4: Mode Dev dan Prod


Membaca kode sumber Realitas Kedua, Anda paling dikejutkan oleh seberapa besar perhatian tim terhadap perubahan mulus dari DEV ke PROD.

Mode Pengembangan



Dalam mode Pengembangan, setiap komponen demo adalah file yang dapat dieksekusi terpisah.

  • DIS dimuat ke TSR penduduk dan diakses melalui interupsi 0cfh.
  • Bootloader menyebabkan interupsi DOS 21huntuk membuka, membaca, mencari, dan menutup file.

Konfigurasi DEV ini memiliki keuntungan sebagai berikut:

  • Setiap pembuat kode dan artis dapat mengerjakan file yang dapat dieksekusi dan mengujinya secara terpisah, tanpa memengaruhi anggota tim lainnya.
  • Demo lengkap kapan saja dapat diuji menggunakan yang kecil SECOND.EXE(tanpa menambahkan semua EXE sampai akhir). Eksekusi setiap BAGIAN dimuat menggunakan interupsi DOS 021hdari file terpisah.

Produksi (mode demo)



Dalam mode Produksi, kecil SECOND.EXE(berisi bootloader), DIS, dan bagian dari demo sebagai EXE yang terpisah digabungkan menjadi satu yang tebal SECOND.EXE.

  • Akses ke DIS masih dilakukan melalui interupsi 0fch.
  • API interupsi DOS 21j telah ditambal oleh rutinitas Future Crew-nya sendiri, yang membuka file dari ujung file besar SECOND.EXE.

Konfigurasi PROD ini memiliki keunggulan dalam hal waktu muat dan perlindungan terhadap rekayasa balik ... tetapi yang paling penting, dari sudut pandang pemrograman atau memuat PART, TIDAK ADA perubahan saat beralih dari DEV ke PROD.

Bagian 5: BAGIAN terpisah


Setiap efek visual Realitas Kedua adalah executable DOS yang berfungsi penuh. Mereka disebut BAGIAN dan semuanya 23. Solusi arsitektural yang demikian memungkinkan untuk prototyping cepat, pengembangan paralel (karena FC kemungkinan besar tidak memiliki alat kontrol versi) dan pilihan bahasa yang bebas (ASM, C, dan bahkan Pascal ditemukan dalam sumber).

BAGIAN terpisah


Daftar semua PART / EXE dapat ditemukan dalam kode sumber mesin: U2.ASM . Berikut ini adalah deskripsi singkat yang lebih nyaman dari ke-23 bagian (dengan lokasi kode sumber, meskipun nama-nama tersebut dapat sangat membingungkan):

JudulFile yang dapat dieksekusiCoderTangkapan layarSumber
STARTMUS.EXEMAIN / STARTMUS.C
MULAI.EXEKEBAKARANMULAI / MAIN.c
Bagian tersembunyiDDSTARS.EXEKEBAKARANDDSTARS / STARS.ASM
Alkutekstit iALKU.EXEKEBAKARANALKU / MAIN.C
Alkutekstit IIU2A.EXEPSIVISU / C / CPLAY.C
Alkutekstit IIIPAM.EXETRUG / WILDFIREPAM /
BEGLOGO.EXEBEG / BEG.C
GlenzGLENZ.EXEPSIGLENZ /
DottitunneliTUNNELI.EXETRUGTUNNELI / TUN10.PAS
TechnoTECHNO.EXEPSITECHNO / KOEA.ASM
PanicfakePANICEND.EXEPSIPanik
Vuori-gulirMNTSCRL.EXEHUTAN / READ2.PAS
Gurun mimpi bintangDDSTARS.EXETRUG
LensaPSI
RotazoomerLNS & ZOOM.EXEPSILENS /
PlasmaKEBAKARAN
PlasmacubePLZPART.EXEKEBAKARANPLZPART /
MiniVectorBallsMINVBALL.EXEPSIDOTS /
PeilipalloscrollRAYSCRL.EXETRUGAIR / DEMO.PAS
Medan sinus 3D3DSINFLD.EXEPSICOMAN / DOLOOP.C
JellypicJPLOGO.EXEPSIJPLOGO / JP.C
Vektor Bagian II 'U2E.EXEPSIVISU / C / CPLAY.C
Keterangan / Ucapan Terima Kasih
ENDLOGO.EXEEND / END.C
CRED.EXEKEBAKARANKREDIT / UTAMA.C
ENDSCRL.EXEENDSCRL / MAIN.C

Tampaknya setiap pengembang memiliki spesialisasi sendiri, yang dapat dibagikan dalam satu bagian. Ini terutama terlihat dalam adegan pertama dengan scrolling, kapal dan ledakan (Alkutekstit). Meskipun ini terlihat seperti satu efek berkelanjutan, sebenarnya itu adalah tiga file yang dapat dieksekusi yang ditulis oleh tiga orang yang berbeda:

Urutan Alkutekstit (Kredit)
ALKU oleh WILDFIREU2A oleh PSIPAM oleh TRUG / WILDFIRE

Aktiva


Aset Gambar ( .LBM) dihasilkan menggunakan Deluxe Paint , editor bitmap yang sangat populer di tahun 90-an. Menariknya, mereka dikonversi ke array byte dan dikompilasi di dalam PART. Sebagai akibatnya, file exe ini juga mengunduh semua aset. Selain itu, ini menyulitkan reverse engineering.

Di antara set aset keren adalah CITY dan SHIP terkenal dari adegan 3D terbaru:



BAGIAN unit internal


Karena mereka semua dikompilasi ke dalam executable DOS, di PART, bahasa apa pun dapat digunakan:


Sedangkan untuk penggunaan memori, saya membaca banyak tentang MMU di Wikipedia dan situs web lain ... tetapi pada kenyataannya, setiap bagian dapat menggunakan apa saja, karena setelah eksekusi itu benar-benar diturunkan dari memori.

Saat bekerja dengan VGA, setiap bagian menggunakan serangkaian triknya sendiri dan bekerja dalam resolusinya. Dalam semua itu, bukan Mode 13h dan bukan ModeX yang digunakan, melainkan mode 13h mode yang dimodifikasi dengan resolusi sendiri. File SCRIPT sering menyebutkan 320x200 dan 320x400.

Sayangnya, ketika menganalisis PART, membaca kode sumber menjadi tugas yang menakutkan: kualitas kode dan komentar menurun secara dramatis. Mungkin ini terjadi karena kesibukan atau karena setiap BAGIAN bekerja pada pengembangnya sendiri (yaitu, tidak ada kebutuhan "nyata" untuk komentar atau kelengkapan kode), tetapi hasilnya adalah sesuatu yang benar-benar membingungkan:


Algoritma yang canggih tidak hanya sulit untuk memahami bahkan nama-nama variabel ( a, b, co[]...). Kode akan jauh lebih mudah dibaca jika pengembang meninggalkan kami petunjuk dalam catatan rilis. Akibatnya, saya tidak mencurahkan banyak waktu untuk mempelajari setiap bagian; Pengecualian adalah mesin 3D yang bertanggung jawab untuk U2A.EXE dan U2E.EXE.

Mesin 3D Realitas Kedua




Lagi pula, saya memutuskan untuk mempelajari secara detail mesin 3D, yang digunakan dalam dua bagian: U2A.EXEdan U2E.EXE.

Kode sumbernya adalah C dengan prosedur yang dioptimalkan assembler (terutama mengisi dan menaungi Gouro):

  • CITY.C (kode utama).
  • VISU.C (perpustakaan visu.lib).
  • AVID.ASM (video assembler yang dioptimalkan (pembersihan, penyalinan layar, dll.)).
  • ADRAW.ASM (menggambar objek dan memotong).
  • ACALC.ASM (matriks dan perhitungan dosa / cos cepat).


Arsitektur komponen ini cukup luar biasa: perpustakaan VISUmelakukan semua tugas yang kompleks, misalnya, memuat aset: objek 3DS, bahan dan aliran (pergerakan kamera dan kapal).

Mesin mengurutkan objek yang perlu digambar, dan membuatnya menggunakan algoritma artis. Ini mengarah ke sejumlah besar redrawing, tetapi karena kait VGA memungkinkan Anda untuk merekam 4 piksel pada saat yang sama, itu tidak terlalu buruk.

Fakta yang menarik: mesin melakukan transformasi dengan cara "old-school": alih-alih menggunakan matriks 4x4 homogen yang umum, ia menggunakan matriks rotasi 3 * 3 dan vektor perpindahan.

Berikut ini ringkasan dalam kode pseudo:

      main(){

            scenem=readfile(tmpname);  // Load materials
            scene0=readfile(tmpname);  // Load animation

            for(f=-1,c=1;c<d;c++){  //Load objects
              sprintf(tmpname,"%s.%03i",scene,e);
              co[c].o=vis_loadobject(tmpname);
            }

            vid_init(1);
            vid_setpal(cp);

            for(;;){

                vid_switch();
                _asm mov bx,1   _asm int 0fch // waitb for retrace via copper simulator interrupt call 
                vid_clear();
                
                // parse animation stream, update objects
                for(;;){}

                vid_cameraangle(fov); // Field of vision

                // Calc matrices and add to order list (only enabled objects)
                for(a=1;ac<conum;a++) if(co[a].on) /* start at 1 to skip camera */
                    calc_applyrmatrix(o->r,&cam);

                // Zsort via Bubble Sort
                for(a=0;ac<ordernum;a++)
                    for(b=a-1;b>=0 && dis>co[order[b]].dist;b--)

                // Draw
                for(a=0;ac<ordernum;a++)
                    vis_drawobject(o);
              }
            }
            return(0);
     }

Pelabuhan untuk sistem modern


Setelah rilis artikel ini, banyak pengembang mulai port Realitas Kedua ke sistem modern. Claudio Matsuoka mulai membuat sr-port , port C untuk Linux dan OpenGL ES 2.0, yang sejauh ini terlihat cukup mengesankan. Nick Kovacs melakukan pekerjaan yang baik pada PART PLZ, memindahkannya ke C (sekarang ini adalah bagian dari kode sumber sr-port), dan juga untuk javascript :


All Articles