Redes e Servidores

9 nov, 2018

As dificuldades de implementação de um jogo multiplayer em rede

Publicidade

Fui motivado a escrever sobre esse assunto quando, conversando com vários amigos da área, descobri que não é tão comum para os desenvolvedores saber o quanto o projeto muda se optarem por colocar multiplayer online no jogo. Se você já é veterano da área ou já fez alguns jogos em rede, provavelmente este texto não é para você. Mas se você nunca fez ou está começando agora, estas dicas podem ser valiosas para seu trabalho.

Para começar, vamos falar sobre os conceitos “Client, Server e Proxy”. Se você não está familiarizado com os termos, vou explicar de forma bem resumida. Imagine três entidades: PlayerServer, PlayerClient e PlayerProxy. Todas elas representam você como jogador, mas por um aspecto diferente. PlayerServer é o objeto que representa o seu player no servidor. Já o PlayerClient é o objeto que é você dentro do jogo sendo executado no seu hardware.

E PlayerProxy é o objeto que representa você no hardware dos adversários. Isso também significa que todos os inimigos que você vê em sua tela são versões proxies dos outros jogadores que estão jogando com você pela rede ou InternetOutro exemplo para tentar deixar mais claro: imagine que iremos programar o item “poção de vida”.

A versão de client desse item pode conter apenas o código com a sua mecânica de utilização. Já a versão de server, além do mesmo código com a regra de utilização da poção, pode conter uma parte adicional de segurança, para validar se o item pode mesmo ser utilizado por aquele jogador ou se é uma tentativa de hack.

Já a versão Proxy talvez não precise manter nenhum dos dois códigos, afinal só precisa representar que aquele item foi utilizado por você para os demais jogadores. Logo, bastaria ter o código de um efeito que mostre a utilização daquele item para os jogadores adversários.

Isso pode parecer confuso no início, mas com o tempo é um conceito bem fácil de aprender e utilizar, já que em jogos multiplayer é uma necessidade constante de arquitetura pensar por esses três prismas.

Mas, João, eu preciso sempre dividir o objeto dessa forma? Sim, precisa ser uma preocupação constante que tipo de código fica em cada tipo de objeto, pois, como citei acima, uma das coisas mais importantes com que você também precisará se preocupar em multiplayer em rede é a segurança.

Se seu jogo não for seguro, ele será facilmente hackeável. Existem inúmeros casos de jogos que, por melhor que fossem, não tiveram sucesso, pois os hackers acabaram com toda a diversão. Uma grande dica é que toda ação importante do seu jogo seja validada no servidor, evitando que alguém que tente usar algum hack para conseguir algum tipo de vantagem consiga fazê-lo.

Porém, para isso, você deve evitar que essa parte do código vá para a versão final executável dos jogadores, para que eles não tenham acesso a essa checagem de segurança caso façam engenharia reversa no executável. Com acesso ao seu código, hackear o jogo é muito mais fácil!

E aí vem outra decisão que você deve tomar: qual técnica de servidor utilizar? Um servidor autoritário ou um servidor semi-autoritário? Ou usar técnicas de self hosting com P2P?

Servidor autoritário é aquele que executa e valida todas as ações do jogador. Em um servidor desse tipo, os jogadores apenas enviam pela rede seus inputs (suas intenções de ação), e o servidor valida todas, executa e replica para client e proxies tudo o que está acontecendo.

Já no servidor semi-autoritário, algumas ações são executadas pelo servidor e outras podem ser executadas pelo client. É como se você confiasse que algumas ações podem ser decididas pelo jogador por não serem tão importantes ou de grande impacto no jogo. Assim, é dada a confiança de que algumas ações não precisam ser validadas pelo servidor.

Ambas são técnicas válidas e podem ser utilizadas conforme a necessidade de cada projeto. A primeira garante mais segurança contra hackers, mas, dependendo da quantidade de validações que o servidor tiver que fazer, aumenta o custo de processamento com o qual talvez você ou sua empresa não queiram arcar – o que pode tornar a segunda opção mais vantajosa.

Vale lembrar que, ao utilizar um servidor – seja autoritário ou semi-autoritário -, é essencial que você o hospede em algum lugar, e lembre-se de que isso tem um custo! Além de um serviço de hospedagem, você precisará se preocupar em dar manutenção nesses servidores, de modo que eles se mantenham o máximo de tempo possível para não estragar a experiência dos seus jogadores.

Existe também a opção de self hosting, que, em termos práticos, é o jogo em que o próprio jogador vira o host da partida. Os outros jogadores se conectam através de conexão Peer2Peer (P2P) a esse jogador host, e jogam sem precisar de um servidor dedicado.

Isso faz com que você não precise de infra com um servidor rodando 24/7. No entanto, ao escolher essa opção, você estará dependendo do hardware do jogador para garantir que a experiência de todos na partida seja satisfatória.

Também é importante apontar que, nessa hipótese, é necessário que todo seu código de server esteja no client – que está em mãos do jogador. Como dito anteriormente, se o jogador possui seus códigos de validação em mãos, a chance de hacking é muito maior.

Outros pontos importantes são arquitetura e escalabilidade. Há uma grande diferença entre jogos limitados por partidas (ex.: Overwatch, Fifa, Counter-Strike) e jogos massivos (MMOs), como World of Warcraft.

