Skip to main content

API Reference

Complete reference for public classes, interfaces, and events in ElysAwareness.

Core Components

UERPAwarenessComponent

Main perception component managing multi-channel pipeline execution.

Header: Core/ERPAwarenessComponent.h

Properties

PropertyTypeDefaultDescription
PerceptionTickIntervalfloat0.0Tick interval in seconds (0 = every frame)
DefaultSamplingRangefloat2000.0Default sampling range (cm) passed to samplers
ChannelPipelinesTArray<FERPChannelPipeline>Multi-channel pipeline configuration
bProvideViewportInfoWhenAvailableboolfalseInclude viewport size and screen reference in context
DefaultScreenReferenceNdcFVector2D(0.5, 0.5)Default screen reference (normalized 0..1)
bEvaluateOnlyForLocalControllerbooltrueOnly tick for the local player (multiplayer)
bDebugPerceptionboolfalseEnable debug logging
DebugPerceptionIntervalSecondsfloat0.0Debug log throttle interval

Methods

AActor* GetChannelCandidate(FName ChannelId) const;
bool HasChannelCandidate(FName ChannelId) const;
void GetAllChannelCandidates(TArray<FName>& OutChannelIds, TArray<AActor*>& OutCandidates) const;
bool ValidateActorForChannel(AActor* Actor, FName ChannelId) const;

Events

FERPOnChannelCandidateAcquiredSignature OnChannelCandidateAcquired; // (FName ChannelId, AActor* Candidate)
FERPOnChannelCandidateLostSignature OnChannelCandidateLost; // (FName ChannelId, AActor* Candidate)
FERPOnChannelEvaluatedSignature OnChannelEvaluated; // (FName ChannelId, TArray<FERPPipelineScoredCandidate>)

OnChannelEvaluated fires after each evaluation with ALL scored candidates (post-filter, post-scoring). Use this for minimap markers, radar, or any UI that needs the full candidate set.

Overridable Functions

void GetPerceptionAimRay(FVector& OutOrigin, FVector& OutDirection) const;
bool GetScreenReferenceNdc(FVector2D& OutScreenReferenceNdc) const;

UERPDomainComponent (Abstract)

Base class for gameplay domain components that consume perception events.

Header: Core/ERPDomainComponent.h

Properties

PropertyTypeDefaultDescription
PerceptionComponentUERPAwarenessComponent*nullptrAuto-found on owner at BeginPlay
ChannelIdFNameNonePerception channel to listen to

Methods

AActor* GetCurrentCandidate() const;
bool HasCandidate() const;
void SetCandidate(AActor* Candidate);
void ClearCandidate();

Events

FERPOnDomainCandidateChangedSignature OnDomainCandidateChanged; // (AActor* Previous, AActor* New, FName ChannelId)

Virtual Hooks (BlueprintNativeEvent)

bool IsCandidateEligible(AActor* Candidate) const;           // Default: true
void HandleCandidateUpdated(AActor* Previous, AActor* Current); // Default: no-op

UERPInteractionComponent

Interaction domain extending UERPDomainComponent. Adds multi-action descriptor support, challenge lifecycle management, wheel mode, and RPC networking.

When the candidate changes, the component automatically looks for UERPInteractableComponent on the candidate actor. If found, it calls SetInteractionFocused and UpdateInteractionDescriptor. If not found, use OnDescriptorChanged / OnDomainCandidateChanged to drive your own UI.

Header: Domains/Interaction/ERPInteractionComponent.h

Properties

PropertyTypeDefaultDescription
RulesTArray<UERPInteractionRule*>Instanced validation rules
MaxInteractionDistancefloat500.0Server-side distance validation (cm)

Methods

// State
void GetCurrentDescriptor(FERPInteractionDescriptor& OutDescriptor) const;
bool HasDescriptor() const;
void ForceRefreshDescriptor(); // Re-pull from current candidate; broadcasts if changed

// Interaction attempt (call from input bindings)
void StartInteractionAttempt(const UInputAction* TriggeredAction = nullptr);
void StopInteractionAttempt(const UInputAction* TriggeredAction = nullptr);
void ResetInteractionAttempt(); // Forcibly cancel; use on stun/death

// Wheel API (call from wheel widget)
void SubmitWheelSelection(const UInputAction* SelectedAction);
void CancelWheelSelection();

// Cooldown queries
bool IsActionOnCooldown(const UInputAction* InputAction) const;
// Returns true if the specified action is currently on cooldown.

