Sincronismo com Socket?

Olá pessoal,
fiquei com uma duvida que não achei explicação vagando no Google.

Suponhamos que temos um jogo ao estilo “Mario” feito em Java, que terá de ser Multiplayer.
ou seja, imaginem Mario e Luigi sendo controlados por 2 jogadores simultaneos cada um em seu proprio PC.
o Servidor estaria em uma terceira maquina, suportando o jogo.

Sendo a conexão feita via socket, como seria feita a sincronia do movimento de ambos os jogadores?

no exemplo de Chat que eu criei (vide Assinatura), não exigia algo em ‘tempo real’ dando refresh continuamente para saber se uma pessoa esta digitando ou não…
o SocketListener (criado 1 par de listeners para cada usuario, sendo 1 no ‘array do server’ e 1 no proprio client), apenas aguardava o usuario mandar 1 palavra, esta palavra sendo recebida era retransmitida para todo o Array de Usuarios que estavam registrados no Server, e então todos tinham as mesmas informações na tela.

Agora em um jogo ou algo mais dinamico, como funcionaria?
Se o Mario segura o botão de andar para a direita por 5 segundos, ele estaria enviando repetidamente um comando por socket chamado, por exemplo,
“Mario Andar Direita”
o servidor então captura essa ‘String’, e envia essa informação tb para o Luigi avisando para o Mario da tela dele se mover para direita.

Seria isso? ou tem um jeito mais facil de manter essa sincronização?

Se fossemos tentar criar um jogo em grande escala com 100+ pessoas online, não sobrecarregaria o numero de informações sendo enviadas por sockets e tendo q ser traduzidas e retransmitidas para todos os jogadores ?

Alguem tem um exemplo prático de um sistema assim funcionando?

Obrigado.

Coincidencia…recentimente estava pensando sobre este tipo de coisa…

Eu tentaria algo bem parecido com o que vc está pensando.

A questão da performance eu iria tentar resolver montado um client bem esperto que dependesse de um mínimo de informação possível para fazer os movimentos e etc…, ou seja, trafegar pela rede quantidades mínimas de informação; se a gente utilizar 4 inteiros e pensar neles como uma fila de bytes talvez consigamos enviar informações suficiente para o client se virar. Isto é escovar bits mas poderia ajudar.

Outra coisa, iria tomar o cuidado de fazer com que o servidor “enviasse” as informações e não o client ficar feito louco em cima do servidor verificando se alguma coisa aconteceu.

Fora isso, no resultado final, a visão dos 2 jogadores ficariam defasada em zero ponto qualquer coisa em relação ao momento exato dos eventos por conta da buferização das informações.

flws

uma perguntinha que tenho… vocês criam as engine do jogo desde o inicio ou usam algum tipo de API? eu nunca consegui desenvolver uma engine desde inicio…

Voce pode estar enviando constatemente uma String com o status do jogador ao servidor… o servidor calcula a reação e envia a todos os jogadores o estado do jogo.

Os Channels da NIO te oferecem a opção de trabalhar com os sockets sem ter que esperar a reposta do outro lado.
Interessante também de se estudar.

Não tenho nenhum exemplo por que perdi um projeto que eu fiz. Mas tinha esse sentido…
Cada jogador que entrasse virava uma navinha no jogo o servidor calculava as ações e respondia a todos os jogadores.

Funcionava legal… fiz uns testes com umas 5 pessoas simultaneas e tava legal. Mas não tenho idéia da onde foi para esse projeto.

basicamente vc manda algum status da posição dos personagens do jogo.

apenas sou contra você usar uma implementação de socket, udp é bem mais adequado pra esses casos (latência de rede)

e se possível, busque uma representação binária dessas posições (a boa e velha struct do C), quanto menos dados você trafegar, mais eficiente será o protocolo de rede

[quote=qmx]basicamente vc manda algum status da posição dos personagens do jogo.

apenas sou contra você usar uma implementação de socket, udp é bem mais adequado pra esses casos (latência de rede)

