Diagnosing Issues

No matter how good the tools are that you use, at some point you will be in the situation that something is not working as you want it to – that’s just an unavoidable reality of software development. In this section, we’ll go over some general and GMC-specific techniques you can use to diagnose and fix issues with your code.

Essential Debug Strategies

Employ the following strategies to figure out problems quickly and efficiently. Most of the information applies to Unreal and software engineering in general. You must know and use these techniques if you want to be a successful game developer.

Pay Attention To The Log

One of the easiest things you can do to save yourself from unnecessary trouble is to always keep an output log window open while you are developing in Unreal. The GMC will usually log obvious problems as either warnings or errors, so by keeping an eye on your log you will be informed immediately when there’s a fundamental issue in your code or setup. Log messages that belong to a GMC category will always be prefixed with LogGMC. If you do not have an output log tab in your project, you can click Window > Output Log in the top bar of the editor to restore it. Additionally, make sure that no GMC categories are filtered out, you can ensure that everything is shown by ticking Filters > Show All in the log window. A warning issued by the GMC would look something like this in the log:

Furthermore, the output log you see in the editor merely displays a processed read-out of the actual text file that’s being generated in the background. You can access this log file even after closing the editor by going to the Saved\Logs directory of your project. Remember this, because when you ask for help in the Discord you will often be asked to provide the log file.

Use The Debugger

A lot of beginners seem to be under the impression that they have to figure out what’s wrong with their code by simply looking at it. That’s generally not how you do it, even very experienced developers would struggle to find bugs with this approach for any but the most obvious cases. Especially when you are a beginner, using the debugger will almost always let you diagnose the issue much faster. It enables you to pause the execution of your code and then step through it node by node, so you can analyse the values of variables at each step and follow the flow of the logic gradually. Refer to the Unreal Engine Documentation to learn how to use the Blueprint debugger, or the documentation of your IDE’s debugger if you are using C++. For Visual Studio, you can find a basic introduction to debugging here.

Add Print Statements

While the debugger will often be your primary tool for finding bugs, in some cases the age-old technique of inserting print statements into your code may help you get to the bottom of the issue faster. This usually applies when you do not have a distinct branch of logic that you can easily place a breakpoint at, or when you already suspect that the value of one particular variable is the problem (although you can also try to use a Blueprint watch in that case). In Blueprint, you can print messages to yourself which are then displayed on screen and/or the output log by using Unreal’s built-in PrintString node. For logging in C++, consult the Unreal Engine Documentation. The GMC offers special logging functions that you can use as well. In addition to the message itself, these will prepend further information about the object that the log message originated from if applicable, which can be especially helpful when testing multiplayer.

Observe The Event Graph While Playing

Another strategy unique to Blueprint that you can employ to quickly assess whether your code is actually doing what you think it does, is to look at the event graph of the Blueprint in question while you are playing the game. The execution wires will light up while they are active, so this will give you a rough impression of what is happening and whether the right branches are being taken. 

One very important thing to note is that you must specify the particular object you want to debug. In the screenshot at the top right, you can see that I have selected the actor with the name BP_TPCharacter0. Initially, the drop-down may display the phrase No debug object selected, so you must first choose the object you want to inspect from the list.

Verbose Logging

In general, logging categories will output more information when you increase their verbosity level. You can specify the verbosity level for a log category via console command, the format is Log <CategoryName> <VerbosityLevel>. For example, if you want to log more information about the internal processes of the organic movement component, you can type Log LogGMCMovement VeryVerbose into the console. However, be aware that VeryVerbose is really not an understatement for this particular category. It will document large parts of the internal movement logic in minute detail and may slow down the editor as a consequence, especially if you have the output log open while the messages are being generated. Regardless, if you have an unusually hard to fix problem with your movement code, and you suspect that it’s somehow caused by a conflict with the built-in logic, this might be the best way to diagnose the issue. I wouldn’t recommend using the command with multiple pawns at the same time though.

Testing And Debugging Networked Games

Since a lot of additional complexity is introduced when you go from single to multiplayer, there’s one golden rule you should always follow: make sure everything works as expected in Standalone (i.e. single player) before you move on to testing in multiplayer. If you add some movement ability and then immediately go to play as a client, and something doesn’t work, you can’t really tell whether you have a replication problem or just made an error in your movement logic (or both). If your goal is to make a multiplayer game, I strongly recommend you stick to the following systematic approach for adding new movement features to your game.

Stage 1: Standalone

Write your new feature and test it thoroughly in Standalone mode. This should also involve testing at different frame rates. Apart from it being highly desirable that the speed of your movement doesn’t depend on the frame rate, this will also become important when you test in multiplayer afterwards, because the GMC will combine similar consecutive client moves into one move with a larger delta time to save bandwidth. If any problems occur at this stage, fix your code by applying the previously discussed debugging strategies.

Stage 2: Single Client

Start PIE as a single client (Number Of Players = 1, Net Mode = Play As Client). Testing as a solitary client will let you isolate issues relating to client prediction and replay. If any problems occur at this stage, it is likely that you haven’t correctly applied the concepts outlined in the Networking Introduction, so you may want to review that chapter. Use the console commands Log LogGMCReplication Verbose and gmc.ShowClientCorrections 1 to gain additional information relating to the replication process and to visualize client corrections in game. These commands will alert you to potential issues even without emulating any latency in the editor. If the log stays silent while playing and no shapes are drawn on the screen, your code is probably fine.

Stage 3: Two Clients

Increase the number of players to 2 clients. At this stage, we are not interested anymore in the pawn that you control yourself, we checked that in the previous step. Instead, we want to observe how the pawn that you control looks for the other player. So you should move around with one of the client pawns, but look at the screen of the second player and verify that the simulation looks as expected. If you do encounter a problem at this stage, it will likely be in the form of some missing animation. If that happens, you have probably not added and/or replicated a required value for simulation. Again, refer to the Networking Introduction to ensure that your replication setup is in order.

Stage 4: Listen Server

This stage is optional if you only care about a dedicated server setup, and it is unlikely that you’ll encounter any new issues here as the GMC treats remotely controlled listen server pawns the same way as simulated proxies (which we checked in the previous step). But since they are not completely the same in reality, it is possible that these could experience unique complications. Set the number of players to 2 again and select Play As Listen Server as the net mode. Now, control the client pawn and observe it on the server. If it looks similarly smooth as the simulated proxy pawn previously, then all is good. By the way, there is no need to test the locally controlled listen server pawn, it behaves the same as in Standalone on the server and is just another simulated proxy on the client.

Testing With More Players

In general, it is not required (or practical) to test your movement code with more than 2 game instances at once in the editor. If you completed all the steps above, it is almost guaranteed that your logic will also work the same with 3, 4 or more players, the underlying network architecture ensures that (at least until you hit bandwidth or performance limitations). At this point, you can have a reasonable amount of certainty that your movement will also work in a real-world network environment when you test with multiple people.

Testing With Net Emulation

You can configure the net emulation settings by selecting a net mode other than Standalone and clicking Advanced Settings… in the same menu. Under the category Multiplayer Options, check Enable Network Emulation and adjust the settings as you like. Refer to he Unreal Engine Documentation for more information. You should test your code with net emulation enabled every now and then, but I generally don’t recommend having it active all the time. The problem is that depending on the emulation configuration, it can cause sporadic network incidents that may be difficult to discern from “real” replication issues, so you may end up chasing ghosts (especially if you are a beginner). You should leave net emulation disabled while following the steps outlined above. Use the console commands instead to reliably detect network errors, and only perform additional tests with net emulation after you have verified that everything works correctly without it.