float GetActionCooldownRemaining(const UInputAction* InputAction) const;
// Returns remaining cooldown time in seconds (0 if not on cooldown).

StartInteractionAttempt(IA) dispatches based on the descriptor:

  • Wheel mode (Actions.Num() > 1, Wheel): fires OnWheelRequested(Actions), ignores TriggeredAction
  • Simple press (no Challenge): executes immediately
  • Challenge present: starts the challenge (DuplicateObject per attempt)

Passing null uses the primary action (Actions[0]).

Events

FERPOnInteractionDescriptorChangedSignature OnDescriptorChanged;
// (AActor* Candidate, const FERPInteractionDescriptor& Descriptor, FName ChannelId)

FERPOnInteractionExecutedSignature OnInteractionExecuted;
// (AActor* InteractableActor)

FERPOnInteractionFailedSignature OnInteractionFailed;
// (AActor* InteractableActor, const FString& Reason)

FERPOnInteractionProgressSignature OnInteractionProgress;
// (const UInputAction* Action, float Progress)
// Action identifies which action's challenge is progressing. Progress is 0..1.

FERPOnWheelRequestedSignature OnWheelRequested;
// (const TArray<FERPInteractionAction>& Actions)
// Fired when wheel mode is triggered. Bind in your HUD to open the wheel widget.

FERPOnWheelDismissedSignature OnWheelDismissed;
// (bool bCancelled)
// Fired when the wheel closes (via SubmitWheelSelection or CancelWheelSelection).

ForceRefreshDescriptor

Call when an interactable changes its descriptor while remaining the active candidate (e.g., a door goes from "Open" to "Locked"). Perception only fires events on candidate transitions — it does not detect data changes on the same actor.

ForceRefreshDescriptor() re-pulls GetInteractionDescriptor from the current candidate and, if the descriptor changed:

  • Broadcasts OnDescriptorChanged
  • Notifies UERPInteractableComponent on the candidate (if present)

RPCs (internal)

Server_RequestInteraction(AActor*, int32 ActionIndex)  // Server RPC with validation
Client_OnInteractionSuccess(AActor*) // Client notification
Client_OnInteractionFailed(AActor*, const FString&) // Client notification

ActionIndex is resolved client-side from UInputAction* before the RPC, avoiding UObject pointer serialization across the network.


UERPTargetingComponent

Targeting domain extending UERPDomainComponent.

Header: Domains/Targeting/ERPTargetingComponent.h

Properties

PropertyTypeDefaultDescription
RulesTArray<UERPTargetRule*>Instanced validation rules

Methods

const FERPTargetDescriptor& GetCurrentDescriptor() const;

Events

FERPOnTargetDescriptorChangedSignature OnDescriptorChanged; // (AActor*, const FERPTargetDescriptor&, FName ChannelId)

UERPChannelListenerComponent

Lightweight single-channel event mirror. No domain logic.

Header: Core/ERPChannelListenerComponent.h

Methods

AActor* GetCurrentCandidate() const;
bool HasCandidate() const;
void SetPerceptionComponent(UERPAwarenessComponent* InPerceptionComponent);
void SetChannelId(FName InChannelId);

Events

FERPOnCandidateAcquiredSignature OnCandidateAcquired; // (AActor*)
FERPOnCandidateLostSignature OnCandidateLost; // (AActor*)

UERPInteractableComponent

All-in-one interactable component: implements IERPInteractable + manages visual feedback (outline + widget).

Header: Domains/Interaction/ERPInteractableComponent.h

Properties — Descriptor

PropertyTypeDescription
DefaultDescriptorFERPInteractionDescriptorUsed when BuildDescriptor is not bound
CanInteractCheckFERPCanInteractCheckDelegateRuntime override for CanBeInteractedWith
BuildDescriptorFERPBuildDescriptorDelegateRuntime override for descriptor

Properties — Widget Classes

PropertyTypeDescription
SingleActionWidgetClassTSubclassOf<UERPInteractionWidgetBase>1 action
MultiActionWidgetClassTSubclassOf<UERPInteractionWidgetBase>2+ actions, DirectKeys
WheelWidgetClassTSubclassOf<UERPInteractionWidgetBase>2+ actions, Wheel
AmbientWidgetClassTSubclassOf<UERPInteractionWidgetBase>Always-on world marker (optional)
WidgetClassOverrideTSubclassOf<UERPInteractionWidgetBase>Overrides all of the above

