Skip to content

Fix vehicle unseating on region crossings by ignoring outgoing sim kills - #6170

Open
Shadowolf7 wants to merge 2 commits into
secondlife:mainfrom
Shadowolf7:upstream-ll-vehicle-fix
Open

Shadowolf7 wants to merge 2 commits into
secondlife:mainfrom
Shadowolf7:upstream-ll-vehicle-fix

Conversation

@Shadowolf7

Copy link
Copy Markdown
Contributor

Description

This PR resolves the long-standing bug where avatars are forcibly unseated from vehicles during region crossings.

Root Cause

During a region crossing:

  1. The avatar and vehicle cross into the receiving simulator, and the viewer sets its active agent region to the new simulator.
  2. The outgoing simulator (lagging by 0–1s) cleans up its local physics representation of the vehicle and sends a UDP KillObject packet to the client.
  3. Because the client did not differentiate between an active-region object deletion and an outgoing-simulator crossing cleanup, process_kill_object called markDead() on the vehicle prim.
  4. In LLViewerObject::markDead(), lines 480-489 detected the seated avatar and executed ((LLVOAvatar*)childp)->getOffObject(), prematurely severing the sit link on the client side before the receiving simulator's ObjectUpdate took over.

Solution

In process_kill_object (indra/newview/llviewermessage.cpp), we check if a kill packet for the avatar's seated root object originates from a non-active (outgoing) region (regionp != gAgent.getRegion()). If so, the cleanup packet is ignored, keeping the vehicle and seated avatar intact across the boundary handoff.

Actual vehicle deletions (e.g. parcel auto-return, hard banlines, llDie()) sent by the active simulator (regionp == gAgent.getRegion()) continue to execute normally.

Verification

  • Tested in-world across 16+ region crossings with multiple vehicles.
  • Confirmed zero markDead() unseat ejections.
  • Maintained continuous, uninterrupted seating through multiple consecutive border crossings.

@github-actions github-actions Bot added the c/cpp label Aug 21, 2026
@github-actions

github-actions Bot commented Aug 21, 2026

Copy link
Copy Markdown

All contributors have signed the CLA ✍️ ✅
Posted by the CLA Assistant Lite bot.

Copilot AI left a comment

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.

Pull request overview

This PR addresses viewer-side unseating during region crossings by ignoring KillObject packets coming from the outgoing (non-active) simulator when they target the seated vehicle root, preventing premature markDead() unseat behavior during the handoff.

Changes:

  • Add a guard in process_kill_object to ignore KillObject messages from non-active regions when they target the agent’s seated root object.
  • Emit an informational log when such a kill is ignored.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread indra/newview/llviewermessage.cpp
- Only emit LL_INFOS when ignoring a kill on the linkset root prim
- Cache objectp->getRootEdit() in a local variable to avoid redundant lookups

Copilot AI left a comment

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.

Pull request overview

Copilot reviewed 1 out of 1 changed files in this pull request and generated 1 comment.

Suppressed comments (1)

indra/newview/llviewermessage.cpp:3685

  • This compares the sender with gAgent.getRegion(), but the ordinary crossing path does not update that pointer: process_crossed_region() only adds the destination region, and the crossing branch of process_agent_movement_complete() does not call gAgent.setRegion(). After the seated linkset has been updated into the destination, a legitimate KillObject from that active simulator can therefore satisfy this condition and be skipped, leaving the object (and its cache/selection state) alive. Compare against the seated root's current object region, or update the agent region as part of the crossing before applying this filter.
            if ( regionp && (regionp != gAgent.getRegion()) &&
                 isAgentAvatarValid() && gAgentAvatarp->isSitting() )
            {
                LLViewerObject* rootp = objectp->getRootEdit();
                if (rootp && (gAgentAvatarp->getRoot() == rootp))

LL_INFOS("Avatar") << "Ignoring vehicle kill from outgoing region " << regionp->getName()
<< " for seated root object " << rootp->getID() << LL_ENDL;
}
continue;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants