Multi-threaded Loop Fixes

So I’m beginning to code in C++ for my prototype and currently I do not know all the ways in which I’ll be using multi-threading in the final project. What I do know is that I want to place on a separate thread things that should run in the background that otherwise would slow down the main game thread. I have two major purposes for this particular worker thread, tracing and loops. With tracing this is simple enough. I had a prior question about having certain things perform a certain action in relation to another actor but the actor it interacts with would be based on its proximity to said actor. Link to said discussion here for context: Fill Variable Based on Proximity

Ultimately I did receive a solution I’m happy with but since the blueprint I built already has it set to where it won’t do anything if the connected actor variable is valid, and the person providing it said that it’s not exactly the most optimized solution, I’d like to know how to build a thread to perform a trace without locking up other threads. That’s one purpose, the other one is that my blueprint has a series of situations where for loops would be used and I’d like to be able to have the for loop play on a separate thread while the game plays so the loop interations can run unimpeded by other things in the game thread. I do have project files but at least according to the tutorial I followed, the setup still doesn’t seem to work with for loops in particular. So I’d like a solution that would allow traces to be performed in the background without crashing the program, and the same for either loop iterations being possible to run without playing in between frames or, if that’s not possible, a way to approximate a loop on the thread that will allow the individual iterations to run in the background without crashing the program.

Thank you for your responses.

As to tracing asynchronously, that’s pretty much built in. There’s a pretty good tutorial on doing async traces here Using Async Collision Traces in Unreal Engine 4 | by Bryan Corell | Medium

I’m not so up to speed on doing other things asynch in C++, I prefer to avoid it whenever possible. Premature optimization can be a total timewaster, if it’s not trivial to implement.

2 Likes

I’m giving your comment a heart because it does actually help get me started on one. However, the asynchronous loops are just as important in this situation so I’m not going to mark it as a solution since it doesn’t have that part. I think that’s pretty fair.

Okay, so I followed the tutorial you posted and it broke. I don’t know how else to explain it other than to just post my CPP and Header files and error log.
AsyncTraceActor.cpp (2.5 KB)
AsyncTraceActor.h (1.1 KB)
ErrorLogCurrentRelevant.txt (2.8 KB)
All of the earlier errors or compiles are not really relevant to this specific portion so I just copypasted the relevant errors to this new .txt. Regardless, I don’t know what went wrong, and the tutorial you posted doesn’t seem to have an explanation. If I missed something, I couldn’t find it going over the document several times.

[2022.08.11-17.57.02:760][611]CompilerResultsLog: F:\Prototype1Edited\Prototype1\Source\Prototype1\AsyncTraceActor.cpp(27) : error C3861: ‘DoWorkWithTraceResults’: identifier not found
[2022.08.11-17.57.02:760][611]CompilerResultsLog: F:\Prototype1Edited\Prototype1\Source\Prototype1\AsyncTraceActor.cpp(31) : error C2039: ‘DoWorkWithTraceResults’: is not a member of ‘AAsyncTraceActor’
[2022.08.11-17.57.02:760][611]CompilerResultsLog: F:\Prototype1Edited\Prototype1\Source\Prototype1\AsyncTraceActor.h(12): note: see declaration of ‘AAsyncTraceActor’

There’s no declaration of DoWorkWithTraceResults() in your .h,

[2022.08.11-17.57.02:760][611]CompilerResultsLog: F:\Prototype1Edited\Prototype1\Source\Prototype1\AsyncTraceActor.cpp(34) : error C3861: ‘ReceiveOnTraceCompleted’: identifier not found

there’s no definition of ReceiveOnTraceCompleted() in your .cpp

[2022.08.11-17.57.02:760][611]CompilerResultsLog: F:\Prototype1Edited\Prototype1\Source\Prototype1\AsyncTraceActor.cpp(50) : error C2653: ‘UKismetSystemLibrary’: is not a class or namespace name
[2022.08.11-17.57.02:760][611]CompilerResultsLog: F:\Prototype1Edited\Prototype1\Source\Prototype1\AsyncTraceActor.cpp(50) : error C2065: ‘NAME_AsyncRequestTrace’: undeclared identifier
[2022.08.11-17.57.02:760][611]CompilerResultsLog: F:\Prototype1Edited\Prototype1\Source\Prototype1\AsyncTraceActor.cpp(50) : error C3861: ‘ConfigureCollisionParams’: identifier not found

You need to include KismetSystemLibrary.h

