1 poin oleh GN⁺ 2024-06-14 | 1 komentar | Bagikan ke WhatsApp
  • Serious Engine 1 menempatkan single-player, multiplayer, dan pemutaran demo di atas simulasi deterministik yang sama; alih-alih mencatat atau mengirim seluruh state setiap tick, engine ini mencatat dan mengirim aksi pemain serta blok stream game
  • Demo dan multiplayer berbagi state game awal lalu menerapkan delta input seperti CPlayerAction, sehingga seed angka acak dan determinisme logika game menjadi kunci sinkronisasi
  • Lapisan jaringan menangani sendiri nomor urut, ACK, retransmisi, pembatasan bandwidth, dan buffer per koneksi di atas UDP, agar permainan tetap berjalan bahkan pada jalur lambat
  • CNetworkMessage menyediakan serialisasi, kompresi LZ77/LZRW1, dan delta encoding berbasis XOR, tetapi pesan termasuk chat tidak dienkripsi dan bisa hanya dikompresi
  • Model client-server Serious Sam menghemat bandwidth karena tiap klien mempertahankan simulasinya sendiri, tetapi sebagai gantinya membutuhkan perangkat pendukung seperti verifikasi sinkronisasi, prediksi, retransmisi, dan pemeriksaan CRC

Struktur simulasi bersama Serious Engine

  • Kode sumber Serious Engine 1 dirilis sebagai GNU GPL v2 pada 2016, dan analisis ini didasarkan pada pembacaan serta debugging codebase publik tersebut
  • Serious Sam sejak awal dirancang sebagai game multiplayer, dan kampanye single-player secara internal berjalan seperti kasus khusus dari struktur multiplayer
  • Mode yang didukung engine adalah sebagai berikut
    • Kampanye single-player offline
    • Co-op online, LAN, lokal, serta beberapa mode game
    • Split-screen, dengan beberapa pemain berpartisipasi dari satu klien
    • Perekaman dan pemutaran demo

Perekaman demo: mencatat aksi, bukan seluruh state

  • Jika demo disimpan sebagai seluruh state game pada setiap tick, ukuran file akan membesar; karena itu Serious Engine menyimpan seluruh state game satu kali pada saat perekaman dimulai, lalu mencatat blok stream game pada setiap tick berikutnya
  • Blok stream game berisi tipe pesan berikut
    • MSG_SEQ_ALLACTIONS: aksi pemain
    • MSG_SEQ_ADDPLAYER: penambahan pemain
    • MSG_SEQ_REMPLAYER: penghapusan pemain
    • MSG_SEQ_PAUSE: jeda atau melanjutkan
    • MSG_SEQ_CHARACTERCHANGE: perubahan atribut karakter pemain
  • Intinya adalah MSG_SEQ_ALLACTIONS; engine mendeserialisasi objek CPlayerAction untuk setiap pemain aktif dan menerapkannya ke CPlayerTarget
  • CPlayerAction menyimpan state pemain
    • Kecepatan gerak berbasis ruang dunia pa_vTranslation
    • Rotasi karakter berbasis ruang dunia pa_aRotation
    • Rotasi pandangan berbasis ruang dunia pa_aViewRotation
    • Tombol yang sedang ditekan pa_ulButtons
    • Timestamp milidetik berbasis TSC pa_llCreated
  • Saat pemutaran, engine membaca state game awal dan menerapkan aksi pemain di tiap tick seperti permainan sungguhan

Mengapa determinisme diperlukan

  • Struktur ini berasumsi bahwa semua hal di dalam game sepenuhnya dapat diprediksi, dan hanya aksi pemain yang mengubah game
  • Angka acak pun ditangani dengan generator pseudo-random yang menggunakan seed sebagai bagian dari state game
    • CEntity::IRnd() menggunakan CSessionState::Rnd()
    • ses_ulRandomSeed diinisialisasi selama proses deserialisasi state game
  • Jika menggunakan generator angka acak sungguhan atau seed yang berbeda, hasil pemutaran demo yang sama dapat berubah, dan ini mengarah pada ketidakcocokan sinkronisasi

