Download

"Blueprint Multiplayer" Video Series is teaching a lot of wrong things

Hey everybody,

most of you might know, that I’m in love with Multiplayer things. That’s why I wrote my Network Compendium.

Today, I gave someone on the Discord Server some help, while he was fighting with the “Blueprint Multiplayer” tutorial on the Unreal Engine Youtube Channel.

He posted me some screenshots and I was kinda confused by what I saw.

Before we start, I want to make something clear:

I really appreciate the work and time you put into these Tutorials and I do not want to talk down peoples work here, but if you create learning resources, then please try to make as less mistakes as possible.
There is a really high chance that I made mistakes in my Compendium, but I gladly correct them if someone tells me about them. So that’s why I’m telling you now, what’s wrong with this series.

##################################################################

Let me show you some examples of what is wrong.

Example #1:

As Networking is something where you really need to pay attention to stopping players from cheating, UE4 provides us with things like “Switch Has Authority”.
This node triggers “Authority” for the Server and “Remote” for the Clients. Using this is great, but it should be used at the correct places.

To further get into the example, the “GameMode” class is a Server Only Class. This means, not a single Client (despite the ListenServer, which I count as the Server here) has an Instance
of this Class. It simply does not exist on the Clients. Using “GetGameMode” on a Client will simply return a so called “nullptr”.

Why is that important? Let’s get back to our SwitchHasAuthority Node:

Would we need this node in the GameMode?

Answer: No, because without an instance, no one can call this function anyway (despite the Server of course).

Now let’s look into the LobbyGameMode, created in the video number 15:

Can someone tell me why this is used here? I’m 99.99% sure, it’s not needed and teaching this is wrong. Of course you need to use it, but not here.

Let’s go further with the GameMode.

Example #2:

RPCs, or so called “Remote Procedure Calls” are used to shift a function call over to the Server, the Client or everyone (to keep it simple).
This is done with a ServerRPC, a ClientRPC or a Multicast.

To call a ServerRPC, we need to be in an “Client Owned” instance of a replicated class. An example for this would be the PlayerController, the PlayerCharacter or the PlayerState.
These classes accept ServerRPCs.

Back to the GameMode. Remember, it does not exist on the Clients. Would a ServerRPC be here of any use?

Answer: No, because there is no Client that could call it.

Let’s go back to video number 15:

So again, why do we need this here?

We also see something else in this picture:

Replicated variables. Why do we need to replicate variables here? There is no Client instance! Nothing to replicate things to!

Then, it’s not even some random variable, it’s an array of PlayerControllers. So let me update the knowledge about PlayerControllers:

The Server has an Instance of any PlayerController. Means, his own, and one of each Client. Clients on the other side, only have their own. They have 1 single PlayerController.
This means, even if we could replicate here, there would be nothing but ONE single PlayerController in this array for the Clients.

So why do we do this?

One other little thing is: Why is PlayerInfo stored in the PlayerController that Clients have trouble accessing?
Why not correctly teaching that it belongs into the PlayerState Class, that every Client can easily access via the GameState’s PlayerArray?
The Class even has a premade PlayerName and Score variable and everything can be correctly replicated.

Example #3:

What do we know about Widgets? Widgets are classified as Client Only classes. This means, only the Clients need to know about them and we should never do any logic in them
that drives GamePlay (in most cases). So looking back at the RPCs, would a ClientRPC make sense here?

Does the Server have an Instance, which is replicated, on which the RPC can be called? No, it doesn’t, a ClientRPC is not needed at all.

Still, this here is in video number 12:

Where is that called? In the PlayerController, locally, already on the Client. There is no need to call a ClientRPC here, yet it is said that we “want this to be on the owning client”.

##################################################################

I could probably go on with this list, by searching through the rest of the videos, but I don’t have a lot of time today.

So what should be done now? Well, in my eyes, this series should be taken offline and should be redone.
And before you do this, get someone who knows exactly what’s going on in the multiplayer framework of UE4.

And again, I don’t want to talk down your work. I know this all costs a lot of time and I really like that you address it, but I am totally NOT fine with
the way it’s done. This needs to be correct, small mistakes are totally fine, but this explains your own Engine wrong. And that on the official channel.

The thing is, that we community people, who do this stuff in our free time, need to remove all these wrong learned things out of the community again.
So back to the person who had trouble while learning with the series and who came to the Discord Server to ask for help.
He is now learning things that are unnecessary, if not even wrong and I might need to explain to him what things he doesn’t or shouldn’t need to do.

