Жаңадан бастаушыларға арналған ойындардағы желілік модель туралы

Жаңадан бастаушыларға арналған ойындардағы желілік модель туралы
Соңғы екі аптада мен өз ойынымның онлайн қозғалтқышында жұмыс істеп жатырмын. Бұған дейін мен ойындарда желі құру туралы мүлде білмедім, сондықтан мен көптеген мақалаларды оқып, барлық ұғымдарды түсіну және өз желілік қозғалтқышымды жаза алу үшін көптеген эксперименттер жасадым.

Бұл нұсқаулықта мен сізбен өзіңіздің ойын қозғалтқышыңызды жазбас бұрын үйренуіңіз керек әртүрлі ұғымдармен, сондай-ақ оларды үйренуге арналған ең жақсы ресурстар мен мақалалармен бөліскім келеді.

Жалпы алғанда, желілік архитектураның екі негізгі түрі бар: бір деңгейлі және клиент-сервер. Тең-теңімен (p2p) архитектурасында деректер қосылған ойыншылардың кез келген жұптары арасында тасымалданады, ал клиент-сервер архитектурасында деректер тек ойыншылар мен сервер арасында тасымалданады.

Кейбір ойындарда тең дәрежелі архитектура әлі де қолданылғанымен, клиент-сервер стандарт болып табылады: оны жүзеге асыру оңай, арнаның кішірек енін қажет етеді және алдаудан қорғауды жеңілдетеді. Сондықтан, бұл оқулықта біз клиент-сервер архитектурасына назар аударамыз.

Атап айтқанда, бізді авторитарлық серверлер қызықтырады: мұндай жүйелерде сервер әрқашан дұрыс. Мысалы, егер ойыншы өзін (10, 5) координаттардамын деп ойласа және сервер оған (5, 3) екенін айтса, клиент өз орнын вице емес, сервер хабарлағанымен ауыстыруы керек. керісінше. Беделді серверлерді пайдалану алаяқтарды анықтауды жеңілдетеді.

Желілік ойын жүйелері үш негізгі компоненттен тұрады:

  • Тасымалдау протоколы: деректер клиенттер мен сервер арасында қалай тасымалданады.
  • Қолдану протоколы: клиенттерден серверге және серверден клиенттерге не және қандай форматта беріледі.
  • Қолданба логикасы: тасымалданатын деректер клиенттер мен сервердің күйін жаңарту үшін қалай пайдаланылады.

Әрбір бөліктің рөлін және олармен байланысты қиындықтарды түсіну өте маңызды.

Тасымалдау протоколы

Бірінші қадам сервер мен клиенттер арасында деректерді тасымалдауға арналған протоколды таңдау болып табылады. Бұл үшін екі Интернет протоколы бар: TCP и UDP. Бірақ олардың біреуі негізінде өзіңіздің тасымалдау протоколыңызды жасай аласыз немесе оларды пайдаланатын кітапхананы пайдалана аласыз.

TCP және UDP салыстыру

TCP және UDP екеуі де негізделген IP. IP пакетті дереккөзден алушыға жіберуге мүмкіндік береді, бірақ жіберілген пакеттің ерте ме, кеш пе алушыға жететініне, оның кем дегенде бір рет жететініне және пакеттер тізбегі дұрыс келетініне кепілдік бермейді. тапсырыс. Сонымен қатар, пакетте мәнмен берілген деректердің шектеулі көлемі ғана болуы мүмкін МТУ.

UDP - бұл IP-нің үстіндегі жұқа қабат. Сондықтан ол бірдей шектеулерге ие. Керісінше, TCP көптеген мүмкіндіктерге ие. Ол қателерді тексеру арқылы екі түйін арасындағы сенімді, реттелген қосылымды қамтамасыз етеді. Демек, TCP өте ыңғайлы және көптеген басқа хаттамаларда қолданылады, мысалы. HTTP, FTP и SMTP. Бірақ бұл мүмкіндіктердің барлығы бағаға ие: кешігу.

