// Copyright Epic Games, Inc. All Rights Reserved. #include "MoverMassTranslators.h" #include "DefaultMovementSet/NavMoverComponent.h" #include "VisualLogger/VisualLogger.h" #include "MassEntityManager.h" #include "MassCommonTypes.h" #include "MassExecutionContext.h" #include "MassMovementFragments.h" #include "MassSpawnerTypes.h" #include "MassDebugger.h" DECLARE_LOG_CATEGORY_EXTERN(LogMassMoverTranslator, Log, All); DEFINE_LOG_CATEGORY(LogMassMoverTranslator); DECLARE_LOG_CATEGORY_EXTERN(LogMassMoverDivergence, Log, All); DEFINE_LOG_CATEGORY(LogMassMoverDivergence); //----------------------------------------------------------------------// // UMassNavMoverToMassTranslator //----------------------------------------------------------------------// UMassNavMoverToMassTranslator::UMassNavMoverToMassTranslator() : EntityQuery(*this) { ExecutionFlags = (int32)EProcessorExecutionFlags::AllNetModes; ExecutionOrder.ExecuteInGroup = UE::Mass::ProcessorGroupNames::SyncWorldToMass; RequiredTags.Add(); } void UMassNavMoverToMassTranslator::ConfigureQueries(const TSharedRef& EntityManager) { AddRequiredTagsToQuery(EntityQuery); EntityQuery.AddRequirement(EMassFragmentAccess::ReadOnly); EntityQuery.AddRequirement(EMassFragmentAccess::ReadWrite); EntityQuery.AddRequirement(EMassFragmentAccess::ReadWrite); EntityQuery.AddRequirement(EMassFragmentAccess::ReadWrite); } void UMassNavMoverToMassTranslator::Execute(FMassEntityManager& EntityManager, FMassExecutionContext& Context) { EntityQuery.ForEachEntityChunk(Context, [this](FMassExecutionContext& Context) { const TConstArrayView ComponentList = Context.GetFragmentView(); const TArrayView LocationList = Context.GetMutableFragmentView(); const TArrayView VelocityList = Context.GetMutableFragmentView(); const TArrayView DesiredMovementList = Context.GetMutableFragmentView(); for (FMassExecutionContext::FEntityIterator EntityIt = Context.CreateEntityIterator(); EntityIt; ++EntityIt) { if (const UNavMoverComponent* AsMovementComponent = ComponentList[EntityIt].Component.Get()) { LocationList[EntityIt].GetMutableTransform().SetLocation(AsMovementComponent->GetFeetLocation()); VelocityList[EntityIt].Value = AsMovementComponent->GetVelocityForNavMovement(); DesiredMovementList[EntityIt].DesiredMaxSpeedOverride = AsMovementComponent->GetMaxSpeedForNavMovement(); #if WITH_MASSENTITY_DEBUG const bool bDisplayDebug = UE::Mass::Debug::IsDebuggingEntity(Context.GetEntity(EntityIt)); if (bDisplayDebug) { const FVector& PreviousVelocity = VelocityList[EntityIt].DebugPreviousValue; const FVector ZOffset(0,0,5); const FVector& Location = LocationList[EntityIt].GetTransform().GetLocation() + ZOffset; constexpr FVector::FReal VelocityDeltaSquared = 1; if (FVector::DistSquared(PreviousVelocity, AsMovementComponent->GetVelocityForNavMovement()) > VelocityDeltaSquared) { // Draw expected and current velocities UE_VLOG_ARROW(this, LogMassMoverDivergence, Log, Location, Location + VelocityList[EntityIt].Value, FColor::Orange, TEXT("Current\nSpeed %.1f"), VelocityList[EntityIt].Value.Size()); UE_VLOG_ARROW(this, LogMassMoverDivergence, Log, Location, Location + PreviousVelocity, FColor::Green, TEXT("Expected\nSpeed %.1f"), PreviousVelocity.Size()); } } #endif //WITH_MASSENTITY_DEBUG } } }); } //----------------------------------------------------------------------// // UMassToNavMoverTranslator //----------------------------------------------------------------------// UMassToNavMoverTranslator::UMassToNavMoverTranslator() : EntityQuery(*this) { ExecutionFlags = (int32)EProcessorExecutionFlags::AllNetModes; ExecutionOrder.ExecuteInGroup = UE::Mass::ProcessorGroupNames::UpdateWorldFromMass; ExecutionOrder.ExecuteAfter.Add(UE::Mass::ProcessorGroupNames::Movement); RequiredTags.Add(); } void UMassToNavMoverTranslator::ConfigureQueries(const TSharedRef& EntityManager) { AddRequiredTagsToQuery(EntityQuery); EntityQuery.AddRequirement(EMassFragmentAccess::ReadWrite); #if WITH_MASSENTITY_DEBUG EntityQuery.AddRequirement(EMassFragmentAccess::ReadWrite); #else EntityQuery.AddRequirement(EMassFragmentAccess::ReadOnly); #endif //WITH_MASSENTITY_DEBUG EntityQuery.AddRequirement(EMassFragmentAccess::ReadOnly); } void UMassToNavMoverTranslator::Execute(FMassEntityManager& EntityManager, FMassExecutionContext& Context) { EntityQuery.ForEachEntityChunk(Context, [this](FMassExecutionContext& Context) { const TArrayView ComponentList = Context.GetMutableFragmentView(); #if WITH_MASSGAMEPLAY_DEBUG const TArrayView VelocityList = Context.GetMutableFragmentView(); #else const TConstArrayView VelocityList = Context.GetFragmentView(); #endif //WITH_MASSGAMEPLAY_DEBUG const TConstArrayView LocationList = Context.GetFragmentView(); for (FMassExecutionContext::FEntityIterator EntityIt = Context.CreateEntityIterator(); EntityIt; ++EntityIt) { if (UNavMoverComponent* AsMovementComponent = ComponentList[EntityIt].Component.Get()) { FVector RequestedMove = VelocityList[EntityIt].Value; RequestedMove.Z = 0.0f; #if WITH_MASSGAMEPLAY_DEBUG // Store requested velocity. VelocityList[EntityIt].DebugPreviousValue = RequestedMove; #endif //WITH_MASSGAMEPLAY_DEBUG AsMovementComponent->RequestDirectMove(RequestedMove, /*bForceMaxSpeed=*/false); #if WITH_MASSGAMEPLAY_DEBUG bool bDisplayDebug = UE::Mass::Debug::IsDebuggingEntity(Context.GetEntity(EntityIt)); if (bDisplayDebug) { const FVector ActorLocation = AsMovementComponent->GetFeetLocation(); const FVector EntityLocation = LocationList[EntityIt].GetTransform().GetLocation(); UE_VLOG_ARROW(AsMovementComponent, LogMassMoverTranslator, Display, ActorLocation, ActorLocation + RequestedMove, FColor::Green, TEXT("Requested Move: %s"), *(RequestedMove.ToString())); UE_VLOG_SPHERE(AsMovementComponent, LogMassMoverTranslator, Display, EntityLocation, 5.0f, FColor::White, TEXT("EntityLocation: %s"), *(RequestedMove.ToString())); UE_VLOG_SPHERE(AsMovementComponent, LogMassMoverTranslator, Display, EntityLocation + RequestedMove, 5.0f, FColor::Blue, TEXT("EntityPrediction: %s"), *(RequestedMove.ToString())); } #endif // WITH_MASSGAMEPLAY_DEBUG } } }); } //----------------------------------------------------------------------// // UMassNavMoverActorOrientationToMassTranslator //----------------------------------------------------------------------// UMassNavMoverActorOrientationToMassTranslator::UMassNavMoverActorOrientationToMassTranslator() : EntityQuery(*this) { ExecutionFlags = (int32)EProcessorExecutionFlags::AllNetModes; ExecutionOrder.ExecuteInGroup = UE::Mass::ProcessorGroupNames::SyncWorldToMass; RequiredTags.Add(); bRequiresGameThreadExecution = true; } void UMassNavMoverActorOrientationToMassTranslator::ConfigureQueries(const TSharedRef& EntityManager) { AddRequiredTagsToQuery(EntityQuery); EntityQuery.AddRequirement(EMassFragmentAccess::ReadOnly); EntityQuery.AddRequirement(EMassFragmentAccess::ReadWrite); } void UMassNavMoverActorOrientationToMassTranslator::Execute(FMassEntityManager& EntityManager, FMassExecutionContext& Context) { EntityQuery.ForEachEntityChunk(Context, [this](FMassExecutionContext& Context) { const TConstArrayView ComponentList = Context.GetFragmentView(); const TArrayView LocationList = Context.GetMutableFragmentView(); for (FMassExecutionContext::FEntityIterator EntityIt = Context.CreateEntityIterator(); EntityIt; ++EntityIt) { if (const UNavMoverComponent* AsNavMoverComponent = ComponentList[EntityIt].Component.Get()) { if (const USceneComponent* UpdatedComponent = Cast(AsNavMoverComponent->GetUpdatedObject())) { LocationList[EntityIt].GetMutableTransform().SetRotation(UpdatedComponent->GetComponentTransform().GetRotation()); } } } }); } //----------------------------------------------------------------------// // UMassOrientationToNavMoverActorOrientationTranslator //----------------------------------------------------------------------// UMassOrientationToNavMoverActorOrientationTranslator::UMassOrientationToNavMoverActorOrientationTranslator() : EntityQuery(*this) { ExecutionFlags = (int32)EProcessorExecutionFlags::AllNetModes; ExecutionOrder.ExecuteInGroup = UE::Mass::ProcessorGroupNames::UpdateWorldFromMass; ExecutionOrder.ExecuteAfter.Add(UE::Mass::ProcessorGroupNames::Movement); RequiredTags.Add(); bRequiresGameThreadExecution = true; } void UMassOrientationToNavMoverActorOrientationTranslator::ConfigureQueries(const TSharedRef& EntityManager) { AddRequiredTagsToQuery(EntityQuery); EntityQuery.AddRequirement(EMassFragmentAccess::ReadWrite); EntityQuery.AddRequirement(EMassFragmentAccess::ReadOnly); EntityQuery.RequireMutatingWorldAccess(); // due to mutating World by setting component rotation } void UMassOrientationToNavMoverActorOrientationTranslator::Execute(FMassEntityManager& EntityManager, FMassExecutionContext& Context) { EntityQuery.ForEachEntityChunk(Context, [this](FMassExecutionContext& Context) { const TArrayView ComponentList = Context.GetMutableFragmentView(); const TConstArrayView TransformList = Context.GetFragmentView(); for (FMassExecutionContext::FEntityIterator EntityIt = Context.CreateEntityIterator(); EntityIt; ++EntityIt) { if (const UNavMoverComponent* AsNavMoverComponent = ComponentList[EntityIt].Component.Get()) { if (USceneComponent* UpdatedComponent = Cast(AsNavMoverComponent->GetUpdatedObject())) { // TODO: Set OrientToMovement to true or false here - currently this isn't an option the Mover component but it should be // TODO: Mover also doesn't like setting rotation directly and may cause a warning about outside systems modifying the updated component const FTransformFragment& Transform = TransformList[EntityIt]; UpdatedComponent->SetWorldRotation(Transform.GetTransform().GetRotation()); } } } }); }