zoukankan      html  css  js  c++  java
  • 3:虚幻引擎网络架构:GameInfo,PlayerMove

      1.GameInfo和Network初始化

      在一个单独类中是使用WorldInfo.Game来获取当前的游戏类型的,在客户端是没有GameInfo,即WorldInfo.Game=none。而只有服务器端才会具有,因为只有服务器端规定了游戏规则。

      在游戏启动的时候,GameInfo会进行以下序列:

      - event InitGame(string options,out string ErrorMessage),即服务器启动游戏时调用这个函数,解析URL选项,如 Unreal.exe MyLevel.rnr?Game=unreali.teamgame,其中Option字符串是?game=unreali.teamgame。错误将返回失败

      - event PreLogin(string Options,string Address,out string ErrorMessage,out string FailCode), 当客户端登录时调用这个函数,使得服务器可以拒绝玩家,这是服务器可以验证玩家的密码,执行限制。

      - event Login(string Portal,string Options,out string ErrorMessage),当调用PreLogin正确后调用,负责使用Option中的参数来生成玩家,成功返回PlayerController,Login和PostLogin也负责在单机游戏中创建PlayerController

          - event PostLogin(PlayerController NewPlayer) 可以为函数赋值等操作。

      

      2.预测玩家移动

      Unreal不是使用了纯粹的客户端-服务器模式,否则玩家的运动是非常缓慢的,我估计大多数国产网络游戏使用的是这种方式(大牛勿喷哈:D)。

      若是传统的网络模式,会是这样:如果网络延迟是300ms,那么游戏延迟将会达到300ms。Unreal使用了QuakeWorld的预测方式,即在UnrealScript中进行实现。这是在PlayerController中实现的一个高级功能,而不是网络代码的功能。

      

      Unreal客户端的运动预测是基于网络代码中的复制功能设计的。在PlayerPawn中可以查看其代码,这种方法被描述为锁步,预测/校正 算法。

      客户端考虑了操作键盘,手柄,鼠标,物理力(重力,浮力,区域速度)并把它描述为3D加速度矢量。在复制函数中调用ServerMove,客户端把它的加速度及各种输入相关的信息及它当前的时间戳(WorldInfo.TimeSeconds)发送给服务器端。由于过程详细且重要,我直接将流程表复制以下方便观察:

    服务器 客户端
        ReplicateMove()
        调用这个函数替代 ProcessMove()。 根据玩家输入进行 pawn 物理更新,保存(在 PlayerController SavedMoves 中)并复制结果。 SavedMove 可以是子类,保存游戏指定的运动输入和结果。 ReplicateMove() 也会尝试结合复制的运动来保存上游带宽并改善服务器性能。
    ServerMove() <- CallServerMove()
    根据接收到的输入进行 pawn 物理更新,然后将结果与客户端发送的结果对比。 注意根据客户端计时器进行运动更新。 如果客户端已经积聚了一个严重的位置错误,那么请求校正。 否则,请求确认运动适宜。   发送一个或两个当前运动(根据帧速率和可以使用的带宽),它们附带客户端时钟时间戳记。 每次发送两个运动可以保存带宽,但是会增加校正的延迟时间。 在包丢失的情况下也可以调用 OldServerMove() 重新发送最近的“重要”运动。
    SendClientAdjustment() -> ClientAckGoodMove()
    推迟到 PlayerController 记号的末端的客户端相应可以在多个 ServerMoves() 接收到这个记号的情况下避免发送多个响应。 如果没有错误,那么确认运动适宜。   根据时间戳记的环回时间更新 ping,通过以前的时间戳记清除保存的运动。
    服务器 客户端
    SendClientAdjustment() -> ClientAdjustPosition()
    推迟到 PlayerController 记号的末端的客户端相应可以在多个 ServerMoves() 接收到这个记号的情况下避免发送多个响应。 如果有错误,请调用 ClientAdjustPosition() 确认运动适宜。   使用校正时间戳记之前的时间戳记清除 SavedMoves。 将 Pawn 移动到服务器指定的位置,然后设置 bUpdatePosition。
        ClientUpdatePosition()
        在 bUpdatePosition 为 true 的情况下通过 PlayerTick() 调用这个函数。 重新播放所有未完成的 SavedMoves 使 Pawn 返回当前客户端时间。

      在服务器端有一些非关联性的动画不需要执行,例如你在看CS中丢手雷,手雷出去但并没有看到手丢的动作,我们使用bUpdateSkelWhenNoRendered和IgnoreControllersWhenNotRendered为false来让其在服务器端不更新。

      对于尸体bTearOff=true将不会被复制到客户端,并且在已经复制了这个Actor的客户端上关闭变成一个Role_Authority。当接收到bTearOff,会调用TornOff()

      3.武器开火

      - 一旦玩家输入开火,客户端将会立即播放开火特效。并调用ServerStartFire()和ServerStopFire()函数来要求服务器开火。

      客户端有足够的信息来预测当前是否在开火,例如根据(子弹数量,武器时间状态)来预测武器是否开火。

      - 服务器Spawn Projectile,这个Projectile将会被复制到Client。

      Projectile:

      Projectile也可以很轻易的进行预测。

      bNetTemporary=true

      当被复制后,Actor Channel将会被关闭,Actor将永远不会被更新,Actor将会被client,Destroy掉。

      涉及网络部分的内容还非常的多,只有深入操作才能更好的理解和记忆。下一章将会进行实例代码。

      

  • 相关阅读:
    给出两个 非空 的链表用来表示两个非负的整数。其中,它们各自的位数是按照 逆序 的方式存储的,并且它们的每个节点只能存储 一位 数字。
    11
    实战 迁移学习 VGG19、ResNet50、InceptionV3 实践 猫狗大战 问题
    tx2系统备份与恢复
    如何在Ubuntu 18.04上安装和卸载TeamViewer
    bzoj 3732 Network (kruskal重构树)
    bzoj2152 聪聪可可 (树形dp)
    牛客 216D 消消乐 (二分图最小点覆盖)
    牛客 197E 01串
    Wannafly挑战赛23
  • 原文地址:https://www.cnblogs.com/NEOCSL/p/4734333.html
Copyright © 2011-2022 走看看