Reorganize Blueprint categories under ASTERION namespace, move bAutoStartBehavior to PersonalityComponent, add user documentation

- Bulk rename Category/ClassGroup strings to ASTERION|PS_AI_ConvAgent|... and ASTERION|PS_AI_Behavior|... (284 occurrences, 24 files) so functions/properties/components group cleanly in Blueprint menus
- Move bAutoStartBehavior from AIController to PersonalityComponent so the same AIController class can drive multiple NPC archetypes with per-instance scripted-mode override
- Add PowerPoint user documentation for both plugins in Docs/ with generator scripts

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-17 16:30:48 +02:00
parent 15871be9e9
commit 48d1543329
40 changed files with 1723 additions and 312 deletions

View File

@@ -81,7 +81,12 @@ void APS_AI_Behavior_AIController::OnPossess(APawn* InPawn)
SetupBlackboard();
if (bAutoStartBehavior)
// Read auto-start from PersonalityComponent (defaults to true if no component)
const bool bAutoStart = PersonalityComp
? PersonalityComp->bAutoStartBehavior
: true;
if (bAutoStart)
{
StartBehavior();
}
@@ -89,7 +94,7 @@ void APS_AI_Behavior_AIController::OnPossess(APawn* InPawn)
{
// Stay in Scripted state — no BT, no services, controlled externally
SetBehaviorState(EPS_AI_Behavior_State::Scripted);
UE_LOG(LogPS_AI_Behavior, Log, TEXT("[%s] bAutoStartBehavior=false — entering Scripted state."),
UE_LOG(LogPS_AI_Behavior, Log, TEXT("[%s] bAutoStartBehavior=false (from Profile) — entering Scripted state."),
*GetName());
}
@@ -97,7 +102,7 @@ void APS_AI_Behavior_AIController::OnPossess(APawn* InPawn)
TryBindGazeComponent();
UE_LOG(LogPS_AI_Behavior, Log, TEXT("[%s] Possessed Pawn '%s' — TeamId=%d, AutoStart=%d."),
*GetName(), *InPawn->GetName(), TeamId, (int32)bAutoStartBehavior);
*GetName(), *InPawn->GetName(), TeamId, (int32)bAutoStart);
}
void APS_AI_Behavior_AIController::OnUnPossess()

View File

@@ -48,7 +48,7 @@ public:
uint8 TeamId = FGenericTeamId::NoTeam;
/** Set the team ID at runtime. */
UFUNCTION(BlueprintCallable, Category = "PS AI Behavior|Team")
UFUNCTION(BlueprintCallable, Category = "ASTERION|PS_AI_Behavior|Team")
void SetTeamId(uint8 NewTeamId);
// ─── IGenericTeamAgentInterface (inherited from AAIController) ────
@@ -59,10 +59,6 @@ public:
// ─── Configuration ──────────────────────────────────────────────────
/** If false, the Behavior Tree does NOT start on possess. Call StartBehavior() manually. */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Behavior")
bool bAutoStartBehavior = true;
/** Behavior Tree to run. If null, uses the Profile's DefaultBehaviorTree. */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Behavior")
TObjectPtr<UBehaviorTree> BehaviorTreeAsset;
@@ -78,45 +74,45 @@ public:
// ─── Gaze Configuration ────────────────────────────────────────────
/** Detection radius for proximity gaze (cm). NPC glances at nearby actors within this range. */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "PS AI Behavior|Gaze", meta = (ClampMin = "100.0", ClampMax = "1500.0"))
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "ASTERION|PS_AI_Behavior|Gaze", meta = (ClampMin = "100.0", ClampMax = "1500.0"))
float GazeProximityRadius = 400.0f;
/** Maximum duration (seconds) the NPC looks at a proximity target before releasing. */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "PS AI Behavior|Gaze", meta = (ClampMin = "0.5", ClampMax = "30.0"))
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "ASTERION|PS_AI_Behavior|Gaze", meta = (ClampMin = "0.5", ClampMax = "30.0"))
float GazeMaxDuration = 3.0f;
/** Cooldown (seconds) before re-targeting the same actor after releasing. */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "PS AI Behavior|Gaze", meta = (ClampMin = "0.0", ClampMax = "30.0"))
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "ASTERION|PS_AI_Behavior|Gaze", meta = (ClampMin = "0.0", ClampMax = "30.0"))
float GazeCooldown = 5.0f;
/** Enable/disable proximity gaze (NPC glances at nearby actors in Idle/Patrol). */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "PS AI Behavior|Gaze")
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "ASTERION|PS_AI_Behavior|Gaze")
bool bEnableProximityGaze = true;
// ─── Component Access ───────────────────────────────────────────────
UFUNCTION(BlueprintCallable, Category = "PS AI Behavior")
UFUNCTION(BlueprintCallable, Category = "ASTERION|PS_AI_Behavior")
UPS_AI_Behavior_PerceptionComponent* GetBehaviorPerception() const { return BehaviorPerception; }
UFUNCTION(BlueprintCallable, Category = "PS AI Behavior")
UFUNCTION(BlueprintCallable, Category = "ASTERION|PS_AI_Behavior")
UPS_AI_Behavior_PersonalityComponent* GetPersonalityComponent() const { return PersonalityComp; }
// ─── Blackboard Helpers ─────────────────────────────────────────────
/** Write the current behavior state to the Blackboard. */
UFUNCTION(BlueprintCallable, Category = "PS AI Behavior|Blackboard")
UFUNCTION(BlueprintCallable, Category = "ASTERION|PS_AI_Behavior|Blackboard")
void SetBehaviorState(EPS_AI_Behavior_State NewState);
/** Read the current behavior state from the Blackboard. */
UFUNCTION(BlueprintCallable, Category = "PS AI Behavior|Blackboard")
UFUNCTION(BlueprintCallable, Category = "ASTERION|PS_AI_Behavior|Blackboard")
EPS_AI_Behavior_State GetBehaviorState() const;
/** Start (or restart) the Behavior Tree. If state is Scripted, transitions to Idle. */
UFUNCTION(BlueprintCallable, Category = "PS AI Behavior")
UFUNCTION(BlueprintCallable, Category = "ASTERION|PS_AI_Behavior")
void StartBehavior();
/** Stop the Behavior Tree and enter Scripted state. NPC stays alive and perceptible. */
UFUNCTION(BlueprintCallable, Category = "PS AI Behavior")
UFUNCTION(BlueprintCallable, Category = "ASTERION|PS_AI_Behavior")
void StopBehavior();
protected:

View File

@@ -17,7 +17,7 @@ DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FOnDamageReceived, float, Damage, A
*
* Attach to the NPC Pawn alongside PersonalityComponent.
*/
UCLASS(ClassGroup = "PS AI Behavior", meta = (BlueprintSpawnableComponent, DisplayName = "PS AI Behavior - Combat"))
UCLASS(ClassGroup = "ASTERION|PS_AI_Behavior", meta = (BlueprintSpawnableComponent, DisplayName = "PS AI Behavior - Combat"))
class PS_AI_BEHAVIOR_API UPS_AI_Behavior_CombatComponent : public UActorComponent
{
GENERATED_BODY()
@@ -52,21 +52,21 @@ public:
// ─── Delegates ──────────────────────────────────────────────────────
/** Fired on ALL machines (server + clients) when an attack is executed. */
UPROPERTY(BlueprintAssignable, Category = "PS AI Behavior|Combat")
UPROPERTY(BlueprintAssignable, Category = "ASTERION|PS_AI_Behavior|Combat")
FOnAttackExecuted OnAttackExecuted;
/** Fired on server when damage is received. */
UPROPERTY(BlueprintAssignable, Category = "PS AI Behavior|Combat")
UPROPERTY(BlueprintAssignable, Category = "ASTERION|PS_AI_Behavior|Combat")
FOnDamageReceived OnDamageReceived;
// ─── API ────────────────────────────────────────────────────────────
/** Whether the NPC can currently attack (cooldown elapsed). Server-only. */
UFUNCTION(BlueprintCallable, Category = "PS AI Behavior|Combat")
UFUNCTION(BlueprintCallable, Category = "ASTERION|PS_AI_Behavior|Combat")
bool CanAttack() const;
/** Whether the target is within attack range. */
UFUNCTION(BlueprintCallable, Category = "PS AI Behavior|Combat")
UFUNCTION(BlueprintCallable, Category = "ASTERION|PS_AI_Behavior|Combat")
bool IsInAttackRange(AActor* Target) const;
/**
@@ -74,14 +74,14 @@ public:
* cooldown, and multicasts cosmetic event to all clients.
* @return True if the attack was executed.
*/
UFUNCTION(BlueprintCallable, Category = "PS AI Behavior|Combat")
UFUNCTION(BlueprintCallable, Category = "ASTERION|PS_AI_Behavior|Combat")
bool ExecuteAttack(AActor* Target);
/**
* Called when this NPC takes damage. Updates threat perception.
* Hook this into the owning Actor's OnTakeAnyDamage.
*/
UFUNCTION(BlueprintCallable, Category = "PS AI Behavior|Combat")
UFUNCTION(BlueprintCallable, Category = "ASTERION|PS_AI_Behavior|Combat")
void NotifyDamageReceived(float Damage, AActor* DamageInstigator);
// ─── Replication ────────────────────────────────────────────────────

View File

@@ -88,23 +88,23 @@ public:
// ─── API ────────────────────────────────────────────────────────────
/** Can this point be used by the given NPC type? */
UFUNCTION(BlueprintCallable, Category = "PS AI Behavior|Cover")
UFUNCTION(BlueprintCallable, Category = "ASTERION|PS_AI_Behavior|Cover")
bool IsAccessibleTo(EPS_AI_Behavior_NPCType NPCType) const;
/** Is there room for one more occupant? */
UFUNCTION(BlueprintCallable, Category = "PS AI Behavior|Cover")
UFUNCTION(BlueprintCallable, Category = "ASTERION|PS_AI_Behavior|Cover")
bool HasRoom() const;
/** Try to claim this point for an NPC. Returns true if successful. */
UFUNCTION(BlueprintCallable, Category = "PS AI Behavior|Cover")
UFUNCTION(BlueprintCallable, Category = "ASTERION|PS_AI_Behavior|Cover")
bool Claim(AActor* Occupant);
/** Release this point (NPC leaves cover). */
UFUNCTION(BlueprintCallable, Category = "PS AI Behavior|Cover")
UFUNCTION(BlueprintCallable, Category = "ASTERION|PS_AI_Behavior|Cover")
void Release(AActor* Occupant);
/** Get the facing direction (forward vector of the actor). */
UFUNCTION(BlueprintCallable, Category = "PS AI Behavior|Cover")
UFUNCTION(BlueprintCallable, Category = "ASTERION|PS_AI_Behavior|Cover")
FVector GetCoverDirection() const;
/**
@@ -113,11 +113,11 @@ public:
* @param ThreatLocation Where the threat is.
* @return Combined score 0.0 to 1.0.
*/
UFUNCTION(BlueprintCallable, Category = "PS AI Behavior|Cover")
UFUNCTION(BlueprintCallable, Category = "ASTERION|PS_AI_Behavior|Cover")
float EvaluateAgainstThreat(const FVector& ThreatLocation) const;
/** Enable/disable at runtime (e.g. barricade destroyed). */
UFUNCTION(BlueprintCallable, Category = "PS AI Behavior|Cover")
UFUNCTION(BlueprintCallable, Category = "ASTERION|PS_AI_Behavior|Cover")
void SetEnabled(bool bNewEnabled);
#if WITH_EDITOR

View File

@@ -44,11 +44,11 @@ public:
// ─── NPC Type ───────────────────────────────────────────────────────
/** Get this NPC's type (Civilian, Enemy, Protector). */
UFUNCTION(BlueprintNativeEvent, BlueprintCallable, Category = "PS AI Behavior")
UFUNCTION(BlueprintNativeEvent, BlueprintCallable, Category = "ASTERION|PS_AI_Behavior")
EPS_AI_Behavior_NPCType GetBehaviorNPCType() const;
/** Set this NPC's type. Called by gameplay logic or plugin actions. */
UFUNCTION(BlueprintNativeEvent, BlueprintCallable, Category = "PS AI Behavior")
UFUNCTION(BlueprintNativeEvent, BlueprintCallable, Category = "ASTERION|PS_AI_Behavior")
void SetBehaviorNPCType(EPS_AI_Behavior_NPCType NewType);
// ─── Hostility ──────────────────────────────────────────────────────
@@ -58,14 +58,14 @@ public:
* An infiltrated Enemy with IsHostile=false appears as Civilian to the perception system.
* When SetHostile(true) is called, the NPC reveals itself and TeamId changes.
*/
UFUNCTION(BlueprintNativeEvent, BlueprintCallable, Category = "PS AI Behavior")
UFUNCTION(BlueprintNativeEvent, BlueprintCallable, Category = "ASTERION|PS_AI_Behavior")
bool IsBehaviorHostile() const;
/**
* Set hostility state. Typically called by gameplay scripts or ConvAgent actions.
* Implementors should update their TeamId accordingly.
*/
UFUNCTION(BlueprintNativeEvent, BlueprintCallable, Category = "PS AI Behavior")
UFUNCTION(BlueprintNativeEvent, BlueprintCallable, Category = "ASTERION|PS_AI_Behavior")
void SetBehaviorHostile(bool bNewHostile);
// ─── Movement ───────────────────────────────────────────────────────
@@ -80,13 +80,13 @@ public:
*
* @param NewSpeed Desired walk speed in cm/s.
*/
UFUNCTION(BlueprintNativeEvent, BlueprintCallable, Category = "PS AI Behavior")
UFUNCTION(BlueprintNativeEvent, BlueprintCallable, Category = "ASTERION|PS_AI_Behavior")
void SetBehaviorMovementSpeed(float NewSpeed);
/**
* Get the Pawn's current movement speed (cm/s).
*/
UFUNCTION(BlueprintNativeEvent, BlueprintCallable, Category = "PS AI Behavior")
UFUNCTION(BlueprintNativeEvent, BlueprintCallable, Category = "ASTERION|PS_AI_Behavior")
float GetBehaviorMovementSpeed() const;
/**
@@ -98,7 +98,7 @@ public:
* @param NewState The new behavioral state.
* @param OldState The previous behavioral state.
*/
UFUNCTION(BlueprintNativeEvent, BlueprintCallable, Category = "PS AI Behavior")
UFUNCTION(BlueprintNativeEvent, BlueprintCallable, Category = "ASTERION|PS_AI_Behavior")
void OnBehaviorStateChanged(EPS_AI_Behavior_State NewState, EPS_AI_Behavior_State OldState);
// ─── Target Validation ──────────────────────────────────────────────
@@ -113,7 +113,7 @@ public:
* @param TargetActor The actor to validate.
* @return True if the actor can still be targeted.
*/
UFUNCTION(BlueprintNativeEvent, BlueprintCallable, Category = "PS AI Behavior")
UFUNCTION(BlueprintNativeEvent, BlueprintCallable, Category = "ASTERION|PS_AI_Behavior")
bool IsTargetActorValid(AActor* TargetActor) const;
// ─── Combat ─────────────────────────────────────────────────────────
@@ -125,21 +125,21 @@ public:
*
* @param Target The actor to attack.
*/
UFUNCTION(BlueprintNativeEvent, BlueprintCallable, Category = "PS AI Behavior")
UFUNCTION(BlueprintNativeEvent, BlueprintCallable, Category = "ASTERION|PS_AI_Behavior")
void BehaviorStartAttack(AActor* Target);
/**
* Order the Pawn to stop attacking.
* Called when the BT exits the Attack task (state changed, target lost, etc.).
*/
UFUNCTION(BlueprintNativeEvent, BlueprintCallable, Category = "PS AI Behavior")
UFUNCTION(BlueprintNativeEvent, BlueprintCallable, Category = "ASTERION|PS_AI_Behavior")
void BehaviorStopAttack();
/**
* Query whether the Pawn can currently attack the target (has ammo, weapon ready, etc.).
* If false, the BT will keep the NPC in combat stance but won't call BehaviorStartAttack.
*/
UFUNCTION(BlueprintNativeEvent, BlueprintCallable, Category = "PS AI Behavior")
UFUNCTION(BlueprintNativeEvent, BlueprintCallable, Category = "ASTERION|PS_AI_Behavior")
bool CanBehaviorAttack(AActor* Target) const;
// ─── Stance ─────────────────────────────────────────────────────────
@@ -151,7 +151,7 @@ public:
*
* @param bCrouch True = crouch, False = stand up.
*/
UFUNCTION(BlueprintNativeEvent, BlueprintCallable, Category = "PS AI Behavior")
UFUNCTION(BlueprintNativeEvent, BlueprintCallable, Category = "ASTERION|PS_AI_Behavior")
void SetBehaviorCrouch(bool bCrouch);
// ─── Combat Style ───────────────────────────────────────────────────
@@ -162,7 +162,7 @@ public:
* Melee NPCs rush the target; Ranged NPCs use cover and maintain distance.
* Default: Melee.
*/
UFUNCTION(BlueprintNativeEvent, BlueprintCallable, Category = "PS AI Behavior")
UFUNCTION(BlueprintNativeEvent, BlueprintCallable, Category = "ASTERION|PS_AI_Behavior")
EPS_AI_Behavior_CombatType GetBehaviorCombatType() const;
// ─── Actor Resolution ──────────────────────────────────────────────
@@ -177,6 +177,6 @@ public:
*
* @return The actor to use as threat source / target.
*/
UFUNCTION(BlueprintNativeEvent, BlueprintCallable, Category = "PS AI Behavior")
UFUNCTION(BlueprintNativeEvent, BlueprintCallable, Category = "ASTERION|PS_AI_Behavior")
AActor* GetBehaviorThreatActor() const;
};