Неліктен бұл функциялар кідіріс тудыратынын түсіну үшін TCP қалай жұмыс істейтінін түсінуіміз керек. Жіберуші түйін пакетті қабылдаушы түйінге жібергенде, ол растауды (ACK) алуды күтеді. Егер белгілі бір уақыттан кейін ол оны алмаса (себебі пакет немесе растау жоғалған немесе басқа себептермен), онда ол пакетті қайта жібереді. Сонымен қатар, TCP пакеттердің дұрыс ретпен қабылдануына кепілдік береді, сондықтан жоғалған пакет алынғанша, барлық басқа пакеттерді, тіпті қабылдаушы хост алған болса да, өңдеу мүмкін емес.

Бірақ сіз ойлағандай, көп ойыншы ойындарындағы кешігу өте маңызды, әсіресе FPS сияқты экшнге толы жанрларда. Сондықтан көптеген ойындар өз протоколымен UDP пайдаланады.

UDP негізіндегі жергілікті протокол әртүрлі себептермен TCP протоколынан тиімдірек болуы мүмкін. Мысалы, ол кейбір пакеттерді сенімді, ал басқаларын сенімсіз деп белгілей алады. Сондықтан сенімсіз пакеттің алушыға жетуі маңызды емес. Немесе ол бір ағындағы жоғалған пакет қалған ағындарды бәсеңдетпеуі үшін бірнеше деректер ағындарын өңдей алады. Мысалы, ойнатқыш енгізуге арналған ағын және чат хабарларына арналған басқа ағын болуы мүмкін. Шұғыл емес чат хабары жоғалса, ол шұғыл енгізуді бәсеңдетпейді. Немесе меншікті протокол бейне ойын ортасында тиімдірек болу үшін сенімділікті TCP протоколынан басқаша жүзеге асыруы мүмкін.

Сонымен, егер TCP соншалықты сорып жатса, біз UDP негізінде өзіміздің тасымалдау протоколын жасаймыз ба?

Бұл сәл күрделірек. TCP ойын желілік жүйелері үшін дерлік оңтайлы емес болса да, ол сіздің нақты ойыныңыз үшін өте жақсы жұмыс істей алады және құнды уақытыңызды үнемдей алады. Мысалы, кезекке негізделген ойын немесе кідіріс пен пакет жоғалту Интернетке қарағанда әлдеқайда төмен болатын LAN желілерінде ғана ойналатын ойын үшін мәселе болмауы мүмкін.

Көптеген табысты ойындар, соның ішінде World of Warcraft, Minecraft және Terraria, TCP пайдаланады. Дегенмен, көптеген FPS-тер өздерінің UDP негізіндегі протоколдарын пайдаланады, сондықтан біз олар туралы төменде толығырақ айтатын боламыз.

TCP пайдалануды шешсеңіз, оның өшірілгеніне көз жеткізіңіз Нагль алгоритмі, себебі ол жіберу алдында пакеттерді буферлейді, яғни ол кідіріс уақытын арттырады.

Көп ойыншы ойындары контекстіндегі UDP және TCP арасындағы айырмашылықтар туралы көбірек білу үшін сіз Гленн Фидлердің мақаласын оқи аласыз. UDP қарсы TCP.

Меншікті протокол

Сонымен, сіз өзіңіздің тасымалдау протоколыңызды жасағыңыз келеді, бірақ неден бастау керектігін білмейсіз бе? Сізге сәттілік, өйткені Гленн Фидлер бұл туралы екі таңғажайып мақала жазды. Сіз олардан көптеген ақылды ойларды таба аласыз.

Бірінші мақала Ойын бағдарламашыларына арналған желі 2008, екіншісінен оңайырақ, Ойын желісінің протоколын құру 2016. Мен сізге үлкенінен бастауды ұсынамын.

Гленн Фидлер UDP негізіндегі теңшелетін протоколды пайдаланудың үлкен жақтаушысы екенін ескеріңіз. Оның мақалаларын оқығаннан кейін, сіз оның TCP-де бейне ойындарда елеулі кемшіліктері бар деген пікірін қабылдайтын шығарсыз және сіз өзіңіздің хаттамаңызды жүзеге асырғыңыз келеді.