Properties — Placement

PropertyTypeDefaultDescription
WidgetOffsetFVector(0,0,0)Offset from attachment point
WidgetAnchorTagFNameERP_WidgetAnchorComponent tag for custom anchor
WidgetSpaceEWidgetSpaceScreenScreen or World space

Properties — Feedback

PropertyTypeDefaultDescription
bEnableCustomDepthFeedbackbooltrueOutline on focus
CustomDepthStencilValueint321Stencil value

Events

FERPOnInteractedSignature OnInteracted; // (AActor* InteractingActor, int32 ActionIndex)

Methods (Feedback API — called by ERPInteractionComponent)

void SetInteractionFocused(APlayerController* PC, bool bFocused);
void UpdateInteractionDescriptor(APlayerController* PC, const FERPInteractionDescriptor& Descriptor);
void UpdateInteractionProgress(APlayerController* PC, const UInputAction* Action, float Progress);
bool IsInteractionFocused() const;
void ApplyDefaultCustomDepthFeedback(bool bEnable);
UWidgetComponent* GetInteractionWidgetComponent() const;
UWidgetComponent* GetAmbientWidgetComponent() const;

Blueprint NativeEvents

void OnInteractionFocused(APlayerController* PC, bool bFocused);
void OnDescriptorUpdated(APlayerController* PC, const FERPInteractionDescriptor& Descriptor);
void OnInteractionProgress(APlayerController* PC, const UInputAction* Action, float Progress);

UERPCandidateRegistrySubsystem

World-level registry for declarative candidate registration (non-spatial perception).

Header: Core/ERPCandidateRegistrySubsystem.h

Methods

void RegisterActor(FName ChannelId, AActor* Actor);
void UnregisterActor(FName ChannelId, AActor* Actor);
void UnregisterFromAll(AActor* Actor);
TArray<AActor*> GetRegisteredActors(FName ChannelId);
bool HasRegisteredActors(FName ChannelId) const;
bool IsActorRegistered(FName ChannelId, AActor* Actor) const;

Events

FERPOnActorRegisteredSignature OnActorRegistered;     // (FName ChannelId, AActor* Actor)
FERPOnActorUnregisteredSignature OnActorUnregistered; // (FName ChannelId, AActor* Actor)

UERPRegistrationComponent

Auto-registers the owning actor in the candidate registry on BeginPlay/EndPlay.

Header: Core/ERPRegistrationComponent.h

Properties

PropertyTypeDefaultDescription
ChannelIdsTArray<FName>Channels to register for

Methods

void RegisterChannel(FName ChannelId);
void UnregisterChannel(FName ChannelId);

Widget Base Classes

UERPInteractionWidgetBase (Abstract)

Base widget for all interaction prompt types: single action, multi-action list, and wheel.

Header: UI/Interaction/ERPInteractionWidgetBase.h

Methods

void UpdateFromDescriptor(const FERPInteractionDescriptor& Descriptor);
// Caches descriptor, calls OnDescriptorUpdated and OnActionsUpdated.

void SetFocused(bool bNewFocused);
// Calls OnFocusChanged.

void OnActionProgressChanged(const UInputAction* Action, float Progress);
// Forwards to OnActionProgress. Called by UERPInteractableComponent.

const FERPInteractionDescriptor& GetDescriptor() const;
bool IsFocused() const;

FText GetInputActionDisplayKey(const UInputAction* InputAction) const;
// Returns the bound key text from Enhanced Input (e.g. "E"). Returns "?" if not found.

FText GetPrimaryActionDisplayKey() const;
// Shortcut: key for Actions[0].InputAction. Returns "?" if no primary action.

Blueprint NativeEvents

void OnDescriptorUpdated(const FERPInteractionDescriptor& Descriptor);
// Default: no-op. Override to refresh ObjectName, ObjectDescription, ObjectIcon.

void OnActionsUpdated(const TArray<FERPInteractionAction>& Actions);
// Default: no-op. Override to build action rows (multi-action) or wheel slices.

void OnActionProgress(const UInputAction* Action, float Progress);
// Default: no-op. Override to route progress to the matching challenge sub-widget.
// Action identifies which action is progressing. Progress is 0..1.

void OnFocusChanged(bool bNewFocused);
// Default: toggles visibility (HitTestInvisible / Collapsed).

