Hemera

De Arkaik - Wikipédia
Ir para navegação Ir para pesquisar
Notas
Este artigo foi criado por Zell, é um relato pessoal e não possui relação direta com o servidor, a leitura é interessante para aqueles que gostam de conhecer sobre o desenvolvimento de jogos, você não precisa ler isto para jogar nosso projeto.


Hemera é o nome da versão em produção do hook e seu conjunto de tecnologias utilizados que fazem o "overlay" em Arkaik:Tales of Sarina. O nome Hemera vem da Deusa da Luz (mitologia grega) que também tem a alcunha de Deusa da Mentira. Escolhi este nome pois o "overlay" não é um overlay nativo ao jogo, ele apenas tenta mascarar e enganar os jogadores para que achem que a interface e telas fazem parte do jogo.

Em suma, nossa aplicação fica por cima do cliente do jogo fingindo fazer parte do jogo, ao mover a tela do jogo, Hemera vai movimentar junto o hook e se o jogo perder o foco ela também oculta as telas do jogo, dando a impressão que Hemera faz parte do jogo.

História de Origem

A ideia do hook surgiu por volta de 2018 ao perceber uma necessidade que segurava a minha imaginação. Atualmente era possível criar script's, mapas, monstros, habilidades e classes customizadas graças a diversas ferramentas criadas pela comunidade de servidores ao decorrer de anos.

Entretanto ainda faltava algo... a possibilidade de criar novas telas, possibilitando criar mecânicas novas ao jogo utilizando novas interfaces. E foi com isto em mente que tracei qual seria o objetivo da nossa prova de conceito:

Criar uma tela nova que faça com que os jogadores não percebam que ela não está de fato "dentro" do jogo.

POC - Prova de Conceito

Nós sabíamos o que queríamos fazer, mas como comprovar meu conceito? Como criar uma tela customizada que conversa com o nosso servidor?

Bom, há algumas formas de fazer isto e elas são várias, listamos todas elas e depois fomos por eliminação baseado no tempo e minha experiência como desenvolvedor. Eu queria não perder mais do que 3 meses nessa prova de conceito.

roBrowser

Alguns de vocês devem conhecer o roBrowser, um cliente web feito pelo membro do rAthena: KeyWord. O projeto foi abandonado pelo mesmo após receber uma "ameaça" da gravity, mas bastante coisa foi feita, era possível jogar sem maiores problemas, o que mais fazia falta era a leitura de efeitos hardcoded no cliente ou algumas telas que ainda não haviam sido implementadas, mas isto eu poderia fazer.

Entretanto duas coisas me fizeram descartar esta ideia em 2018. A primeira é que em 2018 eu ainda não possuía o conhecimento que tenho atualmente em javascript, eu era completamente leigo e teria que colocar em peso a curva de aprendizado da linguagem. Todavia foi o segundo problema que me fez descartar o roBrowser: jogabilidade travada.

As coisas no jogo pareciam ser travadas, eu sentia que a jogabilidade do cliente nativo era mais fluida do que no navegador, causando um desconforto que logo me fez descartar o roBrowser juntando os 2 problemas.

Hook direto no Directx

Bom, eu poderia aprender a como fazer um hook direto no directx vendo como o código do falecido RCX e do SimpleRoHook funcionavam. Ambos os programas eram capazes de desenhar no jogo informações de FPS ou adicionar texturas no chão demonstrando o alcance das habilidades dos jogadores.

Bom, clonei o repositório do fork mais atual do projeto e me deparei com um problema: minha falta de conhecimento no uso das API do directx e falta de paciência em aprender como desenhar utilizando o mesmo, e isso não é tudo, ainda teria a parte de conversar com o emulador. Analisando o código do SimpleRoHook eu vi um monstro e olha que como o nome sugere, eles faz coisas teoricamente simples, então quanto tempo eu não perderia tentando criar telas novas nisso? Bom, como uma das minhas metas era fazer uma prova de conceito em menos de 3 meses, puxei outras cartas do baralho, ainda restavam duas.

Engenharia Reversa (Assembly)

Eu poderia me odiar o suficiente para aprofundar meus estudos em Assembly? Eu já tinha uma base e talvez não demorasse tanto... mas quem eu queria enganar? Se fosse algo tão trivial assim a ponto de em 3 meses eu conseguir fazer algo decente algum dos desenvolvedores renomados do rAthena já teria feito algo. Olha, talvez eu pudesse superar meus limites e conseguir fazer algo, mas então existe uma coisa que sempre me faz ficar com pé atrás ao aprender qualquer coisa nova em meu tempo livre em relação a programação... eu poderei usar este conhecimento adquirido em minha carreira profissional? A resposta óbvia é que não, dificilmente em algum momento da minha vida eu irei querer entrar em uma vaga de programação em assembly... ideia descartada com sucesso.

Overlay Externo

Quando todas as esperanças estavam perdidas... eu encontrei este projeto no github. Era uma aplicação em WinForms que imitava o comportamento de um overlay. Ao conseguir compilar e executar o projeto, ao ver a informação de experiência do meu personagem ao cliente só consegui pensar: É ISTO.