View File

@@ -14,7 +14,7 @@
*
* Automatically added by PS_AI_Behavior_AIController — you don't need to add it manually.
*/
UCLASS(ClassGroup = "PS AI Behavior", meta = (DisplayName = "PS AI Behavior - Perception"))
UCLASS(ClassGroup = "ASTERION|PS_AI_Behavior", meta = (DisplayName = "PS AI Behavior - Perception"))
class PS_AI_BEHAVIOR_API UPS_AI_Behavior_PerceptionComponent : public UAIPerceptionComponent
{
GENERATED_BODY()
@@ -32,7 +32,7 @@ public:
* If empty, uses default [Protector, Player, Civilian].
* @return The most threatening actor, or nullptr if none perceived.
*/
UFUNCTION(BlueprintCallable, Category = "PS AI Behavior|Perception")
UFUNCTION(BlueprintCallable, Category = "ASTERION|PS_AI_Behavior|Perception")
AActor* GetHighestThreatActor(const TArray<EPS_AI_Behavior_TargetType>& TargetPriority);
/** Convenience overload — reads priority from the Pawn's PersonalityProfile. */
@@ -42,7 +42,7 @@ public:
* Compute an aggregate threat level from all currently perceived hostile stimuli.
* Returns 0.0 (no threat) to 1.0+ (extreme danger).
*/
UFUNCTION(BlueprintCallable, Category = "PS AI Behavior|Perception")
UFUNCTION(BlueprintCallable, Category = "ASTERION|PS_AI_Behavior|Perception")
float CalculateThreatLevel();
/**
@@ -50,7 +50,7 @@ public:
* @param OutLocation Filled with the threat location if any threat exists.
* @return True if a threat was found.
*/
UFUNCTION(BlueprintCallable, Category = "PS AI Behavior|Perception")
UFUNCTION(BlueprintCallable, Category = "ASTERION|PS_AI_Behavior|Perception")
bool GetThreatLocation(FVector& OutLocation);
/**
@@ -82,7 +82,7 @@ protected:
* Uses IsPlayerControlled() for Player, IPS_AI_Behavior interface or
* PersonalityComponent for NPC type.
*/
UFUNCTION(BlueprintCallable, Category = "PS AI Behavior|Perception")
UFUNCTION(BlueprintCallable, Category = "ASTERION|PS_AI_Behavior|Perception")
static EPS_AI_Behavior_TargetType ClassifyActor(const AActor* Actor);
private:

View File

@@ -22,7 +22,7 @@ DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FOnBehaviorStateChanged, EPS_AI_Beh
*
* Attach to the NPC Pawn/Character.
*/
UCLASS(ClassGroup = "PS AI Behavior", meta = (BlueprintSpawnableComponent, DisplayName = "PS AI Behavior - Personality"))
UCLASS(ClassGroup = "ASTERION|PS_AI_Behavior", meta = (BlueprintSpawnableComponent, DisplayName = "PS AI Behavior - Personality"))
class PS_AI_BEHAVIOR_API UPS_AI_Behavior_PersonalityComponent : public UActorComponent
{
GENERATED_BODY()
@@ -36,6 +36,14 @@ public:
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Personality")
TObjectPtr<UPS_AI_Behavior_PersonalityProfile> Profile;
/**
* If false, the Behavior Tree does NOT start on possess.
* Use this for NPCs controlled externally (conversations, cinematics).
* Call StartBehavior() on the AIController to activate manually.
*/
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Personality")
bool bAutoStartBehavior = true;
/**
* Master debug toggle for this NPC.
* When enabled, draws floating text above the NPC's head with:
@@ -73,7 +81,7 @@ public:
// ─── Delegates ──────────────────────────────────────────────────────
/** Fired when the behavioral state changes (on server AND clients via OnRep). */
UPROPERTY(BlueprintAssignable, Category = "PS AI Behavior|Personality")
UPROPERTY(BlueprintAssignable, Category = "ASTERION|PS_AI_Behavior|Personality")
FOnBehaviorStateChanged OnBehaviorStateChanged;
// ─── API ────────────────────────────────────────────────────────────
@@ -82,7 +90,7 @@ public:
* Evaluate the NPC's reaction based on current traits and perceived threat.
* Returns the recommended behavioral state. Server-only.
*/
UFUNCTION(BlueprintCallable, Category = "PS AI Behavior|Personality")
UFUNCTION(BlueprintCallable, Category = "ASTERION|PS_AI_Behavior|Personality")
EPS_AI_Behavior_State EvaluateReaction() const;
/**
@@ -90,23 +98,23 @@ public:
* Server-only: state is replicated to clients via OnRep.
* @return The new behavioral state.
*/
UFUNCTION(BlueprintCallable, Category = "PS AI Behavior|Personality")
UFUNCTION(BlueprintCallable, Category = "ASTERION|PS_AI_Behavior|Personality")
EPS_AI_Behavior_State ApplyReaction();
/** Get a runtime trait value (returns 0.5 if undefined). */
UFUNCTION(BlueprintCallable, Category = "PS AI Behavior|Personality")
UFUNCTION(BlueprintCallable, Category = "ASTERION|PS_AI_Behavior|Personality")
float GetTrait(EPS_AI_Behavior_TraitAxis Axis) const;
/** Modify a runtime trait by delta, clamped to [0, 1]. Server-only. */
UFUNCTION(BlueprintCallable, Category = "PS AI Behavior|Personality")
UFUNCTION(BlueprintCallable, Category = "ASTERION|PS_AI_Behavior|Personality")
void ModifyTrait(EPS_AI_Behavior_TraitAxis Axis, float Delta);
/** Force a specific state (e.g. from conversation agent action). Server-only. */
UFUNCTION(BlueprintCallable, Category = "PS AI Behavior|Personality")
UFUNCTION(BlueprintCallable, Category = "ASTERION|PS_AI_Behavior|Personality")
void ForceState(EPS_AI_Behavior_State NewState);
/** Get the NPC type from the interface or profile. */
UFUNCTION(BlueprintCallable, Category = "PS AI Behavior|Personality")
UFUNCTION(BlueprintCallable, Category = "ASTERION|PS_AI_Behavior|Personality")
EPS_AI_Behavior_NPCType GetNPCType() const;
/**
@@ -114,7 +122,7 @@ public:
* Driven by the Combat/Cover cycle timer based on Aggressivity vs Caution.
* Used by the IsCoverNeeded BT decorator.
*/
UFUNCTION(BlueprintCallable, Category = "PS AI Behavior|Personality")
UFUNCTION(BlueprintCallable, Category = "ASTERION|PS_AI_Behavior|Personality")
bool ShouldPreferCover() const { return bPreferCover; }
// ─── Replication ────────────────────────────────────────────────────

View File

@@ -160,11 +160,11 @@ public:
/**
* Get the score for a given trait axis. Returns 0.5 if the axis is not defined.
*/
UFUNCTION(BlueprintCallable, Category = "PS AI Behavior|Personality")
UFUNCTION(BlueprintCallable, Category = "ASTERION|PS_AI_Behavior|Personality")
float GetTrait(EPS_AI_Behavior_TraitAxis Axis) const;
/** Get the speed for a given state. Returns DefaultWalkSpeed if state not in SpeedPerState. */
UFUNCTION(BlueprintCallable, Category = "PS AI Behavior|Personality")
UFUNCTION(BlueprintCallable, Category = "ASTERION|PS_AI_Behavior|Personality")
float GetSpeedForState(EPS_AI_Behavior_State State) const;
/** UPrimaryDataAsset interface */

View File

@@ -10,7 +10,7 @@
* Project-wide settings for the PS AI Behavior plugin.
* Accessible via Project Settings -> Plugins -> PS AI Behavior.
*/
UCLASS(config = Game, defaultconfig, meta = (DisplayName = "PS AI Behavior"))
UCLASS(config = Game, defaultconfig, meta = (DisplayName = "ASTERION|PS_AI_Behavior"))
class PS_AI_BEHAVIOR_API UPS_AI_Behavior_Settings : public UDeveloperSettings
{
GENERATED_BODY()

View File

@@ -32,7 +32,7 @@ DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnSplineEndReached,
*
* Attach to the NPC Pawn. Works with or without the AI Controller.
*/
UCLASS(ClassGroup = "PS AI Behavior", meta = (BlueprintSpawnableComponent, DisplayName = "PS AI Behavior - Spline Follower"))
UCLASS(ClassGroup = "ASTERION|PS_AI_Behavior", meta = (BlueprintSpawnableComponent, DisplayName = "PS AI Behavior - Spline Follower"))
class PS_AI_BEHAVIOR_API UPS_AI_Behavior_SplineFollowerComponent : public UActorComponent
{
GENERATED_BODY()
@@ -109,15 +109,15 @@ public:
// ─── Delegates ──────────────────────────────────────────────────────
/** Fired when approaching a junction. Use to make custom spline selection. */
UPROPERTY(BlueprintAssignable, Category = "PS AI Behavior|Spline Follower")
UPROPERTY(BlueprintAssignable, Category = "ASTERION|PS_AI_Behavior|Spline Follower")
FOnApproachingJunction OnApproachingJunction;
/** Fired when the NPC switches to a different spline. */
UPROPERTY(BlueprintAssignable, Category = "PS AI Behavior|Spline Follower")
UPROPERTY(BlueprintAssignable, Category = "ASTERION|PS_AI_Behavior|Spline Follower")
FOnSplineChanged OnSplineChanged;
/** Fired when the NPC reaches the end of a spline (if bReverseAtEnd is false). */
UPROPERTY(BlueprintAssignable, Category = "PS AI Behavior|Spline Follower")
UPROPERTY(BlueprintAssignable, Category = "ASTERION|PS_AI_Behavior|Spline Follower")
FOnSplineEndReached OnSplineEndReached;
// ─── API ────────────────────────────────────────────────────────────
@@ -128,24 +128,24 @@ public:
* @param bForward Direction of travel.
* @return True if successfully started.
*/
UFUNCTION(BlueprintCallable, Category = "PS AI Behavior|Spline Follower")
UFUNCTION(BlueprintCallable, Category = "ASTERION|PS_AI_Behavior|Spline Follower")
bool StartFollowing(APS_AI_Behavior_SplinePath* Spline, bool bForward = true);
/**
* Start following the given spline from a specific distance.
*/
UFUNCTION(BlueprintCallable, Category = "PS AI Behavior|Spline Follower")
UFUNCTION(BlueprintCallable, Category = "ASTERION|PS_AI_Behavior|Spline Follower")
bool StartFollowingAtDistance(APS_AI_Behavior_SplinePath* Spline, float StartDistance, bool bForward = true);
/** Stop following the current spline. */
UFUNCTION(BlueprintCallable, Category = "PS AI Behavior|Spline Follower")
UFUNCTION(BlueprintCallable, Category = "ASTERION|PS_AI_Behavior|Spline Follower")
void StopFollowing();
/** Pause/resume without losing state. */
UFUNCTION(BlueprintCallable, Category = "PS AI Behavior|Spline Follower")
UFUNCTION(BlueprintCallable, Category = "ASTERION|PS_AI_Behavior|Spline Follower")
void PauseFollowing();
UFUNCTION(BlueprintCallable, Category = "PS AI Behavior|Spline Follower")
UFUNCTION(BlueprintCallable, Category = "ASTERION|PS_AI_Behavior|Spline Follower")
void ResumeFollowing();
/**
@@ -154,15 +154,15 @@ public:
* @param DistanceOnNew Distance along the new spline to start from.
* @param bNewForward Direction on the new spline.
*/
UFUNCTION(BlueprintCallable, Category = "PS AI Behavior|Spline Follower")
UFUNCTION(BlueprintCallable, Category = "ASTERION|PS_AI_Behavior|Spline Follower")
void SwitchToSpline(APS_AI_Behavior_SplinePath* NewSpline, float DistanceOnNew, bool bNewForward = true);
/** Get the effective walk speed (considering spline override). */
UFUNCTION(BlueprintCallable, Category = "PS AI Behavior|Spline Follower")
UFUNCTION(BlueprintCallable, Category = "ASTERION|PS_AI_Behavior|Spline Follower")
float GetEffectiveSpeed() const;
/** Get progress as a 0-1 ratio. */
UFUNCTION(BlueprintCallable, Category = "PS AI Behavior|Spline Follower")
UFUNCTION(BlueprintCallable, Category = "ASTERION|PS_AI_Behavior|Spline Follower")
float GetProgress() const;
protected:

View File

@@ -35,7 +35,7 @@ public:
* Called automatically after world initialization. Can be called again
* if splines are added/removed at runtime.
*/
UFUNCTION(BlueprintCallable, Category = "PS AI Behavior|SplineNetwork")
UFUNCTION(BlueprintCallable, Category = "ASTERION|PS_AI_Behavior|SplineNetwork")
void RebuildNetwork();
// ─── Queries ────────────────────────────────────────────────────────
@@ -49,7 +49,7 @@ public:
* @param OutDistance Distance along the spline to the closest point.
* @return True if a spline was found within MaxDistance.
*/
UFUNCTION(BlueprintCallable, Category = "PS AI Behavior|SplineNetwork")
UFUNCTION(BlueprintCallable, Category = "ASTERION|PS_AI_Behavior|SplineNetwork")
bool FindClosestSpline(const FVector& WorldLocation,
EPS_AI_Behavior_NPCType NPCType, float MaxDistance,
APS_AI_Behavior_SplinePath*& OutSpline, float& OutDistance) const;
@@ -57,7 +57,7 @@ public:
/**
* Get all splines of a given category.
*/
UFUNCTION(BlueprintCallable, Category = "PS AI Behavior|SplineNetwork")
UFUNCTION(BlueprintCallable, Category = "ASTERION|PS_AI_Behavior|SplineNetwork")
TArray<APS_AI_Behavior_SplinePath*> GetSplinesForCategory(
EPS_AI_Behavior_NPCType Category) const;
@@ -73,7 +73,7 @@ public:
* @param CautionScore Optional: NPC's caution trait (0-1). Higher = prefer quieter paths.
* @return The chosen spline (could be the same if staying is best).
*/
UFUNCTION(BlueprintCallable, Category = "PS AI Behavior|SplineNetwork")
UFUNCTION(BlueprintCallable, Category = "ASTERION|PS_AI_Behavior|SplineNetwork")
APS_AI_Behavior_SplinePath* ChooseSplineAtJunction(
APS_AI_Behavior_SplinePath* CurrentSpline, int32 JunctionIndex,
EPS_AI_Behavior_NPCType NPCType,
@@ -81,11 +81,11 @@ public:
float CautionScore = 0.5f) const;
/** Total number of splines in the network. */
UFUNCTION(BlueprintCallable, Category = "PS AI Behavior|SplineNetwork")
UFUNCTION(BlueprintCallable, Category = "ASTERION|PS_AI_Behavior|SplineNetwork")
int32 GetSplineCount() const { return AllSplines.Num(); }
/** Total number of junctions detected. */
UFUNCTION(BlueprintCallable, Category = "PS AI Behavior|SplineNetwork")
UFUNCTION(BlueprintCallable, Category = "ASTERION|PS_AI_Behavior|SplineNetwork")
int32 GetJunctionCount() const { return TotalJunctions; }
private:

View File

@@ -94,7 +94,7 @@ public:
// ─── API ────────────────────────────────────────────────────────────
/** Can the given NPC type use this spline? */
UFUNCTION(BlueprintCallable, Category = "PS AI Behavior|Spline")
UFUNCTION(BlueprintCallable, Category = "ASTERION|PS_AI_Behavior|Spline")
bool IsAccessibleTo(EPS_AI_Behavior_NPCType NPCType) const;
/**
@@ -104,7 +104,7 @@ public:
* @param OutWorldPoint World location of the closest point on the spline.
* @return Distance from WorldLocation to the closest spline point.
*/
UFUNCTION(BlueprintCallable, Category = "PS AI Behavior|Spline")
UFUNCTION(BlueprintCallable, Category = "ASTERION|PS_AI_Behavior|Spline")
float GetClosestPointOnSpline(const FVector& WorldLocation,
float& OutDistance, FVector& OutWorldPoint) const;
@@ -115,24 +115,24 @@ public:
* @param bForward Travel direction (true = increasing distance).
* @return Array of upcoming junctions.
*/
UFUNCTION(BlueprintCallable, Category = "PS AI Behavior|Spline")
UFUNCTION(BlueprintCallable, Category = "ASTERION|PS_AI_Behavior|Spline")
TArray<FPS_AI_Behavior_SplineJunction> GetUpcomingJunctions(
float CurrentDistance, float LookAheadDist, bool bForward) const;
/** Total spline length. */
UFUNCTION(BlueprintCallable, Category = "PS AI Behavior|Spline")
UFUNCTION(BlueprintCallable, Category = "ASTERION|PS_AI_Behavior|Spline")
float GetSplineLength() const;
/** Get world location at a distance along the spline. */
UFUNCTION(BlueprintCallable, Category = "PS AI Behavior|Spline")
UFUNCTION(BlueprintCallable, Category = "ASTERION|PS_AI_Behavior|Spline")
FVector GetWorldLocationAtDistance(float Distance) const;
/** Get world rotation at a distance along the spline. */
UFUNCTION(BlueprintCallable, Category = "PS AI Behavior|Spline")
UFUNCTION(BlueprintCallable, Category = "ASTERION|PS_AI_Behavior|Spline")
FRotator GetWorldRotationAtDistance(float Distance) const;
/** Get world-space tangent direction at a distance along the spline. */
UFUNCTION(BlueprintCallable, Category = "PS AI Behavior|Spline")
UFUNCTION(BlueprintCallable, Category = "ASTERION|PS_AI_Behavior|Spline")
FVector GetWorldDirectionAtDistance(float Distance) const;
#if WITH_EDITOR

View File

@@ -35,7 +35,7 @@ public:
* @param Loudness Noise loudness (default 1.0). Scales with HearingRange.
* @param MaxRange Override max hearing range (0 = use sense default).
*/
UFUNCTION(BlueprintCallable, Category = "PS AI Behavior|Perception",
UFUNCTION(BlueprintCallable, Category = "ASTERION|PS_AI_Behavior|Perception",
meta = (WorldContext = "WorldContext", DefaultToSelf = "Shooter"))
static void ReportGunfire(UObject* WorldContext, FVector Location,
AActor* Shooter, bool bIsEnemyFire = false,

View File

@@ -21,7 +21,7 @@
* Enemy (Team 2) — Protectors and Civilians react
* Protector (Team 3) — Allied with Civilians, hostile to Enemies
*/
UCLASS(ClassGroup = "PS AI Behavior", meta = (BlueprintSpawnableComponent,
UCLASS(ClassGroup = "ASTERION|PS_AI_Behavior", meta = (BlueprintSpawnableComponent,
DisplayName = "PS AI Behavior Pawn Identity"))
class PS_AI_BEHAVIOR_API UPS_AI_Behavior_TeamComponent : public UActorComponent
{
@@ -31,16 +31,16 @@ public:
UPS_AI_Behavior_TeamComponent();
/** Role of this actor in the behavior system. Determines team affiliation. */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "PS AI Behavior|Team")
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "ASTERION|PS_AI_Behavior|Team")
EPS_AI_Behavior_NPCType Role = EPS_AI_Behavior_NPCType::Civilian;
/** Faction within the same role. Same role + different faction = rivals. */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "PS AI Behavior|Team",
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "ASTERION|PS_AI_Behavior|Team",
meta = (ClampMin = "0", ClampMax = "15"))
uint8 Faction = 0;
/** Change role at runtime. */
UFUNCTION(BlueprintCallable, Category = "PS AI Behavior|Team")
UFUNCTION(BlueprintCallable, Category = "ASTERION|PS_AI_Behavior|Team")
void SetRole(EPS_AI_Behavior_NPCType NewRole) { Role = NewRole; }
/** Returns the TeamId derived from the current Role. */

View File

@@ -36,7 +36,7 @@ public:
* Obtain from https://elevenlabs.io used to authenticate WebSocket connections.
* Keep this secret; do not ship with the key hard-coded in a shipping build.
*/
UPROPERTY(Config, EditAnywhere, Category = "PS AI ConvAgent|ElevenLabs API")
UPROPERTY(Config, EditAnywhere, Category = "ASTERION|PS_AI_ConvAgent|ElevenLabs API")
FString API_Key;
/**
@@ -45,18 +45,18 @@ public:
* - US: force US servers (api.us.elevenlabs.io).
* - EU / India: Enterprise-only data residency endpoints.
*/
UPROPERTY(Config, EditAnywhere, Category = "PS AI ConvAgent|ElevenLabs API")
UPROPERTY(Config, EditAnywhere, Category = "ASTERION|PS_AI_ConvAgent|ElevenLabs API")
EPS_AI_ConvAgent_ElevenLabsRegion ServerRegion = EPS_AI_ConvAgent_ElevenLabsRegion::Global;
/**
* Override the ElevenLabs WebSocket URL entirely. Leave empty to use ServerRegion setting.
* Example: wss://custom-proxy.example.com/v1/convai/conversation?agent_id=YOUR_ID
*/
UPROPERTY(Config, EditAnywhere, AdvancedDisplay, Category = "PS AI ConvAgent|ElevenLabs API")
UPROPERTY(Config, EditAnywhere, AdvancedDisplay, Category = "ASTERION|PS_AI_ConvAgent|ElevenLabs API")
FString CustomWebSocketURL;
/** Log verbose WebSocket messages to the Output Log (useful during development). */
UPROPERTY(Config, EditAnywhere, AdvancedDisplay, Category = "PS AI ConvAgent|ElevenLabs API")
UPROPERTY(Config, EditAnywhere, AdvancedDisplay, Category = "ASTERION|PS_AI_ConvAgent|ElevenLabs API")
bool bVerboseLogging = false;
/**
@@ -65,7 +65,7 @@ public:
* Injected at conversation start via dynamic variables — changes take effect
* on the next conversation without re-syncing agents.
*/
UPROPERTY(Config, EditAnywhere, Category = "PS AI ConvAgent|Global Prompt",
UPROPERTY(Config, EditAnywhere, Category = "ASTERION|PS_AI_ConvAgent|Global Prompt",
meta = (MultiLine = "true",
ToolTip = "Context prompt shared by all agents.\nDescribe the world, era, common rules.\nChanges take effect on next conversation start (no re-sync needed)."))
FString GlobalContextPrompt;

View File

@@ -24,7 +24,7 @@ public:
* This allows per-instance override without modifying the Skeletal Mesh asset.
* @param SkelMeshComp The target Skeletal Mesh Component.
* @param AnimBPClass The AnimBlueprint class to use as post-process (nullptr to clear). */
UFUNCTION(BlueprintCallable, Category = "PS AI ConvAgent|Utilities",
UFUNCTION(BlueprintCallable, Category = "ASTERION|PS_AI_ConvAgent|Utilities",
meta = (DisplayName = "Set Post Process Anim Blueprint"))
static void SetPostProcessAnimBlueprint(USkeletalMeshComponent* SkelMeshComp,
TSubclassOf<UAnimInstance> AnimBPClass);

View File

@@ -55,7 +55,7 @@ DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FOnBodyExpressionChanged,
// 4. The component listens to conversation lifecycle + emotion events.
// 5. The AnimNode reads GetSnapshot() and blends the upper body pose.
// ─────────────────────────────────────────────────────────────────────────────
UCLASS(ClassGroup = "PS AI ConvAgent", meta = (BlueprintSpawnableComponent),
UCLASS(ClassGroup = "ASTERION|PS_AI_ConvAgent", meta = (BlueprintSpawnableComponent),
DisplayName = "PS AI ConvAgent Body Expression")
class PS_AI_CONVAGENT_API UPS_AI_ConvAgent_BodyExpressionComponent : public UActorComponent
{
@@ -68,28 +68,28 @@ public:
/** Body pose map asset containing body animation lists per emotion.
* Create a dedicated PS_AI_ConvAgent_BodyPoseMap asset in the Content Browser. */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "PS AI ConvAgent|BodyExpression",
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "ASTERION|PS_AI_ConvAgent|BodyExpression",
meta = (ToolTip = "Body Pose Map asset with animation lists per emotion.\nRight-click Content Browser > Miscellaneous > PS AI ConvAgent Body Pose Map."))
TObjectPtr<UPS_AI_ConvAgent_BodyPoseMap> BodyPoseMap;
/** Whether body expressions are currently active (read-only).
* Managed automatically: activates on conversation connect, deactivates on disconnect. */
UPROPERTY(BlueprintReadOnly, Category = "PS AI ConvAgent|BodyExpression")
UPROPERTY(BlueprintReadOnly, Category = "ASTERION|PS_AI_ConvAgent|BodyExpression")
bool bActive = false;
/** How long (seconds) to blend in/out when conversation starts/ends. */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "PS AI ConvAgent|BodyExpression",
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "ASTERION|PS_AI_ConvAgent|BodyExpression",
meta = (ClampMin = "0.05", ClampMax = "3.0"))
float ActivationBlendDuration = 0.5f;
/** Crossfade duration (seconds) when switching between animations. */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "PS AI ConvAgent|BodyExpression",
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "ASTERION|PS_AI_ConvAgent|BodyExpression",
meta = (ClampMin = "0.1", ClampMax = "3.0",
ToolTip = "How long (seconds) to crossfade between animations.\n0.5 = snappy, 1.5 = smooth."))
float EmotionBlendDuration = 1.0f;
/** Overall blend weight for body expressions. 1.0 = full, 0.5 = subtle. */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "PS AI ConvAgent|BodyExpression",
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "ASTERION|PS_AI_ConvAgent|BodyExpression",
meta = (ClampMin = "0.0", ClampMax = "1.0",
ToolTip = "Overall blend weight for body expressions.\n1.0 = full, 0.5 = subtle."))
float BlendWeight = 1.0f;
@@ -97,12 +97,12 @@ public:
// ── Debug ────────────────────────────────────────────────────────────────
/** Enable debug logging for this component. */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "PS AI ConvAgent|Debug")
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "ASTERION|PS_AI_ConvAgent|Debug")
bool bDebug = false;
/** Verbosity level when bDebug is true.
* 0 = minimal extras, 1 = normal debug, 2 = detailed, 3 = per-frame data. */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "PS AI ConvAgent|Debug",
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "ASTERION|PS_AI_ConvAgent|Debug",
meta = (ClampMin = "0", ClampMax = "3", EditCondition = "bDebug"))
int32 DebugVerbosity = 1;
@@ -117,22 +117,22 @@ public:
}
/** Get the active emotion. */
UFUNCTION(BlueprintPure, Category = "PS AI ConvAgent|BodyExpression")
UFUNCTION(BlueprintPure, Category = "ASTERION|PS_AI_ConvAgent|BodyExpression")
EPS_AI_ConvAgent_Emotion GetActiveEmotion() const { return ActiveEmotion; }
/** Get the active emotion intensity. */
UFUNCTION(BlueprintPure, Category = "PS AI ConvAgent|BodyExpression")
UFUNCTION(BlueprintPure, Category = "ASTERION|PS_AI_ConvAgent|BodyExpression")
EPS_AI_ConvAgent_EmotionIntensity GetActiveIntensity() const { return ActiveEmotionIntensity; }
/** True when the agent is currently speaking (body uses N/M/E lists). */
UFUNCTION(BlueprintPure, Category = "PS AI ConvAgent|BodyExpression")
UFUNCTION(BlueprintPure, Category = "ASTERION|PS_AI_ConvAgent|BodyExpression")
bool IsSpeaking() const { return bIsSpeaking; }
// ── Events ───────────────────────────────────────────────────────────────
/** Fired when the body expression changes (emotion + intensity).
* Only fires when the emotion actually differs from the previous one. */
UPROPERTY(BlueprintAssignable, Category = "PS AI ConvAgent|BodyExpression|Events")
UPROPERTY(BlueprintAssignable, Category = "ASTERION|PS_AI_ConvAgent|BodyExpression|Events")
FOnBodyExpressionChanged OnBodyExpressionChanged;
/** Current activation blend alpha (0 = fully inactive, 1 = fully active).

View File

@@ -91,11 +91,11 @@ struct PS_AI_CONVAGENT_API FPS_AI_ConvAgent_ConversationInfo_ElevenLabs
GENERATED_BODY()
/** Unique ID of this conversation session assigned by ElevenLabs. */
UPROPERTY(BlueprintReadOnly, Category = "PS AI ConvAgent|ElevenLabs")
UPROPERTY(BlueprintReadOnly, Category = "ASTERION|PS_AI_ConvAgent|ElevenLabs")
FString ConversationID;
/** Agent ID that is responding. */
UPROPERTY(BlueprintReadOnly, Category = "PS AI ConvAgent|ElevenLabs")
UPROPERTY(BlueprintReadOnly, Category = "ASTERION|PS_AI_ConvAgent|ElevenLabs")
FString AgentID;
};
@@ -108,15 +108,15 @@ struct PS_AI_CONVAGENT_API FPS_AI_ConvAgent_TranscriptSegment_ElevenLabs
GENERATED_BODY()
/** Transcribed text. */
UPROPERTY(BlueprintReadOnly, Category = "PS AI ConvAgent|ElevenLabs")
UPROPERTY(BlueprintReadOnly, Category = "ASTERION|PS_AI_ConvAgent|ElevenLabs")
FString Text;
/** "user" or "agent". */
UPROPERTY(BlueprintReadOnly, Category = "PS AI ConvAgent|ElevenLabs")
UPROPERTY(BlueprintReadOnly, Category = "ASTERION|PS_AI_ConvAgent|ElevenLabs")
FString Speaker;
/** Whether this is a final transcript or a tentative (in-progress) one. */
UPROPERTY(BlueprintReadOnly, Category = "PS AI ConvAgent|ElevenLabs")
UPROPERTY(BlueprintReadOnly, Category = "ASTERION|PS_AI_ConvAgent|ElevenLabs")
bool bIsFinal = false;
};
@@ -155,15 +155,15 @@ struct PS_AI_CONVAGENT_API FPS_AI_ConvAgent_ClientToolCall_ElevenLabs
GENERATED_BODY()
/** Name of the tool the agent wants to invoke (e.g. "set_emotion"). */
UPROPERTY(BlueprintReadOnly, Category = "PS AI ConvAgent|ElevenLabs")
UPROPERTY(BlueprintReadOnly, Category = "ASTERION|PS_AI_ConvAgent|ElevenLabs")
FString ToolName;
/** Unique ID for this tool invocation — must be echoed back in client_tool_result. */
UPROPERTY(BlueprintReadOnly, Category = "PS AI ConvAgent|ElevenLabs")
UPROPERTY(BlueprintReadOnly, Category = "ASTERION|PS_AI_ConvAgent|ElevenLabs")
FString ToolCallId;
/** Raw JSON parameters as key-value string pairs. */
UPROPERTY(BlueprintReadOnly, Category = "PS AI ConvAgent|ElevenLabs")
UPROPERTY(BlueprintReadOnly, Category = "ASTERION|PS_AI_ConvAgent|ElevenLabs")
TMap<FString, FString> Parameters;
};
@@ -177,11 +177,11 @@ struct PS_AI_CONVAGENT_API FPS_AI_ConvAgent_AgentAction_ElevenLabs
GENERATED_BODY()
/** Action identifier sent by the LLM (e.g. "flee", "draw_weapon"). Keep short, snake_case. */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "PS AI ConvAgent|ElevenLabs")
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "ASTERION|PS_AI_ConvAgent|ElevenLabs")
FString Name;
/** Human-readable description — helps the LLM understand when to use this action. */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "PS AI ConvAgent|ElevenLabs")
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "ASTERION|PS_AI_ConvAgent|ElevenLabs")
FString Description;
};
@@ -210,23 +210,23 @@ struct PS_AI_CONVAGENT_API FPS_AI_ConvAgent_ToolParameter_ElevenLabs
/** Parameter identifier (snake_case). Must match the name expected by the client code.
* Examples: "emotion", "intensity", "action", "target_name" */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "PS AI ConvAgent|ElevenLabs",
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "ASTERION|PS_AI_ConvAgent|ElevenLabs",
meta = (ToolTip = "Parameter name (snake_case).\nThe key sent in the tool call JSON."))
FString Name;
/** Data type for this parameter. Maps to JSON Schema "type". */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "PS AI ConvAgent|ElevenLabs",
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "ASTERION|PS_AI_ConvAgent|ElevenLabs",
meta = (ToolTip = "Data type: String, Integer, Number, or Boolean."))
EPS_AI_ConvAgent_ToolParamType Type = EPS_AI_ConvAgent_ToolParamType::String;
/** Whether this parameter is required in the tool call. */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "PS AI ConvAgent|ElevenLabs",
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "ASTERION|PS_AI_ConvAgent|ElevenLabs",
meta = (ToolTip = "If true, the LLM must provide this parameter."))
bool bRequired = true;
/** Description passed to the LLM explaining what this parameter is
* and how to extract or determine its value from the conversation. */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "PS AI ConvAgent|ElevenLabs",
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "ASTERION|PS_AI_ConvAgent|ElevenLabs",
meta = (MultiLine = "true",
ToolTip = "LLM prompt describing this parameter.\nGuides the LLM on what value to provide."))
FString Description;
@@ -234,7 +234,7 @@ struct PS_AI_CONVAGENT_API FPS_AI_ConvAgent_ToolParameter_ElevenLabs
/** Optional predefined values the LLM can choose from.
* If empty, the LLM can use any value of the specified type.
* Examples: ["joy","sadness","anger"] for emotion, ["low","medium","high"] for intensity. */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "PS AI ConvAgent|ElevenLabs",
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "ASTERION|PS_AI_ConvAgent|ElevenLabs",
meta = (ToolTip = "Predefined enum values (optional).\nIf set, the LLM must choose from these."))
TArray<FString> EnumValues;
};

