我曾尝试搜索如何制作MMO,并且总是找到相同的回复,即它是不可能的或需要大量资金,但从未给出制作指南。
我想构建一个非常可扩展的项目,我目前关于如何构建MMO的想法如下:
组件:
- 登录服务器:客户端向该服务器发送用户名和密码,如果成功,则提供要连接的游戏服务器。
- 游戏服务器[1..N]:所有游戏逻辑都在此处,客户端连接到此服务器。
- 位置数据库:存储当前已登录用户和活动怪物的数据,在哪个游戏服务器上,他们在地图上的位置以及他们正在进行的操作(移动、攻击等)。
- 帐户数据数据库:存储有关用户的所有数据(用户名、密码、角色、物品、任务等)
- 聊天服务器:由于在同一位置的用户可能在不同的服务器上,因此需要额外的服务器,以便玩家可以彼此通信。
- 怪物数据库:包含所有怪物的属性、基本位置和AI脚本的数据库。
- 怪物服务器[1..N]:服务器中的所有活动怪物
- 日志数据库:存储所有采取的操作和聊天文本。
操作:
- 登录:
- 客户端向登录服务器发送用户名和密码。
- 登录服务器验证帐户数据库中的数据,并检查该用户当前是否已登录(位置数据库),如果成功,则转到3,否则返回失败的登录消息。
- 登录服务器更新位置数据库,将新连接的用户添加到他将连接的服务器(人数最少/最近)中。
- 位置数据库通知相应的游戏服务器用户已连接。
- 登录服务器向客户端发送所连接的游戏服务器。
- 主循环(客户端):
- 客户端在位置数据库中检查自己的当前位置和操作,以及那些接近他的人(玩家和怪物),接收到的数据还包括玩家上次更新的时间(齿轮或等级)。
- 客户端比较收到的玩家日期与当前保存在内存中的玩家日期,如果该玩家不在内存中或者日期不同,则客户端请求帐户数据库获取等级、齿轮等信息。
- 客户端渲染玩家。
- 一段时间后返回1。
- 聊天:
- 客户端向聊天服务器发送消息(私人/普通/全部)。
- 如果是私人,聊天服务器将消息发送给目标。
- 如果是普通,聊天服务器与位置服务器检查该区域的玩家(与主循环(客户端)中检查接近玩家的玩家相同)并将消息发送给这些玩家。
- 如果是全部,聊天服务器广播给所有玩家。
- 确认发送方和接收方都已收到消息。
- 操作:
- 客户端向游戏服务器发送操作(制作、移动、攻击等)。
- 游戏服务器处理操作,并将操作的影响更新到位置数据库中(客户端将知道主循环操作发生了什么)。
- 在制作或拾取物品的情况下,游戏服务器将获得的物品返回给客户端。
- 主循环(游戏服务器):
- 检查来自客户端的所有接收数据并对其进行处理。
- 向客户端发送处理结果(伤害、经验值、获得的物品等),并将其效果更新到位置数据库中(新位置等)。
- 一段时间后返回1。
- 主循环(怪物服务器):
- 检查是否有玩家靠近活动怪物,如果没有,则从怪物服务器和位置数据库中删除它。
- 检查位置数据库中的所有玩家是否有任何接近的怪物(来自怪物数据库)并且未激活,并将其激活(更新位置服务器和怪物服务器)。
- 怪物根据存储在怪物数据库中的脚本采取行动(攻击、移动、不做任何事情等)。
- 一段时间后返回1。
我有以下问题:
- 这种实现方式是否可行?(考虑到有大量怪物和玩家的大地图)
- 我感觉如果事情变得更加复杂,位置数据库会承受很大的压力。最好的方法是:
- 建立多个位置数据库
- 建立一个链接(玩家/怪物,游戏服务器,位置数据库)的数据库
- 建立一个链接(位置数据库,区域)的数据库
- 这样一个位置数据库就是基于一个区域(或几个区域),当一个玩家移动到另一个区域时,他的数据就会被转移到另一个位置数据库中;最后一个数据库(位置数据库,区域)是为了防止一个区域有太多玩家而几个位置数据库可以共享同一区域(如果某些区域的人不多,则一个位置数据库可以承载一些区域)
- 关于使用的技术,我正在考虑以下内容:
- 登录服务器:scala/django
- 游戏服务器:C++原始编程?
- 位置数据库:scala/django用于通信和带有SQL的数据库
- 账户数据库:scala/django用于通信和数据库,不确定是否使用像mongoDB这样的NoSQL,还是将账户保存在文件上(哪种更好?)
- 聊天服务器:C++原始编程,还是应该尝试适应IRC服务器?
- 怪物数据库:SQL
- 怪物服务器:像游戏服务器一样
- 日志数据库:SQL
- 客户端和服务器之间的通信应该使用UDP以实现更快的通信?登录时使用TCP?或者应该始终保持一个开放的TCP套接字连接客户端和服务器?以及对于聊天,是TCP还是UDP?
- 主循环大约每多少时间运行一次可以使游戏顺畅进行?每0.5秒,0.1秒,接近60fps的时间?另外,为了创建计时器,抛出线程比较好?(控制线程的数量,因此如果循环所需时间超过预计时间)