UERPChallengeWidgetBase (Abstract)

Base widget for challenge progress display (hold ring, press counter, timing bar).

Intended to be embedded inside an interaction prompt widget as a sub-widget per action row. The parent widget calls SetChallengeProgress(Progress) in its OnActionProgress override.

Header: UI/Interaction/ERPChallengeWidgetBase.h

Methods

void SetChallengeProgress(float InProgress);    // 0..1
void NotifyChallengeComplete(bool bSuccess);
void ResetChallenge();
float GetChallengeProgress() const;

Blueprint NativeEvents

void OnChallengeProgressChanged(float Progress); // Default: no-op
void OnChallengeCompleted(bool bSuccess); // Default: no-op
void OnChallengeReset(); // Default: no-op

UERPTargetingWidgetBase (Abstract)

Base widget for targeting UI (reticles, lock-on indicators, info panels).

Header: UI/Targeting/ERPTargetingWidgetBase.h

Methods

void UpdateFromDescriptor(const FERPTargetDescriptor& Descriptor);
void SetTargetActive(bool bActive);
void SetTargetActor(AActor* Actor);
const FERPTargetDescriptor& GetDescriptor() const;
bool IsTargetActive() const;
AActor* GetTargetActor() const;

Blueprint NativeEvents

void OnDescriptorUpdated(const FERPTargetDescriptor& Descriptor);
void OnTargetActiveChanged(bool bActive); // Default: toggle visibility
void OnTargetActorChanged(AActor* NewTargetActor);

Concrete Interaction Widgets

ClassHeaderParentDescription
UERPBaseMultiPressChallengeWidgetUI/Interaction/ERPBaseMultiPressChallengeWidget.hUERPChallengeWidgetBase"Mash [E]" press counter with progress bar
UERPBaseRadialHoldWidgetUI/Interaction/ERPBaseRadialHoldWidget.hUERPChallengeWidgetBaseCircular fill hold challenge (MID-driven)
UERPBaseWorldInteractionWidgetUI/Interaction/ERPBaseWorldInteractionWidget.hUERPInteractionWidgetBaseWorld-space prompt for interactable actors
UERPBaseTimedPressChallengeWidgetUI/Interaction/ERPBaseTimedPressChallengeWidget.hUERPChallengeWidgetBaseCountdown bar + key prompt (QTE timed press)
UERPBaseTimingChallengeWidgetUI/Interaction/ERPBaseTimingChallengeWidget.hUERPChallengeWidgetBaseTrack with moving cursor + target zone (QTE timing)

Concrete Targeting Widgets

ClassHeaderParentDescription
UERPBaseTargetFrameWidgetUI/Targeting/ERPBaseTargetFrameWidget.hUERPTargetingWidgetBaseHUD nameplate (name + icon + tag coloring)
UERPBaseTargetHealthBarWidgetUI/Targeting/ERPBaseTargetHealthBarWidget.hUERPBaseTargetFrameWidgetNameplate + health bar
UERPBaseTargetReticleWidgetUI/Targeting/ERPBaseTargetReticleWidget.hUERPTargetingWidgetBaseWorld-space lock-on reticle

See Built-in Widgets for full style property tables and layout details.


Interfaces

IERPInteractable

Header: Domains/Interaction/ERPInteractable.h

// Is this object currently interactable? Called frequently — keep it lightweight.
bool CanBeInteractedWith(AActor* InteractingActor) const;

// Fill the descriptor with all available actions, object identity, and mode.
void GetInteractionDescriptor(FERPInteractionDescriptor& OutDescriptor) const;

// Execute action at the given index. Called on the SERVER.
// ActionIndex is the index into Descriptor.Actions. Pass INDEX_NONE or 0 for primary.
// Return true on success, false on failure.
bool ExecuteInteraction(AActor* InstigatorActor, int32 ActionIndex);

IERPTargetable

Header: Domains/Targeting/ERPTargetable.h

bool CanBeTargetedBy(AActor* TargetingActor) const;
UERPTargetDescriptor* GetTargetDescriptor() const;

Challenges

UERPInteractionChallenge (Abstract)

Base class for interaction challenges. Subclass to create custom challenge types.

Header: Domains/Interaction/Challenges/ERPInteractionChallenge.h

Challenges are instanced on FERPInteractionAction.Challenge. The interaction component creates a DuplicateObject per attempt to avoid shared mutable state across concurrent players.

Properties

UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Challenge")
TSubclassOf<UERPChallengeWidgetBase> WidgetClass;
// Optional: widget class for displaying this challenge's progress.

Methods (BlueprintNativeEvent)

void StartChallenge();     // Called when the attempt begins
void OnInputPressed(); // Called when the action input is pressed
void OnInputReleased(); // Called when the action input is released
void TickChallenge(float DeltaTime); // Called each frame during an active challenge
void Reset(); // Called to reset state for a new attempt

Events

FERPOnChallengeProgressSignature OnProgress; // (float Progress) — 0..1
FERPOnChallengeCompleteSignature OnComplete; // (bool bSuccess)

UERPHoldChallenge

Hold the action key for a fixed duration.

Header: Domains/Interaction/Challenges/ERPHoldChallenge.h

Properties

PropertyTypeDefaultDescription
HoldDurationfloat1.5Hold time in seconds

Behavior:

  • StartChallenge: begins accumulating time
  • OnInputReleased: resets accumulated time, fires OnProgress(0)
  • TickChallenge: advances progress; fires OnComplete(true) when duration reached

UERPMultiPressChallenge

Press the action key N times.

Header: Domains/Interaction/Challenges/ERPMultiPressChallenge.h

Properties

PropertyTypeDefaultDescription
RequiredPressesint325Number of presses to complete
PressCooldownfloat0.0Minimum time between valid presses (seconds) — useful for animation sync
DecayPerSecondfloat0.0Progress lost per second when not pressing — creates mash decay pressure

Behavior:

  • OnInputPressed: increments press count (if cooldown elapsed), fires OnProgress; fires OnComplete(true) when count reached
  • TickChallenge: applies DecayPerSecond (reduces progress toward 0 if not pressing)

UERPTimedPressChallenge

Press the action key before a countdown expires.

Header: Domains/Interaction/Challenges/ERPTimedPressChallenge.h

Properties

PropertyTypeDefaultDescription
TimeWindowfloat3.0Seconds before the challenge fails

Behavior:

  • StartChallenge: begins countdown timer
  • OnInputPressed: if timer hasn't expired, fires OnComplete(true)
  • TickChallenge: advances timer; fires OnProgress with value counting down from 1 to 0; fires OnComplete(false) on timeout

UERPSequenceChallenge

Press a series of input actions in the correct order.

Header: Domains/Interaction/Challenges/ERPSequenceChallenge.h

Properties

PropertyTypeDefaultDescription
SequenceTArray<UInputAction*>Ordered list of input actions to press
bFailOnWrongKeybooltrueFail immediately on wrong key press
TimeLimitfloat0.0Max seconds to complete the sequence (0 = no limit)

Methods

int32 GetCurrentKeyIndex() const;
// Returns the index of the next key the player must press (0-based).

const UInputAction* GetNextExpectedAction() const;
// Returns the UInputAction the player must press next, or null if complete.

Behavior:

  • OnInputPressed: checks if the pressed action matches Sequence[CurrentIndex]; advances on match, fails on mismatch if bFailOnWrongKey
  • TickChallenge: checks TimeLimit (if > 0); fires OnComplete(false) on timeout
  • Progress = completed keys / total keys

UERPTimingChallenge

Press when a moving cursor lands inside a target zone on a track.

Header: Domains/Interaction/Challenges/ERPTimingChallenge.h

Properties

PropertyTypeDefaultDescription
CursorSpeedfloat1.0Cursor oscillation speed (cycles per second)
TargetCenterfloat0.5Center of the target zone (0..1)
TargetHalfWidthfloat0.1Half-width of the target zone
bFailOnMissboolfalseFail immediately if the player presses outside the zone
RequiredHitsint321Successful hits needed to complete

Methods

float GetCursorPosition() const;
// Returns the current cursor position on the track (0..1).

bool IsCursorInTargetZone() const;
// Returns true if the cursor is currently within the target zone.

Behavior:

  • TickChallenge: oscillates cursor position between 0 and 1
  • OnInputPressed: checks if cursor is in target zone; increments hit count on success, fails on miss if bFailOnMiss
  • Progress = current hits / required hits
  • Fires OnComplete(true) when RequiredHits reached

Pipeline Base Classes

UERPSamplerBase

void Sample(const FERPAwarenessContext& Context, float Range, TArray<AActor*>& OutCandidates) const;

UERPFilterBase

bool Passes(const FERPAwarenessContext& Context, AActor* Candidate) const;

