1 पॉइंट द्वारा GN⁺ 2024-06-14 | 1 टिप्पणियां | WhatsApp पर शेयर करें
  • Serious Engine 1 ने single-player, multiplayer, और demo playback को एक ही deterministic simulation पर बनाया, जिसमें हर tick पर पूरा state रिकॉर्ड/ट्रांसमिट करने के बजाय player actions और game stream blocks रिकॉर्ड/भेजे जाते थे
  • Demo और multiplayer शुरुआती game state साझा करने के बाद CPlayerAction जैसे input deltas लागू करते हैं, इसलिए random seed और game logic की determinism synchronization की कुंजी बन जाती है
  • Network layer UDP के ऊपर sequence numbers, ACK, retransmission, bandwidth limits, और per-connection buffers को खुद संभालती है, ताकि धीमी lines पर भी play जारी रखा जा सके
  • CNetworkMessage serialization, LZ77/LZRW1 compression, और XOR-आधारित delta encoding देता है, लेकिन chat सहित messages encrypted नहीं होते और केवल compressed हो सकते हैं
  • Serious Sam के client-server model में bandwidth बचाने के लिए हर client अपनी simulation बनाए रखता है, लेकिन इसके बदले synchronization verification, prediction, retransmission, CRC checks जैसे सहायक तंत्र चाहिए होते हैं

Serious Engine की common simulation संरचना

  • Serious Engine 1 source code को 2016 में GNU GPL v2 के तहत public किया गया था, और यह analysis इस public codebase को पढ़ने और debug करने पर आधारित है
  • Serious Sam को शुरुआत से ही multiplayer game के रूप में design किया गया था, और single-player campaign भी internally multiplayer structure के special case की तरह काम करता है
  • Engine जिन modes को support करता है, वे हैं
    • Offline single-player campaign
    • Online, LAN, local co-op play और कई game modes
    • एक client पर कई players के साथ split screen
    • Demo recording और playback

Demo recording: पूरे state के बजाय actions रिकॉर्ड करना

  • अगर demo को हर tick पर पूरे game state के रूप में save किया जाए तो file बड़ी हो जाएगी, इसलिए Serious Engine recording शुरू होने के समय पूरा game state एक बार save करता है और उसके बाद हर tick पर game stream blocks रिकॉर्ड करता है
  • Game stream block में ये message types होते हैं
    • MSG_SEQ_ALLACTIONS: player actions
    • MSG_SEQ_ADDPLAYER: player जोड़ना
    • MSG_SEQ_REMPLAYER: player हटाना
    • MSG_SEQ_PAUSE: pause या unpause
    • MSG_SEQ_CHARACTERCHANGE: player character attributes बदलना
  • मुख्य चीज़ MSG_SEQ_ALLACTIONS है; engine हर active player के लिए CPlayerAction object को deserialize करके CPlayerTarget पर लागू करता है
  • CPlayerAction player state रखता है
    • world space के आधार पर movement speed pa_vTranslation
    • world space के आधार पर character rotation pa_aRotation
    • world space के आधार पर view rotation pa_aViewRotation
    • अभी दबाए गए buttons pa_ulButtons
    • TSC-आधारित millisecond timestamp pa_llCreated
  • Playback के समय शुरुआती game state पढ़ा जाता है और हर tick के player actions को वास्तविक play की तरह apply किया जाता है

Determinism क्यों जरूरी है

  • यह structure इस assumption पर आधारित है कि game के अंदर हर चीज़ पूरी तरह predictable है, और केवल player actions ही game को बदलते हैं
  • Randomness को भी game state के हिस्से seed का इस्तेमाल करने वाले pseudorandom generator से handle किया जाता है
    • CEntity::IRnd() CSessionState::Rnd() का इस्तेमाल करता है
    • ses_ulRandomSeed game state deserialization के दौरान initialize होता है
  • अगर true random generator या अलग seeds इस्तेमाल हों, तो वही demo play करने पर भी result बदल सकता है, और इससे synchronization mismatch हो सकता है

