AI Perception Mark player as enemy

How do I mark the player as an enemy for my AI so that they will sense him when using “Detection by Affiliation: Detect Enemies”?

Also see this old topic: https://answers.unrealengine.com/questions/285849/aiperception-how-to-use-detection-by-affiliation.html

What’s the proper way to do this now? I added the interface IGenericTeamAgentInterface. But I have no idea how to set the actual (const) member. All I could find was:

87154-c.png

I set the interface in C++:

#include "Runtime/AIModule/Classes/GenericTeamAgentInterface.h"
class AFPS1Character : public ACharacter, public IGenericTeamAgentInterface

But it crashes: Assertion failed: bCreateOnlyIfEmpty || !PointerToUberGraphFrame->RawPointer [File:D:\BuildFarm\buildmachine_++UE4+Release-4.11\Engine\Source\Runtime\Engine\Private\BlueprintGeneratedClass.cpp] [Line: 647]

But could also be done through this: https://docs.unrealengine.com/latest/INT/Engine/Blueprints/UserGuide/Types/Interface/UsingInterfaces/index.html (which does not crash the engine even though they should be the same?)

Why is it so hard to set a simple int-variable? Am I doing it all wrong?

Since 4.10 is recommended to use a AI controller as provider of diplomacy options:

class AIMODULE_API AAIController : .... public IGenericTeamAgentInterface

Override method with logics of your game:

virtual FGenericTeamId GetGenericTeamId() const override { return TeamID; }
virtual ETeamAttitude::Type	 GetTeamAttitudeTowards(const AActor& Other) const override;

Sorry I’m not that experienced with C++ yet.

virtual FGenericTeamId GetGenericTeamId() const override { return FGenericTeamId::NoTeam; }

There is no build-in struct-member for Enemy, Player & Neutral. Does that mean we have to create those ourselves as well? Only FGenericTeamId::NoTeam is present.

Also it gives me 496 errors:

GetGenericTeamId provides ID of the team only. GetTeamAttitudeTowards logic provides attittude to unit (Enemy, Neutral or Friendly). At the moment there is no version of these functions for use in blueprints.

Your controller should override these methods, and as an option to provide a wrapper for blueprints. I do not know any other way at this time.

UENUM(BlueprintType)
enum class ETeamAttitudeWrapper : uint8
{
Friendly = 0,
Neutral,
Hostile
};

UFUNCTION(BlueprintCallable, DisplayName = "GetTeamAttitudeTowards", Category = "AI")
ETeamAttitudeWrapper K2_GetTeamAttitudeTowards(AActor* Other) const;

ETeamAttitudeWrapper  YourAIController::K2_GetTeamAttitudeTowards(AActor* Other) const
{
	return (ETeamAttitudeWrapper)GetTeamAttitudeTowards(*Other);
}

Sorry I can’t get it to compile. Also can’t really make our own enum for it. We have to use the one UE4 uses in it’s interface ( FGenericTeamId | Unreal Engine Documentation ) and extend that. But C++ does not really support it. And you end up with gigantic workarounds. I give up.

I’m going back to PawnSensing. I know it’s ‘deprecated’ but at least it works. This is too much of a mess just to set a very very simple enum on the player actor…

I’ll mark it as answered since you are pointing in the right direction but my C++ knowledge is just not advanced enough yet to do this.

Other solution

UCLASS(BlueprintType)
class UTempResult : public UObject
{
	GENERATED_BODY()

public:
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "AI")
	ETeamAttitudeWrapper Result;
};

class AYourAIController
{
public:
	UFUNCTION(BlueprintImplementableEvent, DisplayName = "GetTeamAttitudeTowards", Category = "AI")
	void	K2_GetTeamAttitudeTowards(const AActor* Other, UTempResult* Result);
	virtual void K2_GetTeamAttitudeTowards_Implementation(const AActor* Other, UTempResult* Result);

	UPROPERTY()
	UTempResult* TempResult;
};

void AYourAIController::BeginPlay()
{
	Super::BeginPlay();
	TempResult = NewObject<UTempResult>();
}

void AYourAIController::K2_GetTeamAttitudeTowards_Implementation(const AActor*, UTempResult* Result)
{
}

ETeamAttitude::Type AYourAIController::GetTeamAttitudeTowards(const AActor& Other) const
{
	// Hack
	const_cast<AYourAIController*>(this)->K2_GetTeamAttitudeTowards(&Other, TempResult);
	ETeamAttitude::Type Result = (ETeamAttitude::Type) TempResult->Result;

	return Result;
}

I gave it another try without hacking around first. But it always returns neutral because OtherTeamAgent always evaluates to false. And I was so close…
Still, the amount of C++ knowledge needed for this is quite advanced. You need knowledge about: inheritance, overriding with different scopes, virtuals + constants, references, extending enums (EPredefinedId), etc. etc. How are people using only blueprints supposed to implement this? Also the internal code looks ‘odd’, may need some refactoring.