UERPScorerBase

float Score(const FERPAwarenessContext& Context, AActor* Candidate) const;

EERPResolverPolicy (Enum)

enum class EERPResolverPolicy : uint8
{
LowestScore, // Lowest aggregated score wins (default)
HighestScore, // Highest aggregated score wins
};

Data Structures

FERPInteractionDescriptor

Pure runtime data contract for an interactable and its available actions.

Header: Domains/Interaction/ERPInteractionDescriptor.h

struct FERPInteractionDescriptor
{
// Object identity
FText ObjectName; // "Wooden Door", "Iron Chest"
FText ObjectDescription; // Shown in rich tooltips / wheel center
TSoftObjectPtr<UTexture2D> ObjectIcon; // Resolve soft ref in widget when needed

// Actions
TArray<FERPInteractionAction> Actions; // [0] = primary action
EERPMultiActionMode MultiActionMode; // DirectKeys or Wheel

// Metadata
FGameplayTagContainer InteractionTags;

// Helpers
bool IsValid() const; // Actions.Num() > 0
const FERPInteractionAction* GetPrimaryAction() const; // Actions[0] or null
const FERPInteractionAction* FindAction(const UInputAction* IA) const;
int32 FindActionIndex(const UInputAction* IA) const;
bool operator==(const FERPInteractionDescriptor& Other) const;
};

FERPInteractionAction

One interaction action within a descriptor.

Header: Domains/Interaction/ERPInteractionAction.h

struct FERPInteractionAction
{
FText ActionName; // "Open", "Inspect", "Loot"
FText ActionDescription; // Tooltip for this action
TSoftObjectPtr<UTexture2D> ActionIcon; // Per-action icon

TObjectPtr<const UInputAction> InputAction; // Key binding reference; also used as identifier
// In DirectKeys mode: player presses this key to trigger this action.
// In Wheel mode: used as identifier; SubmitWheelSelection(InputAction) dispatches to this action.
// In Server RPC: resolved to ActionIndex (int32) client-side before serialization.

TObjectPtr<UERPInteractionChallenge> Challenge; // Instanced (EditInlineNew).
// null = simple press (instant execution).
// Set UERPHoldChallenge, UERPMultiPressChallenge, or a custom subclass.

float Cooldown = 0.0f; // Seconds before this action can be used again (0 = no cooldown)
EERPCooldownScope CooldownScope = EERPCooldownScope::ThisAction;
// ThisAction: only this action is blocked during cooldown.
// AllActions: all actions on this interactable are blocked (widget hides).

bool IsSimplePress() const { return Challenge == nullptr; }
};

EERPMultiActionMode

enum class EERPMultiActionMode : uint8
{
DirectKeys, // Each action has its own key. Player presses the matching key.
Wheel, // A single input opens a radial wheel. Player selects with stick or mouse.
};

EERPCooldownScope

enum class EERPCooldownScope : uint8
{
ThisAction, // Only this action is disabled during cooldown. Other actions remain available.
AllActions, // All actions on this interactable are blocked. The widget hides entirely.
};

FERPAwarenessContext

struct FERPAwarenessContext
{
FName ChannelId;
AActor* ContextActor;
FVector Origin;
FVector Forward;
bool bHasAimRay;
FVector AimOrigin;
FVector AimDirection;
bool bHasViewport;
FVector2D ViewportSizePx;
bool bHasScreenReference;
FVector2D ScreenReferenceNdc; // Normalized 0..1
APlayerController* ScreenProjectionPC;
};

FERPScorerEntry

struct FERPScorerEntry
{
UERPScorerBase* Scorer;
float Weight = 1.0f;
};

FERPChannelPipeline

struct FERPChannelPipeline
{
FName ChannelId;
FName SamplerCacheId; // Optional: force cache sharing across channels
UERPSamplerBase* Sampler;
TArray<UERPFilterBase*> Filters;
TArray<FERPScorerEntry> Scorers;
EERPResolverPolicy ResolverPolicy; // LowestScore (default) or HighestScore
float StickyBias = 0.1f; // Hysteresis bias (0 = disabled)
};

Aggregation is always a built-in weighted average. There is no separate aggregator or resolver class.


Default Implementations

Samplers

  • UERPSphereOverlapSampler — Sphere overlap query (spatial, range-limited)
  • UERPBoxOverlapSampler — Box overlap query (non-uniform spatial areas)
  • UERPRegistrySampler — Registry-based query (non-spatial, declarative)