Floating point और tick processing

  • PC version Serious Sam मूल रूप से Windows-only release था, इसलिए समान compiler और runtime इस्तेमाल होने की धारणा ने floating-point synchronization issues कम किए
  • Renderer एक DLL है और OpenGL या DirectX API calls FPU precision बदल सकती हैं, इसलिए Serious Engine CSetFPUPrecision FPUPrecision(FPT_24BIT) जैसे precision guards इस्तेमाल करता है
  • Rounding control को explicitly set किया गया हो, ऐसा स्थान नहीं मिला, लेकिन _controlfp से _RC_NEAR state check करने वाला assert मौजूद है
  • Game logic rendering framerate से अलग है
    • Rendering hardware और settings के अनुसार बदलती है और internally 500 FPS तक limited लगती है
    • Game logic 20 ticks per second पर fixed है
  • Smooth movement current tick और previous tick के बीच linear interpolation से बनाया जाता है, और console में /net_bLerping=0 से interpolation बंद किया जा सकता है

UDP के ऊपर बनाया गया custom packet layer

  • Serious Engine multiplayer में StartPeerToPeer_t जैसे function names बचे हैं, लेकिन actual model client-server structure है
  • Server client messages receive और process करता है, फिर relevant जानकारी सभी clients तक भेजता है
  • हर player demo system की तरह अपनी simulation चलाता है और दूसरे players की action information लेकर state को आगे बढ़ाता है
  • Network UDP इस्तेमाल करता है और out-of-order delivery तथा loss को हल करने के लिए अपना protocol ऊपर चढ़ाता है
  • CPacket packet order और reliability manage करता है
    • pa_ulSequence: sequence number से ordering और duplicate removal करता है
    • pa_ubReliable: reliability flag रखता है
    • pa_ubRetryNumber: retransmission count track करता है
    • pa_tvSendWhen: scheduled send time और congestion control में इस्तेमाल होता है
  • Reliable packets ACK का इंतजार करते हैं, और ACK न मिलने पर retransmit होते हैं
    • Maximum retry count net_iMaxSendRetries से set होता है और default 10 लगता है
    • Retransmission interval net_fSendRetryWait से set होता है और default 0.5f लगता है
  • Reliable packets कई packets में बंटे stream बना सकते हैं
    • पहला packet UDP_PACKET_RELIABLE_HEAD
    • आखिरी packet UDP_PACKET_RELIABLE_TAIL
    • Single reliable packet में दोनों flags होते हैं
  • Unreliable packets loss पर stream तोड़ सकते हैं, इसलिए वे stream नहीं बनाते

Connection lifecycle और packet routing

  • CCommunicationInterface packet-layer communication संभालता है और server, client, तथा broadcast के लिए interface functions रखता है
  • Server और client interfaces मानते हैं कि connection target पहले से पता है, और broadcast interface arbitrary addresses के साथ send/receive के लिए इस्तेमाल होता है
  • CCommunicationInterface दो master buffers maintain करता है
    • cci_pbMasterInput: आए हुए UDP packets को CPacket में deserialize करके store करता है
    • cci_pbMasterOutput: भेजे जाने वाले CPacket को serialize करके socket API से transmit करता है
  • Actual per-client communication abstraction CClientInterface संभालता है
    • Server cm_aciClients array से हर player interface रखता है
    • Client cm_ciLocalClient से server के साथ communicate करता है
    • Client और server दोनों connection setup के लिए cm_ciBroadcast का उपयोग करते हैं
  • CAddress का adr_uwID client unique identifier या broadcast packet indicator के रूप में इस्तेमाल होता है
    • value '//' या 0 हो तो broadcast packet है
    • बाकी values session के अंदर client ID हैं

