Comment puis-je attribuer des identifiants d'entité de manière robuste dans un jeu en réseau?

17

Je travaille sur un système d'entités pour un jeu en réseau et j'attribue à chaque entité un identifiant entier 32 bits unique que je peux utiliser pour sérialiser les références aux entités et aux entités elles-mêmes.

Actuellement, j'incrémente simplement un compteur chaque fois qu'une entité est créée. Je suppose que les identifiants finiront par manquer mais je ne m'attends pas vraiment à avoir 4 milliards d'entités. Cela évite également le problème si l'entité n ° 5 est détruite et que nous obtenons un identifiant de 5. Est-ce destiné à faire référence au nouveau n ° 5 ou à l'ancien n ° 5 supprimé?

Le problème est que je ne sais pas comment gérer / éviter les collisions. Actuellement, si un client reçoit une mise à jour pour une entité avec un identifiant supérieur à son "identifiant gratuit" actuel, il ne fait que dépasser son identifiant gratuit jusqu'au-delà. Mais cela ne semble pas très robuste.

J'ai pensé à peut-être attribuer des plages à chaque client afin qu'il puisse allouer des entités sans entrer en conflit (disons que les n premiers bits sont le numéro du joueur), mais je m'inquiète de ce qui se passe si les plages commencent à se chevaucher au fil du temps.

Existe-t-il une meilleure façon de gérer cela? Dois-je même me soucier des ID débordant ou dépassant la fin de la plage autorisée? Je pourrais ajouter du code pour détecter ces cas, mais que ferait-il s'ils se produisaient autre que le crash.

Une autre option consiste à utiliser quelque chose avec une plus grande chance d'être unique comme un GUID 128 bits, mais cela semble vraiment lourd pour un jeu qui essaie de minimiser le trafic réseau. De plus, de manière réaliste, je n'aurais jamais besoin de plus d'entités à la fois, puis je rentrerais dans un entier 32 bits ou même 24 bits.

Merci!