Filters

  • UERPTargetableFilter — Requires IERPTargetable
  • UERPInteractableFilter — Requires IERPInteractable
  • UERPDistanceFilter — Range-based filtering
  • UERPImplementsInterfaceFilter — Generic interface check
  • UERPConeFilter — Angle from forward direction
  • UERPLineOfSightFilter — Visibility trace
  • UERPGameplayTagFilter — Gameplay tag matching

Scorers

  • UERPDistanceScorer — Distance-based (lower = closer = better)
  • UERPConeScorer — Angle from forward direction
  • UERPDotProductScorer — Dot product scoring
  • UERPViewportEllipseScorer — Screen-space ellipse (requires bProvideViewportInfoWhenAvailable)

Validation Rules

  • UERPInteractionRule — Base for interaction validation rules
  • UERPTargetRule — Base for targeting validation rules

Instanced Interaction

UERPInstancedInteractionComponent

Player-side component that scans for nearby ISMC/HISMC instances and spawns actors to replace them. Supports two actor types: AERPInstanceProxy (full state machine + interaction) and any AActor with optional IERPInstanceStateReceiver interface.

Header: Domains/InstancedInteraction/ERPInstancedInteractionComponent.h

Properties

PropertyTypeDefaultDescription
MeshConfigTableUDataTable*nullDataTable (row type: FERPInstancedMeshConfig) defining which meshes are interactable
SwapRadiusfloat600.0Radius (cm) around the owning pawn to scan for instances
DespawnMarginfloat200.0Extra margin added to SwapRadius for despawning (prevents flickering at boundary)
ScanIntervalfloat0.2How often to scan for instances (seconds)

Events

FERPOnInstanceActorStateChanged OnInstanceActorStateChanged;
// (AActor* SpawnedActor, FGameplayTag StateTag, int32 StepIndex, const FERPInstanceKey& InstanceKey)
// Fired when an actor is spawned or changes state as an ISMC instance replacement.
// Works for both AERPInstanceProxy and generic actors.

AERPInstanceProxy

Minimal actor spawned at the world transform of an ISMC/HISMC instance to make it individually interactable. Implements IERPInstanceStateReceiver. Subclass in Blueprint to override events.

Header: Domains/InstancedInteraction/ERPInstanceProxy.h

Components

ComponentTypeDescription
MeshComponentUStaticMeshComponent*Root component. Mesh set automatically per state step
InteractableComponentUERPInteractableComponent*Handles interaction focus, widget display, and descriptor

Properties

PropertyTypeDefaultDescription
StateStepsTArray<FERPInstanceStateStep>Ordered state lifecycle. Transitions via interaction (Duration=0) or auto-timer (Duration>0)

Methods

// Initialization (called by UERPInstancedInteractionComponent)
void InitializeProxy(const FERPInstanceKey& InKey, const FTransform& InOriginalTransform, int32 InitialStepIndex);

// Accessors
const FERPInstanceKey& GetInstanceKey() const;
FGameplayTag GetCurrentStateTag() const;
int32 GetCurrentStepIndex() const;
const FTransform& GetOriginalTransform() const;
bool IsInteractable() const; // True if current step has actions
const TArray<FERPInstanceStateStep>& GetStateSteps() const;
void SetStateSteps(const TArray<FERPInstanceStateStep>& InSteps);

// State management
void AdvanceState(); // Next step in array (or loop if bLoopToFirst)
void SetStateByIndex(int32 StepIndex); // Jump to specific step
void SetStateByTag(FGameplayTag Tag); // Jump to first step matching tag

Blueprint NativeEvents

void OnProxyInitialized(const FERPInstanceKey& Key);
// Called after spawn and key assignment. Override to configure StateSteps or custom setup.

void OnInstanceInteracted(AActor* InstigatorActor, int32 ActionIndex);
// Called on interaction. Default calls AdvanceState().
// Override to give loot, play VFX, etc.

void OnStateChanged(FGameplayTag OldState, FGameplayTag NewState, int32 StepIndex);
// Called on state transition. Default calls ApplyCurrentStep() (mesh + descriptor + timer).
// Call Parent to keep default behavior.

UERPInstanceSwapSubsystem

World subsystem that tracks instanced interaction state globally. Persists instance states across World Partition stream in/out cycles and PCG regeneration with stable seeds. States are identified by GameplayTags (children of ERP.Instance).

