Files
Brandyn / Techy fcc1b09210 init
2026-04-04 15:40:51 -05:00

240 lines
6.5 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "ToolTargetManager.h"
#include "InteractiveToolsContext.h"
#include "ToolBuilderUtil.h"
#include UE_INLINE_GENERATED_CPP_BY_NAME(ToolTargetManager)
namespace ToolTargetManagerLocals
{
// Given an array and a 1:1 array of bools, remove all entries that have the corresponding bool set to true.
// Returns number of elements removed
int32 RemoveByFlags(TArray<UObject*>& ObjectsInOut, const TArray<bool>& RemoveFlags)
{
if (!ensure(RemoveFlags.Num() == ObjectsInOut.Num()))
{
return 0;
}
int32 OutIndex = 0;
int32 InIndex = 0;
while (InIndex < ObjectsInOut.Num())
{
if (!RemoveFlags[InIndex])
{
ObjectsInOut[OutIndex] = ObjectsInOut[InIndex];
++OutIndex;
}
++InIndex;
}
ObjectsInOut.SetNum(OutIndex);
return InIndex - OutIndex;
}
}
void UToolTargetManager::Initialize()
{
bIsActive = true;
}
void UToolTargetManager::Shutdown()
{
Factories.Empty();
bIsActive = false;
}
void UToolTargetManager::AddTargetFactory(UToolTargetFactory* Factory)
{
// If this type of factory has already been added, skip it.
if (Factories.ContainsByPredicate(
[Factory](UToolTargetFactory* ExistingFactory) {
return ExistingFactory->GetClass() == Factory->GetClass();
}))
{
return;
}
Factories.Add(Factory);
}
void UToolTargetManager::RemoveTargetFactoriesByPredicate(TFunctionRef<bool(UToolTargetFactory*)> Predicate)
{
Factories.RemoveAll(Predicate);
}
UToolTargetFactory* UToolTargetManager::FindFirstFactoryByPredicate(TFunctionRef<bool(UToolTargetFactory*)> Predicate)
{
TObjectPtr<UToolTargetFactory>* Found = Factories.FindByPredicate(Predicate);
return (Found) ? Found->Get() : nullptr;
}
bool UToolTargetManager::CanBuildTarget(UObject* SourceObject, const FToolTargetTypeRequirements& TargetType) const
{
if (InputFilterFunction && !InputFilterFunction(SourceObject))
{
return false;
}
for (UToolTargetFactory* Factory : Factories)
{
if (Factory->CanBuildTarget(SourceObject, TargetType))
{
return true;
}
}
return false;
}
UToolTarget* UToolTargetManager::BuildTarget(UObject* SourceObject, const FToolTargetTypeRequirements& TargetType)
{
if (InputFilterFunction && !InputFilterFunction(SourceObject))
{
return nullptr;
}
for (UToolTargetFactory* Factory : Factories)
{
if (Factory->CanBuildTarget(SourceObject, TargetType))
{
UToolTarget* Result = Factory->BuildTarget(SourceObject, TargetType);
if (Result != nullptr)
{
return Result;
}
}
}
return nullptr;
}
int32 UToolTargetManager::CountSelectedAndTargetable(const FToolBuilderState& SceneState, const FToolTargetTypeRequirements& TargetType) const
{
return CountSelectedAndTargetableWithPredicate(SceneState, TargetType,
// We currently only ever get components out of our scene state, so it is ok to
// use the predicate that takes an actor component
[](UActorComponent& Component) { return true; });
}
void UToolTargetManager::EnumerateSelectedAndTargetableComponents(const FToolBuilderState& SceneState,
const FToolTargetTypeRequirements& TargetRequirements,
TFunctionRef<void(UActorComponent*)> ComponentFunc) const
{
// Gather input objects
TArray<UObject*> InputObjects;
InputObjects.Append(ToolBuilderUtil::FindAllComponents(SceneState, [this](UActorComponent* Component)
{
return Component && (!InputFilterFunction || InputFilterFunction(Component));
}));
TArray<bool> Used;
for (TObjectPtr<UToolTargetFactory> Factory : Factories)
{
int32 NumTargets = Factory->CanBuildTargets(InputObjects, TargetRequirements, Used);
if (NumTargets > 0)
{
for (int32 Index = 0; Index < Used.Num(); ++Index)
{
if (Used[Index] && ensure(InputObjects.IsValidIndex(Index)))
{
ComponentFunc(static_cast<UActorComponent*>(InputObjects[Index]));
}
}
ensureMsgf(ToolTargetManagerLocals::RemoveByFlags(InputObjects, Used) > 0,
TEXT("Factory claimed it could build target(s) without using any objects."));
if (InputObjects.IsEmpty())
{
break;
}
}
}
}
int32 UToolTargetManager::CountSelectedAndTargetableWithPredicate(const FToolBuilderState& SceneState,
const FToolTargetTypeRequirements& TargetRequirements,
TFunctionRef<bool(UActorComponent&)> ComponentPred) const
{
// Gather input objects
TArray<UObject*> InputObjects;
InputObjects.Append(ToolBuilderUtil::FindAllComponents(SceneState, [this, &ComponentPred](UActorComponent* Component)
{
return Component
&& (!InputFilterFunction || InputFilterFunction(Component))
&& ComponentPred(*Component);
}));
int32 Count = 0;
TArray<bool> Used;
for (TObjectPtr<UToolTargetFactory> Factory : Factories)
{
int32 NumTargets = Factory->CanBuildTargets(InputObjects, TargetRequirements, Used);
if (NumTargets > 0)
{
Count += NumTargets;
ensureMsgf(ToolTargetManagerLocals::RemoveByFlags(InputObjects, Used) > 0,
TEXT("Factory claimed it could build target(s) without using any objects."));
if (InputObjects.IsEmpty())
{
break;
}
}
}
return Count;
}
UToolTarget* UToolTargetManager::BuildFirstSelectedTargetable(const FToolBuilderState& SceneState, const FToolTargetTypeRequirements& TargetType)
{
// Gather input objects
TArray<UObject*> InputObjects;
InputObjects.Append(ToolBuilderUtil::FindAllComponents(SceneState, [this](UActorComponent* Component)
{
return Component && (!InputFilterFunction || InputFilterFunction(Component));
}));
TArray<bool> Used;
for (TObjectPtr<UToolTargetFactory> Factory : Factories)
{
int32 NumTargets = Factory->CanBuildTargets(InputObjects, TargetType, Used);
if (NumTargets > 0)
{
return Factory->BuildFirstTarget(InputObjects, TargetType, Used);
}
}
return nullptr;
}
TArray<TObjectPtr<UToolTarget>> UToolTargetManager::BuildAllSelectedTargetable(const FToolBuilderState& SceneState,
const FToolTargetTypeRequirements& TargetType)
{
TArray<TObjectPtr<UToolTarget>> TargetsOut;
// Gather input objects
TArray<UObject*> InputObjects;
InputObjects.Append(ToolBuilderUtil::FindAllComponents(SceneState, [this](UActorComponent* Component)
{
return Component && (!InputFilterFunction || InputFilterFunction(Component));
}));
TArray<bool> Used;
for (TObjectPtr<UToolTargetFactory> Factory : Factories)
{
int32 NumTargets = Factory->CanBuildTargets(InputObjects, TargetType, Used);
if (NumTargets > 0)
{
TargetsOut.Append(Factory->BuildTargets(InputObjects, TargetType, Used));
ensureMsgf(ToolTargetManagerLocals::RemoveByFlags(InputObjects, Used) > 0,
TEXT("Factory claimed it could build target(s) without using any objects."));
if (InputObjects.IsEmpty())
{
break;
}
}
}
return TargetsOut;
}