Contents
What is replication?
Put simply, replication is a way of making best use of limited bandwidth in a network game. The replication page has a more in-depth exposition of the concept – but if you're completely new to it, it's likely you'll make a few false assumptions...
The Myths of replication
If you've read a few documents on replication and looked at the nuts and bolts of it – the UnrealScript keywords and variables that are involved – then there is a very good chance you've fallen into some commmon traps.
- Having read basic replication docs, you might have imagined that clients did their own thing, more or less running a duplicate of the game and occasionally exchanging data to keep things tied together. The truth is: Clients do mostly nothing.
- You might think that a function marked as "simulated" is made to run on clients when it runs on the server. Not so – the "simulated" keyword doesn't mean that when something happens on the server, it also makes it happen on the client. The truth is: The server doesn't cause clients to simulate simulated functions.
- The "reliable if" statement doesn't state "this variable is reliable", it's an instruction to try to replicate the variable... reliably.
We'll be looking into these in more detail throughout the tutorials.
Why you need it
Why would you need replication anyway? The dedicated server has all information of all the clients (that's why the server is so called "authority") regarding gameflow and making decisions (eg does the player has the correct key to open a door, if yes, issue the open-door-command on the door object) the server can decide everything by itself only.
So when is replication (or simulation) really needed and is something you should take care of?
- When it's not already taken care of by the Epic code.
- Example: I change the actor location by a server running code only, and the new actor position is automatically replicated by the Epic code (so this is more a negative example – you dont need to handle replication in this case since Epic does it already for you).
- When it's something visible the client has to display/render. Imagine the player's computer just as a visual frontend, not more!
- Example: I want to have some "Weapon overheat function", so the temperature is somehow calulated and the rounds shot are taking into account. This is purely server side – no calculation needed on the client. When overheated, I want the weapon to glow red. "Red glow info" is visible to the player and has to be replicated to the client (since Epic is not already doing it for me).
- When you want to minimize communication between the server and the client.
- Example: A simple projectile moves in a straight line with a fixed velocity until it hits level geometry. That's predictable movement, and there's no point in having the server send constant location updates to the clients; so I just set the starting location, direction and velocity of the projectile and let the client simulate the movement by itself from there on. (Actually, virtually all of the game's projectiles are done that way, even those with more complicated movement trajectories such as the Flak secondary fire.)
So you have only to consider replication in the second and third case – the second in order to display something on the clientside which is not already covered by the epic code (something new!), and the third to cleverly reduce network load. Generally – if five percent of you code will handle with replication I would consider it much.
Multiple copies
In a network game of UT, there are several machines involved. Simplifying a little, these are servers and clients. Each machine has it's own actors, and each actor exists on a particular machine.
This means that an actor such as a player is actually multiple actors, one on each machine. These multiple copies know that they correspond to one another. How they exchange information to make sure they keep in sync is the basic idea of replication.
However, client versions generally don't do much (First Myth). Furthermore, you the programmer don't really have access to the heart of replication. You can't say in UnrealScript: "send this piece of information across the network now".
Replication is rather like having a number of islands and some bottles to send messages between them. You tell the engine it should try to keep certain things in sync, and it will work the bottles and do its best – but there are no guarantees. You don't know how many bottles there are or when they are sent out, or when they are received.
The methods of replication
So now you know that clients do nothing (First Myth), the question is: how do you actually make them do something?
- Replicate variable values.
When a variable value changes and has a replication statement such as reliable if (Role == ROLE_Authority)
, the engine checks – at its own discretion, and subject to certain networking-related Actor variables – its replication condition (here: Role == ROLE_Authority
). If a variable changes often, those checks happen frequently.
If the replication condition is fulfilled, the engine sends an update of that variable's value over the network to the other side (in our case: from the server to the client). If the variable has a special meaning such as Location
or Rotation
, the client copy will change its appearance as soon as it receives the update.
- Mark event functions as "simulated."
If you mark an event function as "simulated," however, that tells the engine to call that event function client-side too (whenever the event happens, client-side). Then the UnrealScript code which is executed client-side can affect the client copy of the actor directly (or call other non-event functions client-side if they have been marked as "simulated" too).
- Replicate function calls.
It's also possible to call a function on the server and have it execute on the one client who "owns" that actor (i.e. the client whose player is – directly or indirectly – the Owner
of that actor).
That happens asynchronously, meaning that "calling the function on the server" just makes the engine send a notification over the network to the affected client and return immediately without any feedback of whether and when the function was actually executed client-side; because of that, it's not possible to get return values from replicated functions.
Next Step
The next tutorial is the ProjectileDestroyerVolume actor.
Related Topics
- Replication
- Replication Block
- Role and RemoteRole, and NetMode.
- Netcode Idioms
- Replication Examples
Planning
- We should have examples of the following:
- actors that exist on the server only
- actors that exist on the server and clients
- actors that are spawned clientside only
- actors that are spawned on owning clients only
- We should also give examples of how to:
- call a function on the server from a client via function replication
- call a function on an owning client via function replication
- trigger function calls on clients with PostNetReceive()
Discussion
Tarquin: I would really like a basic tutorial on replication: maybe something like a Trigger actor that does something to all players when touched.
NickR: I wouldn't mind some small replication examples just showing one type replication related code. Like when the simulated key word should be used or if static functions can be called from either the client or server and run on either.
VitalOverdose I think the ONSMineProjectile is a very good example for replication.
Foxpaw: I'm not sure about tutorials, but those are (fairly) easily explained. Simulated functions run on actors with ROLE_SimulatedProxy or better. However, only if they are called from another simulated function. Entry points like Tick can be declared as simulated when you override them to facilitate this. A short example:
simulated function Tick( float Delta ) { Super.Tick( Delta ); DoStuffOnServerOnly(); DoStuffOnBoth(); } // Called from a simulated function, but not simulated itself, // the engine skips over this function on clients. (or rather, // the non-authority version, which is usually the client) function DoStuffOnServerOnly() { DoStuffOnClient(); } // A simulated function getting called from another simulated // function. This gets called on both machines. simulated function DoStuffOnBoth() { } // Oops! This is a simulated function, but gets called from a // non-simulated function, so although it COULD run on a client // (because it's simulated) the code that calls it doesn't run // on the client and so this won't ever get called. simulated function DoStuffOnClient() { }
Static functions on the other hand, have no relation to replication and are functions that exist outside the context of an object. Static functions can't get replicated, obviously, because they aren't associated with any particular instance of an object. They can access only default variables and stuff. See Static Function and Simulated Function.
Also, feel free to refactor this somewhere or expand it into a full tutorial.. it's more a demonstration at the moment.
Tarquin: Thanks... but see, you've alreayd lost RepliN00bs with this: run on actors with ROLE_SimulatedProxy or better.... how does Replication actually WORK? Should we imagine multiple facets of the same actor on different machines, or many actors on different machines that somehow correspond to each other?
Foxpaw: Well, they're different actors, but they have a unique identifier so they "correspond" to each other. An actors Role variable determines it's replication behaviour. ROLE_Authority is usually the one on the server, and it runs all functions, simulated or not. ROLE_SimulatedProxy is usually on the client, and runs only simulated functions. ROLE_DumbProxy runs no functions, but still replicates variables. ROLE_None replicates nothing.
Tarquin: I simply don't understand how to visualize what is going on with replication. I'm used to thinking of an actor as a script that is running. How do I think of a replicated actor? Two scripts in tandem? How? Take something like this:
replication { reliable if (Role == ROLE_Authority) Foo, Bar; }
What is this an instruction to? When is this parsed? What does it cause to happen?
Mychaeel: The engine executes the condition in this statement at its own discretion. It's not clearly specified when that happens; the documentation only says that it happens, and that it happens frequently.
Each machine in a network game for which an actor is "relevant" has a copy of that actor. For simplicity, let's assume a single client here – the server spawns the actor, and the server engine tells the client that there's a new actor around. So we have two copies of the same actor: One on the server, and one on the client. The engines of both machines know that those two copies correspond to each other, but by itself that doesn't mean a lot – specifically, it doesn't mean that the client copy is automatically kept in sync with the server copy.
Apart from that, nothing special happens. The server copy runs its events and other code, and the client copy just sits there, doing nothing. There are, however, several ways to make the client copy do something:
- Replicate variable values.
When a variable value changes and has a replication statement such as Foo
and Bar
above, the engine checks – at its own discretion, and subject to certain networking-related Actor variables – its replication condition (here: Role == ROLE_Authority
). If a variable changes often, those checks happen frequently.
If the replication condition is fulfilled, the engine sends an update of that variable's value over the network to the other side (in our case: from the server to the client). If the variable has a special meaning such as Location
or Rotation
, the client copy will change its appearance as soon as it receives the update.
- Mark event functions as "simulated."
If you mark an event function as "simulated," however, that tells the engine to call that event function client-side too (whenever the event happens, client-side). Then the UnrealScript code which is executed client-side can affect the client copy of the actor directly (or call other non-event functions client-side if they have been marked as "simulated" too).
- Replicate function calls.
It's also possible to call a function on the server and have it execute on the one client who "owns" that actor (i.e. the client whose player is – directly or indirectly – the Owner
of that actor).
That happens asynchronously, meaning that "calling the function on the server" just makes the engine send a notification over the network to the affected client and return immediately without any feedback of whether and when the function was actually executed client-side; because of that, it's not possible to get return values from replicated functions.
So, the server and client copies of the same actor are basically independent entities – but you can use the techniques explained above to keep them in sync on both machines.
Tarquin: This is starting to make sense! When you say "does nothing" – even if affected by other actors? If I have a player and a trigger, when the player touches the trigger, nothing happens on the client actors, only on the server?
2nd question: is there a way for the server actor to make something happen on the client actor?
Mychaeel: "Nothing" means "nothing." A server-side trigger will only trigger server-side; plus, only code within a simulated function or simulated state can (or from the engine's point of view: may) be executed client-side at all (but it's a common misconception that making a function "simulated" will magically execute it client-side – there's no such magic, unless that function happens to be an engine event and that event is caused client-side).
Virtually all interaction between actors happens purely server-side, with the client copy being hardly ever any more than just a visual representation of the server copy.
And actually most of what I wrote above is about how the server actor can make something happen on the client actor – starting from "There are, however"...
Tarquin: Based on what I now know, I can identify two major newbie mistakes in understanding replication:
- the "reliable if" statement doesn't state "this variable is reliable", it's an instruction to try to replicate the variable... reliably. Not sure if that makes sense, but I found out I've been completely misreading the meaning of that.
- clients do mostly nothing. Having read basic replication docs, I imagined that clients did their own thing, more or less running a duplicate of the game and occasionally echanging data to keep things tied together.
I made a simple map with a Trigger to test something for Jailbreak, and I ran it as a netgame. The Trigger actor, that's I'd set bHidden=False on, wasn't visible when I played. Am I right in thinking that the Trigger wasn't even there on the client?
Given this, could someone with knowlegde of replication conceive of a simple situation where an actor such as a Trigger or Keypoint class might require some replication, and I'll see if I can write a tutorial on it?
Mychaeel: Yes, you're right – the Trigger wasn't even there on the clients. (You have to set bNoDelete=True to prevent the engine from discarding it on clients after it was loaded with the map file; or bAlwaysRelevant=True to have the server replicate it to all clients again after the map was loaded. But since a Trigger is only acting server-side anyway, neither of those options makes sense in this context.)
Tarquin: Do we have a reference page of events that can be used as simulated? Are they the ones markes as [event] on Actor/Methods?
Mychaeel: The important difference between "event function" and "normal function" here is only that an event is automatically called by the engine. Just think about it – any function that's called directly by engine code qualifies, starting from PreBeginPlay over Tick and Timer to Destroyed... and any other, self-defined function doesn't (like MyOwnFunction or CanBeJailed).
Tarquin: How do you spawn an actor only on a client, or only on a particular client? Is this possible? I think the 3rd newbie mistake is supposing that the ways in which you can pass information from server to client are not as restricted as they are.
Mychaeel: To spawn an actor only on a (particular) client... just do so. :-) You can't directly initiate that from a server (as in "server, tell client XY to spawn this actor"); but you can spawn it directly from client-side code on that particular client.
Tarquin: For the first tutorial, I think I'll do a Volume that destroys incoming projectiles. It's fairly simple, but exposes some important concepts (I think... if I've got it right...). Work in progress: ProjectileDestroyerVolume. And I'll be cleaning up this page too ....
Lilguy: Hey, I just added a bit, hope it's alright. since the "myths" section listed a bunch of facts, not myths, I changed it to "some facts of replication." I also made a little list of examples we should make that would be helpful. Most of them could probably be copied and pasted from Epic's code, but we could make some simple examples of each one too.
Tarquin: Hmm... well, I like the title so I've put it back, but you are quite right, I wrote them as facts, which could be very confusing. I have rephrased the first two – is that better? I'm working on the first tutorial in the series. I think the 2nd one should involve the replication block with a replicated variable, somehow – but I don't know what sort of example would be good. After that, I have no idea... :)
Lilguy:Heh, sorry 'bout that, I had actually kinda liked the title too. That'll do fine...
Perhaps for the second example, there could be some sort of street light or something, with 2 alternate textures that randomly switch back and forth at random intervals. They would only do this if the light was in "damaged mode" which would be signaled by bDamaged, a reliably replicated variable. I guess maybe I should stop talking and start coding, lol.
Foxpaw: I have to disagree with the assertion that clients do mostly nothing. Clients handle physics just like the server. In UT2003, some actors are handled almost entirely client-side. (general projectiles, for instance, are handled almost entirely client side, with the exception being the actual application of damage.) An efficient replication system should have nearly everything handled client side, with only critical values replicated.
Lilguy: Yeah, I kind of agree there. SimulatedProxy actors are given an initial physical state, then they're only updated periodically to make sure everything matches up. And there are a lot of clientside only actors, such as almost all emitter effects, the hud, interactions, etc. Perhaps it could be ammended to say that clients are in charge of almost nothing, since the server is usually the ultimate authority on the state of actors that exist on the client and actors. It's really best to always think about this when you're coding, and keep in mind what code should be running on the server, and what should be running on the client, and to program it likewise.
Tarquin: I think the point is that clients will do nothing unless told to. Using "SimulatedProxy" is telling it. A "client-side effect" has to be MADE to be client-side.
Andreas: Catching up with replication - I would like to add some more basic ideas to replication?
Tarquin: inserted at the top :) BTW, please review Wiki markup :)
Andreas: thanks for layouting - reading it the example 1 was not that clear - tried to clarify it a bit. Maybe the link
http://unreal.epicgames.com/Network.htm could be included - it helped me quite a bit.
Legal: Threadmode anyone? This page needs some cleaning up, perhaps a Refractor Me tag would be in order? Also, to add to the discussion, coders need to make sure as much as possible is done client side and with as little code as possible. Some mods which could have impressed requires so much bandwidth that few people get ping over 200.
Andreas: Im not a wikiexpert (due to limited sparetime I have) - but if it improves - sure - I agree. I disagree on doing everything clientside - the goal of writing a program using replication is to minimise networktraffic. So the server would be my first place (assuming it has enough cpu power) since 1. it has a complete view of the game-status and 2. epic did already implement "clever" methods to reduce the network load (by not updating clients with data they dont need anyways, since they cannot see the actor and so on) I would not want to reinvent. As a coder I would ask me what tasks have to be done (see weapon overheat example), and where I can split server/client in order to minimize communciation. There is no way around updating the client as far it considers visual informations - the client is the visual frontend - but upon everything else the coder is free to decide where to perform the tasks.
Andreas: To add, replication (especially simulated functions running on the client) might be usefull when someone wants to give clients different views or play different sounds locally.
FatalOverdose: In the first few paragraphs you say 'The truth is: Clients do mostly nothing.' and then a little further down you have 'However, client versions generally don't do much (First Myth).'
. its a bit confusing
Solid Snake: This was asked by Mychaeel a long time ago, so I've converted my post into a wiki page, found here A Study Of Replication
Tarquin: I think a simple tutorial would be fixing the example on Using LocalMessages to broadcast the message so clients can see it. Can anyone help me by suggesting how it might be done?
Ransico: Something that has bothered me for a long time, is there is no info on how to get something to run properly on -only- the client... for example, I was stuck on how to get a custom LOD actor working. The issue I had, was that the tick and timer events would never get called on the client.
The fix turned out to be that the client was deleting the object soon after its creation on the client, no matter what combo of defaultproperty switches I used.
There may be a better way to do it, but I set bNoDelete=true and it solved my problem. The entire source can be found here - someone else may find it useful, it also tells you how to make something run on the client: Ransico/LODMesh
Vitaloverdose: The page is called 'introduction to replication' so it was the first document i read on the subject but it begins with "If you've read a few documents on replication". Maybe the 'myths of replication' bit might be better off further into the page or as part of a summery as its not introducing the subject so much as reviewing it.Im sure the page is very helpfull for the reader with prior knowledge of the subject but could be very confusing/unhelpful to anyone looking into the issue for the first time as it is referrencing aspects of replication that havent been explained at this point.
Kiff: I attempted making a tutorial for function calls using PostNetReceive. It might be a little cluttered, so feel free to make suggestions and/or corrections. Kiff
Category:Legacy To Do – Work to organize according to Replication/Discussing.