Бірақ егер сіз желіні жаңадан бастасаңыз, өзіңізге жақсылық жасаңыз және TCP немесе кітапхананы пайдаланыңыз. Өзіңіздің тасымалдау протоколыңызды сәтті енгізу үшін алдын ала көп нәрсені үйрену керек.

Желілік кітапханалар

Егер сізге TCP-ге қарағанда тиімдірек нәрсе қажет болса, бірақ өзіңіздің жеке протоколыңызды енгізу және көптеген егжей-тегжейлерге бару сияқты қиындықтардан өтуді қаламасаңыз, желілік кітапхананы пайдалана аласыз. Олардың көпшілігі бар:

  • йоджимбо Гленн Фидлер
  • RakNet, ол енді қолдау көрсетілмейді, бірақ оның шанышқысы SLikeNet Әлі де белсенді сияқты.
  • ENet көп ойыншы FPS үшін жасалған кітапхана болып табылады Текше
  • GameNetworkingSockets Клапан

Мен олардың барлығын сынап көрмедім, бірақ мен ENet-ті ұнатамын, себебі оны пайдалану оңай және сенімді. Сонымен қатар, оның нақты құжаттары мен жаңадан бастаушыларға арналған оқу құралы бар.

Тасымалдау хаттамасы: Қорытынды

Қорытындылай келе: екі негізгі транспорттық хаттамалар бар: TCP және UDP. TCP көптеген пайдалы мүмкіндіктерге ие: сенімділік, пакеттік тапсырысты сақтау, қателерді анықтау. UDP-де мұның бәрі жоқ, бірақ TCP өзінің табиғаты бойынша кідірісті арттырды, бұл кейбір ойындар үшін қолайсыз. Яғни, төмен кідірісті қамтамасыз ету үшін UDP негізінде өзіңіздің хаттамаңызды жасай аласыз немесе UDP-де тасымалдау протоколын жүзеге асыратын және көп ойыншы бейне ойындарына бейімделген кітапхананы пайдалана аласыз.

TCP, UDP және кітапхана арасындағы таңдау бірнеше факторларға байланысты. Біріншіден, ойынның қажеттіліктерінен: оған төмен кідіріс қажет пе? Екіншіден, қолданбалы хаттама талаптарынан: оған сенімді хаттама қажет пе? Келесі бөлімде көретініміздей, сенімсіз хаттама әбден қолайлы болатын қолданбалы хаттаманы жасауға болады. Соңында, сіз желілік қозғалтқышты әзірлеушінің тәжірибесін де ескеруіңіз керек.

Менің екі кеңесім бар:

  • Барлық кодты қайта жазбай оңай ауыстыруға болатындай етіп, көлік протоколын қолданбаның қалған бөлігінен мүмкіндігінше қысқартыңыз.
  • Шамадан тыс оңтайландырмаңыз. Егер сіз желілік сарапшы болмасаңыз және пайдаланушы UDP негізіндегі тасымалдау протоколы қажет екеніне сенімді болмасаңыз, TCP немесе сенімділікті қамтамасыз ететін кітапханадан бастай аласыз, содан кейін өнімділікті тексеріп, өлшей аласыз. Мәселелер туындаса және оның себебі тасымалдау протоколында екеніне сенімді болсаңыз, өзіңіздің тасымалдау протоколыңызды жасайтын уақыт болуы мүмкін.

Осы бөлімнің соңында мен сізге оқуға кеңес беремін Көп ойыншы ойынын бағдарламалауға кіріспе Брайан Хук, мұнда талқыланған көптеген тақырыптарды қамтиды.

Қолдану протоколы

Енді біз клиенттер мен сервер арасында деректер алмасуға болатындықтан, қандай деректерді және қандай форматта тасымалдау керектігін шешуіміз керек.