Floating point dan pemrosesan tick

  • Serious Sam versi PC awalnya dirilis khusus Windows, sehingga asumsi penggunaan compiler dan runtime yang sama mengurangi masalah sinkronisasi floating point
  • Renderer berbentuk DLL, dan pemanggilan API OpenGL atau DirectX dapat mengubah presisi FPU; karena itu Serious Engine menggunakan guard presisi seperti CSetFPUPrecision FPUPrecision(FPT_24BIT)
  • Tidak ditemukan tempat yang secara eksplisit mengatur kontrol pembulatan, tetapi ada assert yang memeriksa status _RC_NEAR melalui _controlfp
  • Logika game dipisahkan dari framerate rendering
    • Rendering berubah sesuai hardware dan pengaturan, dan tampaknya dibatasi secara internal pada 500 FPS
    • Logika game dikunci pada 20 tick per detik
  • Gerakan halus dibuat dengan interpolasi linear antara tick saat ini dan tick sebelumnya, dan interpolasi dapat dimatikan dari konsol dengan /net_bLerping=0

Lapisan paket sendiri di atas UDP

  • Di multiplayer Serious Engine masih tersisa nama fungsi seperti StartPeerToPeer_t, tetapi model sebenarnya adalah struktur client-server
  • Server menerima dan memproses pesan klien, lalu meneruskan informasi terkait ke semua klien
  • Tiap pemain menjalankan simulasinya sendiri, mirip sistem demo, dan memajukan state dengan menerima informasi aksi pemain lain
  • Jaringan menggunakan UDP, dengan protokol sendiri di atasnya untuk mengatasi urutan paket yang terbalik dan kehilangan paket
  • CPacket mengelola urutan dan reliabilitas paket
    • pa_ulSequence: melakukan pengurutan dan penghapusan duplikat sebagai nomor urut
    • pa_ubReliable: menyimpan flag reliabilitas
    • pa_ubRetryNumber: melacak jumlah retransmisi
    • pa_tvSendWhen: digunakan untuk waktu pengiriman terjadwal dan kontrol kemacetan
  • Paket reliabel menunggu ACK, dan akan dikirim ulang jika ACK tidak ada
    • Jumlah percobaan ulang maksimum diatur oleh net_iMaxSendRetries, dengan nilai default tampaknya 10
    • Interval retransmisi diatur oleh net_fSendRetryWait, dengan nilai default tampaknya 0.5f
  • Paket reliabel dapat membentuk stream yang terbagi menjadi beberapa paket
    • Paket pertama adalah UDP_PACKET_RELIABLE_HEAD
    • Paket terakhir adalah UDP_PACKET_RELIABLE_TAIL
    • Paket reliabel tunggal memiliki kedua flag tersebut
  • Paket non-reliabel tidak membentuk stream karena stream dapat rusak jika terjadi kehilangan paket

Siklus hidup koneksi dan routing paket

  • CCommunicationInterface menangani komunikasi lapisan paket dan memiliki fungsi antarmuka untuk server, klien, dan broadcast
  • Antarmuka server dan klien berasumsi bahwa tujuan koneksi sudah diketahui, sedangkan antarmuka broadcast digunakan untuk kirim-terima dengan alamat arbitrer
  • CCommunicationInterface mempertahankan dua master buffer
    • cci_pbMasterInput: menyimpan paket UDP masuk setelah dideserialisasi menjadi CPacket
    • cci_pbMasterOutput: menserialisasi CPacket yang akan dikirim dan mengirimkannya lewat API socket
  • Abstraksi komunikasi aktual per klien ditangani oleh CClientInterface
    • Server memiliki antarmuka tiap pemain dalam array cm_aciClients
    • Klien berkomunikasi dengan server melalui cm_ciLocalClient
    • Baik klien maupun server menggunakan cm_ciBroadcast untuk pembentukan koneksi
  • adr_uwID pada CAddress digunakan sebagai pengenal unik klien atau penanda paket broadcast
    • Jika nilainya '//' atau 0, itu adalah paket broadcast
    • Nilai lain adalah ID klien dalam sesi