Connection setup और basic security mechanisms

  • Client server से जुड़ने के लिए UDP_PACKET_CONNECT_REQUEST flag वाला reliable broadcast packet भेजता है
  • अगर उसी address और port वाला client पहले से connected है तो server request ignore करता है
  • नया client हो तो server खाली client interface ढूंढकर ये काम करता है
    • उस client का unique identifier generate करता है
    • UDP_PACKET_CONNECT_RESPONSE reliable broadcast packet से identifier client को भेजता है
  • Identifier केवल fixed index का इस्तेमाल नहीं करता, बल्कि timer value के कुछ हिस्से और client index को मिलाकर बनाया जाता है
  • किसी दूसरे player की impersonation करने के लिए uwID guess करना होगा, इसलिए attack surface घटती है
  • अगर unconnected player non-broadcast packet भेजे, तो Serious Engine console में warning print कर सकता है

Single-player और demo local connection के special cases हैं

  • Single-player और demo playback में भी internally server और client मौजूद होते हैं, लेकिन same process के अंदर चलते हैं
  • Same process के बीच sockets इस्तेमाल करने की जरूरत नहीं होती, इसलिए Client_OpenLocal() local client interface और server-side interface को आपस में connect करता है
  • Connected दो CClientInterface ExchangeBuffers से एक side के output buffer के packets को दूसरी side के input buffer में move करते हैं
  • Local play को master input/output buffers और actual network socket से गुजरने की जरूरत नहीं होती

Network message layer

  • CNetworkMessage packets के ऊपर message abstraction है और stream की तरह read/write किया जा सकता है
  • Messages Read, Write, ReadBits, WriteBits और <<, >> operators से serialize/deserialize होते हैं
  • Sub-messages भी रखे जा सकते हैं, और जरूरी data लिखने के बाद Shrink से buffer size को data size के अनुरूप किया जा सकता है
  • CNetworkMessage buffer AllocMemory के जरिए allocate होता है और internally malloc call करता लगता है
  • CLinearAllocator मौजूद है, लेकिन इसका उपयोग होने वाली जगह नहीं मिली; message buffers अक्सर allocate/reallocate होते हैं

Compression और delta encoding

  • Messages specified compressor या message type के default compressor से compress हो सकते हैं
  • MESSAGETYPE में lower 6 bits type हैं और बाकी 2 bits compression method दर्शाते हैं
    • LZ77 CzlibCompressor
    • LZRW1 CLZCompressor
    • Uncompressed
  • Default compression LZRW1 लगती है, और net_iCompression shell variable से बदली जा सकती है
  • CPlayerAction को जैसा है वैसा नहीं भेजा जाता; current action और last action को XOR करके बना delta भेजा जाता है
  • Receiver last action पर delta को फिर XOR करके original CPlayerAction restore करता है
  • Delta data में changes छोटे हों तो बेहतर compress होता है
    • Pressed keys अक्सर कई frames तक बनी रहती हैं
    • Speed और view rotation भी floating-point की पूरी range में बहुत ज्यादा इधर-उधर नहीं जाते
  • जब server MSG_SEQ_ALLACTIONS से कई players के actions एक साथ भेजता है, तो इस method का असर और बढ़ सकता है

Message encryption और chat

  • Serious Engine के messages encrypted नहीं होते
  • net_iCompression=0 से compression बंद करने पर in-game chat messages UDP packet payload में plaintext में दिखते हैं
  • वास्तविक situation में compression on हो तो packet sniffer को LZ compression stream समझकर decompress करना होगा, लेकिन जरूरी data packet के अंदर होता है
  • उस दौर के games अक्सर encryption handle नहीं करते थे, और authentication तथा key exchange जैसे mechanisms implement करने से complexity बढ़ सकती थी
  • उस समय web भी ज्यादातर HTTP था

Game session layer

  • CNetworkLibrary नाम के उलट game state CSessionState सहित game session manage करता है
  • CNetworkLibrary पहले आए CMessageDispatcher से inherit करता है
  • Server start होने पर engine यह procedure करता है
    • CRC collection initialize करके connected clients के पास server जैसी files हैं या नहीं, इसकी जांच की तैयारी करता है
    • नया CSessionState बनाता है और serialize करके default state ga_pubDefaultState में save करता है
    • Local world instance load करता है
    • Global communication interface initialize करता है
    • Local session state initialize करता है, और client connect होने पर default state तथा server current state का state delta भेज सकने लायक बनाता है
    • CRC collection खत्म करके ga_ulCRC में store करता है
  • CRC check cheat prevention से ज्यादा synchronization mismatch की early detection जैसा है
  • Client join procedure यह flow follow करता है
    • Empty local session state और communication interface initialize करता है
    • MSG_REQ_CONNECTREMOTESESSIONSTATE से build version, mode name, server password, local player count, CSessionSocketParams भेजता है
    • MSG_REP_CONNECTREMOTESESSIONSTATE से message, world filename, difficulty/game mode flags, session attributes receive करता है
    • Reference game state initialize करता है
    • MSG_REQ_STATEDELTA भेजकर server current state से difference request करता है
    • MSG_REP_STATEDELTA मिलने के बाद reverse diff से game state stream reconstruct करता है
    • CSessionState::Read_t() से local session state initialize करता है
    • CRC check करता है और mismatch हो तो disconnect करता है

Main loop और game stream retransmission

  • Client और server के main loops broadly similar हैं, लेकिन server extra काम करता है
  • Loop local client interface और broadcast interface update करता है, और local session state incoming network messages process करता है
  • Server paired client interfaces के बीच buffer exchange, server-side client interface update, GameAgent update, और remote admin shell commands processing भी संभालता है
  • SessionStateLoop() unreliable और reliable messages को अलग-अलग process करता है
    • Unreliable: MSG_GAMESTREAMBLOCKS, MSG_KEEPALIVE, MSG_INF_PINGS, MSG_CHAT_OUT
    • Reliable: MSG_INF_DISCONNECTED, MSG_ADMIN_RESPONSE
  • MSG_GAMESTREAMBLOCKS unreliable message है, लेकिन missing होने पर synchronization टूट सकता है
  • Serious Engine game stream processing stage में missing sequences check करता है और retransmission request करता है
    • अगला expected sequence block हो तो process करता है
    • अगला block नहीं है और उससे newer block भी नहीं है तो उस loop में कुछ नहीं करता
    • अगला block नहीं है लेकिन newer block है तो missing होने की संभावना है, इसलिए timeout set करता है
    • Timeout के बाद MSG_REQUESTGAMESTREAMRESEND से missing block sequence और count request करता है
  • Server requested game stream blocks फिर से भेजता है

Game stream block processing

  • MSG_SEQ_ADDPLAYER player के game में आने पर भेजा जाता है और player index तथा CPlayerCharacter descriptor शामिल करता है
  • MSG_SEQ_REMPLAYER player disconnect होने पर भेजा जाता है और केवल player index रखता है
  • MSG_SEQ_CHARACTERCHANGE player name, team, appearance changes deliver करता है
    • Serious Sam में appearance buffer CPlayerSettings structure रखता है
    • इसमें player model filename, weapon auto-selection policy, crosshair type, और कई flags शामिल हैं
  • MSG_SEQ_PAUSE pause या unpause deliver करता है और requesting player का name console में print करता है
  • MSG_SEQ_ALLACTIONS current tick time और सभी player actions रखता है
    • हर CPlayerTarget पर CPlayerAction apply करता है
    • इसके बाद timers, events, moving entities, और physics processing करता है
  • Synchronization check MakeSynchronisationCheck() से होता है
    • Entities और player targets आदि के ChecksumForSync() से CSyncCheck बनाता है
    • Client MSG_SYNCCHECK server को भेजता है, और server state से mismatch हो तो connection disconnect हो जाता है

Prediction से input delay कम करना

  • Prediction internet latency के कारण fast games के सुस्त महसूस होने की समस्या घटाने का mechanism है
  • Local player prediction server को भेजे गए actions इस्तेमाल करता है
  • Remote player prediction server से last received action इस्तेमाल करता है
  • अगर client server response का इंतजार किए बिना actual game state को खुद आगे बढ़ाए, तो दूसरे player actions का पता नहीं होगा और synchronization टूट सकता है
  • Serious Engine actual state और predicted state को mix न करने के लिए predictor इस्तेमाल करता है
    • Predictor सामान्य entity से जुड़े “ghost” copy जैसा होता है
    • Temporary predictor prediction के दौरान बनता है और actual game state की linked entity नहीं रखता
  • Prediction tick process करते समय केवल predictor entities process होती हैं
  • Client को server से player actions मिलते ही existing predictor destroy कर दिया जाता है और नया prediction cycle शुरू होता है
  • Rendering के समय prediction में मौजूद original entity draw नहीं होती, predictor draw होता है, जिससे actual state को ज्यादा बदले बिना movement progress करता हुआ दिखता है
  • Local player केवल plt_abPrediction में stored server-sent action count जितना ही predict कर सकता है
  • Remote player prediction में cli_bLerpActions off हो तो last received action repeat होता है
  • cli_bLerpActions on हो तो last two actions के बीच linear interpolation होता है, लेकिन default off है

Doom और Quake से तुलना

  • Doom networking असल में peer-to-peer था, लेकिन clients CPlayerAction जैसी structure exchange करते और अपनी-अपनी independent simulation चलाते थे
  • Doom भी demo recording और playback के लिए similar system इस्तेमाल करता है
  • Quake ने अलग structure इस्तेमाल किया; client बड़े game logic को directly process नहीं करता था और server से state updates पाने के तरीके के करीब था
  • Quake approach में synchronization issues की चिंता कम करनी पड़ती है, और server द्वारा दीवार के पीछे entities की information न भेजने जैसे तरीके से cheat prevention भी आसान हो सकता है
  • Serious Sam में Quake की तुलना में active enemies और objects बहुत ज्यादा वाले sessions सामान्य थे, इसलिए हर tick पर कई object states भेजना bandwidth पर भारी पड़ सकता था

Portability और structural limits

  • कुछ network messages structures को reinterpret cast के करीब तरीके से serialize करते हैं
  • Single compiler और single platform की assumption पर यह चल सकता है, लेकिन cross-platform game में struct layout और padding अलग हो सकते हैं
  • 32-bit executable 4-byte boundary, और 64-bit executable 8-byte boundary alignment करने की कोशिश कर सकता है
  • Endian issues भी मौजूद हैं
    • x86 PC little-endian है
    • PS3 big-endian है
  • Serious Engine की structure इस मायने में elegant है कि उसने network और file जैसे transport media के differences को game logic से abstract किया, लेकिन सभी clients के पास game state copy होने वाला model cheating को संभव बनाता है
  • उदाहरण के लिए, modified client deathmatch में दीवार के पीछे दूसरे players की outlines दिखा सकता है