Thanks for your time and for reading this.

Cheers,

eXi

+1 I agree with this

Very interesting points here!
I am planning to go through that series soon and it would be nice to know that some collaboration is done to ensure it is polished up as much as it can be.

Thanks for letting us know! We’ll take a look and see what is the best course of action

Jumping in here,

Thank you for the constructive feedback eXi, coming from you this means a lot. At the time of creating this tutorial series, it was based largely upon the existing Multiplayer Shootout Project that some members from our internal teams created, so I based a lot of what I did on that. Some of the examples you call out, you are correct in that they may not be needed but existed in that project so I followed suit (should have checked with our internal teams to see if it would be a best practice or not).

Regarding your specific points, for the examples 1 and 2, Switch Has Authority and calling Execute on Server from within the Game Mode, I know that the Game Mode doesn’t exist on the client but wasn’t sure if a client could somehow hack or emulate the Game Mode in any way, so I still used those in those situations that if somehow someone were able to emulate any Game Mode portion of code, that when it is executed, making sure that it stems from the Server only. You are correct, it is not needed though.

Regarding the use of the Player Controller to store Player Info and it being replicated, also correct. If I were to do it over, I would use the Player State. Maybe that can be something we tackle in an update or in an Advanced Blueprint Networking series. It’s the same as executing some Blueprint Code in the Character Blueprint or Controller Blueprint, while both will work. Some things make more sense to be put in others. This was working, so I didn’t want to revamp the project to make this change.

For your third example regarding Widgets, I’m not 100% certain why I put that particular node to Execute on Owning Client other than the fact I was thinking that I wanted this script to be working for each client so I put it to that not realizing that I didn’t need to. Again, it is one of those things where it was working so I didn’t want to break it.

I really want to express how grateful I am for you taking the time to not only provide feedback on this series, but for taking your free time to help the community with your own training content, feedback and engagement with community members. When we provide updates to this series or future series, I’d love to have you involved before that content actually goes live. Maybe that is something we can work out with Alex where we PM you a link to the content before it goes live? Will talk with the team here to see what we can do about improving the quality and accuracy of the content that is released.

Regards,

-W

First of all, thanks for your time! I want to make sure (again), that you don’t see this post as a “personal” attack against your work. I just want to improve the learning resources.

Fair enough, but even if it’s based on existing content, aka the Multiplayer Shootout, it should not contain unnecessary and maybe wrong code, right?
So yes, talking back to the internal team might be needed. I mean, this affects ALL learning resources as soon as it comes to stuff that one is, maybe, not so familiar with.
I know you can’t know everything.

MAYBE, someone, somehow, is able to emulate the GameMode. But this needs the “hacker/cheater” to connect Client and Server version of the GameMode and switch ownership to himself, otherwise ServerRPCs are dropped anyway.
But let’s not talk about what could be possible exploits of the system, let’s focus on the tutorial for now.

I totally agree with you, that Code that works, is fine, as long as it doesn’t cause trouble in the long run.

But you need to consider something here, that also applies to the part of your post about the GameMode:

This Lobby Project, and what ever other project will be created for learning purpose, is not meant to just “work”. It’s meant to teach how to do it correctly. This means, the project should not contain sloppy workarounds,
which work just for the sake of working. It should properly explain, why to use the PlayerState at this point and not the PlayerController/Character.
Because this will make your viewers understand the Engine and the GameFramework and this will make them understand on how to create their own stuff.

Why does that apply to the GameMode part? I don’t actually know if you explained it in the video the same way you did here, but if not, then one big thing needs to be clear:

The viewer might not know that the GameMode exists on the Server only. You know that, and you know tons of other cool and important stuff. But just going with it and not telling why you put the ServerRPC there,
although it’s not directly necessary, will only cause confusion.

And why do I think it causes confusion? I read the comments under the YouTube videos. Most of the people don’t really ask why you do it and why not, but some
got confused and asked why the GameMode has all these replicated variables etc.

So the focus should be shifted to explaining the classes and how RPCs work (ownership is here very important!).

Guess same words from above apply here too. I get why you put the RPC there, but this kinda shows how insecure you were when working out the project.
Otherwise you would have simply said “Hey, this node doesn’t need to be an RPC here, cause …]”.

Thanks for the kind words! We (community) do that, because we like helping each other. I often answer the question “Why UE4?” with two simple words: “The Community”.

