一、作者简介
裴玄机。
开发游戏服务器和网络引擎“ProudNet”。 ProudNet已为超过200家游戏开发商提供并持续提供技术支持。 韩国最著名的游戏服务器开发商之一。
2. 开始
世界上有许多用于游戏开发的服务器和网络库。 我将这些统称为服务器引擎。 服务器引擎由服务器端模块和网络客户端模块组成。
有大量的开源代码,还有商业软件,这是需要购买的产品。 但大多数用户使用开源。 它不仅是免费的开发学习,而且它的源代码是公开的,因此没有任何限制。 但商业引擎也有其优点,那就是与开源不同,一旦出现问题,用户不需要自己解决所有问题。
使用商业引擎,游戏开发者可以更轻松地解决用钱买时间的问题。 对于像我这样供应商用发动机的人来说,情况恰恰相反。 开发游戏服务器和上线网络游戏时会出现很多问题。 解决这些问题需要时间。 有些简单的问题五分钟就可以解决,但也有半个月解决不了的问题,甚至有需要飞到现场查看的情况。
解决问题的过程固然是困难的,但是在解决这些问题的过程中却可以积累相当多的经验。 我从1995年开始在一家游戏公司担任游戏开发人员,直到2004年,开发了多款网络游戏,这13年里积累了相当多的经验。 但2008年到2016年间通过游戏服务器引擎开发、维护和问题解决所获得的经验恐怕比过去13年多了好几倍。
在这里,我想根据我目前积累的经验,分享一些可能对大家有所帮助的见解。
基于ProudNet的手机RPG游戏MARVEL FUTURE FIGHT
3.自动生成数据包发送和接收代码
我从 1997 年开始开发游戏服务器。值得夸耀的是,我是最早在 Windows NT 中通过 IOCP 开发游戏服务器的人之一。 当时开发游戏服务器过程中的难点之一就是数据包的发送和接收过程需要一一编码。
将数据包的发送和接收过程一一编码不仅不方便,而且还可能导致错误。 请看下面的代码。
数据发送端正在发送x,y,z,但接收端只提取x,z。 肯定会有问题。 如果程序很简单,就没有人会犯这个错误。 但如果程序变大,很多人调整的话,那就不一样了。
如何解决这个问题呢? 只需将数据包的发送和接收部分的代码交给机器进行编码即可。
假设您正在编写用于发送和接收角色移动和攻击信息的代码。 为了让机器为您编码手机游戏服务端开发3D角色,您需要定义以下函数。
通过程序的执行来分析上述函数的定义,然后自动生成发送代码和接收代码,最后生成如下代码。
每个人该做的事都已经完成了。 如果你想向另一台计算机发送数据包,只需调用自动生成代码的函数即可。 将在接收计算机上调用具有相同名称的函数。
这种技术称为RPC(远程过程调用)。 目前Google protobuf等都可以实现这个功能,但我早在2000年就已经实现了这个功能,并出版了一本关于这个主题的书。
我用英文写了这本书,后来被翻译成中文。
我开发的服务器引擎ProudNet于2008年推出,其中包括我自己编写的RPC。
4、服务器引擎简单使用
ProudNet包括客户端与服务器之间的网络功能以及客户端之间的P2P网络通信功能。 能够轻松简单地使用这些功能是ProudNet的特点之一。
我们简单看一下ProudNet的使用方法。
当需要启动游戏服务器时,只需创建一个NetServer实例并调用Start函数即可。 就这样。
当客户端访问服务器时手机游戏服务端开发,它也会创建一个NetClient实例并调用Connect函数。 此时服务器会回调OnClientJoin函数。 您可以创建 OnClientJoin 函数。 当客户端连接到服务器时,会回调OnJoinServerComplete函数。 同样的,大家只需要实现这个函数的功能即可。
客户端和服务器之间的网络连接可以使用 PRC。
如果要将Knight_Move信息从客户端发送到服务器,首先在客户端调用Knight_Move函数,然后在服务器上生成Knight_Move函数。 其处理速度当然符合实时多人游戏所需的要求。
如果从服务器向客户端55发送Knight_ShowMove消息,则只需在服务器上调用Knight_ShowMove即可。 此时第一个输入参数为客户端ID55。
如果要实现客户端55、56、57之间的P2P通信,必须将它们绑定到P2P组中。 P2P群组可以看作是QQ聊天窗口这样的概念。 同一聊天窗口中的人可以互相聊天,但不请自来的人不能说话。
首先在服务器上调用CreateP2PGroup,并输入55,56,57作为参数。 假设出现一个ID90的P2P组。
客户端很快得知它已加入P2P组90。您还将知道该组中除了您之外还有其他客户端55、56和57。
当客户端55向客户端56发送Knight_Attack时,需要调用Knight_Attack并输入56作为参数。 此时,客户端56将立即执行Knight_Attack函数。 客户端57调用Knight_Attack时,输入P2P组90作为参数,则客户端55、56、57都会回调Knight_Attack。
利用这一点可以减轻网络游戏服务器的运行负载,缩短玩家交换位置信息的时间。 例如,在MMORPG中,大部分数据传输是通过客户端和服务器之间的通信来处理的,指示玩家移动的信息可以使用P2P和C/S通信。
在大型多人在线游戏 (MMO) 中,玩家的移动信息不会传递给所有其他玩家。 例如,玩家55的动作只传递给其他能看到玩家55的玩家。ProudNet对于这个功能的实现非常成熟。 P2P群是基于“能看到55号玩家”的原则而建立的。 如果可以看到玩家55的其他玩家57进入视野,则玩家57将被添加到P2P组中。 相反,如果玩家 58 离开视野,则将添加玩家 58。 已从 P2P 组中删除。 要实现这些功能,只需要调用NetServer的JoinP2PGroup和LeaveP2PGroup即可。 ProudNet的稳定性保证了该函数的频繁调用。
如果想要开发者能够自由地使用C/S网络和P2P网络,那么服务器引擎就必须在底层提供稳定、流畅的支持。 在各种网络环境下无故障运行。
5. P2P连接过程无需等待时间
开发者在开发P2P网络游戏或应用程序时,对服务器引擎的运行有以下愿望。
“当调用客户端之间的P2P连接功能时,可以立即无条件地实现通信。”
进行P2P通信,需要经历NAT打洞的过程。 此过程需要 0.1 至 2 秒。 可能存在无法进行打孔的情况。 等待打孔或编写替换代码是乏味的。
为了解决这个问题,我选择了下面的方法。
“在打孔到来之前进行中继通信,在此期间,在后台尝试打孔。打孔成功后进行P2P通信。
实现这个功能并不难,但问题在于P2P之间的可靠消息传递。 可靠的信息传输类似于TCP,必须保证“我发送的东西对方一定会收到”。 TCP的可靠信息传递机制是发送方窗口在确认对方已接受之前会重新发送消息。 在客户端之间的P2P中继通信过程中,一旦打孔成功,发送方窗口也会被转移到打孔通道中。 这部分是我刚开发ProudNet时遇到的第一个挑战,但是我还是很好的解决了这个问题。
基于 ProudNet 的格斗游戏《街头霸王 5》