ElevenLabs: guard null gaze target on late join (replicated ref not resolved)
A client that joins while a conversation is already active can run OnRep with NetConnectedPawns/NetActiveSpeakerPawn entries whose replicated pawn references haven't resolved yet (actor channel not open). NetConnectedPawns.Num() > 0 did not guarantee a non-null element, so OnRep_ConversationState dereferenced a null pawn in its log (crash in Dev/PIE) and ApplyConversationGaze set TargetActor to null (gaze glitch). Both now skip until the reference resolves — OnRep fires again once it's patched in. More likely with 3+ clients. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -2060,12 +2060,18 @@ void UPS_AI_ConvAgent_ElevenLabsComponent::OnRep_ConversationState()
|
||||
{
|
||||
Gaze->bActive = true;
|
||||
// Use active speaker if set, otherwise first connected pawn.
|
||||
// GazeTarget can be null on a late joiner if the replicated pawn
|
||||
// reference hasn't resolved yet (actor channel not open). Skip until
|
||||
// it resolves — OnRep fires again once the reference is patched in.
|
||||
APawn* GazeTarget = NetActiveSpeakerPawn ? NetActiveSpeakerPawn : NetConnectedPawns.Last();
|
||||
Gaze->TargetActor = GazeTarget;
|
||||
Gaze->ResetBodyTarget();
|
||||
Gaze->bEnableBodyTracking = true;
|
||||
UE_LOG(LogPS_AI_ConvAgent_ElevenLabs, Log,
|
||||
TEXT("[NET-REP] Gaze ACTIVATED, TargetActor set to %s"), *GazeTarget->GetName());
|
||||
if (GazeTarget)
|
||||
{
|
||||
Gaze->TargetActor = GazeTarget;
|
||||
Gaze->ResetBodyTarget();
|
||||
Gaze->bEnableBodyTracking = true;
|
||||
UE_LOG(LogPS_AI_ConvAgent_ElevenLabs, Log,
|
||||
TEXT("[NET-REP] Gaze ACTIVATED, TargetActor set to %s"), *GazeTarget->GetName());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -2704,10 +2710,12 @@ void UPS_AI_ConvAgent_ElevenLabsComponent::ApplyConversationGaze()
|
||||
{
|
||||
Gaze->bActive = true;
|
||||
// Look at active speaker if set, otherwise last connected pawn.
|
||||
// GazeTarget can be null if a replicated pawn ref hasn't resolved yet
|
||||
// (late joiner). Don't overwrite the target with null in that case.
|
||||
AActor* GazeTarget = NetActiveSpeakerPawn
|
||||
? static_cast<AActor*>(NetActiveSpeakerPawn)
|
||||
: static_cast<AActor*>(NetConnectedPawns.Last());
|
||||
if (Gaze->TargetActor != GazeTarget)
|
||||
if (GazeTarget && Gaze->TargetActor != GazeTarget)
|
||||
{
|
||||
Gaze->TargetActor = GazeTarget;
|
||||
Gaze->ResetBodyTarget();
|
||||
|
||||
Reference in New Issue
Block a user