Java RMI e Web Services na Implementação de um Jogo Multiusuário Distribuído para Desktop Eduardo Bastian, Beatriz Terezinha Borsoi, Omero Francisco Bertol UTFPR - Universidade Tecnológica Federal do Paraná, câmpus Pato Branco. GETIC (Grupo de Estudos e Pesquisa em Tecnologias de Informação e Comunicação) Via do Conhecimento, Km 01, Caixa Postal 571, 85501-970, Pato Branco, PR, Brazil eduardobastian@gmail.com;beatriz@utfpr.edu.br;omero@utfpr.edu.br RESUMO Os jogos são utilizados com objetivos distintos, incluindo entretenimento, aprendizagem e terapia, e nas diversas fases da vida do ser humano. As redes de computadores, destacando-se a Internet, têm ampliado o mercado de jogos computacionais, especialmente os multiusuário e voltados para entretenimento. A diversidade de aplicabilidade dos jogos e de público usuário, motivou o desenvolvimento deste trabalho, que se refere ao uso de web services e RMI no desenvolvimento de um jogo multiusuário distribuído. É jogo para ambiente desktop implementado utilizando a linguagem Java. Palavras-chave: Java RMI. Jogos computacionais. Jogo multiusuário. Jogo para desktop. Jogos em Java. 1. INTRODUÇÃO Jogos, como atividades lúdicas, são utilizados com objetivos distintos e estão presentes nas diversas atividades e fases da vida do ser humano. De maneira geral, para as crianças, as atividades lúdicas são fontes de socialização; para os jovens podem estar voltadas ao entretenimento; e para os adultos podem estar relacionadas ao passatempo. Os jogos também podem ser utilizados com objetivos de aprendizagem e terapêuticos. Como instrumento de aprendizagem, os jogos são utilizados por instituições de ensino e empresas para auxílio no aprendizado e socialização. Como terapia, eles são utilizados em aplicações e com objetivos diversos, incluindo o auxílio no tratamento de problemas físicos e psicológicos. Eles podem, assim, ser utilizados para auxiliar na correção de dificuldades motoras, de fala, de audição, cognitivas e para terapia ocupacional, dentre outras. Os jogos eletrônicos ou computacionais podem ser encontrados em dispositivos diversos, como computadores pessoais, consoles domésticos e dispositivos móveis [1]. As redes de computadores, destacando-se a Internet, desempenham um papel relevante no uso dos jogos, inclusive pela possibilidade de unir jogadores geograficamente separados. A grande disseminação dos jogos computacionais em rede fundamenta-se em alguns fatores, destacando-se [2]: a competição que se mostra mais atraente e desafiadora; e o fato de os jogos promoverem aspectos sociais interessantes ao permitirem a interação entre os participantes. A diversidade de aplicabilidade dos jogos e usuários motivou o desenvolvimento de um jogo multiusuário distribuído. Exemplificar o uso de Java RMI (Remote Method Invocation) e web services é o objetivo principal deste trabalho, visando apresentar como o desenvolvimento de jogos pode beneficiar-se de cada um deles. A linguagem Java foi utilizada pelos seus recursos e características que facilitam o controle de usuários e o uso de RMI e web services. A tecnologia de web services foi utilizada para implementar controles, como a contagem da pontuação de cada jogador. RMI é uma interface de programação utilizada para executar chamadas remotas. No jogo desenvolvido essa interface foi utilizada para fazer a troca de mensagens e o controle da competição entre os jogadores. Este texto está organizado em seções. Esta é a primeira e apresenta o contexto do trabalho e o seu objetivo. Na Seção 2 está o referencial teórico que é sobre jogos eletrônicos. A seção 3 apresenta o jogo desenvolvido enfatizando a sua implementação. E na Seção 4 está a conclusão. 2. JOGOS ELETRÔNICOS Um jogo, com objetivos lúdicos, de entretenimento ou de apoio à aprendizagem, é caracterizado como uma atividade que possui uma meta ou um objetivo a ser alcançado pelos seus participantes. Essa atividade é controlada por regras preestabelecidas visando prover interatividade ou competição entre os jogadores. Para este trabalho um jogo eletrônico ou computacional é definido como uma simulação visual e interativa exibida em uma tela de um dispositivo eletrônico computacional [3]. Os jogos eletrônicos podem ser categorizados por critérios distintos. Em relação ao tipo de dispositivo eletrônico utilizado, os jogos podem ser categorizados em: a) em rede; b) não em rede; c) para dispositivos móveis; d) para console. Considerando a estratégia de jogo, para o IMPA [4] existem os jogos cooperativos e os
não-cooperativos. Considerando o número de jogadores simultâneos, eles são classificados em: a) monousuário; e b) multiusuário. Em relação à jogabilidade, definida por Porto [5] e Castilho [`6] como o grau de interatividade, os jogos são basicamente divididos em: a) de simulação; b) de tabuleiro. Jogos multiusuário são simulações de ambientes em que cada jogador busca alcançar determinado objetivo por meio de interação com outros jogadores e com o ambiente [7]. Esse ambiente representa o espaço de realização do jogo que é compartilhado pelos jogadores. Assim, é fundamental manter o estado global consistente entre os jogadores. Para isso as ações de cada jogador devem ser repassadas de forma confiável e ordenadas para garantir a correta execução dos eventos do jogo. Helin [8] aponta três grandes problemas dos jogos multiusuário em rede: a) a infraestrutura de rede que pode afetar o andamento e a consistência do jogo; b) a arquitetura de comunicação que cria obstáculos para a escalabilidade desses jogos; c) a necessidade de garantia de um jogo justo, por meio da prevenção de trapaça. A arquitetura cliente/servidor é usada para jogos por possuir implementação simples e auxiliar a resolver problemas de inconsistência e segurança. Isso ocorre porque as mensagens enviadas aos jogadores (clientes) são validadas e determinadas pelo servidor. Contudo, nessa arquitetura há concentração do processamento e das conexões. O uso de diferentes estruturas e técnicas de distribuição de mensagens permite definir arquiteturas de comunicação, de controle e de dados, que ajudam a atenuar os efeitos limitadores relativos à plataforma física para jogos multiusuário. Esses efeitos são [9]: distribuição de mensagens, arquiteturas de comunicação, compressão e agregação de mensagens e gerenciamento de áreas de interesse. a) Distribuição de mensagens - a largura de banda necessária para um jogo multiusuário depende do número de jogadores e das técnicas de distribuição de mensagens utilizadas. As principais formas de distribuição das mensagens nesse tipo de jogo são: a.1) Broadcast - repassa a mensagem de um jogador para todos os que estão participando da mesma sessão de jogo; a.2) Unicast - determina que cada mensagem possua um único emissor e um único receptor; a.3) Multicast - permite que uma única mensagem seja distribuída para um grupo de destinatários, propiciando melhor utilização da rede. b) Arquiteturas de comunicação - a arquitetura de comunicação de um jogo multiusuário baseia-se nas diferentes formas como os computadores interagindo em um jogo estão interconectados. As arquiteturas para jogos multiusuário mais conhecidas são [8]: ponto a ponto, cliente/servidor, replicação e grade de servidores. b.1) Ponto a ponto - a topologia de comunicação entre jogadores é formada por um conjunto de nós, todos possuem características iguais em relação ao software necessário para participação no jogo. b.2) Cliente/servidor - um nó da rede realiza o papel de servidor do jogo e é responsável pela comunicação entre os jogadores. O servidor mantém o estado do jogo centralizado e recebe notificações sobre as atualizações de cada jogador. O servidor atualiza o estado do jogo e repassa as atualizações para os jogadores. b.3) Replicação de servidores - é um modelo híbrido entre as arquiteturas ponto a ponto e cliente/servidor. A infraestrutura de comunicação dos jogadores pode ser vista como uma arquitetura ponto a ponto de servidores de arquiteturas cliente/servidor. Se houver necessidade, jogadores podem ser realocados para um outro servidor. b.4) Grade de servidores - o estado do jogo é distribuído entre os vários servidores. O uso de grade computacional permite balancear a carga entre servidores. c) Compressão e agregação de mensagens - a compressão de mensagens diminui o tamanho das mensagens transmitidas pela redução do número de bits necessários para representar a informação enviada. A agregação de mensagens mescla informações de várias mensagens em uma única, diminuindo a sobrecarga gerada com cabeçalhos de mensagens. Essas duas técnicas têm o objetivo de reduzir o consumo da banda utilizada. d) Gerenciamento de áreas de interesse - uma área de interesse é a parte do mundo virtual que o usuário pode interagir. O gerenciamento dessas áreas permite que os jogadores expressem seus interesses em subconjuntos de informações do jogo. 3. JOGO DESENVOLVIDO Para a implementação do jogo objeto deste trabalho foi utilizada a linguagem Java para a lógica de negócio e para interface que foi agregada por Java RMI e web services, com o ambiente de desenvolvimento NetBeans; o Firebird como banco de dados com o IBExpert como administrador; e o Hibernate para o mapeamento objeto relacional entre as classes Java e as tabelas do banco de dados. Em um jogo de campo minado tradicional um jogador deve descobrir e marcar onde estão as minas em um tabuleiro, sem que elas sejam ativadas. Para os objetivos deste trabalho o jogo foi adaptado visando torná-lo multiusuário. O jogador que descobrir o maior número de minas vence a partida. O jogo inicia pela tela de login. Para conectar-se ao jogo, o usuário, com um computador conectado em rede, deve digitar seu nome de usuário e senha. Se o jogador não possui uma conta, ele pode cadastrar-se. A senha não é definida no cadastro. É gerada automaticamente e enviada para o e-mail do jogador. O cadastro do usuário é importante, pois é por meio dele que são registradas as informações de desempenho do jogador, como número de jogos, vitórias, derrotas e desistências. Com essas informações é calculada a pontuação de cada jogador e a
respectiva classificação no jogo. Essa classificação pode ser vista em uma tela que lista os jogadores e suas respectivas estatísticas. Além do jogo em si, o sistema oferece opções de troca de mensagens entre jogadores que não estão jogando uma mesma partida. Essas mensagens são como emails internos do sistema. Elas podem ser utilizadas para, por exemplo, convidar outros jogadores para jogar. Para jogar, um jogador deve criar um jogo (iniciar um servidor) indicando uma porta de acesso, um nome para a partida e o total de jogadores pretendidos para o jogo (Figura 1). já conectados no mesmo jogo. Essa janela permanecerá até que o usuário que criou o servidor inicie o jogo. Durante o jogo é possível trocar mensagens entre os jogadores. Essas mensagens são mostradas para todos os jogadores conectados no jogo, não havendo a possibilidade de envio de mensagens para determinados jogadores. É uma forma de prevenção de trapaça. A Figura 3 apresenta a tela de criação do jogo (essa figura foi segmentada para facilitar a visualização). Na parte inferior dessa janela há uma caixa de texto na qual o servidor apresenta informações sobre o jogo como: o jogador que inicia o jogo; o jogador que deve efetuar a jogada atual; o resultado de uma jogada. O resultado indica se o jogador localizou ou não uma mina e quantos pontos foram obtidos na jogada. Figura 1. Criação de um jogo novo É por meio dessas informações que outros jogadores se conectam ao jogo (Figura 2). Figura 2. Conexão a um jogo Além da configuração do servidor é possível alterar as configurações do jogo, (Figura 1). Essas configurações se referem ao número de colunas e linhas do tabuleiro e o número de minas existentes. Depois do jogo criado, o servidor fica aguardando até que os outros jogadores se conectem para que a partida seja iniciada. Para se conectar a um jogo, o jogador deve saber o nome do jogo, porta e o IP (Internet Protocol) do computador que iniciou o servidor (Figura 2). Caso obtenha êxito na conexão, uma janela será mostrando listando os jogadores Figura 3. Tela de criação de um novo jogo Na parte central da tela do jogo está o tabuleiro (área quadriculada na Figura 3). No lado direito, parte superior, está um painel que exibe os nomes dos jogadores
conectados ao jogo, como sua pontuação e na parte inferior está uma área para troca de mensagens entre os jogadores. Um dos jogadores é sorteado para iniciar o jogo e apenas esse jogador pode efetuar a jogada. Os tabuleiros dos demais jogadores ficam inativos. O jogador da vez deve clicar no campo do tabuleiro desejado para tentar encontrar uma mina. Caso o jogador encontre uma mina ele deve jogar novamente. Uma mensagem é enviada para todos os jogadores informando o êxito da jogada e o número de minas que ainda restam. Ao errar, a vez passa para o próximo jogador. O fim do jogo é alcançado quando: a) o número de minas restante é zero; b) o número de minas restante é menor que a diferença de pontos entre o primeiro e o segundo colocado; c) os jogadores desistem do jogo. Caso um jogador desista do jogo é incrementada uma desistência em suas estatísticas e ele perde 25 pontos na classificação. O jogador vencedor incrementa seu número de vitórias recebendo 32 pontos. O jogador que perde uma partida tem um decréscimo de 17 pontos. Caso haja empate, os jogadores perdem 17 pontos na classificação. Essa é uma forma de impedir que jogadores forcem empate para ambos incrementarem sua classificação. É uma forma de controle para evitar trapaça. 3.1. Implementação do Jogo Para o desenvolvimento desse jogo, a implementação foi dividida em dois projetos: a) WSJogo - elaboração dos web services que fazem o acesso ao banco de dados Firebird por meio do framework Hibernate; b) CampoMinado - criação do jogo utilizando a tecnologia RMI da linguagem Java e um cliente para consumo dos web services. No projeto WSJogo foi criada a base de dados com o IBExpert utilizando o banco de dados Firebird. A persistência dos dados é feita pelo framework Hibernate, que possibilita a criação de objetos relacionais, que são objetos da linguagem Java convertidos para registros em tabelas relacionais. Para utilizar o Hibernate é necessário baixar suas bibliotecas disponíveis no formato.jar (arquivo compactado usado para distribuir um conjunto de classes Java) e adicioná-las no projeto que fará a persistência no banco de dados. Em seguida, deve-se criar o arquivo hibernate.cfg no diretório raiz das classes do projeto. Esse arquivo é responsável pela configuração do framework Hibernate. Nele são definidas as informações necessárias para a conexão ao banco de dados como driver, diretório, usuário e senha do banco. Além disso, são mapeadas as classes que serão persistidas no banco. Para controlar os acessos ao banco por meio de sessões foi definida uma classe responsável por criar e recuperar sessões, para salvar, atualizar e excluir objetos e também para criar as sentenças de consulta. Com essa classe foi possível eliminar a utilização de classes DAO (Data Access Object) que seriam responsáveis pelo acesso a base de dados específica. Cada classe mapeada no arquivo hibernate.cfg deve ter sua estrutura definida de acordo com a tabela do banco de dados que ela representa. Esse mapeamento é feito com as Hibernate Annotations que pertencem ao pacote de classes javax.persistence. Na implementação do jogo Campo Minado foram criadas três classes que representam entidades do banco de dados: Jogador, Email, EmailJogador. A classe Jogador representa a entidade Jogadores do banco de dados. As classes Email e EmailJogador são responsáveis pela representação das entidades Emails e EmailsJogadores da mesma base de dados. Email e EmailJogador controlam o armazenamento das mensagens que são enviadas entre os jogadores, simulando uma conta de e-mail interna do sistema. Ressalta-se que o envio de mensagens não ocorre por meio de serviço de correio eletrônico. Depois de concluir e testar o mapeamento do banco de dados foi iniciado o desenvolvimento da classe ServicosBaseJogo responsável por disponibilizar os web services. Ela possui uma anotação @WebService() que especifica que esta é uma classe de serviços web. Ao criar uma classe desse tipo é necessário definir pelo menos uma operação, caso contrário ela não terá utilidade. Nessa classe foram criadas todas as operações necessárias para acesso e manipulação das informações dos usuários do jogo. Para o envio dos e-mails contendo as informações de login para o usuário foi utilizado o Commons Email que fornece uma API (Application Programming Interface). Ela é construída a partir da Java Mail API que oferece uma API independente de plataforma e de protocolo para criar mensagens de correio eletrônico. Ao enviar um email, utilizando a operação enviaremail, o Hibernate insere o objeto na tabela Emails. Uma trigger é disparada após essa inserção. Essa trigger é responsável por criar um registro com o código da mensagem enviada para cada jogador. Assim, tanto o jogador que envia a mensagem quanto a que a recebe tem acesso à mensagem. O projeto CampoMinado é a implementação do jogo em si. Esse projeto utiliza um cliente de web services para consumir os serviços do projeto WSJogo e para ter acesso ao banco de dados. Esse projeto foi desenvolvido separando as interações em camadas visando melhor organização e reutilização das classes. Cada camada é divida em threads para que o processamento de uma não interfira no processamento de outra. Desta forma, há uma thread para o objeto que controla o servidor, outra para o cliente e uma outra para a interface. A implementação do projeto CampoMinado foi iniciada pelas classes responsáveis pela comunicação entre os usuários, utilizando a interface RMI do Java. Para que essa comunicação fosse possível foi necessário criar um
servidor que é responsável por tornar acessíveis os métodos do jogo. Assim, cada usuário pode acessar os métodos do jogo de forma remota. Os objetos que serão enviados entre os métodos devem ser instâncias de classes serializáveis, para isso essas classes devem implementar a interface Serializable. A classe Servidor é responsável pela criação e publicação do jogo e é utilizada apenas pelo jogador que cria uma partida e é executada em uma thread separada da que executa a interface. Ela utiliza a classe LocateRegistry para obter uma referência a um objeto remoto em um determinado host ou para criar um objeto remoto que aceita chamadas em uma porta específica. Nessa classe, o LocateRegistry foi utilizado para criar um objeto remoto instanciado da classe JogoImpl que implementa a interação do jogo. Para definir um nome de referência ao objeto remoto e torná-lo acessível foi utilizado o método rebind(). Esses comandos podem ser vistos no código da classe servidor para criar o objeto remoto, como mostram as instruções na Figura 4. registry = LocateRegistry.createRegistry(porta); jogo = new JogoImpl(config); //config = objeto com configurações do jogo registry.rebind(this.nomejogo, jogo); //nome do jogo = nome de referência ownerform.servidoriniciado(); //avisa a thread com a interface Figura 4. Classe para criar objeto remoto A classe JogoImpl implementa a interface IJogo que define o cabeçalho dos métodos que os jogadores acessam para manipular o jogo como iniciarjogo (método acessado pelo jogador que criou o servidor que inicia o jogo em todos os clientes), enviarjogada (método acessado pelo jogador da vez para enviar as coordenadas de sua jogada), registrar (método que serve para permitir que o servidor possa acessar o cliente através do objeto remoto que o cliente instancia ao se conectar ao servidor). Esse método registrar da classe JogoImpl está representado no código que está na Figura 5. public int registrar(ijogador callback, String nome) throws RemoteException { conexaojogador[jogadoresconectados] = callback; nomejogadores[jogadoresconectados] = nome; pontosjogadores[jogadoresconectados] = 0; conexaojogador[jogadoresconectados].setid(jogad oresconectados); jogadoresconectados++; enviarmensagem("servidor", nomejogadores[jogadoresconectados-1] + " se conectou."); for(int i = 0;i<jogadoresConectados;i++) { conexaojogador[i].listarjogadoresconectados(nom ejogadores); } return jogadoresconectados; } Figura 5. Método registrar da classe JogoImpl Cada chamada de método por um cliente é processada no servidor e a resposta que resulta em uma interação do jogo é repassada a todos os clientes (jogadores) conectados, tornando a comunicação do tipo broadcasting. Cada jogador, inclusive o que criou o servidor, instancia um objeto da classe Cliente que é responsável por procurar o objeto remoto do jogo utilizando sua referência, porta e host. Esse objeto é executado em uma outra thread e seus principais comandos estão apresentados no código a seguir. Esse código (Figura 6) é parte da classe Cliente para procurar o objeto remoto do servidor. Registry registry = LocateRegistry.getRegistry(host, this.porta); jogo = (IJogo) registry.lookup(nomejogo); //procura o objeto pela referência jogador = new JogadorImpl(jogo, this.ownerform); //objeto remoto do cliente int id = jogo.registrar(jogador, nomejogador); //registra-se no servidor Figura 6. Código para procura do objeto remoto no servidor Quando o jogador da vez invoca o método enviarjogada vários testes são realizados para que seja obtido o resultado da jogada e para determinar o prosseguimento do jogo. Apenas após serem realizados todos os testes é que o servidor envia os resultados para os jogadores conectados, inclusive o jogador da vez. Desta forma, garante-se que todos os jogadores recebam a mesma informação. O primeiro teste realizado se refere ao valor no tabuleiro da coordenada que o jogador marcou. Se na coordenada jogada não houver uma mina, o jogador que jogou perde a vez e o próximo jogador fica com o tabuleiro habilitado para jogar. Caso o jogador da vez encontre uma mina, é verificado se o número de minas restante é zero. Se for, é verificada a pontuação do primeiro colocado e se essa pontuação é maior que a pontuação do segundo colocado, a vitória é definida para o jogador com mais pontos. Porém, se o primeiro colocado tiver o mesmo número de pontos que o segundo colocado o jogo é declarado empatado. Se ainda restarem mais minas no tabuleiro, verifica-se se a diferença entre o primeiro colocado e o segundo. Se essa diferença é maior que o número de minas restantes no tabuleiro, o jogo é finalizado e o jogador com mais pontos torna-se o vencedor. Caso contrário o jogador da vez deve jogar novamente, pois encontrou uma mina. 4. CONSIDERAÇÕES FINAIS Um dos objetivos dos jogos é divertir e envolver o usuário em uma competição e exigir raciocínio lógico ou treinamento de habilidades. Assim, no desenvolvimento do jogo objeto deste trabalho alguns incrementos foram realizados em relação aos jogos de campo minando comumente encontrados. Esses incrementos visam
motivar o jogador a permanecer no jogo e minimizar formas de trapaça. Embora o RMI nativo tenha implementação bastante complexa se utilizado na implementação de sistemas para execução na rede Internet, sua implementação para uma rede local é bastante simplificada. E é útil pela facilidade de compartilhar métodos e objetos remotos. Os web services permitem que várias operações em um mesmo banco de dados sejam compartilhados por usuários conectados. Os controles fornecidos pelo framework Hibernate, como concorrência de acesso e limite de conexões simultâneas, foram muitos úteis no desenvolvimento do jogo. Facilitando, assim, o controle das jogadas e do jogador ativo. A criação da interface utilizando o pacote de componentes javax.swing do Java no Netbeans pode ser tornar complexa para desenvolvedores sem muita experiência. No desenvolvimento do jogo objeto deste trabalho, parte da interface foi implementada manualmente, inclusive pelo fato de os componentes swing nem sempre fornecem a mesma visualização em tempo de projeto e de execução. O desenvolvimento do jogo Campo Minado foi uma oportunidade de exemplificar o uso de Java, web services e RMI no desenvolvimento desse tipo de aplicativo. Como perspectiva futura está o desenvolvimento de uma versão para Internet. Distribuídos, Dissertação, Instituto de informática, UFRGS, 2005. [8] V. Helin, Development of Modern Multiplayer Games, Dissertação, Helsinki University of Technology, 2003. [9] J. Smed, T. Kaukoranta e H. Hakonen, Aspects of Networking in Multiplayer Computer Games, In: International Conference on Application and Development of Computer Games in the 21st Century, p. 74-81, 2001. 5. REFERÊNCIAS [1] D. C. Barboza, Ambiente Visual para Desenvolvimento de Jogos Eletrônicos, Monografia, Curso de Bacharelado em Ciência da Computação do Centro Universitário Serra dos Órgãos, 2008. [2] F. Trinta, e F. R. Cecin, Jogos Multiusuário Distribuídos: Modelos, Suporte, Variações e Estado da Arte, In: VI Brazilian Symposium on Games and Digital Entertainmen, 2007. [3] J. M. Silveira Neto, Desenvolvimento de Jogos, http://lia.ufc.br/~silveira/pub/desenvolvimento_de_jo gos.pdf, 2009. [4] IMPA - Instituto Nacional de Matemática Pura e Aplicada, Teoria dos Jogos Não Cooperativos, http://webold.impa.br/disciplinas/ementas/9.3.30.htm l, 2009. [5] S. A. Porto, Planejamento em Redes de Tarefas Hierárquicas com Aplicação em Jogos, Dissertação, Universidade Federal do Paraná, 2006. [6] M. A. Castilho, Planejamento Aplicado a Jogos de Computador: uma Implementação Baseada em Redes de Tarefas Hierárquicas, In: XXVII Congresso da SBC, Encontro Nacional de Inteligência Artificial, Rio de Janeiro, p. 1162-1171, 2007. [7] F. R. Cecin, FreeMMG: uma Arquitetura Cliente- Servidor e Par-a-Par de Suporte a Jogos Maciçamente