Creating a EQS Test

I’m trying to create a EQS test that is used with the Actors of type generator. the purpose of the test is to check the team variable inside the class passed. ( I understand that it’s not very generic but it will get the job done for now ). I’m just taking a shot at it by looking at the EQS Distance Test but I’m having trouble converting the QueryInstance to my specific actor class. I imagine that this is because tests are supposed to be able to be used with any kind of generator but I just don’t have a switch in there yet. This is where I stand so far but the Cast< AShadowHeroes_Unit >(QueryInstance.GetItemAsActor) throws an error.

If anyone can help point me in the correct direction, I’d appreciate it.

I know it should be more generic than it is, but It’s a proof of concept before I try to include a templated class parameter to the test. (I’ll look at how it’s done in the actors of class generator)

EQS_TeamTest.h

UCLASS()
class UEQS_TeamTest : public UEnvQueryTest
{
	GENERATED_BODY()

	UPROPERTY(EditDefaultsOnly, Category = Team)
	int16 Team;

	virtual void RunTest(FEnvQueryInstance& QueryInstance) const override;

	virtual FString GetDescriptionTitle() const override;
	virtual FText GetDescriptionDetails() const override;	
	
};

EQS_TeamTest.cpp

void UEQS_TeamTest::RunTest(FEnvQueryInstance& QueryInstance) const
{
	float MinThresholdValue = 0.0f;
	if (!QueryInstance.GetParamValue(FloatFilterMin, MinThresholdValue, TEXT("FloatFilterMin")))
	{
		return;
	}

	float MaxThresholdValue = 0.0f;
	if (!QueryInstance.GetParamValue(FloatFilterMax, MaxThresholdValue, TEXT("FloatFilterMax")))
	{
		return;
	}

	for (FEnvQueryInstance::ItemIterator It(this, QueryInstance); It; ++It)
	{	
		if ( Cast<AShadowHeroes_Unit>(QueryInstance.GetItemAsActor)->Team == Team)
		{
			It.SetScore(TestPurpose, FilterType, 1, MinThresholdValue, MaxThresholdValue);
		}
	}
	
}

What kind of error does it throw at you? If you just copy-pasted your code here I’d guess the problem is that you’re missing parenthesis in your GetItemAsActor call :slight_smile:

Cheers,

–mieszko

After going over the code over and over again, I don’t know how I missed that. Sometimes It’s the little things right? :wink:

Happens to everyone :slight_smile:

This is a bit odd, it looks like the iterator is not moving across the actors. Inside my Run Test I have this:

int i = 0;
	for (FEnvQueryInstance::ItemIterator It(this, QueryInstance); It; ++It)
	{	
		i++;
			
		UE_LOG(LogTemp, Warning, TEXT("%s T-%d : Test - %d"),
			*(Cast<AShadowHeroes_Unit>(QueryInstance.GetItemAsActor(It)))->GetName(),
			Cast<AShadowHeroes_Unit>(QueryInstance.GetItemAsActor(It))->Team,
			Team);				

		if ( (Cast<AShadowHeroes_Unit>(QueryInstance.GetItemAsActor(It)))->Team == Team )
		{			
			UE_LOG(LogTemp, Warning, TEXT("%d : Pass"), i);
			It.SetScore(TestPurpose, EEnvTestFilterType::Match, 1, 1);
		} 
		else
		{
			UE_LOG(LogTemp, Warning, TEXT("%d : Fail"), i);
			It.SetScore(TestPurpose, EEnvTestFilterType::Match, 0, 1);
		}
	}

Yet my output is always the same for the actor being checked. The name of the actor should be changing as it move across the actors in range. ( I do a distance check as well which I assume is running first since both tests are low and distance is listed first )

23391-output.png

What is the relationship between the Item Iterator and the test? I thought the iterator would go over each item being tested and by calling QueryInstance.GetItemAsActor(It) it would return the actor related to that test. but it seems that it only return the first instance.

Ok I got it to iterate though it was not very intuitive. It actually feels kind of dirty to be using a int value inside a iterator for loop. It feels kind of hacky right now. Is this the intended way of getting actors?

	int i = 0;

	for (FEnvQueryInstance::ItemIterator It(this, QueryInstance); It; ++It)
	{
		if ((Cast<AShadowHeroes_Unit>(QueryInstance.GetItemAsActor(QueryInstance.ItemDetails[i].ItemIndex)))->Team == Team)
		{
			It.SetScore(TestPurpose, EEnvTestFilterType::Match, 1, 1);
		}
		else
		{
			It.SetScore(TestPurpose, EEnvTestFilterType::Match, 0, 1);
		}
		i++;
	}

I finally had a moment to look at this, and there’s a bug in your code: QueryInstance.GetItemAsActor(It) will always result in getting the actor at index 1 since using pure It in this case will result in converting it to bool rather then int32 index. Use *It instead.

I’ve noticed one of engine level tests recently added ( UEnvQueryTest_GameplayTags ) suffers from the same issue. I’ll get it fixed right away.

Also, I’ll add a kind of safety feature so this gets detected in the future. Thanks for making this mistake that will result in more robust EQS code! :smiley:

No worries, the fix is already in the master branch :slight_smile:

ahh that makes sense an no problem. Just let me know and I’ll screw up all day for you :stuck_out_tongue: