Debug Help! I cannot find issue and don't know how to test. Multithreading.

Context: I’ve just started moving from blueprints into C++ because I need to multithread my CPU-heavy project. The first thing I’d like to multithread is my A* pathfinding. I’ve converted my blueprints into c++. My problem is that the game crashes during standalone bootup so I don’t even know how to test it with UELog or screen prints.

I’ve submitted my error logs and code to ChatGPT and it suggests potential memory handling issues or that I’m not properly killing the FRunnable thread. I’ve been spending days messing around with ChatGPT’s suggestions. I feel like ive google everything, but there isnt a lot of info on FRunnable. Was hoping a pro could look over this to see if I have pointer issues or an infinite loop. It works perfectly in blueprints and converting it to C++ seemed pretty straight forward.

Live-coding error log:

UE Crash reporter log:

FRunnable Handler Actor class:
AsyncPatherfinderActor.h (1.5 KB)
AsyncPatherfinderActor.cpp (2.9 KB)

Frunnable Thread:
AsyncPathfinder.h (2.1 KB)
AsyncPathfinder.cpp (8.6 KB)

Any resources, suggestions on how to test something like this, or a second set of eyes on the code would be SO helpful. Thank you in advance!

It could also be that I’m not cleaning up the thread upon kill. I had the Frunnable working prior to adding the pathfinding code though.

The other insanely annoying thing is that it compiles fine and then when i run it it crashes and breaks all of my C++ structs and various pins & functions in the C++ actor class in blueprints. Then i have to rebuild literally everything just to test it again.

  1. Did you save the blueprint? Losing changes in the blueprint should only happen if you did not save it before trying it.
  2. Start the UE-Editor from Visual Studio with F5, then do as normal until the game crashes, use the callstack, scroll through until you find lines in YOUR code and check these lines for your error.

I did what you said with F5 and tried to boot from VS but i get this error

Screenshot 2024-06-25 125738

and when i go into the properties i cant make sense of it.

To start coding in VS I usually just open a c++ class from UE5 and then live compile in the editor.

@BugSwat

As far as saving- yes i always save, but UE just decides that my c++ structs and enums don’t exist anymore.

I’m feeling like I’m never gonna get past this uggh. Any suggestions? Im trying to put UELOG reports at every step of the way but it seems like its not even getting into the class before it crashes.

I’ll pay someone to get these Multithread classes working, explain what’s wrong and how to replicate it for other processes. Thanks

Give me an example for the data needed for Find path

it throws an error data is not valid

LineWarsMax.zip (614.4 KB)

I’m surprised you even got yours to compile. The functions wont take pure enum arrays.

Next time please post the accompanying enums and structs.
People will help you, but value their time.
Not everyone will have the patience to recreate missing files based on sparse data.

1 Like

Hey Raven! Thx so much for your help. I’m sorry I didn’t provide everything you would need.

Here’s the enums and structs
MyCustomEnums.h (808 Bytes)
MyCustomStructs.h (1.4 KB)
MyCustomEnums.cpp (112 Bytes)
MyCustomStructs.cpp (114 Bytes)

Here is example data. The map creates a 3x3 grid all tiles are valid EXCEPT the middle one (marked obstacle). The pathfinding starts at 0,0 and should end at 2,2 avoiding the middle tile 1,1.

This I’m not sure about - I’ve been using enum arrays a ton in my code. Uh oh!

@3dRaven

The other thing to note is that every time I restart unreal it breaks all of my C++ structs and enums like this. I can’t figure out why…

You need to run your project from your IDE otherwise custom c++ parent files break.

1 Like

It says this in live coding screen

Don’t use live coding. It only partly evaluates changes in code and can make your project prone to corruption.

1 Like

Ok. Understood on the last couple messages. Thx for your time. I really appreciate it

You error was in GetValidTileNeighbors, you forgot to check if the passed in parameter Data is a null pointer. This would cause the engine to crash once you tried to access it and if it was invalid

