Wind主打简单易上手特性,默认在Windows下开发,多个平台部署。游戏业务开发流程只需要三步,第一步是定义与客户端通信的协议,第二步是生成协议数据,第三步是编写业务逻辑函数。
- 协议定义
Wind支持Protobuf通信协议,协议文件放在engine\codec\proto
目录下,分为客户端通信协议proto_client
和服务间通信协议proto_server
。与客户端通信的协议一般以Request
和Response
结尾,如下。
message PlayerLoginRequest
{
string player_id = 1;
}
message PlayerLoginResponse
{
string player_id = 1;
bool result = 2;
}
- 协议生成
运行script
目录下的gen_protobuf.bat
脚本,生成协议的Protobuf对象。
- RPC逻辑函数
Wind的RPC函数采用自动注册的方式,你只需要在对应服务handlers
目录下编写以Handler_
开头的函数就行,起服时会自动注册函数。
# 客户端rpc函数以Handler_开头 后面接Protobuf的协议名
async def Handler_PlayerLoginRequest(client: ClientConn, request):
logging.info(f"player_id:{client}, request:{request} ")
client.set_player_id(request.player_id)
GateRouterMgr().on_player_login(request.player_id)
逻辑服务
Wind整个核心的目录是engine
,engine
包含服务引擎所有的底层基础功能,比如网络、序列化、服务发现等等。engine
目录下最重要的文件是SrvEngine.py
,SrvEngine.py
包含Engine
类,它是所有逻辑服务的基类,其他的逻辑服务需要继承Engine
类,并且增加自己的逻辑功能。
逻辑服务放在service
目录下,目前有gateway
服务和game
服务。gateway
是与客户端直连的服务,如果是分布式服务的话,用于路由客户端的RPC请求到后端服务。game
服务是后端服务,用于处理游戏逻辑,一般gateway
服务的RPC 请求就会路由到这。这里的game
和gateway
服务的功能只是我测试使用的的,你可以根据业务需求,自定义服务功能。
一般各个逻辑服务的逻辑写到对应服务的handlers
和mgr
的目录下。
逻辑模块
各个服务的逻辑模块写在mgrs
目录下,当然你也可以新建文件夹。Python层的逻辑是单线程异步协程,单个时刻写逻辑时只需要考虑一个客户端的请求就行,所以逻辑模块通常使用单例类来管理各个玩家的本地缓存数据,比如:
from engine.utils.Singleton import Singleton
# 玩家管理模块
class GamePlayerMgr(Singleton):
def __init__(self):
# 各个玩家的服务绑定信息
self.player2server = {}
def get_player_bind_server(self, player_id):
return self.player2server.get(player_id, "*")
定时器
服务器的一些定时任务可以用Engine的add_timer 函数注册,比如:
self.add_timer(int(Config.ETCD_TTL / 2), self.registry.tick)
服务间的RPC
服务间的RPC流程跟上面使用流程是一样的,不过服务间协议一般以S_
开头。比如:
message S_PlayerRegister
{
string player_id = 1;
string gate_server_id = 2;
}
message S_PlayerRegisterAck
{
bool result = 1;
}
服务器间的通信使用Nats
消息队列,因为Nats
能保证有序,这对服务器逻辑非常重要。发送RPC时只需要知道对方server_id
就行。
SrvEngine.srv_inst.send_server_message(SeverType.GAME, bind_server, player_id, sync)