<?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_Transfer_Between_Regions</id>
	<title>OpenSimulator Internals/Walkthroughs/Avatar Transfer Between Regions - 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_Transfer_Between_Regions"/>
	<link rel="alternate" type="text/html" href="http://osimdev.org/wiki/index.php?title=OpenSimulator_Internals/Walkthroughs/Avatar_Transfer_Between_Regions&amp;action=history"/>
	<updated>2026-08-04T15:37:13Z</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_Transfer_Between_Regions&amp;diff=85&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_Transfer_Between_Regions&amp;diff=85&amp;oldid=prev"/>
		<updated>2026-07-07T13:09:43Z</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 Transfer Between Regions =&lt;br /&gt;
&lt;br /&gt;
== Overview ==&lt;br /&gt;
&lt;br /&gt;
Traces what happens in code, connectors, and database when an avatar teleports from one region to another on the same grid. Covers the V2 protocol path (protocol version &amp;gt;= 0.2), which is the current standard.&lt;br /&gt;
&lt;br /&gt;
For region border crossing (walking/flying across a boundary), see the Crossing section below. For HG teleport, see [[OpenSimulator Internals/Walkthroughs/Avatar Goes HG]].&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Part 1: Teleport ==&lt;br /&gt;
&lt;br /&gt;
=== 1. Teleport Requested ===&lt;br /&gt;
&lt;br /&gt;
 OpenSim/Region/Framework/Scenes/Scene.cs -- RequestTeleportLocation()&lt;br /&gt;
 OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs -- Teleport()&lt;br /&gt;
&lt;br /&gt;
# Viewer sends TeleportLocationRequest packet (or map click, lure, landmark).&lt;br /&gt;
# Scene.RequestTeleportLocation() gets ScenePresence, checks not deleted/in transit, calls EntityTransferModule.Teleport().&lt;br /&gt;
# EntityTransferModule.Teleport():&lt;br /&gt;
#* Checks CanTeleport permissions.&lt;br /&gt;
#* Calls SetInTransit() -- rejects if already in transit.&lt;br /&gt;
#* Calls Util.CompareRegionHandles() to determine if destination is within current region bounds.&lt;br /&gt;
#* If same region: calls TeleportAgentWithinRegion() -- local move, no inter-region protocol.&lt;br /&gt;
#* If different region: calls TeleportAgentToDifferentRegion().&lt;br /&gt;
&lt;br /&gt;
=== 2. Destination Lookup ===&lt;br /&gt;
&lt;br /&gt;
 EntityTransferModule -- TeleportAgentToDifferentRegion() → GetTeleportDestinationRegion()&lt;br /&gt;
&lt;br /&gt;
# Calls GridService.GetRegionByPosition() -- HTTP GET to ROBUST GridService.&lt;br /&gt;
#* ROBUST reads regions table, returns GridRegion for the destination.&lt;br /&gt;
# Calls GetFinalDestination() -- on base class returns same region (HG override resolves foreign address).&lt;br /&gt;
# Calls ValidateGenericConditions() -- base class returns true (override point).&lt;br /&gt;
&lt;br /&gt;
; DB reads (on ROBUST side):&lt;br /&gt;
* regions -- SELECT by world position&lt;br /&gt;
&lt;br /&gt;
=== 3. Pre-flight Checks ===&lt;br /&gt;
&lt;br /&gt;
 EntityTransferModule -- DoTeleportInternal()&lt;br /&gt;
&lt;br /&gt;
# DNS resolution: finalDestination.ExternalEndPoint.&lt;br /&gt;
# Calls SimulationService.QueryAccess() -- HTTP POST to destination simulator&amp;#039;s QueryAccess endpoint.&lt;br /&gt;
#* Destination calls Scene.QueryAccess(): checks ban list, parcel access, agent limit, AllowAvatarCrossing.&lt;br /&gt;
#* Returns true/false + reason string.&lt;br /&gt;
# Checks sp.Appearance.CanTeleport(ctx.OutboundVersion) -- rejects if outfit incompatible with destination protocol version.&lt;br /&gt;
# If avatar sitting: calls sp.StandUp().&lt;br /&gt;
# Sets sp.IsInLocalTransit, sp.IsInTransit = true.&lt;br /&gt;
# Sends TeleportStart to viewer.&lt;br /&gt;
&lt;br /&gt;
=== 4. Create Agent at Destination (V2) ===&lt;br /&gt;
&lt;br /&gt;
 EntityTransferModule -- TransferAgent_V2() → CreateAgent()&lt;br /&gt;
&lt;br /&gt;
# Builds AgentCircuitData for the destination -- includes caps path, start position, appearance height.&lt;br /&gt;
# Determines OutSideViewRange: whether destination is outside current draw distance (needs new child agent vs reusing existing one).&lt;br /&gt;
# Calls SimulationService.CreateAgent() -- HTTP POST to destination simulator&amp;#039;s NewAgentIn endpoint.&lt;br /&gt;
#* Destination calls Scene.NewUserConnection() with the AgentCircuitData.&lt;br /&gt;
#* NewUserConnection() validates presence, authorises user, sets up caps, adds circuit.&lt;br /&gt;
#* Returns success/failure + reason.&lt;br /&gt;
# If failed: sends TeleportFailed to viewer, clears transit state.&lt;br /&gt;
# Fires EventManager.TriggerTeleportStart on source.&lt;br /&gt;
&lt;br /&gt;
=== 5. Send TeleportFinish to Viewer ===&lt;br /&gt;
&lt;br /&gt;
 EntityTransferModule -- TransferAgent_V2()&lt;br /&gt;
&lt;br /&gt;
# Sets sp.IsChildAgent = true on source (before UpdateAgent, to prevent race with destination requesting a child close).&lt;br /&gt;
# Sends TeleportFinishEvent via IEventQueue -- gives viewer: destination handle, endpoint, caps seed URL, teleport flags.&lt;br /&gt;
# Viewer receives TeleportFinish and begins connecting to destination simulator.&lt;br /&gt;
&lt;br /&gt;
=== 6. Send Full Agent State to Destination ===&lt;br /&gt;
&lt;br /&gt;
 EntityTransferModule -- TransferAgent_V2() → UpdateAgent()&lt;br /&gt;
 ScenePresence -- CopyTo()&lt;br /&gt;
&lt;br /&gt;
# Builds AgentData via sp.CopyTo(agent, isCrossUpdate=false):&lt;br /&gt;
#* Position, velocity, camera axes.&lt;br /&gt;
#* Appearance (full AvatarAppearance copy).&lt;br /&gt;
#* Animations, animation overrides, motion state.&lt;br /&gt;
#* Attachment SOGs (cloned via AttachmentsModule.CopyAttachments()) with script states.&lt;br /&gt;
#* Script controls, god data, group info, friends online cache.&lt;br /&gt;
#* Sets SenderWantsToWaitForRoot = true.&lt;br /&gt;
# Calls SimulationService.UpdateAgent() -- HTTP POST to destination simulator.&lt;br /&gt;
#* Destination calls Scene.IncomingUpdateChildAgent(AgentData).&lt;br /&gt;
#* Destination&amp;#039;s ScenePresence.UpdateChildAgent() calls CopyFrom() which sets m_originRegionID.&lt;br /&gt;
#* If SenderWantsToWaitForRoot: destination waits (up to 25s polling) for sp.IsChildAgent to become false (CompleteMovement fires when viewer sends CompleteMovementToRegion).&lt;br /&gt;
#* Returns true when avatar is root at destination.&lt;br /&gt;
# UpdateAgent() blocks on source until destination returns.&lt;br /&gt;
&lt;br /&gt;
=== 7. Avatar Becomes Root at Destination ===&lt;br /&gt;
&lt;br /&gt;
 ScenePresence -- CompleteMovement() (destination side)&lt;br /&gt;
&lt;br /&gt;
# Viewer sends CompleteMovementToRegion to destination simulator.&lt;br /&gt;
# Destination CompleteMovement() fires (see [[OpenSimulator Internals/Walkthroughs/Avatar Rez In Region]] steps 3-5 for detail).&lt;br /&gt;
# Key difference from login: WaitForUpdateAgent() waits up to 10s for m_originRegionID to be set (set by UpdateAgent arriving). For teleport this is not skipped.&lt;br /&gt;
# MakeRootAgent() called -- physics actor created, position adjusted.&lt;br /&gt;
# Avatar data sent to all presences at destination.&lt;br /&gt;
# Attachments: for teleport (not IsRealLogin), attachments were carried in AgentData. Scripts restarted via RestartAttachmentScripts() rather than RezAttachments().&lt;br /&gt;
&lt;br /&gt;
=== 8. Source Cleans Up ===&lt;br /&gt;
&lt;br /&gt;
 EntityTransferModule -- TransferAgent_V2() (source, after UpdateAgent returns)&lt;br /&gt;
