<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>http://osimdev.org/wiki/index.php?action=history&amp;feed=atom&amp;title=OpenSimulator_Internals%2FWalkthroughs%2FAvatar_Logs_Out</id>
	<title>OpenSimulator Internals/Walkthroughs/Avatar Logs Out - Revision history</title>
	<link rel="self" type="application/atom+xml" href="http://osimdev.org/wiki/index.php?action=history&amp;feed=atom&amp;title=OpenSimulator_Internals%2FWalkthroughs%2FAvatar_Logs_Out"/>
	<link rel="alternate" type="text/html" href="http://osimdev.org/wiki/index.php?title=OpenSimulator_Internals/Walkthroughs/Avatar_Logs_Out&amp;action=history"/>
	<updated>2026-08-04T15:36:59Z</updated>
	<subtitle>Revision history for this page on the wiki</subtitle>
	<generator>MediaWiki 1.45.3</generator>
	<entry>
		<id>http://osimdev.org/wiki/index.php?title=OpenSimulator_Internals/Walkthroughs/Avatar_Logs_Out&amp;diff=84&amp;oldid=prev</id>
		<title>Jwbshaw: first</title>
		<link rel="alternate" type="text/html" href="http://osimdev.org/wiki/index.php?title=OpenSimulator_Internals/Walkthroughs/Avatar_Logs_Out&amp;diff=84&amp;oldid=prev"/>
		<updated>2026-07-07T13:06:06Z</updated>

		<summary type="html">&lt;p&gt;first&lt;/p&gt;
&lt;p&gt;&lt;b&gt;New page&lt;/b&gt;&lt;/p&gt;&lt;div&gt;= OpenSimulator Internals/Walkthroughs/Avatar Logs Out =&lt;br /&gt;
&lt;br /&gt;
== Overview ==&lt;br /&gt;
&lt;br /&gt;
Traces what happens in code, connectors, and database when an avatar logs out normally. Covers both viewer-initiated logout and region-initiated close.&lt;br /&gt;
&lt;br /&gt;
This does not cover region crossing or teleport departure -- see [[OpenSimulator Internals/Walkthroughs/Avatar Transfer Between Regions]].&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== 1. Logout Initiated ==&lt;br /&gt;
&lt;br /&gt;
=== Viewer-initiated ===&lt;br /&gt;
&lt;br /&gt;
 OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs&lt;br /&gt;
&lt;br /&gt;
# Avatar clicks Logout in viewer.&lt;br /&gt;
# Viewer sends LogoutRequest UDP packet.&lt;br /&gt;
# LLClientView.HandleLogout() fires. Sets IsLoggingOut = true on the client.&lt;br /&gt;
# Calls Scene.CloseAgent(agentID, force=false).&lt;br /&gt;
&lt;br /&gt;
=== Region-initiated (admin kick or simulator shutdown) ===&lt;br /&gt;
&lt;br /&gt;
# Console command or admin API calls Scene.CloseAgent(agentID, force=true).&lt;br /&gt;
# Or: LLClientView.OnConnectionClosed fires when viewer connection drops; EntityTransferModule.OnConnectionClosed() sets transfer state to Aborting if in transit.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== 2. Scene.CloseAgent() ==&lt;br /&gt;
&lt;br /&gt;
 OpenSim/Region/Framework/Scenes/Scene.cs -- CloseAgent()&lt;br /&gt;
&lt;br /&gt;
Under m_removeClientLock:&lt;br /&gt;
&lt;br /&gt;
# Gets ScenePresence. If null or IsDeleted: removes from clientManager, authenticateHandler, capsModule directly and returns.&lt;br /&gt;
# Checks LifecycleState -- must be Running or PreRemove to proceed.&lt;br /&gt;
# Checks DoNotCloseAfterTeleport -- if true (another region renewed the child connection), resets flag and returns false without closing.&lt;br /&gt;
# Sets sp.LifecycleState = Removing.&lt;br /&gt;
&lt;br /&gt;
Then outside the lock:&lt;br /&gt;
&lt;br /&gt;
# Calls sp.ControllingClient.Close(force, force) -- this triggers RemoveClient() via the client stack.&lt;br /&gt;
# For NPCs: calls UserManagementModule.RemoveUser().&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== 3. RemoveClient() ==&lt;br /&gt;
&lt;br /&gt;
 OpenSim/Region/Framework/Scenes/Scene.cs -- RemoveClient()&lt;br /&gt;
