Runtime-editable environment queries from c++ won't build

Hi,

I am trying to create an environment query from c++ code at load time, so it can be modified at runtime and so I can use a context that just pulls values from a static array of targetable entities.

I am deriving an example query from the eqs quickstart tutorial in the official docs. The source code of the environment query system seems to indicate a way to port the query to c++, what I have is this:

static void FindCoverAttackSpot(FString name, float minDist, float maxDist, float optimalDist) {
		UEnvQuery* eq = NewObject<UEnvQuery>();
		TArray<UEnvQueryOption*>& options=eq->GetOptionsMutable();
		options.Reset();
		options.Add(NewObject<UEnvQueryOption>());
		options[0]->Generator = NewObject<UEnvQueryGenerator_ActorsOfClass>();
		Cast<UEnvQueryGenerator_ActorsOfClass>(options[0]->Generator)->SearchRadius.DefaultValue = 10.0;
		Cast<UEnvQueryGenerator_ActorsOfClass>(options[0]->Generator)->SearchedActorClass = ACoverAttackSpot::StaticClass();
		options[0]->Tests.Add(NewObject<UEnvQueryTest_Distance>());
		Cast<UEnvQueryTest_Distance>(options[0]->Tests[0])->TestMode = EEnvTestDistance::Distance3D;
		Cast<UEnvQueryTest_Distance>(options[0]->Tests[0])->DistanceTo = UPlayersContext::StaticClass();
		Cast<UEnvQueryTest_Distance>(options[0]->Tests[0])->FloatValueMin.DefaultValue = minDist;
		Cast<UEnvQueryTest_Distance>(options[0]->Tests[0])->FloatValueMax.DefaultValue = maxDist;
		Cast<UEnvQueryTest_Distance>(options[0]->Tests[0])->ReferenceValue.DefaultValue = optimalDist;
		Cast<UEnvQueryTest_Distance>(options[0]->Tests[0])->FilterType = EEnvTestFilterType::Range;
		options[0]->Tests.Add(NewObject<UEnvQueryTest_Distance>());
		Cast<UEnvQueryTest_Distance>(options[0]->Tests[1])->TestMode = EEnvTestDistance::Distance3D;
		Cast<UEnvQueryTest_Distance>(options[0]->Tests[1])->DistanceTo = UEnvQueryContext_Querier::StaticClass();
		Cast<UEnvQueryTest_Distance>(options[0]->Tests[1])->FloatValueMin.DefaultValue = 0.0;
		Cast<UEnvQueryTest_Distance>(options[0]->Tests[1])->FloatValueMax.DefaultValue = 10000.0;
		Cast<UEnvQueryTest_Distance>(options[0]->Tests[1])->ReferenceValue.DefaultValue = 1.0;
		Cast<UEnvQueryTest_Distance>(options[0]->Tests[1])->FilterType = EEnvTestFilterType::Range;
		options[0]->Tests.Add(NewObject<UEnvQueryTest_Trace>());
		Cast<UEnvQueryTest_Trace>(options[0]->Tests[2])->Context = UPlayersContext::StaticClass();
		Cast<UEnvQueryTest_Trace>(options[0]->Tests[2])->FilterType = EEnvTestFilterType::Match;
		Cast<UEnvQueryTest_Trace>(options[0]->Tests[2])->BoolValue.DefaultValue=false;
		options[0]->Tests.Add(NewObject<UEnvQueryTest_Dot_Exposed>());
		Cast<UEnvQueryTest_Dot_Exposed>(options[0]->Tests[3])->SetDefaults();
		options[0]->Tests.Add(NewObject<UEnvQueryTest_Pathfinding>());
		Cast<UEnvQueryTest_Pathfinding>(options[0]->Tests[4])->TestMode = EEnvTestPathfinding::PathCost;
		Cast<UEnvQueryTest_Pathfinding>(options[0]->Tests[4])->Context = UEnvQueryContext_Querier::StaticClass();
		Cast<UEnvQueryTest_Pathfinding>(options[0]->Tests[4])->PathFromContext.DefaultValue = true;

		Cast<UEnvQueryTest_Pathfinding>(options[0]->Tests[4])->SkipUnreachable.DefaultValue = true;
		queries.Add(name, eq);
	}

This differs from the tutorial in some of the parameters and logic, but hopefully you can see what I am trying to do.
UPlayersContext has the following method:

