哈喽,大家好,我叫人宅,这里详细讲解一下关于本次代码的一个解读,毕竟代码量好几万了,代码融合了很多的技术,如果真的要看懂,阅读者需要一定的代码火候,所以这次我们来解读一下本次代码,希望对大家有所帮助。

这次主要介绍的是机器人协议,什么意思呢?
拿到源码后,进入TestGameMap,点击开始游戏,内部会接通一个协议,这个协议就是机器人协议。
为什么要有机器人协议呢?
这套工程是基于分布式+DS服务器架构模式来架构的,没办法通过登录到大厅再到游戏场景里面。
内部原理是登录->捏脸->大厅 这些是在分布式SNC进行的,但是游戏场景是DS服务器,并不是单一的服务器来接管,是多服务器合作运行。
如果游戏打包后,那这种问题就不存在。关键现在是编辑器中,我们不能写一行代码都要打包游戏才可以看到结果,那效率太低了,所以才有了机器人协议。
什么是机器人协议呢?
就是可以完成从登录到大厅再到游戏场景中的过程,也就是把所有主要协议都走一边,然后再进入到游戏场景。
这就是机器人的第一句协议,获取捏脸数据,这个捏脸数据是直接通过网关获取,模拟角色在大厅的效果。

我们不用关心服务器到底返回什么,以后会详细分析大厅协议的执行内容。
现在我们详细分析协议的登录流程
当我们接受到捏脸协议后 我们直接运行RunLoginToDSServerRequests 函数内容

这个函数可以直接连接到DS服务器,也就是登录DS服务器,依然是通过网关发送,我们重点来看看这个协议都干了什么.

首先可以看到 它发送了一个ID和SlotID,这两个主要是用户的ID和它存档的位置。因为本次的角色是具有可以创建存档位置的,所以这么操作是非常有必要,只有这些数据正确才可以保证后续的玩家登录到DS服务器。
我们刚刚考伦的内容都发生在MMOARPG的项目里面,这里我们省区了网关的代码转发,直接看中心服务器那边都做了什么?
这个是目前的中心服务器:

