• Pacotes - Pawn.RakNet
Os sistemas que usam a biblioteca RakNet, se comunicam através do que é conhecido como pacotes. Ou mais precisamente no caso de UDP, datagramas. Cada datagrama é criado pela biblioteca RakNet e contém uma ou mais mensagens. Essas mensagens podem ser vida, posição do jogador, veículo atual, entre outros.
O primeiro byte do pacote (8 bits) é o seu identificador numérico.
Existem vários identificadores de pacote, sendo os mais comuns:
Tipos de Pacotes:
-Outcoming Packets: Pacotes mandados pelo servidor ao cliente.
-Incoming Packets: Pacotes mandados pelo cliente ao servidor.
Prioridades:
-SYSTEM_PRIORITY: Usada pelo RakNet para enviar chamadas de prioridade acima do normal.
-HIGH_PRIORITY: Chamadas de alta prioridade são enviadas antes das chamadas de prioridade média.
-MEDIUM_PRIORITY: As chamadas de prioridade média são enviadas antes das chamadas de baixa prioridade.
-LOW_PRIORITY: As chamadas de baixa prioridade só são enviadas quando nenhuma outra chamada está aguardando.[/INDENT]
Confiabilidades:
-UNRELIABLE: Os pacotes UNRELIABLE são enviados por UDP direto. Eles podem chegar fora de ordem, ou não. Isto é melhor para os dados que não são importantes ou os dados que você envia com muita freqüência, mesmo que alguns pacotes sejam perdidos, os pacotes mais novos serão compensados.
Vantagens - Esses pacotes não precisam ser reconhecidos pela rede, salvando o tamanho de um cabeçalho UDP em reconhecimento (cerca de 50 bytes ou mais). As economias podem realmente se somar.
Desvantagens - Sem pedidos de pacotes, os pacotes podem nunca chegar, esses pacotes são os primeiros a serem descartados se o buffer de envio estiver cheio.
-UNRELIABLE_SEQUENCED: Os pacotes UNRELIABLE_SEQUENCED são os mesmos que os pacotes UNRELIABLE, exceto que apenas o pacote mais recente é aceito. Os pacotes mais antigos são ignorados. Vantagens - Mesma baixa sobrecarga que pacotes UNRELIABLE, e você não precisa se preocupar com pacotes mais antigos que mudam seus dados para valores antigos.
Desvantagens - muitos pacotes serão descartados, uma vez que eles nunca podem chegar por causa do UDP e podem cair mesmo quando eles chegam. Esses pacotes são os primeiros a serem descartados se o buffer de envio estiver cheio. O último pacote enviado pode nunca chegar, o que pode ser um problema se você parar de enviar pacotes em algum ponto particular.
-RELIABLE: Os pacotes RELIABLE são pacotes UDP monitorados por uma camada de confiabilidade para garantir que eles chegam ao destino.
Vantagens - Você sabe que o pacote chegará lá. Eventualmente ...
Desvantagens - Retransmissões e reconhecimentos podem adicionar exigências significativas de largura de banda. Os pacotes podem chegar muito tarde se a rede estiver ocupada. Não há pedidos de pacotes.
-RELIABLE_ORDERED: Os pacotes RELIABLE_ORDERED são pacotes UDP monitorados por uma camada de confiabilidade para garantir que eles chegam ao destino. Vantagens - O pacote chegará na ordem em que foi enviado. Estes são, de longe, os mais fáceis de programar, porque você não precisa se preocupar com comportamento estranho devido a falta de ordem ou pacotes perdidos.
Desvantagens - Retransmissões e reconhecimentos podem adicionar exigências significativas de largura de banda. Os pacotes podem chegar muito tarde se a rede estiver ocupada. Um pacote tardio pode atrasar muitos pacotes que chegaram mais cedo, resultando em espasmos significativos. No entanto, essa desvantagem pode ser atenuada pelo uso inteligente de fluxos de pedidos.
-RELIABLE_SEQUENCED: Os pacotes RELIABLE_SEQUENCED são pacotes UDP monitorados por uma camada de confiabilidade para garantir que eles chegam ao destino e são seqüenciados no destino.
Vantagens - Você obtém a confiabilidade dos pacotes UDP, o pedido de pacotes ordenados, mas não precisa aguardar pacotes antigos. Mais pacotes chegarão com esse método do que com o método UNRELIABLE_SEQUENCED, e eles serão distribuídos de forma mais uniforme. A vantagem mais importante no entanto é que o último pacote enviado chegará, onde com UNRELIABLE_SEQUENCED o último pacote enviado pode não chegar.
Desvantagens - Desperdício de largura de banda, porque ele usa a sobrecarga de pacotes UDP confiáveis para garantir a chegada de pacotes atrasados que apenas sejam ignorados de qualquer maneira.
• O que é BitStream?
A classe BitStream é uma classe auxiliar na biblioteca RakNet, que é usada para fazer um wrap de uma matriz dinâmica com a finalidade de (des)empacotar bits.
• Modificando as mensagens (dados) de um pacote
No exemplo acima, modificamos a mensagem de arma atual do jogador, logo fazendo com que todos o vejam segurando uma minigun (38).
BS_IgnoreBits(bs, 8); - Antes de ler os dados do pacote, ignoramos os primeiros 8 bits (1 byte), pois esses contém o identificador do pacote.
BS_ReadOnFootSync(bs, onFootData); - Após ignorar os primeiros 8 bits, podemos ler o pacote, que terá seus dados passados para onFootData (referenciando o enumerador PR_OnFootSync).
onFootData[PR_weaponId] = 38; - Mudamos o ID da arma no pacote, que queremos que outros jogadores vejam.
BS_SetWriteOffset(bs, 8); - Mudamos a offset de escrita de dados para depois dos 8 bits, pois não queremos escrever em cima do identificador do pacote.
BS_WriteOnFootSync(bs, onFootData); - Então, escrevemos os novos dados de sincronização a pé no BitStream.
return 1; - Retornamos 1, permitindo o envio do pacote com os dados escritos no BitStream.
• Mandando um pacote
Para mandar um pacote, temos que escrever seus dados em um BitStream, sendo o primeiro parâmetro o seu identificador (8 bits).
No exemplo acima, a função manda um pacote com dados de tiro para um jogador específico.
new BitStream:bs = BS_New(); - Criamos um BitStream, onde podemos escrever os dados do nosso pacote.
PR_UINT8, ID_BULLET_SYNC, - Primeiro parâmetro do bitstream. Este é o identificador do pacote (primeiros 8 bits).
PR_UINT16, from - Segundo parâmetro do bitstream. Este é o jogador responsável, de quem os dados de tiro vão originar.
BS_WriteBulletSync(bs, data); - "data" referência o enumerador PR_BulletSync, vamos escrever os dados no BitStream.
BS_Send(bs, to, PR_HIGH_PRIORITY, PR_RELIABLE_ORDERED); - "to" é o jogador que receberá o pacote. Mandamos o BitStream com os dados de pacote para este jogador. Se você mandar "to" como -1, todos os jogadores vão receber o pacote. PR_HIGH_PRIORITY é a prioridade do pacote, e PR_RELIABLE_ORDERED é sua confiabilidade.
BS_Delete(bs); - Removemos o BitStream após o uso.
Os sistemas que usam a biblioteca RakNet, se comunicam através do que é conhecido como pacotes. Ou mais precisamente no caso de UDP, datagramas. Cada datagrama é criado pela biblioteca RakNet e contém uma ou mais mensagens. Essas mensagens podem ser vida, posição do jogador, veículo atual, entre outros.
O primeiro byte do pacote (8 bits) é o seu identificador numérico.
Existem vários identificadores de pacote, sendo os mais comuns:
ID_VEHICLE_SYNC (200) = Responsável pelas mensagens (dados) de sincronização de veículo. Ex: quando o jogador está dentro de um carro. Sua posição, vida do carro, velocidade, etc, são as mensangens do pacote.
ID_AIM_SYNC (203) = Responsável pelas mensagens (dados) de mira/câmera do jogador. Ex: Vetores de câmera, zoom de câmera, estado da arma, objeto/carro/jogador/ator em que o jogador está mirando, etc são as mensangens do pacote.
ID_BULLET_SYNC (206) = Responsável pelas mensagens (dados) de tiros de armas. Ex: tipo de disparo, origem do disparo, destino do disparo, alvo, centro do disparo, arma usada para o disparo, etc, são as mensagens do pacote.
ID_PLAYER_SYNC (207) = Responsável pelas mensagens (dados) do jogador quando está a pé. Ex: teclas pressionadas, posição atual, vida, colete, arma em mãos, velocidade, animações, posição de surfing em algum veículo, se o jogador esta "surfando" algum veículo, ação especial, etc, são as mensagens do pacote.
Tipos de Pacotes:
-Outcoming Packets: Pacotes mandados pelo servidor ao cliente.
-Incoming Packets: Pacotes mandados pelo cliente ao servidor.
Prioridades:
-SYSTEM_PRIORITY: Usada pelo RakNet para enviar chamadas de prioridade acima do normal.
-HIGH_PRIORITY: Chamadas de alta prioridade são enviadas antes das chamadas de prioridade média.
-MEDIUM_PRIORITY: As chamadas de prioridade média são enviadas antes das chamadas de baixa prioridade.
-LOW_PRIORITY: As chamadas de baixa prioridade só são enviadas quando nenhuma outra chamada está aguardando.[/INDENT]
Confiabilidades:
-UNRELIABLE: Os pacotes UNRELIABLE são enviados por UDP direto. Eles podem chegar fora de ordem, ou não. Isto é melhor para os dados que não são importantes ou os dados que você envia com muita freqüência, mesmo que alguns pacotes sejam perdidos, os pacotes mais novos serão compensados.
Vantagens - Esses pacotes não precisam ser reconhecidos pela rede, salvando o tamanho de um cabeçalho UDP em reconhecimento (cerca de 50 bytes ou mais). As economias podem realmente se somar.
Desvantagens - Sem pedidos de pacotes, os pacotes podem nunca chegar, esses pacotes são os primeiros a serem descartados se o buffer de envio estiver cheio.
-UNRELIABLE_SEQUENCED: Os pacotes UNRELIABLE_SEQUENCED são os mesmos que os pacotes UNRELIABLE, exceto que apenas o pacote mais recente é aceito. Os pacotes mais antigos são ignorados. Vantagens - Mesma baixa sobrecarga que pacotes UNRELIABLE, e você não precisa se preocupar com pacotes mais antigos que mudam seus dados para valores antigos.
Desvantagens - muitos pacotes serão descartados, uma vez que eles nunca podem chegar por causa do UDP e podem cair mesmo quando eles chegam. Esses pacotes são os primeiros a serem descartados se o buffer de envio estiver cheio. O último pacote enviado pode nunca chegar, o que pode ser um problema se você parar de enviar pacotes em algum ponto particular.
-RELIABLE: Os pacotes RELIABLE são pacotes UDP monitorados por uma camada de confiabilidade para garantir que eles chegam ao destino.
Vantagens - Você sabe que o pacote chegará lá. Eventualmente ...
Desvantagens - Retransmissões e reconhecimentos podem adicionar exigências significativas de largura de banda. Os pacotes podem chegar muito tarde se a rede estiver ocupada. Não há pedidos de pacotes.
-RELIABLE_ORDERED: Os pacotes RELIABLE_ORDERED são pacotes UDP monitorados por uma camada de confiabilidade para garantir que eles chegam ao destino. Vantagens - O pacote chegará na ordem em que foi enviado. Estes são, de longe, os mais fáceis de programar, porque você não precisa se preocupar com comportamento estranho devido a falta de ordem ou pacotes perdidos.
Desvantagens - Retransmissões e reconhecimentos podem adicionar exigências significativas de largura de banda. Os pacotes podem chegar muito tarde se a rede estiver ocupada. Um pacote tardio pode atrasar muitos pacotes que chegaram mais cedo, resultando em espasmos significativos. No entanto, essa desvantagem pode ser atenuada pelo uso inteligente de fluxos de pedidos.
-RELIABLE_SEQUENCED: Os pacotes RELIABLE_SEQUENCED são pacotes UDP monitorados por uma camada de confiabilidade para garantir que eles chegam ao destino e são seqüenciados no destino.
Vantagens - Você obtém a confiabilidade dos pacotes UDP, o pedido de pacotes ordenados, mas não precisa aguardar pacotes antigos. Mais pacotes chegarão com esse método do que com o método UNRELIABLE_SEQUENCED, e eles serão distribuídos de forma mais uniforme. A vantagem mais importante no entanto é que o último pacote enviado chegará, onde com UNRELIABLE_SEQUENCED o último pacote enviado pode não chegar.
Desvantagens - Desperdício de largura de banda, porque ele usa a sobrecarga de pacotes UDP confiáveis para garantir a chegada de pacotes atrasados que apenas sejam ignorados de qualquer maneira.
• O que é BitStream?
A classe BitStream é uma classe auxiliar na biblioteca RakNet, que é usada para fazer um wrap de uma matriz dinâmica com a finalidade de (des)empacotar bits.
• Modificando as mensagens (dados) de um pacote
- Código:
#define ID_PLAYER_SYNC 207
public OnIncomingPacket(playerid, packetid, BitStream:bs)
{
if (packetid == ID_PLAYER_SYNC)
{
new onFootData[PR_OnFootSync];
BS_IgnoreBits(bs, 8);
BS_ReadOnFootSync(bs, onFootData);
onFootData[PR_weaponId] = 38;
BS_SetWriteOffset(bs, 8);
BS_WriteOnFootSync(bs, onFootData);
}
return 1;
}
No exemplo acima, modificamos a mensagem de arma atual do jogador, logo fazendo com que todos o vejam segurando uma minigun (38).
BS_IgnoreBits(bs, 8); - Antes de ler os dados do pacote, ignoramos os primeiros 8 bits (1 byte), pois esses contém o identificador do pacote.
BS_ReadOnFootSync(bs, onFootData); - Após ignorar os primeiros 8 bits, podemos ler o pacote, que terá seus dados passados para onFootData (referenciando o enumerador PR_OnFootSync).
onFootData[PR_weaponId] = 38; - Mudamos o ID da arma no pacote, que queremos que outros jogadores vejam.
BS_SetWriteOffset(bs, 8); - Mudamos a offset de escrita de dados para depois dos 8 bits, pois não queremos escrever em cima do identificador do pacote.
BS_WriteOnFootSync(bs, onFootData); - Então, escrevemos os novos dados de sincronização a pé no BitStream.
return 1; - Retornamos 1, permitindo o envio do pacote com os dados escritos no BitStream.
• Mandando um pacote
Para mandar um pacote, temos que escrever seus dados em um BitStream, sendo o primeiro parâmetro o seu identificador (8 bits).
- Código:
#define ID_BULLET_SYNC 206
SendBullet(from, to, data[PR_BulletSync])
{
new BitStream:bs = BS_New();
BS_WriteValue(
bs,
PR_UINT8, ID_BULLET_SYNC,
PR_UINT16, from
);
BS_WriteBulletSync(bs, data);
BS_Send(bs, to, PR_HIGH_PRIORITY, PR_RELIABLE_ORDERED);
BS_Delete(bs);
}
/*Em algum lugar em seu código*/
new bulletData[PR_BulletSync];
bulletData[PR_hitType] = /*tipo de acerto*/;
bulletData[PR_hitId] = /*ID do objeto/jogador/carro acertado*/;
bulletData[PR_origin][0] = /*origem X*/;
bulletData[PR_origin][1] = /*origem Y*/;
bulletData[PR_origin][2] = /*origem Z*/;
bulletData[PR_hitPos][0] = /*posição de acerto X*/;
bulletData[PR_hitPos][1] = /*posição de acerto Y*/;
bulletData[PR_hitPos][2] = /*posição de acerto Z*/;
bulletData[PR_offsets][0] = /*offset X*/;
bulletData[PR_offsets][1] = /*offset Y*/;
bulletData[PR_offsets][2] = /*offset Z*/;
bulletData[PR_weaponId] = /*id da arma*/;
SendBulletData(0, 1, bulletData);
No exemplo acima, a função manda um pacote com dados de tiro para um jogador específico.
new BitStream:bs = BS_New(); - Criamos um BitStream, onde podemos escrever os dados do nosso pacote.
PR_UINT8, ID_BULLET_SYNC, - Primeiro parâmetro do bitstream. Este é o identificador do pacote (primeiros 8 bits).
PR_UINT16, from - Segundo parâmetro do bitstream. Este é o jogador responsável, de quem os dados de tiro vão originar.
BS_WriteBulletSync(bs, data); - "data" referência o enumerador PR_BulletSync, vamos escrever os dados no BitStream.
BS_Send(bs, to, PR_HIGH_PRIORITY, PR_RELIABLE_ORDERED); - "to" é o jogador que receberá o pacote. Mandamos o BitStream com os dados de pacote para este jogador. Se você mandar "to" como -1, todos os jogadores vão receber o pacote. PR_HIGH_PRIORITY é a prioridade do pacote, e PR_RELIABLE_ORDERED é sua confiabilidade.
BS_Delete(bs); - Removemos o BitStream após o uso.