Daily Unreal Column #86 - AI Data Provider
Writing modular functionality to support AI agents in your game can be very challenging. There are some great tools you can use to make this easier. Data providers are one of them.
Imaging creating a behavior tree for one of the agents in your game. One of the behavior tree tasks expect you to pass their attack range. Then you also want to run an EQS with a donut pattern generated using the attack range as a radius. And you also want to use this somewhere in your game code, directly. Making sure that all these places uses same source of truth is not easy. This is exactly where AI Data Providers shine.
To be specific, the structure we are talking about here is FAIDataProviderValue
and its subclasses. This struct has a property of type UAIDataProvider
. This one is the most interesting one from the end user perspective. The engine ships with two subclasses to this one:
UAIDataProvider_QueryParams
UAIDataProvider_Random
The first one is used in EQS to allow specifying EQS params when requesting query execution. The second one, as the name states, is purely random.
Let’s go back to the example I mentioned in the first paragraph and assume that we are using Gameplay Ability System (GAS) in our game. This means, that the attack range is most likely a property in an attribute set for either character or a weapon. What we can do is create a subclass of UAIDataProvider
class and make it bind its value to a specific attribute value.
class AIMODULE_API UAIDataProvider_Attribute : public UAIDataProvider
{
GENERATED_BODY()
public:
virtual void BindData(const UObject& Owner, int32 RequestId) override;
UPROPERTY(EditAnywhere, Category = Provider)
EAttributeType AttributeType;
UPROPERTY()
float FloatValue;
UPROPERTY()
int32 IntValue;
UPROPERTY()
bool BoolValue;
};
Above is an exampel code on how to declare a class that will bind attribute value based on the specified AttributeType
. Inside the BindData
function what we need to do is query the attribute value from the Owner and set its value to the FloatValue
, IntValue
and BoolValue
.
Then, wherever you create a reference for the FAIDataProvider
struct, you will be able to assign your new UAIDataProvider
class reference to dynamically bind the attribute value to it.
Here is an example on how the above would look like in the editor when used for specifing grid half size for EQS simple grid generator:
Pro tip: it’s worth adding a property to your data provider to specifying a constant fall through value. This is because when testing EQS in the editor time using EQS testing pawn, these data providers will fail to bind to any meaningful values as there are most likely no instances of actors that we can read the attributes from.