Eu possuía um conhecimento prévio em WinForms e um conhecimento avançado em C#. Obviamente não demorei muito para compreender que a melhor alternativa seria ir para o WPF, afinal nada é mais gostoso para um desenvolvedor backend do que montar tela arrastando componentes.

Pronto, eu sabia que era possível e tinha um código como base, agora eu precisava pensar em como seria a arquitetura do hook. Como fazer a comunicação entre as telas que eu criar e o servidor? Veja isso e muito mais na seção abaixo.

Arquitetura

A essa altura eu já havia perdido 1 mês da minha vida só montando as classes básicas do hook já que a do projeto do github estavam um tanto quanto defasadas e eu não gostei muito de algumas coisas.

E agora eu precisava resolver um problema: como fazer o hook conversar com o cliente? No fim muitas ideias surgiram, algumas gambiarras foram levantadas, mas no fim das contas eu me deparei com o seguinte desenho, e na minha cabeça parecia que isso funcionaria:

Hemera Diagram.png

Confesso que aqui pulei várias outras tentativas de desenho de arquitetura, mas no fim das contas esta foi a vencedora. Resumindo, meu objetivo era fazer com que quando o jogador executasse o client do jogo através de meu Launcher, o hook se conectaria ao servidor com as mesmas credenciais do jogador (login 1), mas se identificando como um hook para o handshake entre o servidor e o cliente acontecer. O servidor então somente aceita a conexão do client (login 2) após saber que o hook destas mesmas credenciais se conectou.

Após 1 mês de cria classe ali, cria classe aqui, finalmente eu estava com a arquitetura base da Satella (nome da primeira versão) pronta. Era feio, uma baita de uma gambiarra, sem nenhum pattern mas funcionava. Eu conseguia enviar pacotes ao servidor pelo hook e sabia qual jogador estava enviando isto. Exemplificando o fluxo do que acontece:

Jogador clica em um botão no hook -> Hook envia um pacote ao servidor -> Servidor verifica se esta conexão do tipo de hook possui uma conta com o mesmo token de credenciais conectado -> Internalmente dentro do emulador, o Hook passa a ser o struct do jogador e a partir daqui é como se o jogador tivesse executado este hook.

Versões

Satella

A primeira versão da prova de conceito se chamava Satella e foi aplicada em um servidor Full PvP. O motivo de ser um full pvp? Bem, precisávamos de um servidor cobaia que pudesse ser montado rápido e que pudéssemos colocar a prova de conceito em um ambiente de produção.

Esta primeira versão possuía um código deveras confuso e criar novas telas era muito trabalhoso, sempre me dava vontade de chorar. Entretanto ele possuía já algumas funcionalidades avançadas, tais como andar pelo WASD do jogo. Eu ainda estava aprendendo a usar o cheat engine para fazer as capturas dos offsets, então eu conseguia pegar a posição da camera do jogador para fazer o WASD funcionar independente da posição da camera.

Entretanto esta versão praticamente só adicionava coisas novas, não fui tão ambicioso.

Esta versão via com as seguintes funcionalidades:

  1. Novo chat onde era possível enviar stickers.
  2. Tela de Maestrias baseado em um antigo protótipo abandonado pela gravity. (https://streamable.com/rl3dqg)

Entretanto, o novo chat entrava em conflito com o chat nativo do jogo e tornava a jogabilidade muito estranha. A função de batalha também não funcionava corretamente com ele, mas o objetivo da Satella foi concluído. Quase todos os jogadores não haviam percebido que a tela de maestria não pertencia ao jogo.

Megumi

Bom, Satella foi um sucesso para provar que o hook era viavel, mas adicionar uma tela nova a Satella era um trabalho arduo e havia muita repetição de código. Eu refiz o código do Overlay apenas reaproveitando a leitura da memória dos offset do client.

Com a Megumi eu comecei a ser mais ambicioso e a fazer com que o hook através de inject removesse telas do jogo, me permitindo por exemplo ocultar a tela básica do jogo e mostrar a minha própria, atualizando-a com os dados direto do client nela.

Após muita refatoração, eu utilizei Megumi em um projeto de Yu-Gi-Oh + Ragnarok, porém o resultado final da jogabilidade não me agradou, mas me fez perceber que eu estava capacitado a refazer totalmente a HUD do jogo, mas ainda precisava fazer um ajuste que me assombrava: ainda estava muito trabalhoso adicionar telas novas.

Hemera (Versão Final)

Mais uma vez comecei a refazer tudo e ter um pensamento de arquitetura mais orientada a módulos, neste periodo eu estudei Unity para entender alguns conceitos de desenvolvimento para jogos.

Foi então que criei a classe GameModule que possuía tudo que eu peguei de experiência com Satella e Megumi, o que eu precisava para gerar uma tela? Funções básicas como Criar Texture, aplicar bind's, attachar a outros módulos e etc... a classe ficou especializada e pronta para uso. Agora eu conseguia criar telas novas complexas em um dia, coisa que antes me tomaria 1 semana utilizando a arquitetura antiga da Megumi.

Dividir em modulos ajudou a estruturar e reaproveitar muito mais o código, utilizando o conceito de scriptables do unity. Por exemplo, a sprite de um item na Hemera passou ser um modulo que possui suas funções e lógica, então se eu quisesse adicionar uma sprite de um item em uma nova tela é só adicionar a referência ao SpriteModule.