Lucas
la source
1
Pourquoi tous les clients n'ont-ils pas les mêmes entités? Les clients ne sont-ils pas synchronisés? Ou est-ce un grand monde en quelque sorte où les clients ne jouent pas tous le même jeu.
Philip
2
Jusqu'à présent, mon architecture suit vaguement celle de l'UE3 (plus d'informations ici ). Fondamentalement, les clients ne connaissent que les entités qui sont près d'eux dans le monde. De plus, les clients ne s'exécutent pas en étape de verrouillage, mais le serveur contrôle la majeure partie de la logique et peut remplacer les données client à tout moment. Je suppose que maintenant que j'y pense, je ne pouvais autoriser le serveur qu'à créer des entités et à faire en sorte que les clients utilisent RPC pour ce faire. Je ne suis pas sûr de la meilleure approche. Je suis un programmeur graphique de jour :)
Lucas
1
Je pense, comme vous le dites, que cela ne devrait être géré que par le serveur si cela est possible dans votre architecture. Gardez ensuite une pile d'ID d'entité libre qui existe séparément de la liste / carte d'entité, afin que vous sachiez quels ID sont disponibles. À défaut d'un modèle de serveur faisant autorité, votre approche à distance devrait fonctionner correctement, en termes de plages. Quatre milliards, c'est beaucoup, même à partager entre 4000 joueurs dans un MMO. Ensuite, utilisez la même approche pour garder une trace des ID disponibles qu'avec une authentification. serveur.
Ingénieur
@Lucas, votre lien dit "Le serveur identifie l'ensemble d'acteurs" pertinents "pour chaque client". Cela implique que le serveur connaît toutes les entités et est en mesure de les énumérer.
Kylotan
1
Bien sûr, mais que se passe-t-il si un client crée une nouvelle entité A mais avant qu'il ne puisse obtenir le message de création, le serveur crée une nouvelle entité B, ils reçoivent tous les deux le même identifiant "gratuit".
Lucas

Réponses:

13

Ce que j'ai fait, c'est que le serveur fasse tout . Le ou les clients peuvent simplement demander au serveur de faire quelque chose mais ne peuvent rien faire eux-mêmes. Dans ce cas, le serveur sera toujours celui qui attribue les ID et le problème est résolu.

Je n'ai pas traité de prédiction côté client en attendant que le serveur approuve des actions comme: "Tirer une fusée" ou "Faire une station solaire ici". Ces actions voudront créer des entités et les entités ont des ID. Jusqu'à présent, je suis juste assis sur mon pouce en attendant le serveur, mais je crois que ce qui doit être fait est de créer une entité temporaire pendant que vous attendez l'approbation du serveur. Lorsque vous recevez l'approbation du serveur, le serveur attribue un ID et vous pouvez soit mettre à jour, soit écraser l'objet temporaire.

Je n'ai pas non plus traité un débordement d'ID, mais si le serveur est en plein contrôle et qu'il détecte un débordement, il pourrait faire tout ce que vous jugerez nécessaire (redémarrer à 0, choisir dans une pile libre, planter, etc.) et tout le reste les clients ne savent même pas ou ne se soucient pas. Les clients n'accepteront que les identifiants remis par le serveur.

John McDonald
la source
Merci pour tous les bons gars info! J'ai fini par aller avec le serveur crée l'approche de toutes les entités, mais si je trouve que cela introduit trop de latence je vais essayer la méthode de Trevor.
Lucas
Pour les identifiants spécifiques au client (nécessaires pour la prédiction en attendant le serveur), vous pouvez simplement utiliser un préfixe sur l'identifiant.
danijar
6

Lorsque j'ai fait cela pour un jeu multijoueur commercial, j'ai fait exactement ce que vous proposez: utiliser un entier GUID 32 bits, où les huit premiers bits sont le numéro du joueur et les vingt-quatre bits inférieurs contiennent un numéro localement unique.

Si / lorsque le numéro local débordait (dans mon cas, cela ne se produirait presque jamais; en utilisation normale, il aurait fallu quatre à cinq jours de lecture continue dans une seule session réseau pour que cela se produise), le propriétaire enverrait un Message "Réinitialisation de tous mes objets" et renuméroter tous les objets encore existants à partir de zéro il y a. Le message disait à tous les pairs de jeter les objets qu'ils avaient reçus et de les interroger à nouveau.

Une approche plus sophistiquée serait un message "Objet avec GUID 'n' est maintenant Objet avec GUID 'm'" pour chaque objet existant. Mais dans mon cas, il était peu probable que cela se produise réellement, et je ne pensais pas que les gens se soucieraient vraiment des objets distants disparaissant du monde pendant une demi-seconde, après cinq jours de jeu sans arrêt dans une seule session réseau. ;)

Trevor Powell
la source
C'est une bonne idée pour gérer le débordement. Simple, mais je n'y ai pas pensé :). "Oublier" toutes vos entités est agréable car il peut essentiellement réutiliser le même chemin de code que le client utilise lorsqu'il rejoint le jeu
Lucas
4

Si vos clients peuvent créer leurs propres entités, je suppose que vous avez un jeu multijoueur peer-to-peer.

Si c'est le cas, vous n'avez probablement pas trop de clients. Certainement pas plus de 256. Et votre identifiant d'entité est garanti pour tenir en 24 bits (16000000+ entités suffisent pour tout le monde!). Donc, faites juste l'octet le plus élevé de votre identifiant égal à l'identifiant du client:

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

ou quelque chose.

Et si je me trompe et que vous avez un serveur faisant autorité, ne créez jamais de nouvelles entités sur les clients.

Ça ne fait rien
la source
1

J'utilise la méthode «la plus naïve» (juste incrémenter un entier pour chaque nouvel ID) dans mon jeu multijoueur persistant et cela fonctionne très bien parce que je ne laisse pas le client créer un nouvel ID: s.

Si vous laissez le client décider (en utilisant une sorte de technique GUID expliquée), le client peut également introduire divers bogues en attribuant un ancien ID à un nouvel élément (c'est exactement ce que j'ai pensé au-dessus de ma tête en pensant à 5 secondes , il peut y avoir des tas d'autres failles).

Comme d'habitude, pour éviter la triche , le serveur doit faire TOUTE la création et la validation .

Valmond
la source