In a multiplayer session, game state information is communicated between multiple machines over an internet connection rather than residing solely on a single computer.
尽早规划多人
因为多人游戏当做单机游戏一样可以正常运作,反之则不一定,因此如果程序将来有多人需求的话,应尽早在最开始就朝着多人的方向来规划。
Client-Server模型
In a single-player or local multiplayer game, your game is run locally on a standalone game. Players connect input to a single computer and control everything on it directly, and everything in the game, including the Actors, the world, and the user interface for each player, exists on that local machine.
Single-player and local multiplayer take place on only one machine.
In network multiplayer, the game takes place between a server (1) and several clients (2) that are connected to it. The server processes gameplay, and the clients show the game to users.
基本网络概念
Network Modes and Server Types
Network mode describes a computer's relationship to a network multiplayer session.
Network Mode |
Description |
Standalone |
不接收远程终端的连接。所有Player均严格限定为local玩家。单人游戏和local多人游戏采用该模式。同时运行server-side logic和client-side logic为local players。 |
Client |
网络多人会话中连接到server的终端。不运行server-side logic。 |
Listen Server |
网络多人会话的服务器。接收远程终端的连接,同时有local玩家运行在该server上。 |
Dedicated Server |
网络多人会话的服务器。接收远程终端的连接,但不运行local players。因此,它舍弃了graphics, sound, input and other other player-oriented features in order to run more effeciently. |
Actor Replication
Replication是网络会话中在多台机器之间同步游戏状态信息的过程。同步也可以叫reproducing. 默认绝大部分Actor的replication配置是关闭的,需要手动激活。
以下是绝大部分的replication features:
Replication Feature |
Description |
Creation and Destruction |
当一个激活了replication的Actor母版在server端产生时,会自动创建其远程代理在各个客户终端上。该Actor会replicate信息到那些远程代理。如果销毁母版Actor,远端代理会被自动销毁。 |
Movement Replication |
如果母版Actor激活了Replicate Movement属性(或者bReplicateMovement=true in C++),它会自动replicate其Location,Rotation,Velocity到远端代理。 |
Variable Replication |
激活了Replicate的变量属性,会自动replicate其值从母版Actor到远端代理,当值变时。 |
Component Replication |
Actor的Components的Replication是作为其所属的Actor的Replication的一部分。如果母版Actor没有激活Replication配置,那其包含的Components自然就不会有Replication发生。Component里的Variable的Replication同上。 |
Remote Procedure Calls(RPCs) |
|
Several common features of Actors, Pawns, and Characters do not replicate:
- Skeletal Mesh and Static Mesh Components
- Materials
- Animation Blueprints
- Particle Systems
- Sound Emitters
- Physics Objects
Each of these runs separately on all clients. However, if the variables that drive these visual elements are replicated, it will ensure that all client has the same information and therefore simulates them in approximately the same way.
Network Role and Authority
一个Actor的Network Role用于确定网络游戏中的哪台机器拥有Actor的控制权。典型的,一个authoritative Actor控制着该Actor的state,其会replicate information到游戏网络中的其他机器。而一个remote proxy则是远端机器上的一个拷贝,其接收replicated information从authoritative Actor。
Actor的LocalRole和RemoteRole变量用于追踪这些,其合法取值如下:
Network Role |
Description |
None |
The Actor has no role in a network game and does not replicate. |
Authority |
The Actor is authoritative and replicates its information to remote proxies of it on other machines. |
Simulated Proxy |
The Actor is a remote proxy that is controlled entirely by an authoritative Actor on another machine. Most Actors in a network game, like pickups, projectiles, or interactive objects, will appear as Simulated Proxies on remote clients. |
Autonomous Proxy |
The Actor is a remote proxy that is capable of performing some functions locally, but receives corrections from an authoritative Actor. Autonomous Proxy is usually reserved for Actors under the direct control of a player, like Pawns. |
UE引擎默认使用server-authoritative模型,就是说server总是拥有game state的控制权限,且information总是从server同步到clients。你可以预期server上的Actor的LocalRole属性值为Authority,相应的,也可以预期remote clients上的Proxies的LocalRole属性值为Simulated或Autonomous Proxy。
Client Ownership
终端的所有权。网络游戏里的每个Pawn都是归某个特定client机器上的一个PlayerController所有的.相关
Any time that Pawn calls a client-only function, it will be directed only to the owning player's machine no matter which machine calls the function. Actors that have their Owner variable set to a specific Pawn belong to that Pawn's owning client by association, and will also direct client-only functions to their owner's machine. 这两句话很复杂,经过测试表明:ListenServer上的Pawn的Owner属性值为ListenServer上的PlayerController,server上有3个Pawn的话,其Owner分别对应3个PlayerController(至少在ListenServer的情形里是这样),而remote client里只有一个Pawn的Owner属性有值(该Pawn的IsLocallyControlled属性为True),且值是该remote client上的PlayerController,这个client里的其他Pawn的Owner属性值均为空(这些Pawn的IsLocallyControlled属性为False)。Pawn里设置了一个ClientOnlyFn函数,功能为移动场景里的一个Cube,在remote client里按键触发一个操作:寻找一个IsLocallyControlled属性为False的Pawn,调用该Pawn的ClientOnlyFn函数,结果是只有该remote client里的Cube被移动了=>这表明该Pawn的这个ClientOnlyFn函数在这个remote client上起作用了。将remote client里的按键触发操作改为:寻找一个IsLocallyControlled属性为True的Pawn,调用该Pawn的ClientOnlyFn函数,结果仍然是只有该remote client里的Cube被移动了=>这两种按键动作都表明,ClientOnlyFn函数在哪个client上调用,就在哪个client上执行。这里需要追加一句:这个按键动作在server上执行时,只有server上的Cube被移动,结论不变。因为server也是一个client。还应做个测试:在Server上找到一个Pawn,其IsLocallyControlled为false,对该Pawn调用ClientOnlyFn函数试试,预期只有其对应的client机器上会执行逻辑。
不要在Pawn的构造函数里使用IsLocallyControlled,因为此时该Pawn可能尚未分配给任何Controller。 这种用法可能导致应用逻辑错误。
Relevance and Priority
相关性和优先级。相关性是Actor的性质。相关是指与Player相关。而Player在引擎中有对应的实体存在,比如BoundingBox。因此有规定:如果一个Actor不被任何Players拥有(见上一节的Client Ownership。Player(玩家)通过PlayerController将自己的操控动作引入UE引擎,如果该PlayerController拥有了一个Pawn,那么就认定该Player拥有了该Pawn),并且该Actor不在Players的对应实体附近,那么就定义该Actor没有相关性,该Actor就叫Non-relevant Actor。这个性质用于replication时,剔除掉non-relevant Actor,节省带宽。就像渲染时,剔除掉当前相机视锥体外的Actor,提高渲染效率,对应到这里就是提高replication有效性。被认定为为Non-relevant的Actor仍然存在于server上,且能影响authoritative game state,但不会向clients replicating信息,直到有players靠近该Actor。你可以手动控制relevance通过重载IsNetRelevantFor函数。通过NetCullDistanceSquared属性值来定义多远的距离被视为与player太远。
尽管有了相关性这么个概念,但在宽带不给力时,即便剔除了Non-relevant Actors,也无法在一帧内将所有的relevant Actor给replicating出去。那么,这种情况下,又提出了Priority的概念,用于决定relevant-Actors中哪些优先replicating。默认下:Pawns和PlayerControllers有最高的NetPriority,其值为3.0,同时base Actors的NetPriority为1.0. 如果一个relevant-Actor久未得rep,则其priority会越变越高直到其被成功rep一下。
Variable Replication
标记了Replicated的变量或对象引用,才会被rep机制处理。当authoritative Actor(注意这个前提)的这种变量的值发生改变时,这个变动会从authoritative Actor自动发送到其remote proxies。
RepNotifies
可以经过一番设置后,使得变量的变化在从server端的authoritative Actor发送到remote proxies时,自动触发remote端的对应的RepNotifies函数。
Remote Procedure Calls (RPCs)
标记了replication的函数,一般指Actor的函数。
RPC Type |
Description |
Server |
Called only on the server that is hosting the game |
Client |
Called only on the client that owns the Actor that the function belongs to. If the Actor has no owning connections, this logic will not be executed. |
Called on all clients that are connected to the server as well as the server itself. |
蓝图里的事件和函数在replication方面有相同的属性设置。
Reliability
RPCs必须指定reliable或unreliable属性。
- unreliable就像UDP,适用于那些不是特别重要的且调用非常频繁的RPC,比如Actor movement就是一个例子。
- reliable就像TCP,适用于那些非常重要但调用没那么频繁的RPC,比如碰撞事件、武器开火和停火、创建Actors等。
reliable的RPCs在被成功接收前,会一直处于队列之中。因此,过度使用reliable,可能会发生queue溢出。
Validation
上面代码中出现的WithValidation指示符是用来说明那个UFUNCTION函数不仅有_Implemetation后缀的同名函数,还有一个_Validation后缀的同名函数,这个validation函数用来验证RPC函数的参数,这个函数返回True的话,才会继续调用后面的implementation函数。否则,不调用。
Tips and Further Reading
The following are basic guidelines for implementing efficient and consistent multiplayer systems in your games.
Basic Replicated Actor Checklist
基本的Actor Replication配置实施清单:
- 设置Actor的Replicated设置为True
- 如果这个Replicated Actor会有移动的需求,那就将Replicates Movement也置为True
- 创建和销毁Replicated Actor时,一定要确保是在Server上进行
- 将需要在多个机器间同步的变量都设置为replicated
- 尽量使用UE提供的Movement组件,因为它就是专为replication构建的
- 如果你使用server-authoriative模型,一定要确保玩家能执行的任何动作都在server上触发
Networking Tips
尽可能少用RPCs,用RepNotify替代。
- 尤其谨慎地使用Multicast函数,因为它会给session里的每一个client增加额外的网络负担
- Server-only的逻辑不一定要实现为Server-RPC方式,一个只会运行在server上的non-replicated函数能达到同样的目的
- 严格控制玩家输入触发Reliable-RPCs的频率。玩家的快速按键可能会迅速撑爆Reliable-RPCs队列。
- 高频触发的RPCs,应该置为unreliable。比如Tick里的RPCs调用
通过在server上的Authoritative-Actor修改RepNotify变量,将响应动作写在OnRepNotified函数里,可以避免一些动作的循环调用
通过检查Actor的NetworkRole是否为ROLE_Authority,可以灵活地指定函数是在server或是client端执行
通过Pawn的IsLocallyControlled属性,可以判断该Pawn是否被该client端拥有
避免在构造函数里使用IsLocallyControlled,理由上面有讲过