You've already forked UnrealEngineUWP
mirror of
https://github.com/izzy2lost/UnrealEngineUWP.git
synced 2026-03-26 18:15:20 -07:00
By default: * It implements FTickableGameObject::GetTickableGameObjectWorld to return the subsystem's world * It prevents the subsystem from ticking as soon as the subsystem is deinitialized (has required custom solutions in the past to avoid crashes when UWaterSubsystem and UAutoDestroySubsystem get ticked after their world is pending destroy) * It prevents the subsystem's CDO from ever ticking #rb jean-francois.dube, chris.gagnon, ben.zeigler #jira none [CL 15512967 by jonathan bard in ue5-main branch]
264 lines
7.1 KiB
C++
264 lines
7.1 KiB
C++
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
|
|
#include "LandscapeSubsystem.h"
|
|
#include "UObject/UObjectGlobals.h"
|
|
#include "Engine/EngineBaseTypes.h"
|
|
#include "Engine/World.h"
|
|
#include "ContentStreaming.h"
|
|
#include "Landscape.h"
|
|
#include "LandscapeProxy.h"
|
|
#include "LandscapeStreamingProxy.h"
|
|
#include "LandscapeInfo.h"
|
|
#include "ProfilingDebugging/CsvProfiler.h"
|
|
#include "WorldPartition/WorldPartitionSubsystem.h"
|
|
#include "ActorPartition/ActorPartitionSubsystem.h"
|
|
#include "Engine/World.h"
|
|
#include "Math/IntRect.h"
|
|
#include "LandscapeConfigHelper.h"
|
|
#include "Engine/Canvas.h"
|
|
|
|
static int32 GUseStreamingManagerForCameras = 1;
|
|
static FAutoConsoleVariableRef CVarUseStreamingManagerForCameras(
|
|
TEXT("grass.UseStreamingManagerForCameras"),
|
|
GUseStreamingManagerForCameras,
|
|
TEXT("1: Use Streaming Manager; 0: Use ViewLocationsRenderedLastFrame"));
|
|
|
|
DECLARE_CYCLE_STAT(TEXT("LandscapeSubsystem Tick"), STAT_LandscapeSubsystemTick, STATGROUP_Landscape);
|
|
|
|
#define LOCTEXT_NAMESPACE "LandscapeSubsystem"
|
|
|
|
ULandscapeSubsystem::ULandscapeSubsystem()
|
|
{
|
|
}
|
|
|
|
ULandscapeSubsystem::~ULandscapeSubsystem()
|
|
{
|
|
}
|
|
|
|
void ULandscapeSubsystem::RegisterActor(ALandscapeProxy* Proxy)
|
|
{
|
|
Proxies.AddUnique(Proxy);
|
|
}
|
|
|
|
void ULandscapeSubsystem::UnregisterActor(ALandscapeProxy* Proxy)
|
|
{
|
|
Proxies.Remove(Proxy);
|
|
}
|
|
|
|
void ULandscapeSubsystem::Initialize(FSubsystemCollectionBase& Collection)
|
|
{
|
|
Super::Initialize(Collection);
|
|
|
|
#if WITH_EDITOR
|
|
GrassMapsBuilder = new FLandscapeGrassMapsBuilder(GetWorld());
|
|
GIBakedTextureBuilder = new FLandscapeGIBakedTextureBuilder(GetWorld());
|
|
PhysicalMaterialBuilder = new FLandscapePhysicalMaterialBuilder(GetWorld());
|
|
#endif
|
|
}
|
|
|
|
void ULandscapeSubsystem::Deinitialize()
|
|
{
|
|
#if WITH_EDITOR
|
|
if (GrassMapsBuilder)
|
|
{
|
|
delete GrassMapsBuilder;
|
|
}
|
|
if (GIBakedTextureBuilder)
|
|
{
|
|
delete GIBakedTextureBuilder;
|
|
}
|
|
if (PhysicalMaterialBuilder)
|
|
{
|
|
delete PhysicalMaterialBuilder;
|
|
}
|
|
#endif
|
|
Proxies.Empty();
|
|
|
|
Super::Deinitialize();
|
|
}
|
|
|
|
TStatId ULandscapeSubsystem::GetStatId() const
|
|
{
|
|
RETURN_QUICK_DECLARE_CYCLE_STAT(ULandscapeSubsystem, STATGROUP_Tickables);
|
|
}
|
|
|
|
ETickableTickType ULandscapeSubsystem::GetTickableTickType() const
|
|
{
|
|
return HasAnyFlags(RF_ClassDefaultObject) || !GetWorld() || GetWorld()->IsNetMode(NM_DedicatedServer) ? ETickableTickType::Never : ETickableTickType::Always;
|
|
}
|
|
|
|
void ULandscapeSubsystem::Tick(float DeltaTime)
|
|
{
|
|
SCOPE_CYCLE_COUNTER(STAT_LandscapeSubsystemTick);
|
|
TRACE_CPUPROFILER_EVENT_SCOPE(ULandscapeSubsystem::Tick);
|
|
CSV_SCOPED_TIMING_STAT_EXCLUSIVE(Landscape);
|
|
LLM_SCOPE(ELLMTag::Landscape);
|
|
|
|
Super::Tick(DeltaTime);
|
|
|
|
UWorld* World = GetWorld();
|
|
|
|
static TArray<FVector> OldCameras;
|
|
TArray<FVector>* Cameras = nullptr;
|
|
if (GUseStreamingManagerForCameras == 0)
|
|
{
|
|
if (OldCameras.Num() || World->ViewLocationsRenderedLastFrame.Num())
|
|
{
|
|
Cameras = &OldCameras;
|
|
// there is a bug here, which often leaves us with no cameras in the editor
|
|
if (World->ViewLocationsRenderedLastFrame.Num())
|
|
{
|
|
check(IsInGameThread());
|
|
Cameras = &World->ViewLocationsRenderedLastFrame;
|
|
OldCameras = *Cameras;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
int32 Num = IStreamingManager::Get().GetNumViews();
|
|
if (Num)
|
|
{
|
|
OldCameras.Reset(Num);
|
|
for (int32 Index = 0; Index < Num; Index++)
|
|
{
|
|
auto& ViewInfo = IStreamingManager::Get().GetViewInformation(Index);
|
|
OldCameras.Add(ViewInfo.ViewOrigin);
|
|
}
|
|
Cameras = &OldCameras;
|
|
}
|
|
}
|
|
|
|
int32 InOutNumComponentsCreated = 0;
|
|
for (ALandscapeProxy* Proxy : Proxies)
|
|
{
|
|
#if WITH_EDITOR
|
|
if (GIsEditor)
|
|
{
|
|
if (ALandscape* Landscape = Cast<ALandscape>(Proxy))
|
|
{
|
|
Landscape->TickLayers(DeltaTime);
|
|
}
|
|
|
|
// editor-only
|
|
if (!World->IsPlayInEditor())
|
|
{
|
|
Proxy->UpdateGIBakedTextures();
|
|
Proxy->UpdatePhysicalMaterialTasks();
|
|
}
|
|
}
|
|
#endif
|
|
if (Cameras && Proxy->ShouldTickGrass())
|
|
{
|
|
Proxy->TickGrass(*Cameras, InOutNumComponentsCreated);
|
|
}
|
|
}
|
|
|
|
#if WITH_EDITOR
|
|
if (GIsEditor && !World->IsPlayInEditor())
|
|
{
|
|
LandscapePhysicalMaterial::GarbageCollectTasks();
|
|
}
|
|
#endif
|
|
}
|
|
|
|
#if WITH_EDITOR
|
|
void ULandscapeSubsystem::BuildAll()
|
|
{
|
|
BuildGrassMaps();
|
|
BuildGIBakedTextures();
|
|
BuildPhysicalMaterial();
|
|
}
|
|
|
|
void ULandscapeSubsystem::BuildGrassMaps()
|
|
{
|
|
GrassMapsBuilder->Build();
|
|
}
|
|
|
|
int32 ULandscapeSubsystem::GetOutdatedGrassMapCount()
|
|
{
|
|
return GrassMapsBuilder->GetOutdatedGrassMapCount(/*bInForceUpdate*/false);
|
|
}
|
|
|
|
void ULandscapeSubsystem::BuildGIBakedTextures()
|
|
{
|
|
GIBakedTextureBuilder->Build();
|
|
}
|
|
|
|
int32 ULandscapeSubsystem::GetOutdatedGIBakedTextureComponentsCount()
|
|
{
|
|
return GIBakedTextureBuilder->GetOutdatedGIBakedTextureComponentsCount(/*bInForceUpdate*/false);
|
|
}
|
|
|
|
void ULandscapeSubsystem::BuildPhysicalMaterial()
|
|
{
|
|
PhysicalMaterialBuilder->Build();
|
|
}
|
|
|
|
int32 ULandscapeSubsystem::GetOudatedPhysicalMaterialComponentsCount()
|
|
{
|
|
return PhysicalMaterialBuilder->GetOudatedPhysicalMaterialComponentsCount();
|
|
}
|
|
|
|
bool ULandscapeSubsystem::IsGridBased() const
|
|
{
|
|
return UWorld::HasSubsystem<UWorldPartitionSubsystem>(GetWorld());
|
|
}
|
|
|
|
void ULandscapeSubsystem::ChangeGridSize(ULandscapeInfo* LandscapeInfo, uint32 GridSizeInComponents)
|
|
{
|
|
if (!IsGridBased())
|
|
{
|
|
return;
|
|
}
|
|
|
|
TSet<AActor*> ActorsToDelete;
|
|
FLandscapeConfigHelper::ChangeGridSize(LandscapeInfo, GridSizeInComponents, ActorsToDelete);
|
|
// This code path is used for converting a non grid based Landscape to a gridbased so it shouldn't delete any actors
|
|
check(!ActorsToDelete.Num());
|
|
}
|
|
|
|
ALandscapeProxy* ULandscapeSubsystem::FindOrAddLandscapeProxy(ULandscapeInfo* LandscapeInfo, const FIntPoint& SectionBase)
|
|
{
|
|
if (!IsGridBased())
|
|
{
|
|
return LandscapeInfo->GetCurrentLevelLandscapeProxy(true);
|
|
}
|
|
|
|
return FLandscapeConfigHelper::FindOrAddLandscapeStreamingProxy(LandscapeInfo, SectionBase);
|
|
}
|
|
|
|
void ULandscapeSubsystem::DisplayBuildMessages(FCanvas* Canvas, float& XPos, float& YPos)
|
|
{
|
|
const int32 FontSizeY = 20;
|
|
FCanvasTextItem SmallTextItem(FVector2D(0, 0), FText::GetEmpty(), GEngine->GetSmallFont(), FLinearColor::White);
|
|
SmallTextItem.EnableShadow(FLinearColor::Black);
|
|
|
|
if (int32 OutdatedGrassMapCount = GetOutdatedGrassMapCount())
|
|
{
|
|
SmallTextItem.SetColor(FLinearColor::Red);
|
|
SmallTextItem.Text = FText::Format(LOCTEXT("GRASS_MAPS_NEED_TO_BE_REBUILT_FMT", "GRASS MAPS NEEDS TO BE REBUILT ({0} {0}|plural(one=object,other=objects))"), OutdatedGrassMapCount);
|
|
Canvas->DrawItem(SmallTextItem, FVector2D(XPos, YPos));
|
|
YPos += FontSizeY;
|
|
}
|
|
|
|
if (int32 ComponentsNeedingGITextureBaking = GetOutdatedGIBakedTextureComponentsCount())
|
|
{
|
|
SmallTextItem.SetColor(FLinearColor::Red);
|
|
SmallTextItem.Text = FText::Format(LOCTEXT("LANDSCAPE_TEXTURES_NEED_TO_BE_REBUILT_FMT", "LANDSCAPE BAKED TEXTURES NEEDS TO BE REBUILT ({0} {0}|plural(one=object,other=objects))"), ComponentsNeedingGITextureBaking);
|
|
Canvas->DrawItem(SmallTextItem, FVector2D(XPos, YPos));
|
|
YPos += FontSizeY;
|
|
}
|
|
|
|
if (int32 ComponentsWithOudatedPhysicalMaterial = GetOudatedPhysicalMaterialComponentsCount())
|
|
{
|
|
SmallTextItem.SetColor(FLinearColor::Red);
|
|
SmallTextItem.Text = FText::Format(LOCTEXT("LANDSCAPE_PHYSICALMATERIAL_NEED_TO_BE_REBUILT_FMT", "LANDSCAPE PHYSICAL MATERIAL NEEDS TO BE REBUILT ({0} {0}|plural(one=object,other=objects))"), ComponentsWithOudatedPhysicalMaterial);
|
|
Canvas->DrawItem(SmallTextItem, FVector2D(XPos, YPos));
|
|
YPos += FontSizeY;
|
|
}
|
|
}
|
|
|
|
#endif
|
|
|
|
#undef LOCTEXT_NAMESPACE |