&lt;br /&gt;
Under m_removeClientPrivLock:&lt;br /&gt;
&lt;br /&gt;
# Gets AgentCircuitData -- if null, aborts.&lt;br /&gt;
# Gets ScenePresence -- if null, removes circuit and returns.&lt;br /&gt;
# If child agent and closeChildAgents: sends SendShutdownConnectionNotice() to viewer.&lt;br /&gt;
# If avatar is sitting: calls avatar.StandUp().&lt;br /&gt;
# Calls m_sceneGraph.removeUserCount(!isChildAgent).&lt;br /&gt;
# If root agent and closeChildAgents:&lt;br /&gt;
#* Gets KnownRegionHandles (all known neighbour regions).&lt;br /&gt;
#* Calls m_sceneGridService.SendCloseChildAgentConnections() -- async HTTP DELETE to each neighbour simulator&amp;#039;s agent endpoint.&lt;br /&gt;
# Fires EventManager.TriggerClientClosed().&lt;br /&gt;
# Fires EventManager.TriggerOnRemovePresence().&lt;br /&gt;
# If root agent:&lt;br /&gt;
#* Calls AttachmentsModule.DeRezAttachments() -- saves all attachments to inventory (see step 4).&lt;br /&gt;
#* Calls ForEachClient() sending SendKillObject for this avatar&amp;#039;s LocalId to all connected clients.&lt;br /&gt;
# Calls AgentTransactionsModule.RemoveAgentAssetTransactions() if present.&lt;br /&gt;
&lt;br /&gt;
Finally (in finally block, always runs):&lt;br /&gt;
# m_authenticateHandler.RemoveCircuit(acd).&lt;br /&gt;
# m_sceneGraph.RemoveScenePresence(agentID).&lt;br /&gt;
# m_clientManager.Remove(agentID).&lt;br /&gt;
# m_capsModule.RemoveCaps(agentID, circuitcode).&lt;br /&gt;
# avatar.Dispose().&lt;br /&gt;
&lt;br /&gt;
Note: PresenceService.LogoutAgent() and GridUserService.LoggedOut() are NOT called from RemoveClient(). These are called from LLClientView.Close() or from the login service cleanup path. See step 5.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== 4. Attachments Saved ==&lt;br /&gt;
&lt;br /&gt;
 OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs -- DeRezAttachments()&lt;br /&gt;
&lt;br /&gt;
For each attachment SOG:&lt;br /&gt;
&lt;br /&gt;
# Calls PrepareScriptInstanceForSave() -- fires detach script event, waits 30ms, snapshots script state XML. Must run outside AttachmentsSyncLock.&lt;br /&gt;
# Calls UpdateDetachedObject():&lt;br /&gt;
#* Calls m_scene.DeleteSceneObject() -- removes from scene.&lt;br /&gt;
#* Clears attachment fields (AttachedAvatar, ParentLocalId, IsAttachment).&lt;br /&gt;
#* For local grid users only (not HG visitors): calls UpdateKnownItem() -- serialises SOG to XML, creates new asset, updates inventory item assetID and permissions.&lt;br /&gt;
#* Calls so.RemoveScriptInstances() + so.Dispose().&lt;br /&gt;
# Calls sp.ClearAttachments().&lt;br /&gt;
&lt;br /&gt;
HG visitors: UpdateKnownItem() skipped. Their attachments are not saved to the foreign grid. When they log back in on their home grid, attachments reload from home grid state.&lt;br /&gt;
&lt;br /&gt;
; DB writes:&lt;br /&gt;
* assets -- INSERT: updated serialised object XML per attachment (local users only)&lt;br /&gt;
* inventoryitems -- UPDATE: new assetID per attachment (local users only)&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== 5. Presence and GridUser Updated ==&lt;br /&gt;
&lt;br /&gt;
 OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs -- Close()&lt;br /&gt;
 OpenSim/Services/Connectors/Presence/PresenceServicesConnector.cs&lt;br /&gt;
 OpenSim/Services/Connectors/GridUser/GridUserServicesConnector.cs&lt;br /&gt;
