C# 在使用浮点运算的多人RTS游戏中保持同步

C# 在使用浮点运算的多人RTS游戏中保持同步,c#,network-programming,floating-point,multiplayer,C#,Network Programming,Floating Point,Multiplayer,我正在用C#写一个2D空间RTS游戏。单人游戏有效。现在我想添加一些多人游戏功能。我在谷歌上搜索过,似乎只有一种方法可以让数千个单位在没有强大网络连接的情况下连续移动:只通过网络发送命令,同时对每个玩家运行相同的模拟 现在出现了一个问题,整个引擎在任何地方都使用双倍。浮点计算在很大程度上依赖于编译器优化和cpu体系结构,因此很难保持同步。 它根本不是基于网格的,它有一个简单的物理引擎来移动太空船(太空船有冲量和角动量…)。因此,使用定点重新编码整个内容将非常麻烦(但可能是唯一的解决方案) 到目前

我正在用C#写一个2D空间RTS游戏。单人游戏有效。现在我想添加一些多人游戏功能。我在谷歌上搜索过,似乎只有一种方法可以让数千个单位在没有强大网络连接的情况下连续移动:只通过网络发送命令,同时对每个玩家运行相同的模拟

现在出现了一个问题,整个引擎在任何地方都使用双倍。浮点计算在很大程度上依赖于编译器优化和cpu体系结构,因此很难保持同步。 它根本不是基于网格的,它有一个简单的物理引擎来移动太空船(太空船有冲量和角动量…)。因此,使用定点重新编码整个内容将非常麻烦(但可能是唯一的解决方案)

到目前为止,我有两个选择:

  • 对当前代码说再见,然后使用整数从头开始重新启动
  • 使游戏局域网只有在有足够的带宽,有8名球员与数以千计的单位,并发送位置和方向等在(几乎)每帧

因此,我正在寻找更好的意见(甚至是关于将代码迁移到定点而不弄乱一切的技巧…

当然,您的所有客户机都将使用相同的二进制文件,因此编译器优化对同步问题没有影响

此外,如果您只计划针对一个体系结构(或者至少只允许在同一体系结构上的人相互竞争),那么这也没关系

我在为iPhone和桌面开发游戏的C#中使用浮点做了完全相同的事情,它们都给出了相同的结果,尽管iPhone是ARM,桌面是x86

只要确保游戏进行完全相同的计算,你就会没事了


如果所有其他操作都失败,只需将游戏中所有的
float
实例替换为标准的定点算术类即可。通过这种方式,您可以100%确定您的计算是跨架构的确定性计算,尽管定点算法的性质可能会对您的游戏产生不利影响。

一种常见的技术是让所有客户端定期向其他客户端描述其当前状态


当两台计算机对一个对象的状态存在分歧时(可能是由于浮点错误),游戏会有一些规则来确定哪个是正确的,并且所有客户端都会调整以匹配它。

您使用double的具体目的是什么?你能用十进制吗

服务器通常会存储所有玩家单位的状态(位置/方位/类型)

当player1移动一个单位时 任何一个移动指令被发送到服务器 或更新后的状态将发送到服务器


当玩家客户端需要渲染场景时,服务器会发回请求范围内所有单位位置的状态信息。

我对此的响应有点晚,但从游戏安全的角度来看,模拟应该只在服务器/主机上运行(即:不信任客户端,他们可能会作弊):

  • 客户端应该只向服务器发送他们的动作/命令(服务器会丢弃错误的输入或将其限制在游戏限制内,因此说“我以10000m/s速度运行”的客户端会被服务器限制为10m/s)

  • 服务器/主机只告诉客户端在其视野范围内发生的事情(即:坐标为0,0的玩家如果只能看到其周围50个单位的半径,则不会被告知两个AI在200,0处相互争斗)

  • 这是节省带宽的第二个部分——服务器/主机上的模拟可能需要管理数千个对象,但客户端只需要知道他们自己视野内的大约100或200件事情

    这种情况下唯一的问题是动态射击(子弹、导弹等),其射程可能大于客户的视野半径。服务器/主机告诉客户机它们的原点和初始轨迹/目标对象,然后客户机根据相同的规则模拟它们的路径,但杀死仅在服务器/主机上的模拟中有效


    序列化特定于客户端的世界状态并在传输之前压缩它也可以是一个巨大的胜利,特别是如果您的类属性仅在需要时是公共的。(我通常避免使用XML,但我们在一个应用程序中通过序列化为XML并对其进行压缩,而不是序列化为二进制格式并对其进行压缩,从而显著提高了压缩比。我怀疑使用的ASCII字符的有限范围起了作用,YMMV。)

    是否每个玩家的计算机都必须模拟所有内容,或者仅仅是他们视野内的事物?他们必须模拟一切。正如他在原始帖子中所说,游戏状态将由数千个对象组成,使得整个状态同步不可行。我不知道有哪一款实时策略游戏使用这种方法——它们都是通过同步输入并确保模拟是确定性的来同步的。即使是完全相同的架构的两个实例也可能有不同的浮点结果,原因是FPU控制字、CPU指令根据管道使用情况重新排序、,我知道CPU会对指令进行重新排序,但我不相信它会对浮点运算的操作进行重新排序,从而打破确定性。它在某个地方读到浮点运算是不关联的(由于舍入),一个位的差异可能会导致失同步。即使是不同版本的.NET也可能有不同的JIT优化器,从而导致不同的结果。我不能要求我的用户使用.NET2.0(因为我希望它在Linux上也能与Mono一起使用)。因此,我决定创建一个定点类,并(几乎)用以下内容替换所有double:(他可能面临exactl