Is it impossible to turn off navigation auto-rebuild in the editor?

I’m working on a large world composition level. The navigation data re-build keeps popping up and slowing things down. There appears to be no setting that will prevent it from doing so when in the editor.

First: Is there a setting that’s supposed to do this?

Second: It seems the rebuild is triggered from this code:


void UNavigationSystemV1::RebuildDirtyAreas(float DeltaSeconds)
{
SCOPE_CYCLE_COUNTER(STAT_Navigation_TickMarkDirty);
UWorld* World = GetWorld();
const bool bForceRebuilding = (World != nullptr) && (World->IsGameWorld() == false);
DefaultDirtyAreasController.Tick(DeltaSeconds, NavDataSet, bForceRebuilding);
}


Note that any world that’s not a “Game World” will cause re-builds, and at least the persistent level is an editor world (I think all the levels might be.)

This calls:


void FNavigationDirtyAreasController::Tick(const float DeltaSeconds, const TArray<ANavigationData*>& NavDataSet, bool bForceRebuilding)
{
DirtyAreasUpdateTime += DeltaSeconds;
const bool bCanRebuildNow = bForceRebuilding || (DirtyAreasUpdateFreq != 0.f && DirtyAreasUpdateTime >= (1.0f / DirtyAreasUpdateFreq));

if (DirtyAreas.Num() > 0 && bCanRebuildNow)
...


It’s also interesting that DirtyAreasUpdateFreq is per-second, not seconds-per-rebuild. That’s not super obvious from the tool tip on that setting …

So, what will go wrong if I make a checkbox named “bSuppressNavigationAutoRebuildInEditor” and check it in the bForceRebuilding part?
I’m hoping that “Build Paths” in the overall build process will still re-build as necessary.

It turns out that there is a flag called bNavigationAutoUpdateEnabled, but it’s not easily accessible through the settings UI.
It’s also … toggled each time a world is loaded, to force the “set” function to pay attention to it. Blech!


 if (Mode == FNavigationSystemRunMode::EditorMode)
{
// make sure this static get applied to this instance
bNavigationAutoUpdateEnabled = !bNavigationAutoUpdateEnabled;
SetNavigationAutoUpdateEnabled(!bNavigationAutoUpdateEnabled, this);


void UNavigationSystemV1::SetNavigationAutoUpdateEnabled(bool bNewEnable, UNavigationSystemBase* InNavigationSystemBase)
{
if (bNewEnable != bNavigationAutoUpdateEnabled)
{
bNavigationAutoUpdateEnabled = bNewEnable;

UNavigationSystemV1* NavSystem = Cast<UNavigationSystemV1>(InNavigationSystemBase);
if (NavSystem)
{
const bool bCurrentIsEnabled = NavSystem->GetIsAutoUpdateEnabled();


virtual bool GetIsAutoUpdateEnabled() const { return bNavigationAutoUpdateEnabled; }


So bCurrentIsEnabled will always be the same value as bNewEnable.
This is the worst kind of globals/statics usage that gives C++ a bad name.

Ha! So, that static boolean gets set in the end, by the bNavigationAutoUpdate “miscellaneous editor setting” which has the display name “Update Navigation Automatically”

Not … obvious. Also, the code is way more complimacated than it needs to be, with the cake probably being taken by the virtual function that returns a static member and is never overridden anywhere.