Introduction to replication 翻译
翻译自用,还有很多谬误之处,敬请甄别,转载请注明出处
Introduction to replication (replication介绍)
Replication is one of the most important concepts in Unreal Engine games as it is the basis for keeping game clients synchronized with the game server in network games.
Replication在网络游戏中,作为保持客户端与服务端同步的基础,是虚幻引擎中一个重要的概念,
While details have slightly evolved between engine generations, the basic principles are still the same. Generally there are three major types of replication: actor replication, variable value replication and function
call replication. Replication can only go from the server to one or more clients, or from one client to the server, but never from one client to another directly. Replication does not happen immediately, but is delayed until the end of the
tick, when things are replicated to the remote side. At the start of the next tick, things received from the remote side take effect.
纵然经过数代引擎的更新升级,有很多细节都发生了轻微的变化,但基本原理都是一样的。基本上有三种类型的replication:actor replication, variable value replication and function
Call repolication。Replication 只能从服务端到一个或多个客户端,或者从一个客户端到服务端,但绝不会从一个客户端直接到另外一个客户端。Replication 不是即刻发生的,而是被推迟到了
直到tick结束,他们被复制到了远端之后。下一次tick开始时,things又收到远程端发生的事情。
Actor replication[edit] Actor型的replication
Before any other kind of replication is possible, there needs to be a common ground the server and client can base their communication on. This common ground are actor instances. Variable values and function calls can only be
replicated if both sides know which actor instance the replicated value or function call belongs to.
在任何其他种类的replication可能之前,需要有一个共同的场所用以作为服务器和客户端交流的基础。这个共同的场所就是actor实例。只有在双方都知道了被复制(replicated)的值或者函数调用属于哪一个actor实例之后,变量值和函数调用才能被复制(replicated)
Actor classes that have bStatic or bNoDelete set to True can neither be created nor destroyed at runtime. We'll call these "persistent actors" from here on, as opposed to non-persistent actors that have both bStatic and bNoDelete set to False. Persistent actors make replication pretty simple as they already exist when the level is loaded and they will continue to exist until a different level is loaded or the game exits.
Actor类拥有bStatic 或者 bNoDelete ,如果设置为true,则在运行时无法被创建或销毁。我们称之为"持久的actors",相对的,非持久的acotrs的bStatic 和 bNoDelete 都被设置成了False。持久的actors把replication变得非常简单因为他们在关卡加载之初就已经存在了,并且直到一个不同的关卡被加载或者游戏退出,他们才会退出。
Non-persistent actors, on the other hand, may initially exist in the level but could get destroyed at runtime. Or new instances of a non-persistent actor class are spawned at runtime. Imagine a non-persistent actor that initially existed in the current level, but gets destroyed on the server. Now if a client connects, what will happen to the clientside version of this actor? The Unreal Engine takes a conservative approach here: When a level is loaded on a client, all non-persistent actors are removed there. Then the server will replicate non-persistent actors back to the client without making a difference between initially existing actor and actors spawned at runtime.
另一方面,非持久的actor,可以从一开始就存在于关卡之中,但可以在运行时被摧毁。或者也可以在运行时被创生。想想一下,一个非持久的acotr一开始就存在于当前的关卡之中,但是在服务器里被摧毁了。现在如果客户端练上来了,客户端那边的这个actor版本会发生什么呢?虚幻引擎在这一点上采取了一个保守的做法:当一个关卡在客户端被载入时,所有非持久的actor都会被移除。接着服务器会将非持久的actor复制回来到客户端,并且让一切看起来没有区别,让这些在运行时创生的actor看起来就像是一开始就存在一样。
Actors can't be replicated all the time. Especially when a client connects the server would have to send a great number of actors, taking up valuable bandwidth. The trick is, that the server will only replicate an actor to a specific client if the actor is "relevant" to that client. Many actors are completely excluded from replication because clients simply do not need them. Usually, when an actor is no longer relevant, it is removed from the client again, but there are also exceptions. If a replicated actor is destroyed on the server, it will also be destroyed on all clients it is currently relevant to.
Actors 不能被一直复制(replicated)。特别是当一个客户端连上服务器之后将会发送大量的actor,占用的带宽非常可观的情况下。技巧在于,仅仅当某个actor和特定的客户端发生关联(relevant)时,服务器才复制(replicate)这个actor到这个客户端。由于很多actor客户端根本就不需要,所以它们完全不被复制(replicate)。通常,当一个actor不在被关联(relevant)之后,它就会被这个客户端移除,但也有例外。如果一个被复制(replicated)的actor在服务器上被摧毁了,它也将会在所有关联(relevant)的客户端上被摧毁。
The most important exception are "net-temporary" actors, i.e. instances of actor classes that have bNetTemporary set to True. A net-temporary actor is replicated to any client it becomes relevant to, but after the initial data the client takes full control of the actor, including its eventual destruction. This is mostly used for simple projectiles that fly in a straight line and explode on contact with an object.
最重要的例外就是"net-temporary" actors,比如说,那些将bNetTemporary 设置为true的actor实例。一个net-temporary actor会被复制(replicated )到任何关联的客户端上,但在数据初始化之后,客户端就完全取得这个actor的控制权,包括它最终的销毁。这最常用于一些简单的投射物比如做直线飞行并且在接触物体后爆炸。
Another exception are torn-off actors in Unreal Engine 2 and later. These start out as regular non-persistent actors, but at some point the server sets the actor's bTearOff property to True. This cuts off the connection to clients after a final network update for this actor. When an actor is torn off, it will behave like a locally-spawned, non-replicated actor on the server and all clients it was relevant to at the time of tearing off. Unlike net-temporary actors, a torn-off actor can not become relevant to other clients that didn't know the actor before it was torn off. An example of actors that are torn off at some point are the xPawn class from UT2003 and UT2004. When an xPawn dies, it is torn off and clients independently handle the ragdoll physics, while a dedicated server gets rid of the xPawn actor pretty quickly.
另一个例外,就是虚幻引擎2和之后版本中的torn-off(撕下?) actors。它们一开始和常规的非持久性actor别无二致,但在某些时刻,服务器会将这些actor的bTearOff 属性设置为True。这将导致,在最后一次网络更新这个actor之后,就斩断了和客户端的链接。当一个actor torn off之后,它就会在服务器上和所有相关的客户端上,在tearing off时, 表现得像一个本地诞生的,不可能复制的actor。和net-temporary actors不同,一个torn-off actor不能关联任何一个其他的,在它被torn off之前就认识它的客户端。一个actor被torn off at some point 的例子就是来自UT2003和UT2004的xPawn类 。当xPawn死亡时,它就会被torn off并且客户端独自处理布娃娃物理,与此同时服务器也会相当快地清除这个xPawn。
Variable value replication[edit] 变量型的replication
Values stored in class variables can be replicated from the server to any client if the actor is either persistent or currently relevant to the target client. Variable replication from client to server is possible (but discouraged) in Unreal Engine 1, but not in any later engine generation. Apart from the initial data when an actor is replicated to a client, variable replication does not happen instantly when a variable changes. Only once in a while, as specified by the NetUpdateFrequency property, the server checks for changed variables and replicates their new values.
被存储在类中的变量可以从服务端被复制(replicated)到任何客户端,只要这个actor是持久的,或者当前被关联到了目标客户端。在虚幻引擎1中,变量型的replication,是可以从客户端到服务端的(但不鼓励这么做),但是随后各代的引擎就不是这么一个情况了。当一个actor被复制(replicated)到客户端,除去那些初始化数据,变量型的replication并不会直接发生于变量改变时。只有在偶尔,当特定的NetUpdateFrequency 属性,服务器检查这个特定的属性的值得改变时,会复制(replicates)它们新的值。
Before a variable value is replicated, the client assumes it to have the default value as specified in the defaultproperties block. This also goes for actors that initially exist in the map because the mapper added them in the editor. Generally, variable values are only replicated after they were changed for that actor instance at runtime. Values of configurable or localized variables don't count as "changed" just because their configured/localized default value is different from their original defaultproperties value!
在一个变量被复制(replicated)之前,客户端假设它defaultproperties block在含有一个预设的值。这同样适用于actor在map中初始化的情况,因为mapper 将他们 added 到了编辑器中。一般来说,变量的值只有在运行时,它们为了actor实例而被改变时才会被复制(replicated )。值得预先配置,或者变量的本地化,不能仅仅因为这些值和原始的默认值不同, 就被算作"变量值的改变" 。
The exact conditions for when to replicate a variable's value can be specified in the replication block of the class declaring the variable. It is not possible to change this replication condition for subclasses.The reliable and unreliable keywords that need to be specified in the replication block of Unreal Engine 1 and 2 have no meaning for replicated variables.
复制(replicate )一个变量的值的准确的条件,可以在类的replication block声明变量时明确指出。子类想要改变这一条件是不可能的。reliable 和 unreliable 这两个需要指明的关键词,在虚幻引擎1和2中对于replicated 变量是没有意义的。
If the size of their values allows it, multiple changed variables of a single actor instance are replicated together. Elements of a static array variable are replicated individually and only if they actually changed. The value of a struct variable is always replicated as a unit. If the value is too large to fit into a single packet, it will never get replicated! Similar rules apply to strings, which can only be replicated if their length doesn't exceed the packet size. Dynamic arrays do not support replication at all. Attempting to replicate a dynamic array variable will have no effect, trying to replicate a dynamic array as part of a struct will result in an array empty on the receiving side.
Function call replication[edit]
Function calls can be used for a more responsive and structured communication between the server and individual clients. Whether calls to a function are replicated must be specified in the class that originally declared the function. Subclasses can neither change existing replication declarations, nor can they make overridden functions replicated. Also, in order for a function to actually get replicated to the remote side, the actor mus be directly or indirectly owned by the client involved in the replication, i.e. the client's PlayerPawn/PlayerController is either the actor itself or can be reached by traversing the actor's Owner "chain".
Like replicated variables, the replication of a function call can be tied to certain conditions. In Unreal Engine 1 and 2 this condition is specified via the replication block and typically involves comparing the actor's Role to the value ROLE_Authority
, Unreal Engine 3 provides the special function modifiers client and server instead. Additionally a function can be replicated reliably or unreliably, which is specified by the keywords reliable and unreliable in front of the replication condition or as additional modifier in the UE3 function declaration.
Function calls are always replicated asynchronously. As a result, a replicated function call returns immediately. If the function has a return type, the corresponding type's null value is returned locally. Whatever the function returns on the remote side (i.e. where it is executed) will be discarded there. If the replication conditions for a replicated function call aren't met, the function is executed locally as if it was a non-replicated function. You can use this fact to check whether a function was actually replicated or not:
reliable client function bool DoSomething()
{
return true;
}
if (DoSomething()) {
// function returned True, so it was executed locally
}
else {
// function returned the null value (i.e. False), so it was replicated
}
Note that regular calling restrictions apply for replicated functions. For example if a function is replicated to a client where the actor's local Role is ROLE_SimulatedProxy
, but the function is not declared as simulated, it will not be executed. Conveniently the UE3 modifier client already implies the simulated modifier, so this is more of a problem in earlier engine generations.