I added in a check. Best to debug the algorithm and see if the proper data is being passed on


TArray<FPathfindingDataCPP> FAsyncPathfinder::GetValidTileNeighbors(FIntPoint Index, bool IncludeDiagonals, const TArray<ETileTypeCPP>& ValidTypes)
{

	int32 None = 0;
	int32 Normal = 1;
	int32 Obstacle = 0;
	int32 TowerGround = 1;
	int32 TowerFlyer = 1;
	int32 TowerEth = 1;
	int32 FlyerOnly = 1;
	int32 Trap = 1;
	int32 Spawn = 1;
	int32 Goal = 1;
	int32 DoubleC = 2;
	int32 TripleC = 3;

	int32 SelectedValue;

	TArray<FPathfindingDataCPP> Ret;
	FTileDataCPP* InputData = CurrentGrid.Find(Index);
	TArray<FIntPoint> Neighbors = GetNeighborIndexes(Index, true);
	for (auto& Item : Neighbors)
	{
		FTileDataCPP* Data = CurrentGrid.Find(Item);
		if (Data != nullptr)
		{
			if (ValidTypes.Contains(Data->Type)) {
				switch (Data->Type)
				{
				case ETileTypeCPP::ED_None:
					SelectedValue = None;
					break;
				case ETileTypeCPP::ED_Normal:
					SelectedValue = Normal;
					break;
				case ETileTypeCPP::ED_Obstacle:
					SelectedValue = Obstacle;
					break;
				case ETileTypeCPP::ED_TowerGround:
					SelectedValue = TowerGround;
					break;
				case ETileTypeCPP::ED_TowerFlyer:
					SelectedValue = TowerFlyer;
					break;
				case ETileTypeCPP::ED_TowerEthereal:
					SelectedValue = TowerEth;
					break;
				case ETileTypeCPP::ED_FlyerOnly:
					SelectedValue = FlyerOnly;
					break;
				case ETileTypeCPP::ED_Trap:
					SelectedValue = Trap;
					break;
				case ETileTypeCPP::ED_Spawn:
					SelectedValue = Spawn;
					break;
				case ETileTypeCPP::ED_Goal:
					SelectedValue = Goal;
					break;
				case ETileTypeCPP::ED_DoubleCost:
					SelectedValue = DoubleC;
					break;
				case ETileTypeCPP::ED_TripleCost:
					SelectedValue = TripleC;
					break;
				default:
					SelectedValue = 999;  // Handle invalid case
					break;
				}
				FPathfindingDataCPP TempPFD;
				TempPFD.Index = Data->Index;
				TempPFD.CostToEnterTile = SelectedValue;
				TempPFD.CostFromStart = 999999;
				TempPFD.MinimumCostToTarget = 999999;
				TempPFD.PreviousIndex = Index;
				Ret.Add(TempPFD);
			}
		}
	}
	return Ret;
}

1 Like

Thank you so so much. If it wont even start the game how did you go about debugging this if there is no log being produced?

Run your ide with debugging enabled and put in break points into your c++ code. Once a condition is met and the debugger pauses you can then hover over variables near the debug point to see variable values and step over the code following it’s execution.

You probably still need to add a callback to the thread to let unreal know that the calculations are done so you can access the path

1 Like

It boots up! Woohoo. It is definitely not returning the right information though. It’s returning an empty queue item, but i can work through this now. You’re a life saver!!! I was feeling defeated. So thank you.

Also, you helped me get sorted through the workflow now that I’m working in Visual Studio. I think I’m now on the right path.

Are you saying that if a thread happens to be Enqueueing while another process is dequeueing it could crash?

My plan was to have a process in unreal constantly checking to see if the queue has items. As it gets items i pop them out and process them

No. It’s just that when you use threads they calculate at their own pace. You need to add in a delegate that you can call once the calculations are done to let the engine know that the work is finished => here are the presented path items…

No need for constant checking. It’s a waste of resources and not how threads are meant to work.

1 Like