RakNet学习(2)-- 多人游戏组件

来源:互联网 发布:caffe 添加数据层 编辑:程序博客网 时间:2024/04/28 00:00

多人游戏组件

组成多人游戏的主要系统

       多人使得游戏比单人游戏需要更多系统或者额外设计考虑。按照如下的类别进行列举,带着这些问题解决的方法,以及每一个系统的优缺点。尽管在每个部分的结尾处列举的是RakNet的解决方案,这一页的内容适合于所有的多人游戏,不仅仅是使用RakNet的这些游戏。

发现其的程序

       直接的IP输入

       最古老也是最简单的方法,直接键入要连接的用户的IP地址。远端的用户可以登录网页,例如http://www.whatismyip.com/ 来获取IP地址。然后他们可以通过其他的方法例如邮件或即时通信来交换各自的IP地址。如果远端的IP地址在路由之后,就需要打开防火墙上适当的端口接收连接。如果IP地址位于防火墙后面,那么就需要配置防火墙。

      DNS接入

      用于客户端/服务器模式中控制服务器,可以获得一个到服务器的DNS一条内容。连接的客户端可以连接到DNS服务器,而不用直接输入固定IP地址。如果服务器的IP地址有可能变化时,这种方法比较方便。这种服务是通过http://www.dyndns.com/ 免费提供的。RakNet也提供了一个类实现更新动态的DNS,代码位于Source/DynDNS.h和Source/DynDNS.cpp。这种方式通常用于你自己管理自己服务器的客户端/服务器模式游戏中。

      LAN Broadcast

      如果电脑位于同一个LAN,可以通过发送数据包到IP地址255.255.255.255来发现这个计算机,端口要选择远端系统正在监听的端口号。远端系统接收到该数据包之后,会返回一个响应包。RakNet通过Ping()和AdvertiseSystem()函数来实现这个功能。

      Rooms Server

      更加成熟的游戏使用房间系统来让用户寻找其他的用户。服务器会包含一个房间列表,每一个房间内包含了玩家列表。玩家连接到服务器,搜索并加入到房间,通过这个系统开始游戏。服务器负责存储每一个玩家的IP地址,以及传输数据到每一个玩家。在PC机上RakNet通过RoomsPlugin插件提供这项服务,在Steam上通过SteamLobby插件来提供,相当于XBOX和SP3上各自相应的lobby类。这些通常用于端到端的游戏,在端到端的游戏中,在游戏开始之前玩家有很多的交互。

       目录服务器

       类似于房间服务器,目录服务器是维护了运行的游戏列表的服务器。典型地,在终端用户启动了游戏,他们会将游戏的统计数据发送到目录服务器。目录服务器保存了运行游戏的IP地址,游戏统计数据,并且允许游戏客户端下载正在运行游戏的列表。客户端会局部地连接到服务器加入到正在进行的游戏中。这种方法通常用于玩家自己维护服务器的情况。RakNet提供了CloudServer/CloudClient Projects来实现这种功能。

 

网络拓扑

       客户端/服务器 游戏运营商管理主机

       通常用于大规模的多玩家游戏,你可以管理一个或多个服务器,这些服务器包含了提供给玩家的游戏。这当然也是最昂贵的解决方案,需要专门服务器保证上线时间,以及支付昂贵的带宽费用。许多公司提供这种服务器,包括http://www.dx.net/raknet_dx.phps。

       客户端/服务器 玩家管理主机

       这种方式下,如果服务器挂掉了,那么游戏也挂掉了。尽管这样,它还是比较常见的模式,它有如下的一些优点:

       1. 易于编程,一个单系统就可以解决玩家之间的争论。

       2. 可以支撑更多数量玩家,专用服务器具有高带宽能力。

       3. 更加适宜于长时间的游戏会话,因为专用服务器很少Down掉或引起问题

       4. 专用服务器可以在全世界进行部署,ping值较低

       使用终端用户当做主机也可以实现客户端/服务器模式,但是这样仅仅有容易变成的好处,其他的一些优点都无法获得。

 

       端到端

       这种拓扑用于不太正式的游戏,通常没有专用服务器。这个对于控制台游戏是更加普遍的拓扑,因为控制台不需要专门的服务器,唯一的优点也是不需要专用的服务器。缺点就比较多了:

       1. 需要某种服务器来发现运行的游戏会话,也即寻找正在进行的游戏

       2. 需要穿透路由

       3. 需要处理主机转移

       4. 需要处理冲突,也就是说如果两个对等端同时做了同样的执行操作,如何解决?