Pembentukan koneksi dan mekanisme keamanan dasar

  • Untuk terhubung ke server, klien mengirim paket broadcast reliabel dengan flag UDP_PACKET_CONNECT_REQUEST
  • Server mengabaikan permintaan jika klien dengan alamat dan port yang sama sudah terhubung
  • Jika klien baru, server mencari antarmuka klien kosong lalu melakukan hal berikut
    • Membuat pengenal unik untuk klien tersebut
    • Mengirim pengenal tersebut ke klien melalui paket broadcast reliabel UDP_PACKET_CONNECT_RESPONSE
  • Pengenal tidak hanya memakai indeks tetap, melainkan dibuat dengan menggabungkan sebagian nilai timer dan indeks klien
  • Untuk menyamar sebagai pemain lain, penyerang harus menebak uwID, sehingga permukaan serangan berkurang
  • Jika pemain yang tidak terhubung mengirim paket non-broadcast, Serious Engine dapat menampilkan peringatan di konsol

Single-player dan demo sebagai kasus khusus koneksi lokal

  • Pemutaran single-player dan demo pun secara internal memiliki server dan klien, tetapi berjalan dalam proses yang sama
  • Karena tidak perlu memakai socket antar-proses yang sama, Client_OpenLocal() menghubungkan antarmuka klien lokal dengan antarmuka sisi server
  • Dua CClientInterface yang terhubung memindahkan paket dari buffer output satu sisi ke buffer input sisi lain melalui ExchangeBuffers
  • Permainan lokal tidak perlu melewati master buffer input/output dan socket jaringan nyata

Lapisan pesan jaringan

  • CNetworkMessage adalah abstraksi pesan di atas paket, dan dapat dibaca serta ditulis seperti stream
  • Pesan diserialisasi dan dideserialisasi melalui Read, Write, ReadBits, WriteBits, serta operator << dan >>
  • Pesan juga dapat memuat subpesan, dan setelah data yang diperlukan ditulis, ukuran buffer dapat disesuaikan dengan ukuran data melalui Shrink
  • Buffer CNetworkMessage dialokasikan melalui AllocMemory, yang secara internal tampaknya memanggil malloc
  • CLinearAllocator memang ada, tetapi tidak ditemukan tempat penggunaannya; buffer pesan sering dialokasikan dan direalokasi

Kompresi dan delta encoding

  • Pesan dapat dikompresi dengan kompresor yang ditentukan atau kompresor default per tipe pesan
  • Pada MESSAGETYPE, 6 bit bawah adalah tipe, dan 2 bit sisanya menunjukkan metode kompresi
    • LZ77 CzlibCompressor
    • LZRW1 CLZCompressor
    • Tanpa kompresi
  • Kompresi default tampaknya LZRW1, dan dapat diubah dengan variabel shell net_iCompression
  • CPlayerAction tidak dikirim apa adanya; engine membuat dan mengirim delta dari hasil XOR antara aksi saat ini dan aksi terakhir
  • Penerima memulihkan CPlayerAction asli dengan melakukan XOR ulang delta dengan aksi terakhir
  • Delta lebih mudah dikompresi ketika perubahan data kecil
    • Tombol yang ditekan sering tetap sama selama beberapa frame
    • Kecepatan dan rotasi pandangan juga tidak banyak melompat-lompat di seluruh rentang floating point
  • Efek metode ini bisa lebih besar saat server mengirim aksi beberapa pemain sekaligus melalui MSG_SEQ_ALLACTIONS

Enkripsi pesan dan chat

  • Pesan Serious Engine tidak dienkripsi
  • Jika kompresi dimatikan dengan net_iCompression=0, pesan chat dalam game terlihat sebagai plaintext di payload paket UDP
  • Dalam kondisi nyata ketika kompresi aktif, penyadap paket harus mengenali dan mendekompresi stream kompresi LZ, tetapi data yang diperlukan ada di dalam paket
  • Game pada masa itu sering kali tidak menangani enkripsi, dan implementasi mekanisme seperti autentikasi dan pertukaran kunci dapat menambah kompleksitas
  • Web pada masa itu pun sebagian besar masih HTTP