O primeiro tipo é mais fácil de lidar, pois se utilizam instâncias de servidores diferentes para cada partida iniciada, e caso o servidor em que o jogo está hospedado comece a chegar ao seu limite, é fácil levantar uma segunda máquina com novas instâncias de partidas, e assim por diante. Dessa forma, na teoria, é possível manter um número virtualmente infinito de partidas rodando ao mesmo tempo, sem maiores problemas.

O que leva a um cenário completamente diferente quando se trata de um MMO. Aqui, é necessário utilizar técnicas e várias tecnologias de ponta para conseguir manter vários jogadores em uma mesma região do seu MMO. Manter 100 jogadores conectados em uma ou mais máquinas com várias instâncias de servidores diferentes é um problema muito diferente de manter 1000 jogadores na mesma instância, que é o que geralmente faz um MMO. Nesse segundo caso, há uma grande necessidade de estudo, arquitetura e testes antes de começar a produção do jogo para ter certeza de que ele aguentará o número desejado de jogadores.

A utilização de banda da Internet também precisa ser analisada. A banda de Internet, infelizmente, ainda é um recurso físico e finito tanto para os datacenters, que podem hospedar seus jogos, quanto para seus jogadores, que podem até estar utilizando a conexão de um plano de dados móvel. Jogos como Hearthstone são exemplo de otimização nesse aspecto – mesmo após inúmeras partidas, utilizam apenas alguns kbytes da banda do seu pacote de dados.

Por outro lado, MMOs no geral utilizam muita banda. Isso é normal, dada a natureza desse tipo de jogo, que exige a troca constante de informação por segundo para manter o seu mundo totalmente sincronizado com todos os jogadores.

Sempre que você detectar que alguma ação do seu jogo precisará ser enviada ao servidor, pense em como enviar a menor quantidade de bytes possível para validar a informação. Assim, as chances de conseguir manter a utilização da rede do seu jogo em um nível saudável são muito maiores.

Por último, mas não menos importante, vou falar de um dos problemas mais difíceis com que provavelmente você irá lidar fazendo um jogo multiplayer em rede: a tão temida latência, ou mais comumente conhecida como lag.

A latência é o tempo no qual a informação demora para trafegar do hardware do jogador até o servidor, e lá ser processada e devolvida para o jogador. Mesmo que esse pacote de dados viaje na velocidade da luz, isso significa que a informação terá alguns milissegundos de atraso até ser recebida de volta. Esses milissegundos às vezes podem se tornar segundos, dependendo da distância física entre os jogadores e o servidor do jogo.

Esse tempo de atraso entre servidor e client faz com que tudo o que o jogador vê esteja atrasado em relação ao servidor, e mais atrasado ainda se for pensado em relação aos proxies, conforme pode ser visto na imagem abaixo:

Exemplo de problema de latência

É por isso que alguns jogos criam servidores regionais e restringem as partidas neles apenas para jogadores daquela região. Somente assim você conseguirá a menor latência possível e,com isso, garantir uma experiência melhor para seus jogadores.

Existem inúmeras técnicas de NetCode, que são junções de técnicas de interpolation, prediction e reconciliation que podemos utilizar para mascarar esse problema. No MMORPG Profane, onde atualmente faço parte da equipe e ajudo a desenvolver, utilizamos a seguinte técnica de prediction nos projéteis que temos no jogo: ao disparar uma flecha, o jogador a vê saindo do seu arco instantaneamente ao executar a ação e a vê seguir sua trajetória normalmente.

Porém, essa informação nem chegou ao servidor ainda. Quando o pacote com a ação chega ao server, é feito um cálculo utilizando a velocidade da flecha e quanto tempo a informação demorou para chegar ao servidor.

Com isso, podemos calcular exatamente em qual posição a flecha deveria estar no servidor para que fique sincronizada com a posição que está aparecendo para o player. Em seguida, é feita uma checagem da posição do disparo até a posição em que a flecha deveria estar, se ela deveria ter acertado algo no caminho. Se sim, só confirmamos para o client que ele acertou algo.

Se não, a instanciamos na mesma posição em que o jogador que a disparou a está vendo, e a flecha prossegue seu trajeto normalmente, totalmente sincronizada com o client. Isso não é uma técnica perfeita, mas o custo-benefício era o melhor para nosso tipo de jogo no momento.

Cada jogo utiliza uma técnica diferente, e vale a pena pesquisar como eles o fazem. Cada caso é um caso, e é preciso analisar para seu escopo o que faz mais sentido. A Blizzard divulgou um vídeo que pode ser visto em https://bit.ly/23cWKRq, e nele são explicadas as técnicas utilizadas em Overwatch. Vale a pena conferir e aprender mais sobre isso, pois eles são referências de jogos online no mercado.

Espero com isso ajudá-lo a identificar as dificuldade de implementar um jogo multiplayer em rede. Na dúvida, recomendo começar com um escopo pequeno e gradualmente ir aumentando, até que atinja o resultado esperado. Pode parecer complexo, mas estudar cada um desses tópicos os torna muito mais fáceis no dia a dia, e o resultado será recompensador.

***

Artigo publicado na revista iMasters, edição #28: https://issuu.com/imasters/docs/imasters_28_v5_issuu