Skip to content

Defer processing AvatarAppearance until after first ObjectUpdate#6017

Open
AndrewMeadows wants to merge 6 commits into
developfrom
leviathan/ghi-6009
Open

Defer processing AvatarAppearance until after first ObjectUpdate#6017
AndrewMeadows wants to merge 6 commits into
developfrom
leviathan/ghi-6009

Conversation

@AndrewMeadows

Copy link
Copy Markdown
Collaborator

This PR fixes issue #6009 where the high- and low-priority UDP message queue would exacerbate a race condition where the AvatarAppearance message would be processed before the agent was created by its first ObjectUpdate. It also changes where the packet sequence ID is processed to reduce the WARNING logs about out-of-order packets caused by asymmetric priority during packet floods.

S32 mSize; // size of buffer in bytes
LLHost mHost; // source/dest IP and port
LLHost mReceivingIF; // source/dest IP and port
bool mPacketIDChecked = false;

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We now check the packet sequence ID when we pull it off of the socket. This infrastructure is used to track whether the packet has already been checked or not when it comes time to process it.

Comment thread indra/llmessage/message.cpp Outdated
//
// AvatarAppearance is "Low 158" which means it is stored in four bytes: 0xff 0xff 0x00 0x9E
// the last two bytes represent 158 in a BigEndian U16
return !(header[1] == 255 && header[2] == 0 && header[3] == 158);

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the main fix: we categorize AvatarAppearance messages as low-priority (same as ObjectUpdate) to reduce the race condition where AvatarAppearance is processed too soon.

Comment thread indra/newview/llviewermessage.cpp Outdated
// the ObjectUpdate was lost and is being resent). Defer it until the avatar shows up,
// instead of dropping it.
LL_WARNS("Messaging") << "avatar_appearance sent for unknown avatar " << uuid << "; deferring" << LL_ENDL;
LLVOAvatar::addPendingAvatarAppearance(uuid, mesgsys);

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are still ways by which AvatarAppearance can arrive before the first ObjectUpdate. Here we queue the AvatarAppearance data, give it an expiry, and process it later (or expire it) when new avatars are created.

Comment thread indra/llmessage/message.cpp Outdated
//
// AvatarAppearance is "Low 158" which means it is stored in four bytes: 0xff 0xff 0x00 0x9E
// the last two bytes represent 158 in a BigEndian U16
return !(header[1] == 255 && header[2] == 0 && header[3] == 158);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

return header[1] != 255 || header[2] != 0 || header[3] != 158;

Comment thread indra/llmessage/message.cpp Outdated
// Skip genuine duplicate resends, same as checkMessages()/logValidMsg()
// would do further downstream.
bool recv_resent = (data[0] & LL_RESENT_FLAG) != 0;
if (!(recv_resent && cdp->isDuplicateResend(recv_packet_id)))

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if (!recv_resent || !cdp->isDuplicateResend(recv_packet_id))

Comment thread indra/newview/llvoavatar.cpp Outdated
{
++timer_iter;
}
}

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just now realize: we should check expiries first otherwise we could process an expired appearance for avatarp. Meanwhile, the expiry duration I picked (20 seconds) is mostly arbitrary. I know we can see UDP packets get delayed ~10 seconds on the dual-queues. The viewer will re-ask for AvatarAppearance data on a 120 second timer, so I figure the duration should be between those values.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Meanwhile Henri Beauchamp suggests (via IM): instead of storing the whole AvatarAppearance data just store the agent_id and then when we reach this context just fire off a new avatartexturesrequest.

@akleshchev
akleshchev self-requested a review July 18, 2026 06:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants