• 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掉。

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

      

  • 相关阅读:
    Linux install
    plafrom library
    lua 线程
    plafrom SDK
    CSS中的focus-within伪类选择器
    网站打开速度优化_如何提高网页访问速度技巧方法总结
    网页预加载_骨架屏Skeleton Screen的实现
    SASS简介及使用方法
    什么是BFC布局——浅析BFC布局的概念以及作用
    JAVA面试题(九):JVM
  • 原文地址:https://www.cnblogs.com/NEOCSL/p/4734333.html
Copyright © 2020-2023  润新知