Olen kerran tehnyt multiplayer pelin jossa minun piti näyttää kummallekkin pelaajalle toisen sijainti. Tein sen silloin siten että kumpikin tallensi oman sijaintinsa tietyin ajoin tietokantaan ja sitten toinen haki toisen sijainnin sieltä aina tietyin ajoin. Ongelmaksi muodostui että tietokanta ei ollut kovin nopea jolloin peliin tuli inhottavasti viivettä toisen pelaajan osalta. Onko tämä miten oikeat multiplayer pelitkin tehdään vai miten he ovat ratkaiseet tämän ongelman onko esim SQL tietokanta tarpeeksi nopea vai onko näihin tarkoituksiin suunniteltu jotain omia tietokantoja joissa tieto saadaan ja tallennetaan nopeammin?
Jos sijaintitieto pysyy aina vain yhdellä samalla pelipalvelimella niin yksinkertaista ja nopeaa olisi pitää tieto aina saatavilla keskusmuistissa. Voit myös tallentaa sen tietokantaan, jos sille on tarvetta mutta tarjoile se aina prosessin muistista ja pidä kyseinen prosessi käynnissä koko pelin/kierroksen ajan.
Tosiaan sehän ratkaiseekin ongelman.
Toisin sanoen välimuisti. ;) Jos sille SQL-kannalle edes on tarvetta. Oletin myös että kyseessä oli levylle tallentava tietokanta-asennus, koska viive tosiaan laskee huimasti kun tieto on valmiina prosessin muistissa.
Joo välimuisti kuulostaa ihan fiksulta. ei se tieto oikeastaan tarvitse olla tietokannassa niin se on loistava ratkaisu ainakin omaan ongelmaani jota varten kyselin.
E1ss kirjoitti:
Ongelmaksi muodostui että tietokanta ei ollut kovin nopea jolloin peliin tuli inhottavasti viivettä toisen pelaajan osalta.
Viivettä ei varmaan oikeasti aiheuttanut tietokanta vaan tämä ”tietyin ajoin”. Toki tietokanta on hitaampi kuin tiedon säilytys muistissa, mutta isojakin SQL-kyselyitä voi tehdä millisekunneissa, ja paljon suurempi viive tulee verkosta.
Jos kuvitellaan vaikka ratkaisu, jossa pelaajat lähettävät ja pyytävät tietoja palvelimelta HTTP:llä neljä kertaa sekunnissa, niin tässä viivettä voi tulla hyvinkin puoli sekuntia: aika liikkumisesta lähetykseen (0–250 ms), lähetyksen kesto (100 ms), aika toisen pelaajan pyyntöön (0–250 ms) ja pyynnön kesto (100 ms).
Jos taas tieto lähetetään valmiiksi avoimella yhteydellä palvelimelle, joka lähettää sen heti eteenpäin muille pelaajille, viive riippuu lähinnä verkon nopeudesta ja voi olla hyvissä olosuhteissa esimerkiksi 50 ms ja joka tapauksessa selvästi vähemmän kuin HTTP-ratkaisussa.
Reaaliaikaisessa moninpelissä nopeuden kannalta ensiarvoisen tärkeää on siis se, että yhteys on jatkuvasti auki. Yhteysvaihtoehtoja ovat esimerkiksi TCP, UDP ja WebSocket.
Riippuu pelistä, mitä tietoa on järkevää lähettää. Usein pelaajan komennot ovat kaikkein lyhin vaihtoehto, koska näppäimistöllä ja hiirellä ei voi antaa kovin monta eri komentoa sekunnissa. Esimerkiksi strategiapelissä voi olla, että moneen sekuntiin ei tule yhtään uutta komentoa, ja pelialueella voi silti olla satoja jatkuvasti liikkuvia yksiköitä.
Syötteeseen perustuva ratkaisu vaatii tarkkaavaisuutta aikaleimojen kanssa: peliä voi simuloida eteenpäin vasta, kun kaikkien käyttäjien syötteet kyseiselle hetkelle on saatu, ja siksi pitääkin ehkä sopia, että syötteet käsitellään säännöllisesti hieman myöhässä, jotta ne ehditään ensin lähettää kaikille pelaajille.
Toisaalta myös pelkästään pelaajan sijainnin lähettäminen tuo uusia kysymyksiä siitä, miten pelin mekaniikka toimii, jos sama tieto ei ole kaikilla samaan aikaan: voi olla, että yhden mielestä laukaus osuu ja toisen mielestä ei osu.
Olipa vika tietokannassa tai ei, niin ei sitä kannata käyttää ollenkaan, jos pelin luonne on sellainen, ettei siinä ole mitään järkeä. Tietokantahan on ensisijaisesti pysyväisvarasto, johon tietoa voidaan tallentaa säilöön vaikka siltä varalta, että palvelinkone kaatuu ja RAM-muistissa oleva ohjelman tila menetetään.
Jos ajatellaan jotain Counter-Striken (tällä vuosituhannella syntyneet puhuisivat tosin kai Fortnitestä...) tapaista peliä, niin kyllähän se peli loppuu palvelimen kaatuessa siihen eikä peliä yritetä palauttaa kaatumista edeltävään tilaan joskus myöhemmässä ajassa.
Shakkipelissä siirrot sen sijaan voitaisiin tallentaa kantaan pelin jälkikatselua varten, mutta ei sen silloinkaan tarvitse olla ensisijainen tietovaranto vaan lähinnä backup, johon tiedot viedään säännöllisin väliajoin taustalla, eikä pelin tarvitse silloinkaan odotella tietokantaa reaaliajassa.
Aivan alkeellisimpia naksutteluita lukuun ottamatta tietokannan tuskin tulee koskaan olla reaaliaikainen tietovarasto. Säilyttäisin kaiken tiedon muistissa ja veisin sen tosiaan kantaan korkeintaan tausta-ajona (siis erillisessä säikeessä) tietyin aikavälein.
Mikäli pelisi on nopeatempoinen reaaliajassa tapahtuva "toimintapeli", niin havaitsemasi viive voi tosiaan johtua monestakin asiasta, ja jopa sellaisista asioista, mille et itse voi oikein mitään, vaikka koodisi olisi kuinka tehokasta hyvänsä.
Metabolix kirjoitti:
Syötteeseen perustuva ratkaisu vaatii tarkkaavaisuutta aikaleimojen kanssa: peliä voi simuloida eteenpäin vasta, kun kaikkien käyttäjien syötteet kyseiselle hetkelle on saatu
Useinkin peleihin on toteutettu mahdollisuus että simulointia palautetaan taaksepäin (rollback) ja lasketaan uudestaan jos esim. normaalista poikkeavasta viiveestä johtuen saadaankin myöhässä muiden pelaajien tietoja.
Tässä on sitten syytä miettiä, että pitääkö myös palvelimen pyörittää omaa simulaatiotaan ja päättää mitkä pelaajien syötteet ovat hyväksyttäviä. Voisi ajatella esim. että jossain ihmispelaajien välisessä kaksintaistelutilanteessa yli 100ms palvelimelle saapuessa "viivästyneitä" syötteitä ei hyväksytä mutta sitten taas jos pelaaja taistelee "tietokonetta" vastaan niin voisi vähän isompikin viive sallittu ja pelaajan samoillessa jossain ylhäisessä yksinäisyydessään olisi oikeastaan se ja sama vaikka syötteet tulisi minuutin viiveellä.
Ilman jonkinlaista syötteiden sääntöjenmukaisuustarkistusta pelissä olisi aika helppo huijata.
Aihe on jo aika vanha, joten et voi enää vastata siihen.