UE4 网络基础

client-server架构

  • 一个服务器,一个或多个服务端 (对比:P2P一对一全链接,去中心化网络)

  • 客户端不可信,所有重要信息经过服务器验证

  • 两种服务器类型

    • Listen Server: 服务器上可以有游戏客户端
    • Dedicated Server:专用服务器,没有游戏客户端运行
  • 网络信息传递的两种方式

    • Replication (服务器–>客户端)
    • RPC (双向)

网络复制Replication

  • Actor及其派生的子类才能复制

  • 只能从服务端到客户端单向(客户端到服务端使用RPC)

  • 判断服务器和客户端的方法

    • 蓝图节点:has authority / switch has authority (Authority服务端,Remote客户端)
    • C++:HasAuthority()
  • 三种类型

    • Actor Repliaction:整个对象的复制
    • Property Replication:Actor中属性变量的复制,有两种(Replicated / Rep_Notify)
    • Component Replication:组件的复制 (如CharacterMovement具有完备的网络复制功能)
  • Actor Repliaction

    • 如果一个Actor对象开启repliaction,则由服务器生成,所有客户端生成镜像对象
    • 设置方法:
      • 蓝图:Class Defaults - 勾选replicates
      • C++:bReplicates = true;
    • 判断并只在服务端生成Actor
      • has authority + spawn actor
  • Property Replication

    • 两种类型:Replicated / Rep_Notify

    • Replicated

    • 蓝图:Actor的变量Details 的Relication设置为Replicated

    • C++:

      • UPROPERTY(Replicated);
      • GetLifetimeReplicatedProps函数(overide, 不用声明)中添加DOREPLIFETIME(类名,变量名)
    • Rep_Notify

      • 作用:当一个变量设置成Rep_Notify,当该变量发生replicatiion时
        • 蓝图:服务端和客户端都可调用一个自定义函数
        • C++:只在客户端调用自定义函数
      • 设置方法:
        • 蓝图:Details的Replication下拉设置成Rep_Notify后,自动生成一个onRep_变量名的空函数,添加实现即可
        • C++:
          • UPROPERTY(ReplicatedUsing=函数名) // 函数名一般取名为OnRep_变量名,UFUNCTION()修饰
          • GetLifetimeReplicatedProps函数(overide, 不用声明)中添加DOREPLIFETIME(类名,变量名)
  • 创建一个复制Actor的CheckList

    • 设置Actor Replication

    • 若复制Actor需要移动,将复制移动(Replicates Movement)设为True

    • 生成或销毁复制Actor时,确保在服务器上执行该操作

    • 设置Property Replication,这通常适用于以gameplay为基础的变量。指定类型为RepNotify 或 Replicated,RepNotify需要设置对应的Notify函数

远程过程调用RPC

  • 三种类型:

    • Server:仅在服务器调用
    • Client:仅在客户端调用
    • NetMulticast:服务器+客户端均调用
  • 设置方法:

    • 蓝图:将事件或函数的细节面板-replicates下拉菜单设置为三种类型的一种后启用,同时将 可靠(Reliable) 设为 true/false,蓝图里默认是不可靠

    • C++

      • 提供对应 UFUNCTION 宏中的 ServerClientNetMulticast 说明符,可在将C++函数指定为RPC

      • WithValidation说明符表示该RPC除了有实现函数(_Implementation后缀的函数)还有验证函数(_Validation后缀的函数),只有验证返回true才会执行实现函数

      • //服务器RPC MyFunction的声明。
        UFUNCTION(Server, Reliable, WithValidation)
        void MyFunction(int myInt);
        
        //服务器RPC MyFunction的实现。
        void AExampleClass::MyFunction_Implementation(int myInt)
        {
            //游戏代码在此。
        }
        
        //服务器RPC MyFunction的验证
        bool AExampleClass::MyFunction_Validation(int myInt)
        {
            /* 
                若myInt的值为负,建议不允许运行MyFunction_Implementation。 
                因此仅在myInt大于零时返回true。
            */
            return myInt >= 0;      
        }
        
  • 可靠和不可靠RPC

    • 不可靠RPC无法保证必会到达预定目的地,但其发送速度和频率高于可靠的RPC。其最适用于对gameplay而言不重要或经常调用的函数。例如,由于Actor移动每帧都可能变换,因此使用不可靠RPC复制该Actor移动
    • 可靠的RPC保证到达预定目的地,并在成功接收之前一直保留在队列中。其最适合用于对gameplay很关键或者不经常调用的函数。相关例子包括碰撞事件、武器发射的开始或结束,或生成Actor
    • 滥用可靠函数可能导致其队列溢出,此操作将强制断开连接。若逐帧调用复制函数,应将其设为不可靠。若拥有与玩家输入绑定的可靠函数,应限制玩家调用该函数的频率
  • RPC调用与执行的位置

