UE3客户端加入DS过程

摘要:
Uin=5897623?Name=Tom?Team=0?ClanName=?SpectatorOnly=0?bVIP=0?

拉起DS进程

客户端将比赛地图及相关参数发送给ZoneSvr请求开赛,收到消息后,ZoneSvr会分配一个ip和端口号,并与客户端发过来的地图及其他参数,来构建一个命令行来拉起一个DS进程,

DS启动时在UGameEngine::Init ==> UGameEngine::Browse中调用UGameEngine::LoadMap来序列化地图数据到UWorld* GWorld,

并调用UWorld::SetGameInfo来创建AGameInfo对象(在SetGameInfo函数中,会调用SetGameType静态函数来根据地图名前缀查找对应模式类型),

然后调用UWorld::Listen来创建UNetDriver* NetDriver,并调用UTcpNetDriver::InitListen来创建socket,

在LoadMap结尾发送一个信号量通知ZoneSvr,要ZoneSvr将ip和端口号发送给客户端,告诉客户端自己已经准备好了。

最后,DS在UWorld::Tick中每帧调用NetDriver的UTcpNetDriver::TickDispatch函数中检查是否有客户端连接过来

客户端加入DS

客户端得到DS的ip和端口后,执行命令:open 10.123.102.132:7500?Uin=5897623?Name=Tom?Team=0?ClanName=?SpectatorOnly=0?bVIP=0?bIsRoomOwner=0

open命令会调用UGameEngine::SetClientTravel函数将open命令参数内容设置给UGameEngine的TravelURL变量

客户端在游戏主循环UGameEngine::Tick中会每帧检查UGameEngine的TravelURL变量是否为空

当不为空时,会调用UGameEngine::Browse来创建UNetPendingLevel类型的全局指针变量GPendingLevel

GPendingLevel在其构造函数中创建UTcpNetDriver对象,然后调用该对象的InitConnect函数来创建UDP的Socket、UTcpipConnection对象及Control Channel

然后客户端就正式开启了加入DS的过程,详细如下图所示

UE3客户端加入DS过程第1张UE3客户端加入DS过程第2张

Step2补充说明

Ds在UWorld::Tick中每帧调用NetDriver的UTcpNetDriver::TickDispatch函数会先在ClientConnections数组中查找是否已经创建了这个客户端的连接,

发现没有会调用UTcpipConnection::InitConnection来创建一个新的NetConnection(注:UNetConnection是从UPlayer派生的),然后加入到ClientConnections数组中,

然后使用这个新的NetConnection调用ReceivedRawPacket来处理网络包数据,由于NMT_Hello包使用的是ControlChanel发送的,

而当前NetConnection的Channels数组中没有该Chanel,于是会调用UNetConnection::CreateChannel创建ControlChanel,

然后使用新的ControlChanel调用UChannel::ReceivedRawBunch ==> UChannel::ReceivedSequencedBunch ==> UControlChannel::ReceivedBunch ==> UWorld::NotifyControlMessage来做出应答

Step5补充说明

bSuccessfullyConnected为true,并有了URL.Map及游戏模式,使得UGameEngine::Tick中检查通过开始LoadMap加载客户端地图:

① 加载失败,则调用传入?failed参数调用UGameEngine::Browse来关闭UNetPendingLevel连接并将GPendingLevel置NULL(在UGameEngine::CancelPending函数中实现),然后加载缺省地图(如大厅地图)

② 加载成功,在LoadMap函数中会将GPendingLevel的NetDriver、NetConnection、ControlChannel转交给新地图的GWorld,地图加载完成后会发送NMT_JOIN消息,并将GPendingLevel置NULL

Step6补充说明

在SpawnPlayActor函数中:服务器端通过调用GameInfo.Login来创建PlayerController对象,然后设置PlayerController的NetPlayerIndex、Role、RemoteRole并关联Player

UE3客户端加入DS过程第3张

其他说明

a. UE3通过FSocketSubsystem类型封装了windows(FSocketSubsystemWindows)和unix(FSocketSubsystemBSD)上的Socket,向上对引擎提供了一致的编程接口

引擎通过提供全局变量FSocketSubsystem* GSocketSubsystem单例的方式来使用Socket相关功能

b. 服务器的收包逻辑在UWorld::NotifyControlMessage函数的else分支中,客户端的收包逻辑在UNetPendingLevel::NotifyControlMessage函数中

免责声明:文章转载自《UE3客户端加入DS过程》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇动态将ASPX生成HTML网页并将网页导出PDF洛谷 P5640 【CSGRound2】逐梦者的初心下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

[转]Windows的窗口刷新机制

1、Windows的窗口刷新管理 窗口句柄(HWND)都是由操作系统内核管理的,系统内部有一个z-order序列,记录着当前窗口从屏幕底部(假象的从屏幕到眼睛的方向),到屏幕最高层的一个窗口句柄的排序,这个排序不关注父窗口还是子窗口。 当任意一个窗口接收到WM_PAINT消息产生重绘,更新区域绘制完成以后,就搜索它的前面的一个窗口,如果此窗口的范围和更新区...

HTTP CHUNKED C实现

C语言不像C#一样有很多很多高度的模块化的东西可以使用,在通讯过程中特别是与http相关的通讯过程中可能要对网站返回的数据做一定处理,而且有不少网站的回应是强制性的,例如向网站请求deflate有个能会返回的是gzip的数据。在这过程中与web特性有关的,在服务器构造消息之前可能并不知道或者不方便知道消息的长度,于是就会将消息分为一段段进行传送。 例如如下...

SuperSocket源码解析之会话生命周期

一 基本概念    会话(Session)是客户端与服务器进行通信的基本单元,也是一个Socket的封装,在http协议中也有Session机制,其主要作用封装一个通信单元socket,负责服务器与客户端消息发送与接收,会话之间相互独立互不干扰且拥有唯一SessionId标识,维护着客户与服务器通信的生命周期。 二 SocketSession Socket...

RabbitMQ重试机制

消费端在处理消息过程中可能会报错,此时该如何重新处理消息呢?解决方案有以下两种。 在redis或者数据库中记录重试次数,达到最大重试次数以后消息进入死信队列或者其他队列,再单独针对这些消息进行处理; 使用spring-rabbit中自带的retry功能; 第一种方案我们就不再详细说了,我们主要来看一下第二种方案,老规矩,先上代码: spring:...

jQuery(1)

ajax 中get和post的区别1、get请求的数据大小限制小。追家在url中传送,能在浏览器中缓冲,能被看见,不安全。post以http消息的实体内容发送到web服务器,传送的数据量大。安全。 闭包:javascript语法区域中特殊区域。类似的方法闭包如 (function(){})();能访问局部变量。一个函数可以访问一个函数作用域中的变量。 j...

MQTT的使用介绍

之前项目中使用到了mqtt,刚开始用着用着都不知道是干啥的,后来百度了一下: MQTT MQTT基于订阅者模型架构,客户端如果互相通信,必须在同一订阅主题下,即都订阅了同一个topic,客户端之间是没办法直接通讯的。订阅模型显而易见的好处是群发消息的话只需要发布到topic,所有订阅了这个topic的客户端就可以接收到消息了。 发送消息必须发送到某个to...