Det som skiljer ett MMORPG från ett enspelarspel är servern bakom allt du ser. I den här första delen av devloggen för Ancient Online: Remastered förklarar vi hur vi bygger ett MMORPG med Unreal Engine 5.8: hur arbetet fördelas mellan klient och server, hur världen simuleras och hur vi kan redigera en enda, enhetlig värld live.
Två delar: klient och server
Ancient Online består av två separata program:
- Klienten är skriven i C++ på Unreal Engine 5.8. Rendering, ljud, gränssnitt och inmatning är dess uppgift.
- Servern är oberoende av Unreal: vi har skrivit den från grunden i C++23. Alla spelets regler körs här.
Varför skrev vi servern separat i stället för inne i motorn? För att det en MMORPG-server behöver är något annat än det en spelmotor behöver: det finns ingen grafik, men det finns tusentals entiteter, beständiga data, långa drifttider och ett behov av förutsägbar prestanda. En separat server låter oss göra bara det arbete som krävs och ha kontroll över varje byte.
Den auktoritativa servern: att inte lita på klienten
Vår grundregel är den här: klienten påstår, servern beslutar.
- Rörelse: Spelarens inmatning går till servern, och servern beräknar positionen. Klienten visar den position som servern rapporterar, med mjuk interpolering. En klient som ”teleporterar sig själv” eller går genom en vägg kommer alltså ingenstans, vad servern beträffar.
- Strid: Utfall som skada, träffar och knuffar bakåt beräknas på servern. Det är till exempel servern som avgör om en komboträff slår omkull motståndaren, och den skickar ut resultatet till alla samtidigt.
- Ekonomi: Föremål, valuta och butikstransaktioner ändras bara på servern och i databasen.
Priset för det här upplägget är att nätverksfördröjningen måste hanteras väl; vinsten är en värld där det är mycket svårare att fuska och där samma regler gäller för alla.
En världsloop på 25 Hz
Servern uppdaterar världen 25 gånger i sekunden. I varje steg går monster-AI, rörelse, strid, färdighetseffekter och väder framåt. Ett fast steg håller simuleringen förutsägbar och ser till att samma inmatning alltid ger samma resultat.
Alla spelare behöver inte känna till allt. Servern delar in världen i ett rutnät och skickar varje spelare uppdateringar bara om de entiteter som finns inom spelarens intresseområde (de som är i närheten). Det håller nätverkstrafiken rimlig även i en fullsatt stad.
Ett lättviktigt binärt protokoll
Det finns ingen JSON och inget REST mellan klient och server; varje meddelande är ett binärt paket med fast layout. Det sparar både bandbredd och processortid. När vi lägger till ett nytt system (som väder, rörelse eller kontotjänsten i spelet) skriver vi ett separat, versionerat paketkontrakt för det, och vi använder delade headerfiler för att garantera att klient och server arbetar utifrån samma kontrakt.
Beständighet: att spara utan att låta spelet vänta
Spelardata ligger i en PostgreSQL-databas. Men att låta världsloopen vänta på databasen i varje steg är inte acceptabelt. Därför sker sparandet i bakgrunden, som write-behind-lagring: världsservern lägger ändringarna i en kö (Redis), och en bakgrundsprocess skriver dem till databasen i omgångar. Spelets flöde beror inte på databasens hastighet.
Kanaler och inloggningsservern
Spelarna ansluter först till en inloggningsserver, som sköter kontoverifiering, karaktärsval och sessionen. Därefter går de vidare till en av fyra spelkanaler (CH1–CH4). Kanalernas livestatus visas på spelsajtens sida serverstatus.
En enhetlig värld som redigeras live
Världen i Ancient Online är utformad som en enda, enhetlig värld snarare än separata kartor åtskilda av laddningsskärmar; den är uppdelad i celler och läses in genom strömning.
Världens innehåll (terräng, objekt, monsterplaceringar) ligger inte i koden utan i databasen, versionerat. Vi kan redigera den här världen med en världsredigerare inne i spelet: ändringar görs först i ett utkast, kontrolleras och publiceras sedan. Varje publicering skapar en ny version, och klienten verifierar att världsdata den har stämmer med serverns genom att jämföra ett kontrollvärde. Om de inte stämmer väntar den på att data ska uppdateras innan den fortsätter in i spelet.
Uppdrag: Lua som skriptspråk
Uppdrag och NPC-dialoger skrivs i Lua 5.4 på servern. Det gör att vi kan utveckla och testa uppdrag utan att kompilera om servern.
Spelarnas meddelanden lämnar aldrig våra servrar
Vi använder ingen extern översättningstjänst för chattöversättningen i spelet. Vi kör en lokal översättningsmodell, som bara använder processorn, på våra egna servrar; spelarnas meddelanden skickas inte till något externt API. På så sätt kan spelare som talar olika språk förstå varandra utan att deras meddelanden någonsin lämnar studion.
Vad kommer härnäst?
Del två av devloggen handlar om de beslut vi fattade när vi gjorde samma värld spelbar med mus, pekskärm och handkontroll. Vill du lära känna studion kan du läsa Vilka är Astronaut Entertainment?; för själva spelet finns sidan Spel.