View File

@@ -139,7 +139,7 @@ DECLARE_MULTICAST_DELEGATE_OneParam(FOnAgentAudioData, const TArray<uint8>& /*PC
// 4. React to events (OnAgentTranscript, OnAgentTextResponse, etc.) in Blueprint.
// 5. Call EndConversation() when done.
// ─────────────────────────────────────────────────────────────────────────────
UCLASS(ClassGroup = "PS AI ConvAgent", meta = (BlueprintSpawnableComponent),
UCLASS(ClassGroup = "ASTERION|PS_AI_ConvAgent", meta = (BlueprintSpawnableComponent),
DisplayName = "PS AI ConvAgent - ElevenLabs Conv")
class PS_AI_CONVAGENT_API UPS_AI_ConvAgent_ElevenLabsComponent : public UActorComponent
{
@@ -153,18 +153,18 @@ public:
/** Agent configuration data asset.
* When set, the AgentID is resolved from this asset at conversation start.
* Create one via Content Browser → right-click → Miscellaneous → PS AI ConvAgent Agent Config. */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "PS AI ConvAgent|ElevenLabs",
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "ASTERION|PS_AI_ConvAgent|ElevenLabs",
meta = (ToolTip = "Agent configuration data asset.\nOverrides the AgentID string below when set."))
TObjectPtr<UPS_AI_ConvAgent_AgentConfig_ElevenLabs> AgentConfig;
/** ElevenLabs Agent ID used for this conversation. Leave empty to use the default from Project Settings > PS AI ConvAgent - ElevenLabs.
* Overridden by AgentConfig if set. */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "PS AI ConvAgent|ElevenLabs",
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "ASTERION|PS_AI_ConvAgent|ElevenLabs",
meta = (ToolTip = "ElevenLabs Agent ID. Leave empty to use the project default from Project Settings.\nOverridden by AgentConfig if set."))
FString AgentID;
/** How turn-taking is managed between the user and the agent.\n- Server VAD (recommended): ElevenLabs automatically detects when the user stops speaking.\n- Client Controlled: You manually call StartListening/StopListening (push-to-talk with a key). */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "PS AI ConvAgent|ElevenLabs",
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "ASTERION|PS_AI_ConvAgent|ElevenLabs",
meta = (ToolTip = "Turn-taking mode.\n- Server VAD: ElevenLabs detects end-of-speech automatically (hands-free).\n- Client Controlled: You call StartListening/StopListening manually (push-to-talk)."))
EPS_AI_ConvAgent_TurnMode_ElevenLabs TurnMode = EPS_AI_ConvAgent_TurnMode_ElevenLabs::Server;
@@ -174,38 +174,38 @@ public:
* The agent remembers the full conversation context between interactions.
* When false (ephemeral), each StartConversation opens a fresh WebSocket session
* and EndConversation closes it. */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "PS AI ConvAgent|ElevenLabs",
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "ASTERION|PS_AI_ConvAgent|ElevenLabs",
meta = (ToolTip = "Keep the WebSocket open across conversation cycles.\n- True: agent remembers the full conversation between interactions.\n- False: each StartConversation opens a new session."))
bool bPersistentSession = true;
/** Automatically open the microphone as soon as the WebSocket connection is established. Only applies in Server VAD mode. In Client (push-to-talk) mode, you must call StartListening manually. */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "PS AI ConvAgent|ElevenLabs",
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "ASTERION|PS_AI_ConvAgent|ElevenLabs",
meta = (ToolTip = "Auto-open the microphone when the conversation starts.\nOnly applies in Server VAD mode. In push-to-talk mode, call StartListening() manually."))
bool bAutoStartListening = true;
/** How many milliseconds of microphone audio to accumulate before sending a chunk to ElevenLabs. Lower values reduce latency but may degrade voice detection accuracy. Higher values are more reliable but add delay. */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "PS AI ConvAgent|ElevenLabs|Latency",
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "ASTERION|PS_AI_ConvAgent|ElevenLabs|Latency",
meta = (ClampMin = "20", ClampMax = "500",
ToolTip = "Mic audio chunk duration sent to ElevenLabs.\n- 50-80ms: lower latency, less reliable voice detection.\n- 100ms (default): good balance.\n- 150-250ms: more reliable, higher latency."))
int32 MicChunkDurationMs = 100;
/** Allow the user to interrupt the agent while it is speaking.\n- In Server VAD mode: the microphone stays open during agent speech and the server detects interruptions automatically.\n- In Client (push-to-talk) mode: pressing the talk key while the agent speaks sends an interrupt signal.\n- When disabled: the user must wait for the agent to finish speaking before talking. */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "PS AI ConvAgent|ElevenLabs",
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "ASTERION|PS_AI_ConvAgent|ElevenLabs",
meta = (ToolTip = "Allow the user to interrupt the agent while it speaks.\n- Server VAD: mic stays open, server detects user voice automatically.\n- Push-to-talk: pressing the talk key interrupts the agent.\n- Disabled: user must wait for the agent to finish."))
bool bAllowInterruption = true;
/** Enable the OnAgentTranscript event, which provides real-time speech-to-text of what the user is saying. Disable if you don't need to display user speech to reduce processing overhead. */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "PS AI ConvAgent|ElevenLabs|Events",
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "ASTERION|PS_AI_ConvAgent|ElevenLabs|Events",
meta = (ToolTip = "Fire OnAgentTranscript with real-time speech-to-text of user speech.\nDisable if you don't need to display what the user said."))
bool bEnableUserTranscript = true;
/** Enable the OnAgentTextResponse event, which provides the agent's complete text response once fully generated. Disable if you only need the audio output. */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "PS AI ConvAgent|ElevenLabs|Events",
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "ASTERION|PS_AI_ConvAgent|ElevenLabs|Events",
meta = (ToolTip = "Fire OnAgentTextResponse with the agent's complete text once fully generated.\nDisable if you only need the audio output."))
bool bEnableAgentTextResponse = true;
/** Enable the OnAgentPartialResponse event, which streams the agent's text word-by-word as the LLM generates it. Use this for real-time subtitles that appear while the agent speaks, rather than waiting for the full response. */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "PS AI ConvAgent|ElevenLabs|Events",
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "ASTERION|PS_AI_ConvAgent|ElevenLabs|Events",
meta = (ToolTip = "Fire OnAgentPartialResponse with streaming text fragments as the LLM generates them.\nIdeal for real-time subtitles. Each event gives one text chunk, not the accumulated text."))
bool bEnableAgentPartialResponse = false;
@@ -214,7 +214,7 @@ public:
* When adaptive mode is on, the system starts here and can only decrease
* (never increase) as it measures that chunks arrive fast enough.
* Set to 0 to disable pre-buffering entirely. */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "PS AI ConvAgent|ElevenLabs|Latency",
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "ASTERION|PS_AI_ConvAgent|ElevenLabs|Latency",
meta = (ClampMin = "0", ClampMax = "4000",
ToolTip = "Pre-buffer delay (ms) — your safe 'worst case' value.\nAdaptive mode can only decrease from here, never increase.\nSet 0 to disable pre-buffering entirely."))
int32 AudioPreBufferMs = 300;
@@ -223,13 +223,13 @@ public:
* lowers the pre-buffer when TTS chunks arrive fast enough.
* The system can only decrease from AudioPreBufferMs — never increase.
* Resets to AudioPreBufferMs at the start of each conversation. */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "PS AI ConvAgent|ElevenLabs|Latency",
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "ASTERION|PS_AI_ConvAgent|ElevenLabs|Latency",
meta = (EditCondition = "AudioPreBufferMs > 0",
ToolTip = "Automatically lower pre-buffer when connection is good.\nCan only decrease, never increase beyond AudioPreBufferMs.\nResets each conversation."))
bool bAdaptivePreBuffer = true;
/** Safety timeout: if the server does not start generating a response within this many seconds after the user stops speaking, fire OnAgentResponseTimeout. Set to 0 to disable. A normal response starts within 0.1-0.8s. */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "PS AI ConvAgent|ElevenLabs",
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "ASTERION|PS_AI_ConvAgent|ElevenLabs",
meta = (ClampMin = "0.0",
ToolTip = "Seconds to wait for a server response after the user stops speaking.\nFires OnAgentResponseTimeout if exceeded. Normal latency is 0.1-0.8s.\nSet to 0 to disable. Default: 10s."))
float ResponseTimeoutSeconds = 10.0f;
@@ -237,7 +237,7 @@ public:
/** Maximum auto-reconnection attempts on unexpected WebSocket disconnect.
* Uses exponential backoff (1s, 2s, 4s, ... up to 30s).
* Set to 0 to disable auto-reconnection. */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "PS AI ConvAgent|ElevenLabs",
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "ASTERION|PS_AI_ConvAgent|ElevenLabs",
meta = (ClampMin = "0",
ToolTip = "Auto-reconnect attempts on unexpected disconnect.\n0 = disabled. Uses exponential backoff."))
int32 MaxReconnectAttempts = 5;
@@ -248,7 +248,7 @@ public:
* When set, the agent's audio playback will be spatialized in 3D — volume
* and panning change based on distance and direction from the listener.
* Leave null for non-spatialized (2D) audio (default, same as before). */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "PS AI ConvAgent|ElevenLabs|Audio",
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "ASTERION|PS_AI_ConvAgent|ElevenLabs|Audio",
meta = (ToolTip = "Sound attenuation for 3D spatialized audio.\nLeave null for non-spatialized (2D) playback."))
USoundAttenuation* SoundAttenuation = nullptr;
@@ -256,104 +256,104 @@ public:
/** Enable debug logging for this component.
* When false, only key events (init, errors, state changes) are logged. */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "PS AI ConvAgent|Debug")
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "ASTERION|PS_AI_ConvAgent|Debug")
bool bDebug = false;
/** Verbosity level when bDebug is true.
* 0 = minimal extras, 1 = normal debug, 2 = detailed, 3 = per-frame data. */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "PS AI ConvAgent|Debug",
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "ASTERION|PS_AI_ConvAgent|Debug",
meta = (ClampMin = "0", ClampMax = "3", EditCondition = "bDebug"))
int32 DebugVerbosity = 1;
/** Show a separate latency debug HUD with detailed per-turn timing breakdown.
* Independent from bDebug — can be enabled alone via CVar ps.ai.ConvAgent.Debug.Latency. */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "PS AI ConvAgent|Debug")
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "ASTERION|PS_AI_ConvAgent|Debug")
bool bDebugLatency = false;
// ── Events ────────────────────────────────────────────────────────────────
/** Fired when the WebSocket connection is established and the conversation session is ready. Provides the ConversationID and AgentID. */
UPROPERTY(BlueprintAssignable, Category = "PS AI ConvAgent|ElevenLabs|Events",
UPROPERTY(BlueprintAssignable, Category = "ASTERION|PS_AI_ConvAgent|ElevenLabs|Events",
meta = (ToolTip = "Fires when the connection to ElevenLabs is established and the conversation is ready to begin."))
FOnAgentConnected OnAgentConnected;
/** Fired when the WebSocket connection is closed (gracefully or due to an error). Provides the status code and reason. */
UPROPERTY(BlueprintAssignable, Category = "PS AI ConvAgent|ElevenLabs|Events",
UPROPERTY(BlueprintAssignable, Category = "ASTERION|PS_AI_ConvAgent|ElevenLabs|Events",
meta = (ToolTip = "Fires when the connection to ElevenLabs is closed. Check StatusCode and Reason for details."))
FOnAgentDisconnected OnAgentDisconnected;
/** Fired on any connection or protocol error. The error message describes what went wrong. */
UPROPERTY(BlueprintAssignable, Category = "PS AI ConvAgent|ElevenLabs|Events",
UPROPERTY(BlueprintAssignable, Category = "ASTERION|PS_AI_ConvAgent|ElevenLabs|Events",
meta = (ToolTip = "Fires on connection or protocol errors. The ErrorMessage describes the issue."))
FOnAgentError OnAgentError;
/** Fired with real-time speech-to-text of the user's voice. Includes both tentative (in-progress) and final transcripts. Requires bEnableUserTranscript to be true. */
UPROPERTY(BlueprintAssignable, Category = "PS AI ConvAgent|ElevenLabs|Events",
UPROPERTY(BlueprintAssignable, Category = "ASTERION|PS_AI_ConvAgent|ElevenLabs|Events",
meta = (ToolTip = "Real-time speech-to-text of the user's voice.\nIncludes tentative and final transcripts. Enable with bEnableUserTranscript."))
FOnAgentTranscript OnAgentTranscript;
/** Fired once when the agent's complete text response is available. This is the full text that corresponds to the audio the agent speaks. Requires bEnableAgentTextResponse to be true. */
UPROPERTY(BlueprintAssignable, Category = "PS AI ConvAgent|ElevenLabs|Events",
UPROPERTY(BlueprintAssignable, Category = "ASTERION|PS_AI_ConvAgent|ElevenLabs|Events",
meta = (ToolTip = "The agent's complete text response (matches the spoken audio).\nFires once when the full text is ready. Enable with bEnableAgentTextResponse."))
FOnAgentTextResponse OnAgentTextResponse;
/** Fired repeatedly as the LLM generates text, providing one word/fragment at a time. Use for real-time subtitles. Each call gives a new fragment, NOT the accumulated text. Requires bEnableAgentPartialResponse to be true. */
UPROPERTY(BlueprintAssignable, Category = "PS AI ConvAgent|ElevenLabs|Events",
UPROPERTY(BlueprintAssignable, Category = "ASTERION|PS_AI_ConvAgent|ElevenLabs|Events",
meta = (ToolTip = "Streaming text fragments as the LLM generates them (word by word).\nIdeal for real-time subtitles. Enable with bEnableAgentPartialResponse."))
FOnAgentPartialResponse OnAgentPartialResponse;
/** Fired when the agent begins playing audio (first audio chunk received). Use this to trigger speech animations or UI indicators. */
UPROPERTY(BlueprintAssignable, Category = "PS AI ConvAgent|ElevenLabs|Events",
UPROPERTY(BlueprintAssignable, Category = "ASTERION|PS_AI_ConvAgent|ElevenLabs|Events",
meta = (ToolTip = "Fires when the agent starts speaking (first audio chunk). Use for lip-sync or UI feedback."))
FOnAgentStartedSpeaking OnAgentStartedSpeaking;
/** Fired when audio playback actually starts — AFTER any pre-buffering delay.
* Unlike OnAgentStartedSpeaking (first chunk arrival), this fires when audio is audible.
* Use this for body/gesture animations that should be synced with audible speech. */
UPROPERTY(BlueprintAssignable, Category = "PS AI ConvAgent|ElevenLabs|Events",
UPROPERTY(BlueprintAssignable, Category = "ASTERION|PS_AI_ConvAgent|ElevenLabs|Events",
meta = (ToolTip = "Fires when audio playback actually starts (after pre-buffering).\nSynced with audible speech. Use for body animations."))
FOnAudioPlaybackStarted OnAudioPlaybackStarted;
/** Fired when the agent finishes playing all audio. Use this to re-open the microphone (in Server VAD mode without interruption) or update UI. */
UPROPERTY(BlueprintAssignable, Category = "PS AI ConvAgent|ElevenLabs|Events",
UPROPERTY(BlueprintAssignable, Category = "ASTERION|PS_AI_ConvAgent|ElevenLabs|Events",
meta = (ToolTip = "Fires when the agent finishes speaking. Use to re-open the mic or update UI."))
FOnAgentStoppedSpeaking OnAgentStoppedSpeaking;
/** Fired when the agent's speech is interrupted (either by the user speaking over it, or by a manual InterruptAgent call). The audio playback is automatically stopped. */
UPROPERTY(BlueprintAssignable, Category = "PS AI ConvAgent|ElevenLabs|Events",
UPROPERTY(BlueprintAssignable, Category = "ASTERION|PS_AI_ConvAgent|ElevenLabs|Events",
meta = (ToolTip = "Fires when the agent is interrupted mid-speech. Audio is automatically stopped."))
FOnAgentInterrupted OnAgentInterrupted;
/** Fired when the server starts generating a response (before any audio arrives). Use this for "thinking..." UI feedback. In push-to-talk mode, the microphone is automatically closed when this fires. */
UPROPERTY(BlueprintAssignable, Category = "PS AI ConvAgent|ElevenLabs|Events",
UPROPERTY(BlueprintAssignable, Category = "ASTERION|PS_AI_ConvAgent|ElevenLabs|Events",
meta = (ToolTip = "Fires when the server starts generating (before audio arrives).\nUse for 'thinking...' UI. Mic is auto-closed in push-to-talk mode."))
FOnAgentStartedGenerating OnAgentStartedGenerating;
/** Fired if the server does not start generating a response within ResponseTimeoutSeconds after the user stops speaking. Use this to show a "try again" message or automatically re-open the microphone. */
UPROPERTY(BlueprintAssignable, Category = "PS AI ConvAgent|ElevenLabs|Events",
UPROPERTY(BlueprintAssignable, Category = "ASTERION|PS_AI_ConvAgent|ElevenLabs|Events",
meta = (ToolTip = "Fires if the server doesn't respond within ResponseTimeoutSeconds.\nUse to show 'try again' or re-open the mic automatically."))
FOnAgentResponseTimeout OnAgentResponseTimeout;
/** Fired when the agent changes emotion via the "set_emotion" client tool. The emotion is set BEFORE the corresponding audio arrives, giving you time to smoothly blend facial expressions. */
UPROPERTY(BlueprintAssignable, Category = "PS AI ConvAgent|ElevenLabs|Events",
UPROPERTY(BlueprintAssignable, Category = "ASTERION|PS_AI_ConvAgent|ElevenLabs|Events",
meta = (ToolTip = "Fires when the agent sets an emotion (joy, sadness, surprise, fear, anger, disgust).\nDriven by the 'set_emotion' client tool. Arrives before the audio."))
FOnAgentEmotionChanged OnAgentEmotionChanged;
/** Fired when the LLM triggers a perform_action tool call.
* ActionName is the identifier from the ActionSet (e.g. "flee", "draw_weapon").
* Handle this in Blueprint to play animations, trigger AI behavior, etc. */
UPROPERTY(BlueprintAssignable, Category = "PS AI ConvAgent|ElevenLabs|Events",
UPROPERTY(BlueprintAssignable, Category = "ASTERION|PS_AI_ConvAgent|ElevenLabs|Events",
meta = (ToolTip = "Fires when the agent triggers a physical action.\nActionName matches the Name field from the ActionSet Data Asset."))
FOnAgentActionRequested OnAgentActionRequested;
/** Fired for client tool calls that are NOT automatically handled (i.e. not "set_emotion", not "perform_action"). You must call GetWebSocketProxy()->SendClientToolResult() to respond. */
UPROPERTY(BlueprintAssignable, Category = "PS AI ConvAgent|ElevenLabs|Events",
UPROPERTY(BlueprintAssignable, Category = "ASTERION|PS_AI_ConvAgent|ElevenLabs|Events",
meta = (ToolTip = "Fires for custom client tool calls (not set_emotion, not perform_action).\nYou must respond via GetWebSocketProxy()->SendClientToolResult()."))
FOnAgentClientToolCall OnAgentClientToolCall;
/** Fired when the active speaker changes in a multi-player shared conversation.
* NewSpeaker is null when no one is speaking (idle timeout). */
UPROPERTY(BlueprintAssignable, Category = "PS AI ConvAgent|ElevenLabs|Events",
UPROPERTY(BlueprintAssignable, Category = "ASTERION|PS_AI_ConvAgent|ElevenLabs|Events",
meta = (ToolTip = "Fires when the speaking player changes.\nNewSpeaker is null when no one is speaking."))
FOnActiveSpeakerChanged OnActiveSpeakerChanged;
@@ -361,26 +361,26 @@ public:
* components back to neutral. The NPC is fully idle and the game can start
* the physical action (flee, draw weapon, etc.).
* Call ForceEnableConversation() later to allow conversation again. */
UPROPERTY(BlueprintAssignable, Category = "PS AI ConvAgent|ElevenLabs|Events",
UPROPERTY(BlueprintAssignable, Category = "ASTERION|PS_AI_ConvAgent|ElevenLabs|Events",
meta = (ToolTip = "Fires when all animation components have returned to neutral after ForceDisableConversation().\nThe agent is ready for a game action."))
FOnReadyForAction OnReadyForAction;
/** Fired when this agent starts passively tracking a nearby player (head/eyes gaze). */
UPROPERTY(BlueprintAssignable, Category = "PS AI ConvAgent|ElevenLabs|Events",
UPROPERTY(BlueprintAssignable, Category = "ASTERION|PS_AI_ConvAgent|ElevenLabs|Events",
meta = (ToolTip = "Fires when this agent starts passively tracking a nearby player.\nTriggered by proximity awareness — the agent is not selected for conversation."))
FOnAgentPassiveGazeStarted OnPassiveGazeStarted;
/** Fired when this agent stops passively tracking a player (left range or selected). */
UPROPERTY(BlueprintAssignable, Category = "PS AI ConvAgent|ElevenLabs|Events",
UPROPERTY(BlueprintAssignable, Category = "ASTERION|PS_AI_ConvAgent|ElevenLabs|Events",
meta = (ToolTip = "Fires when this agent stops passively tracking a player.\nThe player left range or selected this agent for active conversation."))
FOnAgentPassiveGazeStopped OnPassiveGazeStopped;
/** The current emotion of the agent, as set by the "set_emotion" client tool. Defaults to Neutral. */
UPROPERTY(ReplicatedUsing = OnRep_Emotion, BlueprintReadOnly, Category = "PS AI ConvAgent|ElevenLabs")
UPROPERTY(ReplicatedUsing = OnRep_Emotion, BlueprintReadOnly, Category = "ASTERION|PS_AI_ConvAgent|ElevenLabs")
EPS_AI_ConvAgent_Emotion CurrentEmotion = EPS_AI_ConvAgent_Emotion::Neutral;
/** The current emotion intensity. Defaults to Medium. */
UPROPERTY(ReplicatedUsing = OnRep_Emotion, BlueprintReadOnly, Category = "PS AI ConvAgent|ElevenLabs")
UPROPERTY(ReplicatedUsing = OnRep_Emotion, BlueprintReadOnly, Category = "ASTERION|PS_AI_ConvAgent|ElevenLabs")
EPS_AI_ConvAgent_EmotionIntensity CurrentEmotionIntensity = EPS_AI_ConvAgent_EmotionIntensity::Medium;
// ── Raw audio data (C++ only, used by LipSync component) ────────────────
@@ -392,26 +392,26 @@ public:
/** True when one or more players are in conversation with this NPC.
* Replicated to all clients for UI feedback, gaze, LOD, etc. */
UPROPERTY(ReplicatedUsing = OnRep_ConversationState, BlueprintReadOnly, Category = "PS AI ConvAgent|Network")
UPROPERTY(ReplicatedUsing = OnRep_ConversationState, BlueprintReadOnly, Category = "ASTERION|PS_AI_ConvAgent|Network")
bool bNetIsConversing = false;
/** All player pawns currently in conversation with this NPC.
* Multiple players can share the same agent — audio is routed via speaker arbitration.
* Replicated to ALL clients for gaze target and LOD distance checks. */
UPROPERTY(ReplicatedUsing = OnRep_ConversationState, BlueprintReadOnly, Category = "PS AI ConvAgent|Network")
UPROPERTY(ReplicatedUsing = OnRep_ConversationState, BlueprintReadOnly, Category = "ASTERION|PS_AI_ConvAgent|Network")
TArray<TObjectPtr<APawn>> NetConnectedPawns;
/** The player currently speaking (active audio sender). Null if no one is speaking.
* Used by GazeComponent for target switching — the NPC looks at whoever is talking.
* Replicated to ALL clients so gaze updates everywhere. */
UPROPERTY(ReplicatedUsing = OnRep_ActiveSpeaker, BlueprintReadOnly, Category = "PS AI ConvAgent|Network")
UPROPERTY(ReplicatedUsing = OnRep_ActiveSpeaker, BlueprintReadOnly, Category = "ASTERION|PS_AI_ConvAgent|Network")
TObjectPtr<APawn> NetActiveSpeakerPawn = nullptr;
// ── Multi-player speaker arbitration (server only) ──────────────────────
/** Minimum seconds of silence from the current speaker before allowing a speaker switch.
* Prevents rapid ping-pong switching when both players make brief sounds. */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "PS AI ConvAgent|Network|MultiPlayer",
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "ASTERION|PS_AI_ConvAgent|Network|MultiPlayer",
meta = (ClampMin = "0.0", ClampMax = "5.0",
ToolTip = "Minimum silence from current speaker before switching to another.\nPrevents rapid gaze flip-flop."))
float SpeakerSwitchHysteresis = 0.3f;
@@ -419,7 +419,7 @@ public:
/** Seconds after last speech before the active speaker is cleared.
* When cleared, gaze returns to the last speaker position (or closest connected player).
* Set to 0 to never clear (last speaker stays active indefinitely). */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "PS AI ConvAgent|Network|MultiPlayer",
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "ASTERION|PS_AI_ConvAgent|Network|MultiPlayer",
meta = (ClampMin = "0.0",
ToolTip = "Seconds of silence before clearing the active speaker.\n0 = last speaker stays active indefinitely."))
float SpeakerIdleTimeout = 3.0f;
@@ -428,14 +428,14 @@ public:
/** Distance (cm) beyond which remote clients stop receiving agent audio entirely.
* The speaking player always receives full audio regardless of distance. */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "PS AI ConvAgent|Network|LOD",
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "ASTERION|PS_AI_ConvAgent|Network|LOD",
meta = (ClampMin = "0", ToolTip = "Distance beyond which audio is culled for non-speaking players. 0 = no cull."))
float AudioLODCullDistance = 3000.f;
/** Distance (cm) beyond which remote clients skip lip-sync / emotion processing.
* Audio still plays (if within AudioLODCullDistance) but without facial animation.
* The speaking player always gets full lip-sync regardless of distance. */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "PS AI ConvAgent|Network|LOD",
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "ASTERION|PS_AI_ConvAgent|Network|LOD",
meta = (ClampMin = "0", ToolTip = "Distance beyond which lip-sync is skipped for non-speaking players. 0 = no LOD."))
float LipSyncLODDistance = 1500.f;
@@ -514,25 +514,25 @@ public:
* Open the WebSocket connection and start the conversation.
* If bAutoStartListening is true, microphone capture also starts once connected.
*/
UFUNCTION(BlueprintCallable, Category = "PS AI ConvAgent|ElevenLabs")
UFUNCTION(BlueprintCallable, Category = "ASTERION|PS_AI_ConvAgent|ElevenLabs")
void StartConversation();
/** Close the WebSocket and stop all audio. */
UFUNCTION(BlueprintCallable, Category = "PS AI ConvAgent|ElevenLabs")
UFUNCTION(BlueprintCallable, Category = "ASTERION|PS_AI_ConvAgent|ElevenLabs")
void EndConversation();
/**
* Start capturing microphone audio and streaming it to ElevenLabs.
* In Client turn mode, also sends a UserTurnStart signal.
*/
UFUNCTION(BlueprintCallable, Category = "PS AI ConvAgent|ElevenLabs")
UFUNCTION(BlueprintCallable, Category = "ASTERION|PS_AI_ConvAgent|ElevenLabs")
void StartListening();
/**
* Stop capturing microphone audio.
* In Client turn mode, also sends a UserTurnEnd signal.
*/
UFUNCTION(BlueprintCallable, Category = "PS AI ConvAgent|ElevenLabs")
UFUNCTION(BlueprintCallable, Category = "ASTERION|PS_AI_ConvAgent|ElevenLabs")
void StopListening();
/**
@@ -540,11 +540,11 @@ public:
* The agent will respond with audio and text just as if it heard you speak.
* Useful for testing in the Editor or for text-based interaction.
*/
UFUNCTION(BlueprintCallable, Category = "PS AI ConvAgent|ElevenLabs")
UFUNCTION(BlueprintCallable, Category = "ASTERION|PS_AI_ConvAgent|ElevenLabs")
void SendTextMessage(const FString& Text);
/** Interrupt the agent's current utterance. */
UFUNCTION(BlueprintCallable, Category = "PS AI ConvAgent|ElevenLabs")
UFUNCTION(BlueprintCallable, Category = "ASTERION|PS_AI_ConvAgent|ElevenLabs")
void InterruptAgent();
/**
@@ -565,7 +565,7 @@ public:
*
* @param ActionName The action to perform once neutral (passed through to OnReadyForAction).
*/
UFUNCTION(BlueprintCallable, Category = "PS AI ConvAgent|ElevenLabs")
UFUNCTION(BlueprintCallable, Category = "ASTERION|PS_AI_ConvAgent|ElevenLabs")
void ForceDisableConversation(const FString& ActionName);
/**
@@ -573,7 +573,7 @@ public:
* Clears the disabled flag so the InteractionComponent can auto-start
* a new conversation on the next tick (if the player is still looking).
*/
UFUNCTION(BlueprintCallable, Category = "PS AI ConvAgent|ElevenLabs")
UFUNCTION(BlueprintCallable, Category = "ASTERION|PS_AI_ConvAgent|ElevenLabs")
void ForceEnableConversation();
/**
@@ -583,7 +583,7 @@ public:
* The component must be connected and listening (StartListening called) for audio to be sent.
* @param FloatPCM Float32 samples, 16000 Hz mono (same format as MicrophoneCaptureComponent output).
*/
UFUNCTION(BlueprintCallable, Category = "PS AI ConvAgent|ElevenLabs")
UFUNCTION(BlueprintCallable, Category = "ASTERION|PS_AI_ConvAgent|ElevenLabs")
void FeedExternalAudio(const TArray<float>& FloatPCM);
/** Receive mic audio from a specific player with speaker arbitration.
@@ -592,13 +592,13 @@ public:
// ── State queries ─────────────────────────────────────────────────────────
UFUNCTION(BlueprintPure, Category = "PS AI ConvAgent|ElevenLabs")
UFUNCTION(BlueprintPure, Category = "ASTERION|PS_AI_ConvAgent|ElevenLabs")
bool IsConnected() const;
UFUNCTION(BlueprintPure, Category = "PS AI ConvAgent|ElevenLabs")
UFUNCTION(BlueprintPure, Category = "ASTERION|PS_AI_ConvAgent|ElevenLabs")
bool IsListening() const { return bIsListening; }
UFUNCTION(BlueprintPure, Category = "PS AI ConvAgent|ElevenLabs")
UFUNCTION(BlueprintPure, Category = "ASTERION|PS_AI_ConvAgent|ElevenLabs")
bool IsAgentSpeaking() const { return bAgentSpeaking; }
/** True when the agent is speaking OR the server hasn't confirmed the full response yet.
@@ -606,21 +606,21 @@ public:
* produce more audio (e.g. during TTS inter-batch gaps). */
bool IsAgentSpeakingOrPending() const { return bAgentSpeaking || (bAgentGenerating && !bAgentResponseReceived); }
UFUNCTION(BlueprintPure, Category = "PS AI ConvAgent|ElevenLabs")
UFUNCTION(BlueprintPure, Category = "ASTERION|PS_AI_ConvAgent|ElevenLabs")
const FPS_AI_ConvAgent_ConversationInfo_ElevenLabs& GetConversationInfo() const;
/** True while conversation is force-disabled (ForceDisableConversation was called).
* While disabled, StartConversation and ServerJoinConversation are blocked. */
UFUNCTION(BlueprintPure, Category = "PS AI ConvAgent|ElevenLabs")
UFUNCTION(BlueprintPure, Category = "ASTERION|PS_AI_ConvAgent|ElevenLabs")
bool IsConversationDisabled() const { return bConversationDisabledByAction; }
/** True while audio is being pre-buffered (playback hasn't started yet).
* Used by the LipSync component to pause viseme queue consumption. */
UFUNCTION(BlueprintPure, Category = "PS AI ConvAgent|ElevenLabs")
UFUNCTION(BlueprintPure, Category = "ASTERION|PS_AI_ConvAgent|ElevenLabs")
bool IsPreBuffering() const { return bPreBuffering; }
/** Access the underlying WebSocket proxy (advanced use). */
UFUNCTION(BlueprintPure, Category = "PS AI ConvAgent|ElevenLabs")
UFUNCTION(BlueprintPure, Category = "ASTERION|PS_AI_ConvAgent|ElevenLabs")
UPS_AI_ConvAgent_WebSocket_ElevenLabsProxy* GetWebSocketProxy() const { return WebSocketProxy; }
// ─────────────────────────────────────────────────────────────────────────

View File

@@ -35,7 +35,7 @@ DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FOnExpressionChanged,
// 4. Emotion animations crossfade smoothly (configurable duration).
// 5. The AnimNode reads GetCurrentEmotionCurves() and injects them into the pose.
// ─────────────────────────────────────────────────────────────────────────────
UCLASS(ClassGroup = "PS AI ConvAgent", meta = (BlueprintSpawnableComponent),
UCLASS(ClassGroup = "ASTERION|PS_AI_ConvAgent", meta = (BlueprintSpawnableComponent),
DisplayName = "PS AI ConvAgent Facial Expression")
class PS_AI_CONVAGENT_API UPS_AI_ConvAgent_FacialExpressionComponent : public UActorComponent
{
@@ -48,23 +48,23 @@ public:
/** Emotion pose map asset containing emotion AnimSequences (Normal / Medium / Extreme per emotion).
* Create a dedicated PS_AI_ConvAgent_EmotionPoseMap asset in the Content Browser. */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "PS AI ConvAgent|FacialExpression",
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "ASTERION|PS_AI_ConvAgent|FacialExpression",
meta = (ToolTip = "Dedicated Emotion Pose Map asset.\nRight-click Content Browser → Miscellaneous → PS AI ConvAgent Emotion Pose Map."))
TObjectPtr<UPS_AI_ConvAgent_EmotionPoseMap> EmotionPoseMap;
/** Whether facial expressions are currently active (read-only).
* Managed automatically: activates on conversation connect, deactivates on disconnect.
* The underlying emotion playback keeps running so reactivation is seamless. */
UPROPERTY(BlueprintReadOnly, Category = "PS AI ConvAgent|FacialExpression")
UPROPERTY(BlueprintReadOnly, Category = "ASTERION|PS_AI_ConvAgent|FacialExpression")
bool bActive = true;
/** How long (seconds) to blend in/out when bActive changes. */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "PS AI ConvAgent|FacialExpression",
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "ASTERION|PS_AI_ConvAgent|FacialExpression",
meta = (ClampMin = "0.05", ClampMax = "3.0"))
float ActivationBlendDuration = 0.5f;
/** Emotion crossfade duration in seconds. */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "PS AI ConvAgent|FacialExpression",
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "ASTERION|PS_AI_ConvAgent|FacialExpression",
meta = (ClampMin = "0.1", ClampMax = "3.0",
ToolTip = "How long (seconds) to crossfade between emotions.\n0.5 = snappy, 1.5 = smooth."))
float EmotionBlendDuration = 0.5f;
@@ -73,12 +73,12 @@ public:
/** Enable debug logging for this component.
* When false, only key events (init, errors, state changes) are logged. */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "PS AI ConvAgent|Debug")
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "ASTERION|PS_AI_ConvAgent|Debug")
bool bDebug = false;
/** Verbosity level when bDebug is true.
* 0 = minimal extras, 1 = normal debug, 2 = detailed, 3 = per-frame data. */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "PS AI ConvAgent|Debug",
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "ASTERION|PS_AI_ConvAgent|Debug",
meta = (ClampMin = "0", ClampMax = "3", EditCondition = "bDebug"))
int32 DebugVerbosity = 1;
@@ -86,7 +86,7 @@ public:
/** Get the current emotion curves evaluated from the playing AnimSequence.
* Returns a COPY — safe to call from any thread (AnimNode worker thread). */
UFUNCTION(BlueprintCallable, Category = "PS AI ConvAgent|FacialExpression")
UFUNCTION(BlueprintCallable, Category = "ASTERION|PS_AI_ConvAgent|FacialExpression")
TMap<FName, float> GetCurrentEmotionCurves() const
{
FScopeLock Lock(&EmotionCurveLock);
@@ -94,15 +94,15 @@ public:
}
/** Get the active emotion. */
UFUNCTION(BlueprintPure, Category = "PS AI ConvAgent|FacialExpression")
UFUNCTION(BlueprintPure, Category = "ASTERION|PS_AI_ConvAgent|FacialExpression")
EPS_AI_ConvAgent_Emotion GetActiveEmotion() const { return ActiveEmotion; }
/** Get the active emotion intensity. */
UFUNCTION(BlueprintPure, Category = "PS AI ConvAgent|FacialExpression")
UFUNCTION(BlueprintPure, Category = "ASTERION|PS_AI_ConvAgent|FacialExpression")
EPS_AI_ConvAgent_EmotionIntensity GetActiveIntensity() const { return ActiveEmotionIntensity; }
/** Check if a curve name belongs to the mouth area (overridden by lip sync). */
UFUNCTION(BlueprintPure, Category = "PS AI ConvAgent|FacialExpression")
UFUNCTION(BlueprintPure, Category = "ASTERION|PS_AI_ConvAgent|FacialExpression")
static bool IsMouthCurve(const FName& CurveName);
// ── Events ───────────────────────────────────────────────────────────────
@@ -111,7 +111,7 @@ public:
* Subscribe in Blueprints to react to expression changes (trigger animations,
* particles, sounds, etc.). Only fires when the emotion actually differs
* from the previous one. */
UPROPERTY(BlueprintAssignable, Category = "PS AI ConvAgent|FacialExpression|Events")
UPROPERTY(BlueprintAssignable, Category = "ASTERION|PS_AI_ConvAgent|FacialExpression|Events")
FOnExpressionChanged OnExpressionChanged;
/** Current activation blend alpha (0 = fully inactive, 1 = fully active).

View File

@@ -58,7 +58,7 @@ struct PS_AI_CONVAGENT_API FPS_AI_ConvAgent_NeckBoneEntry
// 5. Set TargetOffset for actors without a skeleton (e.g. (0,0,160) for
// eye-level on a simple actor).
// ─────────────────────────────────────────────────────────────────────────────
UCLASS(ClassGroup = "PS AI ConvAgent", meta = (BlueprintSpawnableComponent),
UCLASS(ClassGroup = "ASTERION|PS_AI_ConvAgent", meta = (BlueprintSpawnableComponent),
DisplayName = "PS AI ConvAgent Gaze")
class PS_AI_CONVAGENT_API UPS_AI_ConvAgent_GazeComponent : public UActorComponent
{
@@ -71,24 +71,24 @@ public:
/** The actor to look at. Can be any actor (player, prop, etc.).
* Set to null to smoothly return to neutral. */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "PS AI ConvAgent|Gaze",
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "ASTERION|PS_AI_ConvAgent|Gaze",
meta = (ToolTip = "Target actor to look at.\nSet to null to return to neutral."))
TObjectPtr<AActor> TargetActor;
/** When false, all gaze outputs smoothly blend to neutral (passthrough).
* The underlying tracking keeps running so reactivation is seamless.
* Managed automatically: activates on conversation connect, deactivates on disconnect. */
UPROPERTY(BlueprintReadOnly, Category = "PS AI ConvAgent|Gaze")
UPROPERTY(BlueprintReadOnly, Category = "ASTERION|PS_AI_ConvAgent|Gaze")
bool bActive = true;
/** How long (seconds) to blend in/out when bActive changes. */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "PS AI ConvAgent|Gaze",
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "ASTERION|PS_AI_ConvAgent|Gaze",
meta = (ClampMin = "0.05", ClampMax = "3.0"))
float ActivationBlendDuration = 0.5f;
/** When false, body rotation is frozen — only head and eyes track the target.
* Useful to have the agent notice the player (eyes+head) before fully engaging (body). */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "PS AI ConvAgent|Gaze",
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "ASTERION|PS_AI_ConvAgent|Gaze",
meta = (ToolTip = "Enable body rotation toward the target.\nWhen false, only head and eyes track."))
bool bEnableBodyTracking = true;
@@ -96,7 +96,7 @@ public:
* When enabled, TargetOffset is ignored and the agent looks at the midpoint
* between the target pawn's eye bones.
* Fallback chain: eye bones → head bone → PawnViewLocation → FallbackEyeHeight. */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "PS AI ConvAgent|Gaze",
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "ASTERION|PS_AI_ConvAgent|Gaze",
meta = (ToolTip = "Auto-target the pawn's eye bones for eye contact.\nFallback: eye bones > head bone > PawnViewLocation > FallbackEyeHeight."))
bool bAutoTargetEyes = true;
@@ -104,7 +104,7 @@ public:
* AND the target is not a Pawn. For Pawns without skeleton, GetPawnViewLocation()
* is used instead (accounts for BaseEyeHeight automatically).
* Only applies to non-Pawn actors (props, triggers, etc.). */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "PS AI ConvAgent|Gaze",
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "ASTERION|PS_AI_ConvAgent|Gaze",
meta = (EditCondition = "bAutoTargetEyes", ClampMin = "0",
ToolTip = "Height offset (cm) for non-Pawn targets without skeleton.\nPawns use BaseEyeHeight automatically.\nOnly used as last-resort fallback for non-Pawn actors."))
float FallbackEyeHeight = 160.0f;
@@ -112,7 +112,7 @@ public:
/** Offset from the target actor's origin to aim at.
* Only used when bAutoTargetEyes is false.
* E.g. (0,0,160) for eye-level on a simple actor. */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "PS AI ConvAgent|Gaze",
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "ASTERION|PS_AI_ConvAgent|Gaze",
meta = (EditCondition = "!bAutoTargetEyes",
ToolTip = "Offset from target actor origin.\nE.g. (0,0,160) for eye-level.\nOnly used when Auto Target Eyes is disabled."))
FVector TargetOffset = FVector(0.0f, 0.0f, 0.0f);
@@ -127,44 +127,44 @@ public:
// so small movements around the target don't re-trigger higher layers.
/** Maximum head yaw rotation in degrees. */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "PS AI ConvAgent|Gaze",
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "ASTERION|PS_AI_ConvAgent|Gaze",
meta = (ClampMin = "0", ClampMax = "90"))
float MaxHeadYaw = 40.0f;
/** Maximum head pitch rotation in degrees. */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "PS AI ConvAgent|Gaze",
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "ASTERION|PS_AI_ConvAgent|Gaze",
meta = (ClampMin = "0", ClampMax = "90"))
float MaxHeadPitch = 30.0f;
/** Maximum horizontal eye angle in degrees. */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "PS AI ConvAgent|Gaze",
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "ASTERION|PS_AI_ConvAgent|Gaze",
meta = (ClampMin = "0", ClampMax = "90"))
float MaxEyeHorizontal = 15.0f;
/** Maximum vertical eye angle in degrees. */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "PS AI ConvAgent|Gaze",
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "ASTERION|PS_AI_ConvAgent|Gaze",
meta = (ClampMin = "0", ClampMax = "90"))
float MaxEyeVertical = 10.0f;
// ── Smoothing speeds ─────────────────────────────────────────────────────
/** Body rotation interpolation speed (lower = slower, more natural). */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "PS AI ConvAgent|Gaze",
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "ASTERION|PS_AI_ConvAgent|Gaze",
meta = (ClampMin = "0.1", ClampMax = "20"))
float BodyInterpSpeed = 4.0f;
/** Head rotation interpolation speed. */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "PS AI ConvAgent|Gaze",
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "ASTERION|PS_AI_ConvAgent|Gaze",
meta = (ClampMin = "0.1", ClampMax = "20"))
float HeadInterpSpeed = 4.0f;
/** Eye movement interpolation speed (higher = snappier). */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "PS AI ConvAgent|Gaze",
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "ASTERION|PS_AI_ConvAgent|Gaze",
meta = (ClampMin = "0.1", ClampMax = "20"))
float EyeInterpSpeed = 5.0f;
/** Interpolation speed when returning to neutral (TargetActor is null). */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "PS AI ConvAgent|Gaze",
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "ASTERION|PS_AI_ConvAgent|Gaze",
meta = (ClampMin = "0.1", ClampMax = "20"))
float ReturnToNeutralSpeed = 3.0f;
@@ -178,7 +178,7 @@ public:
* 1.0 = head always points at target regardless of animation.
* 0.0 = gaze is additive on top of animation (old behavior).
* Default: 1.0 for conversational AI (always look at who you talk to). */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "PS AI ConvAgent|Gaze",
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "ASTERION|PS_AI_ConvAgent|Gaze",
meta = (ClampMin = "0", ClampMax = "1"))
float HeadAnimationCompensation = 0.9f;
@@ -186,7 +186,7 @@ public:
* 1.0 = eyes frozen on gaze target, animation's eye movement removed.
* 0.0 = animation's eyes play through, gaze is additive.
* Intermediate (e.g. 0.5) = smooth 50/50 blend. */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "PS AI ConvAgent|Gaze",
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "ASTERION|PS_AI_ConvAgent|Gaze",
meta = (ClampMin = "0", ClampMax = "1"))
float EyeAnimationCompensation = 0.6f;
@@ -195,7 +195,7 @@ public:
* counter-rotates the gaze to keep the head pointing at the target.
* 1.0 = full compensation — head stays locked on target even during bows.
* 0.0 = no compensation — head follows body movement naturally. */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "PS AI ConvAgent|Gaze",
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "ASTERION|PS_AI_ConvAgent|Gaze",
meta = (ClampMin = "0", ClampMax = "1"))
float BodyDriftCompensation = 0.8f;
@@ -204,12 +204,12 @@ public:
/** Enable debug logging for this component.
* When false, only key events (init, errors, state changes) are logged.
* When true, additional diagnostic info is logged based on DebugVerbosity. */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "PS AI ConvAgent|Debug")
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "ASTERION|PS_AI_ConvAgent|Debug")
bool bDebug = false;
/** Verbosity level when bDebug is true.
* 0 = minimal extras, 1 = normal debug, 2 = detailed, 3 = per-frame data. */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "PS AI ConvAgent|Debug",
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "ASTERION|PS_AI_ConvAgent|Debug",
meta = (ClampMin = "0", ClampMax = "3", EditCondition = "bDebug"))
int32 DebugVerbosity = 1;
@@ -217,7 +217,7 @@ public:
* Green = head bone → target (desired).
* Cyan = computed gaze direction (body yaw + head + eyes).
* Useful for verifying that eye contact is accurate. */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "PS AI ConvAgent|Debug",
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "ASTERION|PS_AI_ConvAgent|Debug",
meta = (EditCondition = "bDebug"))
bool bDrawDebugGaze = false;
@@ -228,14 +228,14 @@ public:
* 0 = mesh faces +X (default UE convention)
* 90 = mesh faces +Y
* -90 = mesh faces -Y */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "PS AI ConvAgent|Gaze",
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "ASTERION|PS_AI_ConvAgent|Gaze",
meta = (ClampMin = "-180", ClampMax = "180"))
float MeshForwardYawOffset = 90.0f;
// ── Head bone ────────────────────────────────────────────────────────────
/** Name of the head bone on the skeletal mesh (used for eye origin calculation). */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "PS AI ConvAgent|Gaze")
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "ASTERION|PS_AI_ConvAgent|Gaze")
FName HeadBoneName = FName(TEXT("head"));
// ── Neck bone chain ─────────────────────────────────────────────────────
@@ -244,7 +244,7 @@ public:
* Order: root-to-tip (e.g. neck_01 → neck_02 → head).
* Weights should sum to ~1.0.
* If empty, falls back to single-bone behavior (HeadBoneName, weight 1.0). */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "PS AI ConvAgent|Gaze")
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "ASTERION|PS_AI_ConvAgent|Gaze")
TArray<FPS_AI_ConvAgent_NeckBoneEntry> NeckBoneChain;
// ── Getters (read by AnimNode) ───────────────────────────────────────────
@@ -252,7 +252,7 @@ public:
/** Get current eye gaze curves (8 ARKit eye look curves).
* Returns a COPY scaled by activation alpha — safe to call from any thread.
* NOTE: Prefer FillCurrentEyeCurves() for hot paths to avoid per-frame allocation. */
UFUNCTION(BlueprintCallable, Category = "PS AI ConvAgent|Gaze")
UFUNCTION(BlueprintCallable, Category = "ASTERION|PS_AI_ConvAgent|Gaze")
TMap<FName, float> GetCurrentEyeCurves() const
{
FScopeLock Lock(&GazeDataLock);

View File

@@ -45,7 +45,7 @@ DECLARE_DYNAMIC_MULTICAST_DELEGATE(FOnNoConvAgentInRange);
// 4. Mic management is auto-detected (no manual flag needed on agents).
// 5. Agents manage their own WebSocket connections independently.
// ─────────────────────────────────────────────────────────────────────────────
UCLASS(ClassGroup = "PS AI ConvAgent", meta = (BlueprintSpawnableComponent),
UCLASS(ClassGroup = "ASTERION|PS_AI_ConvAgent", meta = (BlueprintSpawnableComponent),
DisplayName = "PS AI ConvAgent Interaction")
class PS_AI_CONVAGENT_API UPS_AI_ConvAgent_InteractionComponent : public UActorComponent
{
@@ -57,7 +57,7 @@ public:
// ── Configuration ─────────────────────────────────────────────────────────
/** Maximum distance (cm) at which an agent can be selected. Agents beyond this are ignored. */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "PS AI ConvAgent|Interaction",
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "ASTERION|PS_AI_ConvAgent|Interaction",
meta = (ClampMin = "0",
ToolTip = "Max distance in cm to interact with an agent.\nAgents beyond this distance are never selected."))
float MaxInteractionDistance = 300.0f;
@@ -65,7 +65,7 @@ public:
/** Half-angle (degrees) of the view cone used for agent selection.
* The cone is centered on the pawn's view direction (camera or control rotation).
* Agents outside this cone are not considered unless they are the current sticky selection. */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "PS AI ConvAgent|Interaction",
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "ASTERION|PS_AI_ConvAgent|Interaction",
meta = (ClampMin = "0", ClampMax = "180",
ToolTip = "Half-angle of the view cone (degrees).\nAgents outside this cone are not selected.\n45 = 90-degree total FOV."))
float ViewConeHalfAngle = 45.0f;
@@ -73,7 +73,7 @@ public:
/** Wider half-angle (degrees) used for the currently selected agent.
* This provides hysteresis so the player can look slightly away from
* the current agent without losing selection (prevents flickering). */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "PS AI ConvAgent|Interaction",
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "ASTERION|PS_AI_ConvAgent|Interaction",
meta = (ClampMin = "0", ClampMax = "180",
ToolTip = "Sticky cone half-angle for the current agent (degrees).\nMust be >= ViewConeHalfAngle for hysteresis to work.\n60 = agent stays selected until 120-degree total cone is exceeded."))
float SelectionStickyAngle = 60.0f;
@@ -81,14 +81,14 @@ public:
/** Height offset (cm) added to the agent's origin for the view cone check.
* Agent origins are typically at foot level; this shifts the target point
* up to chest/head height so close-range look-at checks don't fail. */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "PS AI ConvAgent|Interaction",
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "ASTERION|PS_AI_ConvAgent|Interaction",
meta = (ClampMin = "0",
ToolTip = "Height offset (cm) above the agent origin for the view cone check.\nPrevents losing selection at close range because the camera looks above the agent's feet.\n150 = roughly chest height for a MetaHuman."))
float AgentEyeLevelOffset = 150.0f;
/** When false, only distance matters for selection (no view cone check).
* The closest agent within MaxInteractionDistance is always selected. */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "PS AI ConvAgent|Interaction",
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "ASTERION|PS_AI_ConvAgent|Interaction",
meta = (ToolTip = "Require the player to look at an agent to select it.\nWhen false, the closest agent within range is always selected."))
bool bRequireLookAt = true;
@@ -97,20 +97,20 @@ public:
/** Automatically set/clear the agent's GazeComponent TargetActor
* when the agent is selected/deselected. When false, gaze must
* be managed from Blueprint (e.g. on conversation start). */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "PS AI ConvAgent|Interaction|Gaze",
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "ASTERION|PS_AI_ConvAgent|Interaction|Gaze",
meta = (ToolTip = "Automatically point the agent's gaze at the pawn on selection.\nDisable for manual control (e.g. set target only when conversation starts)."))
bool bAutoManageGaze = true;
/** Delay (seconds) before setting the agent's gaze target after selection.
* 0 = immediate. Useful to let the agent "notice" the player with a beat. */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "PS AI ConvAgent|Interaction|Gaze",
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "ASTERION|PS_AI_ConvAgent|Interaction|Gaze",
meta = (EditCondition = "bAutoManageGaze", ClampMin = "0",
ToolTip = "Seconds to wait before the agent looks at the pawn.\n0 = immediate."))
float GazeAttachDelay = 0.0f;
/** Delay (seconds) before clearing the agent's gaze target after deselection.
* 0 = immediate. Useful to have the agent keep looking briefly as the player leaves. */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "PS AI ConvAgent|Interaction|Gaze",
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "ASTERION|PS_AI_ConvAgent|Interaction|Gaze",
meta = (EditCondition = "bAutoManageGaze", ClampMin = "0",
ToolTip = "Seconds to wait before the agent stops looking at the pawn.\n0 = immediate."))
float GazeDetachDelay = 0.0f;
@@ -119,20 +119,20 @@ public:
* with head+eyes (and optionally body). This creates natural "awareness"
* without requiring an active conversation.
* Also controls the passive gaze retained after switching conversations. */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "PS AI ConvAgent|Interaction|Gaze",
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "ASTERION|PS_AI_ConvAgent|Interaction|Gaze",
meta = (EditCondition = "bAutoManageGaze",
ToolTip = "Agents in range but not selected will passively track the player.\nAlso applies to retained gaze after switching conversations."))
bool bAutoPassiveGaze = true;
/** In passive gaze mode, the agent's head and eyes follow the player. */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "PS AI ConvAgent|Interaction|Gaze",
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "ASTERION|PS_AI_ConvAgent|Interaction|Gaze",
meta = (EditCondition = "bAutoManageGaze && bAutoPassiveGaze",
ToolTip = "Enable head+eyes tracking in passive gaze mode."))
bool bPassiveGazeHeadEyes = true;
/** In passive gaze mode, the agent's body also turns toward the player.
* When false, only head and eyes track — the body stays in its default animation. */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "PS AI ConvAgent|Interaction|Gaze",
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "ASTERION|PS_AI_ConvAgent|Interaction|Gaze",
meta = (EditCondition = "bAutoManageGaze && bAutoPassiveGaze",
ToolTip = "Enable body rotation in passive gaze mode.\nWhen false, only head and eyes track."))
bool bPassiveGazeBody = false;
@@ -142,7 +142,7 @@ public:
/** How long (seconds) the player must look at a different agent before switching
* during an active conversation. Prevents accidental switches when glancing around.
* Only applies when a conversation is active (bNetIsConversing). */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "PS AI ConvAgent|Interaction",
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "ASTERION|PS_AI_ConvAgent|Interaction",
meta = (ClampMin = "0.0", ClampMax = "5.0",
ToolTip = "Seconds the player must look at another agent before switching mid-conversation.\nPrevents accidental switches when glancing around.\n0 = instant switch."))
float ConversationSwitchDelay = 1.0f;
@@ -153,7 +153,7 @@ public:
* via StartConversationWithSelectedAgent() (e.g. on a key press).
* Set to false when you have multiple agents in a scene to prevent them
* all from greeting the player simultaneously. */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "PS AI ConvAgent|Interaction",
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "ASTERION|PS_AI_ConvAgent|Interaction",
meta = (ToolTip = "Auto-start the WebSocket when an agent is selected by proximity.\nSet to false to require explicit interaction (call StartConversationWithSelectedAgent).\nUseful with multiple agents to prevent simultaneous greetings."))
bool bAutoStartConversation = true;
@@ -162,48 +162,48 @@ public:
/** Automatically call StartListening/StopListening on the agent's
* ElevenLabsComponent when selected/deselected. When false, listening
* must be managed from Blueprint. */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "PS AI ConvAgent|Interaction|Listening",
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "ASTERION|PS_AI_ConvAgent|Interaction|Listening",
meta = (ToolTip = "Automatically open/close the agent's mic turn on selection.\nDisable for manual control (e.g. push-to-talk)."))
bool bAutoManageListening = true;
// ── Debug ────────────────────────────────────────────────────────────────
/** Enable debug logging for this component. */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "PS AI ConvAgent|Debug")
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "ASTERION|PS_AI_ConvAgent|Debug")
bool bDebug = false;
/** Verbosity level when bDebug is true.
* 0 = selection changes only, 1 = candidate evaluation, 2 = per-frame data. */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "PS AI ConvAgent|Debug",
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "ASTERION|PS_AI_ConvAgent|Debug",
meta = (ClampMin = "0", ClampMax = "3", EditCondition = "bDebug"))
int32 DebugVerbosity = 1;
// ── Events ────────────────────────────────────────────────────────────────
/** Fired when a new agent enters selection. Use this to set gaze targets, show UI, etc. */
UPROPERTY(BlueprintAssignable, Category = "PS AI ConvAgent|Interaction|Events",
UPROPERTY(BlueprintAssignable, Category = "ASTERION|PS_AI_ConvAgent|Interaction|Events",
meta = (ToolTip = "Fires when a new agent is selected.\nSet gaze targets, update UI, etc."))
FOnConvAgentSelected OnAgentSelected;
/** Fired when the previously selected agent loses selection. */
UPROPERTY(BlueprintAssignable, Category = "PS AI ConvAgent|Interaction|Events",
UPROPERTY(BlueprintAssignable, Category = "ASTERION|PS_AI_ConvAgent|Interaction|Events",
meta = (ToolTip = "Fires when the current agent is deselected.\nClear gaze targets, hide UI, etc."))
FOnConvAgentDeselected OnAgentDeselected;
/** Fired when no agent is within range or view cone. */
UPROPERTY(BlueprintAssignable, Category = "PS AI ConvAgent|Interaction|Events",
UPROPERTY(BlueprintAssignable, Category = "ASTERION|PS_AI_ConvAgent|Interaction|Events",
meta = (ToolTip = "Fires when no agent meets the distance/view criteria."))
FOnNoConvAgentInRange OnNoAgentInRange;
// ── Blueprint API ─────────────────────────────────────────────────────────
/** Get the currently selected agent (null if none). */
UFUNCTION(BlueprintPure, Category = "PS AI ConvAgent|Interaction")
UFUNCTION(BlueprintPure, Category = "ASTERION|PS_AI_ConvAgent|Interaction")
UPS_AI_ConvAgent_ElevenLabsComponent* GetSelectedAgent() const;
/** Manually select a specific agent, bypassing distance/view checks.
* Pass null to clear the selection. Automatic selection resumes next tick. */
UFUNCTION(BlueprintCallable, Category = "PS AI ConvAgent|Interaction")
UFUNCTION(BlueprintCallable, Category = "ASTERION|PS_AI_ConvAgent|Interaction")
void ForceSelectAgent(UPS_AI_ConvAgent_ElevenLabsComponent* Agent);
/** Start the WebSocket conversation with the currently selected agent.
@@ -211,18 +211,18 @@ public:
* interacts (e.g. presses a key, enters a trigger zone).
* Does nothing if no agent is selected or the agent is already connected.
* Also starts mic capture and listening automatically. */
UFUNCTION(BlueprintCallable, Category = "PS AI ConvAgent|Interaction")
UFUNCTION(BlueprintCallable, Category = "ASTERION|PS_AI_ConvAgent|Interaction")
void StartConversationWithSelectedAgent();
/** Send a text message to the currently selected agent.
* The agent responds with audio and text, just as if it heard the player speak.
* Handles network relay automatically (works on both server and client).
* Does nothing if no agent is selected or not connected. */
UFUNCTION(BlueprintCallable, Category = "PS AI ConvAgent|Interaction")
UFUNCTION(BlueprintCallable, Category = "ASTERION|PS_AI_ConvAgent|Interaction")
void SendTextToSelectedAgent(const FString& Text);
/** Clear the current selection. Automatic selection resumes next tick. */
UFUNCTION(BlueprintCallable, Category = "PS AI ConvAgent|Interaction")
UFUNCTION(BlueprintCallable, Category = "ASTERION|PS_AI_ConvAgent|Interaction")
void ClearSelection();
// ── Network relay RPCs ───────────────────────────────────────────────────

View File

@@ -29,11 +29,11 @@ public:
void UnregisterAgent(UPS_AI_ConvAgent_ElevenLabsComponent* Agent);
/** Get all currently registered agent components (weak pointers, may contain stale entries that are cleaned on access). */
UFUNCTION(BlueprintCallable, Category = "PS AI ConvAgent|Interaction")
UFUNCTION(BlueprintCallable, Category = "ASTERION|PS_AI_ConvAgent|Interaction")
TArray<UPS_AI_ConvAgent_ElevenLabsComponent*> GetRegisteredAgents() const;
/** Get the number of registered agents. */
UFUNCTION(BlueprintPure, Category = "PS AI ConvAgent|Interaction")
UFUNCTION(BlueprintPure, Category = "ASTERION|PS_AI_ConvAgent|Interaction")
int32 GetNumRegisteredAgents() const;
private:

View File

@@ -39,7 +39,7 @@ DECLARE_DYNAMIC_MULTICAST_DELEGATE(FOnPS_AI_ConvAgent_VisemesReady);
* 3. Conversation starts → lip sync works automatically.
* 4. (Optional) Bind OnVisemesReady for custom Blueprint handling.
*/
UCLASS(ClassGroup = "PS AI ConvAgent", meta = (BlueprintSpawnableComponent),
UCLASS(ClassGroup = "ASTERION|PS_AI_ConvAgent", meta = (BlueprintSpawnableComponent),
DisplayName = "PS AI ConvAgent Lip Sync")
class PS_AI_CONVAGENT_API UPS_AI_ConvAgent_LipSyncComponent : public UActorComponent
{
@@ -61,16 +61,16 @@ public:
/** Whether lip sync is currently active (read-only).
* Managed automatically: activates on conversation connect, deactivates on disconnect.
* The underlying audio analysis keeps running so reactivation is seamless. */
UPROPERTY(BlueprintReadOnly, Category = "PS AI ConvAgent|LipSync")
UPROPERTY(BlueprintReadOnly, Category = "ASTERION|PS_AI_ConvAgent|LipSync")
bool bActive = true;
/** How long (seconds) to blend in/out when bActive changes. */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "PS AI ConvAgent|LipSync",
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "ASTERION|PS_AI_ConvAgent|LipSync",
meta = (ClampMin = "0.05", ClampMax = "3.0"))
float ActivationBlendDuration = 0.5f;
/** Overall mouth movement intensity multiplier. */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "PS AI ConvAgent|LipSync",
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "ASTERION|PS_AI_ConvAgent|LipSync",
meta = (ClampMin = "0.0", ClampMax = "3.0",
ToolTip = "Lip sync intensity.\n1.0 = normal, higher = more expressive, lower = subtler."))
float LipSyncStrength = 1.0f;
@@ -78,13 +78,13 @@ public:
/** Scales the audio amplitude driving mouth movement.
* Lower values produce subtler animation, higher values are more pronounced.
* Use this to tone down overly strong lip movement without changing the shape. */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "PS AI ConvAgent|LipSync",
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "ASTERION|PS_AI_ConvAgent|LipSync",
meta = (ClampMin = "0.5", ClampMax = "1.0",
ToolTip = "Audio amplitude scale.\n0.5 = subtle, 0.75 = balanced, 1.0 = full.\nReduces overall mouth movement without affecting viseme shape."))
float AmplitudeScale = 1.0f;
/** How quickly viseme weights interpolate towards new values each frame. */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "PS AI ConvAgent|LipSync",
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "ASTERION|PS_AI_ConvAgent|LipSync",
meta = (ClampMin = "35.0", ClampMax = "65.0",
ToolTip = "Smoothing speed for viseme transitions.\n35 = smooth and soft, 50 = balanced, 65 = sharp and responsive."))
float SmoothingSpeed = 50.0f;
@@ -95,7 +95,7 @@ public:
* When the agent is NOT speaking, lip sync releases all mouth curves so the
* FacialExpressionComponent's emotion curves (including mouth) can show through.
* When the agent starts speaking, lip sync smoothly takes over mouth curves. */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "PS AI ConvAgent|LipSync",
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "ASTERION|PS_AI_ConvAgent|LipSync",
meta = (ClampMin = "0.05", ClampMax = "1.0",
ToolTip = "Blend duration when speech starts/stops.\nDuring silence, emotion facial curves control the mouth.\nDuring speech, lip sync takes over."))
float SpeechBlendDuration = 0.15f;
@@ -108,7 +108,7 @@ public:
* 0.0 = lip sync completely overrides expression curves (old behavior).
* 1.0 = emotion fully additive on expression curves during speech.
* 0.5 = balanced blend (recommended). */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "PS AI ConvAgent|LipSync",
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "ASTERION|PS_AI_ConvAgent|LipSync",
meta = (ClampMin = "0.0", ClampMax = "1.0",
ToolTip = "Emotion bleed-through during speech.\n0 = pure lip sync, 0.5 = balanced, 1 = full emotion on expression curves.\nOnly affects expression curves (smile, frown, etc.), not lip shape."))
float EmotionExpressionBlend = 0.5f;
@@ -118,7 +118,7 @@ public:
/** Envelope attack time in milliseconds.
* Controls how fast the mouth opens when speech starts or gets louder.
* Lower = snappier onset, higher = gentler opening. */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "PS AI ConvAgent|LipSync",
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "ASTERION|PS_AI_ConvAgent|LipSync",
meta = (ClampMin = "1.0", ClampMax = "50.0",
ToolTip = "Envelope attack (ms).\n5 = snappy, 10 = balanced, 25 = gentle.\nHow fast the mouth opens on speech onset."))
float EnvelopeAttackMs = 10.0f;
@@ -126,7 +126,7 @@ public:
/** Envelope release time in milliseconds.
* Controls how slowly the mouth closes when speech gets quieter.
* Higher = smoother, more natural decay. */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "PS AI ConvAgent|LipSync",
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "ASTERION|PS_AI_ConvAgent|LipSync",
meta = (ClampMin = "10.0", ClampMax = "200.0",
ToolTip = "Envelope release (ms).\n25 = responsive, 50 = balanced, 120 = smooth/cinematic.\nHow slowly the mouth closes between syllables."))
float EnvelopeReleaseMs = 50.0f;
@@ -135,12 +135,12 @@ public:
/** Enable debug logging for this component.
* When false, only key events (init, errors, state changes) are logged. */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "PS AI ConvAgent|Debug")
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "ASTERION|PS_AI_ConvAgent|Debug")
bool bDebug = false;
/** Verbosity level when bDebug is true.
* 0 = minimal extras, 1 = normal debug, 2 = detailed, 3 = per-frame data. */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "PS AI ConvAgent|Debug",
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "ASTERION|PS_AI_ConvAgent|Debug",
meta = (ClampMin = "0", ClampMax = "3", EditCondition = "bDebug"))
int32 DebugVerbosity = 1;
@@ -152,7 +152,7 @@ public:
* When assigned, curve data is extracted at BeginPlay and replaces the
* hardcoded ARKit blendshape mapping with artist-crafted poses.
* Leave empty to use the built-in ARKit mapping (backward compatible). */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "PS AI ConvAgent|LipSync",
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "ASTERION|PS_AI_ConvAgent|LipSync",
meta = (ToolTip = "Reusable pose map asset.\nAssign your MHF_* AnimSequences once, reuse on all MetaHumans.\nLeave empty for built-in ARKit mapping."))
TObjectPtr<UPS_AI_ConvAgent_LipSyncPoseMap> PoseMap;
@@ -160,19 +160,19 @@ public:
/** Fires every tick when viseme data has been updated.
* Use GetCurrentVisemes() or GetCurrentBlendshapes() to read values. */
UPROPERTY(BlueprintAssignable, Category = "PS AI ConvAgent|LipSync",
UPROPERTY(BlueprintAssignable, Category = "ASTERION|PS_AI_ConvAgent|LipSync",
meta = (ToolTip = "Fires each frame with updated viseme data.\nCall GetCurrentVisemes() or GetCurrentBlendshapes() to read values."))
FOnPS_AI_ConvAgent_VisemesReady OnVisemesReady;
// ── Getters ───────────────────────────────────────────────────────────────
/** Get current OVR viseme weights (15 values: sil, PP, FF, TH, DD, kk, CH, SS, nn, RR, aa, E, ih, oh, ou). */
UFUNCTION(BlueprintCallable, Category = "PS AI ConvAgent|LipSync")
UFUNCTION(BlueprintCallable, Category = "ASTERION|PS_AI_ConvAgent|LipSync")
TMap<FName, float> GetCurrentVisemes() const { return SmoothedVisemes; }
/** Get current ARKit blendshape weights (MetaHuman compatible: jawOpen, mouthFunnel, mouthClose, etc.).
* Thread-safe: returns a snapshot updated each tick. Safe to call from anim worker threads. */
UFUNCTION(BlueprintCallable, Category = "PS AI ConvAgent|LipSync")
UFUNCTION(BlueprintCallable, Category = "ASTERION|PS_AI_ConvAgent|LipSync")
TMap<FName, float> GetCurrentBlendshapes() const
{
FScopeLock Lock(&BlendshapeLock);
@@ -181,7 +181,7 @@ public:
/** True when the agent is currently producing speech audio.
* When false, lip sync releases mouth curves to let emotion curves through. */
UFUNCTION(BlueprintPure, Category = "PS AI ConvAgent|LipSync")
UFUNCTION(BlueprintPure, Category = "ASTERION|PS_AI_ConvAgent|LipSync")
bool IsSpeaking() const { return bIsSpeaking; }
/** Current speech blend alpha (0 = silent/emotion mouth, 1 = lip sync mouth).

View File

@@ -22,7 +22,7 @@ DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnPS_AI_ConvAgent_VoiceActivityChan
* Modelled after Convai's ConvaiAudioCaptureComponent but stripped to the
* minimal functionality needed for conversational AI agents.
*/
UCLASS(ClassGroup = "PS AI ConvAgent", meta = (BlueprintSpawnableComponent),
UCLASS(ClassGroup = "ASTERION|PS_AI_ConvAgent", meta = (BlueprintSpawnableComponent),
DisplayName = "PS AI ConvAgent Microphone Capture")
class PS_AI_CONVAGENT_API UPS_AI_ConvAgent_MicrophoneCaptureComponent : public UActorComponent
{
@@ -32,7 +32,7 @@ public:
UPS_AI_ConvAgent_MicrophoneCaptureComponent();
/** Multiplier applied to the microphone input volume before sending to the agent. Increase if the agent has trouble hearing you, decrease if your audio is clipping. Default: 1.0 (no change). */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "PS AI ConvAgent|MicCapture",
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "ASTERION|PS_AI_ConvAgent|MicCapture",
meta = (ClampMin = "0.0", ClampMax = "4.0",
ToolTip = "Microphone volume multiplier.\n1.0 = no change. Increase if the agent can't hear you, decrease if audio clips."))
float VolumeMultiplier = 1.0f;
@@ -52,50 +52,50 @@ public:
// ── Local Voice Activity Detection ──────────────────────────────────
/** RMS threshold above which audio is considered voice. Adjust based on mic sensitivity and environment noise. */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "PS AI ConvAgent|Voice Activity",
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "ASTERION|PS_AI_ConvAgent|Voice Activity",
meta = (ClampMin = "0.001", ClampMax = "0.2"))
float VoiceActivityThreshold = 0.015f;
/** Time (seconds) RMS must stay above threshold before declaring speech onset. Prevents false triggers from clicks/bumps. */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "PS AI ConvAgent|Voice Activity",
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "ASTERION|PS_AI_ConvAgent|Voice Activity",
meta = (ClampMin = "0.01", ClampMax = "1.0"))
float VoiceOnsetTime = 0.1f;
/** Time (seconds) RMS must stay below threshold before declaring speech ended. Prevents cutting off between words. */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "PS AI ConvAgent|Voice Activity",
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "ASTERION|PS_AI_ConvAgent|Voice Activity",
meta = (ClampMin = "0.1", ClampMax = "3.0"))
float VoiceSilenceTime = 0.5f;
/** Whether the user is currently speaking (local VAD, independent of ElevenLabs server). */
UPROPERTY(BlueprintReadOnly, Category = "PS AI ConvAgent|Voice Activity")
UPROPERTY(BlueprintReadOnly, Category = "ASTERION|PS_AI_ConvAgent|Voice Activity")
bool bIsUserSpeaking = false;
/** Fired when voice activity changes. Use to pause NPC movement, trigger animations, etc. */
UPROPERTY(BlueprintAssignable, Category = "PS AI ConvAgent|Voice Activity")
UPROPERTY(BlueprintAssignable, Category = "ASTERION|PS_AI_ConvAgent|Voice Activity")
FOnPS_AI_ConvAgent_VoiceActivityChanged OnUserVoiceActivityChanged;
// ── Debug ────────────────────────────────────────────────────────────────
/** Enable debug logging for this component.
* When false, only key events (init, errors, state changes) are logged. */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "PS AI ConvAgent|Debug")
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "ASTERION|PS_AI_ConvAgent|Debug")
bool bDebug = false;
/** Verbosity level when bDebug is true.
* 0 = minimal extras, 1 = normal debug, 2 = detailed, 3 = per-frame data. */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "PS AI ConvAgent|Debug",
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "ASTERION|PS_AI_ConvAgent|Debug",
meta = (ClampMin = "0", ClampMax = "3", EditCondition = "bDebug"))
int32 DebugVerbosity = 1;
/** Open the default capture device and begin streaming audio. */
UFUNCTION(BlueprintCallable, Category = "PS AI ConvAgent|MicCapture")
UFUNCTION(BlueprintCallable, Category = "ASTERION|PS_AI_ConvAgent|MicCapture")
void StartCapture();
/** Stop streaming and close the capture device. */
UFUNCTION(BlueprintCallable, Category = "PS AI ConvAgent|MicCapture")
UFUNCTION(BlueprintCallable, Category = "ASTERION|PS_AI_ConvAgent|MicCapture")
void StopCapture();
UFUNCTION(BlueprintPure, Category = "PS AI ConvAgent|MicCapture")
UFUNCTION(BlueprintPure, Category = "ASTERION|PS_AI_ConvAgent|MicCapture")
bool IsCapturing() const { return bCapturing; }
// ─────────────────────────────────────────────────────────────────────────

View File

@@ -69,31 +69,31 @@ public:
// ── Events ────────────────────────────────────────────────────────────────
/** Called once the WebSocket handshake succeeds and the agent sends its initiation metadata. */
UPROPERTY(BlueprintAssignable, Category = "PS AI ConvAgent|ElevenLabs|Events")
UPROPERTY(BlueprintAssignable, Category = "ASTERION|PS_AI_ConvAgent|ElevenLabs|Events")
FOnPS_AI_ConvAgent_ElevenLabs_Connected OnConnected;
/** Called when the WebSocket closes (graceful or remote). */
UPROPERTY(BlueprintAssignable, Category = "PS AI ConvAgent|ElevenLabs|Events")
UPROPERTY(BlueprintAssignable, Category = "ASTERION|PS_AI_ConvAgent|ElevenLabs|Events")
FOnPS_AI_ConvAgent_ElevenLabs_Disconnected OnDisconnected;
/** Called on any connection or protocol error. */
UPROPERTY(BlueprintAssignable, Category = "PS AI ConvAgent|ElevenLabs|Events")
UPROPERTY(BlueprintAssignable, Category = "ASTERION|PS_AI_ConvAgent|ElevenLabs|Events")
FOnPS_AI_ConvAgent_ElevenLabs_Error OnError;
/** Raw PCM audio coming from the agent — feed this into your audio component. */
UPROPERTY(BlueprintAssignable, Category = "PS AI ConvAgent|ElevenLabs|Events")
UPROPERTY(BlueprintAssignable, Category = "ASTERION|PS_AI_ConvAgent|ElevenLabs|Events")
FOnPS_AI_ConvAgent_ElevenLabs_AudioReceived OnAudioReceived;
/** User or agent transcript (may be tentative while the conversation is ongoing). */
UPROPERTY(BlueprintAssignable, Category = "PS AI ConvAgent|ElevenLabs|Events")
UPROPERTY(BlueprintAssignable, Category = "ASTERION|PS_AI_ConvAgent|ElevenLabs|Events")
FOnPS_AI_ConvAgent_ElevenLabs_Transcript OnTranscript;
/** Final text response from the agent (complements audio). */
UPROPERTY(BlueprintAssignable, Category = "PS AI ConvAgent|ElevenLabs|Events")
UPROPERTY(BlueprintAssignable, Category = "ASTERION|PS_AI_ConvAgent|ElevenLabs|Events")
FOnPS_AI_ConvAgent_ElevenLabs_AgentResponse OnAgentResponse;
/** The agent was interrupted by new user speech. */
UPROPERTY(BlueprintAssignable, Category = "PS AI ConvAgent|ElevenLabs|Events")
UPROPERTY(BlueprintAssignable, Category = "ASTERION|PS_AI_ConvAgent|ElevenLabs|Events")
FOnPS_AI_ConvAgent_ElevenLabs_Interrupted OnInterrupted;
/**
@@ -101,15 +101,15 @@ public:
* starts generating. Fires well before audio. The component uses this to stop the
* microphone if it was restarted before the server finished processing the previous turn.
*/
UPROPERTY(BlueprintAssignable, Category = "PS AI ConvAgent|ElevenLabs|Events")
UPROPERTY(BlueprintAssignable, Category = "ASTERION|PS_AI_ConvAgent|ElevenLabs|Events")
FOnPS_AI_ConvAgent_ElevenLabs_ResponseStarted OnAgentResponseStarted;
/** Fired for every agent_chat_response_part with the streaming text fragment. */
UPROPERTY(BlueprintAssignable, Category = "PS AI ConvAgent|ElevenLabs|Events")
UPROPERTY(BlueprintAssignable, Category = "ASTERION|PS_AI_ConvAgent|ElevenLabs|Events")
FOnPS_AI_ConvAgent_ElevenLabs_ResponsePart OnAgentResponsePart;
/** Fired when the agent invokes a client tool. Handle the call and reply with SendClientToolResult. */
UPROPERTY(BlueprintAssignable, Category = "PS AI ConvAgent|ElevenLabs|Events")
UPROPERTY(BlueprintAssignable, Category = "ASTERION|PS_AI_ConvAgent|ElevenLabs|Events")
FOnPS_AI_ConvAgent_ElevenLabs_ClientToolCall OnClientToolCall;
// ── Lifecycle ─────────────────────────────────────────────────────────────
@@ -121,21 +121,21 @@ public:
* @param AgentID ElevenLabs agent ID. Overrides the project-level default when non-empty.
* @param APIKey API key. Overrides the project-level default when non-empty.
*/
UFUNCTION(BlueprintCallable, Category = "PS AI ConvAgent|ElevenLabs")
UFUNCTION(BlueprintCallable, Category = "ASTERION|PS_AI_ConvAgent|ElevenLabs")
void Connect(const FString& AgentID = TEXT(""), const FString& APIKey = TEXT(""));
/**
* Gracefully close the WebSocket connection.
* OnDisconnected will fire after the server acknowledges.
*/
UFUNCTION(BlueprintCallable, Category = "PS AI ConvAgent|ElevenLabs")
UFUNCTION(BlueprintCallable, Category = "ASTERION|PS_AI_ConvAgent|ElevenLabs")
void Disconnect();
/** Current connection state. */
UFUNCTION(BlueprintPure, Category = "PS AI ConvAgent|ElevenLabs")
UFUNCTION(BlueprintPure, Category = "ASTERION|PS_AI_ConvAgent|ElevenLabs")
EPS_AI_ConvAgent_ConnectionState_ElevenLabs GetConnectionState() const { return ConnectionState; }
UFUNCTION(BlueprintPure, Category = "PS AI ConvAgent|ElevenLabs")
UFUNCTION(BlueprintPure, Category = "ASTERION|PS_AI_ConvAgent|ElevenLabs")
bool IsConnected() const { return ConnectionState == EPS_AI_ConvAgent_ConnectionState_ElevenLabs::Connected; }
// ── Audio sending ─────────────────────────────────────────────────────────
@@ -148,7 +148,7 @@ public:
*
* @param PCMData Raw PCM bytes (16-bit LE, 16kHz, mono).
*/
UFUNCTION(BlueprintCallable, Category = "PS AI ConvAgent|ElevenLabs")
UFUNCTION(BlueprintCallable, Category = "ASTERION|PS_AI_ConvAgent|ElevenLabs")
void SendAudioChunk(const TArray<uint8>& PCMData);
// ── Turn control (only relevant in Client turn mode) ──────────────────────
@@ -158,7 +158,7 @@ public:
* Sends a { "type": "user_activity" } message to the server.
* Call this periodically while the user is speaking (e.g. every audio chunk).
*/
UFUNCTION(BlueprintCallable, Category = "PS AI ConvAgent|ElevenLabs")
UFUNCTION(BlueprintCallable, Category = "ASTERION|PS_AI_ConvAgent|ElevenLabs")
void SendUserTurnStart();
/**
@@ -166,7 +166,7 @@ public:
* No explicit API message — simply stop sending user_activity.
* The server detects silence and hands the turn to the agent.
*/
UFUNCTION(BlueprintCallable, Category = "PS AI ConvAgent|ElevenLabs")
UFUNCTION(BlueprintCallable, Category = "ASTERION|PS_AI_ConvAgent|ElevenLabs")
void SendUserTurnEnd();
/**
@@ -174,11 +174,11 @@ public:
* Useful for testing or text-only interaction.
* Sends: { "type": "user_message", "text": "..." }
*/
UFUNCTION(BlueprintCallable, Category = "PS AI ConvAgent|ElevenLabs")
UFUNCTION(BlueprintCallable, Category = "ASTERION|PS_AI_ConvAgent|ElevenLabs")
void SendTextMessage(const FString& Text);
/** Ask the agent to stop the current utterance. */
UFUNCTION(BlueprintCallable, Category = "PS AI ConvAgent|ElevenLabs")
UFUNCTION(BlueprintCallable, Category = "ASTERION|PS_AI_ConvAgent|ElevenLabs")
void SendInterrupt();
/**
@@ -189,12 +189,12 @@ public:
* @param Result A string result to return to the agent.
* @param bIsError True if the tool execution failed.
*/
UFUNCTION(BlueprintCallable, Category = "PS AI ConvAgent|ElevenLabs")
UFUNCTION(BlueprintCallable, Category = "ASTERION|PS_AI_ConvAgent|ElevenLabs")
void SendClientToolResult(const FString& ToolCallId, const FString& Result, bool bIsError = false);
// ── Info ──────────────────────────────────────────────────────────────────
UFUNCTION(BlueprintPure, Category = "PS AI ConvAgent|ElevenLabs")
UFUNCTION(BlueprintPure, Category = "ASTERION|PS_AI_ConvAgent|ElevenLabs")
const FPS_AI_ConvAgent_ConversationInfo_ElevenLabs& GetConversationInfo() const { return ConversationInfo; }
/** Latest WebSocket round-trip latency reported by the server (ms).

View File

@@ -21,7 +21,7 @@ FText UAnimGraphNode_PS_AI_ConvAgent_BodyExpression::GetTooltipText() const
FString UAnimGraphNode_PS_AI_ConvAgent_BodyExpression::GetNodeCategory() const
{
return TEXT("PS AI ConvAgent");
return TEXT("ASTERION|PS_AI_ConvAgent");
}
FLinearColor UAnimGraphNode_PS_AI_ConvAgent_BodyExpression::GetNodeTitleColor() const

View File

@@ -20,7 +20,7 @@ FText UAnimGraphNode_PS_AI_ConvAgent_FacialExpression::GetTooltipText() const
FString UAnimGraphNode_PS_AI_ConvAgent_FacialExpression::GetNodeCategory() const
{
return TEXT("PS AI ConvAgent");
return TEXT("ASTERION|PS_AI_ConvAgent");
}
FLinearColor UAnimGraphNode_PS_AI_ConvAgent_FacialExpression::GetNodeTitleColor() const

View File

@@ -21,7 +21,7 @@ FText UAnimGraphNode_PS_AI_ConvAgent_Gaze::GetTooltipText() const
FString UAnimGraphNode_PS_AI_ConvAgent_Gaze::GetNodeCategory() const
{
return TEXT("PS AI ConvAgent");
return TEXT("ASTERION|PS_AI_ConvAgent");
}
FLinearColor UAnimGraphNode_PS_AI_ConvAgent_Gaze::GetNodeTitleColor() const

View File

@@ -20,7 +20,7 @@ FText UAnimGraphNode_PS_AI_ConvAgent_LipSync::GetTooltipText() const
FString UAnimGraphNode_PS_AI_ConvAgent_LipSync::GetNodeCategory() const
{
return TEXT("PS AI ConvAgent");
return TEXT("ASTERION|PS_AI_ConvAgent");
}
FLinearColor UAnimGraphNode_PS_AI_ConvAgent_LipSync::GetNodeTitleColor() const

View File

@@ -10,7 +10,7 @@
/**
* AnimGraph editor node for the PS AI ConvAgent Body Expression AnimNode.
*
* This node appears in the AnimBP graph editor under the "PS AI ConvAgent" category.
* This node appears in the AnimBP graph editor under the "ASTERION|PS_AI_ConvAgent" category.
* Place it in the character's Body AnimBP after upstream body animations
* (idle, locomotion). It blends emotion-driven body poses onto the upper body
* while passing the lower body through unchanged.

View File

@@ -10,7 +10,7 @@
/**
* AnimGraph editor node for the PS AI ConvAgent Facial Expression AnimNode.
*
* This node appears in the AnimBP graph editor under the "PS AI ConvAgent" category.
* This node appears in the AnimBP graph editor under the "ASTERION|PS_AI_ConvAgent" category.
* Place it BEFORE the PS AI ConvAgent Lip Sync node in the MetaHuman Face AnimBP.
* It auto-discovers the PS_AI_ConvAgent_FacialExpressionComponent on the owning Actor
* and injects CTRL_expressions_* curves for emotion-driven facial expressions.

View File

@@ -10,7 +10,7 @@
/**
* AnimGraph editor node for the PS AI ConvAgent Gaze AnimNode.
*
* This node appears in the AnimBP graph editor under the "PS AI ConvAgent" category.
* This node appears in the AnimBP graph editor under the "ASTERION|PS_AI_ConvAgent" category.
* Place it AFTER the PS AI ConvAgent Facial Expression node and BEFORE the
* PS AI ConvAgent Lip Sync node in the MetaHuman Face AnimBP.
*

View File

@@ -10,7 +10,7 @@
/**
* AnimGraph editor node for the PS AI ConvAgent Lip Sync AnimNode.
*
* This node appears in the AnimBP graph editor under the "PS AI ConvAgent" category.
* This node appears in the AnimBP graph editor under the "ASTERION|PS_AI_ConvAgent" category.
* Drop it into your MetaHuman Face AnimBP between the pose source and the
* Control Rig node. It auto-discovers the PS_AI_ConvAgent_LipSyncComponent on the
* owning Actor and injects CTRL_expressions_* curves for lip sync.