2019-12-26 14:45:42 -05:00
// Copyright Epic Games, Inc. All Rights Reserved.
2019-07-10 13:31:21 -04:00
# include "NavigationDataHandler.h"
# include "NavMesh/RecastNavMeshGenerator.h"
DEFINE_LOG_CATEGORY_STATIC ( LogNavOctree , Warning , All ) ;
namespace
{
int32 GetDirtyFlagHelper ( int32 UpdateFlags , int32 DefaultValue )
{
return ( ( UpdateFlags & FNavigationOctreeController : : OctreeUpdate_Geometry ) ! = 0 ) ? ENavigationDirtyFlag : : All :
( ( UpdateFlags & FNavigationOctreeController : : OctreeUpdate_Modifiers ) ! = 0 ) ? ENavigationDirtyFlag : : DynamicModifier :
DefaultValue ;
}
}
FNavigationDataHandler : : FNavigationDataHandler ( FNavigationOctreeController & InOctreeController , FNavigationDirtyAreasController & InDirtyAreasController )
: OctreeController ( InOctreeController ) , DirtyAreasController ( InDirtyAreasController )
{ }
2020-04-21 23:23:12 -04:00
void FNavigationDataHandler : : RemoveNavOctreeElementId ( const FOctreeElementId2 & ElementId , int32 UpdateFlags )
2019-07-10 13:31:21 -04:00
{
2019-07-16 05:52:45 -04:00
if ( ensure ( OctreeController . IsValidElement ( ElementId ) ) )
2019-07-10 13:31:21 -04:00
{
const FNavigationOctreeElement & ElementData = OctreeController . NavOctree - > GetElementById ( ElementId ) ;
const int32 DirtyFlag = GetDirtyFlagHelper ( UpdateFlags , ElementData . Data - > GetDirtyFlag ( ) ) ;
// mark area occupied by given actor as dirty
2022-05-19 09:59:18 -04:00
DirtyAreasController . AddArea ( ElementData . Bounds . GetBox ( ) , DirtyFlag , [ & ElementData ] { return ElementData . Data - > SourceObject . Get ( ) ; } , nullptr , " Remove from navoctree " ) ;
2019-07-10 13:31:21 -04:00
OctreeController . NavOctree - > RemoveNode ( ElementId ) ;
}
}
FSetElementId FNavigationDataHandler : : RegisterNavOctreeElement ( UObject & ElementOwner , INavRelevantInterface & ElementInterface , int32 UpdateFlags )
{
SCOPE_CYCLE_COUNTER ( STAT_Navigation_RegisterNavOctreeElement ) ;
FSetElementId SetId ;
if ( OctreeController . NavOctree . IsValid ( ) = = false )
{
return SetId ;
}
if ( OctreeController . IsNavigationOctreeLocked ( ) )
{
UE_LOG ( LogNavOctree , Log , TEXT ( " IGNORE(RegisterNavOctreeElement) %s " ) , * GetPathNameSafe ( & ElementOwner ) ) ;
return SetId ;
}
const bool bIsRelevant = ElementInterface . IsNavigationRelevant ( ) ;
UE_LOG ( LogNavOctree , Log , TEXT ( " REG %s %s " ) , * ElementOwner . GetName ( ) , bIsRelevant ? TEXT ( " [relevant] " ) : TEXT ( " [skip] " ) ) ;
if ( bIsRelevant )
{
bool bCanAdd = false ;
UObject * ParentNode = ElementInterface . GetNavigationParent ( ) ;
if ( ParentNode )
{
OctreeController . OctreeChildNodesMap . AddUnique ( ParentNode , FWeakObjectPtr ( & ElementOwner ) ) ;
bCanAdd = true ;
}
else
{
bCanAdd = ( OctreeController . HasObjectsNavOctreeId ( ElementOwner ) = = false ) ;
}
if ( bCanAdd )
{
2022-05-02 10:10:57 -04:00
FNavigationDirtyElement UpdateInfo ( & ElementOwner , & ElementInterface , GetDirtyFlagHelper ( UpdateFlags , 0 ) , DirtyAreasController . bUseWorldPartitionedDynamicMode ) ;
2019-07-10 13:31:21 -04:00
SetId = OctreeController . PendingOctreeUpdates . FindId ( UpdateInfo ) ;
if ( SetId . IsValidId ( ) )
{
// make sure this request stays, in case it has been invalidated already
OctreeController . PendingOctreeUpdates [ SetId ] = UpdateInfo ;
}
else
{
SetId = OctreeController . PendingOctreeUpdates . Add ( UpdateInfo ) ;
}
}
}
return SetId ;
}
void FNavigationDataHandler : : AddElementToNavOctree ( const FNavigationDirtyElement & DirtyElement )
{
check ( OctreeController . NavOctree . IsValid ( ) ) ;
// handle invalidated requests first
if ( DirtyElement . bInvalidRequest )
{
if ( DirtyElement . bHasPrevData )
{
2022-05-19 09:59:18 -04:00
DirtyAreasController . AddArea ( DirtyElement . PrevBounds , DirtyElement . PrevFlags , [ & DirtyElement ] { return DirtyElement . Owner . Get ( ) ; } , & DirtyElement , " Addition to navoctree (invalid request) " ) ;
2019-07-10 13:31:21 -04:00
}
return ;
}
UObject * ElementOwner = DirtyElement . Owner . Get ( ) ;
2021-09-08 16:42:26 -04:00
if ( ! IsValid ( ElementOwner ) | | DirtyElement . NavInterface = = nullptr )
2019-07-10 13:31:21 -04:00
{
return ;
}
2019-07-15 12:47:46 -04:00
FNavigationOctreeElement GeneratedData ( * ElementOwner ) ;
2022-05-27 08:58:40 -04:00
// In WP dynamic mode, store if this is loaded data.
if ( DirtyAreasController . bUseWorldPartitionedDynamicMode )
{
GeneratedData . Data - > bLoadedData = DirtyElement . bIsFromVisibilityChange | | FNavigationSystem : : IsLevelVisibilityChanging ( ElementOwner ) ;
}
2019-07-10 13:31:21 -04:00
const FBox ElementBounds = DirtyElement . NavInterface - > GetNavigationBounds ( ) ;
UObject * NavigationParent = DirtyElement . NavInterface - > GetNavigationParent ( ) ;
if ( NavigationParent )
{
// check if parent node is waiting in queue
const FSetElementId ParentRequestId = OctreeController . PendingOctreeUpdates . FindId ( FNavigationDirtyElement ( NavigationParent ) ) ;
2020-04-21 23:23:12 -04:00
const FOctreeElementId2 * ParentId = OctreeController . GetObjectsNavOctreeId ( * NavigationParent ) ;
2019-07-10 13:31:21 -04:00
if ( ParentRequestId . IsValidId ( ) & & ParentId = = nullptr )
{
FNavigationDirtyElement & ParentNode = OctreeController . PendingOctreeUpdates [ ParentRequestId ] ;
AddElementToNavOctree ( ParentNode ) ;
// mark as invalid so it won't be processed twice
ParentNode . bInvalidRequest = true ;
}
2020-04-21 23:23:12 -04:00
const FOctreeElementId2 * ElementId = ParentId ? ParentId : OctreeController . GetObjectsNavOctreeId ( * NavigationParent ) ;
2019-07-16 05:52:45 -04:00
if ( ElementId & & ensure ( OctreeController . IsValidElement ( * ElementId ) ) )
2019-07-10 13:31:21 -04:00
{
UE_LOG ( LogNavOctree , Log , TEXT ( " ADD %s to %s " ) , * GetNameSafe ( ElementOwner ) , * GetNameSafe ( NavigationParent ) ) ;
2019-07-16 05:52:45 -04:00
OctreeController . NavOctree - > AppendToNode ( * ElementId , DirtyElement . NavInterface , ElementBounds , GeneratedData ) ;
2019-07-10 13:31:21 -04:00
}
else
{
UE_LOG ( LogNavOctree , Warning , TEXT ( " Can't add node [%s] - parent [%s] not found in octree! " ) , * GetNameSafe ( ElementOwner ) , * GetNameSafe ( NavigationParent ) ) ;
}
}
else
{
UE_LOG ( LogNavOctree , Log , TEXT ( " ADD %s " ) , * GetNameSafe ( ElementOwner ) ) ;
OctreeController . NavOctree - > AddNode ( ElementOwner , DirtyElement . NavInterface , ElementBounds , GeneratedData ) ;
}
2020-02-24 18:43:44 -05:00
if ( ! GeneratedData . IsEmpty ( ) )
2019-07-10 13:31:21 -04:00
{
const int32 DirtyFlag = DirtyElement . FlagsOverride ? DirtyElement . FlagsOverride : GeneratedData . Data - > GetDirtyFlag ( ) ;
2022-05-19 09:59:18 -04:00
DirtyAreasController . AddArea ( GeneratedData . Bounds . GetBox ( ) , DirtyFlag , [ & ElementOwner ] { return ElementOwner ; } , & DirtyElement , " Addition to navoctree " ) ;
2019-07-10 13:31:21 -04:00
}
}
2019-09-06 16:30:54 -04:00
bool FNavigationDataHandler : : UnregisterNavOctreeElement ( UObject & ElementOwner , INavRelevantInterface & ElementInterface , int32 UpdateFlags )
2019-07-10 13:31:21 -04:00
{
SCOPE_CYCLE_COUNTER ( STAT_Navigation_UnregisterNavOctreeElement ) ;
if ( OctreeController . NavOctree . IsValid ( ) = = false )
{
2019-09-06 16:30:54 -04:00
return false ;
2019-07-10 13:31:21 -04:00
}
if ( OctreeController . IsNavigationOctreeLocked ( ) )
{
# if !WITH_EDITOR
UE_LOG ( LogNavOctree , Log , TEXT ( " IGNORE(UnregisterNavOctreeElement) %s " ) , * GetPathNameSafe ( & ElementOwner ) ) ;
# endif // WITH_EDITOR
2019-09-06 16:30:54 -04:00
return false ;
2019-07-10 13:31:21 -04:00
}
2019-09-06 16:30:54 -04:00
bool bUnregistered = false ;
2020-04-21 23:23:12 -04:00
const FOctreeElementId2 * ElementId = OctreeController . GetObjectsNavOctreeId ( ElementOwner ) ;
2019-07-10 13:31:21 -04:00
UE_LOG ( LogNavOctree , Log , TEXT ( " UNREG %s %s " ) , * ElementOwner . GetName ( ) , ElementId ? TEXT ( " [exists] " ) : TEXT ( " [does \' t exist] " ) ) ;
if ( ElementId ! = nullptr )
{
RemoveNavOctreeElementId ( * ElementId , UpdateFlags ) ;
OctreeController . RemoveObjectsNavOctreeId ( ElementOwner ) ;
2019-09-06 16:30:54 -04:00
bUnregistered = true ;
2019-07-10 13:31:21 -04:00
}
else
{
const bool bCanRemoveChildNode = ( UpdateFlags & FNavigationOctreeController : : OctreeUpdate_ParentChain ) = = 0 ;
UObject * ParentNode = ElementInterface . GetNavigationParent ( ) ;
if ( ParentNode & & bCanRemoveChildNode )
{
// if node has navigation parent (= doesn't exists in octree on its own)
// and it's not part of parent chain update
// remove it from map and force update on parent to rebuild octree element
OctreeController . OctreeChildNodesMap . RemoveSingle ( ParentNode , FWeakObjectPtr ( & ElementOwner ) ) ;
UpdateNavOctreeParentChain ( * ParentNode ) ;
}
}
// mark pending update as invalid, it will be dirtied according to currently active settings
const bool bCanInvalidateQueue = ( UpdateFlags & FNavigationOctreeController : : OctreeUpdate_Refresh ) = = 0 ;
if ( bCanInvalidateQueue )
{
const FSetElementId RequestId = OctreeController . PendingOctreeUpdates . FindId ( FNavigationDirtyElement ( & ElementOwner ) ) ;
if ( RequestId . IsValidId ( ) )
{
2019-09-06 16:30:54 -04:00
FNavigationDirtyElement & DirtyElement = OctreeController . PendingOctreeUpdates [ RequestId ] ;
// Only consider as unregistered when pending update was not already invalidated since return value must indicate
// that ElementOwner was fully added or about to be added (valid pending update).
bUnregistered | = ( DirtyElement . bInvalidRequest = = false ) ;
DirtyElement . bInvalidRequest = true ;
2019-07-10 13:31:21 -04:00
}
}
2019-09-06 16:30:54 -04:00
return bUnregistered ;
2019-07-10 13:31:21 -04:00
}
void FNavigationDataHandler : : UpdateNavOctreeElement ( UObject & ElementOwner , INavRelevantInterface & ElementInterface , int32 UpdateFlags )
{
INC_DWORD_STAT ( STAT_Navigation_UpdateNavOctree ) ;
if ( OctreeController . IsNavigationOctreeLocked ( ) )
{
UE_LOG ( LogNavOctree , Log , TEXT ( " IGNORE(UpdateNavOctreeElement) %s " ) , * ElementOwner . GetPathName ( ) ) ;
return ;
}
// grab existing octree data
FBox CurrentBounds ;
int32 CurrentFlags ;
const bool bAlreadyExists = OctreeController . GetNavOctreeElementData ( ElementOwner , CurrentFlags , CurrentBounds ) ;
// don't invalidate pending requests
UpdateFlags | = FNavigationOctreeController : : OctreeUpdate_Refresh ;
// always try to unregister, even if element owner doesn't exists in octree (parent nodes)
UnregisterNavOctreeElement ( ElementOwner , ElementInterface , UpdateFlags ) ;
const FSetElementId RequestId = RegisterNavOctreeElement ( ElementOwner , ElementInterface , UpdateFlags ) ;
// add original data to pending registration request
// so it could be dirtied properly when system receive unregister request while actor is still queued
if ( RequestId . IsValidId ( ) )
{
FNavigationDirtyElement & UpdateInfo = OctreeController . PendingOctreeUpdates [ RequestId ] ;
UpdateInfo . PrevFlags = CurrentFlags ;
if ( UpdateInfo . PrevBounds . IsValid )
{
// Is we have something stored already we want to
// sum it up, since we care about the whole bounding
// box of changes that potentially took place
UpdateInfo . PrevBounds + = CurrentBounds ;
}
else
{
UpdateInfo . PrevBounds = CurrentBounds ;
}
UpdateInfo . bHasPrevData = bAlreadyExists ;
}
UpdateNavOctreeParentChain ( ElementOwner , /*bSkipElementOwnerUpdate=*/ true ) ;
}
void FNavigationDataHandler : : UpdateNavOctreeParentChain ( UObject & ElementOwner , bool bSkipElementOwnerUpdate )
{
const int32 UpdateFlags = FNavigationOctreeController : : OctreeUpdate_ParentChain | FNavigationOctreeController : : OctreeUpdate_Refresh ;
TArray < FWeakObjectPtr > ChildNodes ;
OctreeController . OctreeChildNodesMap . MultiFind ( & ElementOwner , ChildNodes ) ;
2019-09-06 16:30:54 -04:00
auto ElementOwnerUpdateFunc = [ & ] ( ) - > bool
2019-07-10 13:31:21 -04:00
{
2019-09-06 16:30:54 -04:00
bool bShouldRegisterChildren = true ;
2019-07-10 13:31:21 -04:00
if ( bSkipElementOwnerUpdate = = false )
{
INavRelevantInterface * ElementInterface = Cast < INavRelevantInterface > ( & ElementOwner ) ;
2019-09-06 16:30:54 -04:00
if ( ElementInterface ! = nullptr )
2019-07-10 13:31:21 -04:00
{
2019-09-06 16:30:54 -04:00
// We don't want to register NavOctreeElement if owner was not already registered or queued
// so we use Unregister/Register combo instead of UpdateNavOctreeElement
if ( UnregisterNavOctreeElement ( ElementOwner , * ElementInterface , UpdateFlags ) )
{
FSetElementId NewId = RegisterNavOctreeElement ( ElementOwner , * ElementInterface , UpdateFlags ) ;
bShouldRegisterChildren = NewId . IsValidId ( ) ;
}
else
{
bShouldRegisterChildren = false ;
}
2019-07-10 13:31:21 -04:00
}
}
2019-09-06 16:30:54 -04:00
return bShouldRegisterChildren ;
} ;
if ( ChildNodes . Num ( ) = = 0 )
{
// Last child was removed, only need to rebuild owner's NavOctreeElement
ElementOwnerUpdateFunc ( ) ;
2019-07-10 13:31:21 -04:00
return ;
}
TArray < INavRelevantInterface * > ChildNavInterfaces ;
ChildNavInterfaces . AddZeroed ( ChildNodes . Num ( ) ) ;
for ( int32 Idx = 0 ; Idx < ChildNodes . Num ( ) ; Idx + + )
{
if ( ChildNodes [ Idx ] . IsValid ( ) )
{
UObject * ChildNodeOb = ChildNodes [ Idx ] . Get ( ) ;
ChildNavInterfaces [ Idx ] = Cast < INavRelevantInterface > ( ChildNodeOb ) ;
if ( ChildNodeOb & & ChildNavInterfaces [ Idx ] )
{
UnregisterNavOctreeElement ( * ChildNodeOb , * ChildNavInterfaces [ Idx ] , UpdateFlags ) ;
}
}
}
2019-09-06 16:30:54 -04:00
const bool bShouldRegisterChildren = ElementOwnerUpdateFunc ( ) ;
if ( bShouldRegisterChildren )
2019-07-10 13:31:21 -04:00
{
2019-09-06 16:30:54 -04:00
for ( int32 Idx = 0 ; Idx < ChildNodes . Num ( ) ; Idx + + )
2019-07-10 13:31:21 -04:00
{
2019-09-06 16:30:54 -04:00
UObject * ChildElement = ChildNodes [ Idx ] . Get ( ) ;
if ( ChildElement & & ChildNavInterfaces [ Idx ] )
{
RegisterNavOctreeElement ( * ChildElement , * ChildNavInterfaces [ Idx ] , UpdateFlags ) ;
}
2019-07-10 13:31:21 -04:00
}
}
}
bool FNavigationDataHandler : : UpdateNavOctreeElementBounds ( UActorComponent & Comp , const FBox & NewBounds , const FBox & DirtyArea )
{
2020-04-21 23:23:12 -04:00
const FOctreeElementId2 * ElementId = OctreeController . GetObjectsNavOctreeId ( Comp ) ;
2019-07-16 05:52:45 -04:00
if ( ElementId ! = nullptr & & ensure ( OctreeController . IsValidElement ( * ElementId ) ) )
2019-07-10 13:31:21 -04:00
{
OctreeController . NavOctree - > UpdateNode ( * ElementId , NewBounds ) ;
// Add dirty area
if ( DirtyArea . IsValid )
{
2019-07-16 05:52:45 -04:00
// Refresh ElementId since components may be stored in a different node after updating bounds
2019-07-10 13:31:21 -04:00
ElementId = OctreeController . GetObjectsNavOctreeId ( Comp ) ;
2019-07-16 05:52:45 -04:00
if ( ElementId ! = nullptr & & ensure ( OctreeController . IsValidElement ( * ElementId ) ) )
2019-07-10 13:31:21 -04:00
{
2020-04-14 16:59:52 -04:00
const FNavigationOctreeElement & ElementData = OctreeController . NavOctree - > GetElementById ( * ElementId ) ;
2022-05-19 09:59:18 -04:00
DirtyAreasController . AddArea ( DirtyArea , ElementData . Data - > GetDirtyFlag ( ) , [ & Comp ] { return & Comp ; } , nullptr , " Bounds change " ) ;
2019-07-10 13:31:21 -04:00
}
}
return true ;
}
return false ;
}
void FNavigationDataHandler : : FindElementsInNavOctree ( const FBox & QueryBox , const FNavigationOctreeFilter & Filter , TArray < FNavigationOctreeElement > & Elements )
{
if ( OctreeController . NavOctree . IsValid ( ) = = false )
{
UE_LOG ( LogNavOctree , Warning , TEXT ( " FNavigationDataHandler::FindElementsInNavOctree gets called while NavOctree is null " ) ) ;
return ;
}
2020-04-15 01:18:48 -04:00
OctreeController . NavOctree - > FindElementsWithBoundsTest ( QueryBox , [ & Elements , & Filter ] ( const FNavigationOctreeElement & Element )
2019-07-10 13:31:21 -04:00
{
if ( Element . IsMatchingFilter ( Filter ) )
{
Elements . Add ( Element ) ;
}
2020-04-14 16:59:52 -04:00
} ) ;
2019-07-10 13:31:21 -04:00
}
bool FNavigationDataHandler : : ReplaceAreaInOctreeData ( const UObject & Object , TSubclassOf < UNavArea > OldArea , TSubclassOf < UNavArea > NewArea , bool bReplaceChildClasses )
{
FNavigationRelevantData * Data = OctreeController . GetMutableDataForObject ( Object ) ;
if ( Data = = nullptr | | Data - > HasModifiers ( ) = = false )
{
return false ;
}
for ( FAreaNavModifier & AreaModifier : Data - > Modifiers . GetMutableAreas ( ) )
{
if ( AreaModifier . GetAreaClass ( ) = = OldArea
| | ( bReplaceChildClasses & & AreaModifier . GetAreaClass ( ) - > IsChildOf ( OldArea ) ) )
{
AreaModifier . SetAreaClass ( NewArea ) ;
}
}
for ( FSimpleLinkNavModifier & SimpleLink : Data - > Modifiers . GetSimpleLinks ( ) )
{
for ( FNavigationLink & Link : SimpleLink . Links )
{
if ( Link . GetAreaClass ( ) = = OldArea
| | ( bReplaceChildClasses & & Link . GetAreaClass ( ) - > IsChildOf ( OldArea ) ) )
{
Link . SetAreaClass ( NewArea ) ;
}
}
for ( FNavigationSegmentLink & Link : SimpleLink . SegmentLinks )
{
if ( Link . GetAreaClass ( ) = = OldArea
| | ( bReplaceChildClasses & & Link . GetAreaClass ( ) - > IsChildOf ( OldArea ) ) )
{
Link . SetAreaClass ( NewArea ) ;
}
}
}
for ( FCustomLinkNavModifier & CustomLink : Data - > Modifiers . GetCustomLinks ( ) )
{
ensureMsgf ( false , TEXT ( " Not implemented yet " ) ) ;
}
return true ;
}
void FNavigationDataHandler : : AddLevelCollisionToOctree ( ULevel & Level )
{
# if WITH_RECAST
if ( OctreeController . NavOctree . IsValid ( ) & &
OctreeController . NavOctree - > GetNavGeometryStoringMode ( ) = = FNavigationOctree : : StoreNavGeometry )
{
const TArray < FVector > * LevelGeom = Level . GetStaticNavigableGeometry ( ) ;
2020-04-21 23:23:12 -04:00
const FOctreeElementId2 * ElementId = OctreeController . GetObjectsNavOctreeId ( Level ) ;
2019-07-10 13:31:21 -04:00
if ( ! ElementId & & LevelGeom & & LevelGeom - > Num ( ) > 0 )
{
2019-07-15 12:47:46 -04:00
FNavigationOctreeElement BSPElem ( Level ) ;
2022-05-27 08:58:40 -04:00
// In WP dynamic mode, store if this is loaded data.
if ( DirtyAreasController . bUseWorldPartitionedDynamicMode )
{
BSPElem . Data - > bLoadedData = Level . HasVisibilityChangeRequestPending ( ) ;
}
2019-07-10 13:31:21 -04:00
FRecastNavMeshGenerator : : ExportVertexSoupGeometry ( * LevelGeom , * BSPElem . Data ) ;
const FBox & Bounds = BSPElem . Data - > Bounds ;
if ( ! Bounds . GetExtent ( ) . IsNearlyZero ( ) )
{
OctreeController . NavOctree - > AddNode ( & Level , nullptr , Bounds , BSPElem ) ;
2022-05-19 09:59:18 -04:00
DirtyAreasController . AddArea ( Bounds , ENavigationDirtyFlag : : All , [ & Level ] { return & Level ; } , nullptr , " Add level " ) ;
2019-07-10 13:31:21 -04:00
UE_LOG ( LogNavOctree , Log , TEXT ( " ADD %s " ) , * Level . GetName ( ) ) ;
}
}
}
# endif // WITH_RECAST
}
void FNavigationDataHandler : : RemoveLevelCollisionFromOctree ( ULevel & Level )
{
if ( OctreeController . NavOctree . IsValid ( ) )
{
2020-04-21 23:23:12 -04:00
const FOctreeElementId2 * ElementId = OctreeController . GetObjectsNavOctreeId ( Level ) ;
2019-07-10 13:31:21 -04:00
UE_LOG ( LogNavOctree , Log , TEXT ( " UNREG %s %s " ) , * Level . GetName ( ) , ElementId ? TEXT ( " [exists] " ) : TEXT ( " " ) ) ;
if ( ElementId ! = nullptr )
{
2019-07-16 05:52:45 -04:00
if ( ensure ( OctreeController . IsValidElement ( * ElementId ) ) )
2019-07-10 13:31:21 -04:00
{
// mark area occupied by given actor as dirty
2020-04-14 16:59:52 -04:00
const FNavigationOctreeElement & ElementData = OctreeController . NavOctree - > GetElementById ( * ElementId ) ;
2022-05-19 09:59:18 -04:00
DirtyAreasController . AddArea ( ElementData . Bounds . GetBox ( ) , ENavigationDirtyFlag : : All , [ & Level ] { return & Level ; } , nullptr , " Remove level " ) ;
2019-07-10 13:31:21 -04:00
}
OctreeController . NavOctree - > RemoveNode ( * ElementId ) ;
OctreeController . RemoveObjectsNavOctreeId ( Level ) ;
}
}
}
void FNavigationDataHandler : : UpdateActorAndComponentsInNavOctree ( AActor & Actor )
{
INavRelevantInterface * NavElement = Cast < INavRelevantInterface > ( & Actor ) ;
if ( NavElement )
{
UpdateNavOctreeElement ( Actor , * NavElement , FNavigationOctreeController : : OctreeUpdate_Default ) ;
}
for ( UActorComponent * Component : Actor . GetComponents ( ) )
{
INavRelevantInterface * CompNavElement = Cast < INavRelevantInterface > ( Component ) ;
if ( CompNavElement )
{
// Component != null is implied by successful INavRelevantInterface cast
2019-08-01 10:35:59 -04:00
if ( Actor . IsComponentRelevantForNavigation ( Component ) )
{
UpdateNavOctreeElement ( * Component , * CompNavElement , FNavigationOctreeController : : OctreeUpdate_Default ) ;
}
else
{
UnregisterNavOctreeElement ( * Component , * CompNavElement , FNavigationOctreeController : : OctreeUpdate_Default ) ;
}
2019-07-10 13:31:21 -04:00
}
}
}
void FNavigationDataHandler : : ProcessPendingOctreeUpdates ( )
{
if ( OctreeController . PendingOctreeUpdates . Num ( ) & & OctreeController . NavOctree )
{
for ( TSet < FNavigationDirtyElement > : : TIterator It ( OctreeController . PendingOctreeUpdates ) ; It ; + + It )
{
AddElementToNavOctree ( * It ) ;
}
}
OctreeController . PendingOctreeUpdates . Empty ( 32 ) ;
2020-03-30 12:13:52 -04:00
}
void FNavigationDataHandler : : DemandLazyDataGathering ( FNavigationRelevantData & ElementData )
{
// Do the lazy gathering on the element
OctreeController . NavOctree - > DemandLazyDataGathering ( ElementData ) ;
// Check if any child asked for some lazy gathering
if ( ElementData . IsPendingChildLazyModifiersGathering ( ) )
{
TArray < FWeakObjectPtr > ChildNodes ;
OctreeController . OctreeChildNodesMap . MultiFind ( ElementData . GetOwner ( ) , ChildNodes ) ;
for ( FWeakObjectPtr & ChildNode : ChildNodes )
{
if ( ChildNode . IsValid ( ) )
{
UObject * ChildNodeOb = ChildNode . Get ( ) ;
INavRelevantInterface * ChildNavInterface = ChildNodeOb ? Cast < INavRelevantInterface > ( ChildNodeOb ) : nullptr ;
if ( ChildNavInterface )
{
OctreeController . NavOctree - > DemandChildLazyDataGathering ( ElementData , * ChildNavInterface ) ;
}
}
}
ElementData . bPendingChildLazyModifiersGathering = false ;
}
}