O que diferencia um MMORPG de um jogo single-player é o servidor por trás de tudo o que você vê. Nesta primeira parte do devlog de Ancient Online: Remastered, explicamos como estamos construindo um MMORPG com a Unreal Engine 5.8: como o trabalho é dividido entre cliente e servidor, como o mundo é simulado e como conseguimos editar ao vivo um mundo único e unificado.
Duas partes: cliente e servidor
Ancient Online é formado por dois softwares separados:
- O cliente é escrito em C++ sobre a Unreal Engine 5.8. Renderização, áudio, interface e entrada de comandos são tarefas dele.
- O servidor é independente da Unreal: nós o escrevemos do zero em C++23. Todas as regras do jogo rodam aqui.
Por que escrevemos o servidor à parte, e não dentro da engine? Porque o que um servidor de MMORPG precisa é diferente do que uma engine de jogos precisa: não há gráficos, mas há milhares de entidades, dados persistentes, longos períodos no ar e a necessidade de um desempenho previsível. Um servidor separado nos permite fazer só o trabalho necessário e controlar cada byte.
O servidor autoritativo: não confiar no cliente
Nossa regra básica é esta: o cliente alega, o servidor decide.
- Movimento: a entrada do jogador vai para o servidor, e o servidor calcula a posição. O cliente exibe a posição informada pelo servidor, com uma interpolação suave. Assim, um cliente que “se teletransporta” ou atravessa uma parede não vai a lugar nenhum do ponto de vista do servidor.
- Combate: resultados como dano, acertos e empurrões são calculados no servidor. Por exemplo, é o servidor que decide se um golpe de combo derruba o adversário, e ele transmite o resultado para todos ao mesmo tempo.
- Economia: itens, moeda e transações de loja só mudam no servidor e no banco de dados.
O custo dessa abordagem é ter que gerenciar bem a latência de rede; a recompensa é um mundo em que trapacear é muito mais difícil e as mesmas regras valem para todos.
Um loop de mundo a 25 Hz
O servidor atualiza o mundo 25 vezes por segundo. A cada passo, avançam a IA dos monstros, o movimento, o combate, os efeitos de habilidades e o clima. Um passo fixo mantém a simulação previsível e garante que a mesma entrada sempre produza o mesmo resultado.
Nem todo jogador precisa saber de tudo. O servidor divide o mundo em uma grade e envia a cada jogador apenas as atualizações das entidades dentro da sua área de interesse (as que estão por perto). Isso mantém o tráfego de rede em um nível razoável mesmo em uma cidade lotada.
Um protocolo binário leve
Não há JSON nem REST entre cliente e servidor; cada mensagem é um pacote binário com layout fixo. Isso economiza banda e tempo de CPU. Quando adicionamos um novo sistema (como o clima, o movimento ou o serviço de conta dentro do jogo), escrevemos para ele um contrato de pacotes separado e versionado, e usamos arquivos de cabeçalho compartilhados para garantir que cliente e servidor trabalhem com o mesmo contrato.
Persistência: salvar sem fazer o jogo esperar
Os dados dos jogadores ficam em um banco de dados PostgreSQL. Mas fazer o loop do mundo esperar pelo banco de dados a cada passo não é aceitável. Por isso, o salvamento é feito em segundo plano, como persistência write-behind: o servidor do mundo coloca as alterações em uma fila (Redis), e um gravador em segundo plano as grava no banco de dados em lotes. O fluxo do jogo não depende da velocidade do banco de dados.
Canais e o servidor de login
Os jogadores primeiro se conectam a um servidor de login, que cuida da verificação da conta, da seleção de personagem e da sessão. Depois, seguem para um dos quatro canais de jogo (CH1–CH4). O status em tempo real dos canais aparece na página de status do servidor do site do jogo.
Um mundo unificado, editado ao vivo
O mundo de Ancient Online é projetado como um mundo único e unificado, em vez de mapas separados por telas de carregamento; ele é dividido em células e carregado por streaming.
O conteúdo do mundo (terreno, objetos, posicionamento de monstros) não fica no código, e sim no banco de dados, versionado. Podemos editar esse mundo com um editor de mundo dentro do jogo: as alterações são feitas primeiro em um rascunho, verificadas e só então publicadas. Cada publicação cria uma nova versão, e o cliente confirma que os dados de mundo que possui correspondem aos do servidor comparando um digest. Se houver divergência, ele espera os dados serem atualizados antes de seguir para dentro do jogo.
Missões: Lua como linguagem de script
As missões e os diálogos de NPC são escritos em Lua 5.4 no servidor. Isso nos permite desenvolver e testar missões sem recompilar o servidor.
As mensagens dos jogadores nunca saem dos nossos servidores
Não usamos um serviço externo de tradução para a tradução do chat dentro do jogo. Rodamos um modelo de tradução local, que usa apenas CPU, em nossos próprios servidores; as mensagens dos jogadores não são enviadas a nenhuma API externa. Assim, jogadores de idiomas diferentes conseguem se entender sem que suas mensagens jamais saiam do estúdio.
O que vem a seguir
A segunda parte do devlog trata das decisões que tomamos para tornar o mesmo mundo jogável com mouse, tela de toque e controle. Para conhecer o estúdio, leia Quem é a Astronaut Entertainment?; para o jogo em si, veja a página de Jogos.