Not sure but I may also have to set the TeamID it seems.

// header file (did the same to the playercontroller)
#pragma once

#include "AIController.h"
#include "FPS1AIController.generated.h"

/**
 * AAIController already implements the IGenericTeamAgentInterface so don't add it here.
 */
UCLASS()
class FPS1_API AFPS1AIController : public AAIController
{
	GENERATED_BODY()
	
public:


	virtual FGenericTeamId GetGenericTeamId() const { return ETeamAttitude::Hostile; }
	// WHY is this method private (in their interface) while their static solver is public?
	// WHY do they use both a solver and this method? Why so complicated?
	virtual ETeamAttitude::Type GetTeamAttitudeTowards(const AActor& Other) const
	{
		const IGenericTeamAgentInterface* OtherTeamAgent = Cast<const IGenericTeamAgentInterface>(&Other);

		if (OtherTeamAgent) // <<<<<<<< always evaluates to false? WHY?
		{
			UE_LOG(LogTemp, Error, TEXT("checking"))
			return OtherTeamAgent->GetGenericTeamId() ? ETeamAttitude::Hostile : ETeamAttitude::Neutral;
			//return ETeamAttitude::Hostile;
			//return OtherTeamAgent->GetGenericTeamId() != GetGenericTeamId() ? ETeamAttitude::Hostile : ETeamAttitude::Friendly;
		}
		else
		{
			UE_LOG(LogTemp, Error, TEXT("neutral"))
			return ETeamAttitude::Neutral;
		}
	}
};

GetGenericTeamId is public anywhere (Interface or implementation) and GetTeamAttitudeTowards too.
OtherTeamAgent is nullptr because Pawn (Actor) in argument has not IGenericTeamAgentInterface’s implementation. I usually do Cast to the desired type of Pawn and check its diplomacy.
My K2 version is working and you can edit logic in BP. For GetGenericTeamID also need to use a K2 wrapper.

ETeamAttitude::Type AMyAIController::GetTeamAttitudeTowards(const AActor& Other) const
{
auto Character = Cast(GetPawn());

	if (Character == nullptr)
		return ETeamAttitude::Neutral;

	// My own implementation
	return Character->GetTeamAttitudeTowards(Other);
}

ETeamAttitude::Type AMyCharacter::GetTeamAttitudeTowards(const AActor& Other) const
{	
	auto OtherCharacter = Cast<const AMyCharacter>(&Other);
	if (OtherCharacter == nullptr)
		return ETeamAttitude::Neutral;

	if (OtherCharacter->Controller == nullptr)
	{
		return GetTeamAttitudeTowards(OtherCharacter...); 
	}

	auto AIController = Cast<const AAIController>(OtherCharacter->Controller);

	if (AIController == nullptr)
		return ETeamAttitude::Neutral;

	const auto& OtherId = AIController->GetGenericTeamId();
	
	return GetTeamAttitudeTowards(OtherCharacter, OtherId ...);
}

GetTeamAttitudeTowards too. OtherTeamAgent is nullptr because Pawn (Actor) in argument has not IGenericTeamAgentInterface’s implementation.

I put 2 enemies (same blueprint) opposite of each other and making them look at one another, thus both having the interface. So if one of them has the implementation, the other one MUST have too it can not be null. Yet I get only null-values for the other agent variable.

I applied your latest code example but again the same problem. I’m really going back to pawnsensing because this new aiperception is just unfinished imo. I’m sure some people hack their way around and and that others use dirty workarounds and perhaps some people get it properly to work. But I’m not one of those. And pawnsensing is like 10 minutes to imlement.

@Napoleon, from how you’ve described your issue, it sounds like your sensing component is (correctly) on your AIController subclass. However, the perception is picking up your AI agent’s Character object and not its AIController object. Since your Character object doesn’t implement the IGenericTeamAgentInterface (it’s AIController does), the interface cast fails and you always get OtherTeamAgent == nullptr. You can get around this by creating a subclass of Character for your AI to use which also implements IGenericTeamAgentInterface. In this class, you’d simply return the Character’s AIController’s TeamID. You’ll need to do something similar for PlayerController as well if your player is going to be on a team. If you’re feeling like this is a lot of work to do to set an int property, you are wrong. But hopefully this will help you get everything sorted. =)

I created a tutorial on how to setup the AI perception correctly.
You can check it out if you are still confused.
[AI Perception Setup Tutorial][1]

[1]:

I see that this is still a problem in 4.21.1.
It can not be so difficult to fix something like that, and that you can edit from blueprint, at least be able to choose if an actor is, friend, neutral or enemy.

it seems like from my little experienced once a feature is ready, they never go back and add stuff to it, so if they for some reason decided not to add that option to blueprint it will never be possible… there is many small stuff like that

Here you can find a tutorial updated to Unreal 4.22 that explains how to setup “Detecting by affiliation”: https://www.thinkandbuild.it/ue4-ai-perception-system/