Классикалық схема - бұл клиенттер серверге енгізуді немесе әрекеттерді жібереді, ал сервер ағымдағы ойын күйін клиенттерге жібереді.

Сервер толық күйді емес, ойнатқыштың жанында орналасқан нысандары бар сүзілген күйді жібереді. Ол мұны үш себеппен жасайды. Біріншіден, толық күй жоғары жиілікте берілу үшін тым үлкен болуы мүмкін. Екіншіден, клиенттерді негізінен көрнекі және дыбыстық деректер қызықтырады, өйткені ойын логикасының көп бөлігі ойын серверінде имитацияланады. Үшіншіден, кейбір ойындарда ойыншы белгілі бір деректерді білудің қажеті жоқ, мысалы, картаның екінші жағындағы жаудың позициясы, әйтпесе ол пакеттерді иіскеп, оны өлтіру үшін қайда қозғалу керектігін нақты біледі.

Серияландыру

Бірінші қадам - ​​біз жібергіміз келетін деректерді (енгізу немесе ойын күйі) тасымалдауға қолайлы пішімге түрлендіру. Бұл процесс деп аталады сериялау.

Бірден ойға келетін ой JSON немесе XML сияқты адам оқи алатын пішімді пайдалану болып табылады. Бірақ бұл мүлдем тиімсіз болады және арнаның көп бөлігін босқа жұмсайды.

Оның орнына екілік пішімді пайдалану ұсынылады, ол әлдеқайда ықшам. Яғни, пакеттерде тек бірнеше байт болады. Бұл жерде ескеретін мәселе бар байт реті, ол әртүрлі компьютерлерде әртүрлі болуы мүмкін.

Деректерді сериялау үшін кітапхананы пайдалануға болады, мысалы:

Кітапхананың портативті мұрағаттар жасайтынына және эндандық туралы қамқорлық жасайтынына көз жеткізіңіз.

Балама шешім - оны өзіңіз жүзеге асыру; бұл әсіресе кодқа деректерге негізделген тәсілді пайдалансаңыз, қиын емес. Бұған қоса, ол кітапхананы пайдалану кезінде әрқашан мүмкін бола бермейтін оңтайландыруларды орындауға мүмкіндік береді.

Гленн Фидлер сериализация туралы екі мақала жазды: Пакеттерді оқу және жазу и Серияландыру стратегиялары.

Қысу

Клиенттер мен сервер арасында тасымалданатын деректер көлемі арнаның өткізу қабілетімен шектеледі. Деректерді қысу әр суретте көбірек деректерді тасымалдауға, жаңарту жиілігін арттыруға немесе арна талаптарын азайтуға мүмкіндік береді.

Битті орау

Бірінші техника - бит орау. Ол қажетті мәнді сипаттау үшін қажетті биттердің дәл санын пайдаланудан тұрады. Мысалы, сізде 16 түрлі мәнге ие болатын санауыңыз болса, онда тұтас байттың (8 бит) орнына бар болғаны 4 битті пайдалануға болады.

Гленн Фидлер мұны қалай жүзеге асыру керектігін мақаланың екінші бөлігінде түсіндіреді Пакеттерді оқу және жазу.

Битті орау әсіресе келесі бөлімнің тақырыбы болатын іріктеумен жақсы жұмыс істейді.

Сынамаларды алу

Сынамаларды алу мәнді кодтау үшін мүмкін мәндердің ішкі жиынын ғана пайдаланатын жоғалтатын қысу әдісі. Дискреттеуді жүзеге асырудың ең оңай жолы - өзгермелі нүкте сандарын дөңгелектеу.

Гленн Фидлер (тағы да!) өз мақаласында сынама алуды тәжірибеде қалай қолдану керектігін көрсетеді Суретті қысу.

Қысу алгоритмдері

Келесі әдіс шығынсыз қысу алгоритмдері болады.