void UPlayersContext::ProvideContext(FEnvQueryInstance& QueryInstance, FEnvQueryContextData& ContextData) const {

	AActor* QuerierActor = Cast<AActor>(QueryInstance.Owner.Get());

	UBlackboardComponent* BB = QuerierActor->FindComponentByClass<UBlackboardComponent>();
	if (BB != nullptr) {
		AActor* target = Cast<AActor>(BB->GetValue<UBlackboardKeyType_Object>(FName(TEXT("Target"))));
		if (target != nullptr) {
			UEnvQueryItemType_Actor::SetContextHelper(ContextData, target);
		}
	}
	TArray<AActor*> ResultingActorsSet;
	std::vector<AActor*> res1 = CharacterRegistry::GetPlayers();
	for (int i = 0, e = res1.size(); i < e; ++i) {
		ResultingActorsSet.Add(res1[i]);
	}
	UEnvQueryItemType_Actor::SetContextHelper(ContextData, ResultingActorsSet);
}

Problem is, I get some link errors:

2>BehaviorRegistry.cpp.obj : error LNK2019: unresolved external symbol "private: static class UClass * __cdecl UEnvQueryGenerator_ActorsOfClass::GetPrivateStaticClass(wchar_t const *)" (?GetPrivateStaticClass@UEnvQueryGenerator_ActorsOfClass@@CAPEAVUClass@@PEB_W@Z) referenced in function "class UEnvQueryGenerator_ActorsOfClass * __cdecl Cast<class UEnvQueryGenerator_ActorsOfClass,class UEnvQueryGenerator>(class UEnvQueryGenerator *)" (??$Cast@VUEnvQueryGenerator_ActorsOfClass@@VUEnvQueryGenerator@@@@YAPEAVUEnvQueryGenerator_ActorsOfClass@@PEAVUEnvQueryGenerator@@@Z)
2>Bounty.generated.cpp.obj : error LNK2001: unresolved external symbol "private: static class UClass * __cdecl UEnvQueryGenerator_ActorsOfClass::GetPrivateStaticClass(wchar_t const *)" (?GetPrivateStaticClass@UEnvQueryGenerator_ActorsOfClass@@CAPEAVUClass@@PEB_W@Z)
2>BehaviorRegistry.cpp.obj : error LNK2019: unresolved external symbol "public: __cdecl UEnvQueryGenerator_ActorsOfClass::UEnvQueryGenerator_ActorsOfClass(class FObjectInitializer const &)" (??0UEnvQueryGenerator_ActorsOfClass@@QEAA@AEBVFObjectInitializer@@@Z) referenced in function "public: static void __cdecl BehaviorRegistry::FindCoverAttackSpot(class FString,float,float,float)" (?FindCoverAttackSpot@BehaviorRegistry@@SAXVFString@@MMM@Z)
2>Bounty.generated.cpp.obj : error LNK2001: unresolved external symbol "public: __cdecl UEnvQueryGenerator_ActorsOfClass::UEnvQueryGenerator_ActorsOfClass(class FObjectInitializer const &)" (??0UEnvQueryGenerator_ActorsOfClass@@QEAA@AEBVFObjectInitializer@@@Z)
2>BehaviorRegistry.cpp.obj : error LNK2019: unresolved external symbol "private: static class UClass * __cdecl UEnvQueryTest_Pathfinding::GetPrivateStaticClass(wchar_t const *)" (?GetPrivateStaticClass@UEnvQueryTest_Pathfinding@@CAPEAVUClass@@PEB_W@Z) referenced in function "class UEnvQueryTest_Pathfinding * __cdecl Cast<class UEnvQueryTest_Pathfinding,class UEnvQueryTest>(class UEnvQueryTest *)" (??$Cast@VUEnvQueryTest_Pathfinding@@VUEnvQueryTest@@@@YAPEAVUEnvQueryTest_Pathfinding@@PEAVUEnvQueryTest@@@Z)
2>Bounty.generated.cpp.obj : error LNK2001: unresolved external symbol "private: static class UClass * __cdecl UEnvQueryTest_Pathfinding::GetPrivateStaticClass(wchar_t const *)" (?GetPrivateStaticClass@UEnvQueryTest_Pathfinding@@CAPEAVUClass@@PEB_W@Z)
2>BehaviorRegistry.cpp.obj : error LNK2019: unresolved external symbol "public: __cdecl UEnvQueryTest_Pathfinding::UEnvQueryTest_Pathfinding(class FObjectInitializer const &)" (??0UEnvQueryTest_Pathfinding@@QEAA@AEBVFObjectInitializer@@@Z) referenced in function "public: static void __cdecl BehaviorRegistry::FindCoverAttackSpot(class FString,float,float,float)" (?FindCoverAttackSpot@BehaviorRegistry@@SAXVFString@@MMM@Z)
2>Bounty.generated.cpp.obj : error LNK2001: unresolved external symbol "public: __cdecl UEnvQueryTest_Pathfinding::UEnvQueryTest_Pathfinding(class FObjectInitializer const &)" (??0UEnvQueryTest_Pathfinding@@QEAA@AEBVFObjectInitializer@@@Z)
2>BehaviorRegistry.cpp.obj : error LNK2019: unresolved external symbol "private: static class UClass * __cdecl UEnvQueryTest_Distance::GetPrivateStaticClass(wchar_t const *)" (?GetPrivateStaticClass@UEnvQueryTest_Distance@@CAPEAVUClass@@PEB_W@Z) referenced in function "class UEnvQueryTest_Distance * __cdecl Cast<class UEnvQueryTest_Distance,class UEnvQueryTest>(class UEnvQueryTest *)" (??$Cast@VUEnvQueryTest_Distance@@VUEnvQueryTest@@@@YAPEAVUEnvQueryTest_Distance@@PEAVUEnvQueryTest@@@Z)
2>Bounty.generated.cpp.obj : error LNK2001: unresolved external symbol "private: static class UClass * __cdecl UEnvQueryTest_Distance::GetPrivateStaticClass(wchar_t const *)" (?GetPrivateStaticClass@UEnvQueryTest_Distance@@CAPEAVUClass@@PEB_W@Z)
2>BehaviorRegistry.cpp.obj : error LNK2019: unresolved external symbol "public: __cdecl UEnvQueryTest_Distance::UEnvQueryTest_Distance(class FObjectInitializer const &)" (??0UEnvQueryTest_Distance@@QEAA@AEBVFObjectInitializer@@@Z) referenced in function "public: static void __cdecl BehaviorRegistry::FindCoverAttackSpot(class FString,float,float,float)" (?FindCoverAttackSpot@BehaviorRegistry@@SAXVFString@@MMM@Z)
2>Bounty.generated.cpp.obj : error LNK2001: unresolved external symbol "public: __cdecl UEnvQueryTest_Distance::UEnvQueryTest_Distance(class FObjectInitializer const &)" (??0UEnvQueryTest_Distance@@QEAA@AEBVFObjectInitializer@@@Z)
2>BehaviorRegistry.cpp.obj : error LNK2019: unresolved external symbol "public: __cdecl UEnvQueryTest_Dot_Exposed::UEnvQueryTest_Dot_Exposed(class FObjectInitializer const &)" (??0UEnvQueryTest_Dot_Exposed@@QEAA@AEBVFObjectInitializer@@@Z) referenced in function "public: static void __cdecl BehaviorRegistry::FindCoverAttackSpot(class FString,float,float,float)" (?FindCoverAttackSpot@BehaviorRegistry@@SAXVFString@@MMM@Z)
2>Bounty.generated.cpp.obj : error LNK2001: unresolved external symbol "public: __cdecl UEnvQueryTest_Dot_Exposed::UEnvQueryTest_Dot_Exposed(class FObjectInitializer const &)" (??0UEnvQueryTest_Dot_Exposed@@QEAA@AEBVFObjectInitializer@@@Z)
2>BehaviorRegistry.cpp.obj : error LNK2001: unresolved external symbol "private: static class TMap<class FString,class UBehaviorTree *,class FDefaultSetAllocator,struct TDefaultMapKeyFuncs<class FString,class UBehaviorTree *,0> > BehaviorRegistry::behaviors" (?behaviors@BehaviorRegistry@@0V?$TMap@VFString@@PEAVUBehaviorTree@@VFDefaultSetAllocator@@U?$TDefaultMapKeyFuncs@VFString@@PEAVUBehaviorTree@@$0A@@@@@A)
2>Bounty.generated.cpp.obj : error LNK2001: unresolved external symbol "private: static class TMap<class FString,class UBehaviorTree *,class FDefaultSetAllocator,struct TDefaultMapKeyFuncs<class FString,class UBehaviorTree *,0> > BehaviorRegistry::behaviors" (?behaviors@BehaviorRegistry@@0V?$TMap@VFString@@PEAVUBehaviorTree@@VFDefaultSetAllocator@@U?$TDefaultMapKeyFuncs@VFString@@PEAVUBehaviorTree@@$0A@@@@@A)
2>BehaviorRegistry.cpp.obj : error LNK2001: unresolved external symbol "private: static class TMap<class FString,class UEnvQuery *,class FDefaultSetAllocator,struct TDefaultMapKeyFuncs<class FString,class UEnvQuery *,0> > BehaviorRegistry::queries" (?queries@BehaviorRegistry@@0V?$TMap@VFString@@PEAVUEnvQuery@@VFDefaultSetAllocator@@U?$TDefaultMapKeyFuncs@VFString@@PEAVUEnvQuery@@$0A@@@@@A)
2>Bounty.generated.cpp.obj : error LNK2001: unresolved external symbol "private: static class TMap<class FString,class UEnvQuery *,class FDefaultSetAllocator,struct TDefaultMapKeyFuncs<class FString,class UEnvQuery *,0> > BehaviorRegistry::queries" (?queries@BehaviorRegistry@@0V?$TMap@VFString@@PEAVUEnvQuery@@VFDefaultSetAllocator@@U?$TDefaultMapKeyFuncs@VFString@@PEAVUEnvQuery@@$0A@@@@@A)
2>GuardSensory.cpp.obj : error LNK2001: unresolved external symbol "public: virtual void __cdecl IGameplayTaskOwnerInterface::OnGameplayTaskActivated(class UGameplayTask &)" (?OnGameplayTaskActivated@IGameplayTaskOwnerInterface@@UEAAXAEAVUGameplayTask@@@Z)
2>NPC.cpp.obj : error LNK2001: unresolved external symbol "public: virtual void __cdecl IGameplayTaskOwnerInterface::OnGameplayTaskActivated(class UGameplayTask &)" (?OnGameplayTaskActivated@IGameplayTaskOwnerInterface@@UEAAXAEAVUGameplayTask@@@Z)
2>Bounty.generated.cpp.obj : error LNK2001: unresolved external symbol "public: virtual void __cdecl IGameplayTaskOwnerInterface::OnGameplayTaskActivated(class UGameplayTask &)" (?OnGameplayTaskActivated@IGameplayTaskOwnerInterface@@UEAAXAEAVUGameplayTask@@@Z)
2>GuardSensory.cpp.obj : error LNK2001: unresolved external symbol "public: virtual void __cdecl IGameplayTaskOwnerInterface::OnGameplayTaskDeactivated(class UGameplayTask &)" (?OnGameplayTaskDeactivated@IGameplayTaskOwnerInterface@@UEAAXAEAVUGameplayTask@@@Z)
2>NPC.cpp.obj : error LNK2001: unresolved external symbol "public: virtual void __cdecl IGameplayTaskOwnerInterface::OnGameplayTaskDeactivated(class UGameplayTask &)" (?OnGameplayTaskDeactivated@IGameplayTaskOwnerInterface@@UEAAXAEAVUGameplayTask@@@Z)
2>Bounty.generated.cpp.obj : error LNK2001: unresolved external symbol "public: virtual void __cdecl IGameplayTaskOwnerInterface::OnGameplayTaskDeactivated(class UGameplayTask &)" (?OnGameplayTaskDeactivated@IGameplayTaskOwnerInterface@@UEAAXAEAVUGameplayTask@@@Z)
2>Bounty.generated.cpp.obj : error LNK2001: unresolved external symbol "protected: virtual void __cdecl UEnvQueryTest_Dot::RunTest(struct FEnvQueryInstance &)const " (?RunTest@UEnvQueryTest_Dot@@MEBAXAEAUFEnvQueryInstance@@@Z)
2>Bounty.generated.cpp.obj : error LNK2001: unresolved external symbol "protected: virtual class FText __cdecl UEnvQueryTest_Dot::GetDescriptionTitle(void)const " (?GetDescriptionTitle@UEnvQueryTest_Dot@@MEBA?AVFText@@XZ)
2>Bounty.generated.cpp.obj : error LNK2001: unresolved external symbol "protected: virtual class FText __cdecl UEnvQueryTest_Dot::GetDescriptionDetails(void)const " (?GetDescriptionDetails@UEnvQueryTest_Dot@@MEBA?AVFText@@XZ)

And so on. Is this because the classes I’m trying to use are not exposed? Am I correct in my suspicion that I will have to fork the engine, expose the appropriate classes in AIModule, and then rebuild? Or is there an easier way to make environment queries runtime-editable from c++? Or is my approach completely wrong?

UEnvQueryTest_Dot_Exposed, I should mention, is just a class that inherits from UEnvQueryTest_Dot and sets the protected members.

Not sure if you found the answer but I found this create new object solution to get around the LNK2019 issue.

    UClass* Class = FindObject<UClass>(ANY_PACKAGE, TEXT("/Script/AIModule.EnvQueryTest_Distance"));
	UEnvQueryTest* DistanceTest = NewObject<UEnvQueryTest>(this, Class);
	UEnvQueryTest_Distance* DistanceTestWrapper = (UEnvQueryTest_Distance*)(Test2);
	DistanceTestWrapper->TestPurpose = EEnvTestPurpose::Score;

I’ll leave this here in case anyone else has a similar issue as I spent hours trying to find a solution.