Tapaustutkimus
Hearthheld: Moninpelattava Skyrim-roolipelipalvelin, joka on rakennettu jonkun toisen pelimoottorin päälle
Laajuus
25+
Alfatestaajaa ilmoittautunut
835
Committia 13 päivässä
~65,000
Riviä palvelimessa, käynnistimessä, botissa ja työkaluissa
71
Pelimoodin moduulia
95
Pelin sisäistä chat-komentoa
47
Palvelimen testisarjaa
28
Laajennus- ja datatyökalua
Ongelma
Skyrimissä on olemassa pitkäkestoisia moninpeliroolipelejä, mutta suuret avoimet palvelimet vaihtavat läheisyyden laajuuteen: satoja pelaajia, tiukempaa moderointia ja kulttuuria, jossa oletuksena on, että kuka tahansa voi liittyä mukaan. Hearthheld panostaa päinvastaiseen suuntaan: se on pieni, vain kutsulla pääsee palvelin, jonka enimmäiskapasiteetti on 100 pelaajaa. Se on suunniteltu niin, että ihmiset, jotka yleensä joutuvat peliyhteisöjen marginaaliin, eivät joudu varautumaan mihinkään ennen sisäänkirjautumista. Se osa on yhteisön suunnittelua. Loput on tekniikkaa jonkun toisen asettamien rajoitusten puitteissa:
- ·Moottori on jo kymmenen vuotta vanha. Skyrim Special Editionissa ei ole moninpeliä, palvelinta eikä API:ta, jota olisi koskaan tarkoitettu tähän tarkoitukseen.
- ·Moninpelikerros on jonkun toisen avoimen lähdekoodin projekti. SkyMP on C++-asiakasliitäntä sekä TypeScript-palvelin-SDK, jonka lisenssi määrää, miten fork on julkaistava.
- ·Sen julkaistu dokumentaatio ei ole ajan tasalla suhteessa sen omaan lähdekoodiin. Asetusoppaasta puuttuu viisi todellista asetusta, ja siinä viitataan edelleen verkkotunnukseen, joka on ollut poissa käytöstä jo vuosia.
- ·Asiakasohjelma on Windows-peli, jota Steam päivittää taustalla. SkyMP vertaa jokaista laajennuksen tavua tavu tavulta, joten yksi taustapäivitys katkaisee pelaajan verkkoyhteyden.
- ·Väliympäristöä ei ole. Maailma on käynnissä oleva palvelin, jossa ihmiset pelaavat roolipelejä samalla kun se muuttuu heidän allaan.
Mikään tästä ei siis ole tyhjältä pöydältä aloitettua. Työskentelyyn kuuluu tuntemattoman koodipohjan perehtyminen riittävän hyvin, jotta siihen voidaan tehdä korjauksia, sellaisen pelimoottorin heikkouksien löytäminen, jota ei ole koskaan tarkoitettu tällaiseen käyttöön, sekä sellaisten työkalujen kehittäminen, joiden avulla hauras, versioon sidottu asiakasohjelmistokokonaisuus selviää tavallisten pelaajien tietokoneiden kanssa tapahtuvasta vuorovaikutuksesta.
Mitä rakennettiin
Neljä liikkuvaa osaa sekä yhteisötaso, joka päätti, mitä kolmen muun osan oli tehtävä.
Työskentely SkyMP:n sisällä
- ·Tein forkin skyrim-multiplayer/skymp-projektista ja merkitsin sen kiinnitetyksi, jotta pääprojekti ei voi muuttaa sitä keskeneräisenä; palvelinaliprojekti on AGPLv3-lisensoitu, joten muokattua palvelinta muiden käyttäjien hyväksi käytettäessä on julkaistava fork - koodi on julkista, mutta yhteisö on yksityinen
- ·Korjauksia forkin C++- ja TypeScript-koodiin: loitsun suuntaaminen siihen, mihin loitsija todella katsoo, loitsun keskeytyksen lähettäminen hahmoille, joilla ei ole animaatiomuuttujia, liikkeen pysäyttäminen, kun chat ottaa näppäimistön hallintaansa, sekä tavattujen pelaajien luettelon täsmäyttäminen palvelimen tallentamaan tunnukseen
- ·Huomasin, että tämän projektin tarkoituksena ollut sallittujen luettelo oli jo toteutettu ylävirrassa: discordAuth on olemassa, se toimii, mutta sitä ei mainita missään julkaistussa konfiguraatio-oppaassa. Settings.ts-tiedoston lukeminen kesti kaksikymmentä minuuttia ja säästää viikon työmäärän.
- ·Luin MasterClientin lähdekoodia ja huomasin, että palvelin rekisteröi itsensä julkisesti aina, kun todennus on käytössä, eikä tätä voi poistaa käytöstä, minkä vuoksi yksityinen verkkokerros muuttui ”kiva lisä” -ominaisuudesta välttämättömäksi vaatimukseksi
Pelipalvelin
- ·71 moduulin ja noin 33 000 rivin pelitila, joka toimii Hetzner Cloudissa Linux-ympäristössä - julkaistuissa ohjeissa mainitaan vain Windows, mutta jatkuvassa integraatiossa (CI) palvelin on koottu ja testattu Ubuntussa ja Archissa jokaisen päivityksen yhteydessä
- ·95 pelin sisäistä chat-komentoa: roolipeli (/me, /whisper, /yell, /ooc), rakentaminen ja esineiden sijoittelu, omistusoikeudet ja lukitukset, metsästys, kaivostoiminta, ammatit, hahmon ulkoasun muokkaaminen sekä erillinen pelinvalvojan työkalupakki
- ·Maailma, jossa ei ole NPC-hahmoja - kaupat, majatalo ja neuvoston paikat ovat rooleja, joita ihmiset esittävät. Tämä poisti suurimman osan Creation Kitin kustannuksista ja teki pelinjohtajan työstä ensiluokkaisen tehtävän, johon palkataan henkilöstöä erillään moderointitehtävistä.
- ·47 testisarjaa sekä staattisia tarkistuksia, jotka suoritetaan ennen jokaista julkaisua, mukaan lukien yksi, joka havaitsee pelin sisäisestä ohjeesta puuttuvat komennot
- ·53 kohdan pelinsisäinen opas, jonka ansiosta säännöt ja turvallisuusohjeet ovat luettavissa siellä, missä ihmiset todella pelaavat, eikä pelkästään Discordissa
Käynnistysohjelma
- ·Electron-sovellus, joka asentaa ja lukitsee koko asiakaspuolen pinon tiettyyn versioon: Skyrim SE -versiossa 1.6.1170, vastaava SKSE64-rakennus, SkyMP-asiakasohjelma sekä jaettu mod-luettelo
- ·Palauttaa Steamin päivittämän asennuksen kiinnitettyyn versioon käyttämällä Steamin omaa depot-konsolia, varmistamalla, että ladattu versio on juuri haluttu versio, ja varmuuskopioimalla kaiken ennen kuin mitään ylikirjoitetaan
- ·Tarkistaa jokaisen vaaditun laajennuksen tavu tavulta palvelimen kopion kanssa, sillä virheellinen versio aiheuttaa samanlaisen virheen kuin puuttuva versio, ja molemmat on havaittava ennen pelin alkamista
- ·Lukee Vortexin omia profiileja vain lukuoikeudella sen sijaan, että siirtäisi tiedostoja sen selän takana - aiemmassa väliaikaistiedostokansiomenetelmässä oli jo menetetty kolmekymmentä laajennusta, kun kaksi järjestelmää luuli omistavansa saman polun
- ·Asentaa ja määrittää NetBird-overlay-verkoston sekä luo Windowsin palomuurisäännön, joka koskee vain kyseistä porttia ja on rajoitettu yksityiseen aliverkkoon
- ·Arachnophobia-tila: neljä erillistä kytkintä, jotka vaihtavat hämähäkkien 3D-mallit paikallisesti, jolloin hahmo säilyttää törmäysominaisuutensa, tekoälynsä, vahinkonsa ja synkronointinsa, vaikka se renderöidään yhden pelaajan koneella näkymättömänä
Tunnistus ja pääsy
- ·Discord-bottiin integroitu itse isännöity pää-API, joka korvaa riippuvuuden ylävirran yhdyskäytävästä: Discord OAuth, kyselypohjainen kirjautumistila, pelisessiot, identiteettipäätepiste, jota pelipalvelin kutsuu, sekä latausjärjestyksen manifestit
- ·Discord-palvelimen jäsenyys toimii sallittujen käyttäjien listan periaatteella - käyttäjän hyväksyminen Discordissa myöntää pääsyn palvelimelle, hänen poistamisensa peruuttaa pääsyn, ja määritetty estorooli poistaa pelaajan istunnon kesken.
- ·Jäsenyys tarkistetaan selaimessa OAuth-prosessin aikana eikä ohjelman käynnistyessä, joten ei-jäsenelle ilmoitetaan asiasta selkeästi sen sijaan, että hänet hylättäisiin portilla ilman minkäänlaista selitystä syystä
- ·Poistaa kolmannen osapuolen tilin rekisteröinnin käyttöönottoprosessista ja ratkaisee samalla palvelimen julkisen luettelointiongelman
- ·Sama botti hoitaa kutsutunnukset, suositukset, kasvun rajoituksen ja moderointityökalut
Sisältöputki
- ·28 Python-rakennustyökalua, noin 7 500 riviä, jotka kirjoittavat .esp-laajennustiedostoja suoraan sen sijaan, että ne luotaisiin Creation Kitin kautta - toistettavissa, vertailukelpoisia ja uudelleenrakennettavissa lähdetiedoista
- ·Karttamerkkejä, malmisuonia, sisätiloja, säätä, rotuja, kykyjä, loitsuja, reseptejä, emoteja ja vaikeustasoja varten luodut tiedot, joita pelimoodi käyttää JSON-muodossa
- ·Karttamerkit oli luotava Tamrielin omaan pysyvään soluun todellisilla koordinaateilla: merkin kuvake on yksi tavu sen TNAM-alatietueessa, johon mikään ajonaikainen kutsu ei voi kirjoittaa
- ·Kohteet ovat aluksi pysäköityinä ja siirtyvät todellisiin koordinaatteihinsa vasta, kun ne löydetään, koska kompassi ei ota huomioon maailmankartan piilotettua osaa ja näyttää kaikki kantaman sisällä olevat merkinnät
Kuvakaappaukset
Kirjoitustyö ja maailmanrakennus
Maailma on omaa kirjoitustyötä, ei Bethesdan asetelman uudelleenmaalausta. Lore-raamattu sijoittaa palvelimen viisikymmentä vuotta pelin jälkeen, varta vasten rakennettuun vapaakaupunkiin, jolla on sodanjälkeisen liittovaltion myöntämä peruskirja: itsenäinen siksi, ettei mikään lääni halua ottaa siitä vastuuta, hallinnossa kiertävä neuvosto, naapureina lämminhenkinen Riften ja varautunut Windhelm. Teksti palvelee suunnittelua eikä koristele sitä. Peli alkaa kaupungin perustamisesta, joten puolityhjä asutus jossa on tusina ihmistä on fiktion toimimista eikä palvelin joka odottaa täyttymistään, eikä mikään vanhoista sankareista ole vahvistettua totuutta, joten kukaan ei saavu seisomaan NPC-hahmon varjoon.
Tekninen arkkitehtuuri
Mitä opin
Suurin osa siitä, mitä tämä projekti opetti minulle, koski työskentelyä sellaisten rajoitusten puitteissa, joita en ollut itse asettanut, ja suurin osa siitä näkyy muutospäiväkirjassa, koska asiat menivät aluksi pieleen.
Luota lähteeseen enemmän kuin ohjeisiin
SkyMP:n julkaistussa asetusoppaassa luetellaan kaksitoista asetusta, eikä siinä mainita lainkaan pääsynhallintaa. Lähdekoodista löytyy viisi lisäasetusta, mukaan lukien Discord-pohjainen sallittujen käyttäjien lista, jonka tämä projekti oli aikeissa rakentaa alusta alkaen. Ohjeet eivät niinkään olleet virheellisiä kuin vanhentuneita, ja sama sivusto ohjaa käyttäjiä edelleen verkkotunnukseen, joka on ollut poissa käytöstä jo vuosia. Kaksikymmentä minuuttia settings.ts-tiedostossa pyyhkäisi viikon työn pois ja muutti täysin tapani lukea dokumentaatiota kaikesta, mitä en itse ole kirjoittanut.
Riippuvuus, jota ei voi määrittää, on riippuvuus, jota ei ole
SkyMP:ssä versioiden yhteneväisyys on ehdoton: jokaista laajennusta verrataan tavu tavulta, ja Steam päivittää Skyrimin milloin tahansa. Siksi käynnistysohjelman piti pystyä palauttamaan pelaajan peli versioon 1.6.1170 pyynnöstä, ja haara piti kiinnittää eikä seurata. Tämä pätee hyvin myös vanhoihin peleihin, sillä kaikki käyttäjien koneilla automaattisesti päivittyvä on osa yhteensopivuusaluettasi, olitpa sen suunnitellut tai et.
Puuttuvat tiedot eivät ole osoitus epäonnistumisesta
Eräänä iltana ilmeni kolme erillistä vikaa, jotka olivat itse asiassa yksi ja sama ongelma. Hahmon muokkausmodin valokytkin ei toiminut, sen värit eivät vaikuttaneet mihinkään, eikä maalaus siirtynyt. Käynnistysohjelma oli asentanut laajennukset ja arkiston, mutta jättänyt moottorin DLL-tiedoston asentamatta, koska modin, jonka tiedostot sijaitsevat arkiston juurikansiossa, kansiot oli ohitettu. Valikko avautui silti, koska se sijaitsee arkistossa, ja latausjärjestyksen tarkistus onnistui, koska laajennukset olivat paikallaan. Kaikki DLL-tiedoston tukemat toiminnot puuttuivat, eikä kukaan huomauttanut siitä. Diagnoosi otti sitten kolme väärää käännöstä, jotka kaikki olivat samaa virhettä molempiin suuntiin: toimiva laajennus julistettiin kuolleeksi lokirivillä, joka ei tarkoittanut mitään sellaista, sitten asennus julistettiin toimivaksi, vaikka yksi tärkeä tiedosto puuttui, ja lukija esitti kysymyksen, jonka tyhjä vastaus on mahdoton erottaa vastaamatta jättämisestä. Tarkistus, joka ei osaa erottaa ”ei” ja ”en kuullut sinua”, valehtelee sinulle kahdesti.
Moottori ilmoittaa, että toiminto onnistui, mutta ei tee mitään
Ensimmäiset karttamerkit siirrettiin uuteen sisäosakenttään sillä perustellulla syyllä, että oletusmaailmatilan ohittaminen on vakavampi virhe. Neljä erillistä kutsua ilmoitti onnistumisesta, mutta kartta pysyi tyhjänä, koska moveTo-funktio ei nosta viittausta ladattamattomasta sisäosasta. Ongelma korjattiin lisäämällä ne Tamrielin pysyvään soluun. Vanhassa moottorissa, jossa ei ole virheilmoituksia, true-arvon palauttava kutsu ei ole todiste siitä, että mitään olisi tapahtunut; vain pelin sisäinen mittaus on.
Virhe, joka ilmenee vain silloin, kun joku pelaa
Lokitiedosto heitti käsittelemättömän poikkeuksen kolmen sekunnin välein koko illan pelisession ajan. Minikartan sisäisen hakutoiminnon pyyntö kohdistui nimeen, jota sille ei koskaan annettu, ja kyseinen haku suoritetaan vain silloin, kun joku on tosiasiallisesti palvelimella, joten mikään testausvaiheessa ei ollut koskaan päässyt lähellekään sitä. Mikä tahansa, joka riippuu todellisesta läsnäolosta, todellisista istunnoista tai todellisesta kuormituksesta, on näkymätöntä testisarjalle, jossa näitä ei ole, ja ainoa keino, jonka löysin, oli lukea reaaliaikaisia lokitietoja ikään kuin ne olisivat tulostetta eikä jätteitä.
Käyttäjäkohtainen näkymä ei saa olla ristiriidassa palvelimen mallin kanssa
Hämähäkkien poistaminen yhden pelaajan näytöltä viittausten poistamisen avulla toimii maisemien kohdalla, mutta on vaarallista elävän vihollisen tapauksessa: palvelin omistaa objektin ja lähettää siitä jatkuvasti päivityksiä, joten asiakasohjelma päätyy taistelemaan omaa näkymäkoodiaan vastaan sellaista vastaan, joka voi edelleen osua sinuun. Meshin korvaaminen sen sijaan jättää törmäykset, tekoälyn, vahingot ja synkronoinnin ennalleen, eikä se renderöi mitään yhdellä koneella. Esteettömyysominaisuudet ansaitsevat paikkansa olemalla näkymättömiä viralliselle mallille, eivät muokkaamalla sitä.
Lisensointi on arkkitehtoninen rajoite, ei paperityötä
skymp5-server on AGPLv3-lisensoitu, joten muokatun palvelimen ylläpitäminen muiden käyttäjien hyväksi edellyttää lähdekoodin julkaisemista. Tämän selvittäminen ennen koodin kirjoittamista määritteli projektin rakenteen jo alusta alkaen: haara on julkinen, yhteisö on yksityinen, ja tämä osoittautui toimivaksi ratkaisuksi, koska avoin koodi ei paljasta käyttäjäluetteloa, Discord-kanavaa eikä osoitetta. Jos tämä olisi selvinnyt vasta jälkikäteen, siitä olisi tullut paljon kalliimpi keskustelu.
Turvallisuus
- ·Discord-palvelimen jäsenyys on pääsylista: hyväksyminen myöntää pääsyn palvelimelle, poistaminen peruuttaa sen, ja ”ban”-rooli potkaisee käyttäjän ulos kesken istunnon
- ·Jäsenyys vahvistetaan selaimessa OAuth-prosessin yhteydessä, joten hylkäys perustellaan sen sijaan, että siitä ilmoitettaisiin vain hiljaisesti
- ·Itse isännöity master-API poistaa riippuvuuden kolmannen osapuolen tilistä sekä siihen liittyvän julkisen listauksen
- ·NetBird-overlay on pakollinen eikä valinnainen, joten vuotanut tai luettelossa mainittu osoite ei ole tavoitettavissa
- ·Windowsin palomuurisääntö on porttipohjainen ja sen soveltamisala rajoittuu yksityiseen aliverkkoon sen sijaan, että se koskisi mitä tahansa verkkoa tai mitä tahansa kohdetta; se ei ole koskaan sidottu binääriseen polkuun
- ·Vain verkkotila; SkyMP:n offline-tilassa ei ole lainkaan tunnistautumista, joten sitä ei voi käyttää tässä yhteydessä
- ·IP-osoitteiden kirjaaminen on oletusarvoisesti pois käytöstä - ylävirran tapahtumalokikanava lähettää jäsenten IP-osoitteet Discordiin jokaisen kirjautumisen yhteydessä
- ·Julkisessa forkissa on mukana vain koodi: jäsenluettelo, Discord ja palvelimen osoite eivät sisälly siihen