Lapisan sesi game

  • Meski namanya begitu, CNetworkLibrary mengelola sesi game termasuk state game CSessionState
  • CNetworkLibrary mewarisi CMessageDispatcher yang disebut sebelumnya
  • Saat server dimulai, engine melakukan prosedur berikut
    • Menginisialisasi pengumpulan CRC untuk menyiapkan pemeriksaan apakah klien yang terhubung memiliki file yang sama dengan server
    • Membuat CSessionState baru dan menserialisasikannya sebagai state dasar ga_pubDefaultState
    • Memuat instance dunia lokal
    • Menginisialisasi antarmuka komunikasi global
    • Menginisialisasi state sesi lokal, dan saat klien terhubung, memungkinkan pengiriman delta state antara state dasar dan state server saat ini
    • Menyelesaikan pengumpulan CRC dan menyimpannya ke ga_ulCRC
  • Pemeriksaan CRC lebih mirip deteksi dini ketidakcocokan sinkronisasi daripada pencegahan cheat
  • Prosedur klien bergabung mengikuti alur berikut
    • Menginisialisasi state sesi lokal kosong dan antarmuka komunikasi
    • Mengirim versi build, nama mode, password server, jumlah pemain lokal, dan CSessionSocketParams melalui MSG_REQ_CONNECTREMOTESESSIONSTATE
    • Menerima pesan, nama file dunia, flag tingkat kesulitan dan mode game, serta atribut sesi melalui MSG_REP_CONNECTREMOTESESSIONSTATE
    • Menginisialisasi state game acuan
    • Mengirim MSG_REQ_STATEDELTA untuk meminta perbedaan dengan state server saat ini
    • Setelah menerima MSG_REP_STATEDELTA, merekonstruksi stream state game dengan diff terbalik
    • Menginisialisasi state sesi lokal melalui CSessionState::Read_t()
    • Melakukan pemeriksaan CRC dan memutus koneksi jika tidak cocok

Main loop dan retransmisi stream game

  • Main loop klien dan server umumnya mirip, tetapi server melakukan pekerjaan tambahan
  • Loop memperbarui antarmuka klien lokal dan antarmuka broadcast, lalu state sesi lokal memproses pesan jaringan yang masuk
  • Server juga menangani pertukaran buffer antar-antarmuka klien yang dipasangkan, pembaruan antarmuka klien sisi server, pembaruan GameAgent, serta pemrosesan perintah shell administrasi jarak jauh
  • SessionStateLoop() memproses pesan non-reliabel dan reliabel secara terpisah
    • Non-reliabel: MSG_GAMESTREAMBLOCKS, MSG_KEEPALIVE, MSG_INF_PINGS, MSG_CHAT_OUT
    • Reliabel: MSG_INF_DISCONNECTED, MSG_ADMIN_RESPONSE
  • MSG_GAMESTREAMBLOCKS adalah pesan non-reliabel, tetapi jika hilang, sinkronisasi dapat rusak
  • Serious Engine memeriksa sequence yang hilang pada tahap pemrosesan stream game dan meminta retransmisi
    • Jika blok sequence berikutnya yang diharapkan ada, blok itu diproses
    • Jika blok berikutnya tidak ada dan blok yang lebih baru juga tidak ada, loop tersebut tidak melakukan apa pun
    • Jika blok berikutnya tidak ada tetapi ada blok yang lebih baru, ada kemungkinan kehilangan, sehingga timeout ditetapkan
    • Setelah timeout, engine meminta sequence blok yang hilang dan jumlahnya melalui MSG_REQUESTGAMESTREAMRESEND
  • Server mengirim ulang blok stream game yang diminta

Pemrosesan blok stream game

  • MSG_SEQ_ADDPLAYER dikirim saat pemain masuk ke game, dan berisi indeks pemain serta deskriptor CPlayerCharacter
  • MSG_SEQ_REMPLAYER dikirim saat koneksi pemain terputus, dan hanya berisi indeks pemain
  • MSG_SEQ_CHARACTERCHANGE menyampaikan perubahan nama pemain, tim, dan penampilan
    • Di Serious Sam, buffer penampilan berisi struktur CPlayerSettings
    • Isinya mencakup nama file model pemain, kebijakan auto-select senjata, tipe crosshair, dan beberapa flag
  • MSG_SEQ_PAUSE menyampaikan jeda atau melanjutkan, dan menampilkan nama pemain yang meminta di konsol
  • MSG_SEQ_ALLACTIONS berisi waktu tick saat ini dan aksi semua pemain
    • Engine menerapkan CPlayerAction ke tiap CPlayerTarget
    • Setelah itu engine memproses timer, event, entitas bergerak, dan fisika
  • Pemeriksaan sinkronisasi dilakukan dengan MakeSynchronisationCheck()
    • CSyncCheck dibuat melalui ChecksumForSync() dari entitas, target pemain, dan lainnya
    • Klien mengirim MSG_SYNCCHECK ke server, dan jika tidak cocok dengan state server, koneksi diputus

