UE AIModule source code interpretation for reference (1)

An efficient way to assign IDs:

  1. First declare an empty structure, and then inherit from a similar FAIBasicCountertemplate structure, this structure may need to meet some conditions:
  • Implement the accumulation function:Type GetNextAvailableID() { return NextAvailableID ++;}
  • Judgment of the upper limit, the method of judging when the upper limit is reached
  • Implementation function to force an ID to be assigned
  • variable to store the ID
  1. If you don’t want to support generics, you can define a structure to use according to the above rules, and the next thing to do is to add a member variable of the structure and a static ID variable to the required class to mark the current newly allocated ID , the IDs assigned in the future can be accumulated through this ID
  2. This method was adopted in FAISightQueryLiheFPerceptionListenerIDFAISenseID
  3. FPerceptionListenerIDThe idea of ​​ID generation in ( FAISenseIDsimilarly)
template<typename TCounterType>
struct FAIBasicCounter
{
typedef TCounterType Type;
protected:
Type NextAvailableID;
public:
FAIBasicCounter() : NextAvailableID(Type(0)) {}
Type GetNextAvailableID() { return NextAvailableID++; }
uint32 GetSize() const { return uint32(NextAvailableID); }
void OnIndexForced(Type ForcedIndex) { NextAvailableID = FMath::Max<Type>(ForcedIndex + 1, NextAvailableID); }
};

NextAvailableIDIdentifies the next effective ID value to be generated
GetNextAvailableIDFunction ID generation accumulative function increments one bit each time
OnIndexForcedFunction is forced to append to a current index ID, this ID must be guaranteed to be greater than the already identified one NextAvailableID, otherwise the original identification variable will be used

struct AIMODULE_API FPerceptionListenerCounter : FAIBasicCounter<uint32>{};
typedef FAIGenericID<FPerceptionListenerCounter> FPerceptionListenerID;

FAIGenericIDIt is a template class, and the core member variables maintained in it are static AIMoudle_API TCounter Counterto identify the generated quantity; the const typename TCounter::Type Indexcurrently used ID, which is a constant, indicates that the function in the
ID that is currently instantiated uses the function in the ID but relies on this static member variable to accumulate The generated method is called in the perception system , which means that if the currently incoming Listener is new data, a new ListenID will be generated and stored in the Listener data structure of the perception system
FAIGenericIDGetNextIDFAIBasicCounterGetNextAvailableIDFAIGenericIDCounter
const FPerceptionListenerID NewListenerId = FPerceptionListenerID::GetNextID();UpdateListener

  1. FAISenseIDWhat is the difference between ID allocation and FPerceptionListenerIDID allocation?
    They are all the same in essence, the only inconsistency is that the logical meaning expressed in the usage is different, the former is to assign indexes to the type and quantity of Sense, while the latter is to the holder of the perception component itself

Efficient way to write a function pointer

const TFunction<void(const FAISightQuery&)>& OnRemoveFunc
auto RemoveQuery = [&ListenerId, &OnRemoveFunc](TArray<FAISightQuery&> SightQueries, const int32 QueryIndex)->EReverseForEachResult
{
	...
	OnRemoveFunc(SightQuery);
	...
}

UAISense_Sight::RemoveAllQueriesByListenerThis function nestedly calls multiple layers of function pointers. First, the incoming one is OnRemoveFuncpassed to the Lambda function as a capture RemoveQuery, and then it is called in the function. In the RemoveQuerytemplate function ReverseForEach, ReverseForEachthe RemoveQueryfunction is called in a loop, which is not as a whole. It is too suitable for frequent use of similar writing, because the readability is not very good. But in some basic general-purpose functions, it is particularly outstanding. For example, TArraya similar function pointer call is used in

Discover a FRotatorvalid method of declaring and assigning

FRotator ViewRotation(ForceInitToZero)
In the same way, FVector supports this operation. ForceInitToZeroIt is an enumeration definition member and the other isForceInitToZero

Create a delegated task with prerequisites

source code

FSimpleDelegateGraphTask::CreateAndDispatchWhenReady(
FSimpleDelegateGraphTask::FDelegate::CreateUObject(
const_cast<UAIPerceptionComponent*     (this),&UAIPerceptionComponent::RemoveDeadData),		>>>GET_STATID(STAT_FSimpleDelegateGraphTask_RequestingRemovalOfDeadPerceptionData), NULL, ENamedThreads::GameThread);

Create a delegate to delete invalid perception data in a timely manner when invalid data is found in the perception data. This delegate is called in the game thread. This delegate uses the
Stat mechanism for performance statistical analysis. The specific implementation is as follows:

DECLARE_CYCLE_STAT(TEXT("Requesting UAIPerceptionComponent::RemoveDeadData call from within a const function"),
STAT_FSimpleDelegateGraphTask_RequestingRemovalOfDeadPerceptionData,
STATGROUP_TaskGraphTasks);

Declare a Stat, which belongs to STATGROUP_TaskGraphTasksthe group group, and the StatId of the identifier GET_STATIDcan be obtained through the macroSTAT_FSimpleDelegateGraphTask_RequestingRemovalOfDeadPerceptionData

#define DECLARE_CYCLE_STAT(CounterName,StatId,GroupId) \
DECLARE_STAT(CounterName,StatId,GroupId,EStatDataType::ST_int64, EStatFlags::ClearEveryFrame | EStatFlags::CycleStat, >>>FPlatformMemory::MCR_Invalid); \
static DEFINE_STAT(StatId)

DECLARE_STAT is a structure declaration macro, which contains the acquisition functions of StatName, StatType, IsClearEveryFrame, etc. The
first parameter passed in will be returned as a description text in the function CounterNamedeclared by the macro, and the second parameter passed in will be used as a string in GetStatName Return, also used as a suffix name in the construction structure. It is a globally unique ID. The last few parameters are used to set the data type of Stat, the state label it has, and the analysis memory area, etc.GetDescription
StatId
GroupId

DECLARE_STATS_GROUP(TEXT("AI"),STATGROUP_AI, STATCAT_Advanced)

The statement is in the Stats2.h header file. The source code comment says that not all of these GroupIDs must be defined in this file. They can be defined in their own Cpp files as needed, but they must be globally unique. Push a more detailed article
: Stat

Get the function in reflection and call

const UFunction* Function = Object.GetClass()->FindFunctionByName(FuncName);
return Function != nullptr;

Guess you like

Origin blog.csdn.net/u011047958/article/details/125631046