// Copyright Epic Games, Inc. All Rights Reserved. #include "MassSmartObjectRegistration.h" #include "MassActorSubsystem.h" #include "MassCommonFragments.h" #include "MassExecutionContext.h" #include "MassSignalSubsystem.h" #include "SmartObjectSubsystem.h" namespace UE::Mass::Signals { const FName SmartObjectActivationChanged = FName(TEXT("SmartObjectActivated")); } //----------------------------------------------------------------------// // UMassSmartObjectInitializerBase //----------------------------------------------------------------------// UMassSmartObjectInitializerBase::UMassSmartObjectInitializerBase() : EntityQuery(*this) { ExecutionFlags = static_cast(EProcessorExecutionFlags::Standalone | EProcessorExecutionFlags::Server); Operation = EMassObservedOperation::Add; } void UMassSmartObjectInitializerBase::ConfigureQueries(const TSharedRef& EntityManager) { ProcessorRequirements.AddSubsystemRequirement(EMassFragmentAccess::ReadWrite); EntityQuery.AddTagRequirement(EMassFragmentPresence::All); EntityQuery.AddRequirement(EMassFragmentAccess::ReadOnly); EntityQuery.AddRequirement(EMassFragmentAccess::ReadWrite); } void UMassSmartObjectInitializerBase::Execute(FMassEntityManager& EntityManager, FMassExecutionContext& ExecutionContext) { UMassSignalSubsystem& SignalSubsystem = ExecutionContext.GetMutableSubsystemChecked(); TArray EntitiesToSignal; EntityQuery.ForEachEntityChunk(ExecutionContext,[&EntitiesToSignal](FMassExecutionContext& Context) { const TConstArrayView InstancedActorFragments = Context.GetFragmentView(); const TArrayView RegistrationFragments = Context.GetMutableFragmentView(); const int32 NumEntities = Context.GetNumEntities(); EntitiesToSignal.Reserve(EntitiesToSignal.Num() + NumEntities); for (FMassExecutionContext::FEntityIterator EntityIt = Context.CreateEntityIterator(); EntityIt; ++EntityIt) { FSmartObjectRegistrationFragment& RegistrationFragment = RegistrationFragments[EntityIt]; const FMassActorInstanceFragment& InstancedActorFragment = InstancedActorFragments[EntityIt]; checkf(!RegistrationFragment.Handle.IsValid(), TEXT("Should create smartobject only once.")) if (RegistrationFragment.Asset.Get() == nullptr) { continue; } if (!InstancedActorFragment.Handle.IsValid()) { continue; } EntitiesToSignal.Add(Context.GetEntity(EntityIt)); } }); // Signal all entities inside the consolidated list if (EntitiesToSignal.Num()) { SignalSubsystem.SignalEntities(Signal, EntitiesToSignal); } } //----------------------------------------------------------------------// // UMassSmartObjectDeinitializerBase //----------------------------------------------------------------------// UMassSmartObjectDeinitializerBase::UMassSmartObjectDeinitializerBase() : EntityQuery(*this) { ExecutionFlags = static_cast(EProcessorExecutionFlags::Standalone | EProcessorExecutionFlags::Server); Operation = EMassObservedOperation::Remove; } void UMassSmartObjectDeinitializerBase::ConfigureQueries(const TSharedRef& EntityManager) { ProcessorRequirements.AddSubsystemRequirement(EMassFragmentAccess::ReadWrite); } void UMassSmartObjectDeinitializerBase::Execute(FMassEntityManager& EntityManager, FMassExecutionContext& ExecutionContext) { UMassSignalSubsystem& SignalSubsystem = ExecutionContext.GetMutableSubsystemChecked(); TArray EntitiesToSignal; EntityQuery.ForEachEntityChunk(ExecutionContext, [&EntitiesToSignal](FMassExecutionContext& Context) { const int32 NumEntities = Context.GetNumEntities(); EntitiesToSignal.Reserve(EntitiesToSignal.Num() + NumEntities); for (FMassExecutionContext::FEntityIterator EntityIt = Context.CreateEntityIterator(); EntityIt; ++EntityIt) { EntitiesToSignal.Add(Context.GetEntity(EntityIt)); } }); // Signal all entities inside the consolidated list if (EntitiesToSignal.Num()) { SignalSubsystem.SignalEntities(Signal, EntitiesToSignal); } } //----------------------------------------------------------------------// // UMassActiveSmartObjectInitializer //----------------------------------------------------------------------// UMassActiveSmartObjectInitializer::UMassActiveSmartObjectInitializer() { ObservedType = FMassInActiveSmartObjectsRangeTag::StaticStruct(); Signal = UE::Mass::Signals::SmartObjectActivationChanged; } //----------------------------------------------------------------------// // UMassActiveSmartObjectDeinitializer //----------------------------------------------------------------------// UMassActiveSmartObjectDeinitializer::UMassActiveSmartObjectDeinitializer() { ObservedType = FMassInActiveSmartObjectsRangeTag::StaticStruct(); Signal = UE::Mass::Signals::SmartObjectActivationChanged; } //----------------------------------------------------------------------// // UMassActorInstanceHandleInitializer //----------------------------------------------------------------------// UMassActorInstanceHandleInitializer::UMassActorInstanceHandleInitializer() { ObservedType = FMassActorInstanceFragment::StaticStruct(); Signal = UE::Mass::Signals::ActorInstanceHandleChanged; } //----------------------------------------------------------------------// // UMassActorInstanceHandleDeinitializer //----------------------------------------------------------------------// UMassActorInstanceHandleDeinitializer::UMassActorInstanceHandleDeinitializer() { ObservedType = FMassActorInstanceFragment::StaticStruct(); Signal = UE::Mass::Signals::ActorInstanceHandleChanged; } //----------------------------------------------------------------------------- // UMassActiveSmartObjectSignalProcessor //----------------------------------------------------------------------------- UMassActiveSmartObjectSignalProcessor::UMassActiveSmartObjectSignalProcessor() : InsideSmartObjectActiveRangeQuery(*this) , OutsideSmartObjectActiveRangeQuery(*this) { // USmartObjectSubsystem CreateSmartObject/DestroySmartObject methods called // from this process are not safe to call from other threads. bRequiresGameThreadExecution = true; } void UMassActiveSmartObjectSignalProcessor::ConfigureQueries(const TSharedRef& EntityManager) { InsideSmartObjectActiveRangeQuery.AddSubsystemRequirement(EMassFragmentAccess::ReadWrite); InsideSmartObjectActiveRangeQuery.AddRequirement(EMassFragmentAccess::ReadOnly); InsideSmartObjectActiveRangeQuery.AddRequirement(EMassFragmentAccess::ReadOnly); InsideSmartObjectActiveRangeQuery.AddRequirement(EMassFragmentAccess::ReadWrite); InsideSmartObjectActiveRangeQuery.AddTagRequirement(EMassFragmentPresence::All); OutsideSmartObjectActiveRangeQuery.AddSubsystemRequirement(EMassFragmentAccess::ReadWrite); OutsideSmartObjectActiveRangeQuery.AddRequirement(EMassFragmentAccess::ReadWrite); OutsideSmartObjectActiveRangeQuery.AddTagRequirement(EMassFragmentPresence::None); } void UMassActiveSmartObjectSignalProcessor::InitializeInternal(UObject& Owner, const TSharedRef& EntityManager) { Super::InitializeInternal(Owner, EntityManager); UMassSignalSubsystem* SignalSubsystem = UWorld::GetSubsystem(Owner.GetWorld()); SubscribeToSignal(*SignalSubsystem, UE::Mass::Signals::ActorInstanceHandleChanged); SubscribeToSignal(*SignalSubsystem, UE::Mass::Signals::SmartObjectActivationChanged); } void UMassActiveSmartObjectSignalProcessor::SignalEntities(FMassEntityManager& EntityManager, FMassExecutionContext& Context, FMassSignalNameLookup&) { // Process entities in active range InsideSmartObjectActiveRangeQuery.ForEachEntityChunk(Context, [this](FMassExecutionContext& Context) { USmartObjectSubsystem& Subsystem = Context.GetMutableSubsystemChecked(); const TConstArrayView TransformFragments = Context.GetFragmentView(); const TConstArrayView InstancedActorFragments = Context.GetFragmentView(); const TArrayView RegistrationFragments = Context.GetMutableFragmentView(); for (FMassExecutionContext::FEntityIterator EntityIt = Context.CreateEntityIterator(); EntityIt; ++EntityIt) { FSmartObjectRegistrationFragment& RegistrationFragment = RegistrationFragments[EntityIt]; const FMassActorInstanceFragment& InstancedActorFragment = InstancedActorFragments[EntityIt]; const FTransformFragment& TransformFragment = TransformFragments[EntityIt]; // Creation if (!RegistrationFragment.Handle.IsValid() && InstancedActorFragment.Handle.IsValid()) { if (const USmartObjectDefinition* Definition = RegistrationFragment.Asset.Get()) { FSmartObjectActorOwnerData InstancedActorOwnerData(InstancedActorFragment.Handle); RegistrationFragment.Handle = Subsystem.CreateSmartObject( *Definition, TransformFragment.GetTransform(), FConstStructView::Make(InstancedActorOwnerData)); } } // Destruction else if (RegistrationFragment.Handle.IsValid() && !InstancedActorFragment.Handle.IsValid()) { Subsystem.DestroySmartObject(RegistrationFragment.Handle); RegistrationFragment.Handle.Invalidate(); } } }); // Process out of active range entities OutsideSmartObjectActiveRangeQuery.ForEachEntityChunk(Context, [this](FMassExecutionContext& Context) { USmartObjectSubsystem& Subsystem = Context.GetMutableSubsystemChecked(); const TArrayView RegistrationFragments = Context.GetMutableFragmentView(); for (FMassExecutionContext::FEntityIterator EntityIt = Context.CreateEntityIterator(); EntityIt; ++EntityIt) { FSmartObjectRegistrationFragment& RegistrationFragment = RegistrationFragments[EntityIt]; if (RegistrationFragment.Handle.IsValid()) { Subsystem.DestroySmartObject(RegistrationFragment.Handle); RegistrationFragment.Handle.Invalidate(); } } }); }