Mengurangi input delay dengan prediksi

  • Prediksi adalah mekanisme untuk mengurangi masalah game cepat yang terasa lamban karena latensi internet
  • Prediksi pemain lokal menggunakan aksi yang dikirim ke server
  • Prediksi pemain jarak jauh menggunakan aksi terakhir yang diterima dari server
  • Jika klien memajukan state game nyata secara langsung tanpa menunggu respons server, ia tidak mengetahui aksi pemain lain, sehingga sinkronisasi dapat rusak
  • Serious Engine menggunakan predictor agar state nyata dan state prediksi tidak bercampur
    • Predictor mirip salinan “hantu” yang terhubung dengan entitas biasa
    • Temporary predictor dibuat saat prediksi dan tidak memiliki entitas terkait di state game nyata
  • Saat memproses tick prediksi, hanya entitas predictor yang diproses
  • Ketika klien menerima aksi pemain dari server, predictor lama dihancurkan dan siklus prediksi baru dimulai
  • Saat rendering, entitas asli yang sedang diprediksi tidak digambar; yang digambar adalah predictor, sehingga gerakan terlihat berlanjut tanpa banyak mengubah state nyata
  • Pemain lokal hanya dapat diprediksi sebanyak jumlah aksi yang dikirim ke server dan disimpan di plt_abPrediction
  • Pada prediksi pemain jarak jauh, jika cli_bLerpActions dimatikan, aksi terakhir yang diterima akan diulang
  • Jika cli_bLerpActions dinyalakan, engine melakukan interpolasi linear antara dua aksi terakhir, tetapi default-nya mati

Perbandingan dengan Doom dan Quake

  • Networking Doom sebenarnya peer-to-peer, tetapi para klien saling bertukar struktur yang mirip CPlayerAction dan menjalankan simulasi independen masing-masing
  • Doom juga menggunakan sistem serupa untuk perekaman dan pemutaran demo
  • Quake menggunakan struktur berbeda; klien tidak banyak memproses logika game sendiri, melainkan lebih dekat ke model menerima pembaruan state dari server
  • Dengan pendekatan Quake, masalah sinkronisasi tidak perlu terlalu dikhawatirkan, dan pencegahan cheat juga bisa lebih mudah, misalnya dengan tidak mengirim informasi entitas di balik dinding dari server
  • Dibandingkan Quake, Serious Sam biasanya memiliki sesi dengan jauh lebih banyak musuh dan objek aktif, sehingga mengirim state banyak objek setiap tick mungkin akan membebani bandwidth

Portabilitas dan keterbatasan struktural

  • Beberapa pesan jaringan menserialisasi struct dengan cara yang mendekati reinterpret cast
  • Ini bisa berhasil jika diasumsikan satu compiler dan satu platform, tetapi pada game lintas platform layout dan padding struct dapat berbeda
  • File executable 32-bit dapat mencoba alignment batas 4 byte, sedangkan executable 64-bit dapat mencoba alignment batas 8 byte
  • Masalah endianness juga ada
    • PC x86 adalah little-endian
    • PS3 adalah big-endian
  • Struktur Serious Engine elegan karena mengabstraksikan perbedaan media transmisi seperti jaringan dan file dari logika game, tetapi model tempat semua klien memiliki salinan state game memungkinkan terjadinya cheat
  • Misalnya, klien yang dimodifikasi dapat menampilkan siluet pemain lain di balik dinding dalam deathmatch

