// Copyright Epic Games, Inc. All Rights Reserved. #include "MassNavigationProcessors.h" #include "MassCommonUtils.h" #include "MassCommandBuffer.h" #include "MassCommonFragments.h" #include "MassNavigationFragments.h" #include "MassNavigationSubsystem.h" #include "MassSimulationLOD.h" #include "MassMovementTypes.h" #include "MassMovementFragments.h" #include "MassEntityView.h" #include "MassExecutionContext.h" #include "Engine/World.h" //----------------------------------------------------------------------// // UMassOffLODNavigationProcessor //----------------------------------------------------------------------// UMassOffLODNavigationProcessor::UMassOffLODNavigationProcessor() : EntityQuery_Conditional(*this) { ExecutionFlags = (int32)EProcessorExecutionFlags::AllNetModes; ExecutionOrder.ExecuteInGroup = UE::Mass::ProcessorGroupNames::Movement; ExecutionOrder.ExecuteAfter.Add(UE::Mass::ProcessorGroupNames::Avoidance); // @todo: remove this direct dependency } void UMassOffLODNavigationProcessor::ConfigureQueries(const TSharedRef& EntityManager) { EntityQuery_Conditional.AddRequirement(EMassFragmentAccess::ReadWrite); EntityQuery_Conditional.AddRequirement(EMassFragmentAccess::ReadOnly); EntityQuery_Conditional.AddTagRequirement(EMassFragmentPresence::All); EntityQuery_Conditional.AddChunkRequirement(EMassFragmentAccess::ReadOnly, EMassFragmentPresence::Optional); EntityQuery_Conditional.SetChunkFilter(&FMassSimulationVariableTickChunkFragment::ShouldTickChunkThisFrame); } void UMassOffLODNavigationProcessor::Execute(FMassEntityManager& EntityManager, FMassExecutionContext& Context) { EntityQuery_Conditional.ForEachEntityChunk(Context, [this](FMassExecutionContext& Context) { #if WITH_MASSGAMEPLAY_DEBUG if (UE::MassMovement::bFreezeMovement) { return; } #endif // WITH_MASSGAMEPLAY_DEBUG const TArrayView LocationList = Context.GetMutableFragmentView(); const TConstArrayView MoveTargetList = Context.GetFragmentView(); for (FMassExecutionContext::FEntityIterator EntityIt = Context.CreateEntityIterator(); EntityIt; ++EntityIt) { FTransform& CurrentTransform = LocationList[EntityIt].GetMutableTransform(); const FMassMoveTargetFragment& MoveTarget = MoveTargetList[EntityIt]; // Snap position to move target directly CurrentTransform.SetLocation(MoveTarget.Center); } }); } //----------------------------------------------------------------------// // UMassNavigationSmoothHeightProcessor //----------------------------------------------------------------------// UMassNavigationSmoothHeightProcessor::UMassNavigationSmoothHeightProcessor() : EntityQuery(*this) { ExecutionFlags = (int32)EProcessorExecutionFlags::AllNetModes; ExecutionOrder.ExecuteAfter.Add(UE::Mass::ProcessorGroupNames::Movement); } void UMassNavigationSmoothHeightProcessor::ConfigureQueries(const TSharedRef& EntityManager) { EntityQuery.AddRequirement(EMassFragmentAccess::ReadWrite); EntityQuery.AddRequirement(EMassFragmentAccess::ReadOnly); EntityQuery.AddTagRequirement(EMassFragmentPresence::None); EntityQuery.AddConstSharedRequirement(EMassFragmentPresence::All); } void UMassNavigationSmoothHeightProcessor::Execute(FMassEntityManager& EntityManager, FMassExecutionContext& Context) { EntityQuery.ForEachEntityChunk(Context, [this](FMassExecutionContext& Context) { #if WITH_MASSGAMEPLAY_DEBUG if (UE::MassMovement::bFreezeMovement) { return; } #endif // WITH_MASSGAMEPLAY_DEBUG const float DeltaTime = Context.GetDeltaTimeSeconds(); const FMassMovementParameters& MovementParams = Context.GetConstSharedFragment(); const TArrayView LocationList = Context.GetMutableFragmentView(); const TConstArrayView MoveTargetList = Context.GetFragmentView(); for (FMassExecutionContext::FEntityIterator EntityIt = Context.CreateEntityIterator(); EntityIt; ++EntityIt) { FTransform& CurrentTransform = LocationList[EntityIt].GetMutableTransform(); const FMassMoveTargetFragment& MoveTarget = MoveTargetList[EntityIt]; if (MoveTarget.GetCurrentAction() == EMassMovementAction::Move || MoveTarget.GetCurrentAction() == EMassMovementAction::Stand) { // Set height smoothly to follow current move targets height. FVector CurrentLocation = CurrentTransform.GetLocation(); FMath::ExponentialSmoothingApprox(CurrentLocation.Z, MoveTarget.Center.Z, DeltaTime, MovementParams.HeightSmoothingTime); CurrentTransform.SetLocation(CurrentLocation); } } }); } //----------------------------------------------------------------------// // UMassMoveTargetFragmentInitializer //----------------------------------------------------------------------// UMassMoveTargetFragmentInitializer::UMassMoveTargetFragmentInitializer() : InitializerQuery(*this) { ObservedType = FMassMoveTargetFragment::StaticStruct(); Operation = EMassObservedOperation::Add; } void UMassMoveTargetFragmentInitializer::ConfigureQueries(const TSharedRef& EntityManager) { InitializerQuery.AddRequirement(EMassFragmentAccess::ReadWrite); InitializerQuery.AddRequirement(EMassFragmentAccess::ReadOnly); } void UMassMoveTargetFragmentInitializer::Execute(FMassEntityManager& EntityManager, FMassExecutionContext& Context) { InitializerQuery.ForEachEntityChunk(Context, [](FMassExecutionContext& Context) { const TArrayView MoveTargetList = Context.GetMutableFragmentView(); const TConstArrayView LocationList = Context.GetFragmentView(); for (FMassExecutionContext::FEntityIterator EntityIt = Context.CreateEntityIterator(); EntityIt; ++EntityIt) { FMassMoveTargetFragment& MoveTarget = MoveTargetList[EntityIt]; const FTransformFragment& Location = LocationList[EntityIt]; MoveTarget.Center = Location.GetTransform().GetLocation(); MoveTarget.Forward = Location.GetTransform().GetRotation().Vector(); MoveTarget.DistanceToGoal = 0.0f; MoveTarget.EntityDistanceToGoal = FMassMoveTargetFragment::UnsetDistance; MoveTarget.SlackRadius = 0.0f; } }); } //----------------------------------------------------------------------// // UMassNavigationObstacleGridProcessor //----------------------------------------------------------------------// UMassNavigationObstacleGridProcessor::UMassNavigationObstacleGridProcessor() { ExecutionFlags = (int32)EProcessorExecutionFlags::AllNetModes; ExecutionOrder.ExecuteAfter.Add(UE::Mass::ProcessorGroupNames::Movement); } void UMassNavigationObstacleGridProcessor::ConfigureQueries(const TSharedRef& EntityManager) { FMassEntityQuery BaseEntityQuery(EntityManager); BaseEntityQuery.AddRequirement(EMassFragmentAccess::ReadOnly); BaseEntityQuery.AddRequirement(EMassFragmentAccess::ReadOnly); BaseEntityQuery.AddRequirement(EMassFragmentAccess::ReadWrite); BaseEntityQuery.AddSubsystemRequirement(EMassFragmentAccess::ReadWrite); AddToGridEntityQuery = BaseEntityQuery; AddToGridEntityQuery.AddRequirement(EMassFragmentAccess::ReadOnly, EMassFragmentPresence::Optional); AddToGridEntityQuery.AddTagRequirement(EMassFragmentPresence::None); AddToGridEntityQuery.AddTagRequirement(EMassFragmentPresence::None); AddToGridEntityQuery.RegisterWithProcessor(*this); UpdateGridEntityQuery = BaseEntityQuery; UpdateGridEntityQuery.AddRequirement(EMassFragmentAccess::ReadOnly, EMassFragmentPresence::Optional); UpdateGridEntityQuery.AddTagRequirement(EMassFragmentPresence::None); UpdateGridEntityQuery.AddTagRequirement(EMassFragmentPresence::All); UpdateGridEntityQuery.RegisterWithProcessor(*this); RemoveFromGridEntityQuery = BaseEntityQuery; RemoveFromGridEntityQuery.AddTagRequirement(EMassFragmentPresence::All); RemoveFromGridEntityQuery.AddTagRequirement(EMassFragmentPresence::All); RemoveFromGridEntityQuery.RegisterWithProcessor(*this); } void UMassNavigationObstacleGridProcessor::Execute(FMassEntityManager& EntityManager, FMassExecutionContext& Context) { // can't be ParallelFor due to MovementSubsystem->GetGridMutable().Move not being thread-safe AddToGridEntityQuery.ForEachEntityChunk(Context, [this, &EntityManager](FMassExecutionContext& Context) { FNavigationObstacleHashGrid2D& HashGrid = Context.GetMutableSubsystemChecked().GetObstacleGridMutable(); TConstArrayView LocationList = Context.GetFragmentView(); TConstArrayView RadiiList = Context.GetFragmentView(); TArrayView NavigationObstacleCellLocationList = Context.GetMutableFragmentView(); const bool bHasColliderData = Context.GetFragmentView().Num() > 0; for (FMassExecutionContext::FEntityIterator EntityIt = Context.CreateEntityIterator(); EntityIt; ++EntityIt) { // Add to the grid const FVector NewPos = LocationList[EntityIt].GetTransform().GetLocation(); const float Radius = RadiiList[EntityIt].Radius; FMassNavigationObstacleItem ObstacleItem; ObstacleItem.Entity = Context.GetEntity(EntityIt); ObstacleItem.ItemFlags |= bHasColliderData ? EMassNavigationObstacleFlags::HasColliderData : EMassNavigationObstacleFlags::None; const FBox NewBounds(NewPos - FVector(Radius, Radius, 0.f), NewPos + FVector(Radius, Radius, 0.f)); NavigationObstacleCellLocationList[EntityIt].CellLoc = HashGrid.Add(ObstacleItem, NewBounds); Context.Defer().AddTag(ObstacleItem.Entity); } }); UpdateGridEntityQuery.ForEachEntityChunk(Context, [this, &EntityManager](FMassExecutionContext& Context) { FNavigationObstacleHashGrid2D& HashGrid = Context.GetMutableSubsystemChecked().GetObstacleGridMutable(); TConstArrayView LocationList = Context.GetFragmentView(); TConstArrayView RadiiList = Context.GetFragmentView(); TArrayView NavigationObstacleCellLocationList = Context.GetMutableFragmentView(); const bool bHasColliderData = Context.GetFragmentView().Num() > 0; for (FMassExecutionContext::FEntityIterator EntityIt = Context.CreateEntityIterator(); EntityIt; ++EntityIt) { // Update position in grid const FVector NewPos = LocationList[EntityIt].GetTransform().GetLocation(); const float Radius = RadiiList[EntityIt].Radius; FMassNavigationObstacleItem ObstacleItem; ObstacleItem.Entity = Context.GetEntity(EntityIt); ObstacleItem.ItemFlags |= bHasColliderData ? EMassNavigationObstacleFlags::HasColliderData : EMassNavigationObstacleFlags::None; const FBox NewBounds(NewPos - FVector(Radius, Radius, 0.f), NewPos + FVector(Radius, Radius, 0.f)); NavigationObstacleCellLocationList[EntityIt].CellLoc = HashGrid.Move(ObstacleItem, NavigationObstacleCellLocationList[EntityIt].CellLoc, NewBounds); #if WITH_MASSGAMEPLAY_DEBUG && 0 const FDebugContext BaseDebugContext(this, LogAvoidance, nullptr, ObstacleItem.Entity); if (DebugIsSelected(ObstacleItem.Entity)) { FBox Box = MovementSubsystem->GetGridMutable().CalcCellBounds(AvoidanceObstacleCellLocationList[EntityIt].CellLoc); Box.Max.Z += 200.f; DebugDrawBox(BaseDebugContext, Box, FColor::Yellow); } #endif // WITH_MASSGAMEPLAY_DEBUG } }); RemoveFromGridEntityQuery.ForEachEntityChunk(Context, [this, &EntityManager](FMassExecutionContext& Context) { FNavigationObstacleHashGrid2D& HashGrid = Context.GetMutableSubsystemChecked().GetObstacleGridMutable(); TArrayView AvoidanceObstacleCellLocationList = Context.GetMutableFragmentView(); for (FMassExecutionContext::FEntityIterator EntityIt = Context.CreateEntityIterator(); EntityIt; ++EntityIt) { FMassNavigationObstacleItem ObstacleItem; ObstacleItem.Entity = Context.GetEntity(EntityIt); HashGrid.Remove(ObstacleItem, AvoidanceObstacleCellLocationList[EntityIt].CellLoc); AvoidanceObstacleCellLocationList[EntityIt].CellLoc = FNavigationObstacleHashGrid2D::FCellLocation(); Context.Defer().RemoveTag(ObstacleItem.Entity); } }); } //----------------------------------------------------------------------// // UMassNavigationObstacleRemoverProcessor //----------------------------------------------------------------------// UMassNavigationObstacleRemoverProcessor::UMassNavigationObstacleRemoverProcessor() : EntityQuery(*this) { ObservedType = FMassNavigationObstacleGridCellLocationFragment::StaticStruct(); Operation = EMassObservedOperation::Remove; ExecutionFlags = (int32)EProcessorExecutionFlags::AllNetModes; } void UMassNavigationObstacleRemoverProcessor::ConfigureQueries(const TSharedRef& EntityManager) { EntityQuery.AddRequirement(EMassFragmentAccess::ReadWrite); EntityQuery.AddSubsystemRequirement(EMassFragmentAccess::ReadWrite); } void UMassNavigationObstacleRemoverProcessor::Execute(FMassEntityManager& EntityManager, FMassExecutionContext& Context) { EntityQuery.ForEachEntityChunk(Context, [this](FMassExecutionContext& Context) { FNavigationObstacleHashGrid2D& HashGrid = Context.GetMutableSubsystemChecked().GetObstacleGridMutable(); const TArrayView AvoidanceObstacleCellLocationList = Context.GetMutableFragmentView(); for (FMassExecutionContext::FEntityIterator EntityIt = Context.CreateEntityIterator(); EntityIt; ++EntityIt) { FMassNavigationObstacleItem ObstacleItem; ObstacleItem.Entity = Context.GetEntity(EntityIt); HashGrid.Remove(ObstacleItem, AvoidanceObstacleCellLocationList[EntityIt].CellLoc); } }); }