- 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
CNetworkMessagemenyediakan 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 pemainMSG_SEQ_ADDPLAYER: penambahan pemainMSG_SEQ_REMPLAYER: penghapusan pemainMSG_SEQ_PAUSE: jeda atau melanjutkanMSG_SEQ_CHARACTERCHANGE: perubahan atribut karakter pemain
- Intinya adalah
MSG_SEQ_ALLACTIONS; engine mendeserialisasi objekCPlayerActionuntuk setiap pemain aktif dan menerapkannya keCPlayerTarget CPlayerActionmenyimpan 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
- Kecepatan gerak berbasis ruang dunia
- 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()menggunakanCSessionState::Rnd()ses_ulRandomSeeddiinisialisasi 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_NEARmelalui_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
CPacketmengelola urutan dan reliabilitas paketpa_ulSequence: melakukan pengurutan dan penghapusan duplikat sebagai nomor urutpa_ubReliable: menyimpan flag reliabilitaspa_ubRetryNumber: melacak jumlah retransmisipa_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 tampaknya10 - Interval retransmisi diatur oleh
net_fSendRetryWait, dengan nilai default tampaknya0.5f
- Jumlah percobaan ulang maksimum diatur oleh
- 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 pertama adalah
- Paket non-reliabel tidak membentuk stream karena stream dapat rusak jika terjadi kehilangan paket
Siklus hidup koneksi dan routing paket
CCommunicationInterfacemenangani 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
CCommunicationInterfacemempertahankan dua master buffercci_pbMasterInput: menyimpan paket UDP masuk setelah dideserialisasi menjadiCPacketcci_pbMasterOutput: menserialisasiCPacketyang 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_ciBroadcastuntuk pembentukan koneksi
- Server memiliki antarmuka tiap pemain dalam array
adr_uwIDpadaCAddressdigunakan sebagai pengenal unik klien atau penanda paket broadcast- Jika nilainya
'//'atau0, itu adalah paket broadcast - Nilai lain adalah ID klien dalam sesi
- Jika nilainya
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
CClientInterfaceyang terhubung memindahkan paket dari buffer output satu sisi ke buffer input sisi lain melaluiExchangeBuffers - Permainan lokal tidak perlu melewati master buffer input/output dan socket jaringan nyata
Lapisan pesan jaringan
CNetworkMessageadalah 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
CNetworkMessagedialokasikan melaluiAllocMemory, yang secara internal tampaknya memanggilmalloc CLinearAllocatormemang 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
- LZ77
- Kompresi default tampaknya LZRW1, dan dapat diubah dengan variabel shell
net_iCompression CPlayerActiontidak dikirim apa adanya; engine membuat dan mengirim delta dari hasil XOR antara aksi saat ini dan aksi terakhir- Penerima memulihkan
CPlayerActionasli 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,
CNetworkLibrarymengelola sesi game termasuk state gameCSessionState CNetworkLibrarymewarisiCMessageDispatcheryang 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
CSessionStatebaru dan menserialisasikannya sebagai state dasarga_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
CSessionSocketParamsmelaluiMSG_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_STATEDELTAuntuk 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
- Non-reliabel:
MSG_GAMESTREAMBLOCKSadalah 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_ADDPLAYERdikirim saat pemain masuk ke game, dan berisi indeks pemain serta deskriptorCPlayerCharacterMSG_SEQ_REMPLAYERdikirim saat koneksi pemain terputus, dan hanya berisi indeks pemainMSG_SEQ_CHARACTERCHANGEmenyampaikan 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
- Di Serious Sam, buffer penampilan berisi struktur
MSG_SEQ_PAUSEmenyampaikan jeda atau melanjutkan, dan menampilkan nama pemain yang meminta di konsolMSG_SEQ_ALLACTIONSberisi waktu tick saat ini dan aksi semua pemain- Engine menerapkan
CPlayerActionke tiapCPlayerTarget - Setelah itu engine memproses timer, event, entitas bergerak, dan fisika
- Engine menerapkan
- Pemeriksaan sinkronisasi dilakukan dengan
MakeSynchronisationCheck()CSyncCheckdibuat melaluiChecksumForSync()dari entitas, target pemain, dan lainnya- Klien mengirim
MSG_SYNCCHECKke 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_bLerpActionsdimatikan, aksi terakhir yang diterima akan diulang - Jika
cli_bLerpActionsdinyalakan, 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
CPlayerActiondan 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
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 masih bisa mendengar suara 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
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
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
Demikian pula Counter-Strike memang grafisnya tidak bagus, tetapi berjalan lancar bahkan di PC setara toaster, sehingga tetap populer untuk waktu yang lama
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
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 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-...
Banyak game telah lama menggunakan sistem seperti ini, tetapi sekarang tampaknya kurang umum dibanding dulu karena berbagai alasan
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
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
Menurut saya ini game yang menghabiskan lebih banyak waktu bergerak mundur daripada maju
Ada di Steam, dan meski saya tidak tahu apakah pembuatnya sama, game itu berada di semesta Serious Sam
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
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
https://www.gamedevs.org/uploads/tribes-networking-model.pdf
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
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