I’ve spent the last few hours digging through documentation and forum posts to no avail. Can someone please explain to me how, in C++, I can correctly take or give ownership/authority of an actor to a client?
If that’s too vague, specifically, I’m trying to get replication of VR motion controllers to work, but let’s ignore that for the moment and go with something more familiar. Let’s say I have a car in the world that players can drive. In order for it to feel correct for the clients, they need to have immediate response from the input, so they need to have authority on the vehicle. What is the correct way to do this in UE4?
In the example you made, the car must be set to **replicate **in order for its status to be constantly updated for all the clients in the game. The server is responsible for its replication.
Thanks for the reply, but that doesn’t really answer my question. First, what/where do I set to replicate? But outside of that, I don’t understand how that gives a client authority over the vehicle’s transform, specifically in such a way that he’s not just going to have his local transform stomped every time he receives a new update from the host.
I think what gedamial means is, step one is to make sure that we’re talking about a replicated actor.
But to answer your question, the function AActor::SetOwner(AActor* NewOwner) when called by the server sets the actor’s owner for networking purposes. If you set an actor’s owner to a player controller, that means that player’s client can call server RPCs. You can also set the actor’s owner to another actor that is in turn owned by a player controller. As long as the actor’s owner’s owner’s owner… etc leads to a player controller, that player has net ownership of that actor. However, that isn’t the same as authority. The machine that spawned the actor is always the authority. So the server keeps authority over any actor that is replicated, even if it passes net ownership to a player.
In practise if you’re writing code that should execute only for the owning player, you can check whether the actor’s Role >= ROLE_AutonomusProxy. From the perspective of the client that has net ownership over an actor, that actor is an “autonomous proxy”: autonomous because the actor can make decisions on that client, and proxy because the real version is still on the server. Aside from managing logic, you can make variables replicate only to the owner or skip the owner. For example, UI values that only the owning player sees don’t have to be replicated to other players. On the other hand, when you have variables that are simulated by the owning client first and only then on the server (for responsiveness), you don’t want the server to replicate those values back to the owner.
A concrete example of that last point is ammo. If you’re programming a machine gun, you want to see the ammo count going down the moment you click instead of waiting for that data from the server. In that case the owning client decrements the ammo count locally, sends a request to the server to do it too, and the server replicates it to all other clients except the owning client by using COND_SkipOwner. Read more about conditional replication here: Conditional Property Replication | Unreal Engine Documentation
I feel like there must be some core concept I’m missing with the network engine. I’m following what you’re saying and a re-read of the Actor Role documentation has cleared it up a little bit. From what I understand, an actor’s role will never change (other than, I would assume, through host migration, but let’s ignore that for now) even if they have net ownership.
I’m still having a tough time figuring out a couple things. First, what effect does net ownership actually have on the logic?
Second… Actually, let me word this one a bit differently. Why does calling TeleportTo on the player pawn not work on the client but calling AddMovementInput does? TeleportTo will move the client locally but they’ll snap back when they receive the next net update. I have a feeling that understanding that will be a bit of an “Aha!” moment for me.
I was able to answer my own question (mostly) on the second one. The way that the pawns are synced in the movement components is done in such a way as to keep a buffer of movements and timestamps. Unreal uses this to have accurate positional updates across clients without needing to use client-side prediction (dead reckoning). It’s using a set of unreliable RPCs and a manual delay timer to ensure that it doesn’t send updates to often, which would overload the connection.
This does help me understand a bit of the design of the overall system. Essentially, the client doesn’t actually have any authority in this case. He’s simply sending a message to the server and the server just treats it as if that client was the authority.
For this, there’s only one piece I’m missing, which is how the client ignores his own the positional updates that are sent back to him from the server. Digging through the code, it looks like it’s just a bunch of bespoke logic that handles the received data differently on the owning client than on the others (I think).
I guess my earlier post could be confusing because I talked about net ownership and authority as if they were different concepts. Authority is a role and net ownership affects an actor’s Role on a machine. The machine that creates the actor, which is always the server in case of replicated actors, will always have authority over that actor. From the server’s perspective, that actor’s role will always be ROLE_Authority. That same actor’s role on clients will depend on the net ownership. If the client is the owner of the actor, it will be ROLE_AutonomousProxy, otherwise it will be ROLE_SimulatedProxy.
The effects of net ownership are of two types:
You can only call server RPCs (client-to-server requests) on actors that you have net ownership of.
You can set variables up to replicate to the owner only, or skip the owner.
An example of the first: AddMovementInput which you mentioned internally sends a server RPC to notify the server of its desire to apply that movement input. It can only do that because you own that pawn. If other clients call that function on your pawn it won’t have effect, at least not any effect that can reach the server and thus other players.
Ah, that’s very good to know. Extrapolating from that, does that mean that most net communication has to go through the player controller (and it becomes a dreaded dumping ground)?
As an example, let’s say there is a switch on the wall. This switch is obviously owned by the server. As a client, I want to change the switch from off to on. Or, rather, I want to inform the server that I’m changing the switch so that we can avoid race conditions where multiple clients are quickly switching it off and on, resulting in a desync. In its simplest form, the client needs a way to send a message to the server to make a request. With what I’m understanding of net ownership, the only way to do this would be to send that request through an object the client owns, such as the player controller. Is that correct?
By the way, thank you very much for answering these questions for me. I have a lot of experience working on multiplayer games, but figuring out the exact way a new engine works can be tough without a bit of guidance.