PCG [UE5.3] Adding "Get Attributes" to World Ray Hit Query

I rescind my previous statement, I figured it out. if you have experience with c++, here’s how to access values of attributes. This is a custom PCGSettings node I created based off PCGDistanceSettings:

FPCGAsync::AsyncPointProcessing(Context, SourcePointData->GetPoints(), OutputData->GetMutablePoints(),
	[OutputData, OwnerBP, GridPositionAttribute, ModifierAttribute, /*SourceShape, SourceShape,*/ &SourcePointDatas/*, MaximumDistance, ScalarAttribute, VectorAttribute, bSetDensity*/](const FPCGPoint& SourcePoint, FPCGPoint& OutPoint) {

		OutPoint = SourcePoint;

/// OutPoint is the actual point, and the MetaDataEntry is just an int64 identifier
/// GetValue() asks for PCGMetadataValueKey but that is just a typedef for int32
		FVector gridPosition = GridPositionAttribute->GetValue(OutPoint.MetadataEntry);
}
};

Header:

// Copyright Jordan Cain. All Rights Reserved.


#pragma once

#include "PCGSettings.h"
#include "Elements/PCGPointProcessingElementBase.h"
#include "PCG/PCGBuildingBlueprint.h"
#include "PCGAssignModifierTagsToPoints.generated.h"


namespace PCGAssignModifierTagsToPoints
{
	extern const FName SourceLabel;
	//extern const FName TargetLabel;
}

/**
 * Assigns the provided tag to a point whose grid position falls within the provided reqs for that tag
 */
UCLASS(BlueprintType, ClassGroup = (Procedural))
class UPCGAssignModifierTagsToPointsSettings : public UPCGSettings
{
	GENERATED_BODY()

public:
	//~Begin UPCGSettings interface
#if WITH_EDITOR
	virtual FName GetDefaultNodeName() const override { return FName(TEXT("AssignModifierTagsToPoints")); }
	virtual FText GetDefaultNodeTitle() const override { return NSLOCTEXT("PCGAssignModifierTagsToPointsSettings", "NodeTitle", "AssignModifierTagsToPoints"); }
	virtual FText GetNodeTooltipText() const override;
	virtual EPCGSettingsType GetType() const override { return EPCGSettingsType::Spatial; }
#endif

	virtual TArray<FPCGPinProperties> InputPinProperties() const override;
	virtual TArray<FPCGPinProperties> OutputPinProperties() const override;

protected:
	virtual FPCGElementPtr CreateElement() const override;
	//~End UPCGSettings interface

public:

	UPROPERTY(BlueprintReadWrite, EditAnywhere, Category = Settings, meta = (PCG_Overridable))
	/// As we cannot pass in custom structs nor arrays of structs as attribute parameter, we'll just access the bp variables directly
	TSoftObjectPtr<APCGBuildingBlueprint> OwnerBlueprint = nullptr;

};

class FPCGAssignModifierTagsElement : public FPCGPointProcessingElementBase
{
protected:
	virtual bool ExecuteInternal(FPCGContext* Context) const override;
};


#if UE_ENABLE_INCLUDE_ORDER_DEPRECATED_IN_5_2
#include "CoreMinimal.h"
#endif

CPP:

// Copyright Jordan Cain. All Rights Reserved.

#include "PCG/PCGAssignModifierTagsToPoints.h"
#include "Data/PCGSpatialData.h"
#include "Helpers/PCGAsync.h"
#include "Data/PCGPointData.h"
#include "PCGContext.h"
#include "PCGPin.h"
#include "Kismet/KismetMathLibrary.h"
#include "GlobalLog.h"

#define LOCTEXT_NAMESPACE "PCGAssignModifierTagsElement"

namespace PCGAssignModifierTagsToPoints
{
	const FName SourceLabel = TEXT("Source");
}

#if WITH_EDITOR
FText UPCGAssignModifierTagsToPointsSettings::GetNodeTooltipText() const
{
	return LOCTEXT("PCGDistanceTooltip", "Calculates and appends a signed 'GridPosition' attribute to the source data. For each of the source points, a GridPosition attribute will be calculated against origin of points.");
}
#endif // WITH_EDITOR

TArray<FPCGPinProperties> UPCGAssignModifierTagsToPointsSettings::InputPinProperties() const
{
	TArray<FPCGPinProperties> PinProperties;
	FPCGPinProperties& PinPropertySource = PinProperties.Emplace_GetRef(PCGAssignModifierTagsToPoints::SourceLabel, EPCGDataType::Point);

#if WITH_EDITOR
	PinPropertySource.Tooltip = LOCTEXT("PCGSourcePinTooltip", "For each of the source points, a grid position attribute will be calculated against origin of points.");
#endif // WITH_EDITOR

	return PinProperties;
}

TArray<FPCGPinProperties> UPCGAssignModifierTagsToPointsSettings::OutputPinProperties() const
{
	TArray<FPCGPinProperties> PinProperties;
	FPCGPinProperties& PinPropertyOutput = PinProperties.Emplace_GetRef(PCGPinConstants::DefaultOutputLabel, EPCGDataType::Point);

#if WITH_EDITOR
	PinPropertyOutput.Tooltip = LOCTEXT("PCGOutputPinTooltip", "The source points will be output with the newly added 'GridPosition' attribute.");
#endif // WITH_EDITOR

	return PinProperties;
}