e se possível, busque uma representação binária dessas posições (a boa e velha struct do C), quanto menos dados você trafegar, mais eficiente será o protocolo de rede

[/quote]

E voce não pode implementar um Socket para UDP?

Eu nao baixei… mas nesse jogo do ViniGodoy http://www.vinigodoy.com.br/pontov/meusjogos/bandeira/bandeirasrc.zip

acho que tem a ultima versao do JGF(Java Game Framework) que ele criou… nela tem Classes uteis para trabalhar com jogos online via UDP.
Alias… fora isso ainda tem classes uteis se voce quiser criar jogos 2D como algoritmos A* para Pathfinding em Matrizes… Métodos para trabalhar com imagens e sprites… E ainda uma parte com matematica vetorial muito interessante…
Eu mesmo usei no jogo que citei antes e gostei de trabalhar com esse framework.

Se não tiver nessa versão procure com ele.

Bom, o buraco é muuuito mais embaixo.
Motivo: Existe atraso na rede.

Quando vc pressiona o botão de pular, num ping normal, vai levar 60ms para o outro lado ver. Em se tratando de tempo real, 0.5s não é pouco tempo. Pode ser a diferença num jogo de corrida entre sair da pista ou se manter nela. Ou num combate 1x1 entre morrer e ser morto. Na verdade, se você deixar para exibir para o jogador a ação de movimento só quando o servidor confirma-la, você vai ter um jogador bastante irritado, sentindo que o jogo dele tem atraso, ou com dificuldades extremas de controlar o seu bonequinho.

Como se faz então? A solução é disfarçar o atraso. Basicamente, são duas as técnicas usadas para isso:

a) Colocar uma animação na ação e tornar as ações do jogador menos previsíveis: É o caso típico dos MMOs. Você aperta o botão de atacar. Seu personagem chachoalha a arma, salta e só então dá o golpe. O tempo que a animação do chacoalhar leva? Pelo menos 0.6ms. É o tempo para o pacote ir e a confirmação do acerto/erro e dano voltarem… Depois, vem o dano. Ele é aleatório! O valor exato na barra de vida do seu oponente também é desconhecido. Então, o servidor pode dar uma “sobrevida” a ele, antes que decida que ele morreu mesmo.

b) Dead Reckoning: Você aperta o botão de pular. Se o computador esperar meio segundo para responder, você ficará irritado. O que se faz então? Usa-se dead reckoning. Seu cliente pula imediatamente, e envia a informação para o servidor. O outro jogador verá a ação um pouco depois. O problema dessa abordagem é que você terá que trabalhar com três momentos de tempo diferente, em cada máquina:
a) o momento atual (você pulando na tela);
b) o momento t-1 (o servidor informando que um monstro te atacou);
c) o momento t-2 (o servidor te informando que outro jogador se moveu).

Isso é complexo para todos os lados. Considere que um jogador A ataca, e o jogador B pula, ao mesmo tempo. A envia a informação para o servidor de que pulou, B de que atacou. A viu o pulo e B ficando para trás. B viu A sendo atingido, parado. O servidor, deve decidir sobre qual versão é a correta. Se disser que é A, B verá todo o dano de A ser absorvido pela sua “armadura” ou verá a mensagem de “Errou o golpe!”, e logo depois A pulará. Se for B, A verá o dano, mesmo com B no chão. Se o designer foi esperto o suficiente, a animação de B será convincente o suficiente para parecer que B foi atingido mesmo assim…

Note que para usar essa técnica você não pode se basear em ações instantâneas, como é o caso do Pong. Aliás, é dificílimo fazer um pong convicente.

No caso da comunicação bruta em si, usa-se UDP. O problema com o TCP é que ele insiste em garantir ordenação e evitar perda de pacotes, o que definitivamente não é adequado para tempo real. Se você vai mandar a mensagem várias vezes (como todos aqui já deduziram), não tem exatamente que se preocupar com perda. Deixe o TCP para o chat, UDP para o jogo.

Mas sim, no final das contas, é o servidor que enviará a posição final para o cliente, e esse tentará sincronizar a view com o que ele tem na máquina local.

