Tietoja verkkomallista aloittelijoille tarkoitetuissa peleissä

Tietoja verkkomallista aloittelijoille tarkoitetuissa peleissä
Viimeiset kaksi viikkoa olen työstänyt pelini verkkomoottoria. Ennen sitä en tiennyt pelien verkostoitumisesta juuri mitään, joten luin paljon artikkeleita ja tein paljon kokeiluja ymmärtääkseni kaikki käsitteet ja pystyäkseni kirjoittamaan oman verkkokoneeni.

Tässä oppaassa haluan jakaa kanssasi erilaiset käsitteet, jotka sinun on opittava ennen oman pelimoottorin kirjoittamista, sekä parhaat resurssit ja artikkelit niiden oppimiseen.

Yleensä verkkoarkkitehtuureja on kahta päätyyppiä: peer-to-peer ja asiakas-palvelin. Peer-to-peer (p2p) -arkkitehtuurissa dataa siirretään minkä tahansa kytkettyjen pelaajien välillä, kun taas asiakas-palvelin -arkkitehtuurissa dataa siirretään vain pelaajien ja palvelimen välillä.

Vaikka joissakin peleissä käytetään edelleen vertaisarkkitehtuuria, asiakaspalvelin on vakiona: se on helpompi toteuttaa, vaatii pienemmän kanavan leveyden ja helpottaa suojaamista huijauksilta. Siksi tässä oppaassa keskitymme asiakas-palvelin-arkkitehtuuriin.

Erityisesti olemme kiinnostuneita autoritaarisista palvelimista: tällaisissa järjestelmissä palvelin on aina oikeassa. Jos pelaaja esimerkiksi luulee olevansa kohdassa (10, 5) ja palvelin kertoo olevansa kohdassa (5, 3), asiakkaan tulee korvata sijaintinsa palvelimen ilmoittamalla sijainnilla, ei päinvastoin. Arvovaltaisten palvelimien käyttö helpottaa huijaajien tunnistamista.

Peliverkkojärjestelmissä on kolme pääkomponenttia:

  • Kuljetusprotokolla: kuinka tietoja siirretään asiakkaiden ja palvelimen välillä.
  • Sovellusprotokolla: mitä välitetään asiakkailta palvelimelle ja palvelimelta asiakkaille ja missä muodossa.
  • Sovelluslogiikka: kuinka lähetettyä dataa käytetään asiakkaiden ja palvelimen tilan päivittämiseen.

On erittäin tärkeää ymmärtää kunkin osan rooli ja niihin liittyvät vaikeudet.

Kuljetusprotokolla

Ensimmäinen askel on valita protokolla tiedon siirtämiseksi palvelimen ja asiakkaiden välillä. Tätä varten on kaksi Internet-protokollaa: TCP и UDP. Voit kuitenkin luoda oman siirtoprotokollasi jonkin niistä pohjalta tai käyttää niitä käyttävää kirjastoa.

TCP:n ja UDP:n vertailu

Sekä TCP että UDP perustuvat IP. IP mahdollistaa paketin lähettämisen lähteestä vastaanottajalle, mutta se ei takaa, että lähetetty paketti saavuttaa vastaanottajan ennemmin tai myöhemmin, että se tulee perille vähintään kerran ja että pakettien sarja saapuu oikea järjestys. Lisäksi paketti voi sisältää vain rajoitetun datakoon arvon mukaan MTU.

UDP on vain ohut kerros IP:n päällä. Siksi sillä on samat rajoitukset. Sitä vastoin TCP:ssä on monia ominaisuuksia. Se tarjoaa luotettavan tilatun yhteyden kahden solmun välille virheentarkistuksen avulla. Siksi TCP on erittäin kätevä ja sitä käytetään monissa muissa protokollissa, esimerkiksi in HTTP, FTP и SMTP. Mutta kaikilla näillä ominaisuuksilla on hintansa: viive.

Ymmärtääksemme, miksi nämä toiminnot voivat aiheuttaa viivettä, meidän on ymmärrettävä, kuinka TCP toimii. Kun lähettävä isäntä lähettää paketin vastaanottavalle isännälle, se odottaa vastaanottavansa kuittauksen (ACK). Jos se ei saa sitä tietyn ajan kuluttua (koska paketti tai vahvistus katosi tai jostain muusta syystä), se lähettää paketin uudelleen. Lisäksi TCP takaa, että paketit vastaanotetaan oikeassa järjestyksessä, joten ennen kuin kadonnut paketti on vastaanotettu, kaikkia muita paketteja ei voida käsitellä, vaikka vastaanottava solmu olisi jo vastaanottanut ne.

Mutta kuten luultavasti ymmärrät, latenssi moninpeleissä on erittäin tärkeä, varsinkin sellaisissa aktiivisissa genreissä kuin FPS. Tästä syystä monet pelit käyttävät UDP:tä omalla protokollallaan.

UDP-pohjainen natiiviprotokolla voi olla tehokkaampi kuin TCP useista syistä. Se voi esimerkiksi merkitä jotkin paketit luotetuiksi ja toiset epäluotetuiksi. Siksi hän ei välitä, jos epäluotettava paketti on saavuttanut vastaanottajan. Tai se voi käsitellä useita tietovirtoja niin, että yhdessä virrassa kadonnut paketti ei hidasta muita virtoja. Esimerkiksi, siellä voi olla säie soittimen syöttämistä varten ja toinen säie chat-viesteille. Jos chat-viesti, joka ei ole kiireellinen data, katoaa, se ei hidasta kiireellistä syöttöä. Tai patentoitu protokolla saattaa toteuttaa luotettavuuden eri tavalla kuin TCP ollakseen tehokkaampi videopeliympäristössä.

Joten jos TCP on perseestä, aiomme rakentaa oman siirtoprotokollamme UDP: n perusteella?

Kaikki on hieman monimutkaisempaa. Vaikka TCP on lähes optimaalinen peliverkkojärjestelmille, se voi toimia melko hyvin tietyssä pelissäsi ja säästää arvokasta aikaa. Esimerkiksi latenssi ei välttämättä ole ongelma vuoropohjaisessa pelissä tai pelissä, jota voidaan pelata vain LAN-verkoissa, joissa latenssi ja pakettihäviö ovat paljon pienemmät kuin Internetissä.

Monet menestyneet pelit, mukaan lukien World of Warcraft, Minecraft ja Terraria, käyttävät TCP:tä. Useimmat FPS:t käyttävät kuitenkin omia UDP-pohjaisia ​​protokolliaan, joten puhumme niistä lisää alla.

Jos päätät käyttää TCP:tä, varmista, että se on poistettu käytöstä Naglen algoritmi, koska se puskuroi paketit ennen lähettämistä, mikä tarkoittaa, että se lisää viivettä.

Lisätietoja UDP:n ja TCP:n eroista moninpelien yhteydessä on Glenn Fiedlerin artikkelissa. UDP vs. TCP.

Oma protokolla

Joten haluat luoda oman siirtoprotokollasi, mutta et tiedä mistä aloittaa? Olet onnekas, sillä Glenn Fiedler kirjoitti siitä kaksi hämmästyttävää artikkelia. Löydät niistä paljon älykkäitä ideoita.

Ensimmäinen artikkeli Verkostoituminen peliohjelmoijille 2008, helpompi kuin toinen Pelin verkkoprotokollan rakentaminen 2016. Suosittelen aloittamaan vanhemmasta.

Muista, että Glenn Fiedler on suuri kannattaja käyttää UDP-pohjaista protokollasi. Ja luettuasi hänen artikkelinsa, omaksut todennäköisesti hänen mielipiteensä siitä, että TCP:llä on vakavia haittoja videopeleissä, ja haluat ottaa käyttöön oman protokollan.

Mutta jos olet uusi verkottumisessa, tee itsellesi palvelus ja käytä TCP:tä tai kirjastoa. Jotta voit toteuttaa oman kuljetusprotokollasi onnistuneesti, sinun on opittava paljon etukäteen.

Verkkokirjastot

Jos tarvitset jotain tehokkaampaa kuin TCP, mutta et halua vaivautua toteuttamaan omaa protokollasi ja syventymään moniin yksityiskohtiin, voit käyttää verkkokirjastoa. Niitä on paljon:

En ole kokeillut kaikkia, mutta pidän enemmän ENetistä, koska se on helppokäyttöinen ja luotettava. Lisäksi siinä on selkeä dokumentaatio ja opetusohjelma aloittelijoille.

Kuljetuspöytäkirjan päätelmä

Yhteenvetona voidaan todeta, että on olemassa kaksi pääkuljetusprotokollaa: TCP ja UDP. TCP:llä on monia hyödyllisiä ominaisuuksia: luotettavuus, pakettijärjestyksen säilyttäminen, virheiden havaitseminen. UDP:llä ei ole kaikkea tätä, mutta TCP:llä on luonteensa vuoksi korkea latenssi, jota ei voida hyväksyä joissakin peleissä. Toisin sanoen alhaisen latenssin varmistamiseksi voit luoda oman UDP-pohjaisen protokollan tai käyttää kirjastoa, joka toteuttaa siirtoprotokollan UDP:ssä ja on sovitettu moninpelivideopeleihin.

Valinta TCP:n, UDP:n ja kirjaston välillä riippuu useista tekijöistä. Ensinnäkin pelin tarpeista: tarvitseeko se alhaisen latenssin? Toiseksi sovellusprotokollan vaatimuksista: tarvitseeko se luotettavan protokollan? Kuten seuraavassa osassa näemme, on mahdollista luoda sovellusprotokolla, johon epäluotettava protokolla on varsin sopiva. Lopuksi sinun on myös otettava huomioon verkkomoottorin kehittäjän kokemus.

Minulla on kaksi vinkkiä:

  • Irrota siirtoprotokolla mahdollisimman paljon muusta sovelluksesta, jotta se voidaan helposti korvata ilman koko koodin uudelleenkirjoittamista.
  • Älä optimoi liikaa. Jos et ole verkon asiantuntija etkä ole varma, tarvitsetko oman UDP-pohjaisen siirtoprotokollan, voit aloittaa TCP:stä tai luotettavuutta tarjoavasta kirjastosta ja testata ja mitata sitten suorituskykyä. Jos sinulla on ongelmia ja olet varma, että se on siirtoprotokolla, saattaa olla aika luoda oma siirtoprotokollasi.

Tämän osan lopussa suosittelen lukemista Johdatus moninpeliohjelmointiin Brian Hook, joka kattaa monet täällä käsitellyt aiheet.

Sovellusprotokolla

Nyt kun voimme vaihtaa tietoja asiakkaiden ja palvelimen välillä, meidän on päätettävä, mitä tietoja siirretään ja missä muodossa.

Klassinen malli on, että asiakkaat lähettävät syötteitä tai toimintoja palvelimelle ja palvelin lähettää asiakkaille sen hetkisen pelitilan.

Palvelin ei lähetä täydellistä, vaan suodatettua tilaa soittimen lähellä olevien entiteettien kanssa. Hän tekee tämän kolmesta syystä. Ensinnäkin kokonaistila voi olla liian suuri lähetettäväksi suurella taajuudella. Toiseksi asiakkaat ovat pääasiassa kiinnostuneita visuaalisesta ja audiodatasta, koska suurin osa pelin logiikasta simuloidaan pelipalvelimella. Kolmanneksi, joissakin peleissä pelaajan ei tarvitse tietää tiettyjä tietoja, kuten vihollisen sijaintia kartan toisella puolella, koska muuten hän voi haistaa paketteja ja tietää tarkalleen minne siirtyä tappaakseen hänet.

