如何在网络游戏中以可靠的方式分配实体ID?


17

我正在为网络游戏开发一个实体系统,并为每个实体分配一个唯一的32位整数ID,该ID可用于序列化对实体和实体本身的引用。

目前,我只是在每次创建实体时增加一个计数器。我想这些ID最终会用完,但我并不真正希望拥有40亿个实体。如果实体#5被销毁并且我们获得ID为5,这也避免了问题。这是指引用新的#5还是旧的已删除的#5?

问题是我不确定如何处理/避免冲突。当前,如果客户收到一个ID高于其当前“免费ID”的实体的更新,则该客户的免费ID会超过该值。但这似乎不是很可靠。

我考虑过为每个客户端分配范围,以便他们可以分配实体而不会发生冲突(例如,前n位是玩家编号),但是我担心如果范围随时间开始重叠会发生什么情况。

有没有更好的方法来解决这个问题?我是否应该担心ID溢出或超出允许范围的末尾?我可以添加代码来检测这些情况,但是如果发生这些情况而不是崩溃,该怎么办。

另一种选择是使用具有更高独特性的功能,例如128位GUID,但对于试图最小化网络流量的游戏而言,这似乎是重量级的。而且,实际上,我永远不会一次需要更多实体,而是适合一个32位甚至24位整数。

谢谢!


1
为什么不是所有客户都有相同的实体?客户端不同步吗?还是这是一个大型世界,其中的客户不一定都在玩同一款游戏。
菲利普(Philip)

2
到目前为止,我的体系结构大致遵循UE3的体系结构(此处有更多信息)。基本上,客户只知道世界上附近的实体。同样,客户端不是以锁步方式运行,而是服务器控制大多数逻辑,并且可以随时覆盖客户端数据。我现在想,我只能允许服务器创建实体并让客户端使用RPC来执行此操作。我不确定最好的方法。我今天是图形程序员:)
卢卡斯

1
我认为,正如您所说,只有在给定架构内完全可行的情况下,才应由服务器处理。然后保留一堆与实体列表/映射分开存在的免费实体ID,以便您知道可用的ID。如果没有权威的服务器模型,那么就范围而言,您的远程方法应该可以正常工作。40亿甚至很多,甚至可以分配到MMO中的4000名玩家中。然后使用与auth相同的方法来跟踪可用的ID。服务器。
工程师

@Lucas,您的链接显示“服务器为每个客户端标识“相关” Actor的集合”。这意味着服务器知道所有实体,并且可以枚举它们。
Kylotan

1
当然可以,但是如果客户端创建了新的实体A,但是在服务器获得新的创建消息之前,服务器创建了新的实体B,则它们都被分配了相同的“免费” id。
卢卡斯

Answers:


13

我所做的就是使服务器执行所有操作。客户端只能要求服务器做某事,但自己不能做任何事。在这种情况下,服务器将始终是分配ID的服务器,并且可以解决问题。

在等待服务器批准诸如“向火箭射击”或“在此处建立太阳能站”之类的操作时,我尚未处理客户端预测。这些操作将要创建实体,并且实体具有ID。到目前为止,我只是坐在拇指上等待服务器,但是我认为需要做的是在等待服务器批准的同时创建一个临时实体。收到服务器批准后,服务器将分配一个ID,您可以更新或覆盖临时对象。

我也没有处理过ID溢出问题,但是如果服务器处于完全控制状态并且检测到溢出,它可以执行您认为必要的任何处理(从0重新启动,从可用堆栈中选择,崩溃等)以及所有客户甚至都不知道或不在乎。客户端将只接受服务器发出的ID。


感谢所有优秀的信息专家!我最终使用服务器创建所有实体的方法,但是如果发现引入了太多的延迟,我将尝试Trevor的方法。
卢卡斯

对于客户端特定的ID(在等待服务器时需要进行预测),您只需在ID上使用前缀即可。
danijar

6

在为商用多人游戏进行此操作时,我完全按照您的建议进行操作:使用32位GUID整数,其中前八位是玩家编号,后二十四位包含本地唯一编号。

如果/当本地号码溢出时(在我的情况下,这几乎不会发生;在正常使用情况下,在单个网络会话中要花四到五天的连续播放时间才能使它发生),所有者将发送一个消息“正在重置我的所有对象”,并从零开始重新编号所有仍存在的对象。该消息告诉所有对等端丢弃他们收到的对象并再次查询。

更为花哨的方法是对每个现有对象发出“ GUID为'n'的对象现在为GUID为'm'的对象”消息。但就我而言,这不太可能真正发生,而且我不认为人们会在一个网络会话中连续玩了五天之后就真的不介意远程对象从世界上消失了半秒钟。;)


这是处理溢出的好主意。很简单,但是我没想到:)。“忘记”您的所有实体都是不错的选择,因为它基本上可以重用客户端加入游戏时客户端使用的相同代码路径
Lucas

4

如果您的客户可以生成自己的实体,那么我猜您有一个点对点的多人游戏。

如果是这样,您可能没有太多的客户。当然不超过256个。并且您的实体ID保证可以容纳24位(16000000+个实体对每个人都足够!)。因此,只需使您ID的最高字节等于客户ID:

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

或者其他的东西。

如果我错了,并且您拥有权威服务器,则永远不要在客户端上创建新实体。


1

我在我的持久多人游戏中使用的是“最幼稚”的方法(只需为每个新ID增加一个整数),它就可以正常工作,因为我不允许客户端创建新ID:s。

如果让客户决定(通过使用所解释的某种GUID技术),客户还可以通过将旧ID分配给新项目来引入各种错误(这就是我想到的大概5秒钟的想法) ,可能还会有其他漏洞的负载)。

像往常一样,为防止作弊,服务器应执行ALL创建和验证

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.