Files
UnrealEngine/Engine/Plugins/Runtime/MassGameplay/Source/MassLOD/Private/MassLODTrait.cpp
2025-05-18 13:04:45 +08:00

154 lines
6.1 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "MassLODTrait.h"
#include "MassEntityTemplateRegistry.h"
#include "MassCommonFragments.h"
#include "MassLODFragments.h"
#include "MassEntityUtils.h"
#include "MassLODCollectorProcessor.h"
#include "MassLODDistanceCollectorProcessor.h"
namespace UE::Mass::Private
{
bool ValidateRequiredProcessor(const TNotNull<const UMassEntityTraitBase*> Trait, const TSubclassOf<UMassProcessor>& ProcessorClass)
{
check(ProcessorClass);
bool bValidCollectorActive = false;
// @todo make this processor class configurable. Could be something like:
// * every processor declared "identifying tag", a unique combination that would identify given processor class
// * traits can add "required processors"
// * tags of required processors are added automatically
// * we can also report required processors that are marked as not auto-added.
// -- downside of that last, similar to the one bellow, is that disabling a given processor might be deliberate and it can still be enabled at runtime
const UMassProcessor* LODCollectorProcessor = ProcessorClass->GetDefaultObject<UMassProcessor>();
if (ensureMsgf(LODCollectorProcessor, TEXT("Failed to fetch CDO from class %s"), *ProcessorClass->GetName()))
{
if (LODCollectorProcessor->ShouldAutoAddToGlobalList())
{
bValidCollectorActive = true;
}
else
{
// look for subclasses
TArray<UClass*> Results;
GetDerivedClasses(ProcessorClass, Results, /*bRecursive=*/true);
for (UClass* Class : Results)
{
check(Class);
const UMassProcessor* LODCollectorSubclassProcessor = Class->GetDefaultObject<UMassProcessor>();
check(LODCollectorSubclassProcessor);
if (LODCollectorSubclassProcessor->ShouldAutoAddToGlobalList())
{
bValidCollectorActive = true;
break;
}
}
if (bValidCollectorActive == false)
{
TStringBuilder<256> SubclassesStringBuilder;
if (Results.Num() > 0)
{
SubclassesStringBuilder << ", nor any of its subclasses: ";
for (UClass* Class : Results)
{
SubclassesStringBuilder << GetNameSafe(Class) << ", ";
}
}
UE_LOG(LogMassLOD, Error, TEXT("Using %s trait while the required processor %s%s is not enabled by default")
, *Trait->GetName(), *GetNameSafe(LODCollectorProcessor->GetClass()), SubclassesStringBuilder.ToString());
}
}
}
return bValidCollectorActive;
}
}
using UE::Mass::Private::ValidateRequiredProcessor;
//-----------------------------------------------------------------------------
// UMassLODCollectorTrait
//-----------------------------------------------------------------------------
void UMassLODCollectorTrait::BuildTemplate(FMassEntityTemplateBuildContext& BuildContext, const UWorld& World) const
{
BuildContext.AddFragment<FMassViewerInfoFragment>();
BuildContext.AddTag<FMassCollectLODViewerInfoTag>();
BuildContext.RequireFragment<FTransformFragment>();
}
bool UMassLODCollectorTrait::ValidateTemplate(const FMassEntityTemplateBuildContext& BuildContext, const UWorld& World, FAdditionalTraitRequirements& OutTraitRequirements) const
{
// if enabled, we require MassLODCollectorProcessor to be enabled.
if (bTestCollectorProcessor && !ValidateRequiredProcessor(this, UMassLODCollectorProcessor::StaticClass()))
{
return false;
}
return Super::ValidateTemplate(BuildContext, World, OutTraitRequirements);
}
//-----------------------------------------------------------------------------
// UMassDistanceLODCollectorTrait
//-----------------------------------------------------------------------------
void UMassDistanceLODCollectorTrait::BuildTemplate(FMassEntityTemplateBuildContext& BuildContext, const UWorld& World) const
{
BuildContext.AddFragment<FMassViewerInfoFragment>();
BuildContext.AddTag<FMassCollectDistanceLODViewerInfoTag>();
BuildContext.RequireFragment<FTransformFragment>();
}
bool UMassDistanceLODCollectorTrait::ValidateTemplate(const FMassEntityTemplateBuildContext& BuildContext, const UWorld& World, FAdditionalTraitRequirements& OutTraitRequirements) const
{
// if enabled, we require UMassLODDistanceCollectorProcessor to be enabled.
if (bTestCollectorProcessor && !ValidateRequiredProcessor(this, UMassLODDistanceCollectorProcessor::StaticClass()))
{
return false;
}
return Super::ValidateTemplate(BuildContext, World, OutTraitRequirements);
}
//-----------------------------------------------------------------------------
// UMassSimulationLODTrait
//-----------------------------------------------------------------------------
void UMassSimulationLODTrait::BuildTemplate(FMassEntityTemplateBuildContext& BuildContext, const UWorld& World) const
{
BuildContext.RequireFragment<FMassViewerInfoFragment>();
BuildContext.RequireFragment<FTransformFragment>();
FMassSimulationLODFragment& LODFragment = BuildContext.AddFragment_GetRef<FMassSimulationLODFragment>();
// Start all simulation LOD in the Off
if (Params.bSetLODTags || bEnableVariableTicking || BuildContext.IsInspectingData())
{
LODFragment.LOD = EMassLOD::Off;
BuildContext.AddTag<FMassOffLODTag>();
}
FMassEntityManager& EntityManager = UE::Mass::Utils::GetEntityManagerChecked(World);
FConstSharedStruct ParamsFragment = EntityManager.GetOrCreateConstSharedFragment(Params);
BuildContext.AddConstSharedFragment(ParamsFragment);
FSharedStruct SharedFragment = EntityManager.GetOrCreateSharedFragment<FMassSimulationLODSharedFragment>(FConstStructView::Make(Params), Params);
BuildContext.AddSharedFragment(SharedFragment);
// Variable ticking from simulation LOD
if (bEnableVariableTicking || BuildContext.IsInspectingData())
{
BuildContext.AddFragment<FMassSimulationVariableTickFragment>();
BuildContext.AddChunkFragment<FMassSimulationVariableTickChunkFragment>();
FConstSharedStruct VariableTickParamsFragment = EntityManager.GetOrCreateConstSharedFragment(VariableTickParams);
BuildContext.AddConstSharedFragment(VariableTickParamsFragment);
FSharedStruct VariableTickSharedFragment = EntityManager.GetOrCreateSharedFragment<FMassSimulationVariableTickSharedFragment>(FConstStructView::Make(VariableTickParams), VariableTickParams);
BuildContext.AddSharedFragment(VariableTickSharedFragment);
}
}