Sarjoittaminen

Ensimmäinen askel on muuntaa lähetettävät tiedot (syöttö tai pelitila) lähetettäväksi sopivaan muotoon. Tätä prosessia kutsutaan sarjoittaminen.

Heti tulee mieleen ajatus käyttää ihmisen luettavaa muotoa, kuten JSON tai XML. Mutta tämä on täysin tehotonta ja vie suurimman osan kanavasta turhaan.

Sen sijaan on suositeltavaa käyttää binaarimuotoa, joka on paljon kompaktimpi. Toisin sanoen paketit sisältävät vain muutaman tavun. Tässä meidän on otettava ongelma huomioon tavujärjestys, jotka voivat vaihdella eri tietokoneissa.

Tietojen sarjoittamiseksi voit käyttää kirjastoa, esimerkiksi:

Varmista vain, että kirjasto luo kannettavia arkistoja ja huolehtii lopullisuudesta.

Vaihtoehtoinen ratkaisu olisi toteuttaa se itse, se ei ole niin vaikeaa, varsinkin jos käytät koodissasi tietokeskeistä lähestymistapaa. Lisäksi sen avulla voit suorittaa optimointeja, jotka eivät aina ole mahdollisia kirjastoa käytettäessä.

Glenn Fiedler on kirjoittanut kaksi artikkelia serialisoinnista: Luku- ja kirjoituspaketit и Sarjastamisstrategiat.

puristus

Asiakkaiden ja palvelimen välillä siirrettävän tiedon määrää rajoittaa kanavan kaistanleveys. Tietojen pakkaamisen avulla voit siirtää enemmän tietoja kussakin tilannekuvassa, lisätä virkistystaajuutta tai yksinkertaisesti vähentää kaistanleveysvaatimuksia.

Pikkupakkaus

Ensimmäinen tekniikka on bittipakkaus. Se koostuu siitä, että käytetään täsmälleen sitä bittimäärää, joka on tarpeen halutun arvon kuvaamiseksi. Jos sinulla on esimerkiksi enum, jolla voi olla 16 eri arvoa, voit käyttää kokonaisen tavun (8 bitin) sijasta vain 4 bittiä.

Glenn Fiedler selittää kuinka tämä toteutetaan artikkelin toisessa osassa. Luku- ja kirjoituspaketit.

Bittipakkaus toimii erityisen hyvin diskretisoinnin kanssa, mikä on seuraavan osan aiheena.

Näytteenotto

Näytteenotto on häviöllinen pakkaustekniikka, joka käyttää vain osajoukkoa mahdollisista arvoista arvon koodaamiseen. Helpoin tapa toteuttaa diskretisointi on pyöristää liukulukuja.

Glenn Fiedler (taas!) näyttää artikkelissaan kuinka diskretisointia sovelletaan käytännössä Tilannekuvan pakkaus.

Pakkausalgoritmit

Seuraava tekniikka on häviöttömät pakkausalgoritmit.

Tässä on mielestäni kolme mielenkiintoisinta algoritmia, jotka sinun on tiedettävä:

  • Huffman koodaus esilasketulla koodilla, joka on erittäin nopea ja voi tuottaa hyviä tuloksia. Sitä käytettiin pakettien pakkaamiseen Quake3-verkkomoottorissa.
  • zlib on yleiskäyttöinen pakkausalgoritmi, joka ei koskaan lisää tiedon määrää. Kuinka voit nähdä täällä, sitä on käytetty monissa sovelluksissa. Päivittävien tilojen osalta se voi olla tarpeeton. Mutta se voi olla hyödyllistä, jos haluat lähettää resursseja, pitkiä tekstejä tai maastoa asiakkaille palvelimelta.
  • Ajonpituuksien kopiointi on luultavasti yksinkertaisin pakkausalgoritmi, mutta se on erittäin tehokas tietyntyyppisille tiedoille, ja sitä voidaan käyttää esikäsittelyvaiheena ennen zlib:iä. Se sopii erityisen hyvin laatoista tai vokseleista koostuvan maaston tiivistämiseen, jossa monet vierekkäiset elementit toistuvat.

