You've already forked UnrealEngineUWP
mirror of
https://github.com/izzy2lost/UnrealEngineUWP.git
synced 2026-03-26 18:15:20 -07:00
* added simple test to run a query and visualize the results * added debug methods to force initialize/cleanup the simulation from the Editor world * definition class is no longer mandatory (like other filtering options) * parent object definition now accessible from SlotView #rnx #preflight 620c077d483ff0ae5ec4c544 #rb mieszko.zielinski, mikko.mononen #ROBOMERGE-OWNER: marc.audy #ROBOMERGE-AUTHOR: yoan.stamant #ROBOMERGE-SOURCE: CL 19014188 via CL 19014236 via CL 19014251 via CL 19031906 #ROBOMERGE-BOT: UE5 (Release-Engine-Staging -> Main) (v917-18934589) [CL 19032135 by marc audy in ue5-main branch]
397 lines
11 KiB
C++
397 lines
11 KiB
C++
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
|
|
#include "SmartObjectTestingActor.h"
|
|
#include "DebugRenderSceneProxy.h"
|
|
#include "PrimitiveViewRelevance.h"
|
|
#include "Debug/DebugDrawService.h"
|
|
|
|
//----------------------------------------------------------------------//
|
|
// FSmartObjectTestSceneProxy
|
|
//----------------------------------------------------------------------//
|
|
#if UE_ENABLE_DEBUG_DRAWING
|
|
class FSmartObjectTestSceneProxy final : public FDebugRenderSceneProxy
|
|
{
|
|
public:
|
|
explicit FSmartObjectTestSceneProxy(const UPrimitiveComponent& InComponent, const EDrawType InDrawType = EDrawType::WireMesh);
|
|
|
|
virtual FPrimitiveViewRelevance GetViewRelevance(const FSceneView* View) const override;
|
|
virtual uint32 GetMemoryFootprint() const override;
|
|
|
|
private:
|
|
uint32 ViewFlagIndex = 0;
|
|
};
|
|
|
|
FSmartObjectTestSceneProxy::FSmartObjectTestSceneProxy(const UPrimitiveComponent& InComponent, const EDrawType InDrawType)
|
|
: FDebugRenderSceneProxy(&InComponent)
|
|
{
|
|
DrawType = InDrawType;
|
|
ViewFlagName = TEXT("Game");
|
|
ViewFlagIndex = uint32(FEngineShowFlags::FindIndexByName(*ViewFlagName));
|
|
}
|
|
|
|
FPrimitiveViewRelevance FSmartObjectTestSceneProxy::GetViewRelevance(const FSceneView* View) const
|
|
{
|
|
FPrimitiveViewRelevance Result;
|
|
Result.bDrawRelevance = IsShown(View) && ViewFlagIndex != INDEX_NONE && View->Family->EngineShowFlags.GetSingleFlag(ViewFlagIndex);
|
|
Result.bDynamicRelevance = true;
|
|
// ideally the TranslucencyRelevance should be filled out by the material, here we do it conservative
|
|
Result.bSeparateTranslucency = Result.bNormalTranslucency = true;
|
|
return Result;
|
|
}
|
|
|
|
uint32 FSmartObjectTestSceneProxy::GetMemoryFootprint(void) const
|
|
{
|
|
return sizeof(*this) + FDebugRenderSceneProxy::GetAllocatedSize();
|
|
}
|
|
#endif // UE_ENABLE_DEBUG_DRAWING
|
|
|
|
|
|
//----------------------------------------------------------------------//
|
|
// USmartObjectTest
|
|
//----------------------------------------------------------------------//
|
|
void USmartObjectTest::PostInitProperties()
|
|
{
|
|
UObject::PostInitProperties();
|
|
|
|
if (!HasAnyFlags(RF_ClassDefaultObject))
|
|
{
|
|
SmartObjectTestingActor = GetTypedOuter<ASmartObjectTestingActor>();
|
|
checkf(SmartObjectTestingActor, TEXT("SmartObjectTest are expected to be used only in ASmartObjectTestingActor"));
|
|
}
|
|
}
|
|
|
|
bool USmartObjectTest::RunTest()
|
|
{
|
|
if (SmartObjectTestingActor != nullptr && SmartObjectTestingActor->GetSubsystem() != nullptr)
|
|
{
|
|
return Run(*SmartObjectTestingActor);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool USmartObjectTest::ResetTest()
|
|
{
|
|
if (SmartObjectTestingActor != nullptr && SmartObjectTestingActor->GetSubsystem() != nullptr)
|
|
{
|
|
return Reset(*SmartObjectTestingActor);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
FBox USmartObjectTest::CalcTestBounds() const
|
|
{
|
|
if (SmartObjectTestingActor != nullptr && SmartObjectTestingActor->GetSubsystem() != nullptr)
|
|
{
|
|
return CalcBounds(*SmartObjectTestingActor);
|
|
}
|
|
return FBox(ForceInit);
|
|
}
|
|
|
|
#if UE_ENABLE_DEBUG_DRAWING
|
|
void USmartObjectTest::DebugDraw(FDebugRenderSceneProxy* DebugProxy) const
|
|
{
|
|
if (SmartObjectTestingActor != nullptr && SmartObjectTestingActor->GetSubsystem() != nullptr)
|
|
{
|
|
DebugDraw(*SmartObjectTestingActor, DebugProxy);
|
|
}
|
|
}
|
|
|
|
void USmartObjectTest::DebugDrawCanvas(UCanvas* Canvas, APlayerController* PlayerController) const
|
|
{
|
|
if (SmartObjectTestingActor != nullptr && SmartObjectTestingActor->GetSubsystem() != nullptr)
|
|
{
|
|
DebugDrawCanvas(*SmartObjectTestingActor, Canvas, PlayerController);
|
|
}
|
|
}
|
|
#endif // UE_ENABLE_DEBUG_DRAWING
|
|
|
|
|
|
//----------------------------------------------------------------------//
|
|
// USmartObjectSimpleQueryTest
|
|
//----------------------------------------------------------------------//
|
|
bool USmartObjectSimpleQueryTest::Run(ASmartObjectTestingActor& TestingActor)
|
|
{
|
|
FSmartObjectRequest RequestWithTransformedBox = Request;
|
|
RequestWithTransformedBox.QueryBox = Request.QueryBox.ShiftBy(TestingActor.GetActorLocation());
|
|
|
|
TArray<FSmartObjectRequestResult> NewResults;
|
|
TestingActor.GetSubsystemRef().FindSmartObjects(RequestWithTransformedBox, NewResults);
|
|
|
|
// Request redraw only when results differ from previous run
|
|
bool bResultsChanged = false;
|
|
if (NewResults.Num() != Results.Num())
|
|
{
|
|
bResultsChanged = true;
|
|
}
|
|
else
|
|
{
|
|
for (int32 i = 0; i < NewResults.Num(); ++i)
|
|
{
|
|
if (NewResults[i] != Results[i])
|
|
{
|
|
bResultsChanged = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
Results = MoveTemp(NewResults);
|
|
return bResultsChanged;
|
|
}
|
|
|
|
bool USmartObjectSimpleQueryTest::Reset(ASmartObjectTestingActor& TestingActor)
|
|
{
|
|
const bool bResultsChanged = Results.Num() > 0;
|
|
Results.Reset();
|
|
return bResultsChanged;
|
|
}
|
|
|
|
FBox USmartObjectSimpleQueryTest::CalcBounds(ASmartObjectTestingActor& TestingActor) const
|
|
{
|
|
FBox BoundingBox(EForceInit::ForceInitToZero);
|
|
BoundingBox += Request.QueryBox.ShiftBy(TestingActor.GetActorLocation());
|
|
|
|
for (const FSmartObjectRequestResult& Result : Results)
|
|
{
|
|
if (Result.IsValid())
|
|
{
|
|
TOptional<FVector> Location = TestingActor.GetSubsystemRef().GetSlotLocation(Result);
|
|
BoundingBox += Location.GetValue();
|
|
}
|
|
}
|
|
|
|
return BoundingBox;
|
|
}
|
|
|
|
#if UE_ENABLE_DEBUG_DRAWING
|
|
void USmartObjectSimpleQueryTest::DebugDraw(ASmartObjectTestingActor& TestingActor, FDebugRenderSceneProxy* DebugProxy) const
|
|
{
|
|
FVector TestLocation = TestingActor.GetActorLocation();
|
|
DebugProxy->Boxes.Emplace(Request.QueryBox.ShiftBy(TestLocation), FColor::Yellow);
|
|
|
|
const FVector Extent(10.f);
|
|
for (const FSmartObjectRequestResult& Result : Results)
|
|
{
|
|
FVector Location = TestingActor.GetSubsystemRef().GetSlotLocation(Result).GetValue();
|
|
|
|
DebugProxy->Boxes.Emplace(FBox(Location - Extent, Location + Extent), FColor::Yellow);
|
|
DebugProxy->Lines.Emplace(Location, TestLocation, FColor::Orange);
|
|
}
|
|
}
|
|
#endif // UE_ENABLE_DEBUG_DRAWING
|
|
|
|
|
|
//----------------------------------------------------------------------//
|
|
// USmartObjectTestRenderingComponent
|
|
//----------------------------------------------------------------------//
|
|
USmartObjectTestRenderingComponent::USmartObjectTestRenderingComponent(const FObjectInitializer& ObjectInitialize)
|
|
: Super(ObjectInitialize)
|
|
{
|
|
#if WITH_EDITORONLY_DATA
|
|
HitProxyPriority = HPP_Wireframe;
|
|
#endif
|
|
}
|
|
|
|
FBoxSphereBounds USmartObjectTestRenderingComponent::CalcBounds(const FTransform& LocalToWorld) const
|
|
{
|
|
if (const ASmartObjectTestingActor* TestingActor = Cast<ASmartObjectTestingActor>(GetOwner()))
|
|
{
|
|
return TestingActor->CalcTestsBounds();
|
|
}
|
|
return FBox(ForceInit);
|
|
}
|
|
|
|
void USmartObjectTestRenderingComponent::OnRegister()
|
|
{
|
|
Super::OnRegister();
|
|
|
|
if (!HasAnyFlags(RF_ClassDefaultObject))
|
|
{
|
|
#if UE_ENABLE_DEBUG_DRAWING
|
|
CanvasDebugDrawDelegateHandle = UDebugDrawService::Register(TEXT("Game"), FDebugDrawDelegate::CreateUObject(this, &USmartObjectTestRenderingComponent::DebugDrawCanvas));
|
|
#endif
|
|
}
|
|
}
|
|
|
|
void USmartObjectTestRenderingComponent::OnUnregister()
|
|
{
|
|
if (!HasAnyFlags(RF_ClassDefaultObject))
|
|
{
|
|
#if UE_ENABLE_DEBUG_DRAWING
|
|
UDebugDrawService::Unregister(CanvasDebugDrawDelegateHandle);
|
|
#endif
|
|
}
|
|
|
|
Super::OnUnregister();
|
|
}
|
|
|
|
void USmartObjectTestRenderingComponent::PostInitProperties()
|
|
{
|
|
Super::PostInitProperties();
|
|
|
|
if (!HasAnyFlags(RF_ClassDefaultObject))
|
|
{
|
|
ensureMsgf(Cast<ASmartObjectTestingActor>(GetOwner()), TEXT("SmartObjectTestRenderingComponent is expected to be used only by SmartObjectTestingActor"));
|
|
}
|
|
}
|
|
|
|
#if UE_ENABLE_DEBUG_DRAWING
|
|
FDebugRenderSceneProxy* USmartObjectTestRenderingComponent::CreateDebugSceneProxy()
|
|
{
|
|
FSmartObjectTestSceneProxy* DebugProxy = new FSmartObjectTestSceneProxy(*this, FDebugRenderSceneProxy::WireMesh);
|
|
DebugDraw(DebugProxy);
|
|
return DebugProxy;
|
|
}
|
|
|
|
void USmartObjectTestRenderingComponent::DebugDraw(FDebugRenderSceneProxy* DebugProxy)
|
|
{
|
|
if (ASmartObjectTestingActor* TestingActor = Cast<ASmartObjectTestingActor>(GetOwner()))
|
|
{
|
|
TestingActor->ExecuteOnEachTest([DebugProxy](const USmartObjectTest& Test) { Test.DebugDraw(DebugProxy); });
|
|
}
|
|
}
|
|
|
|
void USmartObjectTestRenderingComponent::DebugDrawCanvas(UCanvas* Canvas, APlayerController* PlayerController)
|
|
{
|
|
if (ASmartObjectTestingActor* TestingActor = Cast<ASmartObjectTestingActor>(GetOwner()))
|
|
{
|
|
TestingActor->ExecuteOnEachTest([Canvas, PlayerController](const USmartObjectTest& Test) { Test.DebugDrawCanvas(Canvas, PlayerController); });
|
|
}
|
|
}
|
|
#endif // UE_ENABLE_DEBUG_DRAWING
|
|
|
|
|
|
//----------------------------------------------------------------------//
|
|
// ASmartObjectTestingActor
|
|
//----------------------------------------------------------------------//
|
|
ASmartObjectTestingActor::ASmartObjectTestingActor(const FObjectInitializer& ObjectInitializer)
|
|
: Super(ObjectInitializer)
|
|
{
|
|
RenderingComponent = CreateDefaultSubobject<USmartObjectTestRenderingComponent>(TEXT("RenderingComp"));
|
|
RootComponent = RenderingComponent;
|
|
|
|
PrimaryActorTick.bCanEverTick = true;
|
|
PrimaryActorTick.bStartWithTickEnabled = true;
|
|
|
|
SetCanBeDamaged(false);
|
|
}
|
|
|
|
void ASmartObjectTestingActor::PostRegisterAllComponents()
|
|
{
|
|
Super::PostRegisterAllComponents();
|
|
|
|
SmartObjectSubsystem = UWorld::GetSubsystem<USmartObjectSubsystem>(GetWorld());
|
|
}
|
|
|
|
void ASmartObjectTestingActor::ExecuteOnEachTest(const TFunctionRef<void(USmartObjectTest&)> ExecFunc)
|
|
{
|
|
for (USmartObjectTest* Test : Tests)
|
|
{
|
|
if (Test != nullptr)
|
|
{
|
|
ExecFunc(*Test);
|
|
}
|
|
}
|
|
}
|
|
|
|
void ASmartObjectTestingActor::ExecuteOnEachTest(const TFunctionRef<void(const USmartObjectTest&)> ExecFunc) const
|
|
{
|
|
for (const USmartObjectTest* Test : Tests)
|
|
{
|
|
if (Test != nullptr)
|
|
{
|
|
ExecFunc(*Test);
|
|
}
|
|
}
|
|
}
|
|
|
|
void ASmartObjectTestingActor::RunTests()
|
|
{
|
|
bool bRedrawRequired = false;
|
|
ExecuteOnEachTest([&bRedrawRequired](USmartObjectTest& Test) { bRedrawRequired = Test.RunTest() || bRedrawRequired; });
|
|
|
|
if (bRedrawRequired)
|
|
{
|
|
RenderingComponent->MarkRenderStateDirty();
|
|
}
|
|
}
|
|
|
|
void ASmartObjectTestingActor::ResetTests()
|
|
{
|
|
bool bRedrawRequired = false;
|
|
ExecuteOnEachTest([&bRedrawRequired](USmartObjectTest& Test) { bRedrawRequired = Test.ResetTest() || bRedrawRequired; });
|
|
|
|
if (bRedrawRequired)
|
|
{
|
|
RenderingComponent->MarkRenderStateDirty();
|
|
}
|
|
}
|
|
|
|
bool ASmartObjectTestingActor::ShouldTickIfViewportsOnly() const
|
|
{
|
|
// Allow the actor to be ticked in the Editor world without a running simulation
|
|
return true;
|
|
}
|
|
|
|
void ASmartObjectTestingActor::Tick(const float DeltaTime)
|
|
{
|
|
Super::Tick(DeltaTime);
|
|
|
|
if (bRunTestsEachFrame)
|
|
{
|
|
RunTests();
|
|
}
|
|
}
|
|
|
|
FBox ASmartObjectTestingActor::CalcTestsBounds() const
|
|
{
|
|
FBox CombinedBounds(ForceInit);
|
|
ExecuteOnEachTest([&CombinedBounds](const USmartObjectTest& Test) { CombinedBounds += Test.CalcTestBounds(); });
|
|
|
|
return CombinedBounds;
|
|
}
|
|
|
|
#if WITH_EDITOR
|
|
void ASmartObjectTestingActor::PostEditMove(const bool bFinished)
|
|
{
|
|
Super::PostEditMove(bFinished);
|
|
|
|
RunTests();
|
|
|
|
// Force refresh since test results might be the same but reference position has changed
|
|
RenderingComponent->MarkRenderStateDirty();
|
|
}
|
|
|
|
void ASmartObjectTestingActor::PostEditChangeChainProperty(FPropertyChangedChainEvent& PropertyChangedEvent)
|
|
{
|
|
Super::PostEditChangeChainProperty(PropertyChangedEvent);
|
|
|
|
// Force refresh for any change since it might affect test debug draw
|
|
RenderingComponent->MarkRenderStateDirty();
|
|
}
|
|
|
|
void ASmartObjectTestingActor::DebugInitializeSubsystemRuntime()
|
|
{
|
|
#if WITH_SMARTOBJECT_DEBUG
|
|
if (SmartObjectSubsystem != nullptr)
|
|
{
|
|
SmartObjectSubsystem->DebugInitializeRuntime();
|
|
}
|
|
|
|
ResetTests();
|
|
#endif // WITH_SMARTOBJECT_DEBUG
|
|
}
|
|
|
|
void ASmartObjectTestingActor::DebugCleanupSubsystemRuntime()
|
|
{
|
|
#if WITH_SMARTOBJECT_DEBUG
|
|
if (SmartObjectSubsystem != nullptr)
|
|
{
|
|
SmartObjectSubsystem->DebugCleanupRuntime();
|
|
}
|
|
|
|
ResetTests();
|
|
#endif // WITH_SMARTOBJECT_DEBUG
|
|
}
|
|
|
|
#endif // WITH_EDITOR
|