&lt;br /&gt;
On client close (called from CloseAgent step 2):&lt;br /&gt;
&lt;br /&gt;
# PresenceService.LogoutAgent(sessionID) called -- HTTP POST to ROBUST PresenceService.&lt;br /&gt;
#* ROBUST sets presence Online=0, clears RegionID for this session.&lt;br /&gt;
# GridUserService.LoggedOut(agentID, sessionID, regionID, position, lookAt) called -- HTTP POST to ROBUST GridUserService.&lt;br /&gt;
#* ROBUST updates griduser: LastRegionID, LastPosition, LastLookAt, Logout timestamp.&lt;br /&gt;
&lt;br /&gt;
; DB writes:&lt;br /&gt;
* presence -- UPDATE: Online=0, RegionID cleared&lt;br /&gt;
* griduser -- UPDATE: LastPosition, LastLookAt, LastRegionID, Logout timestamp&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== 6. Child Agents Closed ==&lt;br /&gt;
&lt;br /&gt;
Called asynchronously from RemoveClient() step 3 via m_sceneGridService.SendCloseChildAgentConnections().&lt;br /&gt;
&lt;br /&gt;
For each neighbour handle in KnownRegionHandles:&lt;br /&gt;
&lt;br /&gt;
# HTTP DELETE to neighbour simulator&amp;#039;s agent endpoint (SimulationService).&lt;br /&gt;
# Neighbour simulator receives request, validates auth token (SessionID).&lt;br /&gt;
# Calls Scene.CloseAgent() on the child ScenePresence.&lt;br /&gt;
# Child path: no attachment save, no presence update, just removes from scene graph.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== 7. Appearance Save (if queued) ==&lt;br /&gt;
&lt;br /&gt;
If an appearance save was queued via AvatarFactoryModule and the 5-second delay has not yet elapsed:&lt;br /&gt;
&lt;br /&gt;
* AvatarFactoryModule timer fires SaveAppearance().&lt;br /&gt;
* Calls AvatarService.SetAppearance() -- writes final appearance to ROBUST.&lt;br /&gt;
&lt;br /&gt;
Whether this completes before or after the logout depends on timing. A logout immediately after an outfit change may race with or skip the final save.&lt;br /&gt;
&lt;br /&gt;
; DB writes (conditional):&lt;br /&gt;
* avatarappearance -- UPDATE: final wearable list, textures, visual params&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Shutdown vs Normal Logout ==&lt;br /&gt;
&lt;br /&gt;
Scene.Close() (simulator shutdown):&lt;br /&gt;
&lt;br /&gt;
# Fires EventManager.TriggerSceneShuttingDown().&lt;br /&gt;
# Calls GridService.DeregisterRegion() -- removes region from regions table. Sets RegionOnline=0.&lt;br /&gt;
# Sends Kick message to all root avatars via ControllingClient.Kick().&lt;br /&gt;
# Sends SendShutdownConnectionNotice() to all.&lt;br /&gt;
# Sleeps 500ms for messages to deliver.&lt;br /&gt;
# Calls CloseAgent() for every ScenePresence.&lt;br /&gt;
# Calls Backup(true) -- forces persistence of all changed scene objects.&lt;br /&gt;
# Closes SceneGraph and disposes PhysicsScene.&lt;br /&gt;
&lt;br /&gt;
; DB writes (on shutdown):&lt;br /&gt;
* regions -- UPDATE: RegionOnline=0 (via GridService.DeregisterRegion())&lt;br /&gt;
* prims/primshapes/primitems -- UPDATE: all changed objects persisted via Backup(true)&lt;br /&gt;
* presence/griduser -- UPDATE: as per normal logout for each agent&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Summary: DB Tables Touched ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Table !! Operation !! Step&lt;br /&gt;
|-&lt;br /&gt;
| assets || INSERT || Attachment object assets saved (step 4, local users)&lt;br /&gt;
|-&lt;br /&gt;
| inventoryitems || UPDATE || Attachment inventory items updated (step 4, local users)&lt;br /&gt;
|-&lt;br /&gt;
| presence || UPDATE || Online=0, session cleared (step 5)&lt;br /&gt;
|-&lt;br /&gt;
| griduser || UPDATE || LastPosition, Logout timestamp (step 5)&lt;br /&gt;
|-&lt;br /&gt;
| avatarappearance || UPDATE || Final appearance if save queued (step 7, conditional)&lt;br /&gt;
|-&lt;br /&gt;
| regions || UPDATE || RegionOnline=0 on shutdown only&lt;br /&gt;
|-&lt;br /&gt;
| prims/primshapes || UPDATE || Changed objects on shutdown only&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Simultaneous Logout During Teleport ==&lt;br /&gt;
&lt;br /&gt;
If the client sends LogoutRequest while a teleport is in progress:&lt;br /&gt;
&lt;br /&gt;
# EntityTransferModule.OnConnectionClosed() fires.&lt;br /&gt;
# If agent is in transit: sets transfer state to Aborting.&lt;br /&gt;
# The in-progress teleport path checks Aborting state at each stage and aborts.&lt;br /&gt;
# Source region calls CleanupFailedInterRegionTeleport() -- calls SimulationService.CloseAgent() on destination to remove the half-created agent there.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== See Also ==&lt;br /&gt;
&lt;br /&gt;
* [[OpenSimulator Internals/Walkthroughs]]&lt;br /&gt;
* [[OpenSimulator Internals/Code Map/EntityTransferModule]]&lt;br /&gt;
* [[OpenSimulator Internals/Code Map/Scene]]&lt;br /&gt;
* [[OpenSimulator Internals/Code Map/ScenePresence]]&lt;br /&gt;
* [[OpenSimulator Internals/Code Map/AttachmentsModule]]&lt;br /&gt;
* [[OpenSimulator Internals/Code Map/ROBUST/PresenceService]]&lt;br /&gt;
* [[OpenSimulator Internals/Connector Architecture/Presence Connector]]&lt;br /&gt;
* [[OpenSimulator Internals/Walkthroughs/Avatar Rez In Region]]&lt;br /&gt;
* [[OpenSimulator Internals/Walkthroughs/Avatar Transfer Between Regions]]&lt;/div&gt;</summary>
		<author><name>Jwbshaw</name></author>
	</entry>
</feed>