and you need to fix the broken comment in AsyncTrace otherwise nothing will build

I would advise you to start with things that are less complex than multi-threading in C++.

1 Like

AsyncTrace is a separate file that I commented out intentionally because when I started following the tutorial, I made it an interface rather than an actor so that it could be called in any BP. I commented it out so its compilation wouldn’t mess with the other files and I seemed to get more success by following straight on by making an actor and I’ll come back to the interface later. As for the rest, the problem with the other function declarations was that I thought I had done them and my eyes glazed over as I was typing it out. That part’s on me. However, I tried to include the KismetSystemLibrary.h and it told me the library doesn’t exist. In the tutorial it also lists that the library he used was a modification anyway and he left out his includes in the tutorial so I’d have no way of knowing what includes are necessary. Finally, telling me to give up on this after providing what seems like an incomplete tutorial isn’t what I’d call helpful. I realize it’s been a while since I touched C++ and I’m rusty on top of not being that good at it to begin with. But I thought the point of an answer wiki like this is to request assistance if you need it and telling me to give up is not what I’d qualify it as.

Please accept my apologies for my tone and brevity, there.

I don’t want to discourage you from pursuing your goal, but stepping directly from learning the basics of C++ right into one of the more advanced and troublesome concepts in programming, multithreading, is a pretty long leap, even if you have asynchronous and multithreading experience in other languages.

I do appreciate you calling me out on being a jerk on that, because reflecting on what I said there, I should’ve said that better.

I just did a Find In All Files on the source to find the specific location for include, and it’s “Kismet/KismetSystemLibrary.h”.

The error in AsyncTrace.cpp (end of file in comment, meaning it can’t find the closing */ mark in the comment) will prevent the build from completing. Including KismetSystemLibrary, and putting in the missing definition in the .h and the missing function in the .cpp should get it to build, it looks like.

1 Like

I apologize if I came off as a jerk as well. Emotions are running high for me right now for other reasons. Now I did include KismetSystemLibrary but the problem is that looking through the header file it looks like the specific function the tutorial requires me to call is not in that particular library. The tutorial seems to imply that he custom made it but it’s also possible that he’s simply using a function that was added to a version of Unreal Engine post 4.23. If that’s the case, that particular part of the code will remain incomplete until I know what exactly that particular function does so I can replicate it.

I do have a question about the /* in AsyncTrace.cpp. I did do that intentionally because that particular file was an interface when the tutorial said they made it an actor. My actor variation is a file by the name AsyncTraceActor.cpp, which is a separate file. I commented out that code so that the errors in it wouldn’t populate the list of the errors I may get from the files I intend on using, short term anyway, since the more errors you get the harder each one can be to parse when looking at it. But your comment on it suggests that me commenting out that file is having an impact on Unreal Engine’s ability to fully compile the other files. Is that true? If it is, I’ll just have to delete that file and remake it later but I just want that clarified before I take that action.

1 Like

Okay so I’ve got a minor update, not really any closer to a solution but what I have figured out are where a few issues are occurring: firstly is one I mentioned before ConfigureCollisionParams does not actually exist within KismetSystemLibrary but is a function used regularly throughout KismetSystemLibrary. In other words, it’s a function that exists within a separate file. So I’m in the process of narrowing down where it is so I can expose it to my own C++ code because just including the KismetSystemLibrary.h doesn’t seem to be enough. Secondly, the NAME_AsyncRequestTrace seems after looking over it to be a variable, not a function which was confusing me. And because it’s a variable, I need to figure out what type it is so it stops returning that particular error. And thirdly, I found WorldCollisionAsync, which is definitely nice so I was hoping I could go into its header file and expose it to Blueprints and be done with this. However, bizarrely enough, it doesn’t have a header file. It includes the header file for WorldCollision but that’s about it. WorldCollisionAsync.cpp is the only file I had. I wonder if I could be offered an explanation on that because, while I’m not that good at C++, I have taken enough classes to know that header files are required for C++ for the most part. I just find it bizarre that this particular .cpp file doesn’t have a header file when nearly everything else does.

You need to have a matching */ at the end of the comment . . i may be wrong that that will cause a total failure of the build, but i think it will – usually if one file fails, it will mark the build bad and not complete it

hmmm. So ConfigureCollisionParams is included in KismetSystemLibrary, and doesn’t appear to be accessible outside of that. Interesting. I would think it would be reachable if you included KSL, but i’m not sure why that is. In any case, it’s a relatively simple utility function that you actually don’t really need to use, or you could duplicate it pretty easily.