&lt;br /&gt;
# Calls sp.HasMovedAway(nearRegion) -- if nearRegion (within view range and not logout): calls AttachmentsModule.DeleteAttachmentsFromScene() for non-HUD attachments; sends kill packets to presences that won&amp;#039;t see the avatar in the new region.&lt;br /&gt;
# Calls sp.MakeChildAgent(destinationHandle) -- source presence becomes child. Physics removed. OnMakeChildAgent fires.&lt;br /&gt;
# Closes child agents: sp.CloseChildAgents(childRegionsToClose) or sp.closeAllChildAgents() for logout=true.&lt;br /&gt;
# If NeedsClosing (OutSideViewRange): waits up to 15s for sp.IsInTransit to clear, then calls m_scene.CloseAgent() -- fully removes source presence.&lt;br /&gt;
# If within view range (not NeedsClosing): source keeps a child agent. sp.IsInTransit = false.&lt;br /&gt;
&lt;br /&gt;
; No DB writes at source during teleport. Attachment saves happen at logout/detach, not on teleport.&lt;br /&gt;
&lt;br /&gt;
=== 9. GridUser Updated at Destination ===&lt;br /&gt;
&lt;br /&gt;
After CompleteMovement() completes at destination, the region updates position:&lt;br /&gt;
&lt;br /&gt;
# GridUserService.SetLastPosition() -- updates griduser table with new RegionID, position, look.&lt;br /&gt;
&lt;br /&gt;
; DB writes:&lt;br /&gt;
* griduser -- UPDATE: LastRegionID, LastPosition, LastLookAt&lt;br /&gt;
&lt;br /&gt;
=== 10. PresenceService Updated ===&lt;br /&gt;
&lt;br /&gt;
# PresenceService.ReportAgent() (or equivalent) -- updates presence table with new RegionID.&lt;br /&gt;
&lt;br /&gt;
; DB writes:&lt;br /&gt;
* presence -- UPDATE: RegionID to destination region&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Part 2: Region Border Crossing ==&lt;br /&gt;
&lt;br /&gt;
Border crossing is initiated by the source region&amp;#039;s physics simulation, not the viewer.&lt;br /&gt;
&lt;br /&gt;
=== 1. Border Detected ===&lt;br /&gt;
&lt;br /&gt;
 ScenePresence -- CheckForBorderCrossing() (called each heartbeat frame from Update())&lt;br /&gt;
&lt;br /&gt;
# Checks not IsChildAgent, not IsInTransit, not sitting, PhysicsActor != null.&lt;br /&gt;
# Projects position: pos + velocity * FrameTime.&lt;br /&gt;
# If projected position is outside region bounds: calls Scene.CrossAgentToNewRegion().&lt;br /&gt;
# Scene.CrossAgentToNewRegion() checks AllowAvatarCrossing flag, then calls EntityTransferModule.Cross().&lt;br /&gt;
&lt;br /&gt;
=== 2. Destination Found ===&lt;br /&gt;
&lt;br /&gt;
 EntityTransferModule -- Cross() → CrossAsync() → CrossAgentToNewRegionAsync()&lt;br /&gt;
&lt;br /&gt;
# Cross() fires async via WorkManager.RunInThreadPool.&lt;br /&gt;
# CrossAsync():&lt;br /&gt;
#* Projects pos + velocity * 0.2s.&lt;br /&gt;
#* Calls GetDestination() -- GridService.GetRegionByPosition() for the projected world position.&lt;br /&gt;
#* Calls SimulationService.QueryAccess() -- checks destination will accept avatar.&lt;br /&gt;
#* Removes avatar from physics: sp.RemoveFromPhysicalScene().&lt;br /&gt;
# Calls CrossAgentIntoNewRegionMain().&lt;br /&gt;
&lt;br /&gt;
=== 3. Agent State Sent to Destination ===&lt;br /&gt;
&lt;br /&gt;
 EntityTransferModule -- CrossAgentIntoNewRegionMain()&lt;br /&gt;
