UE4 网络联机
https://www.pome.cc/page/4/
https://www.uejoy.com/?p=495
https://zhuanlan.zhihu.com/p/326926285
https://blog.csdn.net/zzq00zzj/article/details/131852911
https://blog.csdn.net/goodriver1/article/details/108593053?spm=1001.2014.3001.5502
CreateSession 创建房间
FindSession 查找房间
JoinSession 加入房间
物体同步需要打开Replicates 勾选
同步事件要调用
Run On Server 在服务器运行
Muticast 调用所有的客户端
服务器变量 属性要Replication 勾选,变量会显示两个小球
物理碰撞具有随机性,帧间时长不一致
Event OnPostLogin 在服务器GameMode上的玩家加入
ClientPostLogin 客户端登录事件
Switch Has Authority 是否具有权限
Is Locally Controled 是否是本地控制者
TMap不支持Replicate
Has Authority 是否具有权限
Get Onwing Player 获得自己的控制器
Starting New Player 玩家登录创建Pawn
IsLocallyControlled()
GetLocalRole 可以查看Actor的所有权,我们在角色的头顶添加一个TextRender,然后把GetLocalRole的控制权名称设置到TextRender上。
- Not Replicated:不进行网络复制;
- Multicast:由服务器调用,在服务器和所有客户端执行;
- Run on Server:在客户端中调用,在服务器中执行;
- Run on owning Client:只在有所有权的客户端执行,执行结果不会同步到其他客户端。
Actor的所有权—ROLE
UE将Actor的控制权分成了三类,分别是:
ROLE_None:这个None就是我们平常理解的None,不属于下面三种的都是None
ROLE_Authority:服务器拥有所有Actor的控制权,即所有的Actor在服务器端的控制权都是ROLE_Authority
ROLE_AutonomousProxy:客户端对本地Actor拥有这个控制权
ROLE_SimulatedProxy:客户端对网络Actor,即其他端的Actor,拥有这个控制权
客户端 只有一个PlayerController 这个是自己控制的,服务器上也会有一个对应的,这个相当于中间连接的接口,所以数据不要放Controller里同步,否则其他客户端收不到同步消息,因为其他Client没有别人的PlayerController
服务器有很多个PlayerController,可以用Is LocalConller来判断当前的PlayerController是否在服务器上运行,返回true就是在Client上运行,False就是在服务器上
服务器和客户端 有多少客户端就有有很多个Pawn,Pawn的数据和其他Actor的数据可以同步,
客户端是无法获取GameMode的,GameMode只存在服务器上,
RunOnServer的Event需要用自己的其他Event调用,别的Actor里面调用这个Event无效
目前OpenLevel好像不能同步
Actor 同步只能从 Server 同步到 Client,Client 唯一向 Server 发送请求的方式只有 RPC,属性同步是单向的
RPC 的使用有一些前提准则,必须满足这些条件才能调用
它们必须从 Actor 上调用。
Actor 必须被复制。
如果 RPC 是从服务器调用并在客户端上执行,则只有实际拥有这个 Actor 的客户端才会执行函数。
如果 RPC 是从客户端调用并在服务器上执行,客户端就必须拥有调用 RPC 的 Actor。
多播 RPC 则是个例外:
如果它们是从服务器调用,服务器将在本地和所有已连接的客户端上执行它们。
如果它们是从客户端调用,则只在本地而非服务器上执行。
现在,我们有了一个简单的多播事件限制机制:在特定 Actor 的网络更新期内,多播函数将不会复制两次以上。按长期计划,我们会对此进行改善,同时更好的支持跨通道流量管理与限制。
原文链接:https://blog.csdn.net/2301_77550592/article/details/131999128
判断是来自于本地玩家视角还是其他玩家视角。联网时,服务器false,客户端上自己true其他人false;单机时,客户端true。 作者:白の鸽丶 https://www.bilibili.com/read/cv15922283/ 出处:bilibili
bool APawn::IsLocallyControlled() const { return ( Controller && Controller->IsLocalController() ); } bool AController::IsLocalController() const { const ENetMode NetMode = GetNetMode(); if (NetMode == NM_Standalone) { // Not networked. return true; } if (NetMode == NM_Client && GetLocalRole() == ROLE_AutonomousProxy) { // Networked client in control. return true; } if (GetRemoteRole() != ROLE_AutonomousProxy && GetLocalRole() == ROLE_Authority) { // Local authority in control. return true; } return false; }
GameMode
在上面这个例子中,GameMode 决定的是游戏规则,即拥有两个角色,先跨过终点线的玩家为冠军。衍生的部分还有比如是否允许观战以及观战的人数最多为多少?玩家如何进入游戏,以及使用哪张比赛地图?游戏是否可以暂停,以及暂停之后如何恢复?游戏是否允许使用道具,又或者是否可以在游戏中作弊等,这些规则都是跑在服务器上的,确保规则的权威性和安全性。
GameMode在Unreal里的实现是AGameModeBase类(用A开头是因为它继承于Unreal的AActor,这是Unreal的类命名规则,可以查看代码规范),它是AGameMode的基类。一个项目可以拥有任意多的GameMode来设置各种各样的玩法,但同一时刻只能使用一个GameMode。
AGameModeBase提供若干基础的、可被override的接口:
- InitGame。 在这里做所有游戏规则的初始化工作。
- PreLogin 。登录前的预处理。由于GameMode只会跑在服务器上,可以在这里检查玩家的合法性,判定是否允许玩家登录服务器。
- PostLogin。登录后的后处理。玩家成功登录服务器之后的调用。
- HandleStartingNewPlayer。一般登录成功之后就会创建玩家在服务器上的对象,对象创建成功之后会调用该函数,可以在这里对玩家进行初始化,比如获取玩家的PlayerState。
- RestartPlayer。创建玩家的实体对象(可操控的,场景上可见的Pawn对象)。
- Logout。玩家退出或者服务器被销毁时调用。
Run on server在child actor component 中是不能RPC给服务器的。
- Only Relevant to Owner 只跟所有者相关
- Always Relevant 永远和所有人相关
- Net Use Owner Relevancy 使用所有者相关性
- Net Cull Distance Squared 与距离相关
-
解读
在服务器上,服务器需要处理所有人的数据,所以所有人在服务器是不检查相关性的,测试时尽量使用DS模式测试。
相关性会影响渲染,例如已知A玩家,当B玩家进入A玩家相机拍摄范围,但是B玩家和A玩家不相关,则A玩家终端不会渲染B玩家(不要使用相关性做什么隐身技能,这不是相关性要处理的)。
最终的测试,建议大家可以启用引擎的DS(专享服务器)模式,完成测试。
测试通过动态生成Actor后,调整Owner来测试,一定要动态生成,Owner可以设置为某个终端控制的Pawn,通过渲染剔除来测试效果
1、Only Relevant to Owner(只和所有者相关)
所有者:虚幻引擎有个概念,即,你生成的对象Actor,添加的组件,都需要有个归属,一般Actor没有指认关系则归属于关卡。组件如果在构造函数中使用CreateDefaultSubobject创建,则归属所在类实例的对象。如果在运行时态,使用NewObject创建,则归属NewObject时填入的Outer。
为什么要有所有者?主要是为了溯源,解决对象释放依赖问题。
网络中的所有者:虚幻网络所有者还有另外一层意图,在客户端,只有属于当前客户端的对象才能向服务器发送Server标记消息。一般的Actor是不归属任何终端的,但是如果某个终端有个玩家拾取一把枪械,枪械应归属拾取角色所在终端,以便后期从所属角色终端向服务器发送消息。修改方法是,必须在服务器,将枪械的Owner设置为目标终端的PlayerController,Pawn,PlayerState,三者之一即可,调用SetOwner函数。
当Actor勾选了Only Relevant to Owner,则只会将网络消息发送给他的Onwer。不会发送给任何人,并且在其他人的终端不会进行渲染(如果Actor是运行时生成会被隐藏,如果是拜访到世界中则不会隐藏渲染,这又是另外一个话题了)。
2、Always Relevant 永远和所有人相关
顾名思义,就是无论在任何地方,任何角落都能接收到此对象的网络数据信息。例如绝对求生中的空投。
3、Net Use Owner Relevancy 使用所有者相关性
使用所有者相关其实就是当你有所有者的时候,相关性检查不走你的规则,而是使用你所有者的规则。一个简单的例子大家就能够懂了:在网络中,一个玩家驾驶一辆载具,载具如何驾驶者的相关性规则不一致,可能会导致车子和驾驶者进入另外一个玩家视野时,另外一个玩家只看到载具或是只看到车辆。这是很奇怪的,所以应该将载具的Owner设置为它的驾驶者,并且勾选使用Owner的相关性。
4、Net Cull Distance Squared 通过距离管控相关性
所有的Actor都是默认使用距离进行相关性检测的。例如A和B设置的相关性距离是10米,那么超过10米,在网络中就会不会向对方发送网络消息了。
注意,此参数需要设置距离的平方,例如你希望超过10米就不要发送数据,需要填入1000×1000
结语
相关性总体来说不是非常复杂,通过贴出来的代码,大家也可以看到检测的基本逻辑。但是需要注意,相关性的检测不是每一帧都检查,所以不要依赖相关性的及时性设计任何逻辑。
官方也给出了相关性检查的规则,以上规则在设置时是有前后顺序的,即一层层检查的,上一层不成立,则继续向下检查。最后是距离剔除。
- 如果 Actor 是 bAlwaysRelevant、归属于 Pawn 或 PlayerController、本身为 Pawn 或者 Pawn 是某些行为(如噪音或伤害)的发起者,则其具有相关性。
- 如果 Actor 是 bNetUseOwnerRelevancy 且拥有一个所有者,则使用所有者的相关性。
- 如果 Actor 是 bOnlyRelevantToOwner 且没有通过第一轮检查,则不具有相关性。
- 如果 Actor 被附加到另一个 Actor 的骨架模型,它的相关性将取决于其所在基础的相关性。
- 如果 Actor 是不可见的 (bHidden == true) 并且它的 Root Component 并没有碰撞,那么则不具有相关性,
- 如果没有 Root Component 的话,AActor::IsNetRelevantFor() 会记录一条警告,提示是否要将它设置为 bAlwaysRelevant=true。
- 如果 AGameNetworkManager 被设置为使用基于距离的相关性,则只要 Actor 低于净剔除距离,即被视为具有相关性。
三种ROLE(本地角色)
Authority: 权威(有对Actor的控制权)
各个Actor在服务端的状态
SimulatedProxy: 模拟代理
当前客户端Actor在其他客户端的状态
AutonomousProxy: 自主代理
当前客户端Actor在当前客户端的状态
Remote_ROLE(远端角色)