FCollisionQueryParams ConfigureCollisionParams(FName TraceTag, bool bTraceComplex, const TArray<AActor*>& ActorsToIgnore, bool bIgnoreSelf, const UObject* WorldContextObject)
{
	FCollisionQueryParams Params(TraceTag, SCENE_QUERY_STAT_ONLY(KismetTraceUtils), bTraceComplex);
	Params.bReturnPhysicalMaterial = true;
	Params.bReturnFaceIndex = !UPhysicsSettings::Get()->bSuppressFaceRemapTable; // Ask for face index, as long as we didn't disable globally
	Params.AddIgnoredActors(ActorsToIgnore);
	if (bIgnoreSelf)
	{
		const AActor* IgnoreActor = Cast<AActor>(WorldContextObject);
		if (IgnoreActor)
		{
			Params.AddIgnoredActor(IgnoreActor);
		}
		else
		{
			// find owner
			const UObject* CurrentObject = WorldContextObject;
			while (CurrentObject)
			{
				CurrentObject = CurrentObject->GetOuter();
				IgnoreActor = Cast<AActor>(CurrentObject);
				if (IgnoreActor)
				{
					Params.AddIgnoredActor(IgnoreActor);
					break;
				}
			}
		}
	}

	return Params;
}

it just creates a FCollisionQueryParams, sets bReturnPhysicalMaterial = true, sets bReturnFaceIndex = setting in physics config, adds a list of actors to ignore, and figures out if it should ignore itself or whatever owns it.

so you could just replace that section basically with FCollisionQueryParams Params(NAME_AsyncRequestTrace, bTraceComplex)
The rest of ConfigureCollisionParams is basically accounting for it being called within Blueprint, and adding some nice to have features to assume “if i’m running in a component that is owned by an actor, then assume we want to ignore the actor not just the component”.

I also don’t have a NAME_AsyncRequestTrace, looks like they forgot to define that in the tutorial

You can just do #define NAME_AsyncRequestTrace FName(TEXT("AsyncRequestTrace")) i think will get there

It’s more of a coding style, which is usually pretty tightly enforced in Unreal (because of the fancy UnrealHeaderTool and UnrealBuildTool). For any UClass in Unreal, which will be in a .cpp file, there should be a corresponding .h include file. If you’re not defining a UClass, you don’t have to follow those rules. WorldCollisionAsync.cpp does not contain any UClasses, it looks like it’s the implementation of many functions inside the UWorld class, though.

And if you’re confused now, so am I, so stick with the style they say not the style they use sometimes :smiley:

Okay so your fixes finally got me to compile completely. Don’t know why closing the comment needed to be done just because the way I did it gave it 0 instructions to begin with either way but that resolved that issue. Creating the ConfigureCollisionParams function worked out, though I ran into some issues because Unreal Engine’s particular brand of function definition is not something I’m used to. I don’t normally have to type out namespaces because I normally just used a #using namespace line before every project, usually std but that’s beside the point. The specific thing you did for NAME_AsyncRequestTrace wasn’t building properly but doing a normal variable definition worked so it’s fine either way.

So I guess all this is perfectly acceptable for the moment. Though I guess a bonus question would be if I had to expose WorldCollisionAsync.cpp to Blueprints, how would I do that? As I was doing this I remembered what .h files are actually for. They’re just a location you can place your function headings so you don’t have to place them at the top of your .cpp files. If that memory is correct, the solution would then be to just go into the top of the file and just use BlueprintCallable but looking at the file that doesn’t seem to be how it’s built. It looks a lot more like the old Java files I’d create where you don’t have to define a function heading and function separately, you just create the function and use it. Which makes this a little bit confusing.

not having a comment closing indicator is usually a sign of forgetting to close the comment, which makes the entire file not compile, which is usually an error, so the compiler chastises you for doing it :smiley:

there was a semicolon at the end of my #define that probably did it. I just edited that out, i don’t use defines too much, and just end my lines with ; but defines don’t use a ; at the end

It looks like most or all of the things in WorldCollisionAsync.cpp are declared in World.h, and are part of the UWorld, which is a singleton (mostly) that you can grab with GetWorld() from most places.

// oh, also i’m sorry to hear of whatever has you out of sorts. i hope that works out for the best. i get that, i’ve had a pretty tragic last 60 days too.