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

149 lines
7.0 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "MassStationaryISMSwitcherProcessor.h"
#include "MassRepresentationSubsystem.h"
#include "MassCommonFragments.h"
#include "MassRepresentationProcessor.h"
#include "MassSignalSubsystem.h"
UMassStationaryISMSwitcherProcessor::UMassStationaryISMSwitcherProcessor(const FObjectInitializer& ObjectInitializer)
: EntityQuery(*this)
{
ExecutionOrder.ExecuteInGroup = UE::Mass::ProcessorGroupNames::Representation;
ExecutionOrder.ExecuteAfter.Add(UMassVisualizationProcessor::StaticClass()->GetFName());
bAutoRegisterWithProcessingPhases = true;
ExecutionFlags = static_cast<int32>(EProcessorExecutionFlags::AllNetModes);
}
void UMassStationaryISMSwitcherProcessor::ConfigureQueries(const TSharedRef<FMassEntityManager>& EntityManager)
{
EntityQuery.AddRequirement<FMassRepresentationLODFragment>(EMassFragmentAccess::ReadOnly);
EntityQuery.AddRequirement<FTransformFragment>(EMassFragmentAccess::ReadOnly);
EntityQuery.AddRequirement<FMassRepresentationFragment>(EMassFragmentAccess::ReadWrite);
EntityQuery.AddConstSharedRequirement<FMassRepresentationParameters>();
EntityQuery.AddSharedRequirement<FMassRepresentationSubsystemSharedFragment>(EMassFragmentAccess::ReadWrite);
EntityQuery.AddTagRequirement<FMassStaticRepresentationTag>(EMassFragmentPresence::All);
EntityQuery.AddTagRequirement<FMassStationaryISMSwitcherProcessorTag>(EMassFragmentPresence::All);
EntityQuery.AddSubsystemRequirement<UMassSignalSubsystem>(EMassFragmentAccess::ReadWrite);
}
void UMassStationaryISMSwitcherProcessor::Execute(FMassEntityManager& EntityManager, FMassExecutionContext& Context)
{
EntityQuery.ForEachEntityChunk(Context, &UMassStationaryISMSwitcherProcessor::ProcessContext);
}
void UMassStationaryISMSwitcherProcessor::ProcessContext(FMassExecutionContext& Context)
{
UMassSignalSubsystem& SignalSubsystem = Context.GetMutableSubsystemChecked<UMassSignalSubsystem>();
UMassRepresentationSubsystem* RepresentationSubsystem = Context.GetMutableSharedFragment<FMassRepresentationSubsystemSharedFragment>().RepresentationSubsystem;
check(RepresentationSubsystem);
FMassInstancedStaticMeshInfoArrayView ISMInfosView = RepresentationSubsystem->GetMutableInstancedStaticMeshInfos();
const TConstArrayView<FMassRepresentationLODFragment> RepresentationLODList = Context.GetFragmentView<FMassRepresentationLODFragment>();
const TConstArrayView<FTransformFragment> TransformList = Context.GetFragmentView<FTransformFragment>();
const TArrayView<FMassRepresentationFragment> RepresentationList = Context.GetMutableFragmentView<FMassRepresentationFragment>();
const FMassRepresentationParameters& RepresentationParams = Context.GetConstSharedFragment<FMassRepresentationParameters>();
const bool bDoKeepActorExtraFrame = UE::Mass::Representation::bAllowKeepActorExtraFrame ? RepresentationParams.bKeepLowResActors : false;
for (FMassExecutionContext::FEntityIterator EntityIt = Context.CreateEntityIterator(); EntityIt; ++EntityIt)
{
const FMassEntityHandle EntityHandle = Context.GetEntity(EntityIt);
const FMassRepresentationLODFragment& RepresentationLOD = RepresentationLODList[EntityIt];
const FTransformFragment& TransformFragment = TransformList[EntityIt];
FMassRepresentationFragment& Representation = RepresentationList[EntityIt];
if (Representation.PrevRepresentation != EMassRepresentationType::StaticMeshInstance
&& Representation.CurrentRepresentation != EMassRepresentationType::StaticMeshInstance)
{
// nothing to do here
continue;
}
if (!ensureMsgf(Representation.StaticMeshDescHandle.IsValid() && ISMInfosView.IsValidIndex(Representation.StaticMeshDescHandle.ToIndex())
, TEXT("Invalid handle index %u for ISMInfosView"), Representation.StaticMeshDescHandle.ToIndex()))
{
continue;
}
FMassInstancedStaticMeshInfo& ISMInfo = ISMInfosView[Representation.StaticMeshDescHandle.ToIndex()];
if (const bool bSwitchedAwayFromStaticMesh = (Representation.PrevRepresentation == EMassRepresentationType::StaticMeshInstance
&& Representation.CurrentRepresentation != EMassRepresentationType::StaticMeshInstance))
{
// note that we're using the PrevLODSignificance here, and the reason for it is that the Prev value matches the
// PrevRepresentation - thus we need to remove from the "previously" used LODSignificance range.
ISMInfo.RemoveInstance(EntityHandle, Representation.PrevLODSignificance);
// consume "prev" data
Representation.PrevRepresentation = Representation.CurrentRepresentation;
if (Representation.PrevRepresentation != EMassRepresentationType::None)
{
SignalSubsystem.SignalEntity(UE::Mass::Signals::SwitchedToActor, EntityHandle);
}
}
else if (const bool bSwitchedToStaticMesh = (Representation.PrevRepresentation != EMassRepresentationType::StaticMeshInstance
&& Representation.CurrentRepresentation == EMassRepresentationType::StaticMeshInstance))
{
const FTransform& Transform = TransformFragment.GetTransform();
const FTransform& PrevTransform = Representation.PrevTransform;
const float LODSignificance = RepresentationLOD.LODSignificance;
const float PrevLODSignificance = Representation.PrevLODSignificance;
if (FMassLODSignificanceRange* NewRange = ISMInfo.GetLODSignificanceRange(RepresentationLOD.LODSignificance))
{
if (ISMInfo.ShouldUseTransformOffset())
{
const FTransform& TransformOffset = ISMInfo.GetTransformOffset();
const FTransform SMTransform = TransformOffset * Transform;
NewRange->AddInstance(EntityHandle, SMTransform);
}
else
{
NewRange->AddInstance(EntityHandle, Transform);
}
if (ISMInfo.GetDesc().CustomDataFloats.Num() > 0)
{
NewRange->AddBatchedCustomDataFloats(ISMInfo.GetDesc().CustomDataFloats, {});
}
}
// consume "prev" data
// @note crazy hacky, but we don't want to consume if bDoKeepActorExtraFrame is true. In that case
// UMassRepresentationProcessor::UpdateRepresentation expects the "prev" state not to be consumed
// a frame longer so that it can do the consuming (and call "disable actor").
if (bDoKeepActorExtraFrame == false)
{
Representation.PrevRepresentation = Representation.CurrentRepresentation;
}
SignalSubsystem.SignalEntity(UE::Mass::Signals::SwitchedToISM, EntityHandle);
}
else if (ISMInfo.GetLODSignificanceRangesNum() > 1 && Representation.PrevLODSignificance != RepresentationLOD.LODSignificance)
{
// we remain in ISM land, but LODSignificance changed and we have multiple LODSignificance ranges for this entity
FMassLODSignificanceRange* OldRange = ISMInfo.GetLODSignificanceRange(Representation.PrevLODSignificance);
FMassLODSignificanceRange* NewRange = ISMInfo.GetLODSignificanceRange(RepresentationLOD.LODSignificance);
if (OldRange != NewRange)
{
if (OldRange)
{
OldRange->RemoveInstance(EntityHandle);
}
if (NewRange)
{
const FTransform& Transform = TransformFragment.GetTransform();
NewRange->AddInstance(EntityHandle, Transform);
}
}
}
// consume "prev" data
Representation.PrevLODSignificance = RepresentationLOD.LODSignificance;
}
}