Міне, менің ойымша, сіз білуіңіз керек ең қызықты үш алгоритм:

  • Хаффман кодтауы алдын ала есептелген кодпен, ол өте жылдам және жақсы нәтижелер бере алады. Ол Quake3 желілік қозғалтқышында пакеттерді қысу үшін пайдаланылды.
  • zlib деректер көлемін ешқашан арттырмайтын жалпы мақсаттағы қысу алгоритмі болып табылады. Қалай көруге болады осында, ол әртүрлі қолданбаларда қолданылған. Бұл күйлерді жаңарту үшін артық болуы мүмкін. Бірақ серверден клиенттерге активтерді, ұзын мәтіндерді немесе жерді жіберу қажет болса, бұл пайдалы болуы мүмкін.
  • Орындау ұзақтығын көшіру - Бұл ең қарапайым қысу алгоритмі болса керек, бірақ ол деректердің белгілі бір түрлері үшін өте тиімді және zlib алдында алдын ала өңдеу қадамы ретінде пайдаланылуы мүмкін. Ол көптеген көрші элементтер қайталанатын плиткалардан немесе воксельдерден тұратын жерді қысу үшін өте қолайлы.

Дельта қысу

Соңғы сығымдау әдісі дельта қысу болып табылады. Ол тек ағымдағы ойын күйі мен клиент қабылдаған соңғы күй арасындағы айырмашылықтар берілетіндігінде тұрады.

Ол алғаш рет Quake3 желілік қозғалтқышында қолданылған. Міне, оны қалай пайдалану керектігін түсіндіретін екі мақала:

Гленн Фидлер де өз мақаласының екінші бөлігінде қолданды Суретті қысу.

Шифрлау

Бұған қоса, клиенттер мен сервер арасындағы ақпаратты тасымалдауды шифрлау қажет болуы мүмкін. Мұның бірнеше себептері бар:

  • құпиялылық/құпиялылық: хабарларды тек алушы оқи алады және желіні иіскейтін басқа ешкім оларды оқи алмайды.
  • аутентификация: ойыншы рөлін ойнағысы келетін адам оның кілтін білуі керек.
  • Хиттің алдын алу: Зиянды ойыншыларға өздерінің алдау пакеттерін жасау әлдеқайда қиын болады, олар шифрлау схемасын қайта жасап, кілтті табуы керек (әр қосылым сайын өзгереді).

Мен бұл үшін кітапхананы пайдалануды ұсынамын. пайдалануды ұсынамын либодий, себебі ол әсіресе қарапайым және тамаша оқу құралдары бар. Әсіресе қызықты оқу құралы кілт алмасу, бұл әрбір жаңа қосылыммен жаңа кілттерді жасауға мүмкіндік береді.

Өтінім хаттамасы: Қорытынды

Бұл біздің өтініш хаттамамызды аяқтайды. Менің ойымша, қысу толығымен міндетті емес және оны пайдалану туралы шешім тек ойынға және қажетті өткізу қабілеттілігіне байланысты. Менің ойымша, шифрлау міндетті, бірақ бірінші прототипте сіз онсыз жасай аласыз.

Қолданба логикасы

Біз қазір клиенттегі күйді жаңарта аламыз, бірақ кідіріс мәселелері туындауы мүмкін. Ойыншы, енгізуді аяқтағаннан кейін, әлемге қандай әсер еткенін көру үшін ойын күйінің серверден жаңартылуын күтуі керек.

Оның үстіне, екі мемлекеттік жаңарту арасында әлем толығымен статикалық. Егер күйді жаңарту жылдамдығы төмен болса, қозғалыстар өте серпінді болады.

Бұл мәселенің әсерін азайтудың бірнеше әдістері бар, мен оларды келесі бөлімде қарастырамын.

Кешіктірілген тегістеу әдістері

Осы бөлімде сипатталған барлық әдістер серияда егжей-тегжейлі талқыланады Жылдам көп ойыншы Габриэль Гамбетта. Мен осы тамаша мақалалар сериясын оқуды ұсынамын. Ол сондай-ақ осы әдістердің іс жүзінде қалай жұмыс істейтінін көруге мүмкіндік беретін интерактивті демонстрацияны қамтиды.

