All posts

Building an MMORPG with Unreal Engine 5.8 — Devlog #1: The Authoritative Server and World Architecture

Ancient Online's architecture: an Unreal Engine 5.8 client, an authoritative server written in C++, a 25 Hz world loop and one unified world edited live.

A workstation of monitors and laptops set side by side in a dimly lit studio

What sets an MMORPG apart from a single-player game is the server behind everything you see. In this first part of the Ancient Online: Remastered devlog, we explain how we are building an MMORPG with Unreal Engine 5.8: how the work is divided between client and server, how the world is simulated, and how we are able to edit a single, unified world live.

Two pieces: client and server

Ancient Online is made up of two separate pieces of software:

  • The client is written in C++ on Unreal Engine 5.8. Rendering, audio, interface and input are its job.
  • The server is independent of Unreal: we wrote it from scratch in C++23. All of the game's rules run here.

Why did we write the server separately rather than inside the engine? Because what an MMORPG server needs is different from what a game engine needs: there are no graphics, but there are thousands of entities, persistent data, long uptimes and a need for predictable performance. A separate server lets us do only the work that is required and control every byte.

The authoritative server: not trusting the client

Our ground rule is this: the client makes a claim, the server makes the decision.

  • Movement: The player's input goes to the server, and the server computes the position. The client displays the position the server reports, using smooth interpolation. So a client that "teleports itself" or walks through a wall goes nowhere as far as the server is concerned.
  • Combat: Outcomes such as damage, hits and knockback are computed on the server. For example, the server decides whether a combo hit knocks the opponent down, and broadcasts the result to everyone at the same time.
  • Economy: Items, currency and shop transactions change only on the server and in the database.

The cost of this approach is having to manage network latency well; the payoff is a world where cheating is much harder and the same rules apply to everyone.

A 25 Hz world loop

The server updates the world 25 times a second. On every step, monster AI, movement, combat, skill effects and weather all advance. A fixed step keeps the simulation predictable and ensures the same input always produces the same result.

Not every player needs to know about everything. The server divides the world into a grid and sends each player updates only for the entities within their area of interest (those nearby). This keeps network traffic reasonable even in a crowded city.

A lightweight binary protocol

There is no JSON or REST between client and server; every message is a binary packet with a fixed layout. That saves both bandwidth and CPU time. When we add a new system (such as weather, movement or the in-game account service), we write a separate, versioned packet contract for it, and we use shared header files to guarantee that client and server work from the same contract.

Persistence: saving without making the game wait

Player data lives in a PostgreSQL database. But having the world loop wait on the database at every step is not acceptable. So saving is done in the background, as write-behind persistence: the world server drops changes into a queue (Redis), and a background writer commits them to the database in batches. The flow of the game does not depend on the speed of the database.

Channels and the login server

Players first connect to a login server, which handles account verification, character selection and the session. They then move on to one of four game channels (CH1–CH4). The live status of the channels is shown on the game site's server status page.

One unified world, edited live

The world of Ancient Online is designed as a single, unified world rather than separate maps divided by loading screens; it is split into cells and loaded by streaming.

The world's content (terrain, objects, monster placements) is kept not in the code but in the database, versioned. We can edit this world with a world editor inside the game: changes are first made in a draft, checked, and then published. Each publish creates a new version, and the client verifies that the world data it holds matches the server's by comparing a digest. If there is a mismatch, it waits for the data to be updated before continuing into the game.

Quests: Lua as the scripting language

Quests and NPC dialogue are written in Lua 5.4 on the server. This lets us develop and test quests without recompiling the server.

Player messages never leave our servers

We do not use an external translation service for in-game chat translation. We run a local, CPU-only translation model on our own servers; player messages are not sent to any external API. That way, players who speak different languages can understand each other without their messages ever leaving the studio.

What's next

Part two of the devlog covers the decisions we made while making the same world playable with a mouse, a touchscreen and a controller. To get to know the studio, read Who is Astronaut Entertainment?; for the game itself, see the Games page.

Share:
Also available in29