1
0
KF2-Dev-Scripts/Engine/Classes/Interface_NavMeshPathObject.uc
2020-12-13 18:01:13 +03:00

358 lines
16 KiB
Ucode

/**
* Interface for path objects which need to interface with the navmesh
* - mostly provides a linkage from edges in the mesh to an object in the game. Useful for specifc edges which
* need special handling (e.g. ladders). This interface does not provide methods for altaring the mesh at runtime, for that
* see Interface_navMeshPathObstacle (which can be used in conjunction with this interface)
*
* Copyright 1998-2013 Epic Games, Inc. All Rights Reserved.
*/
interface Interface_NavMeshPathObject
native(AI);
cpptext
{
/************************************************************************
* Runtime Edge Query interface *
************************************************************************/
virtual void InitGuid( TArray<FGuid>& ExistingNavGuids )
{
AActor* Actor = Cast<AActor>(GetUObjectInterfaceInterface_NavMeshPathObject());
if( Actor != NULL )
{
FGuid* pGuid = Actor->GetGuid();
if( pGuid )
{
if( !pGuid->IsValid() || ExistingNavGuids.ContainsItem(*pGuid) )
{
*pGuid = appCreateGuid();
}
else
{
// save the existing guid to check for duplicates
ExistingNavGuids.AddItem(*pGuid);
}
}
}
}
/**
* Called from edges linked to this PO
* @param Interface - the navhandle interface of the entity pathing
* @param PreviousPoint - the previous point in the path search (e.g. the point along the predecessor edge)
* @param out_PathEdgePoint - the point we used along this edge to determine the cost
* @param Edge - the edge linked to this PO which needs to compute cost
* @return - the cost for traversing this edge
*/
virtual INT CostFor( const FNavMeshPathParams& PathParams, const FVector& PreviousPoint, FVector& out_PathEdgePoint, FNavMeshPathObjectEdge* Edge, FNavMeshPolyBase* SourcePoly )
{
return Edge->FNavMeshEdgeBase::CostFor(PathParams, PreviousPoint, out_PathEdgePoint, SourcePoly);
}
/**
* passthru function from edge to determine if the passed searcher supports this pathobject's movement
* @param Interface - the interface of the searcher
* @param CurPoly - the poly being checked for support
* @param Edge - the edge linked to this path object which is being considered
* @param PredecessorEdge - the edge we are coming from to get to 'Edge'
* @return TRUE if this path object supports the searcher
*/
virtual UBOOL Supports( const FNavMeshPathParams& PathParams,
FNavMeshPolyBase* CurPoly,
FNavMeshPathObjectEdge* Edge,
FNavMeshEdgeBase* PredecessorEdge)
{
return Edge->FNavMeshEdgeBase::Supports(PathParams,CurPoly,PredecessorEdge);
}
/**
* called when an entity is about to move through an edge linked to this path object. Allows the path object to
* trigger animations, etc related to this PO
* @param Interface - the entity which is traversing this PO
* @param out_MovePt - the point generated by GetEdgeDestination which the entity is moving toward
* @param Edge - the edge linked to this PathObject which is being moved through
* @return - whether or not the move was successful (true means we're done with this edge, remove it from path)
*/
virtual UBOOL PrepareMoveThru( class IInterface_NavigationHandle* Interface,
FVector& out_MovePt,
FNavMeshPathObjectEdge* Edge )
{
return FALSE;
}
/**
* called to determine the optimal position along this edge for the passed parameters (e.g. string pulling)
* @param EntityRadius - the radius of the entity we are computing the position for
* @param InfluencePosition - the position we are trying to get close to (e.g. previous point in path)
* @param EntityPosition - the current position of the entity (e.g. starting position of bot)
* @param Edge - the edge which is associated with this PO which we're being asked about
* @param out_EdgeDest - the destination we want to use
* @return whether this PO modified the destination or not (FALSE indicates the default edge functionality should be used)
*/
virtual UBOOL GetEdgeDestination( const FNavMeshPathParams& PathParams,
FLOAT EntityRadius,
const FVector& InfluencePosition,
const FVector& EntityPosition,
FVector& out_EdgeDest,
FNavMeshPathObjectEdge* Edge,
UNavigationHandle* Handle)
{
return FALSE;
}
/**
* called to allow this PO to draw custom stuff for edges linked to it
* @param DRSP - the sceneproxy we're drawing for
* @param DrawOffset - offset from the actual location we should be drawing
* @param Edge - the edge we're drawing
* @return - whether this PO is doing custom drawing for the passed edge (FALSE indicates the default edge drawing functionality should be used)
*/
virtual UBOOL DrawEdge( FDebugRenderSceneProxy* DRSP, FColor C, FVector DrawOffset, FNavMeshPathObjectEdge* Edge )
{
return FALSE;
}
/**
* allows path objects to dictate when it's OK for GetNextMoveLocation to push the current edge past this one in the AI's path.
* (normally the edge the AI is running to is figured out automatically based on which polygon the AI is in)
* @param PathParams - the parameters associated with the AI wondering if it is OK to run normal behavior
* @param bInPoly0 - whether the AI is currently in poly0 of this edge
* @param bInPoly1 - whether the AI is currently in poly1 of this edge
* @return - TRUE if it's OK to automatically progress the edge past this one
*/
virtual UBOOL AllowMoveToNextEdge(FNavMeshPathParams& PathParams, UBOOL bInPoly0, UBOOL bInPoly1){ return TRUE; }
/**
* this function is called after a poly linked to this edge is replaced with a submesh for a pathobstacle
* allows special edges to have a chance to add extra data after the mesh is split
* @params Edge - the edge that we are updating for
* @param Poly - the poly that was just disabled and replaced with a submesh
* @param NewSubMesh - the submesh that now represents the poly
*/
virtual void PostSubMeshUpdateForOwningPoly(FNavMeshPathObjectEdge* Edge, FNavMeshPolyBase* Poly, UNavigationMeshBase* New_SubMesh){}
/**
* This is a helper function which is useful when this pathobject is being used in conjunction with the pathobstacle interface
* - just does all the work normally done in AddObstacleEdge, except convenienty tuned for use with pathobjects
* @param Status - current status of edges (e.g. what still needs adding)
* @param inV1 - vertex location of first vert in the edge
* @param inV2 - vertex location of second vert in the edge
* @param ConnectedPolys - the polys this edge links
* @param bEdgesNeedToBeDynamic - whether or not added edges need to be dynamic (e.g. we're adding edges between meshes)
* @param PolyAssocatedWithThisPO - the index into the connected polys array of the poly which is associated with this path object
* @param POOwner - the owner of the pathobject interface (e.g. the actor that implements interface)
* @param SupportedEdgeWidth - widht of unit this edge supports (defaults to -1.0 in which case the length of the edge will be used)
* @(optional) param EdgeGroupID - ID of the edgegroup this edge is a part of (defaults to no group)
* @return returns an enum describing what just happened (what actions did we take) - used to determien what accompanying actions need to be taken
* by other obstacles and calling code
*/
EEdgeHandlingStatus AddObstacleEdgeForObstacle( EEdgeHandlingStatus Status, const FVector& inV1, const FVector& inV2, TArray<FNavMeshPolyBase*>& ConnectedPolys, UBOOL bEdgesNeedToBeDynamic, INT PolyAssocatedWithThisPO, AActor* POOwner, FLOAT SupportedEdgeWidth=-1.0f, BYTE EdgeGroupID=MAXBYTE)
{
// if an edge has already been added in the direction we want to add an edge then there is probably a conflicting pathobstacle (e.g. we're butted
// up against another obstacle which has already added an edge.. so just bail)
if(Status == EHS_AddedBothDirs)
{
return Status;
}
// if there is already an edge point back into this PO from the other poly, bail
if( (PolyAssocatedWithThisPO == 0 && Status == EHS_Added1to0) ||
(PolyAssocatedWithThisPO == 1 && Status == EHS_Added0to1) )
{
return Status;
}
TArray<FNavMeshPolyBase*> ReversedConnectedPolys=ConnectedPolys;
// so we want to add an edge back into the poly associated with this PO, so swap the order if we need to
if(PolyAssocatedWithThisPO == 0)
{
ReversedConnectedPolys.SwapItems(0,1);
}
UNavigationMeshBase* Mesh = ReversedConnectedPolys(0)->NavMesh;
if( Mesh == NULL )
{
return Status;
}
FNavMeshPathObjectEdge* NewEdge = NULL;
if( bEdgesNeedToBeDynamic )
{
TArray<FNavMeshPathObjectEdge*> CreatedEdges;
Mesh->AddDynamicCrossPylonEdge<FNavMeshPathObjectEdge>(inV1,inV2,ReversedConnectedPolys,SupportedEdgeWidth,EdgeGroupID,TRUE, &CreatedEdges);
NewEdge = (CreatedEdges.Num() > 0) ? CreatedEdges(0) : NULL;
checkSlowish(CreatedEdges.Num() <2);
}
else
{
if (! Mesh->AddOneWayCrossPylonEdgeToMesh<FNavMeshPathObjectEdge>(inV1,inV2,ReversedConnectedPolys,SupportedEdgeWidth,EdgeGroupID,&NewEdge) )
{
// we failed to add an edge for some reason.. if it returns true, we added an edge or there was already an identical edge there
return Status;
}
}
// bind new edge to this avoidance vol
if(NewEdge != NULL)
{
NewEdge->PathObject = POOwner;
NewEdge->InternalPathObjectID = 0;
}
// indicate that we added an edge from dest poly to src poly
if(Status == EHS_AddedNone)
{
if(PolyAssocatedWithThisPO == 0)
{
return EHS_Added1to0;
}
else
{
return EHS_Added0to1;
}
}
else
{
// if we get here that means someone should have already added an edge in the opposite direction
return EHS_AddedBothDirs;
}
}
/************************************************************************
* Mesh generation interface *
************************************************************************/
/**
* this function describes a 'cookie cutter' edge that will be used to split the mesh beneath it
* for example if you have a cost inflicting volume that needs to conform the mesh to itself
* you could return an array of verts along the bottom boundary of the volume, and a height up to the top of the volume
* and then you have poly boundaries exactly along the border of the volume with which you can add
* edges which affect cost
* @param Poly - array of vectors that describe bottom of 'cookie cutter' volume (should be CW and convex)
* @param PolyHeight - height above the poly within which polys should be split (extrude passed poly up by this amount and use faces for clip)
* @return - TRUE if this shape should be used to split the mesh FALSE if no splitting is necessary
*/
virtual UBOOL GetMeshSplittingPoly( TArray<FVector>& Poly, FLOAT& PolyHeight ){ return FALSE; }
/**
* called for each pylon's exploration to see if this path object needs to be consulted during exploration
* @param Py - the pylon being explored that we need to know if this PO should be asked about
* @return - TRUE if this path object needs to have its IsExplorationAllowed function considered during path exploration
*/
virtual UBOOL NeedsForbidExploreCheck(APylon* Py) { return FALSE; }
/**
* called during mesh exploration, allows this PO to forbid exploration through specific areas
* @param Py - the pylon being explored right now
* @param TestPosition - the position of the new poly we are asking about
* @return - TRUE if exploration is allowed
*/
virtual UBOOL IsExplorationAllowed( APylon* Py, const FVector& TestPosition) { return TRUE; }
/**
* called after initial exploration, gives this PO a chance to add seeds to the exploration process
* @param SeedPointList - reference to the main array of seeds that need to be expanded after initial explore
* @param Py - the pylon which is being expanded
*/
virtual void AddAuxSeedPoints( APylon* Py ){}
/**
* called after edge creation is complete for each pylon to allow this PO to add edges for itself
* @param Py - the pylon which we are creating edges for
*/
virtual void CreateEdgesForPathObject( APylon* Py ){}
/**
* Function to be used from within CreateEdgesForPathObject
* @param Interface_Owner - the actor which owns this interface
* @param StartPoly - Source poly for edge
* @param EndPoly - Destination poly for edge
* @param Vert0 - One end point of the edge
* @param Vert1 - Another end point of the edge
* @param InternalPOID - optional param for extra identifier which is attached to the edge being added (to distinguish between edges linked to this PO)
* @return - T/F indicating success
*/
UBOOL AddEdgeForThisPO(AActor* Interface_Owner,
APylon* Py,
FNavMeshPolyBase* StartPoly,
FNavMeshPolyBase* EndPoly,
const FVector& Vert0,
const FVector& Vert1,
INT InternalPOID=-1,
UBOOL bForce=FALSE)
{
UNavigationMeshBase* Mesh = Py->GetNavMesh();
if( Mesh == NULL )
{
return FALSE;
}
if( StartPoly == EndPoly || StartPoly == NULL || EndPoly == NULL )
{
warnf(NAME_Warning,TEXT("WARNING! A pathobject (%s) tried to add an edge that links a poly to itself, or links a poly to nothing. This add is being IGNORED!"), *Interface_Owner->GetName());
return FALSE;
}
TArray<FNavMeshPolyBase*> ConnectedPolys;
ConnectedPolys.AddItem(StartPoly);
ConnectedPolys.AddItem(EndPoly);
FNavMeshPathObjectEdge* NewEdge = NULL;
if( Mesh->AddOneWayCrossPylonEdgeToMesh<FNavMeshPathObjectEdge>(Vert0,Vert1,ConnectedPolys,-1.0f,MAXBYTE,&NewEdge,bForce) )
{
if(NewEdge != NULL)
{
NewEdge->PathObject = Interface_Owner;
NewEdge->InternalPathObjectID = InternalPOID;
}
// still want to return true if newedge is null, false indicates we ran out of vert indices
return TRUE;
}
return FALSE;
}
/**
* This is called offline when edges are about to be added from the exterior of the pathobject to the interior or vice versa
* Default behavior just a normal edge, override to add special costs or behavior
* @param Status - current status of edges (e.g. what still needs adding)
* @param inV1 - vertex location of first vert in the edge
* @param inV2 - vertex location of second vert in the edge
* @param ConnectedPolys - the polys this edge links
* @param PolyAssocatedWithThisPO - the index into the connected polys array parmaeter which tells us which poly from that array is associated with this path object
* @(optional) param SupportedEdgeWidth - width of unit that this edge supports, defaults to -1.0f meaning the length of the edge itself will be used
* @(optional) param EdgeGroupID - ID of the edgegroup this edge is a part of (defaults to no group)
* @return returns an enum describing what just happened (what actions did we take) - used to determien what accompanying actions need to be taken
* by other obstacles and calling code
*/
virtual EEdgeHandlingStatus AddStaticEdgeIntoThisPO( EEdgeHandlingStatus Status, const FVector& inV1, const FVector& inV2, TArray<FNavMeshPolyBase*>& ConnectedPolys, INT PolyAssocatedWithThisPO, FLOAT SupportedEdgeWidth=-1.0f, BYTE EdgeGroupID=MAXBYTE);
/**
* Allows this path object to modify the final path generated for a bot when the path
* uses an edge linked to this path object.. default is to do nothing
* @param Handle - the navigation handle whose path we are molesting
* @param Idx - the index into the pathcache that the edge associated with this path object is at
* @return - TRUE if we modified the path
*/
virtual UBOOL ModifyFinalPath( UNavigationHandle* Handle, INT Idx )
{
return FALSE;
}
/**
* For debugging. Verifies that this pathobject is still alive and well and not orphaned or deleted
* @return - TRUE If this path object is in good working order
*/
virtual UBOOL Verify()
{
return FALSE;
}
}