如何在客户端 - 服务器应用程序中同步客户端和服务器端的同一对象?小消息框架是否适合这项工作?

时间:2021-07-09 15:28:27

I'm making a game engine in c++ and python. I'm using OGRE for 3D rendering, OpenAL for sound, ODE for physics, OIS for input, HawkNL for networking and boost.python for embedded python interpreter. Every subsystem (library) is wrapped by a class - manager and every manager is singleton. Now, I have a class - Object - this could be every visible object in game world. This is some kind of mix, object has graphics representation (entity) and representation in physics simulator (solid). These two are most important here. Class Object is just pure abstract base class - interface. I've decided to implement Object on client side as ObjectClientSide - this implementation has the entity, and on server side as ObjectServerSide - this implementation has the solid. Physics simulator runs only on server, and rendering is done only on client of course. The object can exist only when both implementations are working together. Every object has unique id and both instances of the same object on client and server side have the same id.

我正在使用c ++和python制作游戏引擎。我正在使用OGRE进行3D渲染,OpenAL用于声音,ODE用于物理,OIS用于输入,HawkNL用于网络,boost.python用于嵌入式python解释器。每个子系统(库)都由一个类 - 管理器包装,每个管理器都是单例。现在,我有一个类 - 对象 - 这可能是游戏世界中的每个可见对象。这是某种混合,对象具有图形表示(实体)和物理模拟器中的表示(实体)。这两个在这里最重要。 Class Object只是纯粹的抽象基类 - 接口。我决定在客户端实现Object作为ObjectClientSide - 这个实现有实体,在服务器端有ObjectServerSide - 这个实现有实体。物理模拟器仅在服务器上运行,并且渲染仅在客户端上完成。只有当两个实现一起工作时,该对象才能存在。每个对象都有唯一的id,客户端和服务器端的同一对象的两个实例都具有相同的id。

So, after this short background, my first question is: is this design good? How can I make it better? And the main question: how should I synchronize these objects?

所以,在这短暂的背景之后,我的第一个问题是:这个设计好吗?我怎样才能让它变得更好?主要问题是:我应该如何同步这些对象?

Next, both implementations have the same interface, but part of it is implemented on server side and part on client side. So, for example, if player wants to move forward his character he should send a request to object on server. The server then makes changes to simulation and sends updated position to client. For that reason, I've created small messages framework. There is a Message class, Router, Rule and rules inherited from Rule. When message arrives, Router checks it against the rules and sends it to destination. So, when I call myObjectInstanceOnClientSide->setPosition(x,y,z) this object creates Message, its content is function and parameters and destination is object with the same id on server. When object with the same id on server side gets this message it calls this function with given arguments. So, when a function can't be implemented on one side it creates a message and sends it to object on the other side. I think this can be very useful in scripts. Scripts can be very clean, if script needs for example turn on animation on clients, I only need to call this function on server's local object - the rest is in background.

接下来,两个实现都具有相同的接口,但其中一部分在服务器端实现,部分在客户端实现。因此,例如,如果玩家想要向前移动他的角色,他应该向服务器上的对象发送请求。然后,服务器对模拟进行更改,并将更新的位置发送给客户端。出于这个原因,我创建了小消息框架。从Rule继承的Message类,路由器,规则和规则。当消息到达时,路由器会根据规则对其进行检查并将其发送到目的地。因此,当我调用myObjectInstanceOnClientSide-> setPosition(x,y,z)时,此对象创建Message,其内容为function,参数和destination是服务器上具有相同id的对象。当服务器端具有相同id的对象获得此消息时,它将使用给定的参数调用此函数。因此,当一个函数无法在一侧实现时,它会创建一条消息并将其发送到另一侧的对象。我认为这在脚本中非常有用。脚本可以非常干净,如果脚本需要打开客户端上的动画,我只需要在服务器的本地对象上调用此函数 - 其余部分在后台。

So, is this ok? Am I wrong about this? It this common solution?

那么,这样可以吗?我错了吗?这个常见的解决方案?

1 个解决方案

#1


It sounds like you would be sending a lot of tiny messages. The UDP and IP headers will add 28 bytes of overhead (20 bytes for the IPv4 header or 40 for IPv6 plus 8 bytes for the UDP header). So, I would suggest combining multiple messages to be dispatched together at a perioidic rate.

听起来你会发送很多小信息。 UDP和IP头将增加28字节的开销(IPv4标头为20字节,IPv6为40字节,UDP标头为8字节)。因此,我建议将多个消息组合在一起以perioidic速率发送。

You may also want to read these other questions and answers:

您可能还想阅读以下其他问题和答案:

I added a bunch of useful links to the DevMaster.net Wiki years ago that are still relavent:

我在几年前添加了一些有用的链接到DevMaster.net Wiki仍然相关:

I'd suggest starting to read Glenn Fiedler's blog. He's done some incredibly work with networked physics including the recent Mercenaries 2 release. He started a series of articles called Networking for Game Programmers.

我建议开始阅读Glenn Fiedler的博客。他在网络物理方面做了一些令人难以置信的工作,包括最近的Mercenaries 2版本。他开设了一系列名为Networking for Game Programmers的文章。

#1


It sounds like you would be sending a lot of tiny messages. The UDP and IP headers will add 28 bytes of overhead (20 bytes for the IPv4 header or 40 for IPv6 plus 8 bytes for the UDP header). So, I would suggest combining multiple messages to be dispatched together at a perioidic rate.

听起来你会发送很多小信息。 UDP和IP头将增加28字节的开销(IPv4标头为20字节,IPv6为40字节,UDP标头为8字节)。因此,我建议将多个消息组合在一起以perioidic速率发送。

You may also want to read these other questions and answers:

您可能还想阅读以下其他问题和答案:

I added a bunch of useful links to the DevMaster.net Wiki years ago that are still relavent:

我在几年前添加了一些有用的链接到DevMaster.net Wiki仍然相关:

I'd suggest starting to read Glenn Fiedler's blog. He's done some incredibly work with networked physics including the recent Mercenaries 2 release. He started a series of articles called Networking for Game Programmers.

我建议开始阅读Glenn Fiedler的博客。他在网络物理方面做了一些令人难以置信的工作,包括最近的Mercenaries 2版本。他开设了一系列名为Networking for Game Programmers的文章。