Debugging Unreal C++ With Rider¶
This chapter is about debugging the current Andromeda C++ gameplay flow in Rider.
The important mental model is that Unreal Editor is the running application. The game code is loaded into the editor process. When you press Play in Editor, you are not launching a separate standalone game executable by default. You are running gameplay inside UnrealEditor.exe.
That affects how breakpoints work.
Normal Debugging Workflow¶
The usual workflow is:
Open Andromeda.uproject in Rider.
Choose an editor target, usually DebugGame Editor or Development Editor.
Place breakpoints in C++.
Launch Unreal Editor from Rider's debug configuration, or attach Rider to UnrealEditor.exe.
Press Play in Editor.
Trigger the gameplay path.
For active gameplay debugging, prefer:
DebugGame Editor gives better symbols and stepping behavior for your game module than Development Editor, while avoiding the full cost of debugging all engine code. Development Editor is still useful for normal compile/test loops, but if a breakpoint behaves strangely, switch to DebugGame Editor.
Launch vs Attach¶
There are two common ways to debug.
Launching from Rider means Rider starts Unreal Editor under the debugger. This is the cleanest setup when you know you are about to debug C++.
Attaching means Unreal Editor is already open, and Rider attaches to the running UnrealEditor.exe process. This is useful if the editor is already in the exact state you want to test.
The tradeoff is:
Launch from Rider Cleaner symbols and startup path, but slower.
Attach to editor Faster when editor is already open, but easier to hit stale-code confusion.
If you are unsure, launch from Rider.
Live Coding Caveat¶
Live Coding is useful for quick .cpp iteration, but it can make debugging confusing when code or symbols become stale.
If a breakpoint should hit but does not, use the boring reliable path:
Close Unreal Editor.
Build from Rider.
Launch Unreal Editor under Rider's debugger.
Press Play.
Trigger the code path again.
This is slower, but it removes ambiguity. When learning a new codebase, reliable debugging is usually worth more than the fastest possible iteration loop.
Good Breakpoint Locations¶
These are good first breakpoints for the current codebase.
Startup and input:
AAndromedaPlayerController::BeginPlay
AAndromedaPlayerController::AddDefaultMappingContexts
AAndromedaCharacter::SetupPlayerInputComponent
AAndromedaCharacter::MoveInput
AAndromedaCharacter::MouseLookInput
AAndromedaCharacter::InteractInput
Focus and prompt:
AAndromedaCharacter::Tick
AAndromedaCharacter::UpdateFocusedInteractable
AAndromedaCharacter::ResolveInteractableFromHit
AAndromedaCharacter::NotifyFocusedInteractableChanged
UAndromedaInteractPromptWidget::SetPrompt
UAndromedaInteractPromptWidget::ClearPrompt
Carry flow:
AAndromedaSalvageItem::Interact_Implementation
UAndromedaCarryComponent::PickUpItem
UAndromedaCarryComponent::PlaceHeldItem
UAndromedaCarryComponent::DropHeldItem
UAndromedaCarryComponent::ReleaseHeldItemAtTransform
Station flow:
AAndromedaItemStation::CanInteract_Implementation
AAndromedaItemStation::Interact_Implementation
AAndromedaItemStation::PlaceItemFromCharacter
AAndromedaItemStation::HandleItemPlaced
AAndromedaItemStation::UsePlacedItem
Scanner, tagging, and warehouse:
AAndromedaScanner::ScanCurrentItem
AAndromedaScanner::ShowScanResultWidget
AAndromedaTaggingBench::CanAcceptItem
AAndromedaTaggingBench::UsePlacedItem
AAndromedaWarehouseZone::CanAcceptItem
AAndromedaWarehouseZone::HandleItemPlaced
Salvage data and processing:
AAndromedaSalvageItem::BuildScanResult
AAndromedaSalvageItem::ScanItem
AAndromedaSalvageItem::AssignRequiredPackage
AAndromedaSalvageItem::FindProcessingRule
AAndromedaSalvageItem::ProcessSalvage
UI:
UAndromedaScanResultWidget::NativeOnInitialized
UAndromedaScanResultWidget::SetScanResult
UAndromedaScanResultWidget::HandleCloseClicked
UAndromedaShiftResultWidget::NativeOnInitialized
UAndromedaShiftResultWidget::SetProcessingResult
UAndromedaShiftResultWidget::HandleCloseClicked
Debugging One Complete Item Flow¶
If you want to trace the whole current vertical slice, use this sequence.
First, put a breakpoint in:
This confirms the item is spawned at runtime and that the spawn point has a configured salvage item class.
Then put a breakpoint in:
Look at the spawned item in Play mode. The trace should hit the item. If it does not, check the item's collision and placement.
Next, put a breakpoint in:
Press E. This shows whether the character thinks it has a focused interactable, whether that object still implements the interface, and whether the fallback drop path is being used.
For pickup, step into:
then into:
This confirms that interface dispatch reached the salvage item and that the carry component accepted it.
For scanner placement, look at:
AAndromedaItemStation::Interact_Implementation
AAndromedaItemStation::PlaceItemFromCharacter
UAndromedaCarryComponent::PlaceHeldItem
This tells you whether the station is accepting the held item and whether the carry component is releasing it onto the placement point.
For scanning, interact with the scanner again and step through:
AAndromedaScanner::ScanCurrentItem
AAndromedaSalvageItem::ScanItem
AAndromedaSalvageItem::BuildScanResult
AAndromedaScanner::ShowScanResultWidget
UAndromedaScanResultWidget::SetScanResult
This confirms that the item has data, the scan result is being built, and the widget receives the result.
For tagging and final processing, use:
AAndromedaTaggingBench::UsePlacedItem
AAndromedaSalvageItem::AssignRequiredPackage
AAndromedaWarehouseZone::HandleItemPlaced
AAndromedaSalvageItem::ProcessSalvage
UAndromedaShiftResultWidget::SetProcessingResult
This follows the item from "scanned evidence" to "packaged" to "finalized outcome."
Reading Variables In The Debugger¶
When stopped at a breakpoint, inspect Unreal object references the same way you would inspect pointers in C++.
Useful variables to watch:
FocusedInteractableObject
CarryComponent
HeldItem
PlacedItem
CurrentStation
ItemData
ScanResultWidgetClass
ShiftResultWidgetClass
ProcessingAction
For TObjectPtr, Rider may show the wrapper. Expand it to find the underlying object. Conceptually, you are asking:
Is the reference set?
What concrete object does it point to?
Does that object have the expected class?
Do its reflected properties have the expected values?
If ItemData is null, the salvage item Blueprint or Data Asset assignment is wrong. If ScanResultWidgetClass is null, the scanner Blueprint is missing its widget class. If PlacedItem is null after placement should have happened, the station did not store the item or the carry release path failed.
Debugging Editor-Configured Values¶
A common Unreal debugging issue is that C++ looks correct but a Blueprint Class Default is missing.
Examples:
DefaultMappingContexts empty BP_PlayerController is missing IMC_Player.
InteractAction null BP_PlayerCharacter is missing IA_Interact.
InteractPromptWidgetClass null BP_PlayerCharacter is missing WBP_InteractPrompt.
ScanResultWidgetClass null BP_Scanner is missing WBP_ScanResult.
ItemData null Salvage item Blueprint is missing its Data Asset.
When this happens, do not immediately search for a missing C++ assignment. First ask:
If yes, inspect the Blueprint asset.
Logs vs Breakpoints¶
Use breakpoints when you need to understand control flow or object state.
Use logs when you want persistent evidence over time. For example, if an interaction works once and then stops working, logging can show the sequence of state changes across multiple inputs.
Andromeda currently uses some on-screen debug messages for early feedback. Use breakpoints or logs when the exact state matters.
When To Close The Editor Before Building¶
You do not need to close the editor for every C++ change. Live Coding can handle many .cpp implementation edits.
Close the editor and do a normal build when:
You changed reflected headers: UCLASS, USTRUCT, UENUM, UPROPERTY, or UFUNCTION.
You added or removed reflected properties/functions.
Live Coding reports a failure.
Breakpoints or symbols seem stale.
Blueprints do not see a newly added C++ property.
The editor behaves as if old code is still running.
This is not superstition. Header reflection changes involve UnrealHeaderTool and generated code. A clean editor restart is often the simplest way to get the engine, generated code, Blueprints, and debugger all looking at the same version of the program.