Falando nele… ele apareceu…

ViniGodoy… o caça-bandeiras já tem a ultima versao do JGF? Se não, pode postar por favor, estou interessado a voltar nessa area de desenvolvimento.

[quote=Mark_Ameba]Falando nele… ele apareceu…

ViniGodoy… o caça-bandeiras já tem a ultima versao do JGF? Se não, pode postar por favor, estou interessado a voltar nessa area de desenvolvimento.[/quote]

Posso postar sim.

muito bom então, imaginei que fosse isso q tivesse q fazer mesmo…

mas soh queria a explicação mesmo, eu tenho a intenção atualmente de criar um jogo de cartas, algo bem leve e simples…

seria correto usar TCP para um jogo de cartas?
poderia dar um certo lag, mas como não tem a necessidade de ter movimentos em tempo real, e sim aguardar o movimento do outro jogador de qualquer forma, a precisão dos pacotes seriam mais importantes não?

outra pergunta apenas para confirmar
é correto então usar como falaram, enviar palavras codificadas via socket, q vão representar ações dos jogadores certo?
existe a necessidade dessa info ser ‘criptografada’ antes de ser enviada?
para evitar qualquer tipo de hack ou algo assim?

[quote=alucardeck]outra pergunta apenas para confirmar
é correto então usar como falaram, enviar palavras codificadas via socket, q vão representar ações dos jogadores certo?
existe a necessidade dessa info ser ‘criptografada’ antes de ser enviada?
para evitar qualquer tipo de hack ou algo assim?[/quote]

Não é criptografar, a questão é que você tem que conversar com o servidor com o mínimo de pacotes possível, o que significa que você tem que codificar as tuas ações para que elas ocupem o menor espaço possível. Por exemplo, você dá para a ação atacar o número 1, e o id do jogador Zé é 1234. Então você manda 1 1234, que significa atacar Zé.

Um exemplo de velocidade aparente é a página inicial do Google, por que ela carrega tão rápido? Por que o HTML da página inteira cabe dentro de um pacote TCP.

Otimize para a rede.

[quote=Bruno Laturner]Não é criptografar, a questão é que você tem que conversar com o servidor com o mínimo de pacotes possível, o que significa que você tem que codificar as tuas ações para que elas ocupem o menor espaço possível. Por exemplo, você dá para a ação atacar o número 1, e o id do jogador Zé é 1234. Então você manda 1 1234, que significa atacar Zé.

Um exemplo de velocidade aparente é a página inicial do Google, por que ela carrega tão rápido? Por que o HTML da página inteira cabe dentro de um pacote TCP.

Otimize para a rede.[/quote]

sobre otimizar eu entendi,
agora perguntei sobre a possibilidade de alguem conseguir captar esses dados q estão sendo enviados e enviar dados falsos bagunçando o programa todo…

se um jogador por exemplo perceber q a maquina dele envia um dado toda vez q ele ataca (como vc disse) ‘1 1234’ …
então de alguma maneira ele conseguiria simular esse envio de pacotes ‘1 1234’ ‘2 1234’ ‘3 1234’ por um outro programa, isso poderia ser um hack no sistema todo jah q de forma normal o aplicativo dele nao permitiria fazer isso…

keria saber se alem de otimizado o codigo, existiria a necessidade de criptografar esses ‘IDs’ utilizados para a comunicação entre client/servidor ?

Não entendi a tua preocupação, não é você quem controla o estado do jogo? Se o jogador vez uma jogada ilegal, você simplesmente não a processará, nem a mandará para os outros clientes. Você pode até desconectar o cliente dele e barrar a conta.

O servidor não é somente um repassador de pacotes.

Se é só um jogo de carta, você pode usar um protocolo baseado em texto, criptografado com chave assimétrica de ponta a ponta, que não terá qualquer problema perceptível de performance.

Mas claro, para um jogo simples, use um protocolo simples e com uma criptografia simples. Senão vc corre risco de hack sim, como um jogador forçar um movimento em falso ou ver a mão do adversário.