&lt;br /&gt;
# Builds AgentData via sp.CopyTo(cAgent, isCrossUpdate=true):&lt;br /&gt;
#* Sets CrossingFlags |= 1.&lt;br /&gt;
#* Includes CrossExtraFlags for mouse button state.&lt;br /&gt;
#* Attachments copied with script states.&lt;br /&gt;
# Calls SimulationService.UpdateAgent() -- HTTP POST to destination.&lt;br /&gt;
#* Note: for crossing, CreateAgent() is NOT called first if destination already has a child agent. UpdateAgent() is called directly.&lt;br /&gt;
#* Destination IncomingUpdateChildAgent() fires, sp.UpdateChildAgent() → CopyFrom() sets m_gotCrossUpdate=true.&lt;br /&gt;
# Sets sp.IsChildAgent = true.&lt;br /&gt;
# Sends CrossRegion event queue message to viewer -- gives destination handle, position, velocity, endpoint, caps path.&lt;br /&gt;
# Calls sp.HasMovedAway() and sp.MakeChildAgent().&lt;br /&gt;
# ResetFromTransit() called -- clears transit state.&lt;br /&gt;
&lt;br /&gt;
If UpdateAgent fails (region refused):&lt;br /&gt;
# Calls ReInstantiateScripts() -- restores attachment scripts from InTransitScriptStates.&lt;br /&gt;
# Calls sp.AddToPhysicalScene() -- puts avatar back in physics.&lt;br /&gt;
# Returns false -- CheckForBorderCrossing() calls sp.CrossToNewRegionFail() which repositions avatar inside the region.&lt;br /&gt;
&lt;br /&gt;
=== 4. Avatar Becomes Root at Destination ===&lt;br /&gt;
&lt;br /&gt;
Destination side CompleteMovement() fires when viewer sends CompleteMovementToRegion:&lt;br /&gt;
&lt;br /&gt;
# m_gotCrossUpdate = true (set by CopyFrom).&lt;br /&gt;
# WaitForUpdateAgent() skipped for crossing (not teleport -- no SenderWantsToWaitForRoot set for crossing path).&lt;br /&gt;
# MakeRootAgent() called. Physics created. Position from AgentData.&lt;br /&gt;
# SendRegionHandshake() skipped (not a crossing -- m_gotCrossUpdate suppresses it).&lt;br /&gt;
# MoveAgentIntoRegion() sends viewer its new position.&lt;br /&gt;
# Attachments: scripts restarted via RestartAttachmentScripts() (not RezAttachments).&lt;br /&gt;
# EnableChildAgents() seeds new neighbours.&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 !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| regions || SELECT || Destination lookup (step 2) || ROBUST GridService&lt;br /&gt;
|-&lt;br /&gt;
| griduser || UPDATE || Post-arrival at destination (step 9) || LastRegionID, LastPosition&lt;br /&gt;
|-&lt;br /&gt;
| presence || UPDATE || Post-arrival at destination (step 10) || RegionID&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
No asset or inventory writes occur during a normal teleport or crossing. Attachments are carried in AgentData in memory; they are only written to assets/inventory on detach or logout.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Key Differences: Teleport vs Crossing ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Aspect !! Teleport !! Crossing&lt;br /&gt;
|-&lt;br /&gt;
| Initiator || Viewer request || Physics / heartbeat frame&lt;br /&gt;
|-&lt;br /&gt;
| Protocol || CreateAgent then UpdateAgent || UpdateAgent only (if child exists)&lt;br /&gt;
|-&lt;br /&gt;
| Viewer notification || TeleportFinish event queue || CrossRegion event queue&lt;br /&gt;
|-&lt;br /&gt;
| Script state || Snapshotted in CopyTo, restored via RestartAttachmentScripts || Same&lt;br /&gt;
|-&lt;br /&gt;
| isCrossUpdate flag || false || true&lt;br /&gt;
|-&lt;br /&gt;
| WaitForUpdateAgent || Yes (up to 10s) || No&lt;br /&gt;
|-&lt;br /&gt;
| m_gotCrossUpdate || false || true&lt;br /&gt;
|-&lt;br /&gt;
| RegionHandshake sent || Yes (if not crossing) || No&lt;br /&gt;
|-&lt;br /&gt;
| Source closes || If OutSideViewRange, after 15s || Immediately (MakeChildAgent)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Failure Modes ==&lt;br /&gt;
&lt;br /&gt;
Teleport failure after CreateAgent (destination created but viewer can&amp;#039;t connect):&lt;br /&gt;
* UpdateAgent() times out after ~10s.&lt;br /&gt;
* Fail() called: CleanupFailedInterRegionTeleport() -- SimulationService.CloseAgent() to destination, sp.IsChildAgent=false, scripts re-instantiated.&lt;br /&gt;
* TeleportFailed sent to viewer.&lt;br /&gt;
&lt;br /&gt;
Crossing failure (UpdateAgent to destination fails):&lt;br /&gt;
* ReInstantiateScripts() restores attachment scripts.&lt;br /&gt;
* sp.AddToPhysicalScene() restores physics.&lt;br /&gt;
* sp.CrossToNewRegionFail() repositions avatar inside region bounds.&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/ScenePresence]]&lt;br /&gt;
* [[OpenSimulator Internals/Code Map/Scene]]&lt;br /&gt;
* [[OpenSimulator Internals/Connector Architecture/Simulation Connector]]&lt;br /&gt;
* [[OpenSimulator Internals/Walkthroughs/Avatar Rez In Region]]&lt;br /&gt;
* [[OpenSimulator Internals/Walkthroughs/Avatar Logs Out]]&lt;br /&gt;
* [[OpenSimulator Internals/Walkthroughs/Avatar Goes HG]]&lt;/div&gt;</summary>
		<author><name>Jwbshaw</name></author>
	</entry>
</feed>