中心服务器实际上需要存储用户登录到DS服务器的用户信息,这些信息在本地是没有的,所以这里也是一个转发,但是这种转发是通过dbClient进行,通过数据库客户端来实现转发,将客户端传递的UserID和SlotID发送过来,同样需要传递两个地址,一个是链接客户端的地址和中心服务器的地址到db数据库中。
这里的协议是 SP_PlayerRegistInfoRequests
现在我们看看db服务器那边是如何获取用户数据
case SP_PlayerRegistInfoRequests:
{
int32 UserID = INDEX_NONE;
int32 SlotID = INDEX_NONE;
FSimpleAddrInfo GateAddrInfo;
FSimpleAddrInfo CenterAddrInfo;
//拿到客户端发送的账号
SIMPLE_PROTOCOLS_RECEIVE(
SP_PlayerRegistInfoRequests,
UserID,
SlotID,
GateAddrInfo,
CenterAddrInfo);
if (UserID != INDEX_NONE && SlotID != INDEX_NONE)
{
FMMOARPGUserState UserState;
FString UserInfoJson;
FString SlotInfoJson;
FString DressUPInfoString;
FString JsonString = TEXT("[]");
if (GetUserInfo(UserID, UserInfoJson) &&
GetSlotCAInfo(UserID,SlotID,SlotInfoJson) &&
GetCharacterSave(UserID, SlotID, UserState))
{
FString ArraySlotStringEquipment;
FString ArraySlotStringItem;
FString ArraySlotStringSkill;
FString ArraySlotStringSkin;
GetAllKnapsack(
UserID,
SlotID,
ArraySlotStringEquipment,
ArraySlotStringSkill,
ArraySlotStringItem,
ArraySlotStringSkin,
DressUPInfoString);
SIMPLE_PROTOCOLS_SEND(SP_PlayerRegistInfoResponses,
UserInfoJson,
SlotInfoJson,
UserState,
ArraySlotStringEquipment,
ArraySlotStringSkill,
ArraySlotStringItem,
ArraySlotStringSkin,
DressUPInfoString,
GateAddrInfo,
CenterAddrInfo);
}
else
{
SIMPLE_PROTOCOLS_SEND(SP_PlayerRegistInfoResponses,
JsonString,
JsonString,
UserState,
JsonString,
JsonString,
JsonString,
JsonString,
DressUPInfoString,
GateAddrInfo,
CenterAddrInfo);
}
}
break;
首先通过 SP_PlayerRegistInfoRequests 已经接受到了用户数据。
然后通过 以下的三个API获取对应的 玩家数据 捏脸数据 角色的存档数据

对应数据库是以下的数据:


这三个数据属于主要数据,如果这三个都拿不到后面就不用拿了。
接下来再拿到如下的数据 物品栏和装备栏数据

这里对应数据库如下的内容:

分别是装备栏,道具栏,皮肤栏,技能栏,对应内容如下。

接着还有一个非常重要的内容,就是这个数据

它记录玩家的装备信息,主要体现如下:

数据库代码如下:

拿到这些数据后 正式将其返回到中心服务器,中心服务器会将这些数据缓存起来:

此时我们来到中心服务器

//出
case SP_PlayerRegistInfoResponses:
{
FString ArraySlotStringEquipment;
FString ArraySlotStringItem;
FString ArraySlotStringSkill;
FString ArraySlotStringSkin;
FString DressUPInfoString;
FSimpleAddrInfo GateAddrInfo;
FSimpleAddrInfo CenterAddrInfo;
FMMOARPGPlayerRegistInfo RI;
FString UserJson;
FString SlotJson;
SIMPLE_PROTOCOLS_RECEIVE(
SP_PlayerRegistInfoResponses,
UserJson,
SlotJson,
RI.UserState,
ArraySlotStringEquipment,
ArraySlotStringSkill,
ArraySlotStringItem,
ArraySlotStringSkin,
DressUPInfoString,
GateAddrInfo,
CenterAddrInfo);
if (UserJson != TEXT("[]") && SlotJson != TEXT("[]"))
{
FMMOARPGDressUPInfo DressUPInfo;
NetDataAnalysis::StringToMMOARPGDressUPInfo(DressUPInfoString, DressUPInfo);
NetDataAnalysis::StringToCharacterAppearances(SlotJson, RI.CAInfo);
NetDataAnalysis::StringToUserData(UserJson, RI.UserInfo);
RI.DressUPInfo = DressUPInfo;
NetDataAnalysis::StringToMMOARPGProduct(ArraySlotStringEquipment,RI.WeaponMap);
NetDataAnalysis::StringToMMOARPGProduct(ArraySlotStringSkill, RI.SkillMap);
NetDataAnalysis::StringToMMOARPGProduct(ArraySlotStringItem, RI.ItemsMap);
NetDataAnalysis::StringToMMOARPGProduct(ArraySlotStringSkin, RI.SkinMap);
RI.bInitializeRegistInfo = true;
CenterUserInfo.AddRegistInfo(RI);
//准备ds服务器
if (FSimpleAddr* DsAddr = CenterUserInfo.FindDicatedServerAddrAndCreate(RI.UserState.DSID))
{
SIMPLE_SERVER_SEND(CenterServer, SP_LoginToDSServerResponses, CenterAddrInfo, GateAddrInfo,*DsAddr);
UE_LOG(LogMMOARPGCenterServer, Display, TEXT("A new DS server address was found.Ip=%i,Port=%i."), DsAddr->IP, DsAddr->Port);
}
else
{
FString NewPublicIP = FSimpleNetGlobalInfo::Get()->GetInfo().PublicIP;
FSimpleAddr LocalDSAddr = FSimpleNetManage::GetSimpleAddr(*NewPublicIP, 7777);
SIMPLE_SERVER_SEND(CenterServer, SP_LoginToDSServerResponses, CenterAddrInfo, GateAddrInfo, LocalDSAddr);
UE_LOG(LogMMOARPGCenterServer, Error, TEXT("ERROR: The address cannot be found. The default address is used here.Ip=%i,Port=%i."), LocalDSAddr.IP, LocalDSAddr.Port);
}
}
break;
}
中心服务器拿到数据后,将字符串解析为中心服务器的结构数据,最终存储再CenterUserInfo里面。

因为MMOARPG是多地图组成的,根据玩家的存储信息,判定它到底是在哪个DS服务器,并且取得它的地址,这个地址就是玩家日后要链接的DS服务器地址。

最后 中心服务器会将 DS服务器的地址,发送到MMOARPG的客户端,客户端就可以通过这个地址链接到DS服务器。
以下是客户端接受本次信息,因为在客户端是在编辑器内部执行,也就是本次是DS和客户端一起启动,客户端已经链接到DS服务器,所以没有必要再连一次,除非是打包后的游戏。