Бірінші әдіс - серверден жауапты күтпестен енгізу нәтижесін тікелей қолдану. деп аталады клиенттік болжау. Дегенмен, клиент серверден жаңартуды алғанда, оның болжамының дұрыс екенін тексеруі керек. Егер бұлай болмаса, онда ол серверден алғанына сәйкес күйін өзгертуі керек, өйткені сервер авторитарлық. Бұл әдіс алғаш рет Quake-те қолданылған. Бұл туралы толығырақ мақаладан оқи аласыз Quake Engine кодын шолу Фабиен Сангларс [аударма Хабреде].

Әдістердің екінші жинағы екі күй жаңартуы арасындағы басқа нысандардың қозғалысын тегістеу үшін пайдаланылады. Бұл мәселені шешудің екі жолы бар: интерполяция және экстраполяция. Интерполяция жағдайында соңғы екі күй қабылданып, бірінен екіншісіне өту көрсетіледі. Оның кемшілігі - ол аздаған кідіріс тудырады, өйткені клиент әрқашан өткенде не болғанын көреді. Экстраполяция - бұл клиент алған соңғы күйге негізделген нысандардың қай жерде болуы керектігін болжау. Оның кемшілігі, егер субъект қозғалыс бағытын толығымен өзгертсе, онда болжам мен нақты позиция арасында үлкен қателік болады.

Тек FPS-те пайдалы ең соңғы, ең жетілдірілген әдіс кешіктірілген өтемақы. Кешігуді өтеуді пайдаланған кезде, сервер нысанаға ату кезінде клиенттің кідірістерін ескереді. Мысалы, егер ойыншы өз экранында басын түсіріп, бірақ іс жүзінде олардың нысанасы кешіктіруге байланысты басқа жерде болса, ойыншының кешігуіне байланысты өлтіру құқығынан бас тарту әділетсіздік болар еді. Сондықтан сервер ойыншының экранда көргенін имитациялау және олардың ату мен нысана арасындағы соқтығысты тексеру үшін ойыншының атыс сәтіне қайтарады.

Гленн Фидлер (әдеттегідей!) 2004 жылы мақала жазды Желі физикасы (2004), онда ол сервер мен клиент арасындағы физика модельдеулерін синхрондаудың негізін қалады. 2014 жылы ол мақалалардың жаңа сериясын жазды Желі физикасы, онда физика модельдеулерін синхрондау үшін басқа әдістер сипатталған.

Сондай-ақ Valve викиде екі мақала бар, Бастапқы көп ойыншы желі и Клиент/сервердегі кідірістің орнын толтыру әдістері. Ойын ішіндегі протоколды жобалау және оңтайландыру кешіктіру үшін өтемақы қарастырылады.

Алаяқтықтың алдын алу

Алаяқтықты болдырмаудың екі негізгі әдісі бар.

Біріншіден: алаяқтардың зиянды пакеттерді жіберуін қиындатады. Жоғарыда айтылғандай, мұны жүзеге асырудың жақсы жолы шифрлау болып табылады.

Екіншіден: авторитарлық сервер тек пәрмендерді/енгізуді/әрекеттерді қабылдауы керек. Клиент енгізуді жіберуден басқа сервердегі күйді өзгерте алмауы керек. Содан кейін сервер енгізуді алған сайын, оны қолданар алдында оның жарамдылығын тексеруі керек.

Қолдану логикасы: қорытынды

Клиент пен сервер бір компьютерде жұмыс істеп тұрған кезде де, нашар жағдайда ойыныңыздың әрекетін тексеру үшін жоғары кідірістерді және төмен жаңарту жиіліктерін имитациялау әдісін енгізуді ұсынамын. Бұл кідірістерді тегістеу әдістерін енгізуді айтарлықтай жеңілдетеді.

Басқа пайдалы ресурстар

Желілік үлгілердегі басқа ресурстарды зерттегіңіз келсе, оларды мына жерден таба аласыз:

Ақпарат көзі: www.habr.com

пікір қалдыру