FPCGElementPtr UPCGAssignModifierTagsToPointsSettings::CreateElement() const
{
	return MakeShared<FPCGAssignModifierTagsElement>();
}

bool FPCGAssignModifierTagsElement::ExecuteInternal(FPCGContext* Context) const
{
	TRACE_CPUPROFILER_EVENT_SCOPE(FPCGDistanceElement::Execute);

	const UPCGAssignModifierTagsToPointsSettings* Settings = Context->GetInputSettings<UPCGAssignModifierTagsToPointsSettings>();
	check(Settings);
	check(Settings->OwnerBlueprint);

	TSoftObjectPtr<APCGBuildingBlueprint> OwnerBP = Settings->OwnerBlueprint;
	//const FName AttributeName = Settings->AttributeName;
	//FVector WorldLocationOfOwner = Settings->WorldLocationOfOwner;
	//FRotator RotationOfOwner = Settings->RotationOfOwner;
	//float WallSize = Settings->WallSize;

	TArray<FPCGTaggedData> Sources = Context->InputData.GetInputsByPin(PCGAssignModifierTagsToPoints::SourceLabel);
	TArray<FPCGTaggedData>& Outputs = Context->OutputData.TaggedData;

	TArray<const UPCGPointData*> SourcePointDatas;
	SourcePointDatas.Reserve(Sources.Num());

	for (const FPCGTaggedData& Source : Sources)
	{
		const UPCGSpatialData* SourceData = Cast<UPCGSpatialData>(Source.Data);

		if (!SourceData)
		{
			PCGE_LOG(Error, GraphAndLog, FText::Format(LOCTEXT("SourceMustBeSpatial", "Source must be Spatial data, found '{0}'"), FText::FromString(Source.Data->GetClass()->GetName())));
			continue;
		}

		const UPCGPointData* SourcePointData = SourceData->ToPointData(Context);
		if (!SourcePointData)
		{
			PCGE_LOG(Error, GraphAndLog, FText::Format(LOCTEXT("CannotConvertToPoint", "Cannot convert target '{0}' into Point data"), FText::FromString(Source.Data->GetClass()->GetName())));
			continue;
		}

		SourcePointDatas.Add(SourcePointData);
	}

	for (const FPCGTaggedData& Source : Sources)
	{
		const UPCGSpatialData* SourceData = Cast<UPCGSpatialData>(Source.Data);

		if (!SourceData)
		{
			PCGE_LOG(Error, GraphAndLog, LOCTEXT("InvalidInputData", "Invalid input data"));
			continue;
		}

		const UPCGPointData* SourcePointData = SourceData->ToPointData(Context);
		if (!SourcePointData)
		{
			PCGE_LOG(Error, GraphAndLog, LOCTEXT("CannotConvertToPointData", "Cannot convert input Spatial data to Point data"));
			continue;
		}

		UPCGPointData* OutputData = NewObject<UPCGPointData>();
		OutputData->InitializeFromData(SourcePointData);
		Outputs.Add_GetRef(Source).Data = OutputData;
		
		const FPCGMetadataAttribute<FVector>* GridPositionAttribute = OutputData->Metadata->GetConstTypedAttribute<FVector>(FName("GridPosition"));

		FPCGMetadataAttribute<FName>* ModifierAttribute = OutputData->Metadata->FindOrCreateAttribute<FName>(FName("ModifierTag"), FName("NoModifier"));

		check(GridPositionAttribute);
		check(ModifierAttribute);

		FPCGAsync::AsyncPointProcessing(Context, SourcePointData->GetPoints(), OutputData->GetMutablePoints(),
			[OutputData, OwnerBP, GridPositionAttribute, ModifierAttribute, /*SourceShape, SourceShape,*/ &SourcePointDatas/*, MaximumDistance, ScalarAttribute, VectorAttribute, bSetDensity*/](const FPCGPoint& SourcePoint, FPCGPoint& OutPoint) {

				OutPoint = SourcePoint;
				OutPoint.MetadataEntry;

				FName modifierTag = "NoModifier";

				bool bMeetsModifierCriteria = false;

				FVector gridPosition = GridPositionAttribute->GetValue(OutPoint.MetadataEntry);

				for (FPCGModifierTagReqs& criterion : OwnerBP->modifierConditions)
				{
					bMeetsModifierCriteria = criterion.PointMeetsCriteria(gridPosition);

					if (bMeetsModifierCriteria) { break; }/// We can break at first true criterion
					/// Todo: PCG; What if a point can meet 2 criteria?
				}

				if (bMeetsModifierCriteria)
				{
					if (ModifierAttribute)
					{
						OutputData->Metadata->InitializeOnSet(OutPoint.MetadataEntry);
						ModifierAttribute->SetValue(OutPoint.MetadataEntry, modifierTag);
					}
					else
					{
						Global::LogError(LogPCG, "UPCGAssignModifierTagsToPointsSettings", "ExecuteInternal", TEXT("Modifier: %s"), ModifierAttribute ? TEXT("Is Valid.") : TEXT("Is Not Valid"));
					}
				}

				return true;
			}
		);
	}

	return true;
}

#undef LOCTEXT_NAMESPACE

2 Likes