Overriding A* cost (and HeuristicScale) FRecastQueryFilter/dtQuearyFilter (with minimal Engine code changes)?

Hi there,

A question to anyone into tuning A* using the existing QueryFilter classes:

Q: Did anyone try overriding “dtQueryFilter” or similar A* cost/heuristic implementation changes without touching Engine level code like described below?

I recently tuned existing A related methods* by implementing my own set of UNavigationQueryFilter and its helpers FRecastQueryFilter / dtQueryFilter.

( … and then, in my case to influence A* run-time, calling “setHeuristicScale()” on my own dtMyQueryFilter instance and implementing “dtMyQueryFilter::getVirtualCost()” to add per-node cost calculations and a few custom rules. )

Actual code changes I wanted to investigate further or avoid:

1. Engine code change I’d like to avoid: I added that virtual keyword below to modify “UNavigationQueryFilter::GetQueryFilter()”, otherwise I couldn’t find a good way to create and return my own FNavigationQueryFilter class instance from inside any of the existing GetQueryFilter() calls:

// in AI/Navigation/NavFilters/NavigationQueryFilter.h
class ENGINE_API UNavigationQueryFilter : public UObject
	/** get filter for given navigation data and initialize on first access */
	virtual FSharedConstNavQueryFilter GetQueryFilter(const ANavigationData& NavData, const UObject* Querier) const;

2. Another engine code “issue”, code I would prefer to re-write to be polymorphic, or at least allow class derivates:

The original, unchanged Engine code will cast to “FRecastQueryFilter / dtQueryFilter” (the Engine’s original classes/implementations), i.e. this code is not written exactly with deriving those classes in mind:

In “FPImplRecastNavmesh::FindPath()”:

// see AI\Navigation\PImplRecastNavMesh.cpp", Line 788:

	const FRecastQueryFilter* FilterImplementation = (const FRecastQueryFilter*)(InQueryFilter.GetImplementation());
	const dtQueryFilter* QueryFilter = FilterImplementation->GetAsDetourQueryFilter();

This is kind of working but since “const FRecastQueryFilter*” and “GetAsDetourQueryFilter()” or the context of any surrounding code might still change I feel tempted to remove casts and make methods like “GetAsDetourQueryFilter()” virtual to have a cleaner interface, i.e. caller/callee agree on using FRecastQueryFilter/dtQueryFilter base class or derivates, but don’t cast and/or assume specific classes to exist here at run-time. :stuck_out_tongue: