358 lines
16 KiB
Ucode
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;
|
|
}
|
|
}
|
|
|