1 टिप्पणियां

 
GN⁺ 2024-06-14
Hacker News की टिप्पणियाँ
  • मैं उन developers में से एक था जिसने Serious Sam के network code implementation पर काम किया था
    Croteam के office में desk के नीचे अक्सर सोता था और Usenet खंगालता रहता था, खासकर QuakeWorld के prediction system को समझाने वाली post से inspiration मिला था
    उसी रात, जब मेरे colleague Dan delay simulate कर सकने वाली एक पुरानी 486 Unix machine को router की तरह इस्तेमाल करके test कर रहे थे, मैंने एक simple minimum-function implementation code किया था
    यह actual game के उस पर बनने से काफी पहले की बात थी

    • यह सोचकर हैरानी होती है कि फटते सिर वाले आदमियों को चिल्लाते हुए दौड़कर आने और पास आने पर आवाज़ तेज़ होने वाला क्यों बनाया गया
      वह आवाज़ आज भी सुनाई देती है
    • legendary game कैसे बनी, इस पर article के नीचे किसी का casually “अरे हाँ, वह तो मैंने बनाया था, मज़ा आया था” जैसा कहना बहुत अच्छा लगता है
    • मुझे वह game सच में बहुत पसंद था
      co-op games और shooting games मुझे बहुत पसंद थे, लेकिन मेरे दोस्त हमेशा Counter-Strike ही खेलना चाहते थे
      Serious Sam की वजह से कभी-कभी मैं उन्हें अपनी पसंद का game साथ खेलने के लिए मना पाता था
    • Serious Sam मेरे uncle के सबसे पसंदीदा games में से एक था, और उन्हें Duke Nukem 3D भी पसंद था
      मेरे uncle मेरी ज़िंदगी में बहुत अहम व्यक्ति थे, और उनके पसंदीदा games खेलना उनकी यादों से जुड़े रहने का अच्छा तरीका है
      शानदार game, शानदार multiplayer, और बहुत अच्छी यादों के रूप में बचा हुआ है
    • split-screen play के लिए सच में शुक्रगुज़ार था
  • Serious Sam हमेशा से एक मजबूत LAN party game था
    ऐसा इसलिए नहीं कि वह उस समय का सबसे flashy title था, और न ही इसलिए कि किसी ने पहले से plan किया था
    जब दूसरे games driver issues, overheating issues, update issues वगैरह से दम तोड़ रहे होते थे, तब Serious Sam चलाते ही बस काम कर जाता था, इसलिए वह LAN parties पर छा गया
    sequels में भी यह बात जारी रही; किसी का PC पूरी तरह खराब हो जाए तब भी यह भरोसेमंद split-screen support देता था और input devices भी अच्छी तरह handle करता था
    game का system वाला हिस्सा reliability के लिहाज़ से सचमुच बेहतरीन था

    • Serious Sam खराब hardware पर भी तेज़ चलता था और फिर भी काफी अच्छा दिखता था
      इसी तरह Counter-Strike के graphics बहुत अच्छे नहीं थे, लेकिन toaster जैसे PC पर भी अच्छी तरह चलता था, इसलिए लंबे समय तक popular रहा
    • कई speakers से आती “aaaaaaaaaaaaah” आवाज़ मज़ेदार थी
    • 90s के आखिर में मैं EA की technical support website manage करता था, और support/QA team office hours के बाद बड़े पैमाने पर Serious Sam खेलती थी
      work PCs पर लगातार अच्छी तरह चलने वाला वही एक first-person shooter game था, और वह सच में बहुत मज़ेदार था
      उस समय EA में QA और technical support में काफी overlap था; support लोग summer में year-end releases के लिए internal beta testers के तौर पर काम करते थे, और Christmas के आसपास calls बढ़ने वाले winter में technical support करते थे
  • Vigilante 8 के Game Boy Color port में multiplayer implement करते समय deterministic gameplay इस्तेमाल किया था
    GBC link cable दोनों दिशाओं में एक साथ 1 byte भेजता और प्राप्त करता था, और cable के आर-पार एक-दूसरे को भरने वाले shift registers की जोड़ी की तरह काम करता था
    game GBC के frame rate पर fixed था, और practically हर V-Blank पर screen refresh का काफी काम करना पड़ता था; इसे miss करने पर smooth scrolling टूट जाती थी
    multiplayer शुरू होते समय seeds exchange किए जाते थे, और execution कुछ इस तरह था: frame A में input पढ़कर 1 byte में compress किया और send buffer में डाला. frame B render करते समय transfer होता था. frame C की शुरुआत में हमारे पास frame A में भेजा गया local input और frame B में मिला opponent input होता था
    उन inputs को game state पर apply करके frame C render किया जाता था, इसलिए local और remote inputs दोनों 1-frame delay से apply होते थे
    local play में input delay नहीं था, इसलिए अगर multiplayer में हार गए तो delay को दोष दे सकते हैं, और चाहें तो खास तौर पर मुझे भी दोष दे सकते हैं

    • कुछ हफ्ते पहले मैंने यह cartridge खरीदा था; पुराने GBC rumble cartridges पसंद हैं, इसलिए link cable multiplayer होने की बात देखकर impressed हुआ
      सच में अच्छा game है, और multiplayer implementation की technical explanation भी बहुत शानदार है
  • Croteam सच में talented game development team है
    The Talos Principle 1 और 2 दोनों का खूब आनंद लिया, और पहले game में वे early custom Vulkan game engine बनाने वाले pioneers में से थे

    • The Talos Principle 2 में अपना engine छोड़कर Unreal Engine इस्तेमाल करना बहुत अफसोसजनक लगा
    • अभी-अभी पता चला कि Talos 2 DLC इस Friday Steam पर आ रहा है
  • सोच रहा हूँ कि क्या यह Age of Empires वाले “28.8K पर 1500 archers” जैसा idea है
    https://www.gamedeveloper.com/programming/1500-archers-on-a-...

    • हाँ. दोनों deterministic lockstep systems हैं
      बहुत सारे games लंबे समय से ऐसे systems इस्तेमाल करते आए हैं, लेकिन लगता है आजकल कई वजहों से यह पहले से कम common है
    • यह number देखकर पता चलता है कि Tempest Rising में unit limit होना कितना अजीब है
      या तो resources हों या न हों; limit के लिए अलग से limit लगाने की जरूरत नहीं है
  • 10 गुना bandwidth वाले games भी उतने ज्यादा enemies support करने में संघर्ष करते हैं
    अब जाकर समझ आया कि technical resources की बढ़ोतरी computer science की efficiency और creativity पर उल्टा असर डालती लगती है
    bandwidth, storage, memory और compute power बढ़ते ही software resource per unit के हिसाब से और slow, और bloated, और incapable हो जाता है
    इसे Benjamin Button-style software design effect कहा जा सकता है

    • “उतने ज्यादा enemies” से कितने enemies मतलब है, यह number जानना चाहूँगा
      article में number है तो मुझे नहीं मिला
      modern games में भी ऐसे कई multiplayer games हैं जिनमें enemy count काफी “massive” माना जा सकता है, और अगर अहम चीज़ player count है तो ऐसे games भी हैं जो massive player counts support करते हैं
    • आम तौर पर इसे software bloat के नाम से ज्यादा जाना जाता है
    • हाँ, यह Wirth's law के नाम से जाना जाता है
  • मुझे लगता है यह ऐसा game था जिसमें आगे बढ़ने से ज्यादा समय पीछे चलते हुए बीता

    • यहाँ तक कि इसी विषय पर एक game भी है, जिसका title “I Hate Running Backwards” है
      Steam पर है, और पता नहीं same developer का है या नहीं, लेकिन Serious Sam universe का हिस्सा है
    • आप और Netrisca साथ थे, लेकिन वे हजारों enemies अकेले थे
    • कुछ guns तो mouse button दबाने से कुछ fraction of a second पहले fire होती महसूस होती थीं
    • पीछे हटते हुए spawn हुए ammo को desperately उठाने की याद भी अब तक है
  • Factorio की architecture भी मिलती-जुलती है; यह लगभग सिर्फ input events भेजता है और lockstep simulation core पर निर्भर करता है
    exceptions में rail planning tool जैसे noticeable हिस्से हैं

    • कभी ऐसे lockstep architecture पर काम करना चाहूँगा
      यह satisfying और test करने में आसान design constraint जैसा लगता है
  • बचपन में PC Gamer demo से Serious Sam खेलने की याद है
    तब भी इसे पुराने DOOM और Quake दौर में लौटने जैसा retro-style game माना जाता था
    अब literally 20 साल बीत चुके हैं, और यह खुद एक classic बन गया है

  • Starsiege: Tribes 56K connection पर भी बड़े scale का और absurdly fun था

    • Tribes developers ने similar network code concept पर एक whitepaper लिखा था
      https://www.gamedevs.org/uploads/tribes-networking-model.pdf
    • शायद बचपन का मेरा सबसे पसंदीदा game था, खासकर Tribes 2
      असल में कुछ समय पहले मैंने Tribes 2 download किया और कुछ महीने पहले भी bots के खिलाफ खेला था
      पुराना game है, लेकिन अब भी मज़ेदार था, और अक्सर सोचता हूँ कि Unity जैसी किसी चीज़ में इसे फिर से बनाना चाहूँगा
      शायद किसी दिन करूँ
    • Tribes बेहतरीन था
      1999 में procedurally generated terrain पर skiing की तरह नीचे उतरना, और दूसरे लोगों को उस पर skiing करते हुए ऊपर जाते देखना, साथ में बड़े maps और बहुत सारे players भी थे