RakNet提供了一些插件使得P2P编程更加简单:NATPunchthrough,ReadyEvent,ConnectionGraph2, FullyConnectedMesh2,以及TeamBalancer。

 

游戏和连网后的游戏设计变化

       游戏等级加载

       与单个玩家的游戏不同,并不是在游戏开始时将所有本级的游戏对象加载,对象在现在的多玩家游戏中根据它们对网络的影响进行了分类。

       1. 正常加载的对象是那些总存在于该层,并且网络相关代码不会使用的对象。

       2. 依然与游戏级别一起加载的对象,但是网络代码会访问到它。例如,扳机。这些对象或者使用网络ID(64位的GUID)加载,或代码在加载时可以收集这些类对象并给他们赋予ID值。

       3. 游戏级别中存在或不存在的对象需要动态加载。例如,玩家,出现的武器,以及子弹。有些对象是需要在游戏级别加载时进行加载的,按照假设他们会最终引出,避免运行时的硬驱动访问。

       许多游戏有一组的玩家在同一个时间同时开始。这种情况下,级别在加载完成后不应该立即开始。在考虑级别加载完成之前:

       1. 从影响我们加载状态的其他用户传送选择。例如,其他用户选择的角色模型。警匪类游戏中,一方选择警,会影响到另外一方的角色选择。

       2. 加载级别场景,同时也加载基于其他玩家选择需要加载的任何的模型或地图。

       3. 保持中断界面,一直到所有的玩家也开始加载为止。ReadyEvent可以在此处使用。

       游戏中场加入也是相同的,除了跳过加载中断画面之外的所有情况。如果游戏会话结束了,你的游戏仍旧在加载,需要结束到加载,并且进入到任何游戏结束时的中断状态。

 

游戏对象

       游戏对象是网络化的,需要实现一个借口来支持ReplicaManager3:

1.对象必须可以返回一个标识符来指明该对象所属的类。例如ENUM_BULLET或“CBullet”用于标识一个子弹。

       2. 对象在给定了标识符和初始化数据后必须是可以实例化。有时这通过类工厂实现。

       3. 对象应该实现一个接口,使得他们可以序列化数据来进行构造,销毁,以及每个时间下的数据序列化。

       4. 在拥有该对象的玩家离开游戏会话后,游戏对象必须销毁。例如远端用户的化身需要销毁,但是不能结束本地的游戏会话。

       主机或其他的用户拥有游戏对象或许需要支持一个半交互的“鬼魂状态”,在这个状态下的对象已经进行渲染,且有生命的。但是有物理学中的残疾(不足),并且没有触发活动 (此处不知道如何理解更适合,如果有人知道欢迎告诉我)。然而:

1.       半交互的“鬼魂对象”或许仍然引起声音,例如在玻璃上的脚步声

2.       半交互的“鬼魂对象”也会引发视觉的影响触发。

一个对象是否是完全交互状态,取决于是否一个主机需要解决冲突。在游戏世界中,从带宽和游戏设置考虑,对象需要相应分类。

1. 对象仅仅在主机上是完全交互的,例如触发器在某些方式下会影响游戏设置。

       2. 对象在所有系统中是完全可交互的,例如触发器扮演小量的影响

       3. 对象仅仅在拥有它的主机上是完全可交互的,例如有自己的化身。

主机迁移

       如果每一个系统都有所有系统的完整状态信息,那么主机迁移就不必要了。来自FullyConnectedMesh2的主机更换信息中,只是简单延迟那个系统。否则需要实现主机迁移的UI。

       1. 停止游戏

       2. 传输主机迁移数据

       3. 当所有用户准备好后,使用ReadyEvent来继续游戏

 

用户

       需要实现一个用户类,包含了一些信息,例如分数,名字,用户ID,成绩等等。一些游戏在同一个系统上支持多用户,例如将屏幕分片进行的游戏。

 

远端系统

       远端系统类需要实现,它包涵了等级加载状态或用于欺骗检测的可信尺度。如果游戏在每一个系统上仅仅支持一个用户,这个类通常合并到用户类中。

 

团队

       如果游戏支持团队,这个需要序列化,包括玩家,团队分数等等。团队平衡可以使用TeamBalancer 插件实现。

 

世界/游戏状态

并不是所有信息都是游戏对象必须携带的,例如比赛倒计时。可以使用Replica3展现,或直接通过网络消息进行更新。

 

升级

       当主机决定了这一级别游戏结束,需要升级,游戏需要具备停止游戏设置,通知所有玩家,并且展示某种游戏结束得分屏幕。在这期间,游戏分数更新应该停止,其他游戏事件也应该停止。如果会话统计要传输到服务器,那么可以在这个时间完成。

 