delta-pakkaus

Viimeinen pakkaustekniikka on delta-pakkaus. Se johtuu siitä, että vain nykyisen pelitilan ja asiakkaan viimeksi vastaanottaman tilan väliset erot lähetetään.

Sitä käytettiin ensimmäisen kerran Quake3-verkkomoottorissa. Tässä on kaksi artikkelia, joissa selitetään sen käyttöä:

Glenn Fiedler käytti sitä myös artikkelinsa toisessa osassa. Tilannekuvan pakkaus.

salaus

Lisäksi saatat joutua salaamaan asiakkaiden ja palvelimen välisen tiedonsiirron. Tähän on useita syitä:

  • Yksityisyys/luottamuksellisuus: Vain vastaanottaja voi lukea viestejä, eikä mikään muu verkon nuuskija voi lukea niitä.
  • autentikointi: henkilön, joka haluaa pelata pelaajan roolia, on tunnettava avaimensa.
  • huijausten esto: pahantahtoisten pelaajien on paljon vaikeampaa luoda omia huijauspakettejaan, heidän on kopioitava salausjärjestelmä ja löydettävä avain (joka muuttuu jokaisella yhteydellä).

Suosittelen vahvasti kirjaston käyttöä tähän. suosittelen käyttöä libsodium, koska se on erityisen yksinkertainen ja sisältää upeita opetusohjelmia. Erityisen mielenkiintoinen on opetusohjelma avainten vaihto, jonka avulla voit luoda uusia avaimia jokaiselle uudelle yhteydelle.

Soveltamispöytäkirja: Johtopäätös

Tämä päättää sovellusprotokollan. Uskon, että pakkaus on täysin valinnainen ja päätös käyttää sitä riippuu vain pelistä ja tarvittavasta kaistanleveydestä. Salaus on mielestäni pakollinen, mutta ensimmäisessä prototyypissä voit tehdä ilman sitä.

Sovelluslogiikka

Pystymme nyt päivittämään asiakkaan tilan, mutta saatamme kohdata latenssiongelmia. Syötön jälkeen pelaajan on odotettava pelin tilapäivitystä palvelimelta nähdäkseen, mikä vaikutus sillä on ollut maailmaan.

Lisäksi kahden tilapäivityksen välillä maailma on täysin staattinen. Jos tilan päivitysnopeus on alhainen, liikkeet ovat hyvin nykiviä.

On olemassa useita tekniikoita tämän ongelman vaikutusten lieventämiseksi, ja käsittelen niitä seuraavassa osiossa.

Viiveen tasoitustekniikat

Kaikki tässä osiossa kuvatut tekniikat käsitellään yksityiskohtaisesti sarjassa. Nopeatempoinen moninpeli Gabriel Gambetta. Suosittelen lukemaan tämän erinomaisen artikkelisarjan. Se sisältää myös interaktiivisen esittelyn, jossa nähdään, kuinka nämä tekniikat toimivat käytännössä.

Ensimmäinen tekniikka on syöttää tulos suoraan odottamatta vastausta palvelimelta. Sitä kutsutaan asiakaspuolen ennuste. Kun asiakas kuitenkin saa päivityksen palvelimelta, sen on varmistettava, että sen ennuste oli oikea. Jos näin ei ole, hänen on vain muutettava tilaansa sen mukaan, mitä hän sai palvelimelta, koska palvelin on autoritaarinen. Tätä tekniikkaa käytettiin ensimmäisen kerran Quakessa. Voit lukea siitä lisää artikkelista. Quake Engine -koodin tarkistus Fabien Sanglars [käännös Habrésta].

