Como atribuir IDs de entidade de maneira robusta em um jogo em rede?

17

Estou trabalhando em um sistema de entidades para um jogo em rede e atribuindo a cada entidade um ID inteiro de 32 bits exclusivo que posso usar para serializar referências a entidades e às próprias entidades.

Atualmente, estou apenas incrementando um contador toda vez que uma entidade é criada. Acho que os IDs acabarão, mas não espero ter 4 bilhões de entidades. Isso também evita o problema se a entidade nº 5 for destruída e obtivermos um ID igual a 5. Ele deve se referir ao novo nº 5 ou ao antigo nº 5 excluído?

O problema é que não tenho certeza de como lidar com / evitar colisões. Atualmente, se um cliente recebe uma atualização para uma entidade com um ID maior que o "ID gratuito" atual, ele apenas esbarra no ID gratuito. Mas isso não parece muito robusto.

Pensei em talvez atribuir intervalos a cada cliente para que eles possam alocar entidades sem conflitar (digamos que os n bits superiores sejam o número do jogador), mas estou preocupado com o que acontece se os intervalos começarem a se sobrepor ao longo do tempo.

Existe uma maneira melhor de lidar com isso? Devo me preocupar com ids transbordando ou ultrapassando o final do intervalo permitido? Eu poderia adicionar código para detectar esses casos, mas o que faria se eles acontecessem além da falha.

Outra opção é usar algo com maior chance de ser único, como um GUID de 128 bits, mas que parece realmente pesado para um jogo que está tentando minimizar o tráfego de rede. Além disso, realisticamente, eu nunca precisaria de mais entidades ao mesmo tempo, então caberia em um número inteiro de 32 bits ou mesmo 24 bits.

Obrigado!

Lucas
fonte
1
Por que nem todos os clientes têm as mesmas entidades? Os clientes não são sincronizados? Ou é um tipo de mundo grande, onde os clientes nem todos executam o mesmo jogo.
Philip
2
Até agora, minha arquitetura segue um pouco a UE3 (mais informações aqui ). Basicamente, os clientes conhecem apenas entidades que estão próximas a eles no mundo. Além disso, os clientes não são executados na etapa de bloqueio, mas o servidor controla a maior parte da lógica e pode substituir os dados do cliente a qualquer momento. Acho que agora que penso nisso, só podia permitir que o servidor criasse entidades e fizesse com que os clientes usassem o RPC para fazer isso. Não tenho certeza da melhor abordagem. Eu sou um programador de gráficos por dia :)
Lucas
1
Eu acho que, como você diz, deve ser tratado apenas pelo servidor, se isso for possível dentro de sua arquitetura. Em seguida, mantenha uma pilha de IDs de entidade gratuitos que existam separados da lista / mapa de entidades, para que você saiba quais IDs estão disponíveis. Na falta de um modelo de servidor autorizado, sua abordagem à distância deve funcionar bem, em termos de intervalos. Quatro bilhões é muito, mesmo para dividir entre 4000 jogadores em um MMO. Em seguida, use a mesma abordagem para acompanhar os IDs disponíveis como em uma autenticação. servidor.
Engenheiro de
@ Lucas, seu link diz "O servidor identifica o conjunto de atores" relevantes "para cada cliente". Isso implica que o servidor conhece todas as entidades e está em posição de enumerá-las.
Kylotan
1
Claro, mas e se um cliente cria uma nova entidade A, mas antes que ele possa receber a mensagem de criação, o servidor cria uma nova entidade B, ambos recebem o mesmo ID "gratuito".
Lucas

Respostas:

13

O que eu fiz foi fazer o servidor fazer tudo . O (s) cliente (s) pode apenas pedir ao servidor para fazer alguma coisa, mas não pode fazer nada sozinho. Nesse caso, o servidor sempre atribuirá IDs e o problema será resolvido.

Não lidei com a previsão do lado do cliente enquanto esperava o servidor aprovar ações como: "Disparar um foguete" ou "Fazer uma estação solar aqui". Essas ações desejam criar entidades, e as entidades têm IDs. Até o momento, estou apenas aguardando pelo servidor, mas acredito que o que precisa ser feito é criar uma entidade temporária enquanto você aguarda a aprovação do servidor. Quando você recebe a aprovação do servidor, o servidor atribui um ID e você pode atualizar ou substituir o objeto temporário.

Eu também não lidei com um estouro de ID, mas se o servidor estiver no controle total e detectar um estouro, ele poderá fazer o que você achar necessário (reinicie em 0, escolha entre uma pilha livre, falha, etc.) e todos os clientes nem sabem ou se importam. Os clientes aceitarão apenas os IDs distribuídos pelo servidor.

John McDonald
fonte
Obrigado por todas as boas informações pessoal! Acabei indo com o servidor cria uma abordagem de todas as entidades, mas se eu achar que isso introduz muita latência, tentarei o método de Trevor.
Lucas
Para identificações específicas do cliente (necessárias para previsão enquanto aguarda o servidor), você pode simplesmente usar um prefixo na identificação.
31512 danijar
6

Quando fiz isso para um jogo multiplayer comercial, fiz exatamente o que você propõe: use um inteiro GUID de 32 bits, onde os oito bits principais são o número do jogador e os vinte e quatro bits inferiores contêm um número localmente único.

Se / quando o número local estourar (no meu caso, quase nunca aconteceria; sob uso normal, levaria quatro a cinco dias de reprodução contínua em uma única sessão de rede para que isso acontecesse), o proprietário enviaria uma Mensagem "Redefinindo todos os meus objetos" e renumerar todos os objetos ainda existentes a partir de zero atrás. A mensagem dizia a todos os colegas para descartar os objetos que haviam recebido e consultá-los novamente.

Uma abordagem mais sofisticada seria a mensagem "Objeto com GUID 'n' agora é Objeto com GUID 'm'" para cada objeto existente. Mas no meu caso, era improvável que isso realmente acontecesse, e eu não achava que as pessoas realmente se importariam com objetos remotos desaparecendo do mundo por meio segundo, depois de cinco dias de reprodução sem parar em uma única sessão de rede. ;)

Trevor Powell
fonte
É uma boa ideia para lidar com o estouro. Simples, mas não pensei nisso :). "Esquecer" todas as suas entidades é bom, uma vez que basicamente pode reutilizar o mesmo codepath os usos cliente quando ele entra no jogo
Lucas
4

Se seus clientes podem gerar suas próprias entidades, suponho que você tenha um jogo multiplayer ponto a ponto.

Se for esse o caso, você provavelmente não tem muitos clientes. Certamente não mais que 256. E seu ID de entidade é garantido para caber em 24 bits (16000000+ entidades são suficientes para todos!). Portanto, apenas faça o byte mais alto do seu ID igual ao do cliente:

entityId = clientId<<24 + (maxEntityIn++)

ou alguma coisa.

E se eu estiver errado e você tiver um servidor autorizado, nunca crie novas entidades nos clientes.

deixa pra lá
fonte
1

Estou usando o método 'mais ingênuo' (apenas incremente um número inteiro para cada novo ID) no meu jogo multiplayer persistente e funciona bem porque não deixo o cliente criar novos ID: s.

Se você deixar o cliente decidir (usando uma espécie de técnica GUID explicada), o cliente também poderá introduzir vários erros atribuindo um ID antigo a um novo item (isso é exatamente o que eu pensei em cima da minha cabeça pensando em 5 segundos , pode haver muitas outras brechas).

Como de costume, para evitar trapaças , o servidor deve criar e validar TODAS as informações .

Valmond
fonte