Multiplayer in Unreal Engine: How to Understand Network Replication

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments

This is actually a really good video, I don't think you missed much out at all.

Any beginners looking to get into UE4 networking should definitely start here, wish it was around when I started.

👍︎︎ 4 👤︎︎ u/MissileAlert 📅︎︎ Dec 18 2020 🗫︎ replies

u are the best! thanks

👍︎︎ 1 👤︎︎ u/Somit_ 📅︎︎ Dec 18 2020 🗫︎ replies

This is pretty darn good, both c++ and blueprints way of thinking, thank you.

It would be interesting if you could explain, for example, the shooting/losing health, or analyze the UE shooting project.

The voice/mic setup is perfect, keep it up!

👍︎︎ 1 👤︎︎ u/NailedApex 📅︎︎ Dec 18 2020 🗫︎ replies

One of the best explanations and overview video of Unreals replication system out there! Thank you for this :)

👍︎︎ 1 👤︎︎ u/ryanmaugv1 📅︎︎ Dec 19 2020 🗫︎ replies
Captions
one of unreal engine's most compelling features is its built-in networking support to borrow a phrase from the american auto industry with unreal multiplayer comes standard in a multiplayer game you have multiple instances of the same game running in tandem that could be different processes on the same machine or different computers on the same local network or players on different continents playing over the internet in any case those different game instances have to talk to one another and build a consistent picture of a shared world in unreal's network model players connect to a server and the server maintains the authoritative state of the world when something changes on the server those changes will be propagated down to clients as needed as part of a process called a replication unreal's replication system is a first class feature that's naturally integrated with game code you can easily develop a multiplayer game and you're not managing client connections opening sockets or sending packets and you're not dealing with serialization encoding and byte order or time stamping reordering and routing you can just say i want this property replicated and it'll be replicated replication can seem pretty complex at first glance but once you understand the basic concepts it's really not that difficult in most cases so i'd like to help you wrap your head around unreal's replication system how it works and how to use it first let's talk about net mode the net mode is a property of the world and it can be any of these four values you can differentiate these net modes based on three simple questions for one is the game playable does our game instance have a local player and are we processing that player's input and rendering the world into a viewport next are we a server in other words does our game instance have the canonical authoritative copy of the world with a gamemode actor in it and finally if we are the server are we open for remote connection attempts can other players join in and play as clients as we saw in a previous video when you start up your game you get a game instance object that's tied to the lifetime of the process and then the game browses to a url either a server address or a map name that causes the game to load a map which gives it a world and the world's net mode will differ depending on how your game instance has started up if your game instance has connected to a remote server then its world will have the client net mode the game is playable for the local player but it's updating its world at the behest of the server if your game instance has loaded up a map locally then the world's net mode will be standalone in effect your single game instance is both the server and the client but since it's running in a single player configuration it's not open for clients to connect to if you load up a map locally but add the listen option then you'll be running as a listen server this is basically the same thing as standalone but other instances of the game can connect as clients finally you can run a dedicated server this is an instance of the game that has no local player and no viewport it's just a server only console application that players can connect to as clients so there are three different networking scenarios that an unreal game can run in for a single player game you have one game instance and its world is running in standalone mode for a multiplayer game you have multiple processes each with its own game instance and its own copy of the world one of those processes is either a listen server or a dedicated server and the rest are clients so that's how we might get ourselves into a multiplayer game in the first place once we have a multiplayer game running unreal's replication system works behind the scenes to make sure that all these different instances of the game are in sync they all build their own picture of their shared world and the replication system makes sure they all agree about what's happening in that world in order to make that happen the replication system relies on three important classes net driver net connection and channel in this example we've got a dedicated server and two clients each of these processes has its own engine object when we boot up our server it creates a net driver and it starts listening for messages from remote processes when we boot up a client it creates its own net driver which sends a connection request to the server once a server and client netdriver have made contact that establishes a net connection within each net driver the server has one net connection for each remote player that's connected each client has a single net connection which represents its connection to the server within every net connection there are a number of different channels typically a connection will have a control channel and a voice channel and then each connection will have a series of actor channels one for each actor that's currently being replicated across that connection this illustrates a key fact of the replication system namely that replication happens on the level of actors if you need an actor to stay in sync over the network then you configure that actor to be eligible for replication when an actor that's eligible for replication is considered relevant to a particular player then the server will open an actor channel in that player's net connection and the server and client will use that channel to exchange information about that actor if an actor is being replicated to a client there are three important things that can happen as a result first the lifetime of the actor is kept in sync between the server and the client if the server spawns a replicated actor the client will be notified so it can spawn its own copy if the actor is destroyed on the server it will automatically be destroyed on the client as well then there are replicated properties if an actor has a property that's flagged for replication then when that property is changed on the server the new value will be propagated to the client finally there are rpcs remote procedure calls if you designate a function as a multicast rpc then when you call that function on the server the server will send a message to every client to whom that actor is currently being replicated indicating that the client should call that function on its copy of the actor you can also declare client and server rpcs which let you send messages back and forth between the server and the single client who owns the actor ownership is another important concept for actor replication every actor can have another actor designated as its owner typically you set the owner on spawn but you can also call set owner at runtime the playercontroller class has special importance when it comes to ownership basically each of our net connections represents a player and once the player is fully logged into the game it has a player controller actor associated with it from the server's point of view the connection owns that player controller and by extension the connection owns any actors that can trace their ownership back to the player controller player controllers automatically own the pawn that they're possessing so let's say that each of our player controllers has a pawn and each pawn has spawned a weapon actor that it owns the server can look at either one of these weapon actors follow its chain of owner references back to the player controller and figure out that the weapon actor belongs to a particular client connection so let's look more closely at how you configure an actor to be replicated in order for an actor to ever be considered for replication it needs to have its replicates flag set to true typically you just set this value in the constructor or for a blueprint you check the replicates box in the class defaults but you can also turn replication on or off at run time so long story short if an actor has its replicates flag enabled then it's eligible for replication the server can open an actor channel within any given net connection in order to replicate that actor to the corresponding client an actor's relevancy determines which connections that will happen for and at what times when an actor is eligible for replication every so often the server's net driver will check that actor against each client connection to determine if it's relevant to that client some actors are always relevant this means that as long as they're eligible for replication the server will replicate them to all clients at all times for example the game state and player state actors are always relevant ownership plays an important role in relevancy an actor that's owned by or instigated by a particular player will always be considered relevant for the corresponding client some actors like player controllers are configured to only be relevant to their owner so they'll never replicate to non-owning clients you can also configure an actor so that it inherits its relevancy from its owner if none of these special flags are set and the client in question doesn't own the actor then the default behavior works like this if the actor is hidden and its root component has collision disabled it won't be considered relevant otherwise relevancy is based on distance from the player that corresponds to the client connection if the squared distance from the actor to the player is less than net cold distance squared then the actor is relevant to that player these rules aren't hard-coded you can override the is net relevant for function for any actor class to provide your own custom rules once an actor is being replicated its update frequency and priority will determine how often the server sends updates to clients for whom that actor is relevant setting net update frequency will dictate how many times per second the server will check an actor and potentially send new data to clients if anything's changed keep in mind that real world networks have extremely variable latency and bandwidth can quickly become a limiting factor so even if your actor is set to update 60 times a second you're not going to see perfectly smooth results on the other end the server's net driver employs some simple load balancing in order to mitigate bandwidth saturation at any point in time the net driver has a finite amount of bandwidth to work with so it sorts relevant actors according to priority and then it runs network updates until it's used up its available bandwidth actors that are closer to the player are awaited with a higher priority and actors that haven't been updated in a while will have a higher priority as well so that every actor eventually works its way to the front of the priority list setting an actor's net priority property will apply an additional scale to that weight so for example you could dictate that an important actor should be updated five times more often than it would be otherwise that process of periodic bandwidth limited network updates mostly applies to replicated properties if you have a high priority message but you want to send over the network immediately that's what rpcs are for any u function can be designated client server or net multicast to make it an rpc if you invoke a client rpc from the server then the function implementation will run on the owning client if you invoke a server rpc from the owning client then the function implementation will run on the server if you invoke a multicast rpc from the server the function implementation will run everywhere on the server and then on all clients unlike server and client rpc's relevancy is a factor for multicast rpcs since non-owning clients may not have an open channel for the actor in that case the client simply won't receive the rpc that means you shouldn't rely on multicast rpcs to replicate persistent state changes to clients rpcs can be declared reliable or unreliable unreliable rpcs can be dropped if bandwidth is saturated and they're not guaranteed to arrive and therefore they're not guaranteed to arrive in any order either reliable rpcs are guaranteed to arrive and within a single actor reliable rpcs are guaranteed to arrive in the order in which they were called this reliability is necessary if your function call is critical to gameplay but if overused it can exacerbate bandwidth saturation and it can lead to bottlenecks in the event of packet loss in c plus plus the actual body of your function needs to be defined with the implementation suffix this is the function that actually runs on the remote process whereas the function you call locally is an auto-generated thunk that sends the appropriate messages over the network server rpcs can also be declared with validation in which case you need to implement a corresponding validate function that takes all the same arguments and returns a boolean indicating whether those values are trustworthy this is a means of cheat detection for cases where the server uses data sent from the client in a way that affects gameplay just keep in mind that if a server rpc fails validation the client who sent that rpc will be kicked out of the game so rpcs are sent immediately and they can be reliable that makes them useful for certain cases where replicated properties can be comparatively limited server rpcs are the only way to get data from the client to the server by way of the owning connection so they have their place but by and large rpcs are reserved for high priority time critical network code for example the engine's character movement system makes liberal use of rpcs to send position updates back and forth because movement prediction and correction requires up-to-date information with as little latency as possible for everything else you should rely on replicated properties wherever you can get away with it property replication is the workhorse of unreal's replication system and the load balancing and prioritization features we already discussed make it far more scalable whereas rpcs are immediate the key word with property replication is eventually if you change a replicated property on the server you can count on all clients eventually being in sync with the server if an actor changes on the server when a player is too far away for it to be relevant the change will still stick eventually once the actor becomes relevant to that client again it'll receive the updated property value property replication also respects update frequency and bandwidth limits no matter what you can change a replicated property every single frame on the server and the client will just get the most recent value whenever it happens to be updated the server is under no obligation to send every single intermediate value to enable replication for a property you can add the replicated specifier in c plus plus you need to take the extra step of defining a get lifetime replicated props function in your actor's cpp file you'll want to include unrealnetwork.h there as well this function is where you specify which properties should be replicated and under what conditions in the simplest case you just want a property to be replicated to all clients at all times and you accomplish that by naming the property in a do rep lifetime macro but you can also specify conditions for replication for example you might only need to replicate a property to the owning client or you might need only non-owning clients to get updates or you might have a property that's initialized on spawn but that never changes at run time if you need to run some code when a replicated property is updated then you can declare a rep notify function and use the replicated using specifier anytime the value changes due to a replication update the specified notify function will be called on the client note that in blueprints changing a property's value on the server will automatically invoke the associated rep notify function on the server this isn't the case in c plus plus if you want your rep notify logic to run on the server as well as on clients then you'll want to manually call the rep notify function after updating your property value there's one final concept that we should look at and that's an actor's network role there are a few different roles that an actor can have but in most cases you only need to be concerned with a far simpler question do i have authority over this actor whenever you're running some code in an actor class you can check for authority if you have authority you have the final say in updating the state of the actor either because the game is running in single player mode or your code is being executed by the server or because the actor only exists on the client if you don't have authority your code is running on a client and the actor is being replicated from the server in that case the client's copy of the actor is a proxy for the authoritative version on the server if an actor doesn't have authority then its role is almost always simulated proxy typically autonomous proxy only enters the picture when we're talking about players a player controller is replicated to the owning client as an autonomous proxy and the associated pawn is an autonomous proxy for that client for all other clients the pawn is replicated as a simulated proxy autonomous refers to the fact that the client is directly controlling the actor's movement and behavior even though it doesn't have full authority but unless you're dealing with player characters it's usually just a binary question do i have authority or not if you are dealing with player related code then another important question is whether the player is locally controlled if a pawn is locally controlled then that player corresponds to the game instance where your code is running if not it's a remote clients player so once you have all these concepts in your head the most important thing to appreciate about supporting multiplayer is how it adds complexity to the way that you think about your code you might think that programmers spend all their time furiously typing like in the movies but as a programmer a lot of your time is spent just reasoning about how your code is executed and it doesn't matter how smart you are your brain can only fit a few pieces of information in it at a time so if you have to juggle too many things at once it's going to be very hard to write good maintainable code a lot of skill and experience just boils down to knowing how to design and implement complex functionality in a form that's relatively simple to reason about supporting multiplayer adds a layer of complexity that you have to manage if you have an actor that's replicated then you're not just thinking about what the class is responsible for and what each of its member functions does you also have to consider where that code is being executed and how data flows across the network at different times that extra complexity can feel overwhelming at first but it gets easier to manage with experience so to wrap up here a few tips to keep in mind first it's important to remember that even if an actor is replicated not every part of it needs to be concerned with networking if you have an actor with a static mesh component and a dynamic material instance neither of those objects is network aware you can write the functions that initialize and modify those objects without having to think about networking those functions just run independently on each game instance and you only need to bring replication into the equation to make sure that they're called in a consistent way across all instances of the game most of your game code will ultimately build off of the unreal game framework which is designed for multiplayer out of the box when you're overriding these classes member functions to add your own functionality you'll want to be aware of whether a function is designed to run only on the server only on clients or everywhere using assertions can make it plainly obvious from looking at your code where it's designed to run and it can also be useful to establish naming conventions for helper functions such as using a prefix like auth for functions that are only called with authority you can think of your actor's functionality as sort of a cause and effect flowchart on one end you have the events that set things in motion on the other end you have the state changes that need to occur as a result if you have some process that starts and ends in different places on the network that's where you need to use some form of replication if the process originates on the client and ends up on the server then you typically use a server or pc if a process originates on the server and ends up having effects on the client then you need to consider where to replicate data down to clients your code needs to stay on the server for as long as it's updating authoritative game state or if players could gain an unfair advantage by viewing or modifying the data client side but after that you generally want to replicate the minimal set of data required to reconstruct the end result and let the client handle the rest of the process independently when your code needs to support networking it generally fits one of a handful of simple cases before you start getting lost in the low level details ask yourself if the functionality you're dealing with fits into one of these four buckets if something needs to happen only on the server in multiplayer and also in single player put it behind a has authority check if something's only necessary when running as a remote client and therefore shouldn't run in single player either check that you don't have authority there are some cases where you want to exclude dedicated servers specifically in those cases check is running dedicated server and if you have purely client-side functionality it's usually tied to a pawn or a controller so you can check whether the player is locally controlled that's about it for an overview if you're looking for more information about networking features the official documentation is a great resource and if you want more technical details there's some good places in the engine source where you can poke around in particular netdriver.h has some good information on how the replication system works and you can see its implementation along with some useful console variables in networkdriver.cpp netdriver is just the engine level base class the actual implementation used for the game network driver is called ipnetdriver and it's implemented in the online subsystem utils plugin along with ipconnection if you'd like to mess around with the simple example project seen in this video you can clone it from github and look through the change history and it's pretty exhaustively commented beyond that i'd suggest checking out the shooter game example project if you want to see a bigger more official example of a multiplayer game thanks for watching i hope this video has helped you wrap your head around the replication system please feel free to let me know if you found it helpful or if you have questions or suggestions and i'll see you in the next video
Info
Channel: Alex Forsythe
Views: 26,290
Rating: 4.9903731 out of 5
Keywords:
Id: JOJP0CvpB8w
Channel Id: undefined
Length: 22min 8sec (1328 seconds)
Published: Fri Dec 18 2020
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.