I will gladly look over the content before you release it. And yes, [MENTION=8]Alexander Paschall[/MENTION] might want to handle the communication between us, although I gladly
stay in contact with you directly, if needed.

But also consider taking other community people into this. I’m good with Networking (My Marketplace Project is a BP Multiplayer Lobby after all, hehe), and with the general Framework of the Engine,
but there are probably tons of other topics I can’t really say a word too. So if you want some more eyes that look over your content, grab the leading spotlight members (:

[MENTION=8]Alexander Paschall[/MENTION] will totally know who is good in what.

Again, thanks for your time and I hope you didn’t take any word of mine as a personal attack or something. Written words can, really fast, go into the wrong direction.

Cheers!

I have to say that I agree with all the points Cedric made, especially about “explanations”. I suppose this would depend on the actual target base, but the assumption should have been complete newb who is probably going to want to know every bit of networking there is, all the nooks and crannies in regards to UE4.

Also, while UMG is nice, I feel like it was way too dominating for a series that was supposed to teach “Blueprint Networking”. I was kind of sad that LAN didn’t work out of the box. Also, that we didn’t get Server Listings. Two pretty important parts. Perhaps in another series. But also, there are a lot of stuff that needs to get looked at, especially since 4.14 (which obviously wasn’t in focus at the time) like Replication Conditions, etc. But yeah, more focus on Replication, different scenarios/use cases of using whatever/whenever would be great.

After following this series to help jumpstart steam into my game, i have been BASHING my head against the wall on why a lot of the functions just are not working right in a steam to steam client setup over the internet and have be super confused along the way.

i have spent the last week trying to crawl through this series to get it working in my game and re doing a lot of the implementation because it was simply not working.

then today i open the forums and see this thread and simply say… i want my week back… i have spent at least ~55 hours this last 9 days trying to stumble through this tutorial getting it working on my game to now find out that half of it isimplemented wrong…

hell i still don’t have replication working 100% for player data, and now i understand why.(not why it isn’t working :frowning: locally it works but not steam to steam over the internet )

I feel like a video series posted by epic should always 100% be the best practices for the engine at that day, videos on the epic channel are and should be final say on best practice,
I have been relying a lot on epics video / text documentation and tutorials to get through making my game by myself and i shouldn’t have to worry that what i am watching is
wrong.

saddens me that i had to spend over 35 hours trying to stumble to make it work when it was wrong to start. (no offense to wes you seem like a nice guy and you do quite well on the video series despite the data being kinda wrong :frowning: )

I just want to add that as a user now of unreal engine for about 1.5 years (how long i’ve been working on my game), when i follow online tutorials via web or youtube, 99% of the time i use test projects to make sure things work.

but when i follow a series from epic on their official youtube channel i use it directly in my game because i take official content from epic as the final word of best practices because you guys have been doing this a long time
and know better than me, sucks that i get to the end of a 5 hour series and feel like i don’t understand the networking in unreal engine any more than when i started and i am more confused.

no offense wes again, just a honest review of one of the minions making a game on your great platform.

Hey everyone! Thanks for all the great feedback and discussion going on in this thread. We always strive to create the highest quality learning content, and that includes always showing best practices. We are looking into ways to modify our video pipeline to improve the end results and make sure you always have the best experience. This will include more review on our end, but may also involve the community experts in one way or another. More to come on that. In the meantime, we will be looking at what we can do for this series specifically to fix any issues.

I apologize for any frustration this has caused. If anyone has any questions or concerns, please don’t hesitate to bring them to me.

Any chance of maybe a new final video that is centered around cleanup? where we just modify all the code up to that point to be current best practice? (I’m guessing it wouldn’t be too many modifications)

So,… what are the plans for this series now? I would really like to have this openly shared with us.

Correct me if I’m wrong: It’s possible for different nodes to have authority over different objects?
For example, could I decide that the authority of a spectator camera on a viewing client would lie with that client, not the server?

Guys, I have a question about MP shootout.

So in Player Controller there is a “client post login” script, that asks the GameMode (after a cast) to spawn the player. How does this bit work for the joining client? How can client get anything but null from the cast?
Thanks.

I think what you are talking about is OwnerShip. You can set the Owner of a replicated Actor to be the PlayerController of a Client
and then he would own it (with his connection, as the PlayerController acts like that (kinda)).

The Authority would not change, as this is still the Server.

The OwnerShip, for example, sets if you can call RPCs from Client to Server or from Server to owning Client.

I don’t know about the Spectator Camera, as I haven’t used it yet, but if that’s a Pawn and you posses it, the it would
end up being owned by the Client.

Good catch, this is basically not working :stuck_out_tongue: If the “Client Post Login” function is really an Owning Client RPC, then we would be on the Client and the Client would get a NullPtr for the GameMode.

If, however, this works, I would be kinda surprised and would need to have a look at it.

By default, and that’s what I know, the GameMode doesn’t exist on the Clients and you can’t get it.

@eXi: Thank you for the hint about GameMode being server only. This helped me to simplify things a lot. I also just downloaded your “compendium”, thank you very much for your work! This is incredibly valuable as it takes so much time to find things out by myself, and documentation is very sparse.

I also wished the tutorial would have included PlayerState, it is so important. I was stuck without it, because I needed to be able to replicate character properties to all clients which survive respawn. I think this happens in all but the most trivial multiplayer games.
Then I read about PlayerState - and I spent quite some time just to figure it out how PlayerState works with Blueprints only, because I could not find any documentation on this. I used an override for Event CopyProperties (which is new by @eXi, as I now know) and it simply did not work at first. It turned out that variables to be copied need to be marked as “Editable” (checkbox) in the (derived from) PlayerState blueprint. If you do not do this, the data just won’t be copied. Now if PlayerState would have been explained in the tutorial (even without using it, because it was C++ only at that time) this would have helped a lot.

Although the tutorial was very helpful, I would have much preferred if the focus would be more on the technical multiplayer side of things, like which variables really need to be replicated (not “just because”), and in which order “engine events” occur on server if a new player joins, and maybe some best practises. The original (short) blueprint multiplayer introduction Introduction to Blueprint Networking - YouTube already contained some best practises, for example using “SetLifeSpan” instead of just destroying actors, but I suppose there are a lot more, like how to know when it is safe to call GetControlledPawn and it won’t return null, etc.

Hi all!

First of all, like most of you have mentioned, I greatly appreciate the help we developers receive from all the Epic Staff. We as a community would not have reached this level of success without all of you.

Recently, I watched all the videos in this multiplayer tutorial to make sure I was correctly setting up our project to use the Steam Online Subsystem. I realized I didn’t need to watch all of them but there’s always something new to be learned. In my case for instance, I didn’t know about the Format Text blueprint function (nifty little box).

Anyway, I believe I’ve learned a good amount of networking/multiplayer concepts by reading the documentation, watching youtube videos and practicing on my own so, from the very first couple of videos in this series, I decided to write down anything that I might consider wrong, unnecessary or that could be done better from a multiplayer point of view. Maybe I missed some things but I believe this list can be a good start for anyone who’s confused with RPC functions, replicated variables, etc. Any suggestions or if you find anything wrong with the list, feel free to let me know.

1. Videos: 3 and 4. Variables in GameInfoInstance and PlayerSaveGame classes should NOT be replicated because neither of the classes are (and cannot be). MaxPlayers and ServerName variables are created in the GameInfoInstance class and S_PlayerInfo is created in the PlayerSaveGame class. All these variables are marked replicated. Instances of these classes exist only at the owning client, meaning each player has their own copies of one GameInfoInstance and one (or more) PlayerSaveGame objects. Neither of these classes are replicated and they cannot be. Both classes are used to store local settings and local settings should not be shared, not even between the server and its clients.

2. Videos: 14, 15, 21 and 23. Variables in LobbyGM and GameplayGM should NOT be replicated because they only exist on the server. Replicated variables should only be used for classes that can be replicated (one authoritative instance of the class exists on the server; replicated instances exist on clients). But since GameModes only exist on servers, they have no replicated client instances. Clients cannot access them so obviously they cannot access their variables.

3. Videos: 12, 15, 19 and 23. LobbyGM and GameplayGM should NOT have RPC Server functions because they only exist on the server. Like eXi already mentioned, GameMode instances only exist on the server. To make a successful call to a function marked as Run on Server, a replicated instance of the class must exist on at least one client and this instance must be owned by that client. If the owning client calls this function, then it can be executed on the server instance of the mentioned class. For example, a player controller can call a Run on Server function from its client replicated instance and it will be executed successfully because the player controller exists on the server and on the owning client. But since LobbyGM and GameplayGM only exist on the server, no client has access to them to call any of their functions. Therefore, to mark ANY function as Run on Server is unnecessary/redundant.

4. Videos: 12, 16, 18 and 19. Variables in LobbyMenu, ConnectedPlayer, GameSettings, PlayerButton, ChatWindow and in any other widget should NOT be replicated because neither of the classes are (and cannot be). Similar to the GameInfoInstance and PlayerSaveGame, widgets are objects which exist only at owning clients, meaning each player has their copies. Every UI element seen on screen exists in that screen alone and is not shared with anyone. Not even a server can access widgets from other players. If the server cannot access these widgets (except its own when we’re talking about a listen server), it most definitely cannot access any of their variables to change them.

5. Videos: 12 and 22. LobbyMenu, ChatWindow and any other widget should NOT have RPC Client functions because they only exist on their owning clients. Like eXi also mentioned, widget instances only exist on clients. To make a successful call to a function marked as Run on Owning Client, an instance of the class must exist on the server and a replicated instance of it must exist at its owning client. For example, a player controller can call a Run on Owning Client function from its server instance and it will be executed successfully client-side because the player controller exists on the server and on the owning client. But since widgets exist only at their owning clients, no player (including the listen server) can access other players’ widgets to call any of their functions. Therefore, to mark ANY function as Run on Owning Client is unnecessary/redundant.

6. Videos: 12 and 21. Replicated variables must be set in server’s authoritative instances so that they can be replicated to their respective client copies. Inside the LobbyPC, AllConectedPlayers and AvailableCharacters are marked as replicated but they are only being set client-side. If a variable is marked as replicated in a class that makes sense (like the LobbyPC), it is expected that this variable will be set in the server’s authoritative instance of the class so that it can be REPLICATED to its client copies. But this is not the case here. The variables are marked as replicated but they are set in events marked as Run on Owning Client. If these variables will only be accessed/modified client-side, then they shouldn’t be marked as replicated.

  1. Video: 15. Use of HasAuthority in LobbyGM is unnecessary/redundant. Already discussed by eXi. Any function inside a GameMode is being executed on the server. No client can access/run any of these functions, so the macro Switch Has Authority will ALWAYS output Authority.

  2. Videos: 22 and maybe more. There are two methods to pass variables from a server authoritative instance to a replicated client copy: either mark variables as replicated or pass them through Run on Owning Client functions. No need for both methods. The LobbyPC has SenderName and SenderText marked as replicated. Although they are set server-side, they are passed through a function marked as Run on Owning Client. This is where the client uses them. Variables are marked as replicated so that the server copies the current values to its client copies. But if the variables are also passed through a function, there’s no need to replicate them. I feel like there were other examples for these situations but I didn’t write them down.

9. Video: 23. Variables set from a SaveGame object should NOT be replicated because to load a SaveGame object only occurs on a client. Although a variable can be correctly marked as replicated, if it is only set client-side, it doesn’t need to be replicated. Already discussed in (1), SaveGame objects only exist at owning clients so any variable dependant of them will never be set in a server authoritative instance.

10. Miscellaneous. When to use Pure Cast and regular Cast. This is more of a C++ topic but I consider it to be very important. During these videos, regular Casts are changed to Pure Casts and the Success pin is ignored. Since it is not explained why, it can lead to incorrect implementations. This is fine ONLY if you are sure the object being casted will always be NOT empty and of the casted type. If the object might be empty OR be of a different class, the regular cast should be used. If you’re into C++, I treat Pure Casts as Static Casts and regular Casts as Dynamic Casts.

Again, this is everything I noticed watching the videos. Thanks to Epic again for being so… Epic :slight_smile:

Sorry for the silence on this, guys. We will be looking at options for updating this series after GDC and I will definitely keep you updated.

All of the advice here, including the “GameMode only exists on the server” and “PlayerController is owned by a client but is also instantiated on the server” and such, ought to be distilled down to a “cheat sheet” for replication and RPC.
It’s super helpful to have tutorials for how to get started with the concepts, but having a single place where the rules for each “special” class, and the general-purpose rules for normal classes, are clearly and briefly collected, would be super helpful.
If I need more details, I’ll go look at the documentation for each particular class, but doing that for all the classes involved is way more work than needed, and the documentation for each individual class does not focus on making its network requirements a prime goal.

There were also a lot of problems in that tutorial series for missing steps, missing bp node links, etc. Off the top of my head I know that the ready/not ready button would not work correctly if you followed the tutorial exactly.

The organization is also very poor. I have a problem in one of my projects and I am trying to double check the .ini, .uproject, and plugin settings. I can’t find them in this series and I have been skimming around for about an hour.