You can debug your own C++ code using the Visual Studio debugger and use Function Breakpoints to "track" execution vanilla code even without the source code.
You can learn more about the Visual Studio debugger here.
You can learn more about the Rider for Unreal Engine debugger here.
In order for things to work without all the source code available you’ll need to configure your debugger to be okay with mismatched source code.
In Visual Studio, this can be handled in
Debug > Options… then under
Debugging > General find the entry for "Require source files to exactly match the original version" and uncheck it. It’s roughly halfway down the scrollable area.
Certain Unreal Engine launch arguments can be particularly useful when debugging.
You can learn how to launch your game with launch arguments on the FAQ page.
-NoExceptionHandler argument allows for the use of Just In Time debugging.
When present, the main SEH exception handler is disabled.
That prevents crash reporter from catching SEH exceptions (namely, access violation)
and allows the debugger to handle them instead.
Without it, your attached debugger will not catch any access violations or checks,
they will just crash the game instead.
This argument is added and handled by Unreal Engine.
By adding the
-WaitForDebugger argument to your launch arguments,
the game will wait for a debugger to attach before continuing to launch.
This can help with catching problems very early in the startup sequence.
This launch argument is added by Unreal Engine but does not normally work in Shipping builds of the game. SML includes custom handlers to allow it to work. In Shipping, the exact point it waits at is SML initialization. If not for SML handlers, it would otherwise be inside of the engine loop.
Now you need to attach your debugger of choice to the running Satisfactory process,
After you’ve already attached once during your editing session, you can use "Reattach to Process" to quickly reattach the debugger again.
With the debugger attached you can add breakpoints to your C++ code or any other code you have the source to. When your breakpoint is hit you can view local variables, view the Call Stack, and step through the code.
By setting a Function Breakpoint, you can try to break when one of the vanilla functions are called - even though you don’t have the source code.
To do this in Visual Studio click on 'Debug' in the Toolbar, hover over 'New Breakpoint' and click on 'Function Breakpoint'. When that window pops open you can paste in the function you want to break on using the
While Function Breakpoints seem to work most of the time, there may be cases where it doesn’t break where you expect it. In this case, you’re just out of luck. You’ll have to try breaking on a different function.
Once a function breakpoint has been hit you can view the local variables, view the Call Stack, and step through the code. When stepping through code you obviously won’t be able to see the actual code, but you can get an idea of what happens in what order by setting multiple breakpoints and watching the Call Stack and local variables as different functions are called.
Assertion statements are tools used to check and validate assumptions or conditions in code. These conditions are often checks that a pointer is non-null, a divisor is non-zero, a function isn’t running recursively, or other important assumptions that the code requires, but that would be inefficient to check every time.
When used correctly, they can help catch bugs early and make debugging easier by pinpointing the exact location where an assumption was violated.
You can read more about these utilities (and see usage examples) on the relevant Unreal Engine documentation page.
Note that Assert and Check statements will crash the game if their conditions are not met, however, Ensure statements will allow the game to keep running.
When SML is installed and a debugger is attached, Checks and Ensures will be caught by the debugger. This is not normally the case in Shipping builds of Unreal Engine games; this behavior is enabled by SML.