重放

       一些游戏可以让用户从几个固定的摄像机点,其他玩家的视角观察游戏,或在死后回放游戏。

 

上传游戏数据和UI

       一个游戏会话结束,在进入更高等级时,会出现一系列UI的屏幕显示,包括成绩,得分等。之后,游戏或者回退到游戏浏览窗口,或停留在你先前公共游戏的玩家一起的房间。

 

补丁升级

       基于补丁升级的每个文件的不同

       给用户升级的嘴高级但是最耗费时间的方法就是找到用户拥有文件和现有文件版本之间的差异。在这些环境下,只需发送最少的数据来升级用户文件。如果补丁失败(例如文件版本未知),则需要传输整个文件。补丁系统的一个数据库需要用于维护这些情况,因为在运行时生成这些补丁是最耗费时间的。

       RakNet提供了AutopatcherServer和AutopatcherClient 插件作为一个差异化升级的补丁系统。

每个文件补丁升级

       打补丁的最简单的方法是找到一个变化或丢失的文件的列表,仅仅给客户端发送这些文件。这个系统的优势是它可以用于终端用户作为游戏服务器的情况。例如,如果游戏服务器有一个地图或皮肤,在一个连接的客户端上没有,那么在开始游戏之前就可以下载这个文件。

       RakNet提供了FileListTransfer插件来传输文件列表,使用DirectoryDeltaTransfer插件来传输列表中的变化或丢失的文件。

 

调试

日志

       多玩家游戏很难调试,因为一个Bug可以在两个系统之间传播。例如系统A执行了一个动作,但是系统B没有看到它,或看到的动作是不同的。这样的bug可能是由于延迟造成的,只是在某些加载中才会出现。性能或其他的问题可能随着应用规模的扩大而出现。然而日志可以帮助解决所有这些问题,由于系统时间的不同使得它们很难协作起来。

       RakNet提供了两个日志解决方案。第一个称为SQLite3LoggerPlugin,它是基于一个主机服务器的SQLIte3数据库的,所有的日志全部放到一个服务器上,是自动进行关联的。日志可以让支持SQLite的观察者看到,因此RakNet也提供了一个免费开源的用户观察器,称为EchoChamer。单个游戏和链接消息可以使用PakcetLogger插件在每个系统中进行记录。

 

Minidump

       因为崩溃很难再现,窗口程序可以生成minidump文件。如果你知道了那个版本的代码产生了崩溃,你就可以调试这个崩溃情况,这个你在那时候通过一个调试器链接调试是一样的效果。

       RakNet提供了CrashReporter系统使得崩溃记录与报告更加简单。它还提供了一些额外的功能,例如在服务器没有人照看的情况下发送邮件给开发者。

 

游戏大厅和持久数据

用户数据持久化

       游戏保存的数据不仅仅是一次会话的,这样就需要一个专门系统用于创建用户账户。用户的账户可以存储一些用户信息,例如游戏统计数据,名字,logo。用户可以有游戏部族的好友,实现其他的社会任务。为了写这样一个系统,需要一个持久服务器运行数据库来存储这些数据。但是用户不能随意向数据库发送任意的查询,因此服务器需要编码来形成基于用户输入的一些查询功能。

       Raknet 提供了一个系统,LbbyServer 和LobbyClient,为PC提供各种功能。Steam,PS3和XBOX已经在他们自己的备份上存储了这个。这些情况下,RakNet使用相同的LobbyClient接口,这样可以向所有的系统提供统一的接口。

      

安全

       流行的复杂游戏会吸引一些作弊者。作弊者可以通过如下手段攻击游戏:

       1. 修改EXE发送未授权的数据(发送kill消息)

       2. 修改EXE查看额外的数据(穿墙查看)

       3. 修改传输中的数据报来改变发送数据

       4. 重放数据报来模拟登录或游戏事件(运行攻击机器人)

       5. 引入延迟获取完全的优势

       明智的做法是如果有可能,游戏应该验证所有的输入。即使欺骗不是攻击的考虑也应该做这些工作,因为延迟也会引起不同寻常的输入。

 

RakNet可以使用安全连接技术的支持来抵制3号和4号攻击。用于防止PC机上的EXE被修改的解决方案也因该存在。基于欺骗的针对延迟保护措施仅仅采取了较为智能的设计,例如不能相信client/peer输入。

 

 

注:这个完全翻译有些麻烦,还是从实用出发,翻译一部分,按照自己理解写一部分,加上程序调试说明。学习RakNet的最终目的还是进行应用,因此还是以应用为出发点,加上部分原文翻译。

0 0
原创粉丝点击