1 komentar

 
GN⁺ 2024-06-14
Opini Hacker News
  • Saya adalah salah satu developer yang mengerjakan implementasi kode jaringan Serious Sam
    Saya sering tidur di bawah meja kantor Croteam sambil menelusuri Usenet, dan terutama terinspirasi oleh tulisan yang menjelaskan sistem prediksi QuakeWorld
    Malam itu, saat rekan saya Dan menguji dengan memakai mesin Unix 486 lama sebagai router yang bisa menyimulasikan latensi, saya mengodekan implementasi minimal yang sederhana
    Itu terjadi jauh sebelum game sebenarnya dibangun di atasnya

    • Saya penasaran kenapa mereka membuat para pria berkepala meledak berlari sambil berteriak, dengan suara yang makin keras saat mendekat
      Saya masih bisa mendengar suara itu
    • Saya sangat suka suasana ketika di bawah tulisan tentang bagaimana sebuah game legendaris dibuat, ada orang yang dengan santai berkata, “Oh iya, itu saya yang bikin, seru juga”
    • Saya benar-benar menyukai game itu
      Saya sangat suka game kooperatif dan game tembak-menembak, tapi teman-teman saya selalu hanya ingin main Counter-Strike
      Berkat Serious Sam, sesekali saya bisa meyakinkan mereka untuk ikut memainkan game yang saya suka
    • Serious Sam adalah salah satu game favorit paman saya, dan ia juga menyukai Duke Nukem 3D
      Paman saya adalah sosok yang sangat penting dalam hidup saya, dan memainkan game-game yang ia sukai adalah cara yang baik untuk terhubung dengan kenangan tentangnya
      Game yang hebat, multiplayer yang hebat, dan menjadi kenangan yang sangat indah
    • Saya sangat berterima kasih atas permainan layar terbagi
  • Serious Sam selalu menjadi game LAN party yang kuat
    Bukan karena itu judul paling mencolok pada masanya, dan bukan karena ada orang yang merencanakannya sejak awal
    Serious Sam mendominasi LAN party karena ketika game lain tumbang akibat masalah driver, panas berlebih, update, dan sebagainya, menjalankan Serious Sam ya langsung berfungsi
    Hal ini berlanjut di sekuel-sekuelnya; bahkan ketika PC seseorang benar-benar bermasalah, game ini tetap mendukung layar terbagi dengan stabil dan menangani perangkat input dengan baik
    Bagian sistemik dari game ini benar-benar unggul dalam hal keandalan

    • Serious Sam berjalan cepat bahkan di hardware yang buruk, tetapi tetap terlihat cukup keren
      Demikian pula Counter-Strike memang grafisnya tidak bagus, tetapi berjalan lancar bahkan di PC setara toaster, sehingga tetap populer untuk waktu yang lama
    • Suara “aaaaaaaaaaaaah” dari banyak speaker itu menyenangkan
    • Pada akhir 90-an saya mengelola situs web dukungan teknis EA, dan tim support/QA bermain Serious Sam besar-besaran setelah jam kerja
      Itu satu-satunya first-person shooter yang secara konsisten berjalan baik di PC kantor, dan benar-benar menyenangkan
      Saat itu di EA, QA dan dukungan teknis cukup banyak tumpang tindih; staf support biasanya bekerja sebagai beta tester internal pada musim panas untuk mengejar rilis akhir tahun, lalu menangani dukungan teknis pada musim dingin ketika panggilan meningkat sekitar Natal
  • Saat mengimplementasikan multiplayer di port Game Boy Color Vigilante 8, kami menggunakan gameplay deterministik
    Kabel link GBC mengirim dan menerima 1 byte secara bersamaan dua arah, bekerja seperti sepasang shift register yang saling mengisi melalui kabel
    Game terkunci pada frame rate GBC, dan pada dasarnya banyak pekerjaan pembaruan layar harus dilakukan setiap V-Blank; jika terlewat, scrolling yang mulus akan tersendat
    Saat multiplayer dimulai, seed dipertukarkan, dan eksekusinya kira-kira begini: pada frame A input dibaca, dipadatkan menjadi 1 byte, lalu dimasukkan ke buffer kirim. Selama frame B dirender, transfer berlangsung. Pada awal frame C, kita sudah memiliki input lokal yang dikirim pada frame A dan input lawan yang diterima pada frame B
    Input tersebut diterapkan ke state game dan frame C dirender, sehingga input lokal maupun remote diterapkan dengan latensi 1 frame
    Di permainan lokal tidak ada input lag, jadi kalau kalah di multiplayer, silakan salahkan latensi; kalau perlu, salahkan saya secara khusus

    • Beberapa minggu lalu saya membeli kartrid ini, dan karena saya menyukai kartrid rumble GBC lama, saya terkesan karena ada multiplayer kabel link
      Ini game yang benar-benar bagus, dan penjelasan teknis tentang implementasi multiplayer-nya juga sangat keren
  • Croteam benar-benar tim pengembang game yang berbakat
    Saya sangat menikmati The Talos Principle 1 dan 2, dan pada game pertama mereka termasuk pelopor awal yang membuat engine game Vulkan yang sepenuhnya kustom

    • Saya sangat kecewa ketika The Talos Principle 2 meninggalkan engine sendiri dan memakai Unreal Engine
    • Saya baru tahu bahwa DLC Talos 2 akan hadir di Steam Jumat ini
  • Saya penasaran apakah ini ide yang sama seperti “1500 pemanah di 28.8K” dari Age of Empires
    https://www.gamedeveloper.com/programming/1500-archers-on-a-...

    • Benar. Keduanya adalah sistem deterministic lockstep
      Banyak game telah lama menggunakan sistem seperti ini, tetapi sekarang tampaknya kurang umum dibanding dulu karena berbagai alasan
    • Angka ini menunjukkan betapa anehnya adanya batas unit di Tempest Rising
      Semestinya cukup antara punya resource atau tidak; tidak perlu ada batas hanya demi batas itu sendiri
  • Game dengan bandwidth 10 kali lebih besar pun kesulitan mendukung musuh sebanyak itu
    Saya baru menyadari bahwa peningkatan sumber daya teknis tampaknya justru berdampak buruk pada efisiensi dan kreativitas ilmu komputer
    Semakin besar bandwidth, penyimpanan, memori, dan daya komputasi, software tampaknya merespons dengan menjadi lebih lambat, lebih gemuk, dan lebih tidak cakap per unit resource
    Ini layak disebut efek desain software ala Benjamin Button

    • Saya penasaran angka “musuh sebanyak itu” maksudnya berapa
      Kalau ada angkanya di artikel, saya tidak menemukannya
      Banyak game modern juga multiplayer dan punya jumlah musuh yang bisa dibilang cukup “masif”, dan jika yang penting adalah jumlah pemain, ada juga game yang mendukung jumlah pemain besar
    • Biasanya ini lebih dikenal sebagai software bloat
    • Benar, ini dikenal sebagai Hukum Wirth
  • Menurut saya ini game yang menghabiskan lebih banyak waktu bergerak mundur daripada maju

    • Bahkan ada game yang menjadikan itu tema, judulnya “I Hate Running Backwards”
      Ada di Steam, dan meski saya tidak tahu apakah pembuatnya sama, game itu berada di semesta Serious Sam
    • Anda dan Netrisca bersama-sama, tetapi ribuan musuh itu sendirian
    • Ada juga senjata yang terasa seperti menembak sepersekian detik sebelum tombol mouse ditekan
    • Saya juga masih ingat mati-matian memungut amunisi yang muncul sambil mundur seperti itu
  • Struktur Factorio juga mirip: hampir hanya mengirim event input dan mengandalkan inti simulasi lockstep
    Ada pengecualian berupa bagian-bagian yang mencolok seperti alat perencanaan rel

    • Suatu hari saya ingin bekerja dengan arsitektur lockstep seperti itu
      Itu terlihat seperti batasan desain yang memuaskan dan mudah diuji
  • Saya masih ingat memainkan Serious Sam dari demo PC Gamer saat kecil
    Saat itu pun game ini sudah dianggap sebagai game bergaya retro, seolah kembali ke era DOOM dan Quake lama
    Sekarang secara harfiah sudah 20 tahun berlalu, dan game itu sendiri telah menjadi klasik

  • Starsiege: Tribes terasa berskala besar dan luar biasa menyenangkan bahkan dengan koneksi 56K

    • Para developer Tribes menulis white paper tentang konsep kode jaringan yang mirip
      https://www.gamedevs.org/uploads/tribes-networking-model.pdf
    • Kemungkinan besar itu game favorit saya waktu kecil, terutama Tribes 2
      Sebenarnya belum lama ini saya mengunduh Tribes 2 dan beberapa bulan lalu masih bermain melawan bot
      Meski game lama, masih tetap menyenangkan, dan saya sering berpikir ingin membuat ulang dengan sesuatu seperti Unity
      Mungkin suatu hari nanti
    • Tribes itu hebat
      Pada 1999, ada medan yang dibuat secara prosedural untuk meluncur turun seperti ski, melihat orang lain meluncur naik di atasnya, plus peta besar dan banyak pemain