Header: Domains/InstancedInteraction/ERPInstanceSwapSubsystem.h

Methods

// Proxy management
AERPInstanceProxy* GetProxyForInstance(const FERPInstanceKey& Key) const;
bool RegisterProxy(const FERPInstanceKey& Key, AERPInstanceProxy* Proxy);
void UnregisterProxy(const FERPInstanceKey& Key);

// ISMC restore
void StoreISMCRestoreInfo(const FERPInstanceKey& Key, UInstancedStaticMeshComponent* ISMC,
const FTransform& OriginalTransform);
void RestoreISMCInstance(const FERPInstanceKey& Key);
void SwapISMCInstance(const FERPInstanceKey& Key, UStaticMesh* SwapMesh);
void DestroyDistantStandIn(const FERPInstanceKey& Key);

// State persistence
FGameplayTag GetInstanceState(const FERPInstanceKey& Key) const;
int32 GetInstanceStateIndex(const FERPInstanceKey& Key) const;
void SetInstanceState(const FERPInstanceKey& Key, FGameplayTag StateTag, int32 StepIndex);
bool HasPersistedState(const FERPInstanceKey& Key) const;
void PurgeStaleStates(float MaxAgeSeconds);
// Removes states older than MaxAgeSeconds that have no active proxy.

IERPInstanceStateReceiver

Interface for actors that receive instance state notifications. Implement on any actor class (not just AERPInstanceProxy) to receive state callbacks from the instanced interaction system.

Header: Domains/InstancedInteraction/ERPInstanceStateReceiver.h

Methods (BlueprintNativeEvent)

void OnInstanceStateInitialized(const FERPInstanceKey& Key, FGameplayTag StateTag,
int32 StepIndex, const TArray<FERPInstanceStateStep>& StateSteps);
// Called once after spawning with the instance key and initial state.
// Use to configure the actor based on which state it is replacing.

void OnInstanceStateChanged(FGameplayTag OldState, FGameplayTag NewState, int32 NewStepIndex);
// Called when the state changes (via timer auto-transition or external call).
// Override to play transition animations, swap meshes, spawn VFX, etc.

UStaticMesh* GetDistantMeshOverride() const;
// Return the mesh to show when this actor is despawned.
// Default: null (system falls back to StateStep.DistantMesh, then StateStep.Mesh).

FERPInstanceKey

Stable key for identifying an ISMC/HISMC instance across World Partition stream in/out and PCG regeneration. Uses quantized position (cm precision) instead of instance index, because indices shift when instances are removed.

Header: Domains/InstancedInteraction/ERPInstanceTypes.h

FieldTypeDescription
OwnerPathFNameActor path of the ISMC owner (stable per WP cell)
QuantizedPosFIntVectorPosition quantized to centimeters for stable matching
FString ToString() const;
bool operator==(const FERPInstanceKey& Other) const;

FERPInstanceStateStep

One step in an instance's state lifecycle. Configure an ordered array of these to define how an instance behaves.

Header: Domains/InstancedInteraction/ERPInstanceTypes.h

FieldTypeDefaultDescription
StateFGameplayTagTag identifying this state (e.g., ERP.Instance.Normal)
MeshUStaticMesh*nullMesh on the proxy actor. Null = hidden
DistantMeshUStaticMesh*nullMesh in the ISMC when the player leaves. Null = use Mesh
DescriptorFERPInteractionDescriptorInteraction descriptor. Empty Actions array = not interactable
Durationfloat0Seconds before auto-advancing to next step. 0 = wait for interaction
bLoopToFirstboolfalseIf last step and Duration expires, loop back to step 0

FERPInstancedMeshConfig

DataTable row (inherits FTableRowBase) mapping a static mesh to its instanced interaction configuration.

Header: Domains/InstancedInteraction/ERPInstanceTypes.h

FieldTypeDescription
MeshTSoftObjectPtr<UStaticMesh>The ISMC mesh to match against
ProxyClassTSubclassOf<AActor>Actor class to spawn (AERPInstanceProxy or any actor implementing IERPInstanceStateReceiver)
StateStepsTArray<FERPInstanceStateStep>Ordered state lifecycle. Overrides proxy defaults if non-empty

See Instanced Interaction Guide for usage details and examples.


Next Steps

See Quick Reference for common patterns.

Review Customization for extension examples.

Create custom domains with Custom Domains.