在这里插入图片描述

Client和Server的区分

  • AActor 中都有个 ENetRole Role 变量是用来识别角色的 Actor 的身份的。ENetRole 的几个值:

    • ROLE_None:默认值
    • ROLE_SimulatedProxy:这个actor是其他客户端在本机客户端的一个模拟代理
    • ROLE_AutonomousProxy:这个actor是本机客户端的自己控制的角色
    • ROLE_Authority:这个actor是服务器上的actor
  • 举例:一个服务器上有一个玩家ServerA和一个NPC ServerB,客户端上拥有从服务器复制过来的这个玩家ClientA与NPC ClientB。由于ServerA与ServerB都是在服务器上生成的,所以他们两在服务器上的所有权Role都是ROLE_Authority。ClientA在客户端上由于被玩家控制,他的Role是ROLE_AutonomousProxy。ClientB在客户端是完全通过服务器同步来控制的,他的Role就是ROLE_SimulatedProxy。

Actor的相关性和优先级

  • 相关性概念

    • 场景的规模可能非常大,在特定时刻某个玩家只能看到关卡中的一小部分 Actor。场景中的其他大多数 Actor 都不会被看到和听到, 对玩家也不会产生显著的影响。被服务器认为可见或能够影响客户端的 Actor 组会被视为该客户端的相关 Actor 组。
    • 虚幻引擎的网络代码中包含一处重要的带宽优化:服务器只会让客户端知道其相关组内的 Actor
    • 规则实施函数: AActor::IsNetRelevantFor()
  • 优先级概念

    • 虚幻引擎采用了负载平衡技术来安排所有 Actor 的优先级,并根据它们对游戏的重要性为其分别提供一个公平的带宽份额

    • 每个 Actor 都有一个名为 NetPriority 的浮点变量。这个变量的数值越大,Actor 相对于其他"同伴"的带宽就越多。和优先级为 1.0 的 Actor 相比,优先级是 2.0 的 Actor 可以得到两倍的更新频度。

    • 优先级计算函数:AActor::GetNetPriority()

UE4建立网络链接的流程

  • 主要步骤

    1. 客户端发送连接请求
    2. 服务器将在本地调用 AGameMode::PreLogin。这样可以使 GameMode 有机会拒绝连接
    3. 如果服务器接受连接,则发送当前地图
    4. 服务器等待客户端加载此地图,客户端如果加载成功,会发送Join信息到服务器
    5. 如果接受连接,服务器将调用 AGameMode::Login该函数的作用是创建一个PlayerController,可用于在今后复制到新连接的客户端。成功接收后,这个PlayerController 将替代客户端的临时PlayerController (之前被用作连接过程中的占位符)。此时将调用 APlayerController::BeginPlay。应当注意的是,在此 actor 上调用RPC 函数尚存在安全风险。您应当等待 AGameMode::PostLogin 被调用完成
    6. 如果一切顺利,AGameMode::PostLogin 将被调用。这时,可以放心的让服务器在此 PlayerController 上开始调用RPC 函数
      在这里插入图片描述
  • 链接信息存在哪?

    存储在PlayerController的里面,而这个PlayerController不能是随随便便创建的PlayerController,一定是客户端第一次链接到服务器,服务器同步过来的这个PlayerController(拥有连接的PlayerController)。进一步来说,这个Controller里面包含着相关的NetDriver,Connection以及Session信息。

官方建议

  • 尽可能少用RPC,在合适情况下改用RepNotify
  • 若游戏频繁调用RP图哦如C或复制函数,如tick时,则应将其设为不可靠
  • 检查Actor是否为网络角色: ROLE_Authority
  • 检查Pawn是否受本地控制:IsLocallyControlled(构造期间Pawn可能未被指定控制器,因此避免在构造函数中使用)
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Ctrlturtle

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值