- तेज़ FPS माहौल में देर से पहुँची state जानकारी की कीमत कम होती है, इसलिए Quake 3 ने latency घटाने के लिए UDP/IP-केंद्रित design चुना
- NetChannel, loss-prone UDP के ऊपर communication को abstract करता है, और server client-wise snapshot history से केवल ज़रूरी state differences दोबारा calculate करता है
- server, Master Gamestate, हाल के 32 gamestate और dummy gamestate को साथ इस्तेमाल करके full updates और delta updates को एक ही प्रक्रिया बना देता है
- client ACK न होने पर server आख़िरी confirmed snapshot और current state की तुलना करता है, और missed changes और नए changes को एक message में डालता है
- C में built-in introspection न होने पर भी
netField_t और macros से field differences खोजे जाते हैं, और NetChannel 1400-byte pre-fragmentation से router fragmentation से बचता है
UDP/IP को आधार मानने वाला network model
- Quake 3 का network model engine के सबसे elegant हिस्सों में माना जाता है, और low level पर यह Quake World में पहली बार आए NetChannel module से communication को abstract करता है
- तेज़ game में first transmission में छूटी जानकारी जल्द ही पुरानी हो जाती है, इसलिए दोबारा भेजने के बजाय latest state भेजना ज़्यादा फ़ायदेमंद होता है
- इसी वजह से engine में TCP/IP के निशान नहीं हैं, और reliable transmission से बनने वाली latency को स्वीकार करना मुश्किल माना गया
- network stack में दो mutually exclusive layers जोड़ी गई हैं
- pre-shared key का उपयोग करने वाली encryption
- precomputed Huffman key का उपयोग करने वाली compression
- server UDP datagram size घटाते हुए unreliability की भरपाई करता है
- snapshot history से delta packets बनाता है
- memory introspection तरीके से केवल बदले हुए fields ढूँढकर भेजता है
server और client की भूमिकाएँ
- client-side flow सरल है
- हर frame में server को commands भेजता है
- server से gamestate updates प्राप्त करता है
- server, हर client तक Master Gamestate propagate करते समय lost UDP packets को भी ध्यान में रखता है
- core mechanism तीन elements से बना है
- Master Gamestate: universally true game state; client commands NetChannel के ज़रिए आती हैं,
event_t में बदलती हैं और फिर server पर game state को modify करती हैं
- client-wise recent 32 gamestate: network पर भेजी गई state को circular array में store करता है; इन्हें snapshots कहा जाता है
- dummy gamestate: ऐसी state जिसके सभी fields 0 हैं; previous state न होने पर delta generation के base के रूप में इस्तेमाल होती है
- server इन तीन elements से NetChannel को देने के लिए update message बनाता है
- client-wise gamestate की बड़ी संख्या maintain करनी पड़ती है, इसलिए memory usage बढ़ जाता है
- measurement के अनुसार 4 players के लिए 8MB इस्तेमाल होता है
snapshots से full update और partial update बनाना
- उदाहरण में Client1 को update भेजने की स्थिति ली गई है, जहाँ Client2 की state
pos[X], pos[Y], pos[Z], health चार fields से बनी है
- communication UDP/IP से होता है, और Internet पर messages अक्सर lost हो सकते हैं
-
पहला server frame
- server सभी clients से मिले updates को Master Gamestate में apply करने के बाद Client1 तक state propagate करता है
- network module हर बार वही procedure follow करता है
- Master Gamestate को client record के अगले slot में copy करता है
- copied snapshot की तुलना दूसरे snapshot से करता है
- पहले update में Client1 record में valid snapshot नहीं होता, इसलिए dummy snapshot से compare करता है
- dummy snapshot के सभी fields 0 हैं, इसलिए result full update होता है
- हर field के आगे change status दिखाने वाला bit marker लगता है
- example full update 132 bits इस्तेमाल करता है
- format है
[1 A_on32bits 1 B_on32bits 1 B_on32bits 1 C_on32bits]
-
दूसरा server frame
- अगले frame में Client2 Y-axis पर move करता है और
pos[1] की value E हो जाती है
- Client1 ने पिछले update की receipt ACK कर दी है, इसलिए Snapshot1 ACK state में है
- server Master Gamestate को अगले record slot में copy करके Snapshot2 बनाता है, और valid Snapshot1 से compare करता है
- नतीजतन केवल बदला हुआ
pos[1] = E network पर transmit होता है
- हर field में bit marker होने के कारण यह partial update 36 bits इस्तेमाल करता है
- format है
[0 1 32bitsNewValue 0 0]
-
तीसरा server frame
- अगले frame में Client2 health खोता है और
health = H हो जाता है
- Client1 आख़िरी update को ACK नहीं करता
- server का UDP packet lost हुआ हो सकता है, या client का ACK lost हुआ हो सकता है
- किसी भी case में वह snapshot इस्तेमाल नहीं किया जा सकता
- server Master Gamestate को अगले slot में copy करके Snapshot3 बनाता है, और आख़िरी ACKed Snapshot1 से compare करता है
- भेजा जाने वाला message partial update होता है, और previous change
pos[1] = E तथा new change health = H दोनों को साथ शामिल करता है
- अगर Snapshot1 बहुत पुराना हो जाए और इस्तेमाल न हो सके, तो engine फिर से dummy snapshot को base मानकर full update भेजता है
loss की भरपाई एक ही procedure से कैसे होती है
- snapshot system की simplicity इस बात में है कि वही algorithm दो काम अपने-आप संभालता है
- full update या partial update बनाना
- receive न हुई previous information और new information को एक message में retransmit करना
- UDP packet loss को अलग complex flow से handle नहीं किया जाता; आख़िरी ACKed snapshot और current Master Gamestate के differences calculate करके भरपाई की जाती है
- previous state न हो या usable न हो, तो dummy snapshot को base मानकर full state भेजकर recovery की जाती है
C में field differences खोजने का तरीका
- Quake 3 में C language में introspection नहीं है, लेकिन हर field position को
netField_t array और preprocessor directives से पहले से configure किया जाता है
netField_t में field name, offset और bit count होता है
NETF(x) macro stringizing operator और entityState_t पर offset calculation का उपयोग करके field information को short form में लिखने देता है
- example structure इस प्रकार है
typedef struct { char *name; int offset; int bits; } netField_t;
// using the stringizing operator to save typing...
#define NETF(x) #x,(int)&((entityState_t*)0)->x
netField_t entityStateFields[] = {
{ NETF(pos.trTime), 32 },
{ NETF(pos.trBase[0]), 0 },
{ NETF(pos.trBase[1]), 0 },
...
}
- पूरा implementation MSG_WriteDeltaEntity के एक हिस्से में है
- Quake 3 comparison target के meaning को interpret नहीं करता; यह
entityStateFields के index, offset, size को follow करते हुए differences network पर transmit करता है
1400 bytes में पहले से बाँटने की वजह
- NetChannel module UDP datagram की maximum size 65507 bytes होने के बावजूद messages को 1400-byte chunks में बाँटता है
- संबंधित code Netchan_Transmit में है
- ज़्यादातर network MTU 1500 bytes होता है, इसलिए 1400-byte splitting Internet path पर routers द्वारा packet fragmentation रोकने के लिए चुना गया
- router fragmentation से बचने की दो वजहें हैं
- network में enter करते समय router को packet fragment करते हुए packet को hold करना पड़ता है
- network से निकलते समय datagram के सभी fragments का इंतज़ार करके costly reassembly करनी पड़ती है
वे messages जिन्हें ज़रूर deliver होना चाहिए
- snapshot system network में lost UDP datagrams की भरपाई करता है, लेकिन कुछ messages और commands का deliver होना ज़रूरी है
- player के exit करने या server द्वारा client से नया level load करने की demand करने जैसे cases इसमें आते हैं
- यह guarantee NetChannel abstract करता है
संबंधित reading
अभी कोई टिप्पणी नहीं है.