Toista tekniikkasarjaa käytetään tasoittamaan muiden entiteettien liikettä kahden tilapäivityksen välillä. On kaksi tapaa ratkaista tämä ongelma: interpolointi ja ekstrapolointi. Interpolaation tapauksessa otetaan kaksi viimeistä tilaa ja näytetään siirtymä yhdestä toiseen. Sen haittana on, että se aiheuttaa pienen osan viiveestä, koska asiakas näkee aina mitä on tapahtunut. Ekstrapolaatiolla on tarkoitus ennustaa, missä entiteettien pitäisi nyt olla asiakkaan viimeksi vastaanottaman tilan perusteella. Sen haittapuoli on, että jos kokonaisuus muuttaa liikkeen suunnan kokonaan, ennusteen ja todellisen sijainnin välillä on suuri virhe.

Viimeinen, edistynein tekniikka, joka on hyödyllinen vain FPS:ssä, on viiveen korvaus. Viivekompensaatiota käytettäessä palvelin ottaa huomioon asiakkaan viiveet, kun se laukaisee kohteen. Jos pelaaja esimerkiksi teki päälaukauksen näytöllään, mutta todellisuudessa hänen kohteensa oli eri paikassa viiveen vuoksi, olisi epäreilua evätä pelaajalta oikeus tappaa viiveen vuoksi. Joten palvelin kelaa aikaa taaksepäin siihen hetkeen, jolloin pelaaja ampui simuloidakseen mitä pelaaja näki näytöllään ja tarkistaakseen, onko hänen laukauksensa ja kohteen välillä törmäys.

Glenn Fiedler (kuten aina!) kirjoitti artikkelin vuonna 2004 Verkkofysiikka (2004), jossa hän loi perustan fysiikan simulaatioiden synkronoinnille palvelimen ja asiakkaan välillä. Vuonna 2014 hän kirjoitti uuden artikkelisarjan verkkofysiikka, jossa hän kuvaili muita tekniikoita fysiikan simulaatioiden synkronoimiseksi.

Valven wikissä on myös kaksi artikkelia, Lähde Multiplayer Networking и Viiveen kompensointimenetelmät asiakkaan/palvelimen sisäisessä peliprotokollan suunnittelussa ja optimoinnissa viivästyskorvausten käsittelyssä.

Huijausten ehkäisy

On olemassa kaksi pääasiallista huijaamisen ehkäisytekniikkaa.

Ensinnäkin huijaajien on vaikea lähettää haitallisia paketteja. Kuten edellä mainittiin, hyvä tapa toteuttaa se on salaus.

Toiseksi arvovaltaisen palvelimen tulisi vastaanottaa vain komentoja/syöttöä/toimintoja. Asiakas ei saa pystyä muuttamaan palvelimen tilaa muuten kuin lähettämällä syötettä. Tämän jälkeen palvelimen tulee aina, kun se vastaanottaa syötteen, tarkistaa sen kelpoisuus ennen sen käyttöönottoa.

Sovelluslogiikka: Johtopäätös

Suosittelen, että otat käyttöön tavan simuloida korkeaa latenssia ja alhaisia ​​virkistystaajuuksia, jotta voit testata pelisi käyttäytymistä huonoissa olosuhteissa, vaikka asiakas ja palvelin toimivat samalla koneella. Tämä yksinkertaistaa huomattavasti viiveen tasoitustekniikoiden toteuttamista.

Muita hyödyllisiä resursseja

Jos haluat tutustua muihin verkkomalliresursseihin, löydät ne täältä:

  • Glenn Fiedlerin blogi – kannattaa lukea hänen koko bloginsa, siinä on monia erinomaisia ​​artikkeleita. Täällä kaikki verkkoteknologioita käsittelevät artikkelit on koottu.
  • Mahtava peliverkosto M. Fatih MAR on kattava luettelo artikkeleista ja videoista videopelien verkkomoottoreista.
  • В wiki subreddit r/gamedev Siellä on myös monia hyödyllisiä linkkejä.

Lähde: will.com

Lisää kommentti