MMOARPG-代码解读(一) 编辑器的机器人协议流程详细分析

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

这次主要介绍的是机器人协议,什么意思呢?

拿到源码后,进入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服务器,所以没有必要再连一次,除非是打包后的游戏。

发表回复