Files
netease-bedrock-wiki/mcguide/27-手机网络游戏/课程9:服务器上线/第7节:多版本客户端引擎支持.md
2025-07-31 17:53:14 +08:00

197 lines
8.5 KiB
Markdown
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
front:
hard: 进阶
time: 20分钟
---
# 多版本客户端引擎支持
### 应用场景
整包升级期间网络服支持多个版本客户端同时进入解决升级后低版本客户端无法进入问题。下面以同时支持1.23版本和1.24版本客户端为例,介绍多版本客户端引擎支持方案
## 解决方案
apollo中proxy、master和service是兼容不同版本的只需解决lobby/game兼容问题方法是将玩家分配到适配版本lobby/game中也即1.23版本的玩家进入1.23版本的lobby/game中1.24版本玩家进入1.24版本lobby/game中。下面详细介绍实现细节
### 网络服配置
大厅服需要同时部署多个版本这里同时部署1.23和1.24两个版本的lobby
![image-20211015153007727](./images/image-20211015153007727.png)
![image-20211015153253908](./images/image-20211015153253908.png)
游戏服需要同时部署多个版本并且每种类型的游戏服都要部署多个版本这里同时部署1.23和1.24两个版本的game
![image-20211015153406700](./images/image-20211015153406700.png)
![image-20211015170824022](./images/image-20211015170824022.png)
控制服配置为多个版本中最高版本这里配置为1.24版本
![image-20211015153719169](./images/image-20211015153719169.png)
功能服配置为多个版本中最高版本这里配置为1.24版本
![image-20211015153546589](./images/image-20211015153546589.png)
代理服配置为多个版本中最高版本这里配置为1.24版本
![image-20211015145555301](./images/image-20211015145555301.png)
## 代码支持
将玩家分配到适配lobby/game中需要考虑登陆和切服两种情况
### 登陆
apollo支持将玩家分配到适配的lobby无需开发者做额外开发但是若开发者设置玩家登陆策略参见`SetLoginStratege`接口),则需要考虑多版本兼容问题,实现步骤是:
- 获取可用服务器和协议版本号
- 根据协议版本号将玩家分配到适配版本服务器中
下面示例实现自定义登陆逻辑,将登陆玩家分配到适配版本"gameA"类型游戏服中
```python
#master mod
class testMaster(MasterSystem):
def __init__(self,namespace,systemName):
import master.netgameApi as netMasterApi
MasterSystem.__init__(self, namespace, systemName)
self.mVersion2TargetServerIds = {} #protocolVersion--> serverIds
def loginStratege(uid, callback):
# 获取玩家协议版本号
protocolVersion = netMasterApi.GetProtocolVersionByUID(uid)
targetIds = self.mVersion2TargetServerIds.get(protocolVersion, [])
targetId = random.choice(targetIds) #选择目标服务器
#检查目标服务器是否有效。因为滚动更新过程中,服务器会慢慢下线,处于无效状态
if not serverManager.IsValidServer(targetId):
#若发现有无效服务器,则过滤掉所有无效服务器,然后重新选择目标服务器
targetIds = [server for server in targetIds if serverManager.IsValidServer(server)]
self.mVersion2TargetServerIds[protocolVersion] = targetIds
targetId = random.choice(targetIds)
callback(targetId) #必须执行,执行登陆后续操作
netMasterApi.SetLoginStratege(loginStratege)
self.ListenForEvent('gameANameaspace', 'gameASystem', 'NewLoginServerEvent', self, self.OnNewLoginServer)
def OnNewLoginServer(self, args):
# 将有效目标服务器记录下来
protocolVersion = args['protocolVersion']
serverId = args['serverId]
serverIds = self.mVersion2TargetServerIds.get(protocolVersion, [])
if serverId not in serverIds:
serverIds.append((serverId, ))
self.mVersion2TargetServerIds[protocolVersion] = serverIds
#gameA mod
class gameServer(ServerSystem):
def __init__(self, namespace, systemName):
ServerSystem.__init__(self, namespace, systemName)
self.ListenForEvent(serverApi.GetEngineNamespace(), serverApi.GetEngineSystemName(), 'MasterConnectStatusEvent',
self,self.OnMasterConnectStatus)
def OnMasterConnectStatus(self, args):
# 同master建立连接后马上向master注册为有效服务器
if args['isConnect']:
data = {
'serverId' : lobbyGameApi.GetServerId(),
'protocolVersion' : lobbyGameApi.GetServerProtocolVersion()#获取服务器协议版本号
}
self.NotifyToMaster('NewLoginServerEvent', data)
```
### 切服
切服需要将玩家分配到适配版本的服务器中,实现步骤:
- lobby/game从master获取目标服务器master需要通过协议号找到适配服务器列表然后根据某种算法获取目标服务器
- lobby/game根据目标服务器进行切服
下面示例实现多版本支持的切服逻辑,将登陆玩家分配到适配版本"gameA"类型游戏服中
```python
#master mod
class testMaster(MasterSystem):
def __init__(self,namespace,systemName):
import master.netgameApi as netMasterApi
MasterSystem.__init__(self, namespace, systemName)
self.mVersion2TargetServerIds = {} #protocolVersion--> serverIds
self.InitServerInfo()
self.ListenForEvent(extraMasterApi.GetEngineNamespace(), extraMasterApi.GetEngineSystemName(),
'NetGameCommonConfChangeEvent',self, self.OnNetGameCommonConfChange)
self.ListenForEvent('gameNameaspace', 'gameSystem', 'ChooseTargeGameServerRequestEvent',
self, self.ChooseTargeGameAServer)
def OnNetGameCommonConfChange(self, args)
'''
每次配置发生变化,需要重新获取目标服务器
'''
self.InitServerInfo()
def InitServerInfo(self):
'''
获取gameA服务器和它的协议版本号
'''
import master.serverManager as serverManager
commonConf = netMasterApi.GetCommonConfig()
self.mVersion2TargetServerIds = {}
serverlist = commonConf['serverlist']
for conf in serverlist:
if conf['type'] == 'gameA':
serverId = conf['serverid']
protocolVersion = serverManager.GetServerProtocolVersion(serverId)
ids = self.mVersion2TargetServerIds.get(protocolVersion, [])
ids.append(serverId)
self.mVersion2TargetServerIds[protocolVersion] = ids
def ChooseTargeGameAServer(self, args):
'''
随机选择一个目标服务器
'''
serverId = args['protocolVersion']
protocolVersion = args['protocolVersion']
targetIds = self.mVersion2TargetServerIds.get(protocolVersion, [])
targetId = random.choice(targetIds) #选择目标服务器
#检查目标服务器是否有效。因为滚动更新过程中,服务器会慢慢下线,处于无效状态
if not serverManager.IsValidServer(targetId):
#若发现有无效服务器,则过滤掉所有无效服务器,然后重新选择目标服务器
targetIds = [server for server in targetIds if serverManager.IsValidServer(server)]
self.mVersion2TargetServerIds[protocolVersion] = targetIds
targetId = random.choice(targetIds)
data = {'uid' : uid, 'targetId' : targetId}
self.NotifyToServerNode(serverId, "ChooseTargeGameResponseServerEvent", data)
#game mod
class gameServer(ServerSystem):
def __init__(self, namespace, systemName):
ServerSystem.__init__(self, namespace, systemName)
self.ListenForEvent('masterNameaspace', 'masterSystem', 'ChooseTargeGameResponseServerEvent',
self,self.ChooseTargeGameResponseServer)
def DoTransferPlayer(self, uid):
'''
玩家切服会从master请求获取适配服务器
'''
data = {
'uid' : uid,
'protocolVersion' : lobbyGameApi.GetServerProtocolVersion(),
'serverId' : lobbyGameApi.GetServerId()
}
self.NotifyToMaster('ChooseTargeGameServerRequestEvent', data)
def ChooseTargeGameResponseServer(self, args):
'''
从master获取适配服务器后执行切服操作
'''
playerId = lobbyGameApi.GetPlayerIdByUid(args['uid'])
self.TransferToOtherServerById(playerId, args['uid'], args['targetId'])
```