<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>http://osimdev.org/wiki/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Jwbshaw</id>
	<title>Open Simulator Technical Help - User contributions [en]</title>
	<link rel="self" type="application/atom+xml" href="http://osimdev.org/wiki/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Jwbshaw"/>
	<link rel="alternate" type="text/html" href="http://osimdev.org/wiki/index.php/Special:Contributions/Jwbshaw"/>
	<updated>2026-08-04T14:54:57Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.45.3</generator>
	<entry>
		<id>http://osimdev.org/wiki/index.php?title=OpenSimulator_Internals/Connector_Architecture&amp;diff=121</id>
		<title>OpenSimulator Internals/Connector Architecture</title>
		<link rel="alternate" type="text/html" href="http://osimdev.org/wiki/index.php?title=OpenSimulator_Internals/Connector_Architecture&amp;diff=121"/>
		<updated>2026-07-09T07:14:19Z</updated>

		<summary type="html">&lt;p&gt;Jwbshaw: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= OpenSimulator Internals/Connector Architecture =&lt;br /&gt;
&lt;br /&gt;
== Overview ==&lt;br /&gt;
&lt;br /&gt;
Connectors are the HTTP client layer that sits between region simulators and ROBUST grid services. Each connector implements a service interface (e.g. IAssetService, IPresenceService) using HTTP calls to the corresponding ROBUST handler.&lt;br /&gt;
&lt;br /&gt;
The same interface may be implemented by:&lt;br /&gt;
* A local connector -- calls the service directly in-process (standalone mode or co-located services).&lt;br /&gt;
* A remote connector -- makes HTTP calls to a ROBUST server.&lt;br /&gt;
* An HG connector -- wraps the remote connector with hypergrid-specific logic.&lt;br /&gt;
&lt;br /&gt;
Region code calls only the interface. Which implementation is loaded depends on configuration ([Architecture] section of the ini files).&lt;br /&gt;
&lt;br /&gt;
Because every ROBUST service is stateless, each can be independently load-balanced or replicated without coordination between instances.&lt;br /&gt;
&lt;br /&gt;
See [[OpenSimulator Internals/ROBUST Services]] for the server-side service implementations.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Connector Pattern ==&lt;br /&gt;
&lt;br /&gt;
All remote connectors follow the same pattern:&lt;br /&gt;
&lt;br /&gt;
# Constructor receives IConfigSource and reads the service URL from config.&lt;br /&gt;
# Each method serialises parameters to a REST or XMLRPC request.&lt;br /&gt;
# Sends HTTP POST/GET/DELETE to the ROBUST handler endpoint.&lt;br /&gt;
# Deserialises the response and returns the result.&lt;br /&gt;
&lt;br /&gt;
The HTTP client layer is WebUtil (OpenSim/Framework/WebUtil.cs), which handles serialisation, connection pooling, and error logging.&lt;br /&gt;
&lt;br /&gt;
See [[OpenSimulator Internals/Connector Architecture/Asset Connector]] for a fully worked example of the pattern including both client and server-side handler code.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Individual Connector Pages ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Connector !! Service Interface !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| [[OpenSimulator Internals/Connector Architecture/Asset Connector]] || IAssetService || As of 0.9.2, the three region-side asset modules (LocalAssetServiceConnector, RemoteAssetServiceConnector, HGAssetBroker) were replaced by a single RegionAssetConnector. LocalAssetServiceConnector is retained for test use only. HGAssetBroker and RemoteAssetServiceConnector are no longer used in production. RegionAssetConnector behaviour is controlled by [AssetService] keys LocalGridAssetService and HypergridAssetService. See individual page for full detail including server-side handler code.&lt;br /&gt;
|-&lt;br /&gt;
| [[OpenSimulator Internals/Connector Architecture/GridUser Connector]] || IGridUserService || Tracks last position, login/logout timestamps, home region. Online status in GridUser is less accurate than in Presence, which is updated more frequently.&lt;br /&gt;
|-&lt;br /&gt;
| [[OpenSimulator Internals/Connector Architecture/Presence Connector]] || IPresenceService || Online status, session tracking, region assignment.&lt;br /&gt;
|-&lt;br /&gt;
| [[OpenSimulator Internals/Connector Architecture/UserAccount Connector]] || IUserAccountService || User account CRUD. Known bug: CreateUser() sends first name as email value.&lt;br /&gt;
|-&lt;br /&gt;
| [[OpenSimulator Internals/Connector Architecture/Inventory Connector]] || IInventoryService || XInventory protocol. UpdateFolder() URL-encodes Name; AddFolder() does not.&lt;br /&gt;
|-&lt;br /&gt;
| HGInventoryService || IInventoryService || HG-only. Pre-suitcase implementation. Returns &amp;quot;My Suitcase&amp;quot; folder as root by name lookup. Does not enforce suitcase tree boundaries on operations. Adjusts CreatorData on item fetch to include home grid URL. Deletions and skeleton requests blocked. Present in current code but not recommended for new deployments.&lt;br /&gt;
|-&lt;br /&gt;
| HGSuitcaseInventoryService || IInventoryService || HG-only. Current implementation. Enforces strict suitcase tree boundaries on all folder and item operations. Creates system subfolders under suitcase on first use. Allows access to appearance items outside the suitcase tree. Caches suitcase tree and appearance data (5-minute expiry). Requires AvatarService in config in addition to UserAccountsService. Deletions blocked.&lt;br /&gt;
|-&lt;br /&gt;
| [[OpenSimulator Internals/Connector Architecture/Authentication Connector]] || IAuthenticationService || Password and token authentication, impersonation mechanism.&lt;br /&gt;
|-&lt;br /&gt;
| [[OpenSimulator Internals/Connector Architecture/Avatar Connector]] || IAvatarService || Appearance storage. ResetAvatar() log erroneously says &amp;quot;SetItems reply&amp;quot;.&lt;br /&gt;
|-&lt;br /&gt;
| [[OpenSimulator Internals/Connector Architecture/Friends Connector]] || IFriendsService || Friend list, online notifications.&lt;br /&gt;
|-&lt;br /&gt;
| [[OpenSimulator Internals/Connector Architecture/Grid Connector]] || IGridService || Region registration, lookup, neighbour queries.&lt;br /&gt;
|-&lt;br /&gt;
| [[OpenSimulator Internals/Connector Architecture/Simulation Connector]] || ISimulationService || Inter-simulator agent and object transfer. QueryAccess, CreateAgent, UpdateAgent, CloseAgent, CreateObject.&lt;br /&gt;
|-&lt;br /&gt;
| [[OpenSimulator Internals/Connector Architecture/UserAgent Connector]] || IUserAgentService || HG-only. Home region lookup, login to foreign grid, session verification.&lt;br /&gt;
|-&lt;br /&gt;
| [[OpenSimulator Internals/Connector Architecture/Gatekeeper Connector]] || IGatekeeperService || HG-only. Foreign grid entry point. GetHyperlinkRegion, LoginAgentToGrid.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== HG Connectors ==&lt;br /&gt;
&lt;br /&gt;
HyperGrid introduces additional connectors that wrap or replace the standard ones:&lt;br /&gt;
&lt;br /&gt;
* UserAgent Connector -- used by the source grid to contact the avatar&#039;s home grid UserAgent service during HG teleport.&lt;br /&gt;
* Gatekeeper Connector -- used to contact a foreign grid&#039;s Gatekeeper during HG destination resolution.&lt;br /&gt;
* HGAsset Connector -- used by HGInventoryAccessModule to fetch/push assets between grids (via HGAssetMapper).&lt;br /&gt;
* HGInventoryService / HGSuitcaseInventoryService -- inventory access for visiting HG users. HGSuitcaseInventoryService is current; HGInventoryService is the pre-suitcase predecessor. Both block deletions.&lt;br /&gt;
&lt;br /&gt;
Note: prior to 0.9.2, the HGAssetBroker region module handled the local/remote/foreign asset routing decision. It was retired in 0.9.2 and replaced by RegionAssetConnector. References to HGAssetBroker in older documentation and config examples are obsolete.&lt;br /&gt;
&lt;br /&gt;
These are documented in the individual connector pages above and in:&lt;br /&gt;
* [[OpenSimulator Internals/Code Map/HGEntityTransferModule]]&lt;br /&gt;
* [[OpenSimulator Internals/Code Map/InventoryAccessModule]]&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Configuration ==&lt;br /&gt;
&lt;br /&gt;
Connectors are selected in the [Architecture] ini include files:&lt;br /&gt;
&lt;br /&gt;
* config-include/StandaloneCommon.ini -- standalone mode, services loaded in-process.&lt;br /&gt;
* config-include/GridCommon.ini -- grid mode, remote connectors used.&lt;br /&gt;
* config-include/HGCommon.ini -- hypergrid additions.&lt;br /&gt;
&lt;br /&gt;
The [ServiceList] section of Robust.ini selects which ROBUST handlers are loaded. The [Modules] section of OpenSim.ini selects which connectors the simulator loads.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== See Also ==&lt;br /&gt;
&lt;br /&gt;
* [[OpenSimulator Internals/Code Map/ROBUST]]&lt;br /&gt;
* [[OpenSimulator Internals/ROBUST Services]]&lt;br /&gt;
* [[OpenSimulator Internals/Reading the Code]]&lt;br /&gt;
* [[OpenSimulator Internals/Code Map]]&lt;/div&gt;</summary>
		<author><name>Jwbshaw</name></author>
	</entry>
	<entry>
		<id>http://osimdev.org/wiki/index.php?title=OpenSimulator_Internals/Code_Map/LLUDPServer&amp;diff=120</id>
		<title>OpenSimulator Internals/Code Map/LLUDPServer</title>
		<link rel="alternate" type="text/html" href="http://osimdev.org/wiki/index.php?title=OpenSimulator_Internals/Code_Map/LLUDPServer&amp;diff=120"/>
		<updated>2026-07-09T06:27:37Z</updated>

		<summary type="html">&lt;p&gt;Jwbshaw: first&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Code Map: LLUDPServer =&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Source:&#039;&#039;&#039; &amp;lt;code&amp;gt;OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs&amp;lt;/code&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Namespace:&#039;&#039;&#039; &amp;lt;code&amp;gt;OpenSim.Region.ClientStack.LindenUDP&amp;lt;/code&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Key classes:&#039;&#039;&#039; &amp;lt;code&amp;gt;LLUDPServer&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;LLUDPServerShim&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Overview ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;LLUDPServer&amp;lt;/code&amp;gt; is the UDP transport layer for a single region. It handles&lt;br /&gt;
all inbound and outbound UDP traffic between the region and its connected viewers&lt;br /&gt;
using the Linden Lab UDP (LLUDP) protocol.&lt;br /&gt;
&lt;br /&gt;
One instance exists per region. It is not shared across regions even when multiple&lt;br /&gt;
regions run in the same simulator process.&lt;br /&gt;
&lt;br /&gt;
The region module entry point is &amp;lt;code&amp;gt;LLUDPServerShim&amp;lt;/code&amp;gt;, a thin&lt;br /&gt;
&amp;lt;code&amp;gt;INonSharedRegionModule&amp;lt;/code&amp;gt; wrapper that instantiates and owns&lt;br /&gt;
&amp;lt;code&amp;gt;LLUDPServer&amp;lt;/code&amp;gt;. The shim handles the module lifecycle; the server&lt;br /&gt;
handles the actual network I/O.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Threading Model ==&lt;br /&gt;
&lt;br /&gt;
LLUDPServer runs three persistent threads per region:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Thread !! Started by !! Purpose&lt;br /&gt;
|-&lt;br /&gt;
| Inbound receive thread || &amp;lt;code&amp;gt;StartInbound()&amp;lt;/code&amp;gt; via base class &amp;lt;code&amp;gt;OpenSimUDPBase&amp;lt;/code&amp;gt; || Receives raw UDP datagrams from the OS socket and places them on &amp;lt;code&amp;gt;packetInbox&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;IncomingPacketHandler&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;StartInbound()&amp;lt;/code&amp;gt; || Drains &amp;lt;code&amp;gt;packetInbox&amp;lt;/code&amp;gt;, dispatches packets to the correct &amp;lt;code&amp;gt;LLClientView&amp;lt;/code&amp;gt; via &amp;lt;code&amp;gt;ProcessInPacket()&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;OutgoingPacketHandler&amp;lt;/code&amp;gt; || &amp;lt;code&amp;gt;StartOutbound()&amp;lt;/code&amp;gt; || Drives per-client outbound queues, resends, ACKs, and pings on a timer loop.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
A fourth engine, &amp;lt;code&amp;gt;OqrEngine&amp;lt;/code&amp;gt; (Outgoing Queue Refill Engine), runs as a&lt;br /&gt;
&amp;lt;code&amp;gt;JobEngine&amp;lt;/code&amp;gt; thread pool to refill per-client outbound queues without&lt;br /&gt;
blocking the outgoing packet handler.&lt;br /&gt;
&lt;br /&gt;
=== Inbound path ===&lt;br /&gt;
&lt;br /&gt;
 OS socket&lt;br /&gt;
   → base class receive thread (OpenSimUDPBase)&lt;br /&gt;
     → PacketReceived()&lt;br /&gt;
       → decode + zerodecode&lt;br /&gt;
       → pending cache check (UseCircuitCode handling)&lt;br /&gt;
       → client lookup by endpoint&lt;br /&gt;
       → ACK processing (appended ACKs, PacketAck packets)&lt;br /&gt;
       → duplicate detection (PacketArchive)&lt;br /&gt;
       → packetInbox.Add()&lt;br /&gt;
         → IncomingPacketHandler thread&lt;br /&gt;
           → LLClientView.ProcessInPacket()&lt;br /&gt;
&lt;br /&gt;
UseCircuitCode packets are handled specially: they are dispatched via&lt;br /&gt;
&amp;lt;code&amp;gt;FireAndForget&amp;lt;/code&amp;gt; to &amp;lt;code&amp;gt;HandleUseCircuitCode()&amp;lt;/code&amp;gt;, which&lt;br /&gt;
authenticates the circuit, creates a new &amp;lt;code&amp;gt;LLClientView&amp;lt;/code&amp;gt; and&lt;br /&gt;
&amp;lt;code&amp;gt;LLUDPClient&amp;lt;/code&amp;gt;, and then reinjects any packets that arrived while&lt;br /&gt;
the client was being set up (held in a per-endpoint pending queue).&lt;br /&gt;
&lt;br /&gt;
=== Outbound path ===&lt;br /&gt;
&lt;br /&gt;
 Scene code / region modules&lt;br /&gt;
   → LLClientView.SendXxx()&lt;br /&gt;
     → LLUDPServer.SendPacket() / SendPacketData() / SendUDPPacket()&lt;br /&gt;
       → optional zerocoding&lt;br /&gt;
       → OutgoingPacket constructed&lt;br /&gt;
       → LLUDPClient.EnqueueOutgoing()&lt;br /&gt;
         if queue full or not throttled:&lt;br /&gt;
           → SendPacketFinal() → SyncSend() → OS socket&lt;br /&gt;
         else:&lt;br /&gt;
           → sits in per-client priority queue&lt;br /&gt;
             → OutgoingPacketHandler → DequeueOutgoing() → SendPacketFinal()&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Key Structures ==&lt;br /&gt;
&lt;br /&gt;
=== packetInbox ===&lt;br /&gt;
&lt;br /&gt;
A &amp;lt;code&amp;gt;BlockingCollection&amp;amp;lt;IncomingPacket&amp;amp;gt;&amp;lt;/code&amp;gt;. The receive thread&lt;br /&gt;
produces; the &amp;lt;code&amp;gt;IncomingPacketHandler&amp;lt;/code&amp;gt; thread consumes. Bounded only&lt;br /&gt;
by memory.&lt;br /&gt;
&lt;br /&gt;
=== TokenBucket / ThrottleRates ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;Throttle&amp;lt;/code&amp;gt; is a scene-wide token bucket capping total outbound&lt;br /&gt;
bandwidth. &amp;lt;code&amp;gt;ThrottleRates&amp;lt;/code&amp;gt; holds the per-client default rates for&lt;br /&gt;
each traffic category (resend, texture, asset, land, wind, cloud, task,&lt;br /&gt;
state, AvatarInfo). Both are configured from &amp;lt;code&amp;gt;[ClientStack.LindenUDP]&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Pending cache ===&lt;br /&gt;
&lt;br /&gt;
An &amp;lt;code&amp;gt;ExpiringCacheOS&amp;amp;lt;IPEndPoint, Queue&amp;amp;lt;UDPPacketBuffer&amp;amp;gt;&amp;amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
keyed by endpoint. While a new client is being set up after a UseCircuitCode,&lt;br /&gt;
all arriving packets for that endpoint are held here and reinjected once the&lt;br /&gt;
client is ready. Entries expire after 60 seconds.&lt;br /&gt;
&lt;br /&gt;
=== OqrEngine ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;JobEngine&amp;lt;/code&amp;gt; instance named &amp;quot;Outgoing Queue Refill Engine&amp;quot;. When a&lt;br /&gt;
client&#039;s outbound queue runs dry, a refill job is posted here rather than&lt;br /&gt;
blocking the outgoing packet handler thread. This prevents one slow client&lt;br /&gt;
from stalling outbound processing for all others.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Outgoing Packet Handler Timer Loop ==&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;OutgoingPacketHandler&amp;lt;/code&amp;gt; thread runs a continuous loop with&lt;br /&gt;
three chained timers:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Interval !! Action&lt;br /&gt;
|-&lt;br /&gt;
| 100ms || Check for unacked packets past their RTO; resend via &amp;lt;code&amp;gt;HandleUnacked()&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| 500ms || Send accumulated ACKs for all clients via &amp;lt;code&amp;gt;SendAcks()&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| 5000ms || Send ping checks to all clients via &amp;lt;code&amp;gt;SendPing()&amp;lt;/code&amp;gt;.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
If no packet was sent in a loop iteration and there are connected clients,&lt;br /&gt;
the thread sleeps 15ms. If there are no clients, it sleeps 100ms.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== ACK Handling ==&lt;br /&gt;
&lt;br /&gt;
Inbound ACKs arrive in two forms:&lt;br /&gt;
* Appended to the tail of any reliable packet (&amp;lt;code&amp;gt;Header.AppendedAcks&amp;lt;/code&amp;gt;).&lt;br /&gt;
* As explicit &amp;lt;code&amp;gt;PacketAck&amp;lt;/code&amp;gt; packets.&lt;br /&gt;
&lt;br /&gt;
Both are processed in &amp;lt;code&amp;gt;PacketReceived()&amp;lt;/code&amp;gt; and passed to&lt;br /&gt;
&amp;lt;code&amp;gt;LLUDPClient.NeedAcks.Acknowledge()&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Outbound ACKs are accumulated in &amp;lt;code&amp;gt;LLUDPClient.PendingAcks&amp;lt;/code&amp;gt; and&lt;br /&gt;
sent either appended to the next reliable outbound packet, or as a standalone&lt;br /&gt;
&amp;lt;code&amp;gt;PacketAck&amp;lt;/code&amp;gt; by the 500ms timer, whichever comes first. The&lt;br /&gt;
threshold for immediate ACK sending is 2 * MTU bytes received since the last ACK.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Reliability and Resends ==&lt;br /&gt;
&lt;br /&gt;
Reliable packets are added to &amp;lt;code&amp;gt;LLUDPClient.NeedAcks&amp;lt;/code&amp;gt; after send.&lt;br /&gt;
The 100ms timer calls &amp;lt;code&amp;gt;HandleUnacked()&amp;lt;/code&amp;gt;, which retrieves all packets&lt;br /&gt;
whose age exceeds the client&#039;s current RTO and invokes their&lt;br /&gt;
&amp;lt;code&amp;gt;UnackedMethod&amp;lt;/code&amp;gt; callback (default: &amp;lt;code&amp;gt;ResendUnacked()&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;ResendUnacked()&amp;lt;/code&amp;gt; sets the resent flag on the packet and re-enqueues&lt;br /&gt;
it in the &amp;lt;code&amp;gt;Resend&amp;lt;/code&amp;gt; throttle category.&lt;br /&gt;
&lt;br /&gt;
A client is disconnected if no packet of any kind is received within the ack&lt;br /&gt;
timeout (default 60 seconds; 300 seconds if the client is paused).&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== MTU and Zerocoding ==&lt;br /&gt;
&lt;br /&gt;
MTU is fixed at 1400 bytes. Max payload is 1200 bytes.&lt;br /&gt;
&lt;br /&gt;
Packets marked &amp;lt;code&amp;gt;MSG_ZEROCODED&amp;lt;/code&amp;gt; are compressed by run-length encoding&lt;br /&gt;
of zero bytes before send, and decoded on receive. If zerocoding makes a packet&lt;br /&gt;
larger than the unencoded form, the flag is stripped and the unencoded data&lt;br /&gt;
is sent instead.&lt;br /&gt;
&lt;br /&gt;
Packets larger than the MTU are split into multiple datagrams via&lt;br /&gt;
&amp;lt;code&amp;gt;Packet.ToBytesMultiple()&amp;lt;/code&amp;gt; where the packet type supports variable&lt;br /&gt;
blocks. &amp;lt;code&amp;gt;CoarseLocationUpdate&amp;lt;/code&amp;gt; is explicitly excluded from splitting.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Config ==&lt;br /&gt;
&lt;br /&gt;
All keys are in &amp;lt;code&amp;gt;[ClientStack.LindenUDP]&amp;lt;/code&amp;gt; in &amp;lt;code&amp;gt;OpenSim.ini&amp;lt;/code&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Key !! Default !! Purpose&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;client_socket_rcvbuf_size&amp;lt;/code&amp;gt; || 0 (OS default) || UDP receive buffer size passed to OS.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;scene_throttle_max_bps&amp;lt;/code&amp;gt; || 6250000 || Scene-wide outbound bandwidth cap in bits/sec.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;TextureSendLimit&amp;lt;/code&amp;gt; || 20 || Texture packets queued per OQR event.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DefaultRTO&amp;lt;/code&amp;gt; || 0 (auto) || Default retransmission timeout in ms.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;MaxRTO&amp;lt;/code&amp;gt; || 0 (auto) || Maximum retransmission timeout in ms.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;AckTimeout&amp;lt;/code&amp;gt; || 60 || Seconds before disconnecting a silent client.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;PausedAckTimeout&amp;lt;/code&amp;gt; || 300 || Seconds before disconnecting a paused client.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;DisableFacelights&amp;lt;/code&amp;gt; || false || Strip facelights from client updates.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;SupportViewerObjectsCache&amp;lt;/code&amp;gt; || true || Enable viewer-side object cache support.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Statistics ==&lt;br /&gt;
&lt;br /&gt;
LLUDPServer registers the following stats under the &amp;lt;code&amp;gt;clientstack&amp;lt;/code&amp;gt;&lt;br /&gt;
category (visible via the &amp;lt;code&amp;gt;show stats&amp;lt;/code&amp;gt; console command):&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;InboxPacketsCount&amp;lt;/code&amp;gt; -- packets waiting in &amp;lt;code&amp;gt;packetInbox&amp;lt;/code&amp;gt;.&lt;br /&gt;
* &amp;lt;code&amp;gt;IncomingUDPReceivesCount&amp;lt;/code&amp;gt; -- total UDP datagrams received.&lt;br /&gt;
* &amp;lt;code&amp;gt;IncomingPacketsProcessedCount&amp;lt;/code&amp;gt; -- packets dispatched to clients.&lt;br /&gt;
* &amp;lt;code&amp;gt;IncomingPacketsMalformedCount&amp;lt;/code&amp;gt; -- packets that could not be parsed.&lt;br /&gt;
* &amp;lt;code&amp;gt;IncomingPacketsOrphanedCount&amp;lt;/code&amp;gt; -- packets with no matching client.&lt;br /&gt;
* &amp;lt;code&amp;gt;IncomingPacketsResentCount&amp;lt;/code&amp;gt; -- inbound packets flagged as resends by clients.&lt;br /&gt;
* &amp;lt;code&amp;gt;OutgoingUDPSendsCount&amp;lt;/code&amp;gt; -- total UDP datagrams sent.&lt;br /&gt;
* &amp;lt;code&amp;gt;OutgoingPacketsResentCount&amp;lt;/code&amp;gt; -- packets resent due to missing ACK.&lt;br /&gt;
* &amp;lt;code&amp;gt;OutgoingPacketsQueuedCount&amp;lt;/code&amp;gt; -- packets queued across all clients.&lt;br /&gt;
* &amp;lt;code&amp;gt;OQRERequestsWaiting&amp;lt;/code&amp;gt; -- jobs pending in the OqrEngine.&lt;br /&gt;
* &amp;lt;code&amp;gt;AverageUDPProcessTime&amp;lt;/code&amp;gt; -- average ms per inbound UDP receive.&lt;br /&gt;
* &amp;lt;code&amp;gt;ClientLogoutsDueToNoReceives&amp;lt;/code&amp;gt; -- forced disconnects due to ack timeout.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== See Also ==&lt;br /&gt;
&lt;br /&gt;
* [[OpenSimulator_Internals/Package_Overview#OpenSim.Region.ClientStack|Package Overview: ClientStack]]&lt;br /&gt;
* [[OpenSimulator_Internals/Walkthroughs/Avatar_Rez_In_Region|Walkthrough: Avatar Rez In Region]]&lt;br /&gt;
* [[OpenSimulator_Internals/Walkthroughs/Avatar_Logs_Out|Walkthrough: Avatar Logs Out]]&lt;br /&gt;
&lt;br /&gt;
[[Category:OpenSimulator Internals]]&lt;/div&gt;</summary>
		<author><name>Jwbshaw</name></author>
	</entry>
	<entry>
		<id>http://osimdev.org/wiki/index.php?title=OpenSimulator_Internals/Useful_Queries&amp;diff=119</id>
		<title>OpenSimulator Internals/Useful Queries</title>
		<link rel="alternate" type="text/html" href="http://osimdev.org/wiki/index.php?title=OpenSimulator_Internals/Useful_Queries&amp;diff=119"/>
		<updated>2026-07-09T06:16:28Z</updated>

		<summary type="html">&lt;p&gt;Jwbshaw: /* Regions */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
= OpenSimulator Internals/Useful Queries =&lt;br /&gt;
&lt;br /&gt;
== Overview ==&lt;br /&gt;
&lt;br /&gt;
These queries are for grid administrators and developers working directly with MariaDB. Correlated subqueries are used to look up UUIDs by name so you don&#039;t have to remember them.&lt;br /&gt;
&lt;br /&gt;
All queries assume osimdev_robust for grid data and osimdev_t1 for region data. Substitute your region database name as needed. Examples use &amp;quot;Test User&amp;quot; as the avatar name -- substitute as required.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Connection ==&lt;br /&gt;
&lt;br /&gt;
 mysql -u opensim -p osimdev_robust&lt;br /&gt;
 USE osimdev_t1;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Grid Database (osimdev_robust) ==&lt;br /&gt;
&lt;br /&gt;
=== Users ===&lt;br /&gt;
&lt;br /&gt;
Find a user by first name:&lt;br /&gt;
&lt;br /&gt;
 SELECT PrincipalID, FirstName, LastName, Email, UserLevel,&lt;br /&gt;
        FROM_UNIXTIME(Created) AS created&lt;br /&gt;
 FROM UserAccounts&lt;br /&gt;
 WHERE FirstName LIKE &#039;Test%&#039;;&lt;br /&gt;
&lt;br /&gt;
Show login history by name:&lt;br /&gt;
&lt;br /&gt;
 SELECT FROM_UNIXTIME(Login) AS last_login,&lt;br /&gt;
        FROM_UNIXTIME(Logout) AS last_logout,&lt;br /&gt;
        Online&lt;br /&gt;
 FROM GridUser&lt;br /&gt;
 WHERE UserID = (&lt;br /&gt;
     SELECT PrincipalID FROM UserAccounts&lt;br /&gt;
     WHERE FirstName = &#039;Test&#039; AND LastName = &#039;User&#039;&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
Show home and last location by name:&lt;br /&gt;
&lt;br /&gt;
 SELECT HomePosition, HomeLookAt, LastPosition, LastLookAt,&lt;br /&gt;
        HomeRegionID, LastRegionID&lt;br /&gt;
 FROM GridUser&lt;br /&gt;
 WHERE UserID = (&lt;br /&gt;
     SELECT PrincipalID FROM UserAccounts&lt;br /&gt;
     WHERE FirstName = &#039;Test&#039; AND LastName = &#039;User&#039;&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
Who is currently online:&lt;br /&gt;
&lt;br /&gt;
 SELECT UserID, RegionID, LastSeen FROM Presence;&lt;br /&gt;
&lt;br /&gt;
=== Avatar Appearance ===&lt;br /&gt;
&lt;br /&gt;
Show all appearance data for a user by name:&lt;br /&gt;
&lt;br /&gt;
 SELECT Name, Value&lt;br /&gt;
 FROM Avatars&lt;br /&gt;
 WHERE PrincipalID = (&lt;br /&gt;
     SELECT PrincipalID FROM UserAccounts&lt;br /&gt;
     WHERE FirstName = &#039;Test&#039; AND LastName = &#039;User&#039;&lt;br /&gt;
 )&lt;br /&gt;
 ORDER BY Name;&lt;br /&gt;
&lt;br /&gt;
Show worn wearables only:&lt;br /&gt;
&lt;br /&gt;
 SELECT Name, Value&lt;br /&gt;
 FROM Avatars&lt;br /&gt;
 WHERE PrincipalID = (&lt;br /&gt;
     SELECT PrincipalID FROM UserAccounts&lt;br /&gt;
     WHERE FirstName = &#039;Test&#039; AND LastName = &#039;User&#039;&lt;br /&gt;
 )&lt;br /&gt;
 AND Name LIKE &#039;Wearable%&#039;;&lt;br /&gt;
&lt;br /&gt;
Show attachment points only:&lt;br /&gt;
&lt;br /&gt;
 SELECT Name, Value&lt;br /&gt;
 FROM Avatars&lt;br /&gt;
 WHERE PrincipalID = (&lt;br /&gt;
     SELECT PrincipalID FROM UserAccounts&lt;br /&gt;
     WHERE FirstName = &#039;Test&#039; AND LastName = &#039;User&#039;&lt;br /&gt;
 )&lt;br /&gt;
 AND Name LIKE &#039;_ap_%&#039;;&lt;br /&gt;
&lt;br /&gt;
=== Inventory ===&lt;br /&gt;
&lt;br /&gt;
Count inventory items by asset type for a user:&lt;br /&gt;
&lt;br /&gt;
 SELECT assetType, COUNT(*) AS count&lt;br /&gt;
 FROM inventoryitems&lt;br /&gt;
 WHERE avatarID = (&lt;br /&gt;
     SELECT PrincipalID FROM UserAccounts&lt;br /&gt;
     WHERE FirstName = &#039;Test&#039; AND LastName = &#039;User&#039;&lt;br /&gt;
 )&lt;br /&gt;
 GROUP BY assetType&lt;br /&gt;
 ORDER BY count DESC;&lt;br /&gt;
&lt;br /&gt;
Find an inventory item by name:&lt;br /&gt;
&lt;br /&gt;
 SELECT inventoryName, assetType, assetID, parentFolderID&lt;br /&gt;
 FROM inventoryitems&lt;br /&gt;
 WHERE avatarID = (&lt;br /&gt;
     SELECT PrincipalID FROM UserAccounts&lt;br /&gt;
     WHERE FirstName = &#039;Test&#039; AND LastName = &#039;User&#039;&lt;br /&gt;
 )&lt;br /&gt;
 AND inventoryName LIKE &#039;%house%&#039;;&lt;br /&gt;
&lt;br /&gt;
List top-level inventory folders for a user:&lt;br /&gt;
&lt;br /&gt;
 SELECT folderName, type, folderID&lt;br /&gt;
 FROM inventoryfolders&lt;br /&gt;
 WHERE agentID = (&lt;br /&gt;
     SELECT PrincipalID FROM UserAccounts&lt;br /&gt;
     WHERE FirstName = &#039;Test&#039; AND LastName = &#039;User&#039;&lt;br /&gt;
 )&lt;br /&gt;
 AND parentFolderID = (&lt;br /&gt;
     SELECT folderID FROM inventoryfolders&lt;br /&gt;
     WHERE agentID = (&lt;br /&gt;
         SELECT PrincipalID FROM UserAccounts&lt;br /&gt;
         WHERE FirstName = &#039;Test&#039; AND LastName = &#039;User&#039;&lt;br /&gt;
     )&lt;br /&gt;
     AND type = 8&lt;br /&gt;
 )&lt;br /&gt;
 ORDER BY folderName;&lt;br /&gt;
&lt;br /&gt;
=== Assets ===&lt;br /&gt;
&lt;br /&gt;
Count all assets by type:&lt;br /&gt;
&lt;br /&gt;
 SELECT assetType, COUNT(*) AS count&lt;br /&gt;
 FROM assets&lt;br /&gt;
 GROUP BY assetType&lt;br /&gt;
 ORDER BY count DESC;&lt;br /&gt;
&lt;br /&gt;
Find assets created by a user:&lt;br /&gt;
&lt;br /&gt;
 SELECT id, name, assetType, FROM_UNIXTIME(create_time) AS created&lt;br /&gt;
 FROM assets&lt;br /&gt;
 WHERE CreatorID = (&lt;br /&gt;
     SELECT PrincipalID FROM UserAccounts&lt;br /&gt;
     WHERE FirstName = &#039;Test&#039; AND LastName = &#039;User&#039;&lt;br /&gt;
 )&lt;br /&gt;
 ORDER BY create_time DESC;&lt;br /&gt;
&lt;br /&gt;
Find an asset by name:&lt;br /&gt;
&lt;br /&gt;
 SELECT id, name, assetType, FROM_UNIXTIME(create_time) AS created&lt;br /&gt;
 FROM assets&lt;br /&gt;
 WHERE name LIKE &#039;%note%&#039;;&lt;br /&gt;
&lt;br /&gt;
=== Friends ===&lt;br /&gt;
&lt;br /&gt;
Show friends for a user:&lt;br /&gt;
&lt;br /&gt;
 SELECT Friend, Flags&lt;br /&gt;
 FROM Friends&lt;br /&gt;
 WHERE PrincipalID = (&lt;br /&gt;
     SELECT PrincipalID FROM UserAccounts&lt;br /&gt;
     WHERE FirstName = &#039;Test&#039; AND LastName = &#039;User&#039;&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
=== Tokens ===&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;tokens&amp;lt;/code&amp;gt; table exists in the schema but is not used as of 0.9.x.&lt;br /&gt;
Do not rely on its contents.&lt;br /&gt;
&lt;br /&gt;
=== Regions ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Note:&#039;&#039;&#039; In standalone deployments the &amp;lt;code&amp;gt;regions&amp;lt;/code&amp;gt; table is not&lt;br /&gt;
written. Region data exists only in memory for the duration of the process.&lt;br /&gt;
These queries return no rows on a standalone.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
List all registered regions:&lt;br /&gt;
&lt;br /&gt;
 SELECT regionName,&lt;br /&gt;
        locX/256 AS coord_x, locY/256 AS coord_y,&lt;br /&gt;
        sizeX, sizeY, flags,&lt;br /&gt;
        FROM_UNIXTIME(last_seen) AS last_seen&lt;br /&gt;
 FROM regions;&lt;br /&gt;
&lt;br /&gt;
Check if a region is online:&lt;br /&gt;
&lt;br /&gt;
 SELECT regionName, flags &amp;amp; 4 AS online&lt;br /&gt;
 FROM regions&lt;br /&gt;
 WHERE regionName = &#039;T1&#039;;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Region Database (osimdev_t1) ==&lt;br /&gt;
&lt;br /&gt;
=== Objects ===&lt;br /&gt;
&lt;br /&gt;
List all objects with world position (root prims only):&lt;br /&gt;
&lt;br /&gt;
 SELECT Name, UUID, GroupPositionX, GroupPositionY, GroupPositionZ&lt;br /&gt;
 FROM prims&lt;br /&gt;
 WHERE UUID = SceneGroupID&lt;br /&gt;
 ORDER BY Name;&lt;br /&gt;
&lt;br /&gt;
Count prims per object (root prims only, sorted by size):&lt;br /&gt;
&lt;br /&gt;
 SELECT p.Name, p.SceneGroupID,&lt;br /&gt;
        p.GroupPositionX, p.GroupPositionY, p.GroupPositionZ,&lt;br /&gt;
        COUNT(*) AS prim_count&lt;br /&gt;
 FROM prims p&lt;br /&gt;
 WHERE p.UUID = p.SceneGroupID&lt;br /&gt;
 GROUP BY p.SceneGroupID, p.Name, p.GroupPositionX, p.GroupPositionY, p.GroupPositionZ&lt;br /&gt;
 ORDER BY prim_count DESC;&lt;br /&gt;
&lt;br /&gt;
Find an object by name:&lt;br /&gt;
&lt;br /&gt;
 SELECT UUID, GroupPositionX, GroupPositionY, GroupPositionZ&lt;br /&gt;
 FROM prims&lt;br /&gt;
 WHERE UUID = SceneGroupID&lt;br /&gt;
 AND Name LIKE &#039;%house%&#039;;&lt;br /&gt;
&lt;br /&gt;
List all prims in a named object:&lt;br /&gt;
&lt;br /&gt;
 SELECT UUID, Name, LinkNumber, PositionX, PositionY, PositionZ&lt;br /&gt;
 FROM prims&lt;br /&gt;
 WHERE SceneGroupID = (&lt;br /&gt;
     SELECT UUID FROM prims&lt;br /&gt;
     WHERE UUID = SceneGroupID AND Name LIKE &#039;%Brown House%&#039;&lt;br /&gt;
     LIMIT 1&lt;br /&gt;
 )&lt;br /&gt;
 ORDER BY LinkNumber;&lt;br /&gt;
&lt;br /&gt;
Find objects owned by a specific user:&lt;br /&gt;
&lt;br /&gt;
 SELECT Name, UUID, GroupPositionX, GroupPositionY, GroupPositionZ&lt;br /&gt;
 FROM prims&lt;br /&gt;
 WHERE UUID = SceneGroupID&lt;br /&gt;
 AND OwnerID = (&lt;br /&gt;
     SELECT PrincipalID FROM osimdev_robust.UserAccounts&lt;br /&gt;
     WHERE FirstName = &#039;Test&#039; AND LastName = &#039;User&#039;&lt;br /&gt;
 )&lt;br /&gt;
 ORDER BY Name;&lt;br /&gt;
&lt;br /&gt;
=== Object Contents (Task Inventory) ===&lt;br /&gt;
&lt;br /&gt;
Show contents of a named object:&lt;br /&gt;
&lt;br /&gt;
 SELECT pi.name, pi.assetType, pi.assetID&lt;br /&gt;
 FROM primitems pi&lt;br /&gt;
 WHERE pi.primID IN (&lt;br /&gt;
     SELECT UUID FROM prims&lt;br /&gt;
     WHERE SceneGroupID = (&lt;br /&gt;
         SELECT UUID FROM prims&lt;br /&gt;
         WHERE UUID = SceneGroupID AND Name LIKE &#039;%Box%&#039;&lt;br /&gt;
         LIMIT 1&lt;br /&gt;
     )&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
Count task inventory items by type across all objects:&lt;br /&gt;
&lt;br /&gt;
 SELECT pi.assetType, COUNT(*) AS count&lt;br /&gt;
 FROM primitems pi&lt;br /&gt;
 GROUP BY pi.assetType&lt;br /&gt;
 ORDER BY count DESC;&lt;br /&gt;
&lt;br /&gt;
Show all objects that contain scripts:&lt;br /&gt;
&lt;br /&gt;
 SELECT DISTINCT p.Name, p.UUID, p.GroupPositionX, p.GroupPositionY, p.GroupPositionZ&lt;br /&gt;
 FROM prims p&lt;br /&gt;
 JOIN primitems pi ON pi.primID = p.UUID&lt;br /&gt;
 WHERE p.UUID = p.SceneGroupID&lt;br /&gt;
 AND pi.assetType = 10&lt;br /&gt;
 ORDER BY p.Name;&lt;br /&gt;
&lt;br /&gt;
=== Prim Shape ===&lt;br /&gt;
&lt;br /&gt;
Show shape for a named object:&lt;br /&gt;
&lt;br /&gt;
 SELECT p.Name, p.LinkNumber,&lt;br /&gt;
        ps.ScaleX, ps.ScaleY, ps.ScaleZ,&lt;br /&gt;
        ps.PCode, ps.Shape, ps.ProfileCurve, ps.PathCurve&lt;br /&gt;
 FROM primshapes ps&lt;br /&gt;
 JOIN prims p ON ps.UUID = p.UUID&lt;br /&gt;
 WHERE p.SceneGroupID = (&lt;br /&gt;
     SELECT UUID FROM prims&lt;br /&gt;
     WHERE UUID = SceneGroupID AND Name = &#039;Object&#039;&lt;br /&gt;
     LIMIT 1&lt;br /&gt;
 )&lt;br /&gt;
 ORDER BY p.LinkNumber;&lt;br /&gt;
&lt;br /&gt;
=== Persistence State ===&lt;br /&gt;
&lt;br /&gt;
Find objects with pending changes (not yet persisted):&lt;br /&gt;
&lt;br /&gt;
 SELECT Name, UUID, GroupPositionX, GroupPositionY, GroupPositionZ&lt;br /&gt;
 FROM prims&lt;br /&gt;
 WHERE UUID = SceneGroupID&lt;br /&gt;
 AND RezzerID IS NOT NULL&lt;br /&gt;
 ORDER BY Name;&lt;br /&gt;
&lt;br /&gt;
=== Land ===&lt;br /&gt;
&lt;br /&gt;
Show all parcels:&lt;br /&gt;
&lt;br /&gt;
 SELECT LocalLandID, Name, OwnerUUID, Area, LandStatus,&lt;br /&gt;
        UserLocationX, UserLocationY, UserLocationZ&lt;br /&gt;
 FROM land;&lt;br /&gt;
&lt;br /&gt;
=== Terrain ===&lt;br /&gt;
&lt;br /&gt;
Check terrain revision and blob size:&lt;br /&gt;
&lt;br /&gt;
 SELECT RegionUUID, Revision, LENGTH(Heightfield) AS bytes&lt;br /&gt;
 FROM terrain;&lt;br /&gt;
&lt;br /&gt;
=== Estate ===&lt;br /&gt;
&lt;br /&gt;
All estate tables are in the region database (osimdev_t1), not the grid database.&lt;br /&gt;
&lt;br /&gt;
Show estate settings:&lt;br /&gt;
&lt;br /&gt;
 SELECT EstateID, EstateName, EstateOwner,&lt;br /&gt;
        PublicAccess, AllowVoice, DenyMinors,&lt;br /&gt;
        AllowDirectTeleport, AllowSetHome, AllowLandmark,&lt;br /&gt;
        AllowParcelChanges, AllowEnviromentOverride,&lt;br /&gt;
        FixedSun, SunPosition, UseGlobalTime,&lt;br /&gt;
        DenyAnonymous, DenyIdentified, DenyTransacted&lt;br /&gt;
 FROM estate_settings;&lt;br /&gt;
&lt;br /&gt;
Show which region belongs to which estate:&lt;br /&gt;
&lt;br /&gt;
 SELECT r.regionName, m.EstateID, e.EstateName&lt;br /&gt;
 FROM estate_map m&lt;br /&gt;
 JOIN estate_settings e ON e.EstateID = m.EstateID&lt;br /&gt;
 JOIN osimdev_robust.regions r ON r.uuid = m.RegionID;&lt;br /&gt;
&lt;br /&gt;
List estate managers by name:&lt;br /&gt;
&lt;br /&gt;
 SELECT e.EstateName, em.uuid AS manager_uuid,&lt;br /&gt;
        ua.FirstName, ua.LastName&lt;br /&gt;
 FROM estate_managers em&lt;br /&gt;
 JOIN estate_settings e ON e.EstateID = em.EstateID&lt;br /&gt;
 LEFT JOIN osimdev_robust.UserAccounts ua ON ua.PrincipalID = em.uuid&lt;br /&gt;
 ORDER BY e.EstateName, ua.LastName;&lt;br /&gt;
&lt;br /&gt;
List allowed groups:&lt;br /&gt;
&lt;br /&gt;
 SELECT e.EstateName, eg.uuid AS group_uuid&lt;br /&gt;
 FROM estate_groups eg&lt;br /&gt;
 JOIN estate_settings e ON e.EstateID = eg.EstateID&lt;br /&gt;
 ORDER BY e.EstateName;&lt;br /&gt;
&lt;br /&gt;
List allowed users:&lt;br /&gt;
&lt;br /&gt;
 SELECT e.EstateName, eu.uuid AS user_uuid,&lt;br /&gt;
        ua.FirstName, ua.LastName&lt;br /&gt;
 FROM estate_users eu&lt;br /&gt;
 JOIN estate_settings e ON e.EstateID = eu.EstateID&lt;br /&gt;
 LEFT JOIN osimdev_robust.UserAccounts ua ON ua.PrincipalID = eu.uuid&lt;br /&gt;
 ORDER BY e.EstateName, ua.LastName;&lt;br /&gt;
&lt;br /&gt;
List ban entries:&lt;br /&gt;
&lt;br /&gt;
 SELECT e.EstateName,&lt;br /&gt;
        eb.bannedUUID, eb.bannedIp, eb.bannedIpHostMask,&lt;br /&gt;
        eb.banningUUID, FROM_UNIXTIME(eb.banTime) AS banned_at&lt;br /&gt;
 FROM estateban eb&lt;br /&gt;
 JOIN estate_settings e ON e.EstateID = eb.EstateID&lt;br /&gt;
 ORDER BY e.EstateName, eb.banTime DESC;&lt;br /&gt;
&lt;br /&gt;
== Cross-Database Queries ==&lt;br /&gt;
&lt;br /&gt;
Objects owned by a named user (cross-database):&lt;br /&gt;
&lt;br /&gt;
 SELECT p.Name, p.UUID, p.GroupPositionX, p.GroupPositionY, p.GroupPositionZ&lt;br /&gt;
 FROM osimdev_t1.prims p&lt;br /&gt;
 WHERE p.UUID = p.SceneGroupID&lt;br /&gt;
 AND p.OwnerID = (&lt;br /&gt;
     SELECT PrincipalID FROM osimdev_robust.UserAccounts&lt;br /&gt;
     WHERE FirstName = &#039;Test&#039; AND LastName = &#039;User&#039;&lt;br /&gt;
 )&lt;br /&gt;
 ORDER BY p.Name;&lt;br /&gt;
&lt;br /&gt;
Inventory items for an object currently in the region:&lt;br /&gt;
&lt;br /&gt;
 SELECT pi.name, pi.assetType, a.name AS asset_name&lt;br /&gt;
 FROM osimdev_t1.primitems pi&lt;br /&gt;
 JOIN osimdev_robust.assets a ON a.id = pi.assetID&lt;br /&gt;
 WHERE pi.primID = (&lt;br /&gt;
     SELECT UUID FROM osimdev_t1.prims&lt;br /&gt;
     WHERE UUID = SceneGroupID AND Name LIKE &#039;%Box%&#039;&lt;br /&gt;
     LIMIT 1&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Conversions ==&lt;br /&gt;
&lt;br /&gt;
Unix timestamp to datetime:&lt;br /&gt;
&lt;br /&gt;
 SELECT FROM_UNIXTIME(1782133981);&lt;br /&gt;
&lt;br /&gt;
Region metres to region coordinates:&lt;br /&gt;
&lt;br /&gt;
 SELECT locX/256 AS coord_x, locY/256 AS coord_y FROM regions;&lt;br /&gt;
&lt;br /&gt;
Asset type numbers:&lt;br /&gt;
&lt;br /&gt;
 0  = texture&lt;br /&gt;
 2  = sound&lt;br /&gt;
 3  = landmark&lt;br /&gt;
 5  = clothing&lt;br /&gt;
 6  = object&lt;br /&gt;
 7  = notecard&lt;br /&gt;
 10 = script (LSL)&lt;br /&gt;
 13 = body part&lt;br /&gt;
 20 = animation&lt;br /&gt;
 24 = link (inventory link)&lt;br /&gt;
 25 = mesh&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== See Also ==&lt;br /&gt;
&lt;br /&gt;
* [[OpenSimulator Internals/Databases]]&lt;br /&gt;
* [[OpenSimulator Internals/Walkthroughs/Avatar Rezzes Box]]&lt;br /&gt;
* [[OpenSimulator Internals/Walkthroughs/Avatar Derezzes Object]]&lt;br /&gt;
* [[OpenSimulator Internals/Walkthroughs/Avatar Acquires Inventory]]&lt;br /&gt;
* [[OpenSimulator Internals/Data Dictionaries]]&lt;/div&gt;</summary>
		<author><name>Jwbshaw</name></author>
	</entry>
	<entry>
		<id>http://osimdev.org/wiki/index.php?title=OpenSimulator_Internals/Useful_Queries&amp;diff=118</id>
		<title>OpenSimulator Internals/Useful Queries</title>
		<link rel="alternate" type="text/html" href="http://osimdev.org/wiki/index.php?title=OpenSimulator_Internals/Useful_Queries&amp;diff=118"/>
		<updated>2026-07-09T06:12:23Z</updated>

		<summary type="html">&lt;p&gt;Jwbshaw: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
= OpenSimulator Internals/Useful Queries =&lt;br /&gt;
&lt;br /&gt;
== Overview ==&lt;br /&gt;
&lt;br /&gt;
These queries are for grid administrators and developers working directly with MariaDB. Correlated subqueries are used to look up UUIDs by name so you don&#039;t have to remember them.&lt;br /&gt;
&lt;br /&gt;
All queries assume osimdev_robust for grid data and osimdev_t1 for region data. Substitute your region database name as needed. Examples use &amp;quot;Test User&amp;quot; as the avatar name -- substitute as required.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Connection ==&lt;br /&gt;
&lt;br /&gt;
 mysql -u opensim -p osimdev_robust&lt;br /&gt;
 USE osimdev_t1;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Grid Database (osimdev_robust) ==&lt;br /&gt;
&lt;br /&gt;
=== Users ===&lt;br /&gt;
&lt;br /&gt;
Find a user by first name:&lt;br /&gt;
&lt;br /&gt;
 SELECT PrincipalID, FirstName, LastName, Email, UserLevel,&lt;br /&gt;
        FROM_UNIXTIME(Created) AS created&lt;br /&gt;
 FROM UserAccounts&lt;br /&gt;
 WHERE FirstName LIKE &#039;Test%&#039;;&lt;br /&gt;
&lt;br /&gt;
Show login history by name:&lt;br /&gt;
&lt;br /&gt;
 SELECT FROM_UNIXTIME(Login) AS last_login,&lt;br /&gt;
        FROM_UNIXTIME(Logout) AS last_logout,&lt;br /&gt;
        Online&lt;br /&gt;
 FROM GridUser&lt;br /&gt;
 WHERE UserID = (&lt;br /&gt;
     SELECT PrincipalID FROM UserAccounts&lt;br /&gt;
     WHERE FirstName = &#039;Test&#039; AND LastName = &#039;User&#039;&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
Show home and last location by name:&lt;br /&gt;
&lt;br /&gt;
 SELECT HomePosition, HomeLookAt, LastPosition, LastLookAt,&lt;br /&gt;
        HomeRegionID, LastRegionID&lt;br /&gt;
 FROM GridUser&lt;br /&gt;
 WHERE UserID = (&lt;br /&gt;
     SELECT PrincipalID FROM UserAccounts&lt;br /&gt;
     WHERE FirstName = &#039;Test&#039; AND LastName = &#039;User&#039;&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
Who is currently online:&lt;br /&gt;
&lt;br /&gt;
 SELECT UserID, RegionID, LastSeen FROM Presence;&lt;br /&gt;
&lt;br /&gt;
=== Avatar Appearance ===&lt;br /&gt;
&lt;br /&gt;
Show all appearance data for a user by name:&lt;br /&gt;
&lt;br /&gt;
 SELECT Name, Value&lt;br /&gt;
 FROM Avatars&lt;br /&gt;
 WHERE PrincipalID = (&lt;br /&gt;
     SELECT PrincipalID FROM UserAccounts&lt;br /&gt;
     WHERE FirstName = &#039;Test&#039; AND LastName = &#039;User&#039;&lt;br /&gt;
 )&lt;br /&gt;
 ORDER BY Name;&lt;br /&gt;
&lt;br /&gt;
Show worn wearables only:&lt;br /&gt;
&lt;br /&gt;
 SELECT Name, Value&lt;br /&gt;
 FROM Avatars&lt;br /&gt;
 WHERE PrincipalID = (&lt;br /&gt;
     SELECT PrincipalID FROM UserAccounts&lt;br /&gt;
     WHERE FirstName = &#039;Test&#039; AND LastName = &#039;User&#039;&lt;br /&gt;
 )&lt;br /&gt;
 AND Name LIKE &#039;Wearable%&#039;;&lt;br /&gt;
&lt;br /&gt;
Show attachment points only:&lt;br /&gt;
&lt;br /&gt;
 SELECT Name, Value&lt;br /&gt;
 FROM Avatars&lt;br /&gt;
 WHERE PrincipalID = (&lt;br /&gt;
     SELECT PrincipalID FROM UserAccounts&lt;br /&gt;
     WHERE FirstName = &#039;Test&#039; AND LastName = &#039;User&#039;&lt;br /&gt;
 )&lt;br /&gt;
 AND Name LIKE &#039;_ap_%&#039;;&lt;br /&gt;
&lt;br /&gt;
=== Inventory ===&lt;br /&gt;
&lt;br /&gt;
Count inventory items by asset type for a user:&lt;br /&gt;
&lt;br /&gt;
 SELECT assetType, COUNT(*) AS count&lt;br /&gt;
 FROM inventoryitems&lt;br /&gt;
 WHERE avatarID = (&lt;br /&gt;
     SELECT PrincipalID FROM UserAccounts&lt;br /&gt;
     WHERE FirstName = &#039;Test&#039; AND LastName = &#039;User&#039;&lt;br /&gt;
 )&lt;br /&gt;
 GROUP BY assetType&lt;br /&gt;
 ORDER BY count DESC;&lt;br /&gt;
&lt;br /&gt;
Find an inventory item by name:&lt;br /&gt;
&lt;br /&gt;
 SELECT inventoryName, assetType, assetID, parentFolderID&lt;br /&gt;
 FROM inventoryitems&lt;br /&gt;
 WHERE avatarID = (&lt;br /&gt;
     SELECT PrincipalID FROM UserAccounts&lt;br /&gt;
     WHERE FirstName = &#039;Test&#039; AND LastName = &#039;User&#039;&lt;br /&gt;
 )&lt;br /&gt;
 AND inventoryName LIKE &#039;%house%&#039;;&lt;br /&gt;
&lt;br /&gt;
List top-level inventory folders for a user:&lt;br /&gt;
&lt;br /&gt;
 SELECT folderName, type, folderID&lt;br /&gt;
 FROM inventoryfolders&lt;br /&gt;
 WHERE agentID = (&lt;br /&gt;
     SELECT PrincipalID FROM UserAccounts&lt;br /&gt;
     WHERE FirstName = &#039;Test&#039; AND LastName = &#039;User&#039;&lt;br /&gt;
 )&lt;br /&gt;
 AND parentFolderID = (&lt;br /&gt;
     SELECT folderID FROM inventoryfolders&lt;br /&gt;
     WHERE agentID = (&lt;br /&gt;
         SELECT PrincipalID FROM UserAccounts&lt;br /&gt;
         WHERE FirstName = &#039;Test&#039; AND LastName = &#039;User&#039;&lt;br /&gt;
     )&lt;br /&gt;
     AND type = 8&lt;br /&gt;
 )&lt;br /&gt;
 ORDER BY folderName;&lt;br /&gt;
&lt;br /&gt;
=== Assets ===&lt;br /&gt;
&lt;br /&gt;
Count all assets by type:&lt;br /&gt;
&lt;br /&gt;
 SELECT assetType, COUNT(*) AS count&lt;br /&gt;
 FROM assets&lt;br /&gt;
 GROUP BY assetType&lt;br /&gt;
 ORDER BY count DESC;&lt;br /&gt;
&lt;br /&gt;
Find assets created by a user:&lt;br /&gt;
&lt;br /&gt;
 SELECT id, name, assetType, FROM_UNIXTIME(create_time) AS created&lt;br /&gt;
 FROM assets&lt;br /&gt;
 WHERE CreatorID = (&lt;br /&gt;
     SELECT PrincipalID FROM UserAccounts&lt;br /&gt;
     WHERE FirstName = &#039;Test&#039; AND LastName = &#039;User&#039;&lt;br /&gt;
 )&lt;br /&gt;
 ORDER BY create_time DESC;&lt;br /&gt;
&lt;br /&gt;
Find an asset by name:&lt;br /&gt;
&lt;br /&gt;
 SELECT id, name, assetType, FROM_UNIXTIME(create_time) AS created&lt;br /&gt;
 FROM assets&lt;br /&gt;
 WHERE name LIKE &#039;%note%&#039;;&lt;br /&gt;
&lt;br /&gt;
=== Friends ===&lt;br /&gt;
&lt;br /&gt;
Show friends for a user:&lt;br /&gt;
&lt;br /&gt;
 SELECT Friend, Flags&lt;br /&gt;
 FROM Friends&lt;br /&gt;
 WHERE PrincipalID = (&lt;br /&gt;
     SELECT PrincipalID FROM UserAccounts&lt;br /&gt;
     WHERE FirstName = &#039;Test&#039; AND LastName = &#039;User&#039;&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
=== Tokens ===&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;code&amp;gt;tokens&amp;lt;/code&amp;gt; table exists in the schema but is not used as of 0.9.x.&lt;br /&gt;
Do not rely on its contents.&lt;br /&gt;
&lt;br /&gt;
=== Regions ===&lt;br /&gt;
&lt;br /&gt;
List all registered regions:&lt;br /&gt;
&lt;br /&gt;
 SELECT regionName,&lt;br /&gt;
        locX/256 AS coord_x, locY/256 AS coord_y,&lt;br /&gt;
        sizeX, sizeY, flags,&lt;br /&gt;
        FROM_UNIXTIME(last_seen) AS last_seen&lt;br /&gt;
 FROM regions;&lt;br /&gt;
&lt;br /&gt;
Check if a region is online:&lt;br /&gt;
&lt;br /&gt;
 SELECT regionName, flags &amp;amp; 4 AS online&lt;br /&gt;
 FROM regions&lt;br /&gt;
 WHERE regionName = &#039;T1&#039;;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Region Database (osimdev_t1) ==&lt;br /&gt;
&lt;br /&gt;
=== Objects ===&lt;br /&gt;
&lt;br /&gt;
List all objects with world position (root prims only):&lt;br /&gt;
&lt;br /&gt;
 SELECT Name, UUID, GroupPositionX, GroupPositionY, GroupPositionZ&lt;br /&gt;
 FROM prims&lt;br /&gt;
 WHERE UUID = SceneGroupID&lt;br /&gt;
 ORDER BY Name;&lt;br /&gt;
&lt;br /&gt;
Count prims per object (root prims only, sorted by size):&lt;br /&gt;
&lt;br /&gt;
 SELECT p.Name, p.SceneGroupID,&lt;br /&gt;
        p.GroupPositionX, p.GroupPositionY, p.GroupPositionZ,&lt;br /&gt;
        COUNT(*) AS prim_count&lt;br /&gt;
 FROM prims p&lt;br /&gt;
 WHERE p.UUID = p.SceneGroupID&lt;br /&gt;
 GROUP BY p.SceneGroupID, p.Name, p.GroupPositionX, p.GroupPositionY, p.GroupPositionZ&lt;br /&gt;
 ORDER BY prim_count DESC;&lt;br /&gt;
&lt;br /&gt;
Find an object by name:&lt;br /&gt;
&lt;br /&gt;
 SELECT UUID, GroupPositionX, GroupPositionY, GroupPositionZ&lt;br /&gt;
 FROM prims&lt;br /&gt;
 WHERE UUID = SceneGroupID&lt;br /&gt;
 AND Name LIKE &#039;%house%&#039;;&lt;br /&gt;
&lt;br /&gt;
List all prims in a named object:&lt;br /&gt;
&lt;br /&gt;
 SELECT UUID, Name, LinkNumber, PositionX, PositionY, PositionZ&lt;br /&gt;
 FROM prims&lt;br /&gt;
 WHERE SceneGroupID = (&lt;br /&gt;
     SELECT UUID FROM prims&lt;br /&gt;
     WHERE UUID = SceneGroupID AND Name LIKE &#039;%Brown House%&#039;&lt;br /&gt;
     LIMIT 1&lt;br /&gt;
 )&lt;br /&gt;
 ORDER BY LinkNumber;&lt;br /&gt;
&lt;br /&gt;
Find objects owned by a specific user:&lt;br /&gt;
&lt;br /&gt;
 SELECT Name, UUID, GroupPositionX, GroupPositionY, GroupPositionZ&lt;br /&gt;
 FROM prims&lt;br /&gt;
 WHERE UUID = SceneGroupID&lt;br /&gt;
 AND OwnerID = (&lt;br /&gt;
     SELECT PrincipalID FROM osimdev_robust.UserAccounts&lt;br /&gt;
     WHERE FirstName = &#039;Test&#039; AND LastName = &#039;User&#039;&lt;br /&gt;
 )&lt;br /&gt;
 ORDER BY Name;&lt;br /&gt;
&lt;br /&gt;
=== Object Contents (Task Inventory) ===&lt;br /&gt;
&lt;br /&gt;
Show contents of a named object:&lt;br /&gt;
&lt;br /&gt;
 SELECT pi.name, pi.assetType, pi.assetID&lt;br /&gt;
 FROM primitems pi&lt;br /&gt;
 WHERE pi.primID IN (&lt;br /&gt;
     SELECT UUID FROM prims&lt;br /&gt;
     WHERE SceneGroupID = (&lt;br /&gt;
         SELECT UUID FROM prims&lt;br /&gt;
         WHERE UUID = SceneGroupID AND Name LIKE &#039;%Box%&#039;&lt;br /&gt;
         LIMIT 1&lt;br /&gt;
     )&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
Count task inventory items by type across all objects:&lt;br /&gt;
&lt;br /&gt;
 SELECT pi.assetType, COUNT(*) AS count&lt;br /&gt;
 FROM primitems pi&lt;br /&gt;
 GROUP BY pi.assetType&lt;br /&gt;
 ORDER BY count DESC;&lt;br /&gt;
&lt;br /&gt;
Show all objects that contain scripts:&lt;br /&gt;
&lt;br /&gt;
 SELECT DISTINCT p.Name, p.UUID, p.GroupPositionX, p.GroupPositionY, p.GroupPositionZ&lt;br /&gt;
 FROM prims p&lt;br /&gt;
 JOIN primitems pi ON pi.primID = p.UUID&lt;br /&gt;
 WHERE p.UUID = p.SceneGroupID&lt;br /&gt;
 AND pi.assetType = 10&lt;br /&gt;
 ORDER BY p.Name;&lt;br /&gt;
&lt;br /&gt;
=== Prim Shape ===&lt;br /&gt;
&lt;br /&gt;
Show shape for a named object:&lt;br /&gt;
&lt;br /&gt;
 SELECT p.Name, p.LinkNumber,&lt;br /&gt;
        ps.ScaleX, ps.ScaleY, ps.ScaleZ,&lt;br /&gt;
        ps.PCode, ps.Shape, ps.ProfileCurve, ps.PathCurve&lt;br /&gt;
 FROM primshapes ps&lt;br /&gt;
 JOIN prims p ON ps.UUID = p.UUID&lt;br /&gt;
 WHERE p.SceneGroupID = (&lt;br /&gt;
     SELECT UUID FROM prims&lt;br /&gt;
     WHERE UUID = SceneGroupID AND Name = &#039;Object&#039;&lt;br /&gt;
     LIMIT 1&lt;br /&gt;
 )&lt;br /&gt;
 ORDER BY p.LinkNumber;&lt;br /&gt;
&lt;br /&gt;
=== Persistence State ===&lt;br /&gt;
&lt;br /&gt;
Find objects with pending changes (not yet persisted):&lt;br /&gt;
&lt;br /&gt;
 SELECT Name, UUID, GroupPositionX, GroupPositionY, GroupPositionZ&lt;br /&gt;
 FROM prims&lt;br /&gt;
 WHERE UUID = SceneGroupID&lt;br /&gt;
 AND RezzerID IS NOT NULL&lt;br /&gt;
 ORDER BY Name;&lt;br /&gt;
&lt;br /&gt;
=== Land ===&lt;br /&gt;
&lt;br /&gt;
Show all parcels:&lt;br /&gt;
&lt;br /&gt;
 SELECT LocalLandID, Name, OwnerUUID, Area, LandStatus,&lt;br /&gt;
        UserLocationX, UserLocationY, UserLocationZ&lt;br /&gt;
 FROM land;&lt;br /&gt;
&lt;br /&gt;
=== Terrain ===&lt;br /&gt;
&lt;br /&gt;
Check terrain revision and blob size:&lt;br /&gt;
&lt;br /&gt;
 SELECT RegionUUID, Revision, LENGTH(Heightfield) AS bytes&lt;br /&gt;
 FROM terrain;&lt;br /&gt;
&lt;br /&gt;
=== Estate ===&lt;br /&gt;
&lt;br /&gt;
All estate tables are in the region database (osimdev_t1), not the grid database.&lt;br /&gt;
&lt;br /&gt;
Show estate settings:&lt;br /&gt;
&lt;br /&gt;
 SELECT EstateID, EstateName, EstateOwner,&lt;br /&gt;
        PublicAccess, AllowVoice, DenyMinors,&lt;br /&gt;
        AllowDirectTeleport, AllowSetHome, AllowLandmark,&lt;br /&gt;
        AllowParcelChanges, AllowEnviromentOverride,&lt;br /&gt;
        FixedSun, SunPosition, UseGlobalTime,&lt;br /&gt;
        DenyAnonymous, DenyIdentified, DenyTransacted&lt;br /&gt;
 FROM estate_settings;&lt;br /&gt;
&lt;br /&gt;
Show which region belongs to which estate:&lt;br /&gt;
&lt;br /&gt;
 SELECT r.regionName, m.EstateID, e.EstateName&lt;br /&gt;
 FROM estate_map m&lt;br /&gt;
 JOIN estate_settings e ON e.EstateID = m.EstateID&lt;br /&gt;
 JOIN osimdev_robust.regions r ON r.uuid = m.RegionID;&lt;br /&gt;
&lt;br /&gt;
List estate managers by name:&lt;br /&gt;
&lt;br /&gt;
 SELECT e.EstateName, em.uuid AS manager_uuid,&lt;br /&gt;
        ua.FirstName, ua.LastName&lt;br /&gt;
 FROM estate_managers em&lt;br /&gt;
 JOIN estate_settings e ON e.EstateID = em.EstateID&lt;br /&gt;
 LEFT JOIN osimdev_robust.UserAccounts ua ON ua.PrincipalID = em.uuid&lt;br /&gt;
 ORDER BY e.EstateName, ua.LastName;&lt;br /&gt;
&lt;br /&gt;
List allowed groups:&lt;br /&gt;
&lt;br /&gt;
 SELECT e.EstateName, eg.uuid AS group_uuid&lt;br /&gt;
 FROM estate_groups eg&lt;br /&gt;
 JOIN estate_settings e ON e.EstateID = eg.EstateID&lt;br /&gt;
 ORDER BY e.EstateName;&lt;br /&gt;
&lt;br /&gt;
List allowed users:&lt;br /&gt;
&lt;br /&gt;
 SELECT e.EstateName, eu.uuid AS user_uuid,&lt;br /&gt;
        ua.FirstName, ua.LastName&lt;br /&gt;
 FROM estate_users eu&lt;br /&gt;
 JOIN estate_settings e ON e.EstateID = eu.EstateID&lt;br /&gt;
 LEFT JOIN osimdev_robust.UserAccounts ua ON ua.PrincipalID = eu.uuid&lt;br /&gt;
 ORDER BY e.EstateName, ua.LastName;&lt;br /&gt;
&lt;br /&gt;
List ban entries:&lt;br /&gt;
&lt;br /&gt;
 SELECT e.EstateName,&lt;br /&gt;
        eb.bannedUUID, eb.bannedIp, eb.bannedIpHostMask,&lt;br /&gt;
        eb.banningUUID, FROM_UNIXTIME(eb.banTime) AS banned_at&lt;br /&gt;
 FROM estateban eb&lt;br /&gt;
 JOIN estate_settings e ON e.EstateID = eb.EstateID&lt;br /&gt;
 ORDER BY e.EstateName, eb.banTime DESC;&lt;br /&gt;
&lt;br /&gt;
== Cross-Database Queries ==&lt;br /&gt;
&lt;br /&gt;
Objects owned by a named user (cross-database):&lt;br /&gt;
&lt;br /&gt;
 SELECT p.Name, p.UUID, p.GroupPositionX, p.GroupPositionY, p.GroupPositionZ&lt;br /&gt;
 FROM osimdev_t1.prims p&lt;br /&gt;
 WHERE p.UUID = p.SceneGroupID&lt;br /&gt;
 AND p.OwnerID = (&lt;br /&gt;
     SELECT PrincipalID FROM osimdev_robust.UserAccounts&lt;br /&gt;
     WHERE FirstName = &#039;Test&#039; AND LastName = &#039;User&#039;&lt;br /&gt;
 )&lt;br /&gt;
 ORDER BY p.Name;&lt;br /&gt;
&lt;br /&gt;
Inventory items for an object currently in the region:&lt;br /&gt;
&lt;br /&gt;
 SELECT pi.name, pi.assetType, a.name AS asset_name&lt;br /&gt;
 FROM osimdev_t1.primitems pi&lt;br /&gt;
 JOIN osimdev_robust.assets a ON a.id = pi.assetID&lt;br /&gt;
 WHERE pi.primID = (&lt;br /&gt;
     SELECT UUID FROM osimdev_t1.prims&lt;br /&gt;
     WHERE UUID = SceneGroupID AND Name LIKE &#039;%Box%&#039;&lt;br /&gt;
     LIMIT 1&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Conversions ==&lt;br /&gt;
&lt;br /&gt;
Unix timestamp to datetime:&lt;br /&gt;
&lt;br /&gt;
 SELECT FROM_UNIXTIME(1782133981);&lt;br /&gt;
&lt;br /&gt;
Region metres to region coordinates:&lt;br /&gt;
&lt;br /&gt;
 SELECT locX/256 AS coord_x, locY/256 AS coord_y FROM regions;&lt;br /&gt;
&lt;br /&gt;
Asset type numbers:&lt;br /&gt;
&lt;br /&gt;
 0  = texture&lt;br /&gt;
 2  = sound&lt;br /&gt;
 3  = landmark&lt;br /&gt;
 5  = clothing&lt;br /&gt;
 6  = object&lt;br /&gt;
 7  = notecard&lt;br /&gt;
 10 = script (LSL)&lt;br /&gt;
 13 = body part&lt;br /&gt;
 20 = animation&lt;br /&gt;
 24 = link (inventory link)&lt;br /&gt;
 25 = mesh&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== See Also ==&lt;br /&gt;
&lt;br /&gt;
* [[OpenSimulator Internals/Databases]]&lt;br /&gt;
* [[OpenSimulator Internals/Walkthroughs/Avatar Rezzes Box]]&lt;br /&gt;
* [[OpenSimulator Internals/Walkthroughs/Avatar Derezzes Object]]&lt;br /&gt;
* [[OpenSimulator Internals/Walkthroughs/Avatar Acquires Inventory]]&lt;br /&gt;
* [[OpenSimulator Internals/Data Dictionaries]]&lt;/div&gt;</summary>
		<author><name>Jwbshaw</name></author>
	</entry>
	<entry>
		<id>http://osimdev.org/wiki/index.php?title=OpenSimulator_Internals/Useful_Queries&amp;diff=117</id>
		<title>OpenSimulator Internals/Useful Queries</title>
		<link rel="alternate" type="text/html" href="http://osimdev.org/wiki/index.php?title=OpenSimulator_Internals/Useful_Queries&amp;diff=117"/>
		<updated>2026-07-09T06:01:00Z</updated>

		<summary type="html">&lt;p&gt;Jwbshaw: /* Estate */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
= OpenSimulator Internals/Useful Queries =&lt;br /&gt;
&lt;br /&gt;
== Overview ==&lt;br /&gt;
&lt;br /&gt;
These queries are for grid administrators and developers working directly with MariaDB. Correlated subqueries are used to look up UUIDs by name so you don&#039;t have to remember them.&lt;br /&gt;
&lt;br /&gt;
All queries assume osimdev_robust for grid data and osimdev_t1 for region data. Substitute your region database name as needed. Examples use &amp;quot;Test User&amp;quot; as the avatar name -- substitute as required.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Connection ==&lt;br /&gt;
&lt;br /&gt;
 mysql -u opensim -p osimdev_robust&lt;br /&gt;
 USE osimdev_t1;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Grid Database (osimdev_robust) ==&lt;br /&gt;
&lt;br /&gt;
=== Users ===&lt;br /&gt;
&lt;br /&gt;
Find a user by first name:&lt;br /&gt;
&lt;br /&gt;
 SELECT PrincipalID, FirstName, LastName, Email, UserLevel,&lt;br /&gt;
        FROM_UNIXTIME(Created) AS created&lt;br /&gt;
 FROM UserAccounts&lt;br /&gt;
 WHERE FirstName LIKE &#039;Test%&#039;;&lt;br /&gt;
&lt;br /&gt;
Show login history by name:&lt;br /&gt;
&lt;br /&gt;
 SELECT FROM_UNIXTIME(Login) AS last_login,&lt;br /&gt;
        FROM_UNIXTIME(Logout) AS last_logout,&lt;br /&gt;
        Online&lt;br /&gt;
 FROM GridUser&lt;br /&gt;
 WHERE UserID = (&lt;br /&gt;
     SELECT PrincipalID FROM UserAccounts&lt;br /&gt;
     WHERE FirstName = &#039;Test&#039; AND LastName = &#039;User&#039;&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
Show home and last location by name:&lt;br /&gt;
&lt;br /&gt;
 SELECT HomePosition, HomeLookAt, LastPosition, LastLookAt,&lt;br /&gt;
        HomeRegionID, LastRegionID&lt;br /&gt;
 FROM GridUser&lt;br /&gt;
 WHERE UserID = (&lt;br /&gt;
     SELECT PrincipalID FROM UserAccounts&lt;br /&gt;
     WHERE FirstName = &#039;Test&#039; AND LastName = &#039;User&#039;&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
Who is currently online:&lt;br /&gt;
&lt;br /&gt;
 SELECT UserID, RegionID, LastSeen FROM Presence;&lt;br /&gt;
&lt;br /&gt;
=== Avatar Appearance ===&lt;br /&gt;
&lt;br /&gt;
Show all appearance data for a user by name:&lt;br /&gt;
&lt;br /&gt;
 SELECT Name, Value&lt;br /&gt;
 FROM Avatars&lt;br /&gt;
 WHERE PrincipalID = (&lt;br /&gt;
     SELECT PrincipalID FROM UserAccounts&lt;br /&gt;
     WHERE FirstName = &#039;Test&#039; AND LastName = &#039;User&#039;&lt;br /&gt;
 )&lt;br /&gt;
 ORDER BY Name;&lt;br /&gt;
&lt;br /&gt;
Show worn wearables only:&lt;br /&gt;
&lt;br /&gt;
 SELECT Name, Value&lt;br /&gt;
 FROM Avatars&lt;br /&gt;
 WHERE PrincipalID = (&lt;br /&gt;
     SELECT PrincipalID FROM UserAccounts&lt;br /&gt;
     WHERE FirstName = &#039;Test&#039; AND LastName = &#039;User&#039;&lt;br /&gt;
 )&lt;br /&gt;
 AND Name LIKE &#039;Wearable%&#039;;&lt;br /&gt;
&lt;br /&gt;
Show attachment points only:&lt;br /&gt;
&lt;br /&gt;
 SELECT Name, Value&lt;br /&gt;
 FROM Avatars&lt;br /&gt;
 WHERE PrincipalID = (&lt;br /&gt;
     SELECT PrincipalID FROM UserAccounts&lt;br /&gt;
     WHERE FirstName = &#039;Test&#039; AND LastName = &#039;User&#039;&lt;br /&gt;
 )&lt;br /&gt;
 AND Name LIKE &#039;_ap_%&#039;;&lt;br /&gt;
&lt;br /&gt;
=== Inventory ===&lt;br /&gt;
&lt;br /&gt;
Count inventory items by asset type for a user:&lt;br /&gt;
&lt;br /&gt;
 SELECT assetType, COUNT(*) AS count&lt;br /&gt;
 FROM inventoryitems&lt;br /&gt;
 WHERE avatarID = (&lt;br /&gt;
     SELECT PrincipalID FROM UserAccounts&lt;br /&gt;
     WHERE FirstName = &#039;Test&#039; AND LastName = &#039;User&#039;&lt;br /&gt;
 )&lt;br /&gt;
 GROUP BY assetType&lt;br /&gt;
 ORDER BY count DESC;&lt;br /&gt;
&lt;br /&gt;
Find an inventory item by name:&lt;br /&gt;
&lt;br /&gt;
 SELECT inventoryName, assetType, assetID, parentFolderID&lt;br /&gt;
 FROM inventoryitems&lt;br /&gt;
 WHERE avatarID = (&lt;br /&gt;
     SELECT PrincipalID FROM UserAccounts&lt;br /&gt;
     WHERE FirstName = &#039;Test&#039; AND LastName = &#039;User&#039;&lt;br /&gt;
 )&lt;br /&gt;
 AND inventoryName LIKE &#039;%house%&#039;;&lt;br /&gt;
&lt;br /&gt;
List top-level inventory folders for a user:&lt;br /&gt;
&lt;br /&gt;
 SELECT folderName, type, folderID&lt;br /&gt;
 FROM inventoryfolders&lt;br /&gt;
 WHERE agentID = (&lt;br /&gt;
     SELECT PrincipalID FROM UserAccounts&lt;br /&gt;
     WHERE FirstName = &#039;Test&#039; AND LastName = &#039;User&#039;&lt;br /&gt;
 )&lt;br /&gt;
 AND parentFolderID = (&lt;br /&gt;
     SELECT folderID FROM inventoryfolders&lt;br /&gt;
     WHERE agentID = (&lt;br /&gt;
         SELECT PrincipalID FROM UserAccounts&lt;br /&gt;
         WHERE FirstName = &#039;Test&#039; AND LastName = &#039;User&#039;&lt;br /&gt;
     )&lt;br /&gt;
     AND type = 8&lt;br /&gt;
 )&lt;br /&gt;
 ORDER BY folderName;&lt;br /&gt;
&lt;br /&gt;
=== Assets ===&lt;br /&gt;
&lt;br /&gt;
Count all assets by type:&lt;br /&gt;
&lt;br /&gt;
 SELECT assetType, COUNT(*) AS count&lt;br /&gt;
 FROM assets&lt;br /&gt;
 GROUP BY assetType&lt;br /&gt;
 ORDER BY count DESC;&lt;br /&gt;
&lt;br /&gt;
Find assets created by a user:&lt;br /&gt;
&lt;br /&gt;
 SELECT id, name, assetType, FROM_UNIXTIME(create_time) AS created&lt;br /&gt;
 FROM assets&lt;br /&gt;
 WHERE CreatorID = (&lt;br /&gt;
     SELECT PrincipalID FROM UserAccounts&lt;br /&gt;
     WHERE FirstName = &#039;Test&#039; AND LastName = &#039;User&#039;&lt;br /&gt;
 )&lt;br /&gt;
 ORDER BY create_time DESC;&lt;br /&gt;
&lt;br /&gt;
Find an asset by name:&lt;br /&gt;
&lt;br /&gt;
 SELECT id, name, assetType, FROM_UNIXTIME(create_time) AS created&lt;br /&gt;
 FROM assets&lt;br /&gt;
 WHERE name LIKE &#039;%note%&#039;;&lt;br /&gt;
&lt;br /&gt;
=== Friends ===&lt;br /&gt;
&lt;br /&gt;
Show friends for a user:&lt;br /&gt;
&lt;br /&gt;
 SELECT Friend, Flags&lt;br /&gt;
 FROM Friends&lt;br /&gt;
 WHERE PrincipalID = (&lt;br /&gt;
     SELECT PrincipalID FROM UserAccounts&lt;br /&gt;
     WHERE FirstName = &#039;Test&#039; AND LastName = &#039;User&#039;&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
=== Regions ===&lt;br /&gt;
&lt;br /&gt;
List all registered regions:&lt;br /&gt;
&lt;br /&gt;
 SELECT regionName,&lt;br /&gt;
        locX/256 AS coord_x, locY/256 AS coord_y,&lt;br /&gt;
        sizeX, sizeY, flags,&lt;br /&gt;
        FROM_UNIXTIME(last_seen) AS last_seen&lt;br /&gt;
 FROM regions;&lt;br /&gt;
&lt;br /&gt;
Check if a region is online:&lt;br /&gt;
&lt;br /&gt;
 SELECT regionName, flags &amp;amp; 4 AS online&lt;br /&gt;
 FROM regions&lt;br /&gt;
 WHERE regionName = &#039;T1&#039;;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Region Database (osimdev_t1) ==&lt;br /&gt;
&lt;br /&gt;
=== Objects ===&lt;br /&gt;
&lt;br /&gt;
List all objects with world position (root prims only):&lt;br /&gt;
&lt;br /&gt;
 SELECT Name, UUID, GroupPositionX, GroupPositionY, GroupPositionZ&lt;br /&gt;
 FROM prims&lt;br /&gt;
 WHERE UUID = SceneGroupID&lt;br /&gt;
 ORDER BY Name;&lt;br /&gt;
&lt;br /&gt;
Count prims per object (root prims only, sorted by size):&lt;br /&gt;
&lt;br /&gt;
 SELECT p.Name, p.SceneGroupID,&lt;br /&gt;
        p.GroupPositionX, p.GroupPositionY, p.GroupPositionZ,&lt;br /&gt;
        COUNT(*) AS prim_count&lt;br /&gt;
 FROM prims p&lt;br /&gt;
 WHERE p.UUID = p.SceneGroupID&lt;br /&gt;
 GROUP BY p.SceneGroupID, p.Name, p.GroupPositionX, p.GroupPositionY, p.GroupPositionZ&lt;br /&gt;
 ORDER BY prim_count DESC;&lt;br /&gt;
&lt;br /&gt;
Find an object by name:&lt;br /&gt;
&lt;br /&gt;
 SELECT UUID, GroupPositionX, GroupPositionY, GroupPositionZ&lt;br /&gt;
 FROM prims&lt;br /&gt;
 WHERE UUID = SceneGroupID&lt;br /&gt;
 AND Name LIKE &#039;%house%&#039;;&lt;br /&gt;
&lt;br /&gt;
List all prims in a named object:&lt;br /&gt;
&lt;br /&gt;
 SELECT UUID, Name, LinkNumber, PositionX, PositionY, PositionZ&lt;br /&gt;
 FROM prims&lt;br /&gt;
 WHERE SceneGroupID = (&lt;br /&gt;
     SELECT UUID FROM prims&lt;br /&gt;
     WHERE UUID = SceneGroupID AND Name LIKE &#039;%Brown House%&#039;&lt;br /&gt;
     LIMIT 1&lt;br /&gt;
 )&lt;br /&gt;
 ORDER BY LinkNumber;&lt;br /&gt;
&lt;br /&gt;
Find objects owned by a specific user:&lt;br /&gt;
&lt;br /&gt;
 SELECT Name, UUID, GroupPositionX, GroupPositionY, GroupPositionZ&lt;br /&gt;
 FROM prims&lt;br /&gt;
 WHERE UUID = SceneGroupID&lt;br /&gt;
 AND OwnerID = (&lt;br /&gt;
     SELECT PrincipalID FROM osimdev_robust.UserAccounts&lt;br /&gt;
     WHERE FirstName = &#039;Test&#039; AND LastName = &#039;User&#039;&lt;br /&gt;
 )&lt;br /&gt;
 ORDER BY Name;&lt;br /&gt;
&lt;br /&gt;
=== Object Contents (Task Inventory) ===&lt;br /&gt;
&lt;br /&gt;
Show contents of a named object:&lt;br /&gt;
&lt;br /&gt;
 SELECT pi.name, pi.assetType, pi.assetID&lt;br /&gt;
 FROM primitems pi&lt;br /&gt;
 WHERE pi.primID IN (&lt;br /&gt;
     SELECT UUID FROM prims&lt;br /&gt;
     WHERE SceneGroupID = (&lt;br /&gt;
         SELECT UUID FROM prims&lt;br /&gt;
         WHERE UUID = SceneGroupID AND Name LIKE &#039;%Box%&#039;&lt;br /&gt;
         LIMIT 1&lt;br /&gt;
     )&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
Count task inventory items by type across all objects:&lt;br /&gt;
&lt;br /&gt;
 SELECT pi.assetType, COUNT(*) AS count&lt;br /&gt;
 FROM primitems pi&lt;br /&gt;
 GROUP BY pi.assetType&lt;br /&gt;
 ORDER BY count DESC;&lt;br /&gt;
&lt;br /&gt;
Show all objects that contain scripts:&lt;br /&gt;
&lt;br /&gt;
 SELECT DISTINCT p.Name, p.UUID, p.GroupPositionX, p.GroupPositionY, p.GroupPositionZ&lt;br /&gt;
 FROM prims p&lt;br /&gt;
 JOIN primitems pi ON pi.primID = p.UUID&lt;br /&gt;
 WHERE p.UUID = p.SceneGroupID&lt;br /&gt;
 AND pi.assetType = 10&lt;br /&gt;
 ORDER BY p.Name;&lt;br /&gt;
&lt;br /&gt;
=== Prim Shape ===&lt;br /&gt;
&lt;br /&gt;
Show shape for a named object:&lt;br /&gt;
&lt;br /&gt;
 SELECT p.Name, p.LinkNumber,&lt;br /&gt;
        ps.ScaleX, ps.ScaleY, ps.ScaleZ,&lt;br /&gt;
        ps.PCode, ps.Shape, ps.ProfileCurve, ps.PathCurve&lt;br /&gt;
 FROM primshapes ps&lt;br /&gt;
 JOIN prims p ON ps.UUID = p.UUID&lt;br /&gt;
 WHERE p.SceneGroupID = (&lt;br /&gt;
     SELECT UUID FROM prims&lt;br /&gt;
     WHERE UUID = SceneGroupID AND Name = &#039;Object&#039;&lt;br /&gt;
     LIMIT 1&lt;br /&gt;
 )&lt;br /&gt;
 ORDER BY p.LinkNumber;&lt;br /&gt;
&lt;br /&gt;
=== Persistence State ===&lt;br /&gt;
&lt;br /&gt;
Find objects with pending changes (not yet persisted):&lt;br /&gt;
&lt;br /&gt;
 SELECT Name, UUID, GroupPositionX, GroupPositionY, GroupPositionZ&lt;br /&gt;
 FROM prims&lt;br /&gt;
 WHERE UUID = SceneGroupID&lt;br /&gt;
 AND RezzerID IS NOT NULL&lt;br /&gt;
 ORDER BY Name;&lt;br /&gt;
&lt;br /&gt;
=== Land ===&lt;br /&gt;
&lt;br /&gt;
Show all parcels:&lt;br /&gt;
&lt;br /&gt;
 SELECT LocalLandID, Name, OwnerUUID, Area, LandStatus,&lt;br /&gt;
        UserLocationX, UserLocationY, UserLocationZ&lt;br /&gt;
 FROM land;&lt;br /&gt;
&lt;br /&gt;
=== Terrain ===&lt;br /&gt;
&lt;br /&gt;
Check terrain revision and blob size:&lt;br /&gt;
&lt;br /&gt;
 SELECT RegionUUID, Revision, LENGTH(Heightfield) AS bytes&lt;br /&gt;
 FROM terrain;&lt;br /&gt;
&lt;br /&gt;
=== Estate ===&lt;br /&gt;
&lt;br /&gt;
All estate tables are in the region database (osimdev_t1), not the grid database.&lt;br /&gt;
&lt;br /&gt;
Show estate settings:&lt;br /&gt;
&lt;br /&gt;
 SELECT EstateID, EstateName, EstateOwner,&lt;br /&gt;
        PublicAccess, AllowVoice, DenyMinors,&lt;br /&gt;
        AllowDirectTeleport, AllowSetHome, AllowLandmark,&lt;br /&gt;
        AllowParcelChanges, AllowEnviromentOverride,&lt;br /&gt;
        FixedSun, SunPosition, UseGlobalTime,&lt;br /&gt;
        DenyAnonymous, DenyIdentified, DenyTransacted&lt;br /&gt;
 FROM estate_settings;&lt;br /&gt;
&lt;br /&gt;
Show which region belongs to which estate:&lt;br /&gt;
&lt;br /&gt;
 SELECT r.regionName, m.EstateID, e.EstateName&lt;br /&gt;
 FROM estate_map m&lt;br /&gt;
 JOIN estate_settings e ON e.EstateID = m.EstateID&lt;br /&gt;
 JOIN osimdev_robust.regions r ON r.uuid = m.RegionID;&lt;br /&gt;
&lt;br /&gt;
List estate managers by name:&lt;br /&gt;
&lt;br /&gt;
 SELECT e.EstateName, em.uuid AS manager_uuid,&lt;br /&gt;
        ua.FirstName, ua.LastName&lt;br /&gt;
 FROM estate_managers em&lt;br /&gt;
 JOIN estate_settings e ON e.EstateID = em.EstateID&lt;br /&gt;
 LEFT JOIN osimdev_robust.UserAccounts ua ON ua.PrincipalID = em.uuid&lt;br /&gt;
 ORDER BY e.EstateName, ua.LastName;&lt;br /&gt;
&lt;br /&gt;
List allowed groups:&lt;br /&gt;
&lt;br /&gt;
 SELECT e.EstateName, eg.uuid AS group_uuid&lt;br /&gt;
 FROM estate_groups eg&lt;br /&gt;
 JOIN estate_settings e ON e.EstateID = eg.EstateID&lt;br /&gt;
 ORDER BY e.EstateName;&lt;br /&gt;
&lt;br /&gt;
List allowed users:&lt;br /&gt;
&lt;br /&gt;
 SELECT e.EstateName, eu.uuid AS user_uuid,&lt;br /&gt;
        ua.FirstName, ua.LastName&lt;br /&gt;
 FROM estate_users eu&lt;br /&gt;
 JOIN estate_settings e ON e.EstateID = eu.EstateID&lt;br /&gt;
 LEFT JOIN osimdev_robust.UserAccounts ua ON ua.PrincipalID = eu.uuid&lt;br /&gt;
 ORDER BY e.EstateName, ua.LastName;&lt;br /&gt;
&lt;br /&gt;
List ban entries:&lt;br /&gt;
&lt;br /&gt;
 SELECT e.EstateName,&lt;br /&gt;
        eb.bannedUUID, eb.bannedIp, eb.bannedIpHostMask,&lt;br /&gt;
        eb.banningUUID, FROM_UNIXTIME(eb.banTime) AS banned_at&lt;br /&gt;
 FROM estateban eb&lt;br /&gt;
 JOIN estate_settings e ON e.EstateID = eb.EstateID&lt;br /&gt;
 ORDER BY e.EstateName, eb.banTime DESC;&lt;br /&gt;
&lt;br /&gt;
== Cross-Database Queries ==&lt;br /&gt;
&lt;br /&gt;
Objects owned by a named user (cross-database):&lt;br /&gt;
&lt;br /&gt;
 SELECT p.Name, p.UUID, p.GroupPositionX, p.GroupPositionY, p.GroupPositionZ&lt;br /&gt;
 FROM osimdev_t1.prims p&lt;br /&gt;
 WHERE p.UUID = p.SceneGroupID&lt;br /&gt;
 AND p.OwnerID = (&lt;br /&gt;
     SELECT PrincipalID FROM osimdev_robust.UserAccounts&lt;br /&gt;
     WHERE FirstName = &#039;Test&#039; AND LastName = &#039;User&#039;&lt;br /&gt;
 )&lt;br /&gt;
 ORDER BY p.Name;&lt;br /&gt;
&lt;br /&gt;
Inventory items for an object currently in the region:&lt;br /&gt;
&lt;br /&gt;
 SELECT pi.name, pi.assetType, a.name AS asset_name&lt;br /&gt;
 FROM osimdev_t1.primitems pi&lt;br /&gt;
 JOIN osimdev_robust.assets a ON a.id = pi.assetID&lt;br /&gt;
 WHERE pi.primID = (&lt;br /&gt;
     SELECT UUID FROM osimdev_t1.prims&lt;br /&gt;
     WHERE UUID = SceneGroupID AND Name LIKE &#039;%Box%&#039;&lt;br /&gt;
     LIMIT 1&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Conversions ==&lt;br /&gt;
&lt;br /&gt;
Unix timestamp to datetime:&lt;br /&gt;
&lt;br /&gt;
 SELECT FROM_UNIXTIME(1782133981);&lt;br /&gt;
&lt;br /&gt;
Region metres to region coordinates:&lt;br /&gt;
&lt;br /&gt;
 SELECT locX/256 AS coord_x, locY/256 AS coord_y FROM regions;&lt;br /&gt;
&lt;br /&gt;
Asset type numbers:&lt;br /&gt;
&lt;br /&gt;
 0  = texture&lt;br /&gt;
 2  = sound&lt;br /&gt;
 3  = landmark&lt;br /&gt;
 5  = clothing&lt;br /&gt;
 6  = object&lt;br /&gt;
 7  = notecard&lt;br /&gt;
 10 = script (LSL)&lt;br /&gt;
 13 = body part&lt;br /&gt;
 20 = animation&lt;br /&gt;
 24 = link (inventory link)&lt;br /&gt;
 25 = mesh&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== See Also ==&lt;br /&gt;
&lt;br /&gt;
* [[OpenSimulator Internals/Databases]]&lt;br /&gt;
* [[OpenSimulator Internals/Walkthroughs/Avatar Rezzes Box]]&lt;br /&gt;
* [[OpenSimulator Internals/Walkthroughs/Avatar Derezzes Object]]&lt;br /&gt;
* [[OpenSimulator Internals/Walkthroughs/Avatar Acquires Inventory]]&lt;br /&gt;
* [[OpenSimulator Internals/Data Dictionaries]]&lt;/div&gt;</summary>
		<author><name>Jwbshaw</name></author>
	</entry>
	<entry>
		<id>http://osimdev.org/wiki/index.php?title=OpenSimulator_Internals/Simulator_Services&amp;diff=116</id>
		<title>OpenSimulator Internals/Simulator Services</title>
		<link rel="alternate" type="text/html" href="http://osimdev.org/wiki/index.php?title=OpenSimulator_Internals/Simulator_Services&amp;diff=116"/>
		<updated>2026-07-09T05:45:02Z</updated>

		<summary type="html">&lt;p&gt;Jwbshaw: first&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Simulator Services =&lt;br /&gt;
&lt;br /&gt;
Simulator services run inside OpenSim.exe and are scoped to the simulator process,&lt;br /&gt;
not the grid. They are distinct from [[OpenSimulator_Internals/ROBUST_Services|ROBUST services]],&lt;br /&gt;
which run in ROBUST.exe and serve the entire grid.&lt;br /&gt;
&lt;br /&gt;
Each simulator service follows the same local/remote connector pattern used by&lt;br /&gt;
grid services: a local connector handles in-process calls; a remote connector&lt;br /&gt;
makes HTTP calls to another simulator. See&lt;br /&gt;
[[OpenSimulator_Internals/Connector_Architecture|Connector Architecture]] for the&lt;br /&gt;
general pattern.&lt;br /&gt;
&lt;br /&gt;
Config key for all three services is in the &amp;lt;code&amp;gt;[Modules]&amp;lt;/code&amp;gt; section of&lt;br /&gt;
&amp;lt;code&amp;gt;OpenSim.ini&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Land Service ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Interface:&#039;&#039;&#039; &amp;lt;code&amp;gt;ILandService&amp;lt;/code&amp;gt; (OpenSim.Services.Interfaces)&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Config key:&#039;&#039;&#039; &amp;lt;code&amp;gt;LandServices&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Purpose ===&lt;br /&gt;
&lt;br /&gt;
Retrieves parcel land data by region handle and coordinates. Used when a simulator&lt;br /&gt;
needs land data for a region it does not itself host -- for example, to resolve&lt;br /&gt;
access rules at a region border before a crossing completes.&lt;br /&gt;
&lt;br /&gt;
=== Interface ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;ILandService&amp;lt;/code&amp;gt; exposes a single method:&lt;br /&gt;
&lt;br /&gt;
 LandData GetLandData(UUID scopeID, ulong regionHandle, uint x, uint y, out byte regionAccess)&lt;br /&gt;
&lt;br /&gt;
=== Connectors ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Connector !! Class !! Used when&lt;br /&gt;
|-&lt;br /&gt;
| Local || &amp;lt;code&amp;gt;LocalLandServicesConnector&amp;lt;/code&amp;gt; || Destination region is hosted by this simulator. Walks the local scene list, matches by world coordinates, returns &amp;lt;code&amp;gt;LandData&amp;lt;/code&amp;gt; plus access level and dwell count.&lt;br /&gt;
|-&lt;br /&gt;
| Remote || &amp;lt;code&amp;gt;RemoteLandServicesConnector&amp;lt;/code&amp;gt; || Destination region is on another simulator. Tries local first; falls back to HTTP call via &amp;lt;code&amp;gt;LandServicesConnector&amp;lt;/code&amp;gt; base class.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Notes ===&lt;br /&gt;
&lt;br /&gt;
* The local connector iterates &amp;lt;code&amp;gt;m_Scenes&amp;lt;/code&amp;gt; and matches by world coordinate&lt;br /&gt;
  bounds, not by region UUID. This matters for varregions where a single scene&lt;br /&gt;
  covers a range of coordinates.&lt;br /&gt;
* Dwell count is retrieved via &amp;lt;code&amp;gt;IDwellModule&amp;lt;/code&amp;gt; if present; not part of&lt;br /&gt;
  the core land data.&lt;br /&gt;
* Returns &amp;lt;code&amp;gt;null&amp;lt;/code&amp;gt; if no local scene matches and no remote call is&lt;br /&gt;
  configured.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Library Service ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Interface:&#039;&#039;&#039; &amp;lt;code&amp;gt;ILibraryService&amp;lt;/code&amp;gt; (OpenSim.Services.Interfaces)&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Implementation:&#039;&#039;&#039; &amp;lt;code&amp;gt;OpenSim.Services.InventoryService.LibraryService&amp;lt;/code&amp;gt;&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Config section:&#039;&#039;&#039; &amp;lt;code&amp;gt;[LibraryService]&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Purpose ===&lt;br /&gt;
&lt;br /&gt;
Provides the shared library inventory -- the read-only content visible to all&lt;br /&gt;
users under the Library folder. Backed by XML files on the local filesystem,&lt;br /&gt;
not the database.&lt;br /&gt;
&lt;br /&gt;
=== Config ===&lt;br /&gt;
&lt;br /&gt;
 [LibraryService]&lt;br /&gt;
 DefaultLibrary = inventory/Libraries.xml&lt;br /&gt;
 LibraryName = OpenSim Library&lt;br /&gt;
&lt;br /&gt;
Both keys are optional; the values above are the defaults.&lt;br /&gt;
&lt;br /&gt;
=== Interface ===&lt;br /&gt;
&lt;br /&gt;
 InventoryFolderImpl LibraryRootFolder { get; }&lt;br /&gt;
 Dictionary&amp;lt;UUID, InventoryFolderImpl&amp;gt; GetAllFolders()&lt;br /&gt;
 InventoryItemBase GetItem(UUID itemID)&lt;br /&gt;
 InventoryItemBase[] GetMultipleItems(UUID[] itemIDs)&lt;br /&gt;
&lt;br /&gt;
=== Notes ===&lt;br /&gt;
&lt;br /&gt;
* Not a region module. Instantiated as a &amp;lt;code&amp;gt;ServiceBase&amp;lt;/code&amp;gt; directly by&lt;br /&gt;
  the service infrastructure. No &amp;lt;code&amp;gt;[Modules]&amp;lt;/code&amp;gt; config key.&lt;br /&gt;
* Singleton per process: static instance, initialized once regardless of how&lt;br /&gt;
  many regions the simulator hosts.&lt;br /&gt;
* Loaded from XML files under the &amp;lt;code&amp;gt;inventory/&amp;lt;/code&amp;gt; directory at startup.&lt;br /&gt;
  Root folder UUID is a fixed constant (&amp;lt;code&amp;gt;00000112-000f-0000-0000-000100bba000&amp;lt;/code&amp;gt;);&lt;br /&gt;
  all library UUIDs are fixed and do not vary between installations.&lt;br /&gt;
* No remote connector. No ROBUST equivalent. Library content is local to each&lt;br /&gt;
  simulator.&lt;br /&gt;
* The source explicitly notes this is a stopgap: &amp;quot;basically a hack to give us&lt;br /&gt;
  an Inventory library while we don&#039;t have an inventory server.&amp;quot; Architecturally&lt;br /&gt;
  it should be a grid service with shared content across simulators; it has&lt;br /&gt;
  never been converted.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Simulation Service ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Interface:&#039;&#039;&#039; &amp;lt;code&amp;gt;ISimulationService&amp;lt;/code&amp;gt; (OpenSim.Services.Interfaces)&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Config key:&#039;&#039;&#039; &amp;lt;code&amp;gt;SimulationServices&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Purpose ===&lt;br /&gt;
&lt;br /&gt;
Handles simulator-to-simulator communication: creating and updating agents on&lt;br /&gt;
remote simulators, moving objects across region boundaries, and closing agents&lt;br /&gt;
when they leave. Used for teleports, region crossings, child agent maintenance,&lt;br /&gt;
and object crossings.&lt;br /&gt;
&lt;br /&gt;
This is not a ROBUST service. It runs entirely between simulators.&lt;br /&gt;
&lt;br /&gt;
=== Interface ===&lt;br /&gt;
&lt;br /&gt;
Agent operations:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Method !! Purpose&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;CreateAgent(source, destination, aCircuit, flags, ctx, out reason)&amp;lt;/code&amp;gt; || Creates a new agent circuit on the destination simulator. Entry point for teleport and login-to-region.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;UpdateAgent(destination, AgentData, ctx)&amp;lt;/code&amp;gt; || Full child agent update: position, appearance, animation state.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;UpdateAgent(destination, AgentPosition)&amp;lt;/code&amp;gt; || Lightweight position-only update for child agents.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;QueryAccess(destination, agentID, homeURI, viaTeleport, position, features, ctx, out reason)&amp;lt;/code&amp;gt; || Checks whether the destination will accept this agent. Called before &amp;lt;code&amp;gt;CreateAgent&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;ReleaseAgent(originRegion, agentID, uri)&amp;lt;/code&amp;gt; || Destination notifies origin that the client has connected. Origin clears its teleport-pending state.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;CloseAgent(destination, agentID, auth_token)&amp;lt;/code&amp;gt; || Closes an agent circuit on the destination simulator.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Object operations:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Method !! Purpose&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;CreateObject(destination, newPosition, sog, isLocalCall)&amp;lt;/code&amp;gt; || Sends a scene object to the destination simulator. Used for prim crossings and object teleport. If &amp;lt;code&amp;gt;isLocalCall&amp;lt;/code&amp;gt; is true, the object is cloned before transfer; if false, it is used as received from the wire.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Connectors ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Connector !! Class !! Used when&lt;br /&gt;
|-&lt;br /&gt;
| Local || &amp;lt;code&amp;gt;LocalSimulationConnectorModule&amp;lt;/code&amp;gt; || Destination region is hosted by this simulator. Dispatches directly to the target &amp;lt;code&amp;gt;Scene&amp;lt;/code&amp;gt; by UUID lookup.&lt;br /&gt;
|-&lt;br /&gt;
| Remote || &amp;lt;code&amp;gt;RemoteSimulationConnectorModule&amp;lt;/code&amp;gt; || Destination region is on another simulator. Tries local first; falls back to HTTP via &amp;lt;code&amp;gt;SimulationServiceConnector&amp;lt;/code&amp;gt;.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Notes ===&lt;br /&gt;
&lt;br /&gt;
* The local connector maintains a &amp;lt;code&amp;gt;Dictionary&amp;amp;lt;UUID, Scene&amp;amp;gt;&amp;lt;/code&amp;gt; keyed&lt;br /&gt;
  by region UUID. &amp;lt;code&amp;gt;GetScene()&amp;lt;/code&amp;gt; has a fallback that returns the first&lt;br /&gt;
  available scene if the requested UUID is not found -- this masks bugs and is&lt;br /&gt;
  noted as a known issue in the source.&lt;br /&gt;
* &amp;lt;code&amp;gt;QueryAccess&amp;lt;/code&amp;gt; enforces a version check: if the requesting simulator&lt;br /&gt;
  is running protocol version below 0.3 and the destination is a varregion&lt;br /&gt;
  (non-256x256), the request is denied. Older viewers crash on varregions.&lt;br /&gt;
* &amp;lt;code&amp;gt;RemoteSimulationConnectorModule&amp;lt;/code&amp;gt; wraps a&lt;br /&gt;
  &amp;lt;code&amp;gt;LocalSimulationConnectorModule&amp;lt;/code&amp;gt; instance as its local backend.&lt;br /&gt;
  All calls try local first, then fall through to HTTP only if the destination&lt;br /&gt;
  is confirmed not-local via &amp;lt;code&amp;gt;IsLocalRegion()&amp;lt;/code&amp;gt;.&lt;br /&gt;
* &amp;lt;code&amp;gt;source&amp;lt;/code&amp;gt; in &amp;lt;code&amp;gt;CreateAgent&amp;lt;/code&amp;gt; may be null if the user logged&lt;br /&gt;
  in directly or arrived from an older simulator that does not send it.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== See Also ==&lt;br /&gt;
&lt;br /&gt;
* [[OpenSimulator_Internals/ROBUST_Services|ROBUST Services]]&lt;br /&gt;
* [[OpenSimulator_Internals/Connector_Architecture|Connector Architecture]]&lt;br /&gt;
* [[OpenSimulator_Internals/Walkthroughs/Avatar_Transfer_Between_Regions|Walkthrough: Avatar Transfer Between Regions]]&lt;br /&gt;
* [[OpenSimulator_Internals/Walkthroughs/Avatar_Goes_HG|Walkthrough: Avatar Goes HG]]&lt;br /&gt;
&lt;br /&gt;
[[Category:OpenSimulator Internals]]&lt;/div&gt;</summary>
		<author><name>Jwbshaw</name></author>
	</entry>
	<entry>
		<id>http://osimdev.org/wiki/index.php?title=Main_Page&amp;diff=115</id>
		<title>Main Page</title>
		<link rel="alternate" type="text/html" href="http://osimdev.org/wiki/index.php?title=Main_Page&amp;diff=115"/>
		<updated>2026-07-08T21:23:59Z</updated>

		<summary type="html">&lt;p&gt;Jwbshaw: missing some top level stuff&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= OpenSimulator Internals =&lt;br /&gt;
&lt;br /&gt;
This wiki documents the internal architecture of OpenSimulator for developers and contributors. It covers the database schema, service architecture, connector design, and code structure. Written from code and verified against developer discussion -- where the wiki and the code disagree, the code takes priority.&lt;br /&gt;
&lt;br /&gt;
Maintained by Jagga Meredith. Contributions welcome.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Source Repository ==&lt;br /&gt;
&lt;br /&gt;
 https://github.com/opensim/opensim&lt;br /&gt;
&lt;br /&gt;
Only the &#039;&#039;&#039;master&#039;&#039;&#039; branch is active. All other branches are dead.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Overview ==&lt;br /&gt;
&lt;br /&gt;
OpenSimulator has two main components:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;ROBUST.exe&#039;&#039;&#039; -- handles grid-wide services: user accounts, inventory, assets, presence, and region registration. Multiple simulators connect to a single ROBUST instance.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;OpenSim.exe&#039;&#039;&#039; -- runs one or more regions. Handles objects, avatars, physics, scripting, and terrain. In standalone mode both processes are combined into OpenSim.exe.&lt;br /&gt;
&lt;br /&gt;
The database layer is split to match: ROBUST owns the grid database, each simulator owns its own region database. Both live in the same database server instance as separate databases.&lt;br /&gt;
&lt;br /&gt;
In standalone mode the connector calls the service directly in-process. In grid mode it makes an HTTP call to ROBUST. Same interface either way.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Contents ==&lt;br /&gt;
&lt;br /&gt;
* [[OpenSimulator Internals/Architecture Overview]]&lt;br /&gt;
* [[OpenSimulator Internals/Reading the Code]]&lt;br /&gt;
* [[OpenSimulator Internals/Package Overview]]&lt;br /&gt;
* [[OpenSimulator Internals/ROBUST Services]]&lt;br /&gt;
* [[OpenSimulator Internals/Simulator Services]]&lt;br /&gt;
* [[OpenSimulator Internals/Connector Architecture]]&lt;br /&gt;
* [[OpenSimulator Internals/Databases]]&lt;br /&gt;
* [[OpenSimulator Internals/Data Dictionaries]]&lt;br /&gt;
* [[OpenSimulator Internals/Useful Queries]]&lt;br /&gt;
* [[OpenSimulator Internals/Code Map]]&lt;br /&gt;
* [[OpenSimulator Internals/Walkthroughs]]&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Status ==&lt;br /&gt;
&lt;br /&gt;
This document is a work in progress developed from code review and developer meeting notes. Where the existing wiki disagrees with the source code, the source code takes priority. Discrepancies are noted.&lt;br /&gt;
&lt;br /&gt;
Contributors: Jagga Meredith&lt;/div&gt;</summary>
		<author><name>Jwbshaw</name></author>
	</entry>
	<entry>
		<id>http://osimdev.org/wiki/index.php?title=OpenSimulator_Internals/Package_Overview&amp;diff=114</id>
		<title>OpenSimulator Internals/Package Overview</title>
		<link rel="alternate" type="text/html" href="http://osimdev.org/wiki/index.php?title=OpenSimulator_Internals/Package_Overview&amp;diff=114"/>
		<updated>2026-07-08T21:04:11Z</updated>

		<summary type="html">&lt;p&gt;Jwbshaw: formatting&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Package Overview =&lt;br /&gt;
&lt;br /&gt;
OpenSimulator&#039;s source tree is organized into a hierarchy of packages (C# projects).&lt;br /&gt;
This page gives a top-level map. For detailed internals of individual classes,&lt;br /&gt;
see the [[OpenSimulator_Internals/Code_Map|Code Map]] pages.&lt;br /&gt;
&lt;br /&gt;
== OpenSim ==&lt;br /&gt;
&lt;br /&gt;
The top-level package launches the region server and manages the console.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Entry point:&#039;&#039;&#039; &amp;lt;code&amp;gt;OpenSim/Region/Application/Application.cs&amp;lt;/code&amp;gt; — &amp;lt;code&amp;gt;Main()&amp;lt;/code&amp;gt;&lt;br /&gt;
  instantiates an &amp;lt;code&amp;gt;OpenSim&amp;lt;/code&amp;gt; object, calls &amp;lt;code&amp;gt;Startup()&amp;lt;/code&amp;gt; (which spins&lt;br /&gt;
  up worker threads), then blocks the initial thread on the main console prompt.&lt;br /&gt;
* &amp;lt;code&amp;gt;OpenSim.Startup()&amp;lt;/code&amp;gt; is inherited from&lt;br /&gt;
  &amp;lt;code&amp;gt;OpenSim.Framework.Servers.BaseOpenSimServer&amp;lt;/code&amp;gt;; it delegates to&lt;br /&gt;
  &amp;lt;code&amp;gt;StartupSpecific()&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== OpenSim.Addons ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Note: not actively maintained. Use with caution.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;OpenSim.Addons.Groups&#039;&#039;&#039; — group support.&lt;br /&gt;
* &#039;&#039;&#039;OpenSim.Addons.OfflineIM&#039;&#039;&#039; — offline IM support.&lt;br /&gt;
&lt;br /&gt;
== OpenSim.ApplicationPlugins ==&lt;br /&gt;
&lt;br /&gt;
Application plugins: modular code that affects the entire region server&lt;br /&gt;
(as distinct from [[OpenSimulator_Internals/Package_Overview#OpenSim.Region.CoreModules|region modules]],&lt;br /&gt;
which affect individual regions).&lt;br /&gt;
&lt;br /&gt;
== OpenSim.Capabilities ==&lt;br /&gt;
&lt;br /&gt;
Basic data structures for capability (HTTPS/event-queue) support.&lt;br /&gt;
&lt;br /&gt;
== OpenSim.ConsoleClient ==&lt;br /&gt;
&lt;br /&gt;
REST console client for remote connection to a running OpenSimulator instance.&lt;br /&gt;
Not widely deployed; most operators use a &amp;lt;code&amp;gt;screen&amp;lt;/code&amp;gt; session on Linux&lt;br /&gt;
or separate terminals on Windows.&lt;br /&gt;
&lt;br /&gt;
== OpenSim.Data ==&lt;br /&gt;
&lt;br /&gt;
All low-level database access code. Contains per-backend packages:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;OpenSim.Data.MySQL&#039;&#039;&#039; — MySQL/MariaDB backend (primary for grid deployments).&lt;br /&gt;
* &#039;&#039;&#039;OpenSim.Data.SQLite&#039;&#039;&#039; — SQLite backend (common for standalone/testing).&lt;br /&gt;
&lt;br /&gt;
Each backend implements the &amp;lt;code&amp;gt;IAssetData&amp;lt;/code&amp;gt; and sibling interfaces defined here.&lt;br /&gt;
The interface hierarchy is: &amp;lt;code&amp;gt;OpenSim.Data&amp;lt;/code&amp;gt; defines the interfaces;&lt;br /&gt;
per-DB packages provide the implementations.&lt;br /&gt;
&lt;br /&gt;
See also: [[OpenSimulator_Internals/Useful_Queries|Useful Queries]].&lt;br /&gt;
&lt;br /&gt;
== OpenSim.Framework ==&lt;br /&gt;
&lt;br /&gt;
General framework code shared across the simulator and ROBUST. Not region-specific.&lt;br /&gt;
&lt;br /&gt;
Subpackages of note:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Subpackage !! Purpose&lt;br /&gt;
|-&lt;br /&gt;
| OpenSim.Framework.AssetLoader.Filesystem || Loads library assets from the local filesystem.&lt;br /&gt;
|-&lt;br /&gt;
| OpenSim.Framework.Console || Console infrastructure.&lt;br /&gt;
|-&lt;br /&gt;
| OpenSim.Framework.Monitoring || Statistics gathering and monitoring.&lt;br /&gt;
|-&lt;br /&gt;
| OpenSim.Framework.RegionLoader.FileSystem || Loads region config from filesystem (e.g. &amp;lt;code&amp;gt;bin/Regions/Regions.ini&amp;lt;/code&amp;gt;).&lt;br /&gt;
|-&lt;br /&gt;
| OpenSim.Framework.RegionLoader.Web || Loads region config from a remote URL.&lt;br /&gt;
|-&lt;br /&gt;
| OpenSim.Framework.Serialization || OAR and IAR read/write infrastructure.&lt;br /&gt;
|-&lt;br /&gt;
| OpenSim.Framework.Servers || Generic server base classes, HTTP server infrastructure.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Two subpackages handle configuration loading from HTTP and XML respectively;&lt;br /&gt;
neither is a current deployment path.&lt;br /&gt;
&lt;br /&gt;
== OpenSim.Region ==&lt;br /&gt;
&lt;br /&gt;
Most of the region-specific code lives here.&lt;br /&gt;
&lt;br /&gt;
=== OpenSim.Region.ClientStack ===&lt;br /&gt;
&lt;br /&gt;
Infrastructure for pluggable UDP client stacks. In practice only one stack exists&lt;br /&gt;
(LLUDP); the abstraction remains in case alternatives are ever needed.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;OpenSim.Region.ClientStack.LindenCaps&#039;&#039;&#039; — HTTP/capability side of the Second Life&lt;br /&gt;
  protocol. Glues cap requests to region modules.&lt;br /&gt;
* &#039;&#039;&#039;OpenSim.Region.ClientStack.LindenUDP&#039;&#039;&#039; — UDP side of the Second Life protocol.&lt;br /&gt;
  Glues UDP packets to scene and region module code.&lt;br /&gt;
&lt;br /&gt;
Future Code Map page: [[OpenSimulator_Internals/Code_Map/LLUDPServer|LLUDPServer]] (planned).&lt;br /&gt;
&lt;br /&gt;
=== OpenSim.Region.CoreModules ===&lt;br /&gt;
&lt;br /&gt;
The bundled region modules. This is a large package covering a wide range of&lt;br /&gt;
functionality. Key modules documented in the Code Map:&lt;br /&gt;
&lt;br /&gt;
* [[OpenSimulator_Internals/Code_Map/AttachmentsModule|AttachmentsModule]] — avatar attachment lifecycle.&lt;br /&gt;
* [[OpenSimulator_Internals/Code_Map/EntityTransferModule|EntityTransferModule]] — region crossings and teleports.&lt;br /&gt;
* [[OpenSimulator_Internals/Code_Map/HGEntityTransferModule|HGEntityTransferModule]] — Hypergrid teleport handling.&lt;br /&gt;
* [[OpenSimulator_Internals/Code_Map/InventoryAccessModule|InventoryAccessModule]] — inventory access during rez/derez.&lt;br /&gt;
* [[OpenSimulator_Internals/Code_Map/AvatarFactoryModule|AvatarFactoryModule]] — avatar appearance management.&lt;br /&gt;
&lt;br /&gt;
=== OpenSim.Region.DataSnapshot ===&lt;br /&gt;
&lt;br /&gt;
Generates an XML summary of region contents; can be exposed to external search engines.&lt;br /&gt;
&lt;br /&gt;
=== OpenSim.Region.Framework ===&lt;br /&gt;
&lt;br /&gt;
The core of the simulator: scene graph, [[OpenSimulator_Internals/Code_Map/ScenePresence|ScenePresence]],&lt;br /&gt;
scene object classes, inventory structures, and the [[OpenSimulator_Internals/Code_Map/Scene|Scene]] itself.&lt;br /&gt;
&lt;br /&gt;
=== OpenSim.Region.OptionalModules ===&lt;br /&gt;
&lt;br /&gt;
Region modules not considered core; could in principle be removed while retaining&lt;br /&gt;
a functional Second Life-compatible simulator.&lt;br /&gt;
&lt;br /&gt;
=== OpenSim.Region.Physics ===&lt;br /&gt;
&lt;br /&gt;
Physics framework and engine plugins: BulletSim, ubODE, ODE.&lt;br /&gt;
&lt;br /&gt;
=== OpenSim.Region.ScriptEngine ===&lt;br /&gt;
&lt;br /&gt;
Script engine infrastructure. Current engines: XEngine (older), YEngine (current).&lt;br /&gt;
&lt;br /&gt;
=== OpenSim.Region.UserStatistics ===&lt;br /&gt;
&lt;br /&gt;
Exposes simulator statistics via a web page.&lt;br /&gt;
&lt;br /&gt;
== OpenSim.Server ==&lt;br /&gt;
&lt;br /&gt;
Server infrastructure shared between the region simulator and ROBUST.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;OpenSim.Server.Base&#039;&#039;&#039; — common server infrastructure.&lt;br /&gt;
* &#039;&#039;&#039;OpenSim.Server.Handlers&#039;&#039;&#039; — translates raw incoming HTTP requests to&lt;br /&gt;
  service calls. Used primarily in grid mode for ROBUST instances.&lt;br /&gt;
  Example: &amp;lt;code&amp;gt;Asset/AssetServerGetHandler&amp;lt;/code&amp;gt; translates an asset fetch&lt;br /&gt;
  request into a call to the asset service and returns the result.&lt;br /&gt;
&lt;br /&gt;
== OpenSim.Services ==&lt;br /&gt;
&lt;br /&gt;
Service implementations and the connectors that invoke them remotely over HTTP.&lt;br /&gt;
&lt;br /&gt;
* In &#039;&#039;&#039;grid mode&#039;&#039;&#039;: service implementations run inside ROBUST instances.&lt;br /&gt;
* In &#039;&#039;&#039;standalone mode&#039;&#039;&#039;: service implementations are instantiated directly&lt;br /&gt;
  inside OpenSim.exe.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;OpenSim.Services.Connectors&amp;lt;/code&amp;gt; contains the HTTP client code that&lt;br /&gt;
region simulators use to talk to remote ROBUST services.&lt;br /&gt;
&lt;br /&gt;
See [[OpenSimulator_Internals/Connector_Architecture|Connector Architecture]]&lt;br /&gt;
for the full connector and service table.&lt;br /&gt;
&lt;br /&gt;
== OpenSim.Tests ==&lt;br /&gt;
&lt;br /&gt;
Test infrastructure and some standalone client test code.&lt;br /&gt;
Actual regression tests live in &amp;lt;code&amp;gt;*.Tests&amp;lt;/code&amp;gt; subpackages throughout&lt;br /&gt;
the tree (e.g. &amp;lt;code&amp;gt;OpenSim.Region.Framework.Tests&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
== OpenSim.Tools ==&lt;br /&gt;
&lt;br /&gt;
Utility tools associated with OpenSimulator but not used in normal operation.&lt;br /&gt;
&lt;br /&gt;
== See Also ==&lt;br /&gt;
&lt;br /&gt;
* [[OpenSimulator_Internals/Code_Map|Code Map]] — per-class internals&lt;br /&gt;
* [[OpenSimulator_Internals/Connector_Architecture|Connector Architecture]] — service/connector table&lt;br /&gt;
* [[OpenSimulator_Internals/Useful_Queries|Useful Queries]] — database reference&lt;br /&gt;
* [[OpenSimulator_Internals/Walkthroughs|Walkthroughs]] — runtime flow documentation&lt;br /&gt;
&lt;br /&gt;
[[Category:OpenSimulator Internals]]&lt;/div&gt;</summary>
		<author><name>Jwbshaw</name></author>
	</entry>
	<entry>
		<id>http://osimdev.org/wiki/index.php?title=OpenSimulator_Internals/Package_Overview&amp;diff=113</id>
		<title>OpenSimulator Internals/Package Overview</title>
		<link rel="alternate" type="text/html" href="http://osimdev.org/wiki/index.php?title=OpenSimulator_Internals/Package_Overview&amp;diff=113"/>
		<updated>2026-07-08T20:58:31Z</updated>

		<summary type="html">&lt;p&gt;Jwbshaw: quibbles&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;# Draft: OpenSimulator Internals/Package Overview&lt;br /&gt;
&lt;br /&gt;
Target URL: http://osimdev.org/wiki/index.php/OpenSimulator_Internals/Package_Overview&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## Wiki markup&lt;br /&gt;
&lt;br /&gt;
```mediawiki&lt;br /&gt;
= Package Overview =&lt;br /&gt;
&lt;br /&gt;
OpenSimulator&#039;s source tree is organized into a hierarchy of packages (C# projects).&lt;br /&gt;
This page gives a top-level map. For detailed internals of individual classes,&lt;br /&gt;
see the [[OpenSimulator_Internals/Code_Map|Code Map]] pages.&lt;br /&gt;
&lt;br /&gt;
== OpenSim ==&lt;br /&gt;
&lt;br /&gt;
The top-level package launches the region server and manages the console.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Entry point:&#039;&#039;&#039; &amp;lt;code&amp;gt;OpenSim/Region/Application/Application.cs&amp;lt;/code&amp;gt; — &amp;lt;code&amp;gt;Main()&amp;lt;/code&amp;gt;&lt;br /&gt;
  instantiates an &amp;lt;code&amp;gt;OpenSim&amp;lt;/code&amp;gt; object, calls &amp;lt;code&amp;gt;Startup()&amp;lt;/code&amp;gt; (which spins&lt;br /&gt;
  up worker threads), then blocks the initial thread on the main console prompt.&lt;br /&gt;
* &amp;lt;code&amp;gt;OpenSim.Startup()&amp;lt;/code&amp;gt; is inherited from&lt;br /&gt;
  &amp;lt;code&amp;gt;OpenSim.Framework.Servers.BaseOpenSimServer&amp;lt;/code&amp;gt;; it delegates to&lt;br /&gt;
  &amp;lt;code&amp;gt;StartupSpecific()&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== OpenSim.Addons ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Note: not actively maintained. Use with caution.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;OpenSim.Addons.Groups&#039;&#039;&#039; — group support.&lt;br /&gt;
* &#039;&#039;&#039;OpenSim.Addons.OfflineIM&#039;&#039;&#039; — offline IM support.&lt;br /&gt;
&lt;br /&gt;
== OpenSim.ApplicationPlugins ==&lt;br /&gt;
&lt;br /&gt;
Application plugins: modular code that affects the entire region server&lt;br /&gt;
(as distinct from [[OpenSimulator_Internals/Package_Overview#OpenSim.Region.CoreModules|region modules]],&lt;br /&gt;
which affect individual regions).&lt;br /&gt;
&lt;br /&gt;
== OpenSim.Capabilities ==&lt;br /&gt;
&lt;br /&gt;
Basic data structures for capability (HTTPS/event-queue) support.&lt;br /&gt;
&lt;br /&gt;
== OpenSim.ConsoleClient ==&lt;br /&gt;
&lt;br /&gt;
REST console client for remote connection to a running OpenSimulator instance.&lt;br /&gt;
Not widely deployed; most operators use a &amp;lt;code&amp;gt;screen&amp;lt;/code&amp;gt; session on Linux&lt;br /&gt;
or separate terminals on Windows.&lt;br /&gt;
&lt;br /&gt;
== OpenSim.Data ==&lt;br /&gt;
&lt;br /&gt;
All low-level database access code. Contains per-backend packages:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;OpenSim.Data.MySQL&#039;&#039;&#039; — MySQL/MariaDB backend (primary for grid deployments).&lt;br /&gt;
* &#039;&#039;&#039;OpenSim.Data.SQLite&#039;&#039;&#039; — SQLite backend (common for standalone/testing).&lt;br /&gt;
&lt;br /&gt;
Each backend implements the &amp;lt;code&amp;gt;IAssetData&amp;lt;/code&amp;gt; and sibling interfaces defined here.&lt;br /&gt;
The interface hierarchy is: &amp;lt;code&amp;gt;OpenSim.Data&amp;lt;/code&amp;gt; defines the interfaces;&lt;br /&gt;
per-DB packages provide the implementations.&lt;br /&gt;
&lt;br /&gt;
See also: [[OpenSimulator_Internals/Useful_Queries|Useful Queries]].&lt;br /&gt;
&lt;br /&gt;
== OpenSim.Framework ==&lt;br /&gt;
&lt;br /&gt;
General framework code shared across the simulator and ROBUST. Not region-specific.&lt;br /&gt;
&lt;br /&gt;
Subpackages of note:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Subpackage !! Purpose&lt;br /&gt;
|-&lt;br /&gt;
| OpenSim.Framework.AssetLoader.Filesystem || Loads library assets from the local filesystem.&lt;br /&gt;
|-&lt;br /&gt;
| OpenSim.Framework.Console || Console infrastructure.&lt;br /&gt;
|-&lt;br /&gt;
| OpenSim.Framework.Monitoring || Statistics gathering and monitoring.&lt;br /&gt;
|-&lt;br /&gt;
| OpenSim.Framework.RegionLoader.FileSystem || Loads region config from filesystem (e.g. &amp;lt;code&amp;gt;bin/Regions/Regions.ini&amp;lt;/code&amp;gt;).&lt;br /&gt;
|-&lt;br /&gt;
| OpenSim.Framework.RegionLoader.Web || Loads region config from a remote URL.&lt;br /&gt;
|-&lt;br /&gt;
| OpenSim.Framework.Serialization || OAR and IAR read/write infrastructure.&lt;br /&gt;
|-&lt;br /&gt;
| OpenSim.Framework.Servers || Generic server base classes, HTTP server infrastructure.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Two subpackages handle configuration loading from HTTP and XML respectively;&lt;br /&gt;
neither is a current deployment path.&lt;br /&gt;
&lt;br /&gt;
== OpenSim.Region ==&lt;br /&gt;
&lt;br /&gt;
Most of the region-specific code lives here.&lt;br /&gt;
&lt;br /&gt;
=== OpenSim.Region.ClientStack ===&lt;br /&gt;
&lt;br /&gt;
Infrastructure for pluggable UDP client stacks. In practice only one stack exists&lt;br /&gt;
(LLUDP); the abstraction remains in case alternatives are ever needed.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;OpenSim.Region.ClientStack.LindenCaps&#039;&#039;&#039; — HTTP/capability side of the Second Life&lt;br /&gt;
  protocol. Glues cap requests to region modules.&lt;br /&gt;
* &#039;&#039;&#039;OpenSim.Region.ClientStack.LindenUDP&#039;&#039;&#039; — UDP side of the Second Life protocol.&lt;br /&gt;
  Glues UDP packets to scene and region module code.&lt;br /&gt;
&lt;br /&gt;
Future Code Map page: [[OpenSimulator_Internals/Code_Map/LLUDPServer|LLUDPServer]] (planned).&lt;br /&gt;
&lt;br /&gt;
=== OpenSim.Region.CoreModules ===&lt;br /&gt;
&lt;br /&gt;
The bundled region modules. This is a large package covering a wide range of&lt;br /&gt;
functionality. Key modules documented in the Code Map:&lt;br /&gt;
&lt;br /&gt;
* [[OpenSimulator_Internals/Code_Map/AttachmentsModule|AttachmentsModule]] — avatar attachment lifecycle.&lt;br /&gt;
* [[OpenSimulator_Internals/Code_Map/EntityTransferModule|EntityTransferModule]] — region crossings and teleports.&lt;br /&gt;
* [[OpenSimulator_Internals/Code_Map/HGEntityTransferModule|HGEntityTransferModule]] — Hypergrid teleport handling.&lt;br /&gt;
* [[OpenSimulator_Internals/Code_Map/InventoryAccessModule|InventoryAccessModule]] — inventory access during rez/derez.&lt;br /&gt;
* [[OpenSimulator_Internals/Code_Map/AvatarFactoryModule|AvatarFactoryModule]] — avatar appearance management.&lt;br /&gt;
&lt;br /&gt;
=== OpenSim.Region.DataSnapshot ===&lt;br /&gt;
&lt;br /&gt;
Generates an XML summary of region contents; can be exposed to external search engines.&lt;br /&gt;
&lt;br /&gt;
=== OpenSim.Region.Framework ===&lt;br /&gt;
&lt;br /&gt;
The core of the simulator: scene graph, [[OpenSimulator_Internals/Code_Map/ScenePresence|ScenePresence]],&lt;br /&gt;
scene object classes, inventory structures, and the [[OpenSimulator_Internals/Code_Map/Scene|Scene]] itself.&lt;br /&gt;
&lt;br /&gt;
=== OpenSim.Region.OptionalModules ===&lt;br /&gt;
&lt;br /&gt;
Region modules not considered core; could in principle be removed while retaining&lt;br /&gt;
a functional Second Life-compatible simulator.&lt;br /&gt;
&lt;br /&gt;
=== OpenSim.Region.Physics ===&lt;br /&gt;
&lt;br /&gt;
Physics framework and engine plugins: BulletSim, ubODE, ODE.&lt;br /&gt;
&lt;br /&gt;
=== OpenSim.Region.ScriptEngine ===&lt;br /&gt;
&lt;br /&gt;
Script engine infrastructure. Current engines: XEngine (older), YEngine (current).&lt;br /&gt;
&lt;br /&gt;
=== OpenSim.Region.UserStatistics ===&lt;br /&gt;
&lt;br /&gt;
Exposes simulator statistics via a web page.&lt;br /&gt;
&lt;br /&gt;
== OpenSim.Server ==&lt;br /&gt;
&lt;br /&gt;
Server infrastructure shared between the region simulator and ROBUST.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;OpenSim.Server.Base&#039;&#039;&#039; — common server infrastructure.&lt;br /&gt;
* &#039;&#039;&#039;OpenSim.Server.Handlers&#039;&#039;&#039; — translates raw incoming HTTP requests to&lt;br /&gt;
  service calls. Used primarily in grid mode for ROBUST instances.&lt;br /&gt;
  Example: &amp;lt;code&amp;gt;Asset/AssetServerGetHandler&amp;lt;/code&amp;gt; translates an asset fetch&lt;br /&gt;
  request into a call to the asset service and returns the result.&lt;br /&gt;
&lt;br /&gt;
== OpenSim.Services ==&lt;br /&gt;
&lt;br /&gt;
Service implementations and the connectors that invoke them remotely over HTTP.&lt;br /&gt;
&lt;br /&gt;
* In &#039;&#039;&#039;grid mode&#039;&#039;&#039;: service implementations run inside ROBUST instances.&lt;br /&gt;
* In &#039;&#039;&#039;standalone mode&#039;&#039;&#039;: service implementations are instantiated directly&lt;br /&gt;
  inside OpenSim.exe.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;OpenSim.Services.Connectors&amp;lt;/code&amp;gt; contains the HTTP client code that&lt;br /&gt;
region simulators use to talk to remote ROBUST services.&lt;br /&gt;
&lt;br /&gt;
See [[OpenSimulator_Internals/Connector_Architecture|Connector Architecture]]&lt;br /&gt;
for the full connector and service table.&lt;br /&gt;
&lt;br /&gt;
== OpenSim.Tests ==&lt;br /&gt;
&lt;br /&gt;
Test infrastructure and some standalone client test code.&lt;br /&gt;
Actual regression tests live in &amp;lt;code&amp;gt;*.Tests&amp;lt;/code&amp;gt; subpackages throughout&lt;br /&gt;
the tree (e.g. &amp;lt;code&amp;gt;OpenSim.Region.Framework.Tests&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
== OpenSim.Tools ==&lt;br /&gt;
&lt;br /&gt;
Utility tools associated with OpenSimulator but not used in normal operation.&lt;br /&gt;
&lt;br /&gt;
== See Also ==&lt;br /&gt;
&lt;br /&gt;
* [[OpenSimulator_Internals/Code_Map|Code Map]] — per-class internals&lt;br /&gt;
* [[OpenSimulator_Internals/Connector_Architecture|Connector Architecture]] — service/connector table&lt;br /&gt;
* [[OpenSimulator_Internals/Useful_Queries|Useful Queries]] — database reference&lt;br /&gt;
* [[OpenSimulator_Internals/Walkthroughs|Walkthroughs]] — runtime flow documentation&lt;br /&gt;
&lt;br /&gt;
[[Category:OpenSimulator Internals]]&lt;br /&gt;
```&lt;/div&gt;</summary>
		<author><name>Jwbshaw</name></author>
	</entry>
	<entry>
		<id>http://osimdev.org/wiki/index.php?title=OpenSimulator_Internals/Package_Overview&amp;diff=112</id>
		<title>OpenSimulator Internals/Package Overview</title>
		<link rel="alternate" type="text/html" href="http://osimdev.org/wiki/index.php?title=OpenSimulator_Internals/Package_Overview&amp;diff=112"/>
		<updated>2026-07-08T20:52:30Z</updated>

		<summary type="html">&lt;p&gt;Jwbshaw: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;# Draft: OpenSimulator Internals/Package Overview&lt;br /&gt;
&lt;br /&gt;
Target URL: http://osimdev.org/wiki/index.php/OpenSimulator_Internals/Package_Overview&lt;br /&gt;
&lt;br /&gt;
---&lt;br /&gt;
&lt;br /&gt;
## Wiki markup&lt;br /&gt;
&lt;br /&gt;
```mediawiki&lt;br /&gt;
= Package Overview =&lt;br /&gt;
&lt;br /&gt;
OpenSimulator&#039;s source tree is organized into a hierarchy of packages (C# projects).&lt;br /&gt;
This page gives a top-level map. For detailed internals of individual classes,&lt;br /&gt;
see the [[OpenSimulator_Internals/Code_Map|Code Map]] pages.&lt;br /&gt;
&lt;br /&gt;
== OpenSim ==&lt;br /&gt;
&lt;br /&gt;
The top-level package launches the region server and manages the console.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Entry point:&#039;&#039;&#039; &amp;lt;code&amp;gt;OpenSim/Region/Application/Application.cs&amp;lt;/code&amp;gt; — &amp;lt;code&amp;gt;Main()&amp;lt;/code&amp;gt;&lt;br /&gt;
  instantiates an &amp;lt;code&amp;gt;OpenSim&amp;lt;/code&amp;gt; object, calls &amp;lt;code&amp;gt;Startup()&amp;lt;/code&amp;gt; (which spins&lt;br /&gt;
  up worker threads), then blocks the initial thread on the main console prompt.&lt;br /&gt;
* &amp;lt;code&amp;gt;OpenSim.Startup()&amp;lt;/code&amp;gt; is inherited from&lt;br /&gt;
  &amp;lt;code&amp;gt;OpenSim.Framework.Servers.BaseOpenSimServer&amp;lt;/code&amp;gt;; it delegates to&lt;br /&gt;
  &amp;lt;code&amp;gt;StartupSpecific()&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== OpenSim.Addons ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Note: not actively maintained. Use with caution.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;OpenSim.Addons.Groups&#039;&#039;&#039; — group support.&lt;br /&gt;
* &#039;&#039;&#039;OpenSim.Addons.OfflineIM&#039;&#039;&#039; — offline IM support.&lt;br /&gt;
&lt;br /&gt;
== OpenSim.ApplicationPlugins ==&lt;br /&gt;
&lt;br /&gt;
Application plugins: modular code that affects the entire region server&lt;br /&gt;
(as distinct from [[OpenSimulator_Internals/Package_Overview#OpenSim.Region.CoreModules|region modules]],&lt;br /&gt;
which affect individual regions).&lt;br /&gt;
&lt;br /&gt;
== OpenSim.Capabilities ==&lt;br /&gt;
&lt;br /&gt;
Basic data structures for capability (HTTPS/event-queue) support.&lt;br /&gt;
&lt;br /&gt;
== OpenSim.ConsoleClient ==&lt;br /&gt;
&lt;br /&gt;
REST console client for remote connection to a running OpenSimulator instance.&lt;br /&gt;
Not widely deployed; most operators use a &amp;lt;code&amp;gt;screen&amp;lt;/code&amp;gt; session on Linux&lt;br /&gt;
or separate terminals on Windows.&lt;br /&gt;
&lt;br /&gt;
== OpenSim.Data ==&lt;br /&gt;
&lt;br /&gt;
All low-level database access code. Contains per-backend packages:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;OpenSim.Data.MySQL&#039;&#039;&#039; — MySQL/MariaDB backend (primary for grid deployments).&lt;br /&gt;
* &#039;&#039;&#039;OpenSim.Data.SQLite&#039;&#039;&#039; — SQLite backend (common for standalone/testing).&lt;br /&gt;
* &#039;&#039;&#039;OpenSim.Data.MSSQL&#039;&#039;&#039; — Microsoft SQL Server backend. Perpetually behind; use MySQL/MariaDB or SQLite.&lt;br /&gt;
&lt;br /&gt;
Each backend implements the &amp;lt;code&amp;gt;IAssetData&amp;lt;/code&amp;gt; and sibling interfaces defined here.&lt;br /&gt;
The interface hierarchy is: &amp;lt;code&amp;gt;OpenSim.Data&amp;lt;/code&amp;gt; defines the interfaces;&lt;br /&gt;
per-DB packages provide the implementations.&lt;br /&gt;
&lt;br /&gt;
See also: [[OpenSimulator_Internals/Useful_Queries|Useful Queries]].&lt;br /&gt;
&lt;br /&gt;
== OpenSim.Framework ==&lt;br /&gt;
&lt;br /&gt;
General framework code shared across the simulator and ROBUST. Not region-specific.&lt;br /&gt;
&lt;br /&gt;
Subpackages of note:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Subpackage !! Purpose&lt;br /&gt;
|-&lt;br /&gt;
| OpenSim.Framework.AssetLoader.Filesystem || Loads library assets from the local filesystem.&lt;br /&gt;
|-&lt;br /&gt;
| OpenSim.Framework.Console || Console infrastructure.&lt;br /&gt;
|-&lt;br /&gt;
| OpenSim.Framework.Monitoring || Statistics gathering and monitoring.&lt;br /&gt;
|-&lt;br /&gt;
| OpenSim.Framework.RegionLoader.FileSystem || Loads region config from filesystem (e.g. &amp;lt;code&amp;gt;bin/Regions/Regions.ini&amp;lt;/code&amp;gt;).&lt;br /&gt;
|-&lt;br /&gt;
| OpenSim.Framework.RegionLoader.Web || Loads region config from a remote URL.&lt;br /&gt;
|-&lt;br /&gt;
| OpenSim.Framework.Serialization || OAR and IAR read/write infrastructure.&lt;br /&gt;
|-&lt;br /&gt;
| OpenSim.Framework.Servers || Generic server base classes, HTTP server infrastructure.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Two subpackages handle configuration loading from HTTP and XML respectively;&lt;br /&gt;
both may have decayed and are not considered current deployment paths.&lt;br /&gt;
&lt;br /&gt;
== OpenSim.Region ==&lt;br /&gt;
&lt;br /&gt;
Most of the region-specific code lives here.&lt;br /&gt;
&lt;br /&gt;
=== OpenSim.Region.ClientStack ===&lt;br /&gt;
&lt;br /&gt;
Infrastructure for pluggable UDP client stacks. In practice only one stack exists&lt;br /&gt;
(LLUDP); the abstraction remains in case alternatives are ever needed.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;OpenSim.Region.ClientStack.LindenCaps&#039;&#039;&#039; — HTTP/capability side of the Second Life&lt;br /&gt;
  protocol. Glues cap requests to region modules.&lt;br /&gt;
* &#039;&#039;&#039;OpenSim.Region.ClientStack.LindenUDP&#039;&#039;&#039; — UDP side of the Second Life protocol.&lt;br /&gt;
  Glues UDP packets to scene and region module code.&lt;br /&gt;
&lt;br /&gt;
Future Code Map page: [[OpenSimulator_Internals/Code_Map/LLUDPServer|LLUDPServer]] (planned).&lt;br /&gt;
&lt;br /&gt;
=== OpenSim.Region.CoreModules ===&lt;br /&gt;
&lt;br /&gt;
The bundled region modules. This is a large package covering a wide range of&lt;br /&gt;
functionality. Key modules documented in the Code Map:&lt;br /&gt;
&lt;br /&gt;
* [[OpenSimulator_Internals/Code_Map/AttachmentsModule|AttachmentsModule]] — avatar attachment lifecycle.&lt;br /&gt;
* [[OpenSimulator_Internals/Code_Map/EntityTransferModule|EntityTransferModule]] — region crossings and teleports.&lt;br /&gt;
* [[OpenSimulator_Internals/Code_Map/HGEntityTransferModule|HGEntityTransferModule]] — Hypergrid teleport handling.&lt;br /&gt;
* [[OpenSimulator_Internals/Code_Map/InventoryAccessModule|InventoryAccessModule]] — inventory access during rez/derez.&lt;br /&gt;
* [[OpenSimulator_Internals/Code_Map/AvatarFactoryModule|AvatarFactoryModule]] — avatar appearance management.&lt;br /&gt;
&lt;br /&gt;
=== OpenSim.Region.DataSnapshot ===&lt;br /&gt;
&lt;br /&gt;
Generates an XML summary of region contents; can be exposed to external search engines.&lt;br /&gt;
&lt;br /&gt;
=== OpenSim.Region.Framework ===&lt;br /&gt;
&lt;br /&gt;
The core of the simulator: scene graph, [[OpenSimulator_Internals/Code_Map/ScenePresence|ScenePresence]],&lt;br /&gt;
scene object classes, inventory structures, and the [[OpenSimulator_Internals/Code_Map/Scene|Scene]] itself.&lt;br /&gt;
&lt;br /&gt;
=== OpenSim.Region.OptionalModules ===&lt;br /&gt;
&lt;br /&gt;
Region modules not considered core; could in principle be removed while retaining&lt;br /&gt;
a functional Second Life-compatible simulator.&lt;br /&gt;
&lt;br /&gt;
=== OpenSim.Region.Physics ===&lt;br /&gt;
&lt;br /&gt;
Physics framework and engine plugins: BulletSim, ubODE, ODE.&lt;br /&gt;
&lt;br /&gt;
=== OpenSim.Region.ScriptEngine ===&lt;br /&gt;
&lt;br /&gt;
Script engine infrastructure. Current engines: XEngine (older), YEngine (current).&lt;br /&gt;
&lt;br /&gt;
=== OpenSim.Region.UserStatistics ===&lt;br /&gt;
&lt;br /&gt;
Exposes simulator statistics via a web page.&lt;br /&gt;
&lt;br /&gt;
== OpenSim.Server ==&lt;br /&gt;
&lt;br /&gt;
Server infrastructure shared between the region simulator and ROBUST.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;OpenSim.Server.Base&#039;&#039;&#039; — common server infrastructure.&lt;br /&gt;
* &#039;&#039;&#039;OpenSim.Server.Handlers&#039;&#039;&#039; — translates raw incoming HTTP requests to&lt;br /&gt;
  service calls. Used primarily in grid mode for ROBUST instances.&lt;br /&gt;
  Example: &amp;lt;code&amp;gt;Asset/AssetServerGetHandler&amp;lt;/code&amp;gt; translates an asset fetch&lt;br /&gt;
  request into a call to the asset service and returns the result.&lt;br /&gt;
&lt;br /&gt;
== OpenSim.Services ==&lt;br /&gt;
&lt;br /&gt;
Service implementations and the connectors that invoke them remotely over HTTP.&lt;br /&gt;
&lt;br /&gt;
* In &#039;&#039;&#039;grid mode&#039;&#039;&#039;: service implementations run inside ROBUST instances.&lt;br /&gt;
* In &#039;&#039;&#039;standalone mode&#039;&#039;&#039;: service implementations are instantiated directly&lt;br /&gt;
  inside OpenSim.exe.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;OpenSim.Services.Connectors&amp;lt;/code&amp;gt; contains the HTTP client code that&lt;br /&gt;
region simulators use to talk to remote ROBUST services.&lt;br /&gt;
&lt;br /&gt;
See [[OpenSimulator_Internals/Connector_Architecture|Connector Architecture]]&lt;br /&gt;
for the full connector and service table.&lt;br /&gt;
&lt;br /&gt;
== OpenSim.Tests ==&lt;br /&gt;
&lt;br /&gt;
Test infrastructure and some standalone client test code.&lt;br /&gt;
Actual regression tests live in &amp;lt;code&amp;gt;*.Tests&amp;lt;/code&amp;gt; subpackages throughout&lt;br /&gt;
the tree (e.g. &amp;lt;code&amp;gt;OpenSim.Region.Framework.Tests&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
== OpenSim.Tools ==&lt;br /&gt;
&lt;br /&gt;
Utility tools associated with OpenSimulator but not used in normal operation.&lt;br /&gt;
&lt;br /&gt;
== See Also ==&lt;br /&gt;
&lt;br /&gt;
* [[OpenSimulator_Internals/Code_Map|Code Map]] — per-class internals&lt;br /&gt;
* [[OpenSimulator_Internals/Connector_Architecture|Connector Architecture]] — service/connector table&lt;br /&gt;
* [[OpenSimulator_Internals/Useful_Queries|Useful Queries]] — database reference&lt;br /&gt;
* [[OpenSimulator_Internals/Walkthroughs|Walkthroughs]] — runtime flow documentation&lt;br /&gt;
&lt;br /&gt;
[[Category:OpenSimulator Internals]]&lt;br /&gt;
```&lt;/div&gt;</summary>
		<author><name>Jwbshaw</name></author>
	</entry>
	<entry>
		<id>http://osimdev.org/wiki/index.php?title=OpenSimulator_Internals/Package_Overview&amp;diff=111</id>
		<title>OpenSimulator Internals/Package Overview</title>
		<link rel="alternate" type="text/html" href="http://osimdev.org/wiki/index.php?title=OpenSimulator_Internals/Package_Overview&amp;diff=111"/>
		<updated>2026-07-08T20:48:17Z</updated>

		<summary type="html">&lt;p&gt;Jwbshaw: first&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Package Overview =&lt;br /&gt;
&lt;br /&gt;
OpenSimulator&#039;s source tree is organized into a hierarchy of packages (C# projects).&lt;br /&gt;
This page gives a top-level map. For detailed internals of individual classes,&lt;br /&gt;
see the [[OpenSimulator_Internals/Code_Map|Code Map]] pages.&lt;br /&gt;
&lt;br /&gt;
== OpenSim ==&lt;br /&gt;
&lt;br /&gt;
The top-level package launches the region server and manages the console.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Entry point:&#039;&#039;&#039; &amp;lt;code&amp;gt;OpenSim/Region/Application/Application.cs&amp;lt;/code&amp;gt; — &amp;lt;code&amp;gt;Main()&amp;lt;/code&amp;gt;&lt;br /&gt;
  instantiates an &amp;lt;code&amp;gt;OpenSim&amp;lt;/code&amp;gt; object, calls &amp;lt;code&amp;gt;Startup()&amp;lt;/code&amp;gt; (which spins&lt;br /&gt;
  up worker threads), then blocks the initial thread on the main console prompt.&lt;br /&gt;
* &amp;lt;code&amp;gt;OpenSim.Startup()&amp;lt;/code&amp;gt; is inherited from&lt;br /&gt;
  &amp;lt;code&amp;gt;OpenSim.Framework.Servers.BaseOpenSimServer&amp;lt;/code&amp;gt;; it delegates to&lt;br /&gt;
  &amp;lt;code&amp;gt;StartupSpecific()&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== OpenSim.Addons ==&lt;br /&gt;
&lt;br /&gt;
Components originally from the Diva distribution; organized differently from the&lt;br /&gt;
main tree as a result.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;OpenSim.Addons.Groups&#039;&#039;&#039; — core group support.&lt;br /&gt;
* &#039;&#039;&#039;OpenSim.Addons.OfflineIM&#039;&#039;&#039; — core offline IM support.&lt;br /&gt;
&lt;br /&gt;
== OpenSim.ApplicationPlugins ==&lt;br /&gt;
&lt;br /&gt;
Application plugins: modular code that affects the entire region server&lt;br /&gt;
(as distinct from [[OpenSimulator_Internals/Package_Overview#OpenSim.Region.CoreModules|region modules]],&lt;br /&gt;
which affect individual regions).&lt;br /&gt;
&lt;br /&gt;
== OpenSim.Capabilities ==&lt;br /&gt;
&lt;br /&gt;
Basic data structures for capability (HTTPS/event-queue) support.&lt;br /&gt;
&lt;br /&gt;
== OpenSim.ConsoleClient ==&lt;br /&gt;
&lt;br /&gt;
REST console client for remote connection to a running OpenSimulator instance.&lt;br /&gt;
Not widely deployed; most operators use a &amp;lt;code&amp;gt;screen&amp;lt;/code&amp;gt; session on Linux&lt;br /&gt;
or separate terminals on Windows.&lt;br /&gt;
&lt;br /&gt;
== OpenSim.Data ==&lt;br /&gt;
&lt;br /&gt;
All low-level database access code. Contains per-backend packages:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;OpenSim.Data.MySQL&#039;&#039;&#039; — MySQL/MariaDB backend (primary for grid deployments).&lt;br /&gt;
* &#039;&#039;&#039;OpenSim.Data.SQLite&#039;&#039;&#039; — SQLite backend (common for standalone/testing).&lt;br /&gt;
* &#039;&#039;&#039;OpenSim.Data.MSSQL&#039;&#039;&#039; — Microsoft SQL Server backend (tends to lag behind the others).&lt;br /&gt;
&lt;br /&gt;
Each backend implements the &amp;lt;code&amp;gt;IAssetData&amp;lt;/code&amp;gt; and sibling interfaces defined here.&lt;br /&gt;
The interface hierarchy is: &amp;lt;code&amp;gt;OpenSim.Data&amp;lt;/code&amp;gt; defines the interfaces;&lt;br /&gt;
per-DB packages provide the implementations.&lt;br /&gt;
&lt;br /&gt;
See also: [[OpenSimulator_Internals/Useful_Queries|Useful Queries]].&lt;br /&gt;
&lt;br /&gt;
== OpenSim.Framework ==&lt;br /&gt;
&lt;br /&gt;
General framework code shared across the simulator and ROBUST. Not region-specific.&lt;br /&gt;
&lt;br /&gt;
Subpackages of note:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Subpackage !! Purpose&lt;br /&gt;
|-&lt;br /&gt;
| OpenSim.Framework.AssetLoader.Filesystem || Loads library assets from the local filesystem.&lt;br /&gt;
|-&lt;br /&gt;
| OpenSim.Framework.Console || Console infrastructure.&lt;br /&gt;
|-&lt;br /&gt;
| OpenSim.Framework.Monitoring || Statistics gathering and monitoring.&lt;br /&gt;
|-&lt;br /&gt;
| OpenSim.Framework.RegionLoader.FileSystem || Loads region config from filesystem (e.g. &amp;lt;code&amp;gt;bin/Regions/Regions.ini&amp;lt;/code&amp;gt;).&lt;br /&gt;
|-&lt;br /&gt;
| OpenSim.Framework.RegionLoader.Web || Loads region config from a remote URL.&lt;br /&gt;
|-&lt;br /&gt;
| OpenSim.Framework.Serialization || OAR and IAR read/write infrastructure.&lt;br /&gt;
|-&lt;br /&gt;
| OpenSim.Framework.Servers || Generic server base classes, HTTP server infrastructure.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Two subpackages handle configuration loading from HTTP and XML respectively;&lt;br /&gt;
both may have decayed and are not considered current deployment paths.&lt;br /&gt;
&lt;br /&gt;
== OpenSim.Region ==&lt;br /&gt;
&lt;br /&gt;
Most of the region-specific code lives here.&lt;br /&gt;
&lt;br /&gt;
=== OpenSim.Region.ClientStack ===&lt;br /&gt;
&lt;br /&gt;
Infrastructure for pluggable UDP client stacks. In practice only one stack exists&lt;br /&gt;
(LLUDP); the abstraction remains in case alternatives are ever needed.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;OpenSim.Region.ClientStack.LindenCaps&#039;&#039;&#039; — HTTP/capability side of the Second Life&lt;br /&gt;
  protocol. Glues cap requests to region modules.&lt;br /&gt;
* &#039;&#039;&#039;OpenSim.Region.ClientStack.LindenUDP&#039;&#039;&#039; — UDP side of the Second Life protocol.&lt;br /&gt;
  Glues UDP packets to scene and region module code.&lt;br /&gt;
&lt;br /&gt;
Future Code Map page: [[OpenSimulator_Internals/Code_Map/LLUDPServer|LLUDPServer]] (planned).&lt;br /&gt;
&lt;br /&gt;
=== OpenSim.Region.CoreModules ===&lt;br /&gt;
&lt;br /&gt;
The bundled region modules. This is a large package covering a wide range of&lt;br /&gt;
functionality. Key modules documented in the Code Map:&lt;br /&gt;
&lt;br /&gt;
* [[OpenSimulator_Internals/Code_Map/AttachmentsModule|AttachmentsModule]] — avatar attachment lifecycle.&lt;br /&gt;
* [[OpenSimulator_Internals/Code_Map/EntityTransferModule|EntityTransferModule]] — region crossings and teleports.&lt;br /&gt;
* [[OpenSimulator_Internals/Code_Map/HGEntityTransferModule|HGEntityTransferModule]] — Hypergrid teleport handling.&lt;br /&gt;
* [[OpenSimulator_Internals/Code_Map/InventoryAccessModule|InventoryAccessModule]] — inventory access during rez/derez.&lt;br /&gt;
* [[OpenSimulator_Internals/Code_Map/AvatarFactoryModule|AvatarFactoryModule]] — avatar appearance management.&lt;br /&gt;
&lt;br /&gt;
=== OpenSim.Region.DataSnapshot ===&lt;br /&gt;
&lt;br /&gt;
Generates an XML summary of region contents; can be exposed to external search engines.&lt;br /&gt;
&lt;br /&gt;
=== OpenSim.Region.Framework ===&lt;br /&gt;
&lt;br /&gt;
The core of the simulator: scene graph, [[OpenSimulator_Internals/Code_Map/ScenePresence|ScenePresence]],&lt;br /&gt;
scene object classes, inventory structures, and the [[OpenSimulator_Internals/Code_Map/Scene|Scene]] itself.&lt;br /&gt;
&lt;br /&gt;
=== OpenSim.Region.OptionalModules ===&lt;br /&gt;
&lt;br /&gt;
Region modules not considered core; could in principle be removed while retaining&lt;br /&gt;
a functional Second Life-compatible simulator.&lt;br /&gt;
&lt;br /&gt;
=== OpenSim.Region.Physics ===&lt;br /&gt;
&lt;br /&gt;
Physics framework and engine plugins: BulletSim, ubODE, ODE.&lt;br /&gt;
&lt;br /&gt;
=== OpenSim.Region.ScriptEngine ===&lt;br /&gt;
&lt;br /&gt;
Script engine infrastructure. Current engines: XEngine (older), YEngine (current).&lt;br /&gt;
&lt;br /&gt;
=== OpenSim.Region.UserStatistics ===&lt;br /&gt;
&lt;br /&gt;
Exposes simulator statistics via a web page.&lt;br /&gt;
&lt;br /&gt;
== OpenSim.Server ==&lt;br /&gt;
&lt;br /&gt;
Server infrastructure shared between the region simulator and ROBUST.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;OpenSim.Server.Base&#039;&#039;&#039; — common server infrastructure.&lt;br /&gt;
* &#039;&#039;&#039;OpenSim.Server.Handlers&#039;&#039;&#039; — translates raw incoming HTTP requests to&lt;br /&gt;
  service calls. Used primarily in grid mode for ROBUST instances.&lt;br /&gt;
  Example: &amp;lt;code&amp;gt;Asset/AssetServerGetHandler&amp;lt;/code&amp;gt; translates an asset fetch&lt;br /&gt;
  request into a call to the asset service and returns the result.&lt;br /&gt;
&lt;br /&gt;
== OpenSim.Services ==&lt;br /&gt;
&lt;br /&gt;
Service implementations and the connectors that invoke them remotely over HTTP.&lt;br /&gt;
&lt;br /&gt;
* In &#039;&#039;&#039;grid mode&#039;&#039;&#039;: service implementations run inside ROBUST instances.&lt;br /&gt;
* In &#039;&#039;&#039;standalone mode&#039;&#039;&#039;: service implementations are instantiated directly&lt;br /&gt;
  inside OpenSim.exe.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;OpenSim.Services.Connectors&amp;lt;/code&amp;gt; contains the HTTP client code that&lt;br /&gt;
region simulators use to talk to remote ROBUST services.&lt;br /&gt;
&lt;br /&gt;
See [[OpenSimulator_Internals/Connector_Architecture|Connector Architecture]]&lt;br /&gt;
for the full connector and service table.&lt;br /&gt;
&lt;br /&gt;
== OpenSim.Tests ==&lt;br /&gt;
&lt;br /&gt;
Test infrastructure and some standalone client test code.&lt;br /&gt;
Actual regression tests live in &amp;lt;code&amp;gt;*.Tests&amp;lt;/code&amp;gt; subpackages throughout&lt;br /&gt;
the tree (e.g. &amp;lt;code&amp;gt;OpenSim.Region.Framework.Tests&amp;lt;/code&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
== OpenSim.Tools ==&lt;br /&gt;
&lt;br /&gt;
Utility tools associated with OpenSimulator but not used in normal operation.&lt;br /&gt;
&lt;br /&gt;
== See Also ==&lt;br /&gt;
&lt;br /&gt;
* [[OpenSimulator_Internals/Code_Map|Code Map]] — per-class internals&lt;br /&gt;
* [[OpenSimulator_Internals/Connector_Architecture|Connector Architecture]] — service/connector table&lt;br /&gt;
* [[OpenSimulator_Internals/Useful_Queries|Useful Queries]] — database reference&lt;br /&gt;
* [[OpenSimulator_Internals/Walkthroughs|Walkthroughs]] — runtime flow documentation&lt;br /&gt;
&lt;br /&gt;
[[Category:OpenSimulator Internals]]&lt;/div&gt;</summary>
		<author><name>Jwbshaw</name></author>
	</entry>
	<entry>
		<id>http://osimdev.org/wiki/index.php?title=OpenSimulator_Internals/Walkthroughs/Avatar_Goes_HG&amp;diff=110</id>
		<title>OpenSimulator Internals/Walkthroughs/Avatar Goes HG</title>
		<link rel="alternate" type="text/html" href="http://osimdev.org/wiki/index.php?title=OpenSimulator_Internals/Walkthroughs/Avatar_Goes_HG&amp;diff=110"/>
		<updated>2026-07-07T23:29:59Z</updated>

		<summary type="html">&lt;p&gt;Jwbshaw: Added material from opensimulator.org wiki&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= OpenSimulator Internals/Walkthroughs/Avatar Goes HG =&lt;br /&gt;
&lt;br /&gt;
== Overview ==&lt;br /&gt;
&lt;br /&gt;
Traces what happens in code, connectors, and database when an avatar HyperGrid teleports from their home grid to a foreign grid, and when they return.&lt;br /&gt;
&lt;br /&gt;
Assumes the home grid runs ROBUST + OpenSim with HGEntityTransferModule enabled.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Part 1: Departing the Home Grid ==&lt;br /&gt;
&lt;br /&gt;
=== 1. HG Destination Resolved ===&lt;br /&gt;
&lt;br /&gt;
 OpenSim/Region/CoreModules/Framework/EntityTransfer/HGEntityTransferModule.cs -- GetFinalDestination()&lt;br /&gt;
 OpenSim/Services/Connectors/Hypergrid/GatekeeperServiceConnector.cs&lt;br /&gt;
&lt;br /&gt;
# Avatar clicks a HG link or enters a HG URI (e.g. hg.example.com:8002:RegionName).&lt;br /&gt;
# GridService on source region looks up the destination -- finds a region with RegionFlags.Hyperlink set. This is a local stub entry, not a real region.&lt;br /&gt;
# GetFinalDestination() detects the Hyperlink flag.&lt;br /&gt;
# Calls GatekeeperServiceConnector.GetHyperlinkRegion() -- HTTP POST to the foreign grid&#039;s Gatekeeper service (hg.example.com:8002).&lt;br /&gt;
#* Gatekeeper validates the request and returns a real GridRegion descriptor for the destination on the foreign grid.&lt;br /&gt;
# ValidateGenericConditions() checks appearance restrictions if RestrictAppearanceAbroad=true.&lt;br /&gt;
&lt;br /&gt;
=== 2. Pre-flight at Foreign Gatekeeper ===&lt;br /&gt;
&lt;br /&gt;
 EntityTransferModule -- DoTeleportInternal()&lt;br /&gt;
&lt;br /&gt;
# SimulationService.QueryAccess() --&lt;/div&gt;</summary>
		<author><name>Jwbshaw</name></author>
	</entry>
	<entry>
		<id>http://osimdev.org/wiki/index.php?title=OpenSimulator_Internals/Connector_Architecture&amp;diff=109</id>
		<title>OpenSimulator Internals/Connector Architecture</title>
		<link rel="alternate" type="text/html" href="http://osimdev.org/wiki/index.php?title=OpenSimulator_Internals/Connector_Architecture&amp;diff=109"/>
		<updated>2026-07-07T23:25:37Z</updated>

		<summary type="html">&lt;p&gt;Jwbshaw: updated with content from opensimulator.org wiki&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= OpenSimulator Internals/Connector Architecture =&lt;br /&gt;
&lt;br /&gt;
== Overview ==&lt;br /&gt;
&lt;br /&gt;
Connectors are the HTTP client layer that sits between region simulators and ROBUST grid services. Each connector implements a service interface (e.g. IAssetService, IPresenceService) using HTTP calls to the corresponding ROBUST handler.&lt;br /&gt;
&lt;br /&gt;
The same interface may be implemented by:&lt;br /&gt;
* A local connector -- calls the service directly in-process (standalone mode or co-located services).&lt;br /&gt;
* A remote connector -- makes HTTP calls to a ROBUST server.&lt;br /&gt;
* An HG connector -- wraps the remote connector with hypergrid-specific logic.&lt;br /&gt;
&lt;br /&gt;
Region code calls only the interface. Which implementation is loaded depends on configuration ([Architecture] section of the ini files).&lt;br /&gt;
&lt;br /&gt;
Because every ROBUST service is stateless, each can be independently load-balanced or replicated without coordination between instances.&lt;br /&gt;
&lt;br /&gt;
See [[OpenSimulator Internals/ROBUST Services]] for the server-side service implementations.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Connector Pattern ==&lt;br /&gt;
&lt;br /&gt;
All remote connectors follow the same pattern:&lt;br /&gt;
&lt;br /&gt;
# Constructor receives IConfigSource and reads the service URL from config.&lt;br /&gt;
# Each method serialises parameters to a REST or XMLRPC request.&lt;br /&gt;
# Sends HTTP POST/GET/DELETE to the ROBUST handler endpoint.&lt;br /&gt;
# Deserialises the response and returns the result.&lt;br /&gt;
&lt;br /&gt;
The HTTP client layer is WebUtil (OpenSim/Framework/WebUtil.cs), which handles serialisation, connection pooling, and error logging.&lt;br /&gt;
&lt;br /&gt;
See [[OpenSimulator Internals/Connector Architecture/Asset Connector]] for a fully worked example of the pattern including both client and server-side handler code.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Individual Connector Pages ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Connector !! Service Interface !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| [[OpenSimulator Internals/Connector Architecture/Asset Connector]] || IAssetService || As of 0.9.2, the three region-side asset modules (LocalAssetServiceConnector, RemoteAssetServiceConnector, HGAssetBroker) were replaced by a single RegionAssetConnector. LocalAssetServiceConnector is retained for test use only. HGAssetBroker and RemoteAssetServiceConnector are no longer used in production. RegionAssetConnector behaviour is controlled by [AssetService] keys LocalGridAssetService and HypergridAssetService. See individual page for full detail including server-side handler code.&lt;br /&gt;
|-&lt;br /&gt;
| [[OpenSimulator Internals/Connector Architecture/GridUser Connector]] || IGridUserService || Tracks last position, login/logout timestamps, home region. Online status in GridUser is less accurate than in Presence, which is updated more frequently.&lt;br /&gt;
|-&lt;br /&gt;
| [[OpenSimulator Internals/Connector Architecture/Presence Connector]] || IPresenceService || Online status, session tracking, region assignment.&lt;br /&gt;
|-&lt;br /&gt;
| [[OpenSimulator Internals/Connector Architecture/UserAccount Connector]] || IUserAccountService || User account CRUD. Known bug: CreateUser() sends first name as email value.&lt;br /&gt;
|-&lt;br /&gt;
| [[OpenSimulator Internals/Connector Architecture/Inventory Connector]] || IInventoryService || XInventory protocol. UpdateFolder() URL-encodes Name; AddFolder() does not.&lt;br /&gt;
|-&lt;br /&gt;
| [[OpenSimulator Internals/Connector Architecture/Authentication Connector]] || IAuthenticationService || Password and token authentication, impersonation mechanism.&lt;br /&gt;
|-&lt;br /&gt;
| [[OpenSimulator Internals/Connector Architecture/Avatar Connector]] || IAvatarService || Appearance storage. ResetAvatar() log erroneously says &amp;quot;SetItems reply&amp;quot;.&lt;br /&gt;
|-&lt;br /&gt;
| [[OpenSimulator Internals/Connector Architecture/Friends Connector]] || IFriendsService || Friend list, online notifications.&lt;br /&gt;
|-&lt;br /&gt;
| [[OpenSimulator Internals/Connector Architecture/Grid Connector]] || IGridService || Region registration, lookup, neighbour queries.&lt;br /&gt;
|-&lt;br /&gt;
| [[OpenSimulator Internals/Connector Architecture/Simulation Connector]] || ISimulationService || Inter-simulator agent and object transfer. QueryAccess, CreateAgent, UpdateAgent, CloseAgent, CreateObject.&lt;br /&gt;
|-&lt;br /&gt;
| [[OpenSimulator Internals/Connector Architecture/UserAgent Connector]] || IUserAgentService || HG-only. Home region lookup, login to foreign grid, session verification.&lt;br /&gt;
|-&lt;br /&gt;
| [[OpenSimulator Internals/Connector Architecture/Gatekeeper Connector]] || IGatekeeperService || HG-only. Foreign grid entry point. GetHyperlinkRegion, LoginAgentToGrid.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== HG Connectors ==&lt;br /&gt;
&lt;br /&gt;
HyperGrid introduces additional connectors that wrap or replace the standard ones:&lt;br /&gt;
&lt;br /&gt;
* UserAgent Connector -- used by the source grid to contact the avatar&#039;s home grid UserAgent service during HG teleport.&lt;br /&gt;
* Gatekeeper Connector -- used to contact a foreign grid&#039;s Gatekeeper during HG destination resolution.&lt;br /&gt;
* HGAsset Connector -- used by HGInventoryAccessModule to fetch/push assets between grids (via HGAssetMapper).&lt;br /&gt;
&lt;br /&gt;
Note: prior to 0.9.2, the HGAssetBroker region module handled the local/remote/foreign asset routing decision. It was retired in 0.9.2 and replaced by RegionAssetConnector. References to HGAssetBroker in older documentation and config examples are obsolete.&lt;br /&gt;
&lt;br /&gt;
These are documented in the individual connector pages above and in:&lt;br /&gt;
* [[OpenSimulator Internals/Code Map/HGEntityTransferModule]]&lt;br /&gt;
* [[OpenSimulator Internals/Code Map/InventoryAccessModule]]&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Configuration ==&lt;br /&gt;
&lt;br /&gt;
Connectors are selected in the [Architecture] ini include files:&lt;br /&gt;
&lt;br /&gt;
* config-include/StandaloneCommon.ini -- standalone mode, services loaded in-process.&lt;br /&gt;
* config-include/GridCommon.ini -- grid mode, remote connectors used.&lt;br /&gt;
* config-include/HGCommon.ini -- hypergrid additions.&lt;br /&gt;
&lt;br /&gt;
The [ServiceList] section of Robust.ini selects which ROBUST handlers are loaded. The [Modules] section of OpenSim.ini selects which connectors the simulator loads.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== See Also ==&lt;br /&gt;
&lt;br /&gt;
* [[OpenSimulator Internals/Code Map/ROBUST]]&lt;br /&gt;
* [[OpenSimulator Internals/ROBUST Services]]&lt;br /&gt;
* [[OpenSimulator Internals/Reading the Code]]&lt;br /&gt;
* [[OpenSimulator Internals/Code Map]]&lt;/div&gt;</summary>
		<author><name>Jwbshaw</name></author>
	</entry>
	<entry>
		<id>http://osimdev.org/wiki/index.php?title=Main_Page&amp;diff=108</id>
		<title>Main Page</title>
		<link rel="alternate" type="text/html" href="http://osimdev.org/wiki/index.php?title=Main_Page&amp;diff=108"/>
		<updated>2026-07-07T23:01:09Z</updated>

		<summary type="html">&lt;p&gt;Jwbshaw: moved code map to second last&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= OpenSimulator Internals =&lt;br /&gt;
&lt;br /&gt;
This wiki documents the internal architecture of OpenSimulator for developers and contributors. It covers the database schema, service architecture, connector design, and code structure. Written from code and verified against developer discussion -- where the wiki and the code disagree, the code takes priority.&lt;br /&gt;
&lt;br /&gt;
Maintained by Jagga Meredith. Contributions welcome.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Source Repository ==&lt;br /&gt;
&lt;br /&gt;
 https://github.com/opensim/opensim&lt;br /&gt;
&lt;br /&gt;
Only the &#039;&#039;&#039;master&#039;&#039;&#039; branch is active. All other branches are dead.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Overview ==&lt;br /&gt;
&lt;br /&gt;
OpenSimulator has two main components:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;ROBUST.exe&#039;&#039;&#039; -- handles grid-wide services: user accounts, inventory, assets, presence, and region registration. Multiple simulators connect to a single ROBUST instance.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;OpenSim.exe&#039;&#039;&#039; -- runs one or more regions. Handles objects, avatars, physics, scripting, and terrain. In standalone mode both processes are combined into OpenSim.exe.&lt;br /&gt;
&lt;br /&gt;
The database layer is split to match: ROBUST owns the grid database, each simulator owns its own region database. Both live in the same database server instance as separate databases.&lt;br /&gt;
&lt;br /&gt;
In standalone mode the connector calls the service directly in-process. In grid mode it makes an HTTP call to ROBUST. Same interface either way.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Contents ==&lt;br /&gt;
&lt;br /&gt;
* [[OpenSimulator Internals/Architecture Overview]]&lt;br /&gt;
* [[OpenSimulator Internals/Reading the Code]]&lt;br /&gt;
* [[OpenSimulator Internals/ROBUST Services]]&lt;br /&gt;
* [[OpenSimulator Internals/Connector Architecture]]&lt;br /&gt;
* [[OpenSimulator Internals/Databases]]&lt;br /&gt;
* [[OpenSimulator Internals/Data Dictionaries]]&lt;br /&gt;
* [[OpenSimulator Internals/Useful Queries]]&lt;br /&gt;
* [[OpenSimulator Internals/Code Map]]&lt;br /&gt;
* [[OpenSimulator Internals/Walkthroughs]]&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Status ==&lt;br /&gt;
&lt;br /&gt;
This document is a work in progress developed from code review and developer meeting notes. Where the existing wiki disagrees with the source code, the source code takes priority. Discrepancies are noted.&lt;br /&gt;
&lt;br /&gt;
Contributors: Jagga Meredith&lt;/div&gt;</summary>
		<author><name>Jwbshaw</name></author>
	</entry>
	<entry>
		<id>http://osimdev.org/wiki/index.php?title=Main_Page&amp;diff=107</id>
		<title>Main Page</title>
		<link rel="alternate" type="text/html" href="http://osimdev.org/wiki/index.php?title=Main_Page&amp;diff=107"/>
		<updated>2026-07-07T22:57:57Z</updated>

		<summary type="html">&lt;p&gt;Jwbshaw: remove services&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= OpenSimulator Internals =&lt;br /&gt;
&lt;br /&gt;
This wiki documents the internal architecture of OpenSimulator for developers and contributors. It covers the database schema, service architecture, connector design, and code structure. Written from code and verified against developer discussion -- where the wiki and the code disagree, the code takes priority.&lt;br /&gt;
&lt;br /&gt;
Maintained by Jagga Meredith. Contributions welcome.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Source Repository ==&lt;br /&gt;
&lt;br /&gt;
 https://github.com/opensim/opensim&lt;br /&gt;
&lt;br /&gt;
Only the &#039;&#039;&#039;master&#039;&#039;&#039; branch is active. All other branches are dead.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Overview ==&lt;br /&gt;
&lt;br /&gt;
OpenSimulator has two main components:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;ROBUST.exe&#039;&#039;&#039; -- handles grid-wide services: user accounts, inventory, assets, presence, and region registration. Multiple simulators connect to a single ROBUST instance.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;OpenSim.exe&#039;&#039;&#039; -- runs one or more regions. Handles objects, avatars, physics, scripting, and terrain. In standalone mode both processes are combined into OpenSim.exe.&lt;br /&gt;
&lt;br /&gt;
The database layer is split to match: ROBUST owns the grid database, each simulator owns its own region database. Both live in the same database server instance as separate databases.&lt;br /&gt;
&lt;br /&gt;
In standalone mode the connector calls the service directly in-process. In grid mode it makes an HTTP call to ROBUST. Same interface either way.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Contents ==&lt;br /&gt;
&lt;br /&gt;
* [[OpenSimulator Internals/Architecture Overview]]&lt;br /&gt;
* [[OpenSimulator Internals/Reading the Code]]&lt;br /&gt;
* [[OpenSimulator Internals/ROBUST Services]]&lt;br /&gt;
* [[OpenSimulator Internals/Connector Architecture]]&lt;br /&gt;
* [[OpenSimulator Internals/Code Map]]&lt;br /&gt;
* [[OpenSimulator Internals/Databases]]&lt;br /&gt;
* [[OpenSimulator Internals/Data Dictionaries]]&lt;br /&gt;
* [[OpenSimulator Internals/Useful Queries]]&lt;br /&gt;
* [[OpenSimulator Internals/Walkthroughs]]&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Status ==&lt;br /&gt;
&lt;br /&gt;
This document is a work in progress developed from code review and developer meeting notes. Where the existing wiki disagrees with the source code, the source code takes priority. Discrepancies are noted.&lt;br /&gt;
&lt;br /&gt;
Contributors: Jagga Meredith&lt;br /&gt;
Contributors: Jagga Meredith&lt;/div&gt;</summary>
		<author><name>Jwbshaw</name></author>
	</entry>
	<entry>
		<id>http://osimdev.org/wiki/index.php?title=OpenSimulator_Internals/Useful_Queries&amp;diff=106</id>
		<title>OpenSimulator Internals/Useful Queries</title>
		<link rel="alternate" type="text/html" href="http://osimdev.org/wiki/index.php?title=OpenSimulator_Internals/Useful_Queries&amp;diff=106"/>
		<updated>2026-07-07T22:51:33Z</updated>

		<summary type="html">&lt;p&gt;Jwbshaw: more material&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
= OpenSimulator Internals/Useful Queries =&lt;br /&gt;
&lt;br /&gt;
== Overview ==&lt;br /&gt;
&lt;br /&gt;
These queries are for grid administrators and developers working directly with MariaDB. Correlated subqueries are used to look up UUIDs by name so you don&#039;t have to remember them.&lt;br /&gt;
&lt;br /&gt;
All queries assume osimdev_robust for grid data and osimdev_t1 for region data. Substitute your region database name as needed. Examples use &amp;quot;Test User&amp;quot; as the avatar name -- substitute as required.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Connection ==&lt;br /&gt;
&lt;br /&gt;
 mysql -u opensim -p osimdev_robust&lt;br /&gt;
 USE osimdev_t1;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Grid Database (osimdev_robust) ==&lt;br /&gt;
&lt;br /&gt;
=== Users ===&lt;br /&gt;
&lt;br /&gt;
Find a user by first name:&lt;br /&gt;
&lt;br /&gt;
 SELECT PrincipalID, FirstName, LastName, Email, UserLevel,&lt;br /&gt;
        FROM_UNIXTIME(Created) AS created&lt;br /&gt;
 FROM UserAccounts&lt;br /&gt;
 WHERE FirstName LIKE &#039;Test%&#039;;&lt;br /&gt;
&lt;br /&gt;
Show login history by name:&lt;br /&gt;
&lt;br /&gt;
 SELECT FROM_UNIXTIME(Login) AS last_login,&lt;br /&gt;
        FROM_UNIXTIME(Logout) AS last_logout,&lt;br /&gt;
        Online&lt;br /&gt;
 FROM GridUser&lt;br /&gt;
 WHERE UserID = (&lt;br /&gt;
     SELECT PrincipalID FROM UserAccounts&lt;br /&gt;
     WHERE FirstName = &#039;Test&#039; AND LastName = &#039;User&#039;&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
Show home and last location by name:&lt;br /&gt;
&lt;br /&gt;
 SELECT HomePosition, HomeLookAt, LastPosition, LastLookAt,&lt;br /&gt;
        HomeRegionID, LastRegionID&lt;br /&gt;
 FROM GridUser&lt;br /&gt;
 WHERE UserID = (&lt;br /&gt;
     SELECT PrincipalID FROM UserAccounts&lt;br /&gt;
     WHERE FirstName = &#039;Test&#039; AND LastName = &#039;User&#039;&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
Who is currently online:&lt;br /&gt;
&lt;br /&gt;
 SELECT UserID, RegionID, LastSeen FROM Presence;&lt;br /&gt;
&lt;br /&gt;
=== Avatar Appearance ===&lt;br /&gt;
&lt;br /&gt;
Show all appearance data for a user by name:&lt;br /&gt;
&lt;br /&gt;
 SELECT Name, Value&lt;br /&gt;
 FROM Avatars&lt;br /&gt;
 WHERE PrincipalID = (&lt;br /&gt;
     SELECT PrincipalID FROM UserAccounts&lt;br /&gt;
     WHERE FirstName = &#039;Test&#039; AND LastName = &#039;User&#039;&lt;br /&gt;
 )&lt;br /&gt;
 ORDER BY Name;&lt;br /&gt;
&lt;br /&gt;
Show worn wearables only:&lt;br /&gt;
&lt;br /&gt;
 SELECT Name, Value&lt;br /&gt;
 FROM Avatars&lt;br /&gt;
 WHERE PrincipalID = (&lt;br /&gt;
     SELECT PrincipalID FROM UserAccounts&lt;br /&gt;
     WHERE FirstName = &#039;Test&#039; AND LastName = &#039;User&#039;&lt;br /&gt;
 )&lt;br /&gt;
 AND Name LIKE &#039;Wearable%&#039;;&lt;br /&gt;
&lt;br /&gt;
Show attachment points only:&lt;br /&gt;
&lt;br /&gt;
 SELECT Name, Value&lt;br /&gt;
 FROM Avatars&lt;br /&gt;
 WHERE PrincipalID = (&lt;br /&gt;
     SELECT PrincipalID FROM UserAccounts&lt;br /&gt;
     WHERE FirstName = &#039;Test&#039; AND LastName = &#039;User&#039;&lt;br /&gt;
 )&lt;br /&gt;
 AND Name LIKE &#039;_ap_%&#039;;&lt;br /&gt;
&lt;br /&gt;
=== Inventory ===&lt;br /&gt;
&lt;br /&gt;
Count inventory items by asset type for a user:&lt;br /&gt;
&lt;br /&gt;
 SELECT assetType, COUNT(*) AS count&lt;br /&gt;
 FROM inventoryitems&lt;br /&gt;
 WHERE avatarID = (&lt;br /&gt;
     SELECT PrincipalID FROM UserAccounts&lt;br /&gt;
     WHERE FirstName = &#039;Test&#039; AND LastName = &#039;User&#039;&lt;br /&gt;
 )&lt;br /&gt;
 GROUP BY assetType&lt;br /&gt;
 ORDER BY count DESC;&lt;br /&gt;
&lt;br /&gt;
Find an inventory item by name:&lt;br /&gt;
&lt;br /&gt;
 SELECT inventoryName, assetType, assetID, parentFolderID&lt;br /&gt;
 FROM inventoryitems&lt;br /&gt;
 WHERE avatarID = (&lt;br /&gt;
     SELECT PrincipalID FROM UserAccounts&lt;br /&gt;
     WHERE FirstName = &#039;Test&#039; AND LastName = &#039;User&#039;&lt;br /&gt;
 )&lt;br /&gt;
 AND inventoryName LIKE &#039;%house%&#039;;&lt;br /&gt;
&lt;br /&gt;
List top-level inventory folders for a user:&lt;br /&gt;
&lt;br /&gt;
 SELECT folderName, type, folderID&lt;br /&gt;
 FROM inventoryfolders&lt;br /&gt;
 WHERE agentID = (&lt;br /&gt;
     SELECT PrincipalID FROM UserAccounts&lt;br /&gt;
     WHERE FirstName = &#039;Test&#039; AND LastName = &#039;User&#039;&lt;br /&gt;
 )&lt;br /&gt;
 AND parentFolderID = (&lt;br /&gt;
     SELECT folderID FROM inventoryfolders&lt;br /&gt;
     WHERE agentID = (&lt;br /&gt;
         SELECT PrincipalID FROM UserAccounts&lt;br /&gt;
         WHERE FirstName = &#039;Test&#039; AND LastName = &#039;User&#039;&lt;br /&gt;
     )&lt;br /&gt;
     AND type = 8&lt;br /&gt;
 )&lt;br /&gt;
 ORDER BY folderName;&lt;br /&gt;
&lt;br /&gt;
=== Assets ===&lt;br /&gt;
&lt;br /&gt;
Count all assets by type:&lt;br /&gt;
&lt;br /&gt;
 SELECT assetType, COUNT(*) AS count&lt;br /&gt;
 FROM assets&lt;br /&gt;
 GROUP BY assetType&lt;br /&gt;
 ORDER BY count DESC;&lt;br /&gt;
&lt;br /&gt;
Find assets created by a user:&lt;br /&gt;
&lt;br /&gt;
 SELECT id, name, assetType, FROM_UNIXTIME(create_time) AS created&lt;br /&gt;
 FROM assets&lt;br /&gt;
 WHERE CreatorID = (&lt;br /&gt;
     SELECT PrincipalID FROM UserAccounts&lt;br /&gt;
     WHERE FirstName = &#039;Test&#039; AND LastName = &#039;User&#039;&lt;br /&gt;
 )&lt;br /&gt;
 ORDER BY create_time DESC;&lt;br /&gt;
&lt;br /&gt;
Find an asset by name:&lt;br /&gt;
&lt;br /&gt;
 SELECT id, name, assetType, FROM_UNIXTIME(create_time) AS created&lt;br /&gt;
 FROM assets&lt;br /&gt;
 WHERE name LIKE &#039;%note%&#039;;&lt;br /&gt;
&lt;br /&gt;
=== Friends ===&lt;br /&gt;
&lt;br /&gt;
Show friends for a user:&lt;br /&gt;
&lt;br /&gt;
 SELECT Friend, Flags&lt;br /&gt;
 FROM Friends&lt;br /&gt;
 WHERE PrincipalID = (&lt;br /&gt;
     SELECT PrincipalID FROM UserAccounts&lt;br /&gt;
     WHERE FirstName = &#039;Test&#039; AND LastName = &#039;User&#039;&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
=== Regions ===&lt;br /&gt;
&lt;br /&gt;
List all registered regions:&lt;br /&gt;
&lt;br /&gt;
 SELECT regionName,&lt;br /&gt;
        locX/256 AS coord_x, locY/256 AS coord_y,&lt;br /&gt;
        sizeX, sizeY, flags,&lt;br /&gt;
        FROM_UNIXTIME(last_seen) AS last_seen&lt;br /&gt;
 FROM regions;&lt;br /&gt;
&lt;br /&gt;
Check if a region is online:&lt;br /&gt;
&lt;br /&gt;
 SELECT regionName, flags &amp;amp; 4 AS online&lt;br /&gt;
 FROM regions&lt;br /&gt;
 WHERE regionName = &#039;T1&#039;;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Region Database (osimdev_t1) ==&lt;br /&gt;
&lt;br /&gt;
=== Objects ===&lt;br /&gt;
&lt;br /&gt;
List all objects with world position (root prims only):&lt;br /&gt;
&lt;br /&gt;
 SELECT Name, UUID, GroupPositionX, GroupPositionY, GroupPositionZ&lt;br /&gt;
 FROM prims&lt;br /&gt;
 WHERE UUID = SceneGroupID&lt;br /&gt;
 ORDER BY Name;&lt;br /&gt;
&lt;br /&gt;
Count prims per object (root prims only, sorted by size):&lt;br /&gt;
&lt;br /&gt;
 SELECT p.Name, p.SceneGroupID,&lt;br /&gt;
        p.GroupPositionX, p.GroupPositionY, p.GroupPositionZ,&lt;br /&gt;
        COUNT(*) AS prim_count&lt;br /&gt;
 FROM prims p&lt;br /&gt;
 WHERE p.UUID = p.SceneGroupID&lt;br /&gt;
 GROUP BY p.SceneGroupID, p.Name, p.GroupPositionX, p.GroupPositionY, p.GroupPositionZ&lt;br /&gt;
 ORDER BY prim_count DESC;&lt;br /&gt;
&lt;br /&gt;
Find an object by name:&lt;br /&gt;
&lt;br /&gt;
 SELECT UUID, GroupPositionX, GroupPositionY, GroupPositionZ&lt;br /&gt;
 FROM prims&lt;br /&gt;
 WHERE UUID = SceneGroupID&lt;br /&gt;
 AND Name LIKE &#039;%house%&#039;;&lt;br /&gt;
&lt;br /&gt;
List all prims in a named object:&lt;br /&gt;
&lt;br /&gt;
 SELECT UUID, Name, LinkNumber, PositionX, PositionY, PositionZ&lt;br /&gt;
 FROM prims&lt;br /&gt;
 WHERE SceneGroupID = (&lt;br /&gt;
     SELECT UUID FROM prims&lt;br /&gt;
     WHERE UUID = SceneGroupID AND Name LIKE &#039;%Brown House%&#039;&lt;br /&gt;
     LIMIT 1&lt;br /&gt;
 )&lt;br /&gt;
 ORDER BY LinkNumber;&lt;br /&gt;
&lt;br /&gt;
Find objects owned by a specific user:&lt;br /&gt;
&lt;br /&gt;
 SELECT Name, UUID, GroupPositionX, GroupPositionY, GroupPositionZ&lt;br /&gt;
 FROM prims&lt;br /&gt;
 WHERE UUID = SceneGroupID&lt;br /&gt;
 AND OwnerID = (&lt;br /&gt;
     SELECT PrincipalID FROM osimdev_robust.UserAccounts&lt;br /&gt;
     WHERE FirstName = &#039;Test&#039; AND LastName = &#039;User&#039;&lt;br /&gt;
 )&lt;br /&gt;
 ORDER BY Name;&lt;br /&gt;
&lt;br /&gt;
=== Object Contents (Task Inventory) ===&lt;br /&gt;
&lt;br /&gt;
Show contents of a named object:&lt;br /&gt;
&lt;br /&gt;
 SELECT pi.name, pi.assetType, pi.assetID&lt;br /&gt;
 FROM primitems pi&lt;br /&gt;
 WHERE pi.primID IN (&lt;br /&gt;
     SELECT UUID FROM prims&lt;br /&gt;
     WHERE SceneGroupID = (&lt;br /&gt;
         SELECT UUID FROM prims&lt;br /&gt;
         WHERE UUID = SceneGroupID AND Name LIKE &#039;%Box%&#039;&lt;br /&gt;
         LIMIT 1&lt;br /&gt;
     )&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
Count task inventory items by type across all objects:&lt;br /&gt;
&lt;br /&gt;
 SELECT pi.assetType, COUNT(*) AS count&lt;br /&gt;
 FROM primitems pi&lt;br /&gt;
 GROUP BY pi.assetType&lt;br /&gt;
 ORDER BY count DESC;&lt;br /&gt;
&lt;br /&gt;
Show all objects that contain scripts:&lt;br /&gt;
&lt;br /&gt;
 SELECT DISTINCT p.Name, p.UUID, p.GroupPositionX, p.GroupPositionY, p.GroupPositionZ&lt;br /&gt;
 FROM prims p&lt;br /&gt;
 JOIN primitems pi ON pi.primID = p.UUID&lt;br /&gt;
 WHERE p.UUID = p.SceneGroupID&lt;br /&gt;
 AND pi.assetType = 10&lt;br /&gt;
 ORDER BY p.Name;&lt;br /&gt;
&lt;br /&gt;
=== Prim Shape ===&lt;br /&gt;
&lt;br /&gt;
Show shape for a named object:&lt;br /&gt;
&lt;br /&gt;
 SELECT p.Name, p.LinkNumber,&lt;br /&gt;
        ps.ScaleX, ps.ScaleY, ps.ScaleZ,&lt;br /&gt;
        ps.PCode, ps.Shape, ps.ProfileCurve, ps.PathCurve&lt;br /&gt;
 FROM primshapes ps&lt;br /&gt;
 JOIN prims p ON ps.UUID = p.UUID&lt;br /&gt;
 WHERE p.SceneGroupID = (&lt;br /&gt;
     SELECT UUID FROM prims&lt;br /&gt;
     WHERE UUID = SceneGroupID AND Name = &#039;Object&#039;&lt;br /&gt;
     LIMIT 1&lt;br /&gt;
 )&lt;br /&gt;
 ORDER BY p.LinkNumber;&lt;br /&gt;
&lt;br /&gt;
=== Persistence State ===&lt;br /&gt;
&lt;br /&gt;
Find objects with pending changes (not yet persisted):&lt;br /&gt;
&lt;br /&gt;
 SELECT Name, UUID, GroupPositionX, GroupPositionY, GroupPositionZ&lt;br /&gt;
 FROM prims&lt;br /&gt;
 WHERE UUID = SceneGroupID&lt;br /&gt;
 AND RezzerID IS NOT NULL&lt;br /&gt;
 ORDER BY Name;&lt;br /&gt;
&lt;br /&gt;
=== Land ===&lt;br /&gt;
&lt;br /&gt;
Show all parcels:&lt;br /&gt;
&lt;br /&gt;
 SELECT LocalLandID, Name, OwnerUUID, Area, LandStatus,&lt;br /&gt;
        UserLocationX, UserLocationY, UserLocationZ&lt;br /&gt;
 FROM land;&lt;br /&gt;
&lt;br /&gt;
=== Terrain ===&lt;br /&gt;
&lt;br /&gt;
Check terrain revision and blob size:&lt;br /&gt;
&lt;br /&gt;
 SELECT RegionUUID, Revision, LENGTH(Heightfield) AS bytes&lt;br /&gt;
 FROM terrain;&lt;br /&gt;
&lt;br /&gt;
=== Estate ===&lt;br /&gt;
&lt;br /&gt;
Show estate settings:&lt;br /&gt;
&lt;br /&gt;
 SELECT EstateName, EstateOwner, PublicAccess, AllowVoice,&lt;br /&gt;
        DenyMinors, AllowDirectTeleport, AllowSetHome&lt;br /&gt;
 FROM estate_settings;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Cross-Database Queries ==&lt;br /&gt;
&lt;br /&gt;
Objects owned by a named user (cross-database):&lt;br /&gt;
&lt;br /&gt;
 SELECT p.Name, p.UUID, p.GroupPositionX, p.GroupPositionY, p.GroupPositionZ&lt;br /&gt;
 FROM osimdev_t1.prims p&lt;br /&gt;
 WHERE p.UUID = p.SceneGroupID&lt;br /&gt;
 AND p.OwnerID = (&lt;br /&gt;
     SELECT PrincipalID FROM osimdev_robust.UserAccounts&lt;br /&gt;
     WHERE FirstName = &#039;Test&#039; AND LastName = &#039;User&#039;&lt;br /&gt;
 )&lt;br /&gt;
 ORDER BY p.Name;&lt;br /&gt;
&lt;br /&gt;
Inventory items for an object currently in the region:&lt;br /&gt;
&lt;br /&gt;
 SELECT pi.name, pi.assetType, a.name AS asset_name&lt;br /&gt;
 FROM osimdev_t1.primitems pi&lt;br /&gt;
 JOIN osimdev_robust.assets a ON a.id = pi.assetID&lt;br /&gt;
 WHERE pi.primID = (&lt;br /&gt;
     SELECT UUID FROM osimdev_t1.prims&lt;br /&gt;
     WHERE UUID = SceneGroupID AND Name LIKE &#039;%Box%&#039;&lt;br /&gt;
     LIMIT 1&lt;br /&gt;
 );&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Conversions ==&lt;br /&gt;
&lt;br /&gt;
Unix timestamp to datetime:&lt;br /&gt;
&lt;br /&gt;
 SELECT FROM_UNIXTIME(1782133981);&lt;br /&gt;
&lt;br /&gt;
Region metres to region coordinates:&lt;br /&gt;
&lt;br /&gt;
 SELECT locX/256 AS coord_x, locY/256 AS coord_y FROM regions;&lt;br /&gt;
&lt;br /&gt;
Asset type numbers:&lt;br /&gt;
&lt;br /&gt;
 0  = texture&lt;br /&gt;
 2  = sound&lt;br /&gt;
 3  = landmark&lt;br /&gt;
 5  = clothing&lt;br /&gt;
 6  = object&lt;br /&gt;
 7  = notecard&lt;br /&gt;
 10 = script (LSL)&lt;br /&gt;
 13 = body part&lt;br /&gt;
 20 = animation&lt;br /&gt;
 24 = link (inventory link)&lt;br /&gt;
 25 = mesh&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== See Also ==&lt;br /&gt;
&lt;br /&gt;
* [[OpenSimulator Internals/Databases]]&lt;br /&gt;
* [[OpenSimulator Internals/Walkthroughs/Avatar Rezzes Box]]&lt;br /&gt;
* [[OpenSimulator Internals/Walkthroughs/Avatar Derezzes Object]]&lt;br /&gt;
* [[OpenSimulator Internals/Walkthroughs/Avatar Acquires Inventory]]&lt;br /&gt;
* [[OpenSimulator Internals/Data Dictionaries]]&lt;/div&gt;</summary>
		<author><name>Jwbshaw</name></author>
	</entry>
	<entry>
		<id>http://osimdev.org/wiki/index.php?title=OpenSimulator_Internals/Walkthroughs&amp;diff=105</id>
		<title>OpenSimulator Internals/Walkthroughs</title>
		<link rel="alternate" type="text/html" href="http://osimdev.org/wiki/index.php?title=OpenSimulator_Internals/Walkthroughs&amp;diff=105"/>
		<updated>2026-07-07T22:41:41Z</updated>

		<summary type="html">&lt;p&gt;Jwbshaw: remove stub&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= OpenSimulator Internals/Walkthroughs =&lt;br /&gt;
&lt;br /&gt;
== Overview ==&lt;br /&gt;
Each walkthrough traces a single user-facing action through code, connectors, and database writes. Where the Code Map and Databases pages describe components in isolation, these pages follow one operation end to end.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
* [[OpenSimulator Internals/Walkthroughs/Bring Up Grid]]&lt;br /&gt;
* [[OpenSimulator Internals/Walkthroughs/Bring Up Region]]&lt;br /&gt;
* [[OpenSimulator Internals/Walkthroughs/Avatar Rez In Region]]&lt;br /&gt;
* [[OpenSimulator Internals/Walkthroughs/Avatar Change Outfit]]&lt;br /&gt;
* [[OpenSimulator Internals/Walkthroughs/Avatar Logs Out]]&lt;br /&gt;
* [[OpenSimulator Internals/Walkthroughs/Avatar Transfer Between Regions]]&lt;br /&gt;
* [[OpenSimulator Internals/Walkthroughs/Avatar Goes HG]]&lt;br /&gt;
* [[OpenSimulator Internals/Walkthroughs/Avatar Rezzes Box]]&lt;br /&gt;
* [[OpenSimulator Internals/Walkthroughs/Avatar Acquires Inventory]]&lt;br /&gt;
* [[OpenSimulator Internals/Walkthroughs/Avatar Rezzes Inventory]]&lt;br /&gt;
* [[OpenSimulator Internals/Walkthroughs/Avatar Derezzes Object]]&lt;br /&gt;
* [[OpenSimulator Internals/Walkthroughs/Avatar Removes From Inventory]]&lt;br /&gt;
* [[OpenSimulator Internals/Walkthroughs/Garbage Collection]]&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== See Also ==&lt;br /&gt;
&lt;br /&gt;
* [[OpenSimulator Internals/Code Map]]&lt;br /&gt;
* [[OpenSimulator Internals/Databases]]&lt;br /&gt;
* [[OpenSimulator Internals/Architecture Overview]]&lt;/div&gt;</summary>
		<author><name>Jwbshaw</name></author>
	</entry>
	<entry>
		<id>http://osimdev.org/wiki/index.php?title=OpenSimulator_Internals/Walkthroughs/Avatar_Derezzes_Object&amp;diff=104</id>
		<title>OpenSimulator Internals/Walkthroughs/Avatar Derezzes Object</title>
		<link rel="alternate" type="text/html" href="http://osimdev.org/wiki/index.php?title=OpenSimulator_Internals/Walkthroughs/Avatar_Derezzes_Object&amp;diff=104"/>
		<updated>2026-07-07T22:40:07Z</updated>

		<summary type="html">&lt;p&gt;Jwbshaw: first&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= OpenSimulator Internals/Walkthroughs/Avatar Derezzes Object =&lt;br /&gt;
&lt;br /&gt;
== Overview ==&lt;br /&gt;
&lt;br /&gt;
Traces what happens in code, connectors, and database when an avatar takes an object from the world into inventory (derez), or deletes it. Uses the box-with-notecard from [[OpenSimulator Internals/Walkthroughs/Avatar Rezzes Box]] as the concrete example.&lt;br /&gt;
&lt;br /&gt;
This is a concrete instance of [[OpenSimulator Internals/Walkthroughs/Avatar Acquires Inventory]]. Read that page for the full code path.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Case 1: Take (own object, no-copy) ==&lt;br /&gt;
&lt;br /&gt;
Avatar right-clicks the box and selects Take.&lt;br /&gt;
&lt;br /&gt;
=== 1. Viewer Sends DeRezObject ===&lt;br /&gt;
&lt;br /&gt;
# Viewer sends DeRezObject packet with action=Take, objectLocalID=box local ID.&lt;br /&gt;
# Scene.DeRezObjects() validates permissions (CanTakeObject).&lt;br /&gt;
# Calls IInventoryAccessModule.CopyToInventory(DeRezAction.Take, folderID, [boxSOG], client, false).&lt;br /&gt;
&lt;br /&gt;
=== 2. Object Serialised ===&lt;br /&gt;
&lt;br /&gt;
BasicInventoryAccessModule.CopyBundleToInventory():&lt;br /&gt;
# Serialises box SOG to XML: SceneObjectSerializer.ToOriginalXmlFormat().&lt;br /&gt;
#* XML includes: prim data, shape, permissions, position, rotation, task inventory (the notecard reference is embedded in the XML as a primitems-equivalent block).&lt;br /&gt;
# Creates asset: AssetService.Store() -- new UUID, AssetType.Object, data = XML bytes.&lt;br /&gt;
# CreateItemForObject(Take): determines folder (original FromFolderID if owner taking back own item).&lt;br /&gt;
# AddPermissions(): same-owner path, preserves current permissions.&lt;br /&gt;
# Scene.AddInventoryItem(): InventoryService.AddItem() -- writes inventoryitems row.&lt;br /&gt;
# Sends SendInventoryItemCreateUpdate() to client.&lt;br /&gt;
&lt;br /&gt;
; DB writes:&lt;br /&gt;
* assets -- INSERT: new object XML asset UUID&lt;br /&gt;
* inventoryitems -- INSERT: new item in Object folder (or original folder)&lt;br /&gt;
&lt;br /&gt;
=== 3. Object Removed from Scene ===&lt;br /&gt;
&lt;br /&gt;
DoPostRezWhenFromItem():&lt;br /&gt;
* Box was no-copy: InventoryService.DeleteItems() -- removes original inventoryitems row.&lt;br /&gt;
&lt;br /&gt;
Scene.DeleteSceneObject(boxSOG, false):&lt;br /&gt;
* RemoveScriptInstances() -- no-op (no scripts).&lt;br /&gt;
* Removes physics actor.&lt;br /&gt;
* UnlinkSceneObject() -- removes from scene graph.&lt;br /&gt;
* SimulationDataService.RemoveObject(boxUUID, regionID).&lt;br /&gt;
&lt;br /&gt;
; DB writes:&lt;br /&gt;
* inventoryitems -- DELETE: original no-copy item&lt;br /&gt;
* prims -- DELETE: box prim row&lt;br /&gt;
* primshapes -- DELETE: box shape row&lt;br /&gt;
* primitems -- DELETE: notecard task inventory row&lt;br /&gt;
&lt;br /&gt;
=== 4. DB State After ===&lt;br /&gt;
&lt;br /&gt;
Region database:&lt;br /&gt;
* prims: box row gone.&lt;br /&gt;
* primshapes: box shape row gone.&lt;br /&gt;
* primitems: notecard task inventory row gone.&lt;br /&gt;
&lt;br /&gt;
Robust database:&lt;br /&gt;
* assets: new object XML asset (contains the notecard reference inside the serialised XML).&lt;br /&gt;
* inventoryitems: new item pointing to the new asset UUID.&lt;br /&gt;
* The notecard asset itself remains in assets table -- assets are never deleted on take.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Case 2: Take Copy (copyable object) ==&lt;br /&gt;
&lt;br /&gt;
Avatar right-clicks and selects Take Copy.&lt;br /&gt;
&lt;br /&gt;
Same serialise-and-store process as above, but:&lt;br /&gt;
* DoPostRezWhenFromItem() does NOT delete the original inventory item (item has Copy permission).&lt;br /&gt;
* Scene.DeRezObjects() does NOT call DeleteSceneObject() -- object stays in world.&lt;br /&gt;
&lt;br /&gt;
; DB writes:&lt;br /&gt;
* assets -- INSERT: new object XML asset&lt;br /&gt;
* inventoryitems -- INSERT: new item in Object folder&lt;br /&gt;
&lt;br /&gt;
Region DB unchanged. The box stays in the world.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Case 3: Delete (move to Trash) ==&lt;br /&gt;
&lt;br /&gt;
Avatar right-clicks and selects Delete.&lt;br /&gt;
&lt;br /&gt;
Calls CopyToInventory(DeRezAction.Delete):&lt;br /&gt;
* Destination folder: Trash (FolderType.Trash) if own object, Lost and Found if another&#039;s.&lt;br /&gt;
* Same serialise-and-store process.&lt;br /&gt;
* Scene.DeleteSceneObject() removes from scene and region DB.&lt;br /&gt;
&lt;br /&gt;
; DB writes:&lt;br /&gt;
* assets -- INSERT: serialised object XML&lt;br /&gt;
* inventoryitems -- INSERT: item in Trash&lt;br /&gt;
* prims/primshapes/primitems -- DELETE&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Key DB Tables Affected ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Table !! Take (no-copy) !! Take Copy !! Delete&lt;br /&gt;
|-&lt;br /&gt;
| assets || INSERT (new) || INSERT (new) || INSERT (new)&lt;br /&gt;
|-&lt;br /&gt;
| inventoryitems || INSERT new + DELETE old || INSERT new only || INSERT (Trash)&lt;br /&gt;
|-&lt;br /&gt;
| prims || DELETE || unchanged || DELETE&lt;br /&gt;
|-&lt;br /&gt;
| primshapes || DELETE || unchanged || DELETE&lt;br /&gt;
|-&lt;br /&gt;
| primitems || DELETE || unchanged || DELETE&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Note: asset rows are never deleted from the assets table by any of these operations. Assets accumulate. Cleanup is a separate administrative operation outside normal simulator operation.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== What Happens to the Notecard Inside ==&lt;br /&gt;
&lt;br /&gt;
The notecard was task inventory of the box (a primitems row). When the box is taken or deleted:&lt;br /&gt;
&lt;br /&gt;
* The primitems row is deleted from the region DB.&lt;br /&gt;
* The notecard asset (text content) remains in the assets table -- it is referenced by assetID in the serialised object XML.&lt;br /&gt;
* When the box is later rezzed from inventory, the XML is deserialised and the notecard reappears as task inventory -- it is re-fetched from assets by assetID.&lt;br /&gt;
&lt;br /&gt;
The notecard is not duplicated into the avatar&#039;s personal inventory (inventoryitems). It stays embedded in the object asset.&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/Walkthroughs/Avatar Acquires Inventory]]&lt;br /&gt;
* [[OpenSimulator Internals/Walkthroughs/Avatar Rezzes Box]]&lt;br /&gt;
* [[OpenSimulator Internals/Walkthroughs/Avatar Rezzes Inventory]]&lt;br /&gt;
* [[OpenSimulator Internals/Walkthroughs/Garbage Collection]]&lt;br /&gt;
* [[OpenSimulator Internals/Code Map/InventoryAccessModule]]&lt;br /&gt;
* [[OpenSimulator Internals/Databases]]&lt;/div&gt;</summary>
		<author><name>Jwbshaw</name></author>
	</entry>
	<entry>
		<id>http://osimdev.org/wiki/index.php?title=OpenSimulator_Internals/Walkthroughs/Avatar_Rezzes_Box&amp;diff=103</id>
		<title>OpenSimulator Internals/Walkthroughs/Avatar Rezzes Box</title>
		<link rel="alternate" type="text/html" href="http://osimdev.org/wiki/index.php?title=OpenSimulator_Internals/Walkthroughs/Avatar_Rezzes_Box&amp;diff=103"/>
		<updated>2026-07-07T22:39:12Z</updated>

		<summary type="html">&lt;p&gt;Jwbshaw: first&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= OpenSimulator Internals/Walkthroughs/Avatar Rezzes Box =&lt;br /&gt;
&lt;br /&gt;
== Overview ==&lt;br /&gt;
&lt;br /&gt;
Traces what happens in code, connectors, and database when an avatar rezzes a simple object (a box) from inventory into the world, then puts a notecard inside it. Uses live data from the osimdev T1 region database to illustrate the actual DB state.&lt;br /&gt;
&lt;br /&gt;
This is a concrete instance of [[OpenSimulator Internals/Walkthroughs/Avatar Rezzes Inventory]]. Read that page for the full code path. This page focuses on the DB state before and after.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Setup: What Was in the Database Before ==&lt;br /&gt;
&lt;br /&gt;
Before the box was rezzed, osimdev T1 contained 7 objects (471 prims). After rezzing the box and adding a notecard:&lt;br /&gt;
&lt;br /&gt;
From live query (WHERE UUID = SceneGroupID to get root prim names):&lt;br /&gt;
&lt;br /&gt;
 SceneGroupID                          prim_count  root_name&lt;br /&gt;
 a4cbde76-...                          193         CASA 3 (large house)&lt;br /&gt;
 da990c49-...                          181         Brown House&lt;br /&gt;
 ed13b4e9-...                           54         4 chair set&lt;br /&gt;
 ef6cc0c0-...                           36         Athena Bento BoM Mesh Body 6.5&lt;br /&gt;
 d78b8ebf-...                            5         Brown House Sculpts&lt;br /&gt;
 1285d009-...                            1         Sofa_1_N150911kompleet&lt;br /&gt;
 746c1d97-...                            1         Object (cube)&lt;br /&gt;
 789a253a-...                            1         Box&lt;br /&gt;
&lt;br /&gt;
Note: the original query used MIN(Name) GROUP BY SceneGroupID which returned child prim names (&amp;quot;171800&amp;quot;, &amp;quot;171801&amp;quot; etc.) for the Athena HUD instead of the root prim name. The correct query uses WHERE UUID = SceneGroupID. See WTF file.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== 1. Rezzing the Box ==&lt;br /&gt;
&lt;br /&gt;
Avatar drags &amp;quot;Box&amp;quot; from inventory to the world.&lt;br /&gt;
&lt;br /&gt;
Scene.RezObject() → BasicInventoryAccessModule.RezObject():&lt;br /&gt;
# InventoryService.GetItem() -- fetches the box&#039;s inventory record from inventoryitems table.&lt;br /&gt;
# AssetService.Get(assetID) -- fetches the serialised object XML from assets table.&lt;br /&gt;
# Scene.GetObjectsToRez() -- deserialises XML into SceneObjectGroup (1 prim).&lt;br /&gt;
# GetNewRezLocation() -- raycasts to ground surface for position.&lt;br /&gt;
# DoPreRezWhenFromItem() -- sets name/description, links FromUserInventoryItemID if copyable.&lt;br /&gt;
# Scene.AddNewSceneObject() -- adds to scene graph.&lt;br /&gt;
# SimulationDataService.StoreObject() called immediately on add -- writes prim to DB.&lt;br /&gt;
# CreateScriptInstances() -- no scripts in a plain box, so no-op.&lt;br /&gt;
# Schedules full update to all clients.&lt;br /&gt;
&lt;br /&gt;
; DB reads:&lt;br /&gt;
* inventoryitems -- SELECT: box item record&lt;br /&gt;
* assets -- SELECT: object XML asset&lt;br /&gt;
&lt;br /&gt;
; DB writes (immediate on AddNewSceneObject):&lt;br /&gt;
* prims -- INSERT: 1 row (UUID, SceneGroupID = same UUID for root, Name=&amp;quot;Box&amp;quot;, GroupPositionX/Y/Z, etc.)&lt;br /&gt;
* primshapes -- INSERT: 1 row (shape data: PCode=9 box, ProfileShape=0, etc.)&lt;br /&gt;
&lt;br /&gt;
; DB writes (on next backup cycle, ~18s later):&lt;br /&gt;
* prims -- UPDATE: position/state confirmed&lt;br /&gt;
* primitems -- INSERT: empty (no task inventory yet)&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== 2. Putting the Notecard in the Box ==&lt;br /&gt;
&lt;br /&gt;
Avatar opens the box contents and drags a notecard from inventory into it.&lt;br /&gt;
&lt;br /&gt;
This is a task inventory operation, not a world rez:&lt;br /&gt;
&lt;br /&gt;
# Viewer sends UpdateTaskInventory packet.&lt;br /&gt;
# Scene.UpdateTaskInventory() validates permissions.&lt;br /&gt;
# Copies inventory item to object&#039;s task inventory (SceneObjectPart.Inventory).&lt;br /&gt;
# Sets HasGroupChanged = true on the SOG.&lt;br /&gt;
# On next backup cycle: SimulationDataService.StoreObject() writes primitems row.&lt;br /&gt;
&lt;br /&gt;
; DB writes (on next backup cycle):&lt;br /&gt;
* primitems -- INSERT: 1 row (primID = box UUID, name=&amp;quot;Notecard&amp;quot;, assetID = notecard asset UUID, invType=7, assetType=7, etc.)&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== 3. DB State After ==&lt;br /&gt;
&lt;br /&gt;
prims table: 1 new row for the box root prim.&lt;br /&gt;
primshapes table: 1 new row.&lt;br /&gt;
primitems table: 1 new row for the notecard inside the box.&lt;br /&gt;
&lt;br /&gt;
The notecard asset itself (the text content) lives in the assets table -- it was already there from when the notecard was written. The primitems row references it by assetID.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== 4. What the DB Rows Look Like ==&lt;br /&gt;
&lt;br /&gt;
prims row (key fields):&lt;br /&gt;
* UUID -- unique prim UUID&lt;br /&gt;
* SceneGroupID -- same as UUID for root prim; child prims have root&#039;s UUID here&lt;br /&gt;
* RegionUUID -- T1 region UUID&lt;br /&gt;
* Name -- &amp;quot;Box&amp;quot;&lt;br /&gt;
* GroupPositionX/Y/Z -- world position&lt;br /&gt;
* OwnerID -- avatar UUID&lt;br /&gt;
* CreatorID -- avatar UUID&lt;br /&gt;
* BaseMask, OwnerMask, EveryoneMask, GroupMask, NextOwnerMask -- permissions&lt;br /&gt;
* ScriptAccessPin -- 0 (no scripts)&lt;br /&gt;
* RotationX/Y/Z/W -- orientation quaternion&lt;br /&gt;
&lt;br /&gt;
primshapes row (key fields):&lt;br /&gt;
* UUID -- same as prim UUID&lt;br /&gt;
* PCode -- 9 (primitive)&lt;br /&gt;
* ProfileShape -- 0 (square/box)&lt;br /&gt;
* HollowShape -- 0&lt;br /&gt;
* ScaleX/Y/Z -- 0.5, 0.5, 0.5 (default half-metre cube)&lt;br /&gt;
* PathBegin/PathEnd -- 0/1 (full path)&lt;br /&gt;
* ProfileBegin/ProfileEnd -- 0/1 (full profile)&lt;br /&gt;
&lt;br /&gt;
primitems row (key fields, after notecard added):&lt;br /&gt;
* itemID -- unique UUID for this task inventory entry&lt;br /&gt;
* primID -- box prim UUID&lt;br /&gt;
* assetID -- notecard asset UUID&lt;br /&gt;
* name -- notecard name&lt;br /&gt;
* description -- notecard description&lt;br /&gt;
* invType -- 7 (notecard)&lt;br /&gt;
* assetType -- 7 (notecard)&lt;br /&gt;
* creatorID -- avatar UUID&lt;br /&gt;
* ownerID -- avatar UUID&lt;br /&gt;
* BaseMask/CurrentMask/etc. -- permissions&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/Walkthroughs/Avatar Rezzes Inventory]]&lt;br /&gt;
* [[OpenSimulator Internals/Walkthroughs/Avatar Derezzes Object]]&lt;br /&gt;
* [[OpenSimulator Internals/Code Map/InventoryAccessModule]]&lt;br /&gt;
* [[OpenSimulator Internals/Databases]]&lt;/div&gt;</summary>
		<author><name>Jwbshaw</name></author>
	</entry>
	<entry>
		<id>http://osimdev.org/wiki/index.php?title=OpenSimulator_Internals/Walkthroughs/Garbage_Collection&amp;diff=102</id>
		<title>OpenSimulator Internals/Walkthroughs/Garbage Collection</title>
		<link rel="alternate" type="text/html" href="http://osimdev.org/wiki/index.php?title=OpenSimulator_Internals/Walkthroughs/Garbage_Collection&amp;diff=102"/>
		<updated>2026-07-07T22:38:02Z</updated>

		<summary type="html">&lt;p&gt;Jwbshaw: first&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= OpenSimulator Internals/Walkthroughs/Garbage Collection =&lt;br /&gt;
&lt;br /&gt;
== Overview ==&lt;br /&gt;
&lt;br /&gt;
Traces the two garbage collection mechanisms in OpenSimulator: temporary object cleanup (temp-on-rez objects expiring) and the periodic persistence/auto-return cycle (objects returned to owners for parcel violations). Also covers manual delete and the object persistence lifecycle.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== 1. Temporary Object Cleanup ==&lt;br /&gt;
&lt;br /&gt;
 OpenSim/Region/Framework/Scenes/Scene.cs -- CleanTempObjects()&lt;br /&gt;
&lt;br /&gt;
Temporary objects are those with PrimFlags.TemporaryOnRez set. They expire based on a per-object Expires timestamp.&lt;br /&gt;
&lt;br /&gt;
=== Trigger ===&lt;br /&gt;
&lt;br /&gt;
CleanTempObjects() is called from the main heartbeat loop every m_update_temp_cleaning frames (default 180 frames, approximately every 16 seconds at ~11fps).&lt;br /&gt;
&lt;br /&gt;
Runs asynchronously via WorkManager.RunInThreadPool to avoid blocking the heartbeat.&lt;br /&gt;
&lt;br /&gt;
=== Process ===&lt;br /&gt;
&lt;br /&gt;
# Gets all entities from scene graph.&lt;br /&gt;
# For each SceneObjectGroup:&lt;br /&gt;
#* Checks IsDeleted.&lt;br /&gt;
#* Checks RootPart.Flags has PrimFlags.TemporaryOnRez.&lt;br /&gt;
#* Checks GetSittingAvatarsCount() == 0 -- does not expire objects with seated avatars.&lt;br /&gt;
#* Checks RootPart.Expires &amp;lt;= DateTime.UtcNow.&lt;br /&gt;
# If all conditions met: calls DeleteSceneObject(grp, false).&lt;br /&gt;
&lt;br /&gt;
DeleteSceneObject():&lt;br /&gt;
* Removes script instances.&lt;br /&gt;
* Removes physics actors.&lt;br /&gt;
* Unlinks from scene graph.&lt;br /&gt;
* Fires EventManager.TriggerObjectBeingRemovedFromScene().&lt;br /&gt;
* Calls SimulationDataService.RemoveObject() -- removes from prims/primshapes/primitems tables.&lt;br /&gt;
&lt;br /&gt;
; DB writes:&lt;br /&gt;
* prims -- DELETE&lt;br /&gt;
* primshapes -- DELETE&lt;br /&gt;
* primitems -- DELETE (task inventory)&lt;br /&gt;
&lt;br /&gt;
Temporary objects are not saved to inventory. They simply disappear.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== 2. Periodic Object Persistence ==&lt;br /&gt;
&lt;br /&gt;
 OpenSim/Region/Framework/Scenes/Scene.cs -- UpdateStorageBackup() → Backup()&lt;br /&gt;
&lt;br /&gt;
The region periodically persists changed objects to the database.&lt;br /&gt;
&lt;br /&gt;
=== Trigger ===&lt;br /&gt;
&lt;br /&gt;
UpdateStorageBackup() called every m_update_backup frames (default 200 frames, approximately every 18 seconds). Runs async via WorkManager.RunInThreadPool. Protected by m_backingup flag -- skips if previous backup still running.&lt;br /&gt;
&lt;br /&gt;
=== Process ===&lt;br /&gt;
&lt;br /&gt;
Backup() fires EventManager.TriggerOnBackup(SimulationDataService, forced).&lt;br /&gt;
&lt;br /&gt;
The SimulationDataService handler iterates all SceneObjectGroups. For each group with HasGroupChanged = true:&lt;br /&gt;
&lt;br /&gt;
Persistence timing check (unless forced=true):&lt;br /&gt;
* Must have been changed for at least MinimumTimeBeforePersistenceConsidered (default 60 seconds).&lt;br /&gt;
* Must not have been unchanged for longer than MaximumTimeBeforePersistenceConsidered (default 600 seconds) -- forces persistence of long-unchanged objects.&lt;br /&gt;
&lt;br /&gt;
If conditions met: calls group.ProcessBackup(SimulationDataService, forced).&lt;br /&gt;
&lt;br /&gt;
ProcessBackup() calls SimulationDataService.StoreObject():&lt;br /&gt;
* For each part in the group: writes to prims and primshapes tables (INSERT or UPDATE).&lt;br /&gt;
* Writes task inventory to primitems table.&lt;br /&gt;
* Clears HasGroupChanged.&lt;br /&gt;
&lt;br /&gt;
; DB writes:&lt;br /&gt;
* prims -- INSERT or UPDATE per changed prim&lt;br /&gt;
* primshapes -- INSERT or UPDATE&lt;br /&gt;
* primitems -- INSERT or UPDATE (task inventory)&lt;br /&gt;
&lt;br /&gt;
=== Auto-Return Messages ===&lt;br /&gt;
&lt;br /&gt;
Backup() also drains m_returns dictionary. For each returned object:&lt;br /&gt;
* Sends GridInstantMessage to the owner via IMessageTransferModule.&lt;br /&gt;
* Message: &amp;quot;Your object X was returned from parcel Y in region Z due to [reason].&amp;quot;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== 3. Parcel Auto-Return ==&lt;br /&gt;
&lt;br /&gt;
Objects left on parcels they don&#039;t belong to are returned automatically based on parcel OtherCleanTime setting.&lt;br /&gt;
&lt;br /&gt;
=== Trigger ===&lt;br /&gt;
&lt;br /&gt;
ILandObject.ReturnLandObjects() is called periodically by the land module. Objects exceeding the parcel&#039;s OtherCleanTime are queued for return.&lt;br /&gt;
&lt;br /&gt;
=== Process ===&lt;br /&gt;
&lt;br /&gt;
# LandModule identifies objects that have exceeded their allowed time on the parcel.&lt;br /&gt;
# Calls Scene.returnObjects() with the list.&lt;br /&gt;
# returnObjects() calls IInventoryAccessModule.CopyToInventory(DeRezAction.Return) for each owner group.&lt;br /&gt;
# CopyBundleToInventory() serialises objects, creates assets, inserts inventory items into owner&#039;s Lost and Found folder.&lt;br /&gt;
# Scene.AddReturn() queues the return notification.&lt;br /&gt;
# Scene.DeleteSceneObject() removes objects from scene and database.&lt;br /&gt;
&lt;br /&gt;
; DB writes:&lt;br /&gt;
* assets -- INSERT: serialised object XML&lt;br /&gt;
* inventoryitems -- INSERT: item in Lost and Found&lt;br /&gt;
* prims/primshapes/primitems -- DELETE&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== 4. Object Persistence Lifecycle Summary ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! State !! HasGroupChanged !! In DB !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| Just rezzed || true || yes (immediately on AddNewSceneObject) || Immediately persisted on rez&lt;br /&gt;
|-&lt;br /&gt;
| Modified || true || stale || Queued for next backup cycle&lt;br /&gt;
|-&lt;br /&gt;
| Persisted || false || current || Written by Backup()&lt;br /&gt;
|-&lt;br /&gt;
| Temp-on-rez expired || -- || deleted || CleanTempObjects() removes&lt;br /&gt;
|-&lt;br /&gt;
| Deleted by avatar || -- || deleted || DeleteSceneObject() removes immediately&lt;br /&gt;
|-&lt;br /&gt;
| Returned || -- || deleted || CopyToInventory + DeleteSceneObject&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== 5. Shutdown Persistence ==&lt;br /&gt;
&lt;br /&gt;
On Scene.Close():&lt;br /&gt;
* Calls Backup(true) with forced=true.&lt;br /&gt;
* All objects with HasGroupChanged = true are persisted regardless of timing.&lt;br /&gt;
* Ensures no changes are lost on clean shutdown.&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/Scene]]&lt;br /&gt;
* [[OpenSimulator Internals/Code Map/InventoryAccessModule]]&lt;br /&gt;
* [[OpenSimulator Internals/Walkthroughs/Avatar Removes From Inventory]]&lt;br /&gt;
* [[OpenSimulator Internals/Walkthroughs/Avatar Derezzes Object]]&lt;/div&gt;</summary>
		<author><name>Jwbshaw</name></author>
	</entry>
	<entry>
		<id>http://osimdev.org/wiki/index.php?title=OpenSimulator_Internals/Code_Map&amp;diff=101</id>
		<title>OpenSimulator Internals/Code Map</title>
		<link rel="alternate" type="text/html" href="http://osimdev.org/wiki/index.php?title=OpenSimulator_Internals/Code_Map&amp;diff=101"/>
		<updated>2026-07-07T14:01:35Z</updated>

		<summary type="html">&lt;p&gt;Jwbshaw: more&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= OpenSimulator Internals/Code Map =&lt;br /&gt;
&lt;br /&gt;
== Overview ==&lt;br /&gt;
&lt;br /&gt;
This page maps the OpenSimulator codebase from the top down. Each section links to a drill-down page covering that component in detail.&lt;br /&gt;
&lt;br /&gt;
Both ROBUST and OpenSim.exe are built from the same source tree and share the same DLL output. The difference is which entry point is called and which config file is loaded.&lt;br /&gt;
&lt;br /&gt;
Source repository: https://github.com/opensim/opensim&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
* [[OpenSimulator Internals/Code Map/ROBUST]] -- Grid services process&lt;br /&gt;
* [[OpenSimulator Internals/Code Map/OpenSim]] -- Region simulator process&lt;br /&gt;
** [[OpenSimulator Internals/Code Map/Scene]] -- Central region object&lt;br /&gt;
** [[OpenSimulator Internals/Code Map/ScenePresence]] -- Per-avatar state and lifecycle&lt;br /&gt;
** [[OpenSimulator Internals/Code Map/LLUDP]] -- Viewer network transport layer&lt;br /&gt;
** [[OpenSimulator Internals/Code Map/LLClientView]] -- IClientAPI implementation, packet dispatch and entity update encoding&lt;br /&gt;
** [[OpenSimulator Internals/Code Map/EntityTransferModule]] -- Teleport and region crossing&lt;br /&gt;
** [[OpenSimulator Internals/Code Map/HGEntityTransferModule]] -- HyperGrid teleport extensions&lt;br /&gt;
** [[OpenSimulator Internals/Code Map/AttachmentsModule]] -- Attachment rez, save, transfer&lt;br /&gt;
** [[OpenSimulator Internals/Code Map/AvatarFactoryModule]] -- Appearance baking, save, send&lt;br /&gt;
** [[OpenSimulator Internals/Code Map/InventoryAccessModule]] -- Object rez/take, HG asset mirroring&lt;br /&gt;
* [[OpenSimulator Internals/Code Map/Shared]] -- Code used by both&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== See Also ==&lt;br /&gt;
&lt;br /&gt;
* [[OpenSimulator Internals/Reading the Code]]&lt;br /&gt;
* [[OpenSimulator Internals/Architecture Overview]]&lt;br /&gt;
* [[OpenSimulator Internals/Connector Architecture]]&lt;br /&gt;
* [[OpenSimulator Internals/Walkthroughs]]&lt;/div&gt;</summary>
		<author><name>Jwbshaw</name></author>
	</entry>
	<entry>
		<id>http://osimdev.org/wiki/index.php?title=OpenSimulator_Internals/Code_Map/ROBUST&amp;diff=100</id>
		<title>OpenSimulator Internals/Code Map/ROBUST</title>
		<link rel="alternate" type="text/html" href="http://osimdev.org/wiki/index.php?title=OpenSimulator_Internals/Code_Map/ROBUST&amp;diff=100"/>
		<updated>2026-07-07T13:57:14Z</updated>

		<summary type="html">&lt;p&gt;Jwbshaw: updates&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= OpenSimulator Internals/Code Map/ROBUST =&lt;br /&gt;
&lt;br /&gt;
== Overview ==&lt;br /&gt;
&lt;br /&gt;
ROBUST is the grid services process. It reads configuration, starts HTTP listeners, loads service connector plugins, then sits waiting for incoming HTTP requests from simulators.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
=== Entry Point ===&lt;br /&gt;
&lt;br /&gt;
 OpenSim/Server/ServerMain.cs -- class OpenSimServer, Main()&lt;br /&gt;
&lt;br /&gt;
Sequence:&lt;br /&gt;
&lt;br /&gt;
# Sets culture and .NET HTTP client defaults:&lt;br /&gt;
#* ServicePointManager.DefaultConnectionLimit = 64&lt;br /&gt;
#* ServicePointManager.MaxServicePointIdleTime = 30000&lt;br /&gt;
#* Expect100Continue = false&lt;br /&gt;
#* UseNagleAlgorithm = false&lt;br /&gt;
#* ServerCertificateValidationCallback = ValidateServerCertificate&lt;br /&gt;
# Creates HttpServerBase(&amp;quot;R.O.B.U.S.T.&amp;quot;, args) -- config is loaded here (see Config Loading below)&lt;br /&gt;
# Reads [Startup] section -- throws if missing&lt;br /&gt;
# Reads DnsTimeout (default 30000ms), NoVerifyCertChain, NoVerifyCertHostname from [Startup]&lt;br /&gt;
# Calls WebUtil.SetupHTTPClients() with cert settings and max 32 connections&lt;br /&gt;
# Reads connector list -- merges ServiceConnectors from [Startup] with all keys from [ServiceList]&lt;br /&gt;
# Copies System.Drawing.Common.dll for current platform (Windows vs Linux)&lt;br /&gt;
# Loops through connectors -- parses configName@port/dll:class format, loads each (see Service Connector Loading below)&lt;br /&gt;
# Special case: LLLoginServiceInConnector gets an IndexPHPHandler added to its HTTP server before loading&lt;br /&gt;
# Prints robuststartuplogo.txt to console if present&lt;br /&gt;
# Creates PluginLoader&lt;br /&gt;
# Calls m_Server.Run() -- enters main loop&lt;br /&gt;
# On exit: m_Server.Shutdown(), Util.StopThreadPool(), Environment.Exit()&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
=== Config Loading ===&lt;br /&gt;
&lt;br /&gt;
 OpenSim/Server/Base/HttpServerBase.cs&lt;br /&gt;
 OpenSim/Server/Base/ServicesServerBase.cs&lt;br /&gt;
&lt;br /&gt;
HttpServerBase constructor handles config loading. Layers are applied in order, each overriding the previous:&lt;br /&gt;
&lt;br /&gt;
# Command line args parsed (-i ini file, -c console, -l logfile, -p prompt, -g logconfig)&lt;br /&gt;
# Ini file loaded -- defaults to Robust.ini, derived from executable name. Can be a local file or remote HTTP/HTTPS URL.&lt;br /&gt;
# Include-* keys scanned -- additional ini files merged in. Supports wildcards and URLs. Loop repeats until no new includes found.&lt;br /&gt;
# Environment variables merged in&lt;br /&gt;
# Command line args merged on top -- command line always wins&lt;br /&gt;
# Variable substitution run (ReplaceKeyValues) -- expands ${Section|Key} references&lt;br /&gt;
# ReadConfig() called -- reads [Network] section for port and SSL settings&lt;br /&gt;
&lt;br /&gt;
[Network] minimum requirements:&lt;br /&gt;
* port -- required, no default, ROBUST will not start without it&lt;br /&gt;
* https_main, https_listener, https_external -- optional SSL flags&lt;br /&gt;
* cert_path, cert_pass -- required if SSL enabled&lt;br /&gt;
* ConsolePort -- optional remote console port&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
=== HTTP Servers ===&lt;br /&gt;
&lt;br /&gt;
 OpenSim/Server/Base/HttpServerBase.cs&lt;br /&gt;
&lt;br /&gt;
* Main HTTP server created on port from [Network]&lt;br /&gt;
* Optional second SSL listener if https_listener = true&lt;br /&gt;
* All servers started before connectors are loaded&lt;br /&gt;
* Additional ports are created on demand via MainServer.GetHttpServer(port) during connector loading&lt;br /&gt;
* Handlers register into a running server during connector construction&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
=== Service Connector Loading ===&lt;br /&gt;
&lt;br /&gt;
 OpenSim/Server/Base/ServerUtils.cs -- LoadPlugin()&lt;br /&gt;
&lt;br /&gt;
Connector string format:&lt;br /&gt;
&lt;br /&gt;
 configName@port/OpenSim.Server.Handlers.dll:ClassName&lt;br /&gt;
&lt;br /&gt;
Parsing:&lt;br /&gt;
* Split on / -- left side is optional configName@port, right side is dll:class&lt;br /&gt;
* Split left side on @ -- if two parts, first is configName, second is port&lt;br /&gt;
* If port specified: get or create HTTP server for that port via MainServer.GetHttpServer()&lt;br /&gt;
* If no port: use MainServer.Instance (main port)&lt;br /&gt;
&lt;br /&gt;
Loading:&lt;br /&gt;
* LoadPlugin() tries constructor with (IConfigSource, IHttpServer, configName) first&lt;br /&gt;
* Falls back to (IConfigSource, IHttpServer) if that fails&lt;br /&gt;
* Loaded connectors added to m_ServiceConnectors list&lt;br /&gt;
* Failed loads logged as errors but do not stop startup&lt;br /&gt;
&lt;br /&gt;
See [[OpenSimulator Internals/Connector Architecture]] for the full connector pattern.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
=== Main Loop ===&lt;br /&gt;
&lt;br /&gt;
 OpenSim/Server/Base/ServicesServerBase.cs -- Run()&lt;br /&gt;
&lt;br /&gt;
* Watchdog and MemoryWatchdog threads enabled&lt;br /&gt;
* Sits in a console prompt loop&lt;br /&gt;
* Shutdown signal (quit/shutdown command or SIGTERM) triggers:&lt;br /&gt;
** m_Server.Shutdown()&lt;br /&gt;
** Util.StopThreadPool()&lt;br /&gt;
** Environment.Exit()&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
=== Service Implementations ===&lt;br /&gt;
&lt;br /&gt;
Each service connector loaded from [ServiceList] handles one service domain.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Service !! Implementation !! Handler&lt;br /&gt;
|-&lt;br /&gt;
| AssetService || OpenSim/Services/AssetService/AssetService.cs || OpenSim/Server/Handlers/Asset/&lt;br /&gt;
|-&lt;br /&gt;
| GridService || OpenSim/Services/GridService/GridService.cs || OpenSim/Server/Handlers/Grid/&lt;br /&gt;
|-&lt;br /&gt;
| UserAccountService || OpenSim/Services/UserAccountService/UserAccountService.cs || OpenSim/Server/Handlers/UserAccounts/&lt;br /&gt;
|-&lt;br /&gt;
| PresenceService || OpenSim/Services/PresenceService/PresenceService.cs || OpenSim/Server/Handlers/Presence/&lt;br /&gt;
|-&lt;br /&gt;
| InventoryService || OpenSim/Services/InventoryService/XInventoryService.cs || OpenSim/Server/Handlers/Inventory/&lt;br /&gt;
|-&lt;br /&gt;
| AuthenticationService || OpenSim/Services/AuthenticationService/PasswordAuthenticationService.cs || OpenSim/Server/Handlers/Authentication/&lt;br /&gt;
|-&lt;br /&gt;
| AvatarService || OpenSim/Services/AvatarService/AvatarService.cs || OpenSim/Server/Handlers/Avatar/&lt;br /&gt;
|-&lt;br /&gt;
| GridUserService || OpenSim/Services/UserAccountService/GridUserService.cs || OpenSim/Server/Handlers/GridUser/&lt;br /&gt;
|-&lt;br /&gt;
| AgentPreferencesService || OpenSim/Services/UserAccountService/AgentPreferencesService.cs || OpenSim/Server/Handlers/AgentPreferences/&lt;br /&gt;
|-&lt;br /&gt;
| LoginService || OpenSim/Services/LLLoginService/LLLoginService.cs || OpenSim/Server/Handlers/Login/&lt;br /&gt;
|-&lt;br /&gt;
| GatekeeperService || OpenSim/Services/HypergridService/GatekeeperService.cs || OpenSim/Server/Handlers/Hypergrid/&lt;br /&gt;
|-&lt;br /&gt;
| UserAgentService || OpenSim/Services/HypergridService/UserAgentService.cs || OpenSim/Server/Handlers/Hypergrid/&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Note: GridUserService and AgentPreferencesService source files live in the UserAccountService directory, not separate directories.&lt;br /&gt;
&lt;br /&gt;
See [[OpenSimulator Internals/Code Map/ROBUST/GridService RegisterRegion]] for a detailed trace of GridService.RegisterRegion() and DeregisterRegion().&lt;br /&gt;
&lt;br /&gt;
See [[OpenSimulator Internals/Code Map/ROBUST/PresenceService]] for a detailed trace of PresenceService.&lt;br /&gt;
&lt;br /&gt;
See [[OpenSimulator Internals/Code Map/ROBUST/UserAccountService]] for a detailed trace of UserAccountService.&lt;br /&gt;
&lt;br /&gt;
See [[OpenSimulator Internals/Code Map/ROBUST/InventoryService]] for a detailed trace of InventoryService.&lt;br /&gt;
&lt;br /&gt;
See [[OpenSimulator Internals/Code Map/ROBUST/AuthenticationService]] for a detailed trace of AuthenticationService, including the impersonation mechanism.&lt;br /&gt;
&lt;br /&gt;
See [[OpenSimulator Internals/Code Map/ROBUST/AvatarService]] for a detailed trace of AvatarService.&lt;br /&gt;
&lt;br /&gt;
See [[OpenSimulator Internals/Code Map/ROBUST/GridUserService]] for a detailed trace of GridUserService.&lt;br /&gt;
&lt;br /&gt;
See [[OpenSimulator Internals/Code Map/ROBUST/AgentPreferencesService]] for a detailed trace of AgentPreferencesService.&lt;br /&gt;
&lt;br /&gt;
See [[OpenSimulator Internals/Code Map/ROBUST/LoginService]] for a detailed trace of LLLoginService.&lt;br /&gt;
&lt;br /&gt;
See [[OpenSimulator Internals/Code Map/ROBUST/GatekeeperService]] for a detailed trace of GatekeeperService.&lt;br /&gt;
&lt;br /&gt;
See [[OpenSimulator Internals/Code Map/ROBUST/UserAgentService]] for a detailed trace of UserAgentService.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== See Also ==&lt;br /&gt;
&lt;br /&gt;
* [[OpenSimulator Internals/Code Map]]&lt;br /&gt;
* [[OpenSimulator Internals/Code Map/Scene]]&lt;br /&gt;
* [[OpenSimulator Internals/Code Map/ScenePresence]]&lt;br /&gt;
* [[OpenSimulator Internals/Code Map/AvatarFactoryModule]]&lt;br /&gt;
* [[OpenSimulator Internals/Code Map/AttachmentsModule]]&lt;br /&gt;
* [[OpenSimulator Internals/Code Map/EntityTransferModule]]&lt;br /&gt;
* [[OpenSimulator Internals/Code Map/HGEntityTransferModule]]&lt;br /&gt;
* [[OpenSimulator Internals/Code Map/InventoryAccessModule]]&lt;br /&gt;
* [[OpenSimulator Internals/Reading the Code]]&lt;br /&gt;
* [[OpenSimulator Internals/ROBUST Services]]&lt;br /&gt;
* [[OpenSimulator Internals/Connector Architecture]]&lt;/div&gt;</summary>
		<author><name>Jwbshaw</name></author>
	</entry>
	<entry>
		<id>http://osimdev.org/wiki/index.php?title=OpenSimulator_Internals/Code_Map/Scene&amp;diff=99</id>
		<title>OpenSimulator Internals/Code Map/Scene</title>
		<link rel="alternate" type="text/html" href="http://osimdev.org/wiki/index.php?title=OpenSimulator_Internals/Code_Map/Scene&amp;diff=99"/>
		<updated>2026-07-07T13:55:59Z</updated>

		<summary type="html">&lt;p&gt;Jwbshaw: updates&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= OpenSimulator Internals/Code Map/Scene =&lt;br /&gt;
&lt;br /&gt;
== Overview ==&lt;br /&gt;
&lt;br /&gt;
Scene is the central object of the region simulator. One Scene instance exists per region. It holds all in-world state and coordinates between the physics engine, script engine, client connections, storage, and grid services.&lt;br /&gt;
&lt;br /&gt;
Class hierarchy:&lt;br /&gt;
&lt;br /&gt;
 Scene → SceneBase → RegionApplicationBase&lt;br /&gt;
&lt;br /&gt;
Source: OpenSim/Region/Framework/Scenes/Scene.cs&lt;br /&gt;
&lt;br /&gt;
Scene.cs is a partial class -- additional methods are in other files in the same directory.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Constructor ==&lt;br /&gt;
&lt;br /&gt;
Two constructors:&lt;br /&gt;
&lt;br /&gt;
 Scene(RegionInfo regInfo)  -- base constructor&lt;br /&gt;
 Scene(RegionInfo, AgentCircuitManager, ISimulationDataService, IEstateDataService, IConfigSource, string version)  -- full constructor&lt;br /&gt;
&lt;br /&gt;
Base constructor:&lt;br /&gt;
# Creates SceneGraph (holds all entities and physics)&lt;br /&gt;
# Hooks SceneGraph.UnRecoverableError -- triggers RestartNow() on physics crash&lt;br /&gt;
# Sets defaults: PhysicalPrims=true, CollidablePrims=true, PhysicsEnabled=true, AllowAvatarCrossing=true, PeriodicBackup=true&lt;br /&gt;
# Creates EventManager&lt;br /&gt;
# Creates ScenePermissions&lt;br /&gt;
&lt;br /&gt;
Full constructor (called from OpenSimBase.CreateScene()):&lt;br /&gt;
# Loads RegionSettings from SimulationDataService -- sets default terrain textures if missing, copies classic textures to PBR slots if PBR not set&lt;br /&gt;
# Loads EstateSettings from EstateDataService&lt;br /&gt;
# Creates SceneGridInfo from config and ServerURI&lt;br /&gt;
# Hooks EventManager land object events to SimulationDataService storage&lt;br /&gt;
# Reads [Startup] config -- draw distances, prim limits, physics flags, script engine, persistence timings, frame rate, viewer allow/deny lists, coarse location update interval, terrain update interval, backup interval&lt;br /&gt;
# Reads [EntityTransfer] config -- AllowAvatarCrossing, DisableObjectTransfer&lt;br /&gt;
# Reads [InterestManagement] config -- update prioritization scheme, reprioritization settings, object culling by distance&lt;br /&gt;
# Creates SimStatsReporter&lt;br /&gt;
# Starts timer watchdog&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Service References ==&lt;br /&gt;
&lt;br /&gt;
All grid services are accessed through lazy-loaded properties backed by RequestModuleInterface&amp;lt;T&amp;gt;(). They throw if the service is not available (except EstateDataServiceSafe which returns null).&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Property !! Interface !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| AssetService || IAssetService || throws if missing&lt;br /&gt;
|-&lt;br /&gt;
| InventoryService || IInventoryService || throws if missing, with detailed error message about config&lt;br /&gt;
|-&lt;br /&gt;
| GridService || IGridService || throws if missing&lt;br /&gt;
|-&lt;br /&gt;
| SimulationDataService || ISimulationDataService || throws if missing&lt;br /&gt;
|-&lt;br /&gt;
| EstateDataService || IEstateDataService || throws if missing&lt;br /&gt;
|-&lt;br /&gt;
| UserAccountService || IUserAccountService || null if missing&lt;br /&gt;
|-&lt;br /&gt;
| PresenceService || IPresenceService || null if missing&lt;br /&gt;
|-&lt;br /&gt;
| AuthenticationService || IAuthenticationService || null if missing&lt;br /&gt;
|-&lt;br /&gt;
| AvatarService || IAvatarService || null if missing&lt;br /&gt;
|-&lt;br /&gt;
| GridUserService || IGridUserService || null if missing&lt;br /&gt;
|-&lt;br /&gt;
| AgentPreferencesService || IAgentPreferencesService || null if missing&lt;br /&gt;
|-&lt;br /&gt;
| AuthorizationService || IAuthorizationService || null if missing&lt;br /&gt;
|-&lt;br /&gt;
| LibraryService || ILibraryService || null if missing&lt;br /&gt;
|-&lt;br /&gt;
| SimulationService || ISimulationService || null if missing&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Module references (set by SetModuleInterfaces() after modules load):&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Property !! Interface&lt;br /&gt;
|-&lt;br /&gt;
| EntityTransferModule || IEntityTransferModule -- teleport and region crossing&lt;br /&gt;
|-&lt;br /&gt;
| AttachmentsModule || IAttachmentsModule&lt;br /&gt;
|-&lt;br /&gt;
| AgentTransactionsModule || IAgentAssetTransactions&lt;br /&gt;
|-&lt;br /&gt;
| UserManagementModule || IUserManagement&lt;br /&gt;
|-&lt;br /&gt;
| AvatarFactory || IAvatarFactoryModule&lt;br /&gt;
|-&lt;br /&gt;
| CapsModule || ICapabilitiesModule&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== The Main Loop (Heartbeat) ==&lt;br /&gt;
&lt;br /&gt;
The scene runs one thread: the Heartbeat thread. Started by Start():&lt;br /&gt;
&lt;br /&gt;
 Heartbeat()&lt;br /&gt;
   TriggerOnRegionStarted()&lt;br /&gt;
   Update(1)  -- first frame, watchdog not yet active&lt;br /&gt;
   Watchdog alarm enabled&lt;br /&gt;
   Update(-1)  -- runs until shutdown&lt;br /&gt;
&lt;br /&gt;
Update() loop runs once per frame:&lt;br /&gt;
&lt;br /&gt;
Per frame (every frame unless noted):&lt;br /&gt;
# CheckTerrainUpdates() -- every 4 frames&lt;br /&gt;
# UpdateTerrain() -- every m_update_terrain frames (default 1000)&lt;br /&gt;
# UpdatePreparePhysics() -- physics pre-step&lt;br /&gt;
# SendCoarseLocations() -- every 5 frames, async via thread pool&lt;br /&gt;
# UpdatePhysics(FrameTime) -- main physics step, returns physicsFPS&lt;br /&gt;
# CheckAtTargets() -- check llMoveToTarget / llRotLookAt&lt;br /&gt;
# UpdateObjectGroups() -- send queued object updates to clients&lt;br /&gt;
# UpdatePresences() -- send presence updates to clients&lt;br /&gt;
# CleanTempObjects() -- every 180 frames, async&lt;br /&gt;
# UpdateEvents() -- fires EventManager.OnFrame&lt;br /&gt;
# UpdateStorageBackup() -- every 200 frames, async&lt;br /&gt;
# Frame 20: enable logins, inform neighbours region is up, set Ready=true, GC compact&lt;br /&gt;
&lt;br /&gt;
Frame timing: FrameTime defaults to 0.0908s (~11fps). Sleep is calculated to hit target frame time. Stats normalized to 55fps for viewer display.&lt;br /&gt;
&lt;br /&gt;
Backup runs asynchronously every 200 frames. Objects are only persisted if they have been changed for at least MinimumTimeBeforePersistenceConsidered (default 60s) and no longer than MaximumTimeBeforePersistenceConsidered (default 600s).&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Startup Sequence (called from OpenSimBase.CreateRegion) ==&lt;br /&gt;
&lt;br /&gt;
After construction:&lt;br /&gt;
&lt;br /&gt;
# scene.SetModuleInterfaces() -- wires up module references from loaded region modules&lt;br /&gt;
# loadAllLandObjectsFromStorage() -- loads parcels from region database&lt;br /&gt;
# LoadPrimsFromStorage() -- loads all objects, calls AddRestoredSceneObject() for each&lt;br /&gt;
# RegisterRegionWithGrid() -- calls GridService.RegisterRegion(), throws on failure&lt;br /&gt;
# CreateScriptInstances() -- starts script engine for all loaded objects&lt;br /&gt;
# scene.Start() -- starts Heartbeat thread&lt;br /&gt;
&lt;br /&gt;
AllModulesLoaded() is called after all modules are loaded. Pushes simulator feature data to ISimulatorFeaturesModule (FPS, prim limits, grid info, search URL, etc).&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Region Crossing and Teleport ==&lt;br /&gt;
&lt;br /&gt;
All teleport and crossing logic is delegated to EntityTransferModule:&lt;br /&gt;
&lt;br /&gt;
 RequestTeleportLocation()  →  EntityTransferModule.Teleport()&lt;br /&gt;
 CrossAgentToNewRegion()    →  EntityTransferModule.Cross()&lt;br /&gt;
 TeleportClientHome()       →  EntityTransferModule.TeleportHome()&lt;br /&gt;
&lt;br /&gt;
Incoming objects and attachments from crossings:&lt;br /&gt;
&lt;br /&gt;
 IncomingCreateObject()     →  EntityTransferModule.HandleIncomingSceneObject()&lt;br /&gt;
 IncomingAttechments()      →  EntityTransferModule.HandleIncomingAttachments()&lt;br /&gt;
&lt;br /&gt;
Note: IncomingAttechments() -- the typo is in the source. See WTF file.&lt;br /&gt;
&lt;br /&gt;
OtherRegionUp() is called when a neighbouring region comes online. If within border distance, enables child agents in that region for all current root avatars via EntityTransferModule.EnableChildAgent().&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Avatar Connection (NewUserConnection) ==&lt;br /&gt;
&lt;br /&gt;
Called by the login service or another simulator to initiate a connection. Not triggered by the viewer directly.&lt;br /&gt;
&lt;br /&gt;
# Checks logins enabled&lt;br /&gt;
# Checks viewer allow/deny lists&lt;br /&gt;
# Handles existing ScenePresence (zombie root agents, race conditions during teleport)&lt;br /&gt;
# Clamps start position within region bounds&lt;br /&gt;
# CheckLandPositionAccess() -- checks telehub, parcel access, agent limit&lt;br /&gt;
# VerifyUserPresence() -- checks PresenceService for active session&lt;br /&gt;
# AuthorizeUser() -- checks estate ban, public access, access list, group membership&lt;br /&gt;
# Sets up CAPS via CapsModule&lt;br /&gt;
# ActivateCaps()&lt;br /&gt;
&lt;br /&gt;
Connection is activated later when the viewer sends UseCircuitCodePacket UDP packet.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Avatar Removal (RemoveClient) ==&lt;br /&gt;
&lt;br /&gt;
# Sends shutdown notice to child agents if root&lt;br /&gt;
# Avatar stands up if seated&lt;br /&gt;
# Closes child agent connections on neighbouring regions (async)&lt;br /&gt;
# Triggers ClientClosed and OnRemovePresence events&lt;br /&gt;
# De-rezzes attachments (root only)&lt;br /&gt;
# Sends KillObject to all clients&lt;br /&gt;
# Removes agent transactions&lt;br /&gt;
# Removes circuit, scene presence, client manager entry, CAPS&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Shutdown (Close) ==&lt;br /&gt;
&lt;br /&gt;
# Deregisters from GridService&lt;br /&gt;
# Kicks all root avatars with shutdown message&lt;br /&gt;
# Sets m_shuttingDown = true&lt;br /&gt;
# Sleeps 500ms to let kick messages reach clients&lt;br /&gt;
# Closes all agents&lt;br /&gt;
# Triggers SceneShuttingDown event&lt;br /&gt;
# Backup(true) -- force persist all pending changes&lt;br /&gt;
# Closes SceneGraph&lt;br /&gt;
# Disposes PhysicsScene last (scripts may reference physics during shutdown)&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Object Management ==&lt;br /&gt;
&lt;br /&gt;
Key methods:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Method !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| AddNewPrim() || Creates a new prim via raycast. Checks permissions. Uses entity creator registry if available, else creates SceneObjectGroup directly. Applies user default permissions from AgentPreferencesService.&lt;br /&gt;
|-&lt;br /&gt;
| AddRestoredSceneObject() || Adds object loaded from storage. Delegates to SceneGraph.&lt;br /&gt;
|-&lt;br /&gt;
| AddNewSceneObject() || Adds newly created object. Delegates to SceneGraph. Triggers ObjectAddedToScene event.&lt;br /&gt;
|-&lt;br /&gt;
| DeleteSceneObject() || Removes scripts, keyframe motion, email listeners, physics actors. Unlinks from scene. Triggers ObjectBeingRemovedFromScene.&lt;br /&gt;
|-&lt;br /&gt;
| UnlinkSceneObject() || Removes record from scene without destroying. On hard delete, removes from database.&lt;br /&gt;
|-&lt;br /&gt;
| IncomingCreateObject() || Handles object arriving from region crossing. Delegates to EntityTransferModule.&lt;br /&gt;
|-&lt;br /&gt;
| ForceSceneObjectBackup() || Synchronous backup of a single object. Used for deletes and link/unlink.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Client Event Subscriptions ==&lt;br /&gt;
&lt;br /&gt;
SubscribeToClientEvents() wires all viewer protocol events to scene handlers:&lt;br /&gt;
&lt;br /&gt;
* Terrain events (currently empty)&lt;br /&gt;
* Prim events: position, rotation, scale, shape, texture, name, material, link/unlink, duplicate, permissions, grab, spin, undo/redo&lt;br /&gt;
* Prim rez events: OnAddPrim → AddNewPrim(), OnRezObject → RezObject()&lt;br /&gt;
* Inventory events: folder and item CRUD, task inventory, rez script&lt;br /&gt;
* Teleport events: OnTeleportLocationRequest → RequestTeleportLocation()&lt;br /&gt;
* Script events: reset, get/set running&lt;br /&gt;
* Parcel events: return objects, set clean time, buy&lt;br /&gt;
* Grid events: money transfer&lt;br /&gt;
* Network events: stats update, viewer effect&lt;br /&gt;
&lt;br /&gt;
Note: UnSubscribeToClientEvents() is defined but marked FIXME -- not called anywhere. See WTF file.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Health Monitoring ==&lt;br /&gt;
&lt;br /&gt;
GetHealth() returns an integer 1-5:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Value !! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| 0 || Starting up&lt;br /&gt;
|-&lt;br /&gt;
| 1 || HTTP alive but heartbeat stopped -- possible lockup&lt;br /&gt;
|-&lt;br /&gt;
| 2 || Heartbeat running (frame tick &amp;lt; 4s ago)&lt;br /&gt;
|-&lt;br /&gt;
| 3 || One packet thread running&lt;br /&gt;
|-&lt;br /&gt;
| 4 || Both packet threads running&lt;br /&gt;
|-&lt;br /&gt;
| 5 || New user logged in within last 4 minutes&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
TimerWatchdog runs every second. Pushes health and root agent count to etcd if the IEtcdModule is present.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Persistence ==&lt;br /&gt;
&lt;br /&gt;
Objects are persisted via EventManager.OnBackup → SimulationDataService. Objects qualify for persistence if:&lt;br /&gt;
&lt;br /&gt;
* HasGroupChanged = true&lt;br /&gt;
* Time since last change &amp;gt; MinimumTimeBeforePersistenceConsidered (default 60s)&lt;br /&gt;
* Time since last change &amp;lt; MaximumTimeBeforePersistenceConsidered (default 600s) OR forced=true&lt;br /&gt;
&lt;br /&gt;
Auto-return queued in m_returns dictionary. Return messages sent via IMessageTransferModule on next backup cycle.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Notable Details ==&lt;br /&gt;
&lt;br /&gt;
* MegaRegions (CombineContiguousRegions) are explicitly rejected on startup with a fatal error&lt;br /&gt;
* The restart console command is registered but disabled -- marked unreliable in source&lt;br /&gt;
* IncomingAttechments() has a typo -- see WTF file for both file locations&lt;br /&gt;
* GOTO is used in AuthorizeUser() for group access checks -- commented in source as &amp;quot;some say GOTO is ugly&amp;quot;&lt;br /&gt;
* Heartbeat restart limit: if heartbeat thread dies and restarts more than 10 times, Environment.Exit(1)&lt;br /&gt;
* GC.Collect() is called explicitly at frame 20 and on map tile regeneration&lt;br /&gt;
* etcd integration is optional -- IEtcdModule only -- used for external health monitoring&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== See Also ==&lt;br /&gt;
&lt;br /&gt;
* [[OpenSimulator Internals/Code Map]]&lt;br /&gt;
* [[OpenSimulator Internals/Code Map/OpenSim]]&lt;br /&gt;
* [[OpenSimulator Internals/Code Map/ScenePresence]]&lt;br /&gt;
* [[OpenSimulator Internals/Code Map/EntityTransferModule]]&lt;br /&gt;
* [[OpenSimulator Internals/Code Map/HGEntityTransferModule]]&lt;br /&gt;
* [[OpenSimulator Internals/Code Map/AttachmentsModule]]&lt;br /&gt;
* [[OpenSimulator Internals/Code Map/AvatarFactoryModule]]&lt;br /&gt;
* [[OpenSimulator Internals/Code Map/InventoryAccessModule]]&lt;br /&gt;
* [[OpenSimulator Internals/Code Map/Shared]]&lt;br /&gt;
* [[OpenSimulator Internals/Architecture Overview]]&lt;br /&gt;
* [[OpenSimulator Internals/Connector Architecture]]&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 Transfer Between Regions]]&lt;/div&gt;</summary>
		<author><name>Jwbshaw</name></author>
	</entry>
	<entry>
		<id>http://osimdev.org/wiki/index.php?title=OpenSimulator_Internals/Code_Map/Scene&amp;diff=98</id>
		<title>OpenSimulator Internals/Code Map/Scene</title>
		<link rel="alternate" type="text/html" href="http://osimdev.org/wiki/index.php?title=OpenSimulator_Internals/Code_Map/Scene&amp;diff=98"/>
		<updated>2026-07-07T13:52:01Z</updated>

		<summary type="html">&lt;p&gt;Jwbshaw: wrong paste&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= OpenSimulator Internals/Code Map/Scene =&lt;br /&gt;
&lt;br /&gt;
== Overview ==&lt;br /&gt;
&lt;br /&gt;
Scene is the central object of the region simulator. One Scene instance exists per region. It holds all in-world state and coordinates between the physics engine, script engine, client connections, storage, and grid services.&lt;br /&gt;
&lt;br /&gt;
Class hierarchy:&lt;br /&gt;
&lt;br /&gt;
 Scene → SceneBase → RegionApplicationBase&lt;br /&gt;
&lt;br /&gt;
Source: OpenSim/Region/Framework/Scenes/Scene.cs&lt;br /&gt;
&lt;br /&gt;
Scene.cs is a partial class -- additional methods are in other files in the same directory.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Constructor ==&lt;br /&gt;
&lt;br /&gt;
Two constructors:&lt;br /&gt;
&lt;br /&gt;
 Scene(RegionInfo regInfo)  -- base constructor&lt;br /&gt;
 Scene(RegionInfo, AgentCircuitManager, ISimulationDataService, IEstateDataService, IConfigSource, string version)  -- full constructor&lt;br /&gt;
&lt;br /&gt;
Base constructor:&lt;br /&gt;
# Creates SceneGraph (holds all entities and physics)&lt;br /&gt;
# Hooks SceneGraph.UnRecoverableError -- triggers RestartNow() on physics crash&lt;br /&gt;
# Sets defaults: PhysicalPrims=true, CollidablePrims=true, PhysicsEnabled=true, AllowAvatarCrossing=true, PeriodicBackup=true&lt;br /&gt;
# Creates EventManager&lt;br /&gt;
# Creates ScenePermissions&lt;br /&gt;
&lt;br /&gt;
Full constructor (called from OpenSimBase.CreateScene()):&lt;br /&gt;
# Loads RegionSettings from SimulationDataService -- sets default terrain textures if missing, copies classic textures to PBR slots if PBR not set&lt;br /&gt;
# Loads EstateSettings from EstateDataService&lt;br /&gt;
# Creates SceneGridInfo from config and ServerURI&lt;br /&gt;
# Hooks EventManager land object events to SimulationDataService storage&lt;br /&gt;
# Reads [Startup] config -- draw distances, prim limits, physics flags, script engine, persistence timings, frame rate, viewer allow/deny lists, coarse location update interval, terrain update interval, backup interval&lt;br /&gt;
# Reads [EntityTransfer] config -- AllowAvatarCrossing, DisableObjectTransfer&lt;br /&gt;
# Reads [InterestManagement] config -- update prioritization scheme, reprioritization settings, object culling by distance&lt;br /&gt;
# Creates SimStatsReporter&lt;br /&gt;
# Starts timer watchdog&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Service References ==&lt;br /&gt;
&lt;br /&gt;
All grid services are accessed through lazy-loaded properties backed by RequestModuleInterface&amp;lt;T&amp;gt;(). They throw if the service is not available (except EstateDataServiceSafe which returns null).&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Property !! Interface !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| AssetService || IAssetService || throws if missing&lt;br /&gt;
|-&lt;br /&gt;
| InventoryService || IInventoryService || throws if missing, with detailed error message about config&lt;br /&gt;
|-&lt;br /&gt;
| GridService || IGridService || throws if missing&lt;br /&gt;
|-&lt;br /&gt;
| SimulationDataService || ISimulationDataService || throws if missing&lt;br /&gt;
|-&lt;br /&gt;
| EstateDataService || IEstateDataService || throws if missing&lt;br /&gt;
|-&lt;br /&gt;
| UserAccountService || IUserAccountService || null if missing&lt;br /&gt;
|-&lt;br /&gt;
| PresenceService || IPresenceService || null if missing&lt;br /&gt;
|-&lt;br /&gt;
| AuthenticationService || IAuthenticationService || null if missing&lt;br /&gt;
|-&lt;br /&gt;
| AvatarService || IAvatarService || null if missing&lt;br /&gt;
|-&lt;br /&gt;
| GridUserService || IGridUserService || null if missing&lt;br /&gt;
|-&lt;br /&gt;
| AgentPreferencesService || IAgentPreferencesService || null if missing&lt;br /&gt;
|-&lt;br /&gt;
| AuthorizationService || IAuthorizationService || null if missing&lt;br /&gt;
|-&lt;br /&gt;
| LibraryService || ILibraryService || null if missing&lt;br /&gt;
|-&lt;br /&gt;
| SimulationService || ISimulationService || null if missing&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Module references (set by SetModuleInterfaces() after modules load):&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Property !! Interface&lt;br /&gt;
|-&lt;br /&gt;
| EntityTransferModule || IEntityTransferModule -- teleport and region crossing&lt;br /&gt;
|-&lt;br /&gt;
| AttachmentsModule || IAttachmentsModule&lt;br /&gt;
|-&lt;br /&gt;
| AgentTransactionsModule || IAgentAssetTransactions&lt;br /&gt;
|-&lt;br /&gt;
| UserManagementModule || IUserManagement&lt;br /&gt;
|-&lt;br /&gt;
| AvatarFactory || IAvatarFactoryModule&lt;br /&gt;
|-&lt;br /&gt;
| CapsModule || ICapabilitiesModule&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== The Main Loop (Heartbeat) ==&lt;br /&gt;
&lt;br /&gt;
The scene runs one thread: the Heartbeat thread. Started by Start():&lt;br /&gt;
&lt;br /&gt;
 Heartbeat()&lt;br /&gt;
   TriggerOnRegionStarted()&lt;br /&gt;
   Update(1)  -- first frame, watchdog not yet active&lt;br /&gt;
   Watchdog alarm enabled&lt;br /&gt;
   Update(-1)  -- runs until shutdown&lt;br /&gt;
&lt;br /&gt;
Update() loop runs once per frame:&lt;br /&gt;
&lt;br /&gt;
Per frame (every frame unless noted):&lt;br /&gt;
# CheckTerrainUpdates() -- every 4 frames&lt;br /&gt;
# UpdateTerrain() -- every m_update_terrain frames (default 1000)&lt;br /&gt;
# UpdatePreparePhysics() -- physics pre-step&lt;br /&gt;
# SendCoarseLocations() -- every 5 frames, async via thread pool&lt;br /&gt;
# UpdatePhysics(FrameTime) -- main physics step, returns physicsFPS&lt;br /&gt;
# CheckAtTargets() -- check llMoveToTarget / llRotLookAt&lt;br /&gt;
# UpdateObjectGroups() -- send queued object updates to clients&lt;br /&gt;
# UpdatePresences() -- send presence updates to clients&lt;br /&gt;
# CleanTempObjects() -- every 180 frames, async&lt;br /&gt;
# UpdateEvents() -- fires EventManager.OnFrame&lt;br /&gt;
# UpdateStorageBackup() -- every 200 frames, async&lt;br /&gt;
# Frame 20: enable logins, inform neighbours region is up, set Ready=true, GC compact&lt;br /&gt;
&lt;br /&gt;
Frame timing: FrameTime defaults to 0.0908s (~11fps). Sleep is calculated to hit target frame time. Stats normalized to 55fps for viewer display.&lt;br /&gt;
&lt;br /&gt;
Backup runs asynchronously every 200 frames. Objects are only persisted if they have been changed for at least MinimumTimeBeforePersistenceConsidered (default 60s) and no longer than MaximumTimeBeforePersistenceConsidered (default 600s).&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Startup Sequence (called from OpenSimBase.CreateRegion) ==&lt;br /&gt;
&lt;br /&gt;
After construction:&lt;br /&gt;
&lt;br /&gt;
# scene.SetModuleInterfaces() -- wires up module references from loaded region modules&lt;br /&gt;
# loadAllLandObjectsFromStorage() -- loads parcels from region database&lt;br /&gt;
# LoadPrimsFromStorage() -- loads all objects, calls AddRestoredSceneObject() for each&lt;br /&gt;
# RegisterRegionWithGrid() -- calls GridService.RegisterRegion(), throws on failure&lt;br /&gt;
# CreateScriptInstances() -- starts script engine for all loaded objects&lt;br /&gt;
# scene.Start() -- starts Heartbeat thread&lt;br /&gt;
&lt;br /&gt;
AllModulesLoaded() is called after all modules are loaded. Pushes simulator feature data to ISimulatorFeaturesModule (FPS, prim limits, grid info, search URL, etc).&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Region Crossing and Teleport ==&lt;br /&gt;
&lt;br /&gt;
All teleport and crossing logic is delegated to EntityTransferModule:&lt;br /&gt;
&lt;br /&gt;
 RequestTeleportLocation()  →  EntityTransferModule.Teleport()&lt;br /&gt;
 CrossAgentToNewRegion()    →  EntityTransferModule.Cross()&lt;br /&gt;
 TeleportClientHome()       →  EntityTransferModule.TeleportHome()&lt;br /&gt;
&lt;br /&gt;
Incoming objects and attachments from crossings:&lt;br /&gt;
&lt;br /&gt;
 IncomingCreateObject()     →  EntityTransferModule.HandleIncomingSceneObject()&lt;br /&gt;
 IncomingAttechments()      →  EntityTransferModule.HandleIncomingAttachments()&lt;br /&gt;
&lt;br /&gt;
Note: IncomingAttechments() -- the typo is in the source. See WTF file.&lt;br /&gt;
&lt;br /&gt;
OtherRegionUp() is called when a neighbouring region comes online. If within border distance, enables child agents in that region for all current root avatars via EntityTransferModule.EnableChildAgent().&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Avatar Connection (NewUserConnection) ==&lt;br /&gt;
&lt;br /&gt;
Called by the login service or another simulator to initiate a connection. Not triggered by the viewer directly.&lt;br /&gt;
&lt;br /&gt;
# Checks logins enabled&lt;br /&gt;
# Checks viewer allow/deny lists&lt;br /&gt;
# Handles existing ScenePresence (zombie root agents, race conditions during teleport)&lt;br /&gt;
# Clamps start position within region bounds&lt;br /&gt;
# CheckLandPositionAccess() -- checks telehub, parcel access, agent limit&lt;br /&gt;
# VerifyUserPresence() -- checks PresenceService for active session&lt;br /&gt;
# AuthorizeUser() -- checks estate ban, public access, access list, group membership&lt;br /&gt;
# Sets up CAPS via CapsModule&lt;br /&gt;
# ActivateCaps()&lt;br /&gt;
&lt;br /&gt;
Connection is activated later when the viewer sends UseCircuitCodePacket UDP packet.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Avatar Removal (RemoveClient) ==&lt;br /&gt;
&lt;br /&gt;
# Sends shutdown notice to child agents if root&lt;br /&gt;
# Avatar stands up if seated&lt;br /&gt;
# Closes child agent connections on neighbouring regions (async)&lt;br /&gt;
# Triggers ClientClosed and OnRemovePresence events&lt;br /&gt;
# De-rezzes attachments (root only)&lt;br /&gt;
# Sends KillObject to all clients&lt;br /&gt;
# Removes agent transactions&lt;br /&gt;
# Removes circuit, scene presence, client manager entry, CAPS&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Shutdown (Close) ==&lt;br /&gt;
&lt;br /&gt;
# Deregisters from GridService&lt;br /&gt;
# Kicks all root avatars with shutdown message&lt;br /&gt;
# Sets m_shuttingDown = true&lt;br /&gt;
# Sleeps 500ms to let kick messages reach clients&lt;br /&gt;
# Closes all agents&lt;br /&gt;
# Triggers SceneShuttingDown event&lt;br /&gt;
# Backup(true) -- force persist all pending changes&lt;br /&gt;
# Closes SceneGraph&lt;br /&gt;
# Disposes PhysicsScene last (scripts may reference physics during shutdown)&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Object Management ==&lt;br /&gt;
&lt;br /&gt;
Key methods:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Method !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| AddNewPrim() || Creates a new prim via raycast. Checks permissions. Uses entity creator registry if available, else creates SceneObjectGroup directly. Applies user default permissions from AgentPreferencesService.&lt;br /&gt;
|-&lt;br /&gt;
| AddRestoredSceneObject() || Adds object loaded from storage. Delegates to SceneGraph.&lt;br /&gt;
|-&lt;br /&gt;
| AddNewSceneObject() || Adds newly created object. Delegates to SceneGraph. Triggers ObjectAddedToScene event.&lt;br /&gt;
|-&lt;br /&gt;
| DeleteSceneObject() || Removes scripts, keyframe motion, email listeners, physics actors. Unlinks from scene. Triggers ObjectBeingRemovedFromScene.&lt;br /&gt;
|-&lt;br /&gt;
| UnlinkSceneObject() || Removes record from scene without destroying. On hard delete, removes from database.&lt;br /&gt;
|-&lt;br /&gt;
| IncomingCreateObject() || Handles object arriving from region crossing. Delegates to EntityTransferModule.&lt;br /&gt;
|-&lt;br /&gt;
| ForceSceneObjectBackup() || Synchronous backup of a single object. Used for deletes and link/unlink.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Client Event Subscriptions ==&lt;br /&gt;
&lt;br /&gt;
SubscribeToClientEvents() wires all viewer protocol events to scene handlers:&lt;br /&gt;
&lt;br /&gt;
* Terrain events (currently empty)&lt;br /&gt;
* Prim events: position, rotation, scale, shape, texture, name, material, link/unlink, duplicate, permissions, grab, spin, undo/redo&lt;br /&gt;
* Prim rez events: OnAddPrim → AddNewPrim(), OnRezObject → RezObject()&lt;br /&gt;
* Inventory events: folder and item CRUD, task inventory, rez script&lt;br /&gt;
* Teleport events: OnTeleportLocationRequest → RequestTeleportLocation()&lt;br /&gt;
* Script events: reset, get/set running&lt;br /&gt;
* Parcel events: return objects, set clean time, buy&lt;br /&gt;
* Grid events: money transfer&lt;br /&gt;
* Network events: stats update, viewer effect&lt;br /&gt;
&lt;br /&gt;
Note: UnSubscribeToClientEvents() is defined but marked FIXME -- not called anywhere. See WTF file.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Health Monitoring ==&lt;br /&gt;
&lt;br /&gt;
GetHealth() returns an integer 1-5:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Value !! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| 0 || Starting up&lt;br /&gt;
|-&lt;br /&gt;
| 1 || HTTP alive but heartbeat stopped -- possible lockup&lt;br /&gt;
|-&lt;br /&gt;
| 2 || Heartbeat running (frame tick &amp;lt; 4s ago)&lt;br /&gt;
|-&lt;br /&gt;
| 3 || One packet thread running&lt;br /&gt;
|-&lt;br /&gt;
| 4 || Both packet threads running&lt;br /&gt;
|-&lt;br /&gt;
| 5 || New user logged in within last 4 minutes&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
TimerWatchdog runs every second. Pushes health and root agent count to etcd if the IEtcdModule is present.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Persistence ==&lt;br /&gt;
&lt;br /&gt;
Objects are persisted via EventManager.OnBackup → SimulationDataService. Objects qualify for persistence if:&lt;br /&gt;
&lt;br /&gt;
* HasGroupChanged = true&lt;br /&gt;
* Time since last change &amp;gt; MinimumTimeBeforePersistenceConsidered (default 60s)&lt;br /&gt;
* Time since last change &amp;lt; MaximumTimeBeforePersistenceConsidered (default 600s) OR forced=true&lt;br /&gt;
&lt;br /&gt;
Auto-return queued in m_returns dictionary. Return messages sent via IMessageTransferModule on next backup cycle.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Notable Details ==&lt;br /&gt;
&lt;br /&gt;
* MegaRegions (CombineContiguousRegions) are explicitly rejected on startup with a fatal error&lt;br /&gt;
* The restart console command is registered but disabled -- marked unreliable in source&lt;br /&gt;
* IncomingAttechments() has a typo -- see WTF file for both file locations&lt;br /&gt;
* GOTO is used in AuthorizeUser() for group access checks -- commented in source as &amp;quot;some say GOTO is ugly&amp;quot;&lt;br /&gt;
* Heartbeat restart limit: if heartbeat thread dies and restarts more than 10 times, Environment.Exit(1)&lt;br /&gt;
* GC.Collect() is called explicitly at frame 20 and on map tile regeneration&lt;br /&gt;
* etcd integration is optional -- IEtcdModule only -- used for external health monitoring&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== See Also ==&lt;br /&gt;
&lt;br /&gt;
* [[OpenSimulator Internals/Code Map]]&lt;br /&gt;
* [[OpenSimulator Internals/Code Map/OpenSim]]&lt;br /&gt;
* [[OpenSimulator Internals/Code Map/Shared]]&lt;br /&gt;
* [[OpenSimulator Internals/Architecture Overview]]&lt;br /&gt;
* [[OpenSimulator Internals/Connector Architecture]]&lt;/div&gt;</summary>
		<author><name>Jwbshaw</name></author>
	</entry>
	<entry>
		<id>http://osimdev.org/wiki/index.php?title=OpenSimulator_Internals/Walkthroughs&amp;diff=97</id>
		<title>OpenSimulator Internals/Walkthroughs</title>
		<link rel="alternate" type="text/html" href="http://osimdev.org/wiki/index.php?title=OpenSimulator_Internals/Walkthroughs&amp;diff=97"/>
		<updated>2026-07-07T13:27:55Z</updated>

		<summary type="html">&lt;p&gt;Jwbshaw: update&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= OpenSimulator Internals/Walkthroughs =&lt;br /&gt;
&lt;br /&gt;
== Overview ==&lt;br /&gt;
Each walkthrough traces a single user-facing action through code, connectors, and database writes. Where the Code Map and Databases pages describe components in isolation, these pages follow one operation end to end.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
* [[OpenSimulator Internals/Walkthroughs/Bring Up Grid]]&lt;br /&gt;
* [[OpenSimulator Internals/Walkthroughs/Bring Up Region]]&lt;br /&gt;
* [[OpenSimulator Internals/Walkthroughs/Avatar Rez In Region]]&lt;br /&gt;
* [[OpenSimulator Internals/Walkthroughs/Avatar Change Outfit]]&lt;br /&gt;
* [[OpenSimulator Internals/Walkthroughs/Avatar Logs Out]]&lt;br /&gt;
* [[OpenSimulator Internals/Walkthroughs/Avatar Transfer Between Regions]]&lt;br /&gt;
* [[OpenSimulator Internals/Walkthroughs/Avatar Goes HG]]&lt;br /&gt;
* [[OpenSimulator Internals/Walkthroughs/Avatar Rezzes Box]]&lt;br /&gt;
* [[OpenSimulator Internals/Walkthroughs/Avatar Acquires Inventory]]&lt;br /&gt;
* [[OpenSimulator Internals/Walkthroughs/Avatar Rezzes Inventory]]&lt;br /&gt;
* [[OpenSimulator Internals/Walkthroughs/Avatar Derezzes Object]]&lt;br /&gt;
* [[OpenSimulator Internals/Walkthroughs/Avatar Removes From Inventory]]&lt;br /&gt;
* [[OpenSimulator Internals/Walkthroughs/Garbage Collection]] (stub)&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== See Also ==&lt;br /&gt;
&lt;br /&gt;
* [[OpenSimulator Internals/Code Map]]&lt;br /&gt;
* [[OpenSimulator Internals/Databases]]&lt;br /&gt;
* [[OpenSimulator Internals/Architecture Overview]]&lt;/div&gt;</summary>
		<author><name>Jwbshaw</name></author>
	</entry>
	<entry>
		<id>http://osimdev.org/wiki/index.php?title=OpenSimulator_Internals/Connector_Architecture&amp;diff=96</id>
		<title>OpenSimulator Internals/Connector Architecture</title>
		<link rel="alternate" type="text/html" href="http://osimdev.org/wiki/index.php?title=OpenSimulator_Internals/Connector_Architecture&amp;diff=96"/>
		<updated>2026-07-07T13:23:00Z</updated>

		<summary type="html">&lt;p&gt;Jwbshaw: update&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= OpenSimulator Internals/Connector Architecture =&lt;br /&gt;
&lt;br /&gt;
== Overview ==&lt;br /&gt;
&lt;br /&gt;
Connectors are the HTTP client layer that sits between region simulators and ROBUST grid services. Each connector implements a service interface (e.g. IAssetService, IPresenceService) using HTTP calls to the corresponding ROBUST handler.&lt;br /&gt;
&lt;br /&gt;
The same interface may be implemented by:&lt;br /&gt;
* A local connector -- calls the service directly in-process (standalone mode or co-located services).&lt;br /&gt;
* A remote connector -- makes HTTP calls to a ROBUST server.&lt;br /&gt;
* An HG connector -- wraps the remote connector with hypergrid-specific logic.&lt;br /&gt;
&lt;br /&gt;
Region code calls only the interface. Which implementation is loaded depends on configuration ([Architecture] section of the ini files).&lt;br /&gt;
&lt;br /&gt;
See [[OpenSimulator Internals/ROBUST Services]] for the server-side service implementations.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Connector Pattern ==&lt;br /&gt;
&lt;br /&gt;
All remote connectors follow the same pattern:&lt;br /&gt;
&lt;br /&gt;
# Constructor receives IConfigSource and reads the service URL from config.&lt;br /&gt;
# Each method serialises parameters to a REST or XMLRPC request.&lt;br /&gt;
# Sends HTTP POST/GET/DELETE to the ROBUST handler endpoint.&lt;br /&gt;
# Deserialises the response and returns the result.&lt;br /&gt;
&lt;br /&gt;
The HTTP client layer is WebUtil (OpenSim/Framework/WebUtil.cs), which handles serialisation, connection pooling, and error logging.&lt;br /&gt;
&lt;br /&gt;
See [[OpenSimulator Internals/Connector Architecture/Asset Connector]] for a fully worked example of the pattern including both client and server-side handler code.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Individual Connector Pages ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Connector !! Service Interface !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| [[OpenSimulator Internals/Connector Architecture/Asset Connector]] || IAssetService || Includes server-side handler detail. HG variant wraps with foreign asset server logic.&lt;br /&gt;
|-&lt;br /&gt;
| [[OpenSimulator Internals/Connector Architecture/GridUser Connector]] || IGridUserService || Tracks last position, login/logout timestamps, home region.&lt;br /&gt;
|-&lt;br /&gt;
| [[OpenSimulator Internals/Connector Architecture/Presence Connector]] || IPresenceService || Online status, session tracking, region assignment.&lt;br /&gt;
|-&lt;br /&gt;
| [[OpenSimulator Internals/Connector Architecture/UserAccount Connector]] || IUserAccountService || User account CRUD. Known bug: CreateUser() sends first name as email value.&lt;br /&gt;
|-&lt;br /&gt;
| [[OpenSimulator Internals/Connector Architecture/Inventory Connector]] || IInventoryService || XInventory protocol. UpdateFolder() URL-encodes Name; AddFolder() does not.&lt;br /&gt;
|-&lt;br /&gt;
| [[OpenSimulator Internals/Connector Architecture/Authentication Connector]] || IAuthenticationService || Password and token authentication, impersonation mechanism.&lt;br /&gt;
|-&lt;br /&gt;
| [[OpenSimulator Internals/Connector Architecture/Avatar Connector]] || IAvatarService || Appearance storage. ResetAvatar() log erroneously says &amp;quot;SetItems reply&amp;quot;.&lt;br /&gt;
|-&lt;br /&gt;
| [[OpenSimulator Internals/Connector Architecture/Friends Connector]] || IFriendsService || Friend list, online notifications.&lt;br /&gt;
|-&lt;br /&gt;
| [[OpenSimulator Internals/Connector Architecture/Grid Connector]] || IGridService || Region registration, lookup, neighbour queries.&lt;br /&gt;
|-&lt;br /&gt;
| [[OpenSimulator Internals/Connector Architecture/Simulation Connector]] || ISimulationService || Inter-simulator agent and object transfer. QueryAccess, CreateAgent, UpdateAgent, CloseAgent, CreateObject.&lt;br /&gt;
|-&lt;br /&gt;
| [[OpenSimulator Internals/Connector Architecture/UserAgent Connector]] || IUserAgentService || HG-only. Home region lookup, login to foreign grid, session verification.&lt;br /&gt;
|-&lt;br /&gt;
| [[OpenSimulator Internals/Connector Architecture/Gatekeeper Connector]] || IGatekeeperService || HG-only. Foreign grid entry point. GetHyperlinkRegion, LoginAgentToGrid.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== HG Connectors ==&lt;br /&gt;
&lt;br /&gt;
HyperGrid introduces additional connectors that wrap or replace the standard ones:&lt;br /&gt;
&lt;br /&gt;
* UserAgent Connector -- used by the source grid to contact the avatar&#039;s home grid UserAgent service during HG teleport.&lt;br /&gt;
* Gatekeeper Connector -- used to contact a foreign grid&#039;s Gatekeeper during HG destination resolution.&lt;br /&gt;
* HGAsset Connector -- used by HGInventoryAccessModule to fetch/push assets between grids (via HGAssetMapper).&lt;br /&gt;
&lt;br /&gt;
These are documented in the individual connector pages above and in:&lt;br /&gt;
* [[OpenSimulator Internals/Code Map/HGEntityTransferModule]]&lt;br /&gt;
* [[OpenSimulator Internals/Code Map/InventoryAccessModule]]&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Configuration ==&lt;br /&gt;
&lt;br /&gt;
Connectors are selected in the [Architecture] ini include files:&lt;br /&gt;
&lt;br /&gt;
* config-include/StandaloneCommon.ini -- standalone mode, services loaded in-process.&lt;br /&gt;
* config-include/GridCommon.ini -- grid mode, remote connectors used.&lt;br /&gt;
* config-include/HGCommon.ini -- hypergrid additions.&lt;br /&gt;
&lt;br /&gt;
The [ServiceList] section of Robust.ini selects which ROBUST handlers are loaded. The [Modules] section of OpenSim.ini selects which connectors the simulator loads.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== See Also ==&lt;br /&gt;
&lt;br /&gt;
* [[OpenSimulator Internals/Code Map/ROBUST]]&lt;br /&gt;
* [[OpenSimulator Internals/ROBUST Services]]&lt;br /&gt;
* [[OpenSimulator Internals/Reading the Code]]&lt;br /&gt;
* [[OpenSimulator Internals/Code Map]]&lt;/div&gt;</summary>
		<author><name>Jwbshaw</name></author>
	</entry>
	<entry>
		<id>http://osimdev.org/wiki/index.php?title=OpenSimulator_Internals/Code_Map/InventoryAccessModule&amp;diff=95</id>
		<title>OpenSimulator Internals/Code Map/InventoryAccessModule</title>
		<link rel="alternate" type="text/html" href="http://osimdev.org/wiki/index.php?title=OpenSimulator_Internals/Code_Map/InventoryAccessModule&amp;diff=95"/>
		<updated>2026-07-07T13:21:52Z</updated>

		<summary type="html">&lt;p&gt;Jwbshaw: first&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= OpenSimulator Internals/Code Map/InventoryAccessModule =&lt;br /&gt;
&lt;br /&gt;
== Overview ==&lt;br /&gt;
&lt;br /&gt;
 OpenSim/Region/CoreModules/Framework/InventoryAccess/BasicInventoryAccessModule.cs&lt;br /&gt;
 OpenSim/Region/CoreModules/Framework/InventoryAccess/HGInventoryAccessModule.cs&lt;br /&gt;
&lt;br /&gt;
Two modules, one extends the other. BasicInventoryAccessModule handles all local inventory operations. HGInventoryAccessModule extends it for HyperGrid asset mirroring and suitcase management.&lt;br /&gt;
&lt;br /&gt;
Registered as IInventoryAccessModule. Selected via [Modules] InventoryAccessModule = BasicInventoryAccessModule or HGInventoryAccessModule.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== BasicInventoryAccessModule ==&lt;br /&gt;
&lt;br /&gt;
=== Configuration ===&lt;br /&gt;
&lt;br /&gt;
 [Inventory] section&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Key !! Default !! Purpose&lt;br /&gt;
|-&lt;br /&gt;
| CoalesceMultipleObjectsToInventory || true || Group multiple selected objects into one coalesced inventory item&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Event Wiring ===&lt;br /&gt;
&lt;br /&gt;
OnNewClient() hooks per client:&lt;br /&gt;
* OnCreateNewInventoryItem → CreateNewInventoryItem()&lt;br /&gt;
&lt;br /&gt;
=== CreateNewInventoryItem() ===&lt;br /&gt;
&lt;br /&gt;
Called when avatar creates a new item directly in inventory (new script, notecard, landmark, etc.).&lt;br /&gt;
&lt;br /&gt;
# Checks CanCreateUserInventory permission.&lt;br /&gt;
# Resolves target folder by ID, or by type if folder not found.&lt;br /&gt;
# If transactionID set (asset upload in progress): delegates to IAgentAssetTransactions.HandleItemCreationFromTransaction().&lt;br /&gt;
# Otherwise creates inline based on asset type:&lt;br /&gt;
#* Landmark: generates landmark asset data (region_id, local_pos, region_handle), stores asset, creates inventory item.&lt;br /&gt;
#* LSLText: uses Constants.DefaultScriptID as asset.&lt;br /&gt;
#* Notecard: uses Constants.EmptyNotecardID.&lt;br /&gt;
#* Settings/Material: uses environment/material defaults.&lt;br /&gt;
#* Clothing/Bodypart: sets flags = subType.&lt;br /&gt;
# Calls Scene.CreateNewInventoryItem() -- writes to inventoryitems table via InventoryService.&lt;br /&gt;
&lt;br /&gt;
; DB writes:&lt;br /&gt;
* assets -- INSERT: new asset (landmark, notecard, etc.)&lt;br /&gt;
* inventoryitems -- INSERT: new inventory item&lt;br /&gt;
&lt;br /&gt;
=== CopyToInventory() ===&lt;br /&gt;
&lt;br /&gt;
Main path for taking objects from world to inventory (Take, TakeCopy, Delete, Return).&lt;br /&gt;
&lt;br /&gt;
# Groups SOGs by owner (for coalesced objects, only same-owner SOGs merge).&lt;br /&gt;
# For each bundle: calls CopyBundleToInventory().&lt;br /&gt;
&lt;br /&gt;
CopyBundleToInventory():&lt;br /&gt;
# Suspends keyframe motion on all SOGs.&lt;br /&gt;
# Records and stores positions/rotations (attachment stored pos used for attachments).&lt;br /&gt;
# Applies NextOwnerMask cleanup.&lt;br /&gt;
# Serialises: single SOG → SceneObjectSerializer.ToOriginalXmlFormat(); multiple → CoalescedSceneObjectsSerializer.ToXml().&lt;br /&gt;
# Restores positions.&lt;br /&gt;
# Calls CreateItemForObject() -- determines destination folder and creates InventoryItemBase shell.&lt;br /&gt;
# Calls AddPermissions() -- computes effective permissions from SOG current+folded perms; applies NextOwner if ownership changes.&lt;br /&gt;
# Creates asset: CreateAsset() → UUID.Random(), stores via AssetService.Store().&lt;br /&gt;
# If SaveToExistingUserInventoryItem: InventoryService.UpdateItem().&lt;br /&gt;
# Otherwise: Scene.AddInventoryItem() → InventoryService.AddItem(). Sends SendInventoryItemCreateUpdate() to client or owner&#039;s client.&lt;br /&gt;
&lt;br /&gt;
; DB writes:&lt;br /&gt;
* assets -- INSERT: serialised object XML&lt;br /&gt;
* inventoryitems -- INSERT or UPDATE&lt;br /&gt;
&lt;br /&gt;
=== CreateItemForObject() ===&lt;br /&gt;
&lt;br /&gt;
Determines destination folder and owner:&lt;br /&gt;
&lt;br /&gt;
* Take / TakeCopy: remoteClient&#039;s agent ID, Object folder (or original folder if owner taking back own item).&lt;br /&gt;
* Delete (own item): Trash folder.&lt;br /&gt;
* Delete (other&#039;s item) / Return: Lost and Found folder of object owner.&lt;br /&gt;
* Group-owned: Last owner&#039;s inventory.&lt;br /&gt;
&lt;br /&gt;
=== AddPermissions() ===&lt;br /&gt;
&lt;br /&gt;
* If new owner (remoteClient != object owner) and PropagatePermissions: applies NextOwnerMask, sets ObjectSlamPerm flag.&lt;br /&gt;
* If same owner: copies current perms preserving folded bits.&lt;br /&gt;
&lt;br /&gt;
=== RezObject() ===&lt;br /&gt;
&lt;br /&gt;
Rezzes an inventory item into the scene.&lt;br /&gt;
&lt;br /&gt;
# Gets InventoryItemBase from InventoryService.&lt;br /&gt;
# Gets asset from AssetService.&lt;br /&gt;
# Calls Scene.GetObjectsToRez() -- deserialises XML into List&amp;lt;SceneObjectGroup&amp;gt;.&lt;br /&gt;
# Calls Scene.GetNewRezLocation() -- raycasts to find rez position.&lt;br /&gt;
# Calls DoPreRezWhenFromItem():&lt;br /&gt;
#* Checks CanRezObject permission for each SOG.&lt;br /&gt;
#* Sets name/description from inventory item.&lt;br /&gt;
#* Applies ownership change and permission slam if new owner or Slam flag set.&lt;br /&gt;
#* Calls ApplyNextOwnerPermissions() if ownership changed.&lt;br /&gt;
#* Sets FromUserInventoryItemID if item is copyable.&lt;br /&gt;
# For each SOG: Scene.AddNewSceneObject(), CreateScriptInstances(), ResumeScripts().&lt;br /&gt;
# Calls DoPostRezWhenFromItem():&lt;br /&gt;
#* If item is no-copy: InventoryService.DeleteItems() -- removes item from inventory.&lt;br /&gt;
&lt;br /&gt;
; DB reads:&lt;br /&gt;
* inventoryitems -- SELECT by item UUID&lt;br /&gt;
* assets -- SELECT by asset UUID&lt;br /&gt;
&lt;br /&gt;
; DB writes (conditional):&lt;br /&gt;
* inventoryitems -- DELETE: if no-copy item consumed on rez&lt;br /&gt;
&lt;br /&gt;
=== CapsUpdateInventoryItemAsset() ===&lt;br /&gt;
&lt;br /&gt;
Called via capability when avatar edits a notecard, script, gesture, etc. in-world.&lt;br /&gt;
&lt;br /&gt;
# Gets item, checks ownership and permissions.&lt;br /&gt;
# Creates new asset from uploaded data.&lt;br /&gt;
# Calls AssetService.Store() + InventoryService.UpdateItem().&lt;br /&gt;
# Returns new asset UUID.&lt;br /&gt;
&lt;br /&gt;
; DB writes:&lt;br /&gt;
* assets -- INSERT: updated asset&lt;br /&gt;
* inventoryitems -- UPDATE: new assetID&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== HGInventoryAccessModule ==&lt;br /&gt;
&lt;br /&gt;
Extends BasicInventoryAccessModule. Active when HyperGrid is enabled.&lt;br /&gt;
&lt;br /&gt;
=== Additional Configuration ===&lt;br /&gt;
&lt;br /&gt;
 [HGInventoryAccessModule] section&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Key !! Default !! Purpose&lt;br /&gt;
|-&lt;br /&gt;
| OutboundPermission || true || Allow assets to be posted to foreign user&#039;s asset server&lt;br /&gt;
|-&lt;br /&gt;
| RestrictInventoryAccessAbroad || true || Hide non-suitcase inventory when going HG&lt;br /&gt;
|-&lt;br /&gt;
| CheckSeparateAssets || false || Support grids where world and inventory use different asset servers&lt;br /&gt;
|-&lt;br /&gt;
| RegionHGAssetServerURI || (empty) || Local asset server URL when CheckSeparateAssets=true&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== HGAssetMapper ===&lt;br /&gt;
&lt;br /&gt;
Static singleton. Handles Get() and Post() -- HTTP calls to foreign asset servers to fetch or push assets.&lt;br /&gt;
&lt;br /&gt;
* Get(assetID, agentID, foreignAssetServerURL): fetches asset from foreign server if not in local cache.&lt;br /&gt;
* Post(assetID, agentID, foreignAssetServerURL): pushes local asset to foreign server (subject to OutboundPermission).&lt;br /&gt;
&lt;br /&gt;
=== IsForeignUser() ===&lt;br /&gt;
&lt;br /&gt;
Returns true if the user&#039;s asset server differs from local. Gets AssetServerURI from AgentCircuitData.ServiceURLs or UserManagementModule. If CheckSeparateAssets=true, compares against m_LocalAssetsURL.&lt;br /&gt;
&lt;br /&gt;
=== RezObject() Override ===&lt;br /&gt;
&lt;br /&gt;
Before calling base.RezObject():&lt;br /&gt;
* If IsForeignUser: calls m_assMapper.Get(item.AssetID, agentID, foreignAssetServer) -- fetches object asset from foreign grid if not cached locally.&lt;br /&gt;
&lt;br /&gt;
=== ExportAsset() Override ===&lt;br /&gt;
&lt;br /&gt;
Called from CopyBundleToInventory() after asset is stored:&lt;br /&gt;
* If IsForeignUser and OutboundPermission: calls m_assMapper.Post() -- pushes newly created asset to foreign user&#039;s asset server.&lt;br /&gt;
&lt;br /&gt;
=== Suitcase Management ===&lt;br /&gt;
&lt;br /&gt;
On TeleportStart (HG departure, local user):&lt;br /&gt;
* ProcessInventoryForHypergriding(): fetches root folder content, renames all non-Suitcase folders to &amp;quot;FolderName (Unavailable)&amp;quot;, sends BulkUpdateInventory to client. Avatar sees only My Suitcase contents while abroad.&lt;br /&gt;
&lt;br /&gt;
On TeleportFail (HG departure failed, local user):&lt;br /&gt;
* ProcessInventoryForComingHome(): fetches root folder, sends full inventory back without &amp;quot;(Unavailable)&amp;quot; suffix.&lt;br /&gt;
&lt;br /&gt;
On CompleteMovement (HG arrival, local user returning home):&lt;br /&gt;
* ProcessInventoryForComingHome(): same as TeleportFail -- restores full inventory view.&lt;br /&gt;
&lt;br /&gt;
ProcessInventoryForArriving() and ProcessInventoryForLeaving() are currently no-ops.&lt;br /&gt;
&lt;br /&gt;
=== GenerateLandmark() Override ===&lt;br /&gt;
&lt;br /&gt;
Appends &amp;quot;gatekeeper {URL}&amp;quot; line to landmark data so HG landmarks carry grid identity.&lt;br /&gt;
&lt;br /&gt;
=== Permissions ===&lt;br /&gt;
&lt;br /&gt;
CanTakeObject(): if OutboundPermission=false and user is foreign, only allow taking own objects.&lt;br /&gt;
OnTransferUserInventory(): if OutboundPermission=false, block inventory transfer to foreign users.&lt;br /&gt;
&lt;br /&gt;
=== PostInventoryAsset() ===&lt;br /&gt;
&lt;br /&gt;
Hooked to OnNewInventoryItemUploadComplete event. After any inventory asset upload:&lt;br /&gt;
* If IsForeignUser and OutboundPermission (or asset is a landmark): posts asset to foreign user&#039;s asset server.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== See Also ==&lt;br /&gt;
&lt;br /&gt;
* [[OpenSimulator Internals/Code Map/Scene]]&lt;br /&gt;
* [[OpenSimulator Internals/Code Map/AttachmentsModule]]&lt;br /&gt;
* [[OpenSimulator Internals/Walkthroughs/Avatar Acquires Inventory]]&lt;br /&gt;
* [[OpenSimulator Internals/Walkthroughs/Avatar Rezzes Inventory]]&lt;br /&gt;
* [[OpenSimulator Internals/Walkthroughs/Avatar Removes From Inventory]]&lt;br /&gt;
* [[OpenSimulator Internals/Walkthroughs/Avatar Rezzes Box]]&lt;br /&gt;
* [[OpenSimulator Internals/Walkthroughs/Avatar Derezzes Object]]&lt;/div&gt;</summary>
		<author><name>Jwbshaw</name></author>
	</entry>
	<entry>
		<id>http://osimdev.org/wiki/index.php?title=OpenSimulator_Internals/Code_Map/HGEntityTransferModule&amp;diff=94</id>
		<title>OpenSimulator Internals/Code Map/HGEntityTransferModule</title>
		<link rel="alternate" type="text/html" href="http://osimdev.org/wiki/index.php?title=OpenSimulator_Internals/Code_Map/HGEntityTransferModule&amp;diff=94"/>
		<updated>2026-07-07T13:20:58Z</updated>

		<summary type="html">&lt;p&gt;Jwbshaw: first&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= OpenSimulator Internals/Code Map/HGEntityTransferModule =&lt;br /&gt;
&lt;br /&gt;
== Overview ==&lt;br /&gt;
&lt;br /&gt;
 OpenSim/Region/CoreModules/Framework/EntityTransfer/HGEntityTransferModule.cs&lt;br /&gt;
&lt;br /&gt;
Extends EntityTransferModule. Replaces it when HyperGrid is enabled ([Modules] EntityTransferModule = HGEntityTransferModule). Overrides the key virtual methods to handle cross-grid agent transfer, foreign user logout, appearance restriction, and incoming attachment asset fetching.&lt;br /&gt;
&lt;br /&gt;
Also registers as IUserAgentVerificationModule -- verifies HG client tokens on connection.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Configuration ==&lt;br /&gt;
&lt;br /&gt;
 [EntityTransfer] section&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Key !! Default !! Purpose&lt;br /&gt;
|-&lt;br /&gt;
| LevelHGTeleport || 0 || Minimum user level required to HG teleport (local users only)&lt;br /&gt;
|-&lt;br /&gt;
| RestrictAppearanceAbroad || false || If true, enforce exported appearance before HG TP&lt;br /&gt;
|-&lt;br /&gt;
| AccountForAppearance || (empty) || Comma-separated &amp;quot;First Last&amp;quot; account names whose appearance is the allowed export set&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== GetFinalDestination() Override ==&lt;br /&gt;
&lt;br /&gt;
Called during DoTeleportInternal() to resolve the true destination.&lt;br /&gt;
&lt;br /&gt;
# Calls GridService.GetRegionFlags() to check if the destination region has the Hyperlink flag.&lt;br /&gt;
# If Hyperlink: calls GatekeeperServiceConnector.GetHyperlinkRegion() -- HTTP request to the foreign grid&#039;s Gatekeeper service.&lt;br /&gt;
#* Gatekeeper returns the actual destination GridRegion on the foreign grid.&lt;br /&gt;
# If not Hyperlink: returns the region unchanged (same as base class).&lt;br /&gt;
&lt;br /&gt;
This is the step that resolves a local hyperlink stub into a real foreign region descriptor.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== NeedsClosing() Override ==&lt;br /&gt;
&lt;br /&gt;
Returns true (source agent should be fully closed after transfer) if:&lt;br /&gt;
* OutViewRange is true, OR&lt;br /&gt;
* The destination region has the Hyperlink flag or is unknown (flags == -1).&lt;br /&gt;
&lt;br /&gt;
HG teleports always close the source agent regardless of view distance.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== CreateAgent() Override ==&lt;br /&gt;
&lt;br /&gt;
Called during DoTeleportInternal() to create the agent at the destination.&lt;br /&gt;
&lt;br /&gt;
# Calls GridService.GetRegionFlags() to check if destination is a Hyperlink region.&lt;br /&gt;
# If Hyperlink (HG teleport):&lt;br /&gt;
#* Checks if local user has sufficient UserLevel (&amp;gt;= LevelHGTeleport). Refuses if not.&lt;br /&gt;
#* Reads HomeURI from agentCircuit.ServiceURLs.&lt;br /&gt;
#* Gets or creates a UserAgentServiceConnector for the home grid.&lt;br /&gt;
#* Calls UserAgentService.LoginAgentToGrid() -- HTTP POST to home grid&#039;s UserAgent service.&lt;br /&gt;
#*: Home grid&#039;s UserAgent service calls the foreign Gatekeeper to create the agent there.&lt;br /&gt;
#* Sets logout = true -- flags that this agent should be logged out of the source grid after transfer.&lt;br /&gt;
#* Fires TriggerTeleportStart on success.&lt;br /&gt;
# If not Hyperlink: calls base.CreateAgent() -- normal SimulationService.CreateAgent().&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== AgentHasMovedAway() Override ==&lt;br /&gt;
&lt;br /&gt;
Called after the agent has successfully moved to destination.&lt;br /&gt;
&lt;br /&gt;
# Calls base.AgentHasMovedAway() (currently a no-op in base).&lt;br /&gt;
# If logout == true (HG teleport):&lt;br /&gt;
#* Calls PresenceService.LogoutAgent() -- marks agent offline in source grid&#039;s presence table.&lt;br /&gt;
#* Calls GridUserService.LoggedOut() -- updates source grid&#039;s griduser table with last position.&lt;br /&gt;
&lt;br /&gt;
This is the HG-specific grid logout. The agent is now on the foreign grid and is no longer a presence on the source grid.&lt;br /&gt;
&lt;br /&gt;
; DB writes (source grid, HG teleport only):&lt;br /&gt;
* presence -- UPDATE: Online=0, session cleared&lt;br /&gt;
* griduser -- UPDATE: LastPosition, Logout timestamp&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== ValidateGenericConditions() Override ==&lt;br /&gt;
&lt;br /&gt;
Called before teleport proceeds. For HG teleports with RestrictAppearanceAbroad=true:&lt;br /&gt;
&lt;br /&gt;
# Checks if destination is a Hyperlink region.&lt;br /&gt;
# For local grid users going HG:&lt;br /&gt;
#* Checks each wearable slot against the exported appearance (ExportedAppearance property).&lt;br /&gt;
#* Checks each attachment against the exported attachment list.&lt;br /&gt;
#* Returns false (rejects teleport) if any item is not in the allowed set.&lt;br /&gt;
&lt;br /&gt;
ExportedAppearance: lazy-loaded on first access. Loads appearance for each account in AccountForAppearance from AvatarService, resolves attachment ItemIDs to AssetIDs via InventoryService.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== OnConnectionClosed() Override ==&lt;br /&gt;
&lt;br /&gt;
Called when viewer disconnects.&lt;br /&gt;
&lt;br /&gt;
For local grid users: calls IUserAgentService.LogoutAgent() -- notifies home UserAgent service.&lt;br /&gt;
&lt;br /&gt;
For foreign (HG) users:&lt;br /&gt;
# Gets HomeURI from AgentCircuitData.ServiceURLs.&lt;br /&gt;
# Creates UserAgentServiceConnector for the home grid.&lt;br /&gt;
# Calls security.LogoutAgent() -- HTTP POST to foreign home grid&#039;s UserAgent service.&lt;br /&gt;
# Calls base.OnConnectionClosed() -- handles abort-in-transit case.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== TeleportHome() Override ==&lt;br /&gt;
&lt;br /&gt;
For local grid users: delegates to base.TeleportHome() which uses GridUserService to find home region.&lt;br /&gt;
&lt;br /&gt;
For foreign (HG) users:&lt;br /&gt;
# Gets HomeURI from AgentCircuitData.ServiceURLs.&lt;br /&gt;
# Calls UserAgentService.GetHomeRegion() -- HTTP request to foreign home grid.&lt;br /&gt;
# Constructs a Gatekeeper GridRegion from the HomeURI.&lt;br /&gt;
# Calls DoTeleport() with ViaHome flag.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== HandleIncomingSceneObject() Override ==&lt;br /&gt;
&lt;br /&gt;
Called when an object crosses into this region from another.&lt;br /&gt;
&lt;br /&gt;
For foreign-user attachments arriving via HGLogin (ViaHGLogin flag set):&lt;br /&gt;
# Adds object to scene immediately.&lt;br /&gt;
# Queues an async job on m_incomingSceneObjectEngine (JobEngine, 30s timeout).&lt;br /&gt;
# Job: creates HGUuidGatherer with the foreign AssetServerURI from AgentCircuitData.&lt;br /&gt;
#* Gathers all referenced asset UUIDs from the SOG recursively.&lt;br /&gt;
#* Fetches each asset from the foreign grid&#039;s asset server.&lt;br /&gt;
#* 30-second timeout per gather/fetch step -- removes all jobs for that owner on timeout.&lt;br /&gt;
# After fetch: calls base.HandleIncomingSceneObject().&lt;br /&gt;
&lt;br /&gt;
For non-HGLogin foreign user attachments (already fetched by first local grid region): calls base directly.&lt;br /&gt;
&lt;br /&gt;
For local user attachments: calls base directly.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== HandleIncomingAttachments() Override ==&lt;br /&gt;
&lt;br /&gt;
Same pattern as HandleIncomingSceneObject() but for the attachment list transferred in AgentData during crossing/teleport.&lt;br /&gt;
&lt;br /&gt;
For foreign HGLogin users:&lt;br /&gt;
# Queues async job.&lt;br /&gt;
# HGUuidGatherer fetches all attachment assets from foreign AssetServerURI.&lt;br /&gt;
# On completion: calls base.HandleIncomingAttachments().&lt;br /&gt;
&lt;br /&gt;
Includes sp.IsDeleted check in fetch loop -- aborts if avatar departed during the fetch.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== VerifyClient() ==&lt;br /&gt;
&lt;br /&gt;
IUserAgentVerificationModule implementation. Called by Scene.CheckClient() for HG arrivals.&lt;br /&gt;
&lt;br /&gt;
# Gets HomeURI from AgentCircuitData.&lt;br /&gt;
# Creates UserAgentServiceConnector.&lt;br /&gt;
# Calls security.VerifyClient(SessionID, token) -- HTTP POST to foreign home grid.&lt;br /&gt;
# Returns true/false.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Incoming Attachment Processing ==&lt;br /&gt;
&lt;br /&gt;
m_incomingSceneObjectEngine: JobEngine with 30-second stall timeout. One engine per region. Processes HG attachment asset fetches serially per owner (CommonId = OwnerID).&lt;br /&gt;
&lt;br /&gt;
RemoveIncomingSceneObjectJobs(commonId): drains the queue and reinserts all jobs except those matching the given owner UUID. Used on timeout to cancel stuck fetches.&lt;br /&gt;
&lt;br /&gt;
Stat registered: &amp;quot;HGIncomingAttachmentsWaiting&amp;quot; -- pull stat showing queue depth.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== See Also ==&lt;br /&gt;
&lt;br /&gt;
* [[OpenSimulator Internals/Code Map/EntityTransferModule]]&lt;br /&gt;
* [[OpenSimulator Internals/Code Map/ROBUST/GatekeeperService]]&lt;br /&gt;
* [[OpenSimulator Internals/Code Map/ROBUST/UserAgentService]]&lt;br /&gt;
* [[OpenSimulator Internals/Connector Architecture/Gatekeeper Connector]]&lt;br /&gt;
* [[OpenSimulator Internals/Connector Architecture/UserAgent Connector]]&lt;br /&gt;
* [[OpenSimulator Internals/Walkthroughs/Avatar Goes HG]]&lt;/div&gt;</summary>
		<author><name>Jwbshaw</name></author>
	</entry>
	<entry>
		<id>http://osimdev.org/wiki/index.php?title=OpenSimulator_Internals/Code_Map/EntityTransferModule&amp;diff=93</id>
		<title>OpenSimulator Internals/Code Map/EntityTransferModule</title>
		<link rel="alternate" type="text/html" href="http://osimdev.org/wiki/index.php?title=OpenSimulator_Internals/Code_Map/EntityTransferModule&amp;diff=93"/>
		<updated>2026-07-07T13:19:54Z</updated>

		<summary type="html">&lt;p&gt;Jwbshaw: first&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= OpenSimulator Internals/Code Map/EntityTransferModule =&lt;br /&gt;
&lt;br /&gt;
== Overview ==&lt;br /&gt;
&lt;br /&gt;
 OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs&lt;br /&gt;
&lt;br /&gt;
INonSharedRegionModule. Handles all agent movement between regions: teleport (within region and to other regions), region crossing, child agent management, and object crossing. One instance per region.&lt;br /&gt;
&lt;br /&gt;
Registered as IEntityTransferModule. Extended by HGEntityTransferModule for HyperGrid.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Configuration ==&lt;br /&gt;
&lt;br /&gt;
 [EntityTransfer] section&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Key !! Default !! Purpose&lt;br /&gt;
|-&lt;br /&gt;
| wait_for_callback || true || Source region waits for destination to confirm arrival before closing agent&lt;br /&gt;
|-&lt;br /&gt;
| DisableInterRegionTeleportCancellation || false || If true, tells viewer to disable cancel button&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Event Wiring ==&lt;br /&gt;
&lt;br /&gt;
OnNewClient() hooks per client:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Event !! Handler&lt;br /&gt;
|-&lt;br /&gt;
| OnTeleportHomeRequest || TriggerTeleportHome()&lt;br /&gt;
|-&lt;br /&gt;
| OnTeleportLandmarkRequest || RequestTeleportLandmark()&lt;br /&gt;
|-&lt;br /&gt;
| OnTeleportCancel || OnClientCancelTeleport() (if cancellation enabled)&lt;br /&gt;
|-&lt;br /&gt;
| OnConnectionClosed || OnConnectionClosed()&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
OnConnectionClosed(): if client IsLoggingOut while in transit, updates transfer state to Aborting.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Transfer State Machine ==&lt;br /&gt;
&lt;br /&gt;
EntityTransferStateMachine tracks per-agent transfer state:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! State !! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| (none) || Not in transit&lt;br /&gt;
|-&lt;br /&gt;
| Transferring || Transfer initiated, past point of no clean abort&lt;br /&gt;
|-&lt;br /&gt;
| ReceivedAtDestination || Destination confirmed arrival&lt;br /&gt;
|-&lt;br /&gt;
| CleaningUp || Closing child agents and source agent&lt;br /&gt;
|-&lt;br /&gt;
| Cancelling || Client requested cancel&lt;br /&gt;
|-&lt;br /&gt;
| Aborting || Client disconnected during transfer&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
SetInTransit() / ResetFromTransit() bracket the full operation. UpdateInTransit() moves through states. Failed transitions are logged and abort the operation.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Teleport Entry Point ==&lt;br /&gt;
&lt;br /&gt;
 Teleport(ScenePresence sp, ulong regionHandle, Vector3 position, Vector3 lookAt, uint teleportFlags)&lt;br /&gt;
&lt;br /&gt;
# Checks permissions (CanTeleport). Adds Godlike flag if grid god.&lt;br /&gt;
# Calls SetInTransit() -- rejects if already in transit.&lt;br /&gt;
# If destination handle matches current region after offset check: calls TeleportAgentWithinRegion().&lt;br /&gt;
# Otherwise: calls TeleportAgentToDifferentRegion().&lt;br /&gt;
# ResetFromTransit() in finally block.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== TeleportAgentWithinRegion() ==&lt;br /&gt;
&lt;br /&gt;
Local teleport within the same region.&lt;br /&gt;
&lt;br /&gt;
# Validates position is within region bounds; substitutes emergency pos (128,128,128) if not.&lt;br /&gt;
# Raises Z to ground height + avatar half-height.&lt;br /&gt;
# Sends TeleportStart to viewer.&lt;br /&gt;
# Sends SendLocalTeleport to viewer.&lt;br /&gt;
# Sets sp.TeleportFlags, rotates avatar, zeros velocity.&lt;br /&gt;
# Calls sp.Teleport(position) -- moves physics actor.&lt;br /&gt;
# Fires CHANGED_TELEPORT script event on all attachment SOGs.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== TeleportAgentToDifferentRegion() ==&lt;br /&gt;
&lt;br /&gt;
# Calls GetTeleportDestinationRegion() -- GridService.GetRegionByPosition() accounting for varregion offsets.&lt;br /&gt;
# Calls GetFinalDestination() (HG hook -- returns same region for normal grid).&lt;br /&gt;
# Calls ValidateGenericConditions() (override point).&lt;br /&gt;
# Calls DoTeleportInternal().&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== DoTeleportInternal() ==&lt;br /&gt;
&lt;br /&gt;
Core cross-simulator teleport sequence.&lt;br /&gt;
&lt;br /&gt;
# DNS resolution: finalDestination.ExternalEndPoint.&lt;br /&gt;
# Calls SimulationService.QueryAccess() -- destination region confirms it will accept the agent. Returns reason string on refusal.&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.IsInTransit = true.&lt;br /&gt;
# Sends TeleportStart to viewer.&lt;br /&gt;
# Builds AgentCircuitData for the destination.&lt;br /&gt;
# Determines OutSideViewRange -- whether destination already has a child agent or needs a new one.&lt;br /&gt;
# Selects protocol version: V2 (&amp;gt;= 0.2) or V1 fallback.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== TransferAgent_V2() ==&lt;br /&gt;
&lt;br /&gt;
Current protocol path.&lt;br /&gt;
&lt;br /&gt;
# If OutSideViewRange: removes current region handle from ChildrenCapSeeds.&lt;br /&gt;
# Calls CreateAgent() -- SimulationService.CreateAgent() to destination. Fires TeleportStart event.&lt;br /&gt;
# Checks cancel/abort state.&lt;br /&gt;
# Sets sp.IsChildAgent = true.&lt;br /&gt;
# Sends TeleportFinishEvent to viewer immediately (V2 difference from V1: no prior EnableSimulator/EstablishAgentCommunication).&lt;br /&gt;
# Builds full AgentData via sp.CopyTo() including appearance, animations, attachments, script states.&lt;br /&gt;
# Sets SenderWantsToWaitForRoot = true in AgentData.&lt;br /&gt;
# Calls UpdateAgent() -- SimulationService.UpdateAgent() sends full agent state to destination. Blocks until destination&#039;s CompleteMovement() fires and returns.&lt;br /&gt;
# On UpdateAgent success: calls sp.HasMovedAway(), sp.MakeChildAgent(), CloseChildAgents().&lt;br /&gt;
# If NeedsClosing (OutSideViewRange): waits up to 15 seconds for sp.IsInTransit to clear, then calls m_scene.CloseAgent().&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== TransferAgent_V1() ==&lt;br /&gt;
&lt;br /&gt;
Legacy protocol path (destination protocol &amp;lt; 0.2).&lt;br /&gt;
&lt;br /&gt;
# Calls CreateAgent().&lt;br /&gt;
# If OutSideViewRange: sends EnableSimulator + EstablishAgentCommunication via event queue, then sleeps 200ms.&lt;br /&gt;
# Sends full AgentData via UpdateAgent().&lt;br /&gt;
# Sends TeleportFinishEvent.&lt;br /&gt;
# Waits for WaitForAgentArrivedAtDestination() callback -- blocks up to 10 seconds.&lt;br /&gt;
# On success: CloseChildAgents(), MakeChildAgent(), CloseAgent() after 2-second sleep (viewer compatibility).&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Region Crossing ==&lt;br /&gt;
&lt;br /&gt;
Cross(ScenePresence, isFlying):&lt;br /&gt;
* Fires async via WorkManager.RunInThreadPool.&lt;br /&gt;
* Calls CrossAsync() → CrossAgentToNewRegionAsync() → CrossAgentIntoNewRegionMain().&lt;br /&gt;
&lt;br /&gt;
CrossAgentIntoNewRegionMain():&lt;br /&gt;
# Calls sp.CopyTo(cAgent, isCrossUpdate=true) -- full agent state including cross flags.&lt;br /&gt;
# Sets position to projected crossing position.&lt;br /&gt;
# Calls SimulationService.UpdateAgent() -- sends state to destination. Destination&#039;s IncomingUpdateChildAgent() fires, sets m_originRegionID.&lt;br /&gt;
# On success: sets sp.IsChildAgent = true, sends CrossRegion event queue message to viewer.&lt;br /&gt;
# CloseChildAgents() for out-of-range neighbours.&lt;br /&gt;
# Calls sp.HasMovedAway(), sp.MakeChildAgent().&lt;br /&gt;
&lt;br /&gt;
CrossAsync() detects crossing by projecting position + velocity * 0.2s and calling GetDestination() → GridService.GetRegionByPosition().&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Child Agent Management ==&lt;br /&gt;
&lt;br /&gt;
EnableChildAgents(ScenePresence sp):&lt;br /&gt;
* Computes neighbours within RegionViewDistance via RegionsInSPView().&lt;br /&gt;
* For new neighbours: builds AgentCircuitData, calls CreateAgent() + EnableSimulator + EstablishAgentCommunication.&lt;br /&gt;
* For regions no longer in view: calls sp.CloseChildAgents().&lt;br /&gt;
* Updates KnownRegions and cap seeds.&lt;br /&gt;
* Sends AgentPosition updates to existing known neighbours.&lt;br /&gt;
* Neighbour list cached for 30 seconds.&lt;br /&gt;
&lt;br /&gt;
EnableChildAgent(sp, region): single-region version, used when a new neighbour comes online.&lt;br /&gt;
&lt;br /&gt;
CloseOldChildAgents(sp): called from SendInitialData() on login. Closes any child agents not in current view range.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Failure Handling ==&lt;br /&gt;
&lt;br /&gt;
Fail():&lt;br /&gt;
* Calls CleanupFailedInterRegionTeleport() -- sets IsChildAgent=false, ReInstantiateScripts(), calls SimulationService.CloseAgent() on destination.&lt;br /&gt;
* Sends TeleportFailed to viewer.&lt;br /&gt;
* Fires TriggerTeleportFail event.&lt;br /&gt;
&lt;br /&gt;
BannedRegionCache: ExpiringCacheOS keyed by region handle → Dictionary&amp;lt;UUID, expiry&amp;gt;. Regions that refuse QueryAccess are cached for 60 seconds to avoid hammering.&lt;br /&gt;
&lt;br /&gt;
NotFoundLocationCache: Caches region handle positions that returned null from GridService for 30 seconds.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Key Virtual Methods (HG Override Points) ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Method !! Purpose&lt;br /&gt;
|-&lt;br /&gt;
| GetFinalDestination() || Returns destination region (HG overrides to resolve HG address)&lt;br /&gt;
|-&lt;br /&gt;
| CreateAgent() || Calls SimulationService.CreateAgent() (HG overrides to set logout flag)&lt;br /&gt;
|-&lt;br /&gt;
| UpdateAgent() || Calls SimulationService.UpdateAgent()&lt;br /&gt;
|-&lt;br /&gt;
| AgentHasMovedAway() || Hook after agent departs (HG deletes attachments from scene)&lt;br /&gt;
|-&lt;br /&gt;
| NeedsClosing() || Whether to close source agent (HG uses different logic)&lt;br /&gt;
|-&lt;br /&gt;
| ValidateGenericConditions() || Additional pre-flight checks (base returns true)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Object Crossing ==&lt;br /&gt;
&lt;br /&gt;
CrossPrimGroupIntoNewRegion():&lt;br /&gt;
* Calls SimulationService.CreateObject() on destination.&lt;br /&gt;
* On success: calls scene.DeleteSceneObject() on source.&lt;br /&gt;
&lt;br /&gt;
GetObjectDestination(): projects object position into world coordinates, calls GridService.GetRegionByPosition().&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Statistics ==&lt;br /&gt;
&lt;br /&gt;
Four stats registered per region under &amp;quot;entitytransfer&amp;quot; category:&lt;br /&gt;
* InterRegionTeleportAttempts&lt;br /&gt;
* InterRegionTeleportAborts (simultaneous logout)&lt;br /&gt;
* InterRegionTeleportCancels (client cancel)&lt;br /&gt;
* InterRegionTeleportFailures (network/server problems)&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== See Also ==&lt;br /&gt;
&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 Logs Out]]&lt;br /&gt;
* [[OpenSimulator Internals/Walkthroughs/Avatar Transfer Between Regions]]&lt;br /&gt;
* [[OpenSimulator Internals/Walkthroughs/Avatar Goes HG]]&lt;/div&gt;</summary>
		<author><name>Jwbshaw</name></author>
	</entry>
	<entry>
		<id>http://osimdev.org/wiki/index.php?title=OpenSimulator_Internals/Code_Map/AttachmentsModule&amp;diff=92</id>
		<title>OpenSimulator Internals/Code Map/AttachmentsModule</title>
		<link rel="alternate" type="text/html" href="http://osimdev.org/wiki/index.php?title=OpenSimulator_Internals/Code_Map/AttachmentsModule&amp;diff=92"/>
		<updated>2026-07-07T13:19:05Z</updated>

		<summary type="html">&lt;p&gt;Jwbshaw: first&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= OpenSimulator Internals/Code Map/AttachmentsModule =&lt;br /&gt;
&lt;br /&gt;
== Overview ==&lt;br /&gt;
&lt;br /&gt;
 OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs&lt;br /&gt;
&lt;br /&gt;
INonSharedRegionModule. Handles all attachment operations: rezzing attachments on login, attaching/detaching objects, saving attachment state to inventory, and transferring attachments between regions. One instance per region.&lt;br /&gt;
&lt;br /&gt;
Registered as IAttachmentsModule. Can be disabled via [Attachments] Enabled=false.&lt;br /&gt;
&lt;br /&gt;
Requires IInventoryAccessModule -- disables itself if unavailable.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Configuration ==&lt;br /&gt;
&lt;br /&gt;
 [Attachments] section&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Key !! Default !! Purpose&lt;br /&gt;
|-&lt;br /&gt;
| Enabled || true || Enable/disable the module&lt;br /&gt;
|-&lt;br /&gt;
| WearReplacesAll || true || When attaching to a point, remove all existing attachments at that point&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Event Wiring ==&lt;br /&gt;
&lt;br /&gt;
SubscribeToClientEvents() hooks per client:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Event !! Handler&lt;br /&gt;
|-&lt;br /&gt;
| OnRezSingleAttachmentFromInv || Client_OnRezSingleAttachmentFromInv()&lt;br /&gt;
|-&lt;br /&gt;
| OnRezMultipleAttachmentsFromInv || Client_OnRezMultipleAttachmentsFromInv()&lt;br /&gt;
|-&lt;br /&gt;
| OnObjectAttach || Client_OnObjectAttach()&lt;br /&gt;
|-&lt;br /&gt;
| OnObjectDetach || Client_OnObjectDetach()&lt;br /&gt;
|-&lt;br /&gt;
| OnDetachAttachmentIntoInv || Client_OnDetachAttachmentIntoInv()&lt;br /&gt;
|-&lt;br /&gt;
| OnObjectDrop || Client_OnObjectDrop()&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Scene events:&lt;br /&gt;
* OnStartScript / OnStopScript -- sets HasGroupChanged on attachment SOGs when scripts start/stop.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== RezAttachments() ==&lt;br /&gt;
&lt;br /&gt;
Called from ScenePresence.CompleteMovement() on real login (IsRealLogin true). Not called for teleports or crossings -- those carry attachments in AgentData.&lt;br /&gt;
&lt;br /&gt;
# Returns immediately if sp.GetAttachmentsCount() &amp;gt; 0 (viewer already rezzed them).&lt;br /&gt;
# Fetches all attachment item UUIDs in a single batch: InventoryService.GetMultipleItems().&lt;br /&gt;
# For each attachment in sp.Appearance.GetAttachments():&lt;br /&gt;
#* Validates item exists and owner matches sp.UUID. If not: removes from appearance.&lt;br /&gt;
#* Calls RezSingleAttachmentFromInventoryInternal().&lt;br /&gt;
# For NPCs: uses AssetID directly, skips inventory item checks.&lt;br /&gt;
&lt;br /&gt;
; DB reads:&lt;br /&gt;
* inventoryitems -- SELECT batch by item UUID array&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== RezSingleAttachmentFromInventoryInternal() ==&lt;br /&gt;
&lt;br /&gt;
Core rez path for a single attachment.&lt;br /&gt;
&lt;br /&gt;
# Calls IInventoryAccessModule.RezObject() -- fetches asset, deserialises SOG, adds to scene.&lt;br /&gt;
# Calls AttachObjectInternal() -- attaches SOG to avatar.&lt;br /&gt;
# If doc (saved script state) provided: LoadScriptState() before attach.&lt;br /&gt;
# If attach fails: removes SOG from scene and returns null.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== AttachObjectInternal() ==&lt;br /&gt;
&lt;br /&gt;
Attaches a SOG already in the scene to an avatar.&lt;br /&gt;
&lt;br /&gt;
# Rejects if any avatars are sitting on the object.&lt;br /&gt;
# Resolves attachment point: uses explicit point, or stored LastAttachPoint, or left hand as fallback.&lt;br /&gt;
# Rejects if &amp;gt; Constants.MaxAgentAttachments already attached.&lt;br /&gt;
# If not appending (WearReplacesAll): collects existing SOGs at same attach point for removal.&lt;br /&gt;
# Calls DetachSingleAttachmentToInv() for each displaced attachment.&lt;br /&gt;
# Calls UpdateUserInventoryWithAttachment() -- updates inventory item to reflect new attach point.&lt;br /&gt;
# Calls AttachToAgent() -- physically attaches SOG to avatar in scene.&lt;br /&gt;
# If resumeScripts: CreateScriptInstances() + ResumeScripts().&lt;br /&gt;
# Fires EventManager.TriggerOnAttach().&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== AttachToAgent() ==&lt;br /&gt;
&lt;br /&gt;
Low-level scene attachment.&lt;br /&gt;
&lt;br /&gt;
# Calls m_scene.DeleteFromStorage() -- removes object from region storage.&lt;br /&gt;
# Removes physics actors from all parts.&lt;br /&gt;
# Sets so.AttachedAvatar, so.AttachmentPoint, so.IsAttachment = true.&lt;br /&gt;
# Calls sp.AddAttachment(so).&lt;br /&gt;
# For HUD attachments (HasPrivateAttachmentPoint): sends kill packets to all other clients.&lt;br /&gt;
# Schedules full update for the SOG.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== DetachSingleAttachmentToInv() ==&lt;br /&gt;
&lt;br /&gt;
Detach and save to inventory.&lt;br /&gt;
&lt;br /&gt;
# Calls PrepareScriptInstanceForSave() -- fires detach event, waits 30ms, snapshots script state. Must be done OUTSIDE AttachmentsSyncLock to avoid deadlock.&lt;br /&gt;
# Under AttachmentsSyncLock:&lt;br /&gt;
#* Calls sp.Appearance.DetachAttachment() -- updates appearance wearables.&lt;br /&gt;
#* Calls AvatarFactory.QueueAppearanceSave().&lt;br /&gt;
#* Calls sp.RemoveAttachment().&lt;br /&gt;
#* Calls UpdateDetachedObject().&lt;br /&gt;
&lt;br /&gt;
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 (not HG visitors): calls UpdateKnownItem() -- serialises SOG to XML, updates asset and inventory item.&lt;br /&gt;
* Calls so.RemoveScriptInstances() + so.Dispose().&lt;br /&gt;
&lt;br /&gt;
UpdateKnownItem():&lt;br /&gt;
* Serialises SOG to XML via SceneObjectSerializer.ToOriginalXmlFormat() including script state.&lt;br /&gt;
* Recalculates permissions from current prim permissions.&lt;br /&gt;
* Creates new asset via m_scene.CreateAsset().&lt;br /&gt;
* Calls IInventoryAccessModule.UpdateInventoryItemAsset().&lt;br /&gt;
* Sends SendInventoryItemCreateUpdate() to client.&lt;br /&gt;
&lt;br /&gt;
; DB writes (on detach):&lt;br /&gt;
* assets -- INSERT: new serialised object asset&lt;br /&gt;
* inventoryitems -- UPDATE: new assetID, permissions&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== DetachSingleAttachmentToGround() ==&lt;br /&gt;
&lt;br /&gt;
Drops attachment to world at position 2.5m in front of avatar.&lt;br /&gt;
&lt;br /&gt;
# Removes from inventory (DeleteItems).&lt;br /&gt;
# Clears attachment fields, sets AbsolutePosition.&lt;br /&gt;
# Calls so.ApplyPhysics(), so.AttachToBackup().&lt;br /&gt;
# Sends SendRemoveInventoryItem() to client.&lt;br /&gt;
# Fires TriggerOnAttach(localId, UUID.Zero) -- signals scripts.&lt;br /&gt;
# Removes script permissions (take controls, camera).&lt;br /&gt;
# Resumes scripts, schedules updates.&lt;br /&gt;
&lt;br /&gt;
; DB writes:&lt;br /&gt;
* inventoryitems -- DELETE: removes item from user inventory&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== CopyAttachments() (for region transfer) ==&lt;br /&gt;
&lt;br /&gt;
CopyAttachments(IScenePresence, AgentData) -- called by ScenePresence.CopyTo() on departure:&lt;br /&gt;
* Clones each attachment SOG for transfer.&lt;br /&gt;
* Snapshots script state via GetStateSnapshot().&lt;br /&gt;
* Stores clones and states in ad.AttachmentObjects / ad.AttachmentObjectStates.&lt;br /&gt;
&lt;br /&gt;
CopyAttachments(AgentData, IScenePresence) -- called by ScenePresence.CopyFrom() on arrival:&lt;br /&gt;
* Calls DeleteAttachmentsFromScene() to clear any existing attachments.&lt;br /&gt;
* Calls m_scene.IncomingAttechments() [sic -- typo in source] to add transferred SOGs.&lt;br /&gt;
* Note: typo IncomingAttechments() in Scene.cs line 2976 and AttachmentsModule.cs (Mantis pending).&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== DeRezAttachments() ==&lt;br /&gt;
&lt;br /&gt;
Called on avatar departure (not crossing -- crossing uses CopyAttachments).&lt;br /&gt;
&lt;br /&gt;
* For each attachment: PrepareScriptInstanceForSave() then UpdateDetachedObject().&lt;br /&gt;
* For NPCs: UpdateDetachedObject() with empty script state.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Known Issues ==&lt;br /&gt;
&lt;br /&gt;
* IncomingAttechments() typo in Scene.cs line 2976 and AttachmentsModule.cs (Mantis pending).&lt;br /&gt;
* Comment in source notes that RegionCombiner module accesses SubscribeToClientEvents() and UnsubscribeFromClientEvents() directly, breaking module encapsulation. Marked as needing a fix.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== See Also ==&lt;br /&gt;
&lt;br /&gt;
* [[OpenSimulator Internals/Code Map/ScenePresence]]&lt;br /&gt;
* [[OpenSimulator Internals/Code Map/AvatarFactoryModule]]&lt;br /&gt;
* [[OpenSimulator Internals/Walkthroughs/Avatar Rez In Region]]&lt;br /&gt;
* [[OpenSimulator Internals/Walkthroughs/Avatar Change Outfit]]&lt;br /&gt;
* [[OpenSimulator Internals/Walkthroughs/Avatar Transfer Between Regions]]&lt;/div&gt;</summary>
		<author><name>Jwbshaw</name></author>
	</entry>
	<entry>
		<id>http://osimdev.org/wiki/index.php?title=OpenSimulator_Internals/Code_Map/AvatarFactoryModule&amp;diff=91</id>
		<title>OpenSimulator Internals/Code Map/AvatarFactoryModule</title>
		<link rel="alternate" type="text/html" href="http://osimdev.org/wiki/index.php?title=OpenSimulator_Internals/Code_Map/AvatarFactoryModule&amp;diff=91"/>
		<updated>2026-07-07T13:18:13Z</updated>

		<summary type="html">&lt;p&gt;Jwbshaw: first&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= OpenSimulator Internals/Code Map/AvatarFactoryModule =&lt;br /&gt;
&lt;br /&gt;
== Overview ==&lt;br /&gt;
&lt;br /&gt;
 OpenSim/Region/CoreModules/Avatar/AvatarFactory/AvatarFactoryModule.cs&lt;br /&gt;
&lt;br /&gt;
INonSharedRegionModule. Manages avatar appearance: receives baked texture updates from the viewer, validates the baked texture cache on login, queues appearance saves to AvatarService, and sends appearance to other clients. One instance per region.&lt;br /&gt;
&lt;br /&gt;
Registered as IAvatarFactoryModule. Accessed by other modules via m_scene.AvatarFactory.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Configuration ==&lt;br /&gt;
&lt;br /&gt;
 [Appearance] section in OpenSim.ini&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Key !! Default !! Purpose&lt;br /&gt;
|-&lt;br /&gt;
| DelayBeforeAppearanceSave || 5s || How long to wait after a change before saving to AvatarService&lt;br /&gt;
|-&lt;br /&gt;
| DelayBeforeAppearanceSend || 2s || How long to wait after a change before sending to other clients&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Timer fires every 500ms (m_checkTime) to drain the send and save queues.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Event Wiring ==&lt;br /&gt;
&lt;br /&gt;
SubscribeToClientEvents() hooks per client:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Event !! Handler&lt;br /&gt;
|-&lt;br /&gt;
| OnRequestWearables || Client_OnRequestWearables()&lt;br /&gt;
|-&lt;br /&gt;
| OnSetAppearance || Client_OnSetAppearance()&lt;br /&gt;
|-&lt;br /&gt;
| OnAvatarNowWearing || Client_OnAvatarNowWearing()&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
OnCachedTextureRequest is commented out.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== SetAppearance() ==&lt;br /&gt;
&lt;br /&gt;
Main entry point for appearance changes. Called from Client_OnSetAppearance() and from other modules.&lt;br /&gt;
&lt;br /&gt;
# Acquires m_setAppearanceLock (serialises concurrent updates).&lt;br /&gt;
# Calls sp.Appearance.SetVisualParams() if visualParams provided -- updates slider values, may change height.&lt;br /&gt;
# Calls sp.Appearance.SetTextureEntries() if textureEntry provided -- updates baked texture UUIDs.&lt;br /&gt;
# Calls UpdateBakedTextureCache() -- validates and stores baked textures in local asset cache and IBakedTextureModule.&lt;br /&gt;
# For NPCs: calls SendAppearance() immediately and returns.&lt;br /&gt;
# If appearance changed: calls QueueAppearanceSave().&lt;br /&gt;
# Always calls QueueAppearanceSend().&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== UpdateBakedTextureCache() ==&lt;br /&gt;
&lt;br /&gt;
Called on each texture update from viewer.&lt;br /&gt;
&lt;br /&gt;
# Iterates cacheItems from viewer -- each maps a BakeType index to a CacheId and TextureID.&lt;br /&gt;
# For each entry: checks local IAssetCache for the baked texture asset.&lt;br /&gt;
# If found: updates WearableCacheItems[idx] with new TextureID and CacheId. Counts as a hit.&lt;br /&gt;
# If not found: sends SendRebakeAvatarTextures() to viewer for the missing texture. Throttled via ExpiringKey -- one rebake request per texture per 30 seconds.&lt;br /&gt;
# Clears PBR bake indices (&amp;gt;= BAKES_COUNT_PV7) that were not in the update set.&lt;br /&gt;
# If all items hit and validDirtyBakes &amp;gt; 0: stores full set to IBakedTextureModule (bake server).&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== ValidateBakedTextureCache() ==&lt;br /&gt;
&lt;br /&gt;
Called from CompleteMovement() on new root agent arrival (non-HG). Returns true if cache is valid.&lt;br /&gt;
&lt;br /&gt;
# NPCs always return true.&lt;br /&gt;
# Checks each bake index: if WearableCacheItems matches face texture and asset is in local cache: hit.&lt;br /&gt;
# If local cache invalid and IBakedTextureModule available: fetches from bake server, populates local cache and WearableCacheItems.&lt;br /&gt;
# Returns true if hits &amp;gt;= BAKE_INDICES.Length (skirt index 19 is optional).&lt;br /&gt;
&lt;br /&gt;
If ValidateBakedTextureCache returns false: CompleteMovement() calls QueueAppearanceSave() to trigger a rebake cycle.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Queue / Timer Mechanism ==&lt;br /&gt;
&lt;br /&gt;
QueueAppearanceSend(agentId):&lt;br /&gt;
* Adds agentId to m_sendqueue with timestamp = now + m_sendtime.&lt;br /&gt;
* Starts m_updateTimer.&lt;br /&gt;
&lt;br /&gt;
QueueAppearanceSave(agentId):&lt;br /&gt;
* Adds agentId to m_savequeue with timestamp = now + m_savetime.&lt;br /&gt;
* Starts m_updateTimer.&lt;br /&gt;
&lt;br /&gt;
HandleAppearanceUpdateTimer() (fires every 500ms):&lt;br /&gt;
* Drains m_sendqueue: for each expired entry calls SendAppearance(agentId) -- sp.SendAppearanceToAllOtherAgents() + Animator.SendAnimPack().&lt;br /&gt;
* Drains m_savequeue: batches expired entries, runs SaveAppearance() on thread pool.&lt;br /&gt;
* Stops timer when both queues empty.&lt;br /&gt;
&lt;br /&gt;
SaveAppearance():&lt;br /&gt;
* Calls SetAppearanceAssets() -- resolves each wearable ItemID to AssetID via InventoryService.GetItem().&lt;br /&gt;
* Calls m_scene.AvatarService.SetAppearance() -- writes to ROBUST AvatarService → avatarappearance table.&lt;br /&gt;
&lt;br /&gt;
; DB writes (async, via SaveAppearance):&lt;br /&gt;
* avatarappearance -- UPDATE: full appearance for avatar UUID&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Client_OnAvatarNowWearing() ==&lt;br /&gt;
&lt;br /&gt;
Triggered when viewer sends AvatarIsWearing packet (outfit change initiated).&lt;br /&gt;
&lt;br /&gt;
# Makes a copy of current AvatarAppearance (no lock needed on copy).&lt;br /&gt;
# Updates Wearables array from the wearing list -- sets ItemID, AssetID initially UUID.Zero.&lt;br /&gt;
# Calls avatAppearance.GetAssetsFrom(sp.Appearance) -- copies known asset IDs from current appearance.&lt;br /&gt;
# Under m_setAppearanceLock: updates sp.Appearance.Wearables only (does not overwrite textures or visual params).&lt;br /&gt;
# Calls QueueAppearanceSave() -- schedules async inventory lookup and save.&lt;br /&gt;
&lt;br /&gt;
Note: Does NOT call QueueAppearanceSend(). The viewer will follow with OnSetAppearance once baking is done; that triggers the send.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Client_OnRequestWearables() ==&lt;br /&gt;
&lt;br /&gt;
Viewer requests wearable list (e.g. on login or reconnect). Fires async with a 4-second sleep before sending. Calls client.SendWearables(sp.Appearance.Wearables, sp.Appearance.Serial).&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== SaveBakedTextures() ==&lt;br /&gt;
&lt;br /&gt;
Saves baked textures from local asset cache to permanent AssetService storage. Used for NPCs. Marks assets as non-local, non-temporary, stores via m_scene.AssetService.Store().&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== See Also ==&lt;br /&gt;
&lt;br /&gt;
* [[OpenSimulator Internals/Code Map/ScenePresence]]&lt;br /&gt;
* [[OpenSimulator Internals/Code Map/AttachmentsModule]]&lt;br /&gt;
* [[OpenSimulator Internals/Code Map/ROBUST/AvatarService]]&lt;br /&gt;
* [[OpenSimulator Internals/Walkthroughs/Avatar Rez In Region]]&lt;br /&gt;
* [[OpenSimulator Internals/Walkthroughs/Avatar Change Outfit]]&lt;/div&gt;</summary>
		<author><name>Jwbshaw</name></author>
	</entry>
	<entry>
		<id>http://osimdev.org/wiki/index.php?title=OpenSimulator_Internals/Code_Map/ScenePresence&amp;diff=90</id>
		<title>OpenSimulator Internals/Code Map/ScenePresence</title>
		<link rel="alternate" type="text/html" href="http://osimdev.org/wiki/index.php?title=OpenSimulator_Internals/Code_Map/ScenePresence&amp;diff=90"/>
		<updated>2026-07-07T13:17:18Z</updated>

		<summary type="html">&lt;p&gt;Jwbshaw: first&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= OpenSimulator Internals/Code Map/ScenePresence =&lt;br /&gt;
&lt;br /&gt;
== Overview ==&lt;br /&gt;
&lt;br /&gt;
 OpenSim/Region/Framework/Scenes/ScenePresence.cs&lt;br /&gt;
&lt;br /&gt;
One ScenePresence instance exists per agent per region. It represents the avatar -- whether root (avatar is here) or child (avatar is elsewhere, this is a listening post for interest management). ScenePresence implements IScenePresence and EntityBase.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Lifecycle States ==&lt;br /&gt;
&lt;br /&gt;
Governed by ScenePresenceStateMachine. The critical flag for most code paths is IsChildAgent (bool).&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! State !! IsChildAgent !! Description&lt;br /&gt;
|-&lt;br /&gt;
| Child || true || Pre-seeded in neighbouring region. Tracks position updates, no physics, no full scene state.&lt;br /&gt;
|-&lt;br /&gt;
| Root || false || Avatar is present in this region. Full physics, full scene state, heartbeat participation.&lt;br /&gt;
|-&lt;br /&gt;
| Deleted || -- || IsDeleted set. Dispose() called.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Transition from child to root happens in MakeRootAgent(), called from CompleteMovement(). Transition from root to child happens in MakeChildAgent(), called by EntityTransferModule on departure.&lt;br /&gt;
&lt;br /&gt;
See [[OpenSimulator Internals/Walkthroughs/Avatar Rez In Region]] for the full transition sequence on login.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Constructor ==&lt;br /&gt;
&lt;br /&gt;
 ScenePresence(IClientAPI client, Scene world, AvatarAppearance appearance, PresenceType type)&lt;br /&gt;
&lt;br /&gt;
# Sets IsChildAgent = true.&lt;br /&gt;
# Sets draw distance from client.StartFar, clamped to region MaxDrawDistance / DefaultDrawDistance.&lt;br /&gt;
# Sets RegionHandle, ControllingClient, name fields, UUID, LocalId.&lt;br /&gt;
# Fetches UserAccount -- sets m_userFlags and GodController god level. If no account found, god level 0.&lt;br /&gt;
# Initialises ScenePresenceAnimator and MovementAnimationOverrides.&lt;br /&gt;
# Sets AbsolutePosition from ControllingClient.StartPos.&lt;br /&gt;
# Disables child updates and reprioritization (m_childUpdatesBusy = true, m_reprioritizationBusy = true) -- re-enabled after CompleteMovement.&lt;br /&gt;
# Calls AdjustKnownSeeds() -- initialises m_knownChildRegions from CapsModule.&lt;br /&gt;
# Calls RegisterToClientEvents() -- see Event Wiring below.&lt;br /&gt;
# Sets Appearance from passed AvatarAppearance.&lt;br /&gt;
# Constructs ScenePresenceStateMachine.&lt;br /&gt;
# Calls ControllingClient.RefreshGroupMembership().&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Event Wiring ==&lt;br /&gt;
&lt;br /&gt;
RegisterToClientEvents() hooks the following on ControllingClient:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Event !! Handler&lt;br /&gt;
|-&lt;br /&gt;
| OnCompleteMovementToRegion || CompleteMovement()&lt;br /&gt;
|-&lt;br /&gt;
| OnAgentUpdate || HandleAgentUpdate()&lt;br /&gt;
|-&lt;br /&gt;
| OnAgentCameraUpdate || HandleAgentCamerasUpdate()&lt;br /&gt;
|-&lt;br /&gt;
| OnAgentRequestSit || HandleAgentRequestSit()&lt;br /&gt;
|-&lt;br /&gt;
| OnAgentSit || HandleAgentSit()&lt;br /&gt;
|-&lt;br /&gt;
| OnSetAlwaysRun || HandleSetAlwaysRun()&lt;br /&gt;
|-&lt;br /&gt;
| OnStartAnim || HandleStartAnim()&lt;br /&gt;
|-&lt;br /&gt;
| OnStopAnim || HandleStopAnim()&lt;br /&gt;
|-&lt;br /&gt;
| OnChangeAnim || avnHandleChangeAnim()&lt;br /&gt;
|-&lt;br /&gt;
| OnForceReleaseControls || HandleForceReleaseControls()&lt;br /&gt;
|-&lt;br /&gt;
| OnAutoPilotGo || MoveToTargetHandle()&lt;br /&gt;
|-&lt;br /&gt;
| OnRegionHandShakeReply || RegionHandShakeReply()&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
All removed in RemoveClientEvents() on disposal.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== MakeRootAgent() ==&lt;br /&gt;
&lt;br /&gt;
 private bool MakeRootAgent(Vector3 pos, bool isFlying, ref Vector3 lookat)&lt;br /&gt;
&lt;br /&gt;
Called only from CompleteMovement(). Returns false if already root.&lt;br /&gt;
&lt;br /&gt;
# Acquires m_completeMovementLock.&lt;br /&gt;
# Handles pending sit (ParentUUID set): resolves prim, re-seats avatar.&lt;br /&gt;
# Sets IsChildAgent = false.&lt;br /&gt;
# Updates RegionHandle.&lt;br /&gt;
# Fires EventManager.TriggerSetRootAgentScene().&lt;br /&gt;
# If not sitting:&lt;br /&gt;
#* Calls CheckAndAdjustLandingPoint_OS() or _SL() -- adjusts position for telehubs, parcel landing points, ban lines.&lt;br /&gt;
#* Clamps position to region bounds.&lt;br /&gt;
#* Raises Z to ground height + avatar half-height.&lt;br /&gt;
#* If ViaLogin or ViaLocation flags: raycasts downward from PhysSearchHeight (300f) using RayFilterFlags.PrimsNonPhantomAgents to find surface, avoids placing avatar inside objects.&lt;br /&gt;
#* Sets AbsolutePosition.&lt;br /&gt;
#* Calls AddToPhysicalScene(isFlying).&lt;br /&gt;
# Calls m_scene.SwapRootAgentCount(false, IsNPC).&lt;br /&gt;
# Resets MovementFlags = 0.&lt;br /&gt;
# Updates circuit: AuthenticateHandler.UpdateAgentChildStatus(circuitCode, false).&lt;br /&gt;
# Fires EventManager.TriggerOnMakeRootAgent(this).&lt;br /&gt;
&lt;br /&gt;
Physics position search constants:&lt;br /&gt;
* PhysSearchHeight = 300f&lt;br /&gt;
* PhysMinSkipGap = 20f&lt;br /&gt;
* PhysSkipGapDelta = 30f&lt;br /&gt;
* PhysNumberCollisions = 30&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== MakeChildAgent() ==&lt;br /&gt;
&lt;br /&gt;
 public void MakeChildAgent(ulong newRegionHandle)&lt;br /&gt;
&lt;br /&gt;
Called by EntityTransferModule when avatar departs.&lt;br /&gt;
&lt;br /&gt;
# Resets m_updateAgentReceivedAfterTransferEvent.&lt;br /&gt;
# Clears group information and cross-update flags.&lt;br /&gt;
# Unhooks RegionHeartbeatEnd.&lt;br /&gt;
# Sets IsChildAgent = true.&lt;br /&gt;
# Calls m_scene.SwapRootAgentCount(true, IsNPC).&lt;br /&gt;
# Calls RemoveFromPhysicalScene().&lt;br /&gt;
# Clears parcel tracking.&lt;br /&gt;
# Sends kill packets to root presences that don&#039;t know the new region (won&#039;t receive the avatar as child).&lt;br /&gt;
# Updates circuit: AuthenticateHandler.UpdateAgentChildStatus(circuitCode, true).&lt;br /&gt;
# Fires EventManager.TriggerOnMakeChildAgent(this).&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== CompleteMovement() ==&lt;br /&gt;
&lt;br /&gt;
 public void CompleteMovement(IClientAPI client, bool openChildAgents)&lt;br /&gt;
&lt;br /&gt;
Triggered by OnCompleteMovementToRegion event from viewer.&lt;br /&gt;
&lt;br /&gt;
* For teleports/crossings: calls WaitForUpdateAgent() -- waits up to 10 seconds for source region&#039;s UpdateAgent to arrive (sets m_originRegionID via CopyFrom()).&lt;br /&gt;
* For real login (IsRealLogin() true): skips WaitForUpdateAgent().&lt;br /&gt;
* Calls MakeRootAgent().&lt;br /&gt;
* Sends RegionHandshake if not a crossing.&lt;br /&gt;
* Calls ControllingClient.MoveAgentIntoRegion().&lt;br /&gt;
* Validates baked texture cache (AvatarFactory.ValidateBakedTextureCache()); queues appearance save if invalid.&lt;br /&gt;
* Sends initial avatar data to all presences.&lt;br /&gt;
* Sends appearance and animations to self and others.&lt;br /&gt;
* For real login: calls Scene.AttachmentsModule.RezAttachments(this).&lt;br /&gt;
* For crossing with carried attachments: restarts scripts, sends attachment updates.&lt;br /&gt;
* For login: calls IFriendsModule.SendFriendsOnlineIfNeeded().&lt;br /&gt;
* Hooks RegionHeartbeatEnd for per-frame processing.&lt;br /&gt;
&lt;br /&gt;
IsRealLogin() check:&lt;br /&gt;
&lt;br /&gt;
 (teleportFlags &amp;amp; (ViaLogin | ViaHGLogin)) == ViaLogin&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== RegionHandShakeReply() / SendInitialData() ==&lt;br /&gt;
&lt;br /&gt;
 public void RegionHandShakeReply(IClientAPI client)&lt;br /&gt;
 private void SendInitialData()&lt;br /&gt;
&lt;br /&gt;
RegionHandShakeReply() sets NeedInitialData = 2 on receipt of viewer handshake reply.&lt;br /&gt;
&lt;br /&gt;
SendInitialData() is called from Update() when NeedInitialData &amp;gt; 0. It waits for:&lt;br /&gt;
* ViewerFlags.SentSeeds to be set (caps seeds sent to viewer).&lt;br /&gt;
* NeedInitialData incremented to 6 (several heartbeat frames for viewer to process seeds).&lt;br /&gt;
&lt;br /&gt;
Then fires async (Util.FireAndForget):&lt;br /&gt;
* Releases source region via SimulationService.ReleaseAgent() if callback URI present.&lt;br /&gt;
* Calls IEntityTransferModule.CloseOldChildAgents().&lt;br /&gt;
* Sends terrain layer data if not a teleport.&lt;br /&gt;
* Sends parcel info.&lt;br /&gt;
* Sends full avatar updates for all other root presences (SendOtherAgentsAvatarFullToMe()).&lt;br /&gt;
* Sends ObjectUpdate packets for all scene objects -- full updates or cache probes depending on ViewerFlags.&lt;br /&gt;
* Calls IEntityTransferModule.EnableChildAgents() -- seeds neighbouring regions.&lt;br /&gt;
* Sets m_childUpdatesBusy = false.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Update() ==&lt;br /&gt;
&lt;br /&gt;
Called each heartbeat frame from Scene.Update() for every ScenePresence.&lt;br /&gt;
&lt;br /&gt;
* If NeedInitialData &amp;gt; 0: calls SendInitialData() and returns.&lt;br /&gt;
* If IsChildAgent or IsInTransit: returns.&lt;br /&gt;
* Calls CheckForBorderCrossing().&lt;br /&gt;
* Handles MoveToTarget autopilot updates.&lt;br /&gt;
* Handles delayed stop.&lt;br /&gt;
* If avatar size changed: sends avatar data to all agents.&lt;br /&gt;
* If position, velocity, rotation, or collision plane changed beyond tolerance: calls SendTerseUpdateToAllClients().&lt;br /&gt;
* Calls CheckForSignificantMovement().&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Physical Scene ==&lt;br /&gt;
&lt;br /&gt;
AddToPhysicalScene(bool isFlying):&lt;br /&gt;
* Calls PhysicsScene.AddAvatar() -- creates PhysicsActor.&lt;br /&gt;
* Wires pa.OnCollisionUpdate → PhysicsCollisionUpdate().&lt;br /&gt;
* Wires pa.OnOutOfBounds → OutOfBoundsCall().&lt;br /&gt;
* Sets PhysicsActor = pa.&lt;br /&gt;
&lt;br /&gt;
RemoveFromPhysicalScene():&lt;br /&gt;
* Interlocked.Exchange to null (thread-safe).&lt;br /&gt;
* Unwires collision and OOB events.&lt;br /&gt;
* Calls PhysicsScene.RemoveAvatar().&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Neighbour Region Tracking ==&lt;br /&gt;
&lt;br /&gt;
m_knownChildRegions: Dictionary&amp;lt;ulong, string&amp;gt; -- regionHandle → seed cap URL.&lt;br /&gt;
m_knownChildRegionsSizeInfo: Dictionary&amp;lt;ulong, spRegionSizeInfo&amp;gt; -- regionHandle → (sizeX, sizeY).&lt;br /&gt;
&lt;br /&gt;
Key methods:&lt;br /&gt;
* AddNeighbourRegion() / RemoveNeighbourRegion()&lt;br /&gt;
* GetChildAgentsToClose() -- computes which neighbours to close on departure, based on IsOutsideView() distance check (currently hardcoded 255 rather than RegionViewDistance).&lt;br /&gt;
* CloseChildAgents() -- sends CloseChildAgentConnections to computed list, drops cap seeds.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Sitting ==&lt;br /&gt;
&lt;br /&gt;
HandleAgentRequestSit() → SendSitResponse() → HandleAgentSit() / PhysicsSit().&lt;br /&gt;
&lt;br /&gt;
PhysicsSit() delegates to PhysicsScene.SitAvatar() with callback PhysicsSitResponse(). Falls back to legacy sit if physics engine doesn&#039;t support it.&lt;br /&gt;
&lt;br /&gt;
On sit:&lt;br /&gt;
* RemoveFromPhysicalScene().&lt;br /&gt;
* ParentID = part.LocalId, ParentPart = part.&lt;br /&gt;
* part.AddSittingAvatar(this).&lt;br /&gt;
* Animator.SetMovementAnimations(&amp;quot;SIT&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
StandUp():&lt;br /&gt;
* Computes world position from sit offset and prim rotation.&lt;br /&gt;
* Clears ParentID, ParentPart.&lt;br /&gt;
* Calls AddToPhysicalScene() if addPhys true.&lt;br /&gt;
* part.RemoveSittingAvatar(this).&lt;br /&gt;
* Animator.SetMovementAnimations(&amp;quot;STAND&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
SIT_TARGET_ADJUSTMENT = (0, 0, 0.4f) -- empirically derived fudge factor matching SL behaviour (Mantis 1716).&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Parcel Visibility ==&lt;br /&gt;
&lt;br /&gt;
ParcelHideThisAvatar: true if current parcel has SeeAVs = false.&lt;br /&gt;
&lt;br /&gt;
On parcel crossing (currentParcelUUID setter → ParcelCrossCheck()):&lt;br /&gt;
* Computes which presences need kill packets (now hidden from them or they from us).&lt;br /&gt;
* Computes which presences need view packets (now visible).&lt;br /&gt;
* Sends kills and views accordingly.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Child Agent Data Transfer ==&lt;br /&gt;
&lt;br /&gt;
CopyTo(AgentData, isCrossUpdate): serialises full avatar state for transfer to destination region -- position, velocity, camera, appearance, animations, attachments, script controls, group info, friends online cache.&lt;br /&gt;
&lt;br /&gt;
CopyFrom(AgentData): deserialises on destination side. Sets m_originRegionID, which signals WaitForUpdateAgent() to unblock CompleteMovement().&lt;br /&gt;
&lt;br /&gt;
UpdateChildAgent(AgentData): called on destination when source fires UpdateAgent. Calls CopyFrom() then sets m_updateAgentReceivedAfterTransferEvent.&lt;br /&gt;
&lt;br /&gt;
UpdateChildAgent(AgentPosition): lightweight position-only update for child agent interest management. Adjusts position by region offset, updates throttles with distance-based scaling factor.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Movement ==&lt;br /&gt;
&lt;br /&gt;
HandleAgentUpdate(): main movement handler. Processes AgentUpdateArgs from viewer each packet.&lt;br /&gt;
* Drops updates where IsChildAgent or IsInTransit.&lt;br /&gt;
* Updates DrawDistance, HideTitle, MuteCollisions, mouse state, State byte.&lt;br /&gt;
* Computes movement vector from control flags.&lt;br /&gt;
* Calls AddNewMovement() → sets PhysicsActor.TargetVelocity.&lt;br /&gt;
* Calls Animator.UpdateMovementAnimations().&lt;br /&gt;
* Calls SendControlsToScripts() -- fires EventManager.TriggerControlEvent for scripted control listeners.&lt;br /&gt;
&lt;br /&gt;
Autopilot: MoveToTarget() / HandleMoveToTargetUpdate() -- PID-style movement toward a target position, used by llMoveToTarget() and parcel enforcement.&lt;br /&gt;
&lt;br /&gt;
Border crossing detection: CheckForBorderCrossing() -- projects position by velocity * FrameTime, if outside region bounds calls CrossToNewRegion() → Scene.CrossAgentToNewRegion().&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Attachment Management ==&lt;br /&gt;
&lt;br /&gt;
m_attachments: List&amp;lt;SceneObjectGroup&amp;gt;, locked on AttachmentsSyncLock.&lt;br /&gt;
&lt;br /&gt;
AddAttachment() / RemoveAttachment() / GetAttachments() / ClearAttachments().&lt;br /&gt;
&lt;br /&gt;
SendAttachmentsToAgentNF(): sends terse update then full updates for all attachments to a specific presence.&lt;br /&gt;
SendAttachmentScheduleUpdate(): sends pending flagged updates to self and all visible presences.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Animation ==&lt;br /&gt;
&lt;br /&gt;
Animator: ScenePresenceAnimator -- manages animation state machine.&lt;br /&gt;
Overrides: MovementAnimationOverrides -- server-side animation override pairs.&lt;br /&gt;
&lt;br /&gt;
HandleStartAnim() / HandleStopAnim() / avnHandleChangeAnim(): viewer-initiated animation control.&lt;br /&gt;
RegionHeartbeatEnd hook: calls Animator.UpdateMovementAnimations() every 2 frames when root and not sitting.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Significant Movement ==&lt;br /&gt;
&lt;br /&gt;
CheckForSignificantMovement():&lt;br /&gt;
* MOVEMENT (0.25f sq) threshold: fires EventManager.TriggerOnClientMovement().&lt;br /&gt;
* SIGNIFICANT_MOVEMENT (16.0f sq) threshold: fires EventManager.TriggerSignificantClientMovement().&lt;br /&gt;
* CHILDAGENTSCHECK_MOVEMENT (1024f sq / 32m) threshold: calls IEntityTransferModule.EnableChildAgents() to update neighbour seeds.&lt;br /&gt;
* CHILDUPDATES_MOVEMENT (100f sq): sends AgentPosition updates to known child regions.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Key Constants ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Constant !! Value !! Purpose&lt;br /&gt;
|-&lt;br /&gt;
| MOVEMENT || 0.25f || Minimum movement to trigger client movement event (sq distance)&lt;br /&gt;
|-&lt;br /&gt;
| SIGNIFICANT_MOVEMENT || 16.0f || Minimum movement to trigger significant movement event (sq distance)&lt;br /&gt;
|-&lt;br /&gt;
| CHILDUPDATES_MOVEMENT || 100.0f || Minimum movement to send child agent position update (sq distance)&lt;br /&gt;
|-&lt;br /&gt;
| CHILDAGENTSCHECK_MOVEMENT || 1024.0f || Minimum movement to recheck neighbour child agents (sq distance, ~32m)&lt;br /&gt;
|-&lt;br /&gt;
| CHILDUPDATES_TIME || 2000f || Minimum ms between child agent updates&lt;br /&gt;
|-&lt;br /&gt;
| SIT_TARGET_ADJUSTMENT || (0,0,0.4f) || Sit target fudge factor matching SL (Mantis 1716)&lt;br /&gt;
|-&lt;br /&gt;
| PhysSearchHeight || 300f || Ray cast start height for spawn position search&lt;br /&gt;
|-&lt;br /&gt;
| PhysMinSkipGap || 20f || Minimum gap between surfaces in spawn position search&lt;br /&gt;
|-&lt;br /&gt;
| AgentControlNormalVel || 4.096f || Normal walk speed multiplier&lt;br /&gt;
|-&lt;br /&gt;
| AgentControlMidVel || 0.6 * 4.096f || Slow walk speed multiplier&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Known Issues ==&lt;br /&gt;
&lt;br /&gt;
* IncomingAttechments() typo in Scene.cs line 2976 and AttachmentsModule.cs line 384 (Mantis pending).&lt;br /&gt;
* GetChildAgentsToClose() uses hardcoded 255 for view distance rather than RegionViewDistance -- comment in source acknowledges this.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== See Also ==&lt;br /&gt;
&lt;br /&gt;
* [[OpenSimulator Internals/Code Map/Scene]]&lt;br /&gt;
* [[OpenSimulator Internals/Code Map/LLClientView]]&lt;br /&gt;
* [[OpenSimulator Internals/Code Map/LLUDP]]&lt;br /&gt;
* [[OpenSimulator Internals/Walkthroughs/Avatar Rez In Region]]&lt;br /&gt;
* [[OpenSimulator Internals/Walkthroughs/Avatar Transfer Between Regions]]&lt;br /&gt;
* [[OpenSimulator Internals/Walkthroughs/Avatar Logs Out]]&lt;/div&gt;</summary>
		<author><name>Jwbshaw</name></author>
	</entry>
	<entry>
		<id>http://osimdev.org/wiki/index.php?title=OpenSimulator_Internals/Walkthroughs/Avatar_Removes_From_Inventory&amp;diff=89</id>
		<title>OpenSimulator Internals/Walkthroughs/Avatar Removes From Inventory</title>
		<link rel="alternate" type="text/html" href="http://osimdev.org/wiki/index.php?title=OpenSimulator_Internals/Walkthroughs/Avatar_Removes_From_Inventory&amp;diff=89"/>
		<updated>2026-07-07T13:15:48Z</updated>

		<summary type="html">&lt;p&gt;Jwbshaw: first&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= OpenSimulator Internals/Walkthroughs/Avatar Removes From Inventory =&lt;br /&gt;
&lt;br /&gt;
== Overview ==&lt;br /&gt;
&lt;br /&gt;
Traces what happens when an avatar deletes an item from inventory, moves it to trash, or purges the trash folder. Also covers the Return Object path (estate/parcel manager returning an object to owner&#039;s Lost and Found).&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Case 1: Delete Item (Move to Trash) ==&lt;br /&gt;
&lt;br /&gt;
Avatar selects an item and deletes it (moves to Trash folder).&lt;br /&gt;
&lt;br /&gt;
=== 1. Client Sends RemoveInventoryItem ===&lt;br /&gt;
&lt;br /&gt;
 OpenSim/Region/Framework/Scenes/Scene.cs -- RemoveInventoryItem()&lt;br /&gt;
&lt;br /&gt;
# Viewer sends RemoveInventoryItem packet.&lt;br /&gt;
# Scene.RemoveInventoryItem() calls InventoryService.DeleteItems(agentID, [itemID]) if permitted.&lt;br /&gt;
&lt;br /&gt;
Wait -- DeleteItems moves to trash in v2 protocol or deletes directly depending on implementation. In OpenSim&#039;s XInventoryService, DeleteItems() marks the item deleted (moves to system trash folder or removes depending on config).&lt;br /&gt;
&lt;br /&gt;
; DB writes:&lt;br /&gt;
* inventoryitems -- UPDATE or DELETE depending on server config&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Case 2: Purge Folder (Empty Trash) ==&lt;br /&gt;
&lt;br /&gt;
Avatar right-clicks Trash folder and selects Empty Trash.&lt;br /&gt;
&lt;br /&gt;
=== 1. Client Sends PurgeInventoryDescendents ===&lt;br /&gt;
&lt;br /&gt;
# Viewer sends PurgeInventoryDescendents packet with folderID = Trash folder UUID.&lt;br /&gt;
# Scene.HandlePurgeInventoryDescendents() calls InventoryService.PurgeFolder(folder).&lt;br /&gt;
# ROBUST XInventoryService: deletes all items and subfolders recursively from inventoryitems and inventoryfolders tables.&lt;br /&gt;
&lt;br /&gt;
; DB writes:&lt;br /&gt;
* inventoryitems -- DELETE: all items in folder and subfolders&lt;br /&gt;
* inventoryfolders -- DELETE: all subfolders (not the trash folder itself)&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Case 3: Delete Object from World (DeRez to Trash) ==&lt;br /&gt;
&lt;br /&gt;
Avatar right-clicks object in world and selects Delete (not Take).&lt;br /&gt;
&lt;br /&gt;
=== 1. Client Sends DeRezObject with action=Delete ===&lt;br /&gt;
&lt;br /&gt;
 BasicInventoryAccessModule -- CopyToInventory(DeRezAction.Delete)&lt;br /&gt;
&lt;br /&gt;
# If deleting own object: destination folder = Trash (FolderType.Trash).&lt;br /&gt;
# If deleting another&#039;s object (estate manager): destination = owner&#039;s Lost and Found (FolderType.LostAndFound).&lt;br /&gt;
# CopyBundleToInventory() runs: serialises object, creates asset, inserts inventory item in appropriate folder.&lt;br /&gt;
# Scene.DeleteSceneObject() removes object from scene and region storage.&lt;br /&gt;
&lt;br /&gt;
; DB writes:&lt;br /&gt;
* assets -- INSERT: serialised object XML&lt;br /&gt;
* inventoryitems -- INSERT: item in Trash or LostAndFound&lt;br /&gt;
* prims/primshapes/primitems -- DELETE: object removed from region&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Case 4: Return Object (Parcel/Estate Manager) ==&lt;br /&gt;
&lt;br /&gt;
Estate manager or parcel owner returns an object to its owner&#039;s inventory.&lt;br /&gt;
&lt;br /&gt;
=== 1. Return Triggered ===&lt;br /&gt;
&lt;br /&gt;
 OpenSim/Region/Framework/Scenes/Scene.cs -- returnObjects()&lt;br /&gt;
&lt;br /&gt;
# Parcel manager calls returnObjects() for objects on the parcel.&lt;br /&gt;
# Calls IInventoryAccessModule.CopyToInventory(DeRezAction.Return, UUID.Zero, objlist, null, false).&lt;br /&gt;
#* remoteClient is null -- return is server-initiated.&lt;br /&gt;
#* Destination folder: owner&#039;s Lost and Found (FolderType.LostAndFound).&lt;br /&gt;
# AddPermissions() with null remoteClient: same-owner path, perms preserved.&lt;br /&gt;
# Asset created, item inserted.&lt;br /&gt;
# Scene.AddReturn() queues a notification message to the owner.&lt;br /&gt;
# Scene.DeleteSceneObject() removes from scene.&lt;br /&gt;
&lt;br /&gt;
On next backup cycle, Scene.Backup() processes m_returns:&lt;br /&gt;
* Sends GridInstantMessage to the owner: &amp;quot;Your object X was returned from parcel Y in region Z due to [reason].&amp;quot;&lt;br /&gt;
&lt;br /&gt;
; DB writes:&lt;br /&gt;
* assets -- INSERT: serialised object XML&lt;br /&gt;
* inventoryitems -- INSERT: item in Lost and Found&lt;br /&gt;
* prims/primshapes/primitems -- DELETE&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;
! Case !! Table !! Operation&lt;br /&gt;
|-&lt;br /&gt;
| Delete item || inventoryitems || UPDATE/DELETE&lt;br /&gt;
|-&lt;br /&gt;
| Purge folder || inventoryitems, inventoryfolders || DELETE recursive&lt;br /&gt;
|-&lt;br /&gt;
| Delete object || assets, inventoryitems || INSERT; prims DELETE&lt;br /&gt;
|-&lt;br /&gt;
| Return object || assets, inventoryitems || INSERT; prims DELETE&lt;br /&gt;
|}&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/InventoryAccessModule]]&lt;br /&gt;
* [[OpenSimulator Internals/Walkthroughs/Avatar Acquires Inventory]]&lt;br /&gt;
* [[OpenSimulator Internals/Walkthroughs/Avatar Derezzes Object]]&lt;/div&gt;</summary>
		<author><name>Jwbshaw</name></author>
	</entry>
	<entry>
		<id>http://osimdev.org/wiki/index.php?title=OpenSimulator_Internals/Walkthroughs/Avatar_Rezzes_Inventory&amp;diff=88</id>
		<title>OpenSimulator Internals/Walkthroughs/Avatar Rezzes Inventory</title>
		<link rel="alternate" type="text/html" href="http://osimdev.org/wiki/index.php?title=OpenSimulator_Internals/Walkthroughs/Avatar_Rezzes_Inventory&amp;diff=88"/>
		<updated>2026-07-07T13:14:30Z</updated>

		<summary type="html">&lt;p&gt;Jwbshaw: first&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= OpenSimulator Internals/Walkthroughs/Avatar Rezzes Inventory =&lt;br /&gt;
&lt;br /&gt;
== Overview ==&lt;br /&gt;
&lt;br /&gt;
Traces what happens in code, connectors, and database when an avatar rezzes an object from inventory into the world.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== 1. Client Sends RezObject ==&lt;br /&gt;
&lt;br /&gt;
 OpenSim/Region/Framework/Scenes/Scene.cs -- RezObject()&lt;br /&gt;
&lt;br /&gt;
# Viewer sends RezObject packet with itemID, ray start/end, and rez flags.&lt;br /&gt;
# Scene.RezObject() calls IInventoryAccessModule.RezObject().&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== 2. Item and Asset Fetched ==&lt;br /&gt;
&lt;br /&gt;
 BasicInventoryAccessModule -- RezObject()&lt;br /&gt;
&lt;br /&gt;
# Calls InventoryService.GetItem(agentID, itemID) -- reads inventoryitems table.&lt;br /&gt;
# Validates item exists and is owned by agent.&lt;br /&gt;
# Calls AssetService.Get(assetID) -- fetches object XML asset.&lt;br /&gt;
# If asset null or empty: sends alert to client, returns null.&lt;br /&gt;
&lt;br /&gt;
For HG foreign users (HGInventoryAccessModule):&lt;br /&gt;
* If IsForeignUser: calls m_assMapper.Get(item.AssetID, agentID, foreignAssetServer) before asset fetch -- pulls asset from foreign grid if not cached locally.&lt;br /&gt;
&lt;br /&gt;
; DB reads:&lt;br /&gt;
* inventoryitems -- SELECT by item UUID&lt;br /&gt;
* assets -- SELECT by asset UUID&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== 3. Deserialise and Position ==&lt;br /&gt;
&lt;br /&gt;
 BasicInventoryAccessModule -- RezObject() continued&lt;br /&gt;
&lt;br /&gt;
# Calls Scene.GetObjectsToRez() -- deserialises XML into List&amp;lt;SceneObjectGroup&amp;gt; and position offsets.&lt;br /&gt;
#* Single object: SceneObjectSerializer.FromOriginalXmlFormat().&lt;br /&gt;
#* Coalesced: CoalescedSceneObjectsSerializer.FromXml().&lt;br /&gt;
# Calls Scene.GetNewRezLocation() -- raycasts from RayStart to RayEnd against physics scene to find surface position.&lt;br /&gt;
# Checks CanRezObject permission at target position.&lt;br /&gt;
# If no-copy item fails perm check: sends SendBulkUpdateInventory to restore item to client display.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== 4. Ownership and Permissions Applied ==&lt;br /&gt;
&lt;br /&gt;
 BasicInventoryAccessModule -- DoPreRezWhenFromItem()&lt;br /&gt;
&lt;br /&gt;
# Sets rootPart.Name and Description from inventory item (single object only).&lt;br /&gt;
# Applies ObjectSlamSale if flagged.&lt;br /&gt;
# Sets FromFolderID on SOG.&lt;br /&gt;
# If ownership change (new owner or Slam flag):&lt;br /&gt;
#* Changes OwnerID on all parts, sets LastOwnerID, calls Inventory.ChangeInventoryOwner().&lt;br /&gt;
#* Calls ApplyNextOwnerPermissions() -- applies NextOwnerMask to BasePermissions.&lt;br /&gt;
#* Applies any ObjectOverwrite flags from item.&lt;br /&gt;
# If same owner: sets FromUserInventoryItemID if item is copyable (links rezzed object back to inventory item for &amp;quot;save changes&amp;quot; support).&lt;br /&gt;
# Calls TrimPermissions() and InvalidateDeepEffectivePerms().&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== 5. Object Added to Scene ==&lt;br /&gt;
&lt;br /&gt;
 BasicInventoryAccessModule -- RezObject() continued&lt;br /&gt;
&lt;br /&gt;
# group.ResetIDs() -- assigns new UUIDs to all parts.&lt;br /&gt;
# Clears attachment data (ClearPartAttachmentData()).&lt;br /&gt;
# Sets IsSelected if RezSelected flag.&lt;br /&gt;
# Sets AbsolutePosition from ray result.&lt;br /&gt;
# Calls Scene.AddNewSceneObject(group, true, false) -- adds to scene graph, schedules persistence.&lt;br /&gt;
# Calls CreateScriptInstances(0, true, DefaultScriptEngine, 1) -- starts scripts with on_rez state source.&lt;br /&gt;
# Calls ResumeScripts().&lt;br /&gt;
# Schedules full update to clients.&lt;br /&gt;
&lt;br /&gt;
; DB writes:&lt;br /&gt;
* prims -- INSERT: new prim rows for each part&lt;br /&gt;
* primshapes -- INSERT: shape data for each part&lt;br /&gt;
* primitems -- INSERT: task inventory for each part&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== 6. No-Copy Item Removed from Inventory ==&lt;br /&gt;
&lt;br /&gt;
 BasicInventoryAccessModule -- DoPostRezWhenFromItem()&lt;br /&gt;
&lt;br /&gt;
# If item.CurrentPermissions has no Copy bit: calls InventoryService.DeleteItems(owner, [itemID]).&lt;br /&gt;
# Item is consumed on rez.&lt;br /&gt;
&lt;br /&gt;
; DB writes (no-copy only):&lt;br /&gt;
* inventoryitems -- DELETE: item removed&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== 7. HG Asset Push (HG users only) ==&lt;br /&gt;
&lt;br /&gt;
Not applicable on standard rez. HG asset push (ExportAsset) is triggered on CopyToInventory, not on rez.&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 !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| inventoryitems || SELECT || Fetch item record&lt;br /&gt;
|-&lt;br /&gt;
| assets || SELECT || Fetch object XML&lt;br /&gt;
|-&lt;br /&gt;
| prims || INSERT || New object in region&lt;br /&gt;
|-&lt;br /&gt;
| primshapes || INSERT || Shape data&lt;br /&gt;
|-&lt;br /&gt;
| primitems || INSERT || Task inventory per part&lt;br /&gt;
|-&lt;br /&gt;
| inventoryitems || DELETE || No-copy items only&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Edge Cases ==&lt;br /&gt;
&lt;br /&gt;
Attachment rez (from RezAttachments or RezSingleAttachmentFromInventory): uses same RezObject() path but attachment=true. AddNewSceneObject() is called without script start (scripts start later in AttachToAgent). See [[OpenSimulator Internals/Walkthroughs/Avatar Rez In Region]].&lt;br /&gt;
&lt;br /&gt;
Coalesced object: multiple SOGs deserialised from one asset, each positioned using the stored offsets from CoalescedSceneObjectsSerializer. Each gets its own DB rows.&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/InventoryAccessModule]]&lt;br /&gt;
* [[OpenSimulator Internals/Walkthroughs/Avatar Acquires Inventory]]&lt;br /&gt;
* [[OpenSimulator Internals/Walkthroughs/Avatar Derezzes Object]]&lt;br /&gt;
* [[OpenSimulator Internals/Walkthroughs/Avatar Rezzes Box]]&lt;/div&gt;</summary>
		<author><name>Jwbshaw</name></author>
	</entry>
	<entry>
		<id>http://osimdev.org/wiki/index.php?title=OpenSimulator_Internals/Walkthroughs/Avatar_Acquires_Inventory&amp;diff=87</id>
		<title>OpenSimulator Internals/Walkthroughs/Avatar Acquires Inventory</title>
		<link rel="alternate" type="text/html" href="http://osimdev.org/wiki/index.php?title=OpenSimulator_Internals/Walkthroughs/Avatar_Acquires_Inventory&amp;diff=87"/>
		<updated>2026-07-07T13:13:00Z</updated>

		<summary type="html">&lt;p&gt;Jwbshaw: first&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= OpenSimulator Internals/Walkthroughs/Avatar Acquires Inventory =&lt;br /&gt;
&lt;br /&gt;
== Overview ==&lt;br /&gt;
&lt;br /&gt;
Traces what happens in code, connectors, and database when an avatar acquires an object into inventory. Covers three cases:&lt;br /&gt;
&lt;br /&gt;
# Taking a copyable object from the world (Take Copy).&lt;br /&gt;
# Taking a no-copy object from the world (Take / derez).&lt;br /&gt;
# Buying an object from another avatar or vendor (buy object).&lt;br /&gt;
&lt;br /&gt;
Avatar-to-avatar direct inventory transfer (Give Inventory) is a separate flow not covered here.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Case 1: Take Copy (copyable object) ==&lt;br /&gt;
&lt;br /&gt;
Avatar right-clicks an object they have copy permission on and selects Take Copy.&lt;br /&gt;
&lt;br /&gt;
=== 1. Client Sends DeRezObject ===&lt;br /&gt;
&lt;br /&gt;
 OpenSim/Region/Framework/Scenes/Scene.cs -- DeRezObjects()&lt;br /&gt;
&lt;br /&gt;
# Viewer sends DeRezObject packet with action = TakeCopy.&lt;br /&gt;
# Scene.DeRezObjects() fires.&lt;br /&gt;
# Permission check: CanTakeObject() for the SOG.&lt;br /&gt;
# If passing: calls IInventoryAccessModule.CopyToInventory(DeRezAction.TakeCopy, folderID, objlist, remoteClient, false).&lt;br /&gt;
# Object remains in scene -- Take Copy does not delete it.&lt;br /&gt;
&lt;br /&gt;
=== 2. Object Serialised to Asset ===&lt;br /&gt;
&lt;br /&gt;
 BasicInventoryAccessModule -- CopyBundleToInventory()&lt;br /&gt;
&lt;br /&gt;
# Suspends keyframe motion.&lt;br /&gt;
# Records current world position/rotation.&lt;br /&gt;
# Serialises SOG to XML via SceneObjectSerializer.ToOriginalXmlFormat() (single object) or CoalescedSceneObjectsSerializer (multiple selected).&lt;br /&gt;
# Restores position.&lt;br /&gt;
# Calls CreateItemForObject(TakeCopy):&lt;br /&gt;
#* Destination folder: Object folder (FolderType.Object).&lt;br /&gt;
#* Owner: remoteClient.AgentId.&lt;br /&gt;
# Calls AddPermissions() -- same-owner path: copies current perms, preserves folded bits, applies NextOwnerMask to NextPermissions.&lt;br /&gt;
# Creates asset: UUID.Random(), AssetType.Object, stores via AssetService.Store().&lt;br /&gt;
# Calls Scene.AddInventoryItem() → InventoryService.AddItem().&lt;br /&gt;
# Sends SendInventoryItemCreateUpdate() to client.&lt;br /&gt;
&lt;br /&gt;
; DB writes:&lt;br /&gt;
* assets -- INSERT: serialised object XML&lt;br /&gt;
* inventoryitems -- INSERT: new item in Object folder&lt;br /&gt;
&lt;br /&gt;
=== 3. HG Asset Post (HG users only) ===&lt;br /&gt;
&lt;br /&gt;
 HGInventoryAccessModule -- ExportAsset()&lt;br /&gt;
&lt;br /&gt;
If avatar is a foreign HG user and OutboundPermission=true:&lt;br /&gt;
* m_assMapper.Post(assetID, agentID, foreignAssetServer) -- HTTP POST to push asset to foreign grid.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Case 2: Take (no-copy object, or owner taking back own object) ==&lt;br /&gt;
&lt;br /&gt;
Avatar takes a no-copy object, or picks up their own placed object.&lt;br /&gt;
&lt;br /&gt;
=== 1. Client Sends DeRezObject ===&lt;br /&gt;
&lt;br /&gt;
# Viewer sends DeRezObject packet with action = Take.&lt;br /&gt;
# Same permission check path.&lt;br /&gt;
# Calls IInventoryAccessModule.CopyToInventory(DeRezAction.Take, folderID, objlist, remoteClient, false).&lt;br /&gt;
&lt;br /&gt;
=== 2. Object Serialised (same as Take Copy) ===&lt;br /&gt;
&lt;br /&gt;
CopyBundleToInventory() with Take:&lt;br /&gt;
* Destination folder: original FromFolderID if owner taking back own item and folder still valid; otherwise Object folder.&lt;br /&gt;
* Asset created and stored, inventory item inserted.&lt;br /&gt;
&lt;br /&gt;
=== 3. Object Removed from Scene ===&lt;br /&gt;
&lt;br /&gt;
DoPostRezWhenFromItem():&lt;br /&gt;
* If item is no-copy (CurrentPermissions &amp;amp; Copy == 0): InventoryService.DeleteItems() removes item from inventory first (item was previously there for the no-copy object).&lt;br /&gt;
&lt;br /&gt;
Scene.DeRezObjects() also:&lt;br /&gt;
* Calls DeleteSceneObject() -- removes SOG from scene graph, removes from SimulationDataService (prims table).&lt;br /&gt;
&lt;br /&gt;
; DB writes:&lt;br /&gt;
* assets -- INSERT: serialised object XML&lt;br /&gt;
* inventoryitems -- INSERT: new item (or UPDATE if SaveToExisting)&lt;br /&gt;
* inventoryitems -- DELETE: original no-copy item if applicable&lt;br /&gt;
* prims/primshapes -- DELETE: object removed from region storage&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Case 3: Buy Object ==&lt;br /&gt;
&lt;br /&gt;
Avatar buys an object set for sale (right-click → Buy).&lt;br /&gt;
&lt;br /&gt;
=== 1. Client Sends ObjectBuy ===&lt;br /&gt;
&lt;br /&gt;
 OpenSim/Region/Framework/Scenes/Scene.cs -- ProcessObjectBuy() (via IBuySellModule)&lt;br /&gt;
&lt;br /&gt;
# Viewer sends ObjectBuy packet with price.&lt;br /&gt;
# IBuySellModule.BuyObject() called.&lt;br /&gt;
# Checks sale type and price.&lt;br /&gt;
# If sale type is Copy: calls IInventoryAccessModule.CopyToInventory(DeRezAction.TakeCopy) -- same as Take Copy path above. Object stays in scene.&lt;br /&gt;
# If sale type is Original: calls IInventoryAccessModule.CopyToInventory(DeRezAction.Take). Object leaves scene.&lt;br /&gt;
# If sale type is Contents: copies contents of the object&#039;s inventory to buyer&#039;s inventory, not the object itself (separate path via task inventory).&lt;br /&gt;
&lt;br /&gt;
Money transfer (if price &amp;gt; 0):&lt;br /&gt;
* IBuySellModule calls IMoneyModule.ObjectBuy() -- money transfer between accounts. This is grid-specific; base OpenSim has no money module by default.&lt;br /&gt;
&lt;br /&gt;
; DB writes (object sale):&lt;br /&gt;
* Same as Take or Take Copy depending on sale type.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Permissions Applied on Acquire ==&lt;br /&gt;
&lt;br /&gt;
AddPermissions() is the key method. Two paths:&lt;br /&gt;
&lt;br /&gt;
New owner (buyer or taker who is not the original owner) and PropagatePermissions=true:&lt;br /&gt;
* effectivePerms = intersection of all parts&#039; CurrentAndFoldedNextPermissions().&lt;br /&gt;
* Applies PermissionsUtil.ApplyNoModFoldedPermissions().&lt;br /&gt;
* basePerms = effectivePerms &amp;amp; RootPart.NextOwnerMask.&lt;br /&gt;
* Fixes and folds: PermissionsUtil.FixAndFoldPermissions().&lt;br /&gt;
* Sets ObjectSlamPerm flag -- permissions applied again on rez.&lt;br /&gt;
&lt;br /&gt;
Same owner (taking back own object):&lt;br /&gt;
* effectivePerms = intersection of current perms.&lt;br /&gt;
* NextPermissions = RootPart.NextOwnerMask &amp;amp; effectivePerms.&lt;br /&gt;
* No slam flag.&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 !! Case&lt;br /&gt;
|-&lt;br /&gt;
| assets || INSERT || All cases: new serialised object asset&lt;br /&gt;
|-&lt;br /&gt;
| inventoryitems || INSERT || All cases: new inventory item&lt;br /&gt;
|-&lt;br /&gt;
| inventoryitems || DELETE || No-copy Take: removes existing item&lt;br /&gt;
|-&lt;br /&gt;
| prims/primshapes/primitems || DELETE || Take (no-copy) or Take (own object): removes from region&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== HG Suitcase Note ==&lt;br /&gt;
&lt;br /&gt;
When a local user is abroad (HG), ProcessInventoryForHypergriding() has renamed their non-suitcase folders to &amp;quot;(Unavailable)&amp;quot;. Items they acquire while abroad go into My Suitcase (the only accessible folder). On return home, ProcessInventoryForComingHome() restores the full inventory view.&lt;br /&gt;
&lt;br /&gt;
Foreign users acquiring objects: ExportAsset() posts the asset to their home grid&#039;s asset server if OutboundPermission=true.&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/InventoryAccessModule]]&lt;br /&gt;
* [[OpenSimulator Internals/Walkthroughs/Avatar Rezzes Inventory]]&lt;br /&gt;
* [[OpenSimulator Internals/Walkthroughs/Avatar Removes From Inventory]]&lt;br /&gt;
* [[OpenSimulator Internals/Walkthroughs/Avatar Rezzes Box]]&lt;br /&gt;
* [[OpenSimulator Internals/Walkthroughs/Avatar Derezzes Object]]&lt;/div&gt;</summary>
		<author><name>Jwbshaw</name></author>
	</entry>
	<entry>
		<id>http://osimdev.org/wiki/index.php?title=OpenSimulator_Internals/Walkthroughs/Avatar_Goes_HG&amp;diff=86</id>
		<title>OpenSimulator Internals/Walkthroughs/Avatar Goes HG</title>
		<link rel="alternate" type="text/html" href="http://osimdev.org/wiki/index.php?title=OpenSimulator_Internals/Walkthroughs/Avatar_Goes_HG&amp;diff=86"/>
		<updated>2026-07-07T13:11:03Z</updated>

		<summary type="html">&lt;p&gt;Jwbshaw: first&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= OpenSimulator Internals/Walkthroughs/Avatar Goes HG =&lt;br /&gt;
&lt;br /&gt;
== Overview ==&lt;br /&gt;
&lt;br /&gt;
Traces what happens in code, connectors, and database when an avatar HyperGrid teleports from their home grid to a foreign grid, and when they return.&lt;br /&gt;
&lt;br /&gt;
Assumes the home grid runs ROBUST + OpenSim with HGEntityTransferModule enabled.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Part 1: Departing the Home Grid ==&lt;br /&gt;
&lt;br /&gt;
=== 1. HG Destination Resolved ===&lt;br /&gt;
&lt;br /&gt;
 OpenSim/Region/CoreModules/Framework/EntityTransfer/HGEntityTransferModule.cs -- GetFinalDestination()&lt;br /&gt;
 OpenSim/Services/Connectors/Hypergrid/GatekeeperServiceConnector.cs&lt;br /&gt;
&lt;br /&gt;
# Avatar clicks a HG link or enters a HG URI (e.g. hg.example.com:8002:RegionName).&lt;br /&gt;
# GridService on source region looks up the destination -- finds a region with RegionFlags.Hyperlink set. This is a local stub entry, not a real region.&lt;br /&gt;
# GetFinalDestination() detects the Hyperlink flag.&lt;br /&gt;
# Calls GatekeeperServiceConnector.GetHyperlinkRegion() -- HTTP POST to the foreign grid&#039;s Gatekeeper service (hg.example.com:8002).&lt;br /&gt;
#* Gatekeeper validates the request and returns a real GridRegion descriptor for the destination on the foreign grid.&lt;br /&gt;
# ValidateGenericConditions() checks appearance restrictions if RestrictAppearanceAbroad=true.&lt;br /&gt;
&lt;br /&gt;
=== 2. Pre-flight at Foreign Gatekeeper ===&lt;br /&gt;
&lt;br /&gt;
 EntityTransferModule -- DoTeleportInternal()&lt;br /&gt;
&lt;br /&gt;
# SimulationService.QueryAccess() -- HTTP POST to destination simulator on foreign grid.&lt;br /&gt;
#* Destination checks ban list, parcel access, agent limit.&lt;br /&gt;
# sp.Appearance.CanTeleport() -- checks outfit compatibility with destination protocol version.&lt;br /&gt;
&lt;br /&gt;
=== 3. Agent Created at Foreign Grid ===&lt;br /&gt;
&lt;br /&gt;
 HGEntityTransferModule -- CreateAgent() override&lt;br /&gt;
&lt;br /&gt;
# Detects Hyperlink destination.&lt;br /&gt;
# Checks local user&#039;s UserLevel &amp;gt;= LevelHGTeleport. Refuses if insufficient.&lt;br /&gt;
# Gets HomeURI from agentCircuit.ServiceURLs.&lt;br /&gt;
# Creates UserAgentServiceConnector for home grid&#039;s UserAgent service.&lt;br /&gt;
# Calls UserAgentService.LoginAgentToGrid(source, agentCircuit, gatekeeperRegion, finalDestination, false) -- HTTP POST to home grid&#039;s UserAgent service.&lt;br /&gt;
#* Home UserAgent service validates the request.&lt;br /&gt;
#* Home UserAgent service calls foreign Gatekeeper.CreateAgent() -- HTTP POST to foreign gatekeeper.&lt;br /&gt;
#* Foreign Gatekeeper validates, calls foreign destination simulator&#039;s NewUserConnection.&lt;br /&gt;
#* Returns success.&lt;br /&gt;
# Sets logout = true -- this agent will be logged out of home grid.&lt;br /&gt;
# Fires TriggerTeleportStart.&lt;br /&gt;
&lt;br /&gt;
=== 4. Agent State Sent ===&lt;br /&gt;
&lt;br /&gt;
Same as standard teleport (see [[OpenSimulator Internals/Walkthroughs/Avatar Transfer Between Regions]] steps 5-6):&lt;br /&gt;
&lt;br /&gt;
# sp.IsChildAgent = true set on source.&lt;br /&gt;
# TeleportFinishEvent sent to viewer with foreign destination endpoint and caps URL.&lt;br /&gt;
# AgentData built via sp.CopyTo() -- includes appearance, attachments with script states.&lt;br /&gt;
# SimulationService.UpdateAgent() -- HTTP POST to foreign destination simulator.&lt;br /&gt;
#* Foreign destination&#039;s IncomingUpdateChildAgent() → CopyFrom() fires.&lt;br /&gt;
# UpdateAgent() waits for avatar to become root at destination.&lt;br /&gt;
&lt;br /&gt;
=== 5. Source Grid Logs Out Agent ===&lt;br /&gt;
&lt;br /&gt;
 HGEntityTransferModule -- AgentHasMovedAway() override&lt;br /&gt;
&lt;br /&gt;
Called after UpdateAgent() returns successfully:&lt;br /&gt;
&lt;br /&gt;
# sp.HasMovedAway() -- sends kill packets for non-HUD attachments, handles parcel visibility.&lt;br /&gt;
# sp.MakeChildAgent() -- source becomes child.&lt;br /&gt;
# sp.closeAllChildAgents() -- closes all neighbour child agents (logout=true path).&lt;br /&gt;
# AgentHasMovedAway() fires:&lt;br /&gt;
#* PresenceService.LogoutAgent(sessionID) -- marks agent offline on home grid.&lt;br /&gt;
#* GridUserService.LoggedOut(userID, ...) -- updates home grid&#039;s griduser with last position.&lt;br /&gt;
# NeedsClosing() returns true for HG (always) -- CloseAgent() called on source after delay.&lt;br /&gt;
&lt;br /&gt;
; DB writes (home grid):&lt;br /&gt;
* presence -- UPDATE: Online=0&lt;br /&gt;
* griduser -- UPDATE: LastPosition, Logout timestamp&lt;br /&gt;
&lt;br /&gt;
=== 6. Avatar Arrives at Foreign Grid ===&lt;br /&gt;
&lt;br /&gt;
Foreign destination&#039;s CompleteMovement() fires when viewer sends CompleteMovementToRegion.&lt;br /&gt;
&lt;br /&gt;
Standard arrival sequence (see [[OpenSimulator Internals/Walkthroughs/Avatar Rez In Region]]) with HG differences:&lt;br /&gt;
&lt;br /&gt;
* TeleportFlags.ViaHGLogin is set -- baked texture validation skipped (AvatarFactory.ValidateBakedTextureCache() not called for HG).&lt;br /&gt;
* Attachments carried in AgentData. HandleIncomingAttachments() called.&lt;br /&gt;
* For HGLogin: HGEntityTransferModule.HandleIncomingAttachments() queues async asset fetch:&lt;br /&gt;
#* HGUuidGatherer walks each attachment SOG, collects all referenced asset UUIDs.&lt;br /&gt;
#* Fetches each asset from home grid&#039;s AssetServerURI (from AgentCircuitData.ServiceURLs).&lt;br /&gt;
#* 30-second timeout per asset fetch. On timeout: cancels all pending jobs for this avatar.&lt;br /&gt;
#* On completion: base.HandleIncomingAttachments() adds SOGs to scene.&lt;br /&gt;
* Foreign grid does NOT write to home grid&#039;s databases. Avatar&#039;s home presence/griduser records are already marked offline (step 5).&lt;br /&gt;
&lt;br /&gt;
; DB writes (foreign grid):&lt;br /&gt;
* None for standard avatar data. Foreign grid may cache fetched assets locally.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Part 2: Returning Home ==&lt;br /&gt;
&lt;br /&gt;
=== 1. TeleportHome Initiated ===&lt;br /&gt;
&lt;br /&gt;
 HGEntityTransferModule -- TeleportHome()&lt;br /&gt;
&lt;br /&gt;
# Avatar clicks &amp;quot;Teleport Home&amp;quot; or script calls llTeleportAgentHome().&lt;br /&gt;
# HGEntityTransferModule.TeleportHome() detects foreign user (IsLocalGridUser returns false).&lt;br /&gt;
# Gets HomeURI from AgentCircuitData.ServiceURLs.&lt;br /&gt;
# Creates UserAgentServiceConnector for home grid.&lt;br /&gt;
# Calls UserAgentService.GetHomeRegion(agentID) -- HTTP GET to home grid&#039;s UserAgent service.&lt;br /&gt;
#* Home UserAgent reads griduser table for HomeRegionID, HomePosition, HomeLookAt.&lt;br /&gt;
#* Returns GridRegion descriptor for home region.&lt;br /&gt;
# Constructs Gatekeeper GridRegion from HomeURI.&lt;br /&gt;
# Calls DoTeleport() with ViaHome flag.&lt;br /&gt;
&lt;br /&gt;
=== 2. Home Grid Re-entry ===&lt;br /&gt;
&lt;br /&gt;
Same protocol as any HG teleport but in reverse -- foreign grid is now source, home grid is destination.&lt;br /&gt;
&lt;br /&gt;
Home grid&#039;s Gatekeeper receives CreateAgent request. Home grid validates. Home grid&#039;s NewUserConnection() fires. Standard arrival sequence.&lt;br /&gt;
&lt;br /&gt;
On home grid arrival:&lt;br /&gt;
* TeleportFlags.ViaHGLogin is set.&lt;br /&gt;
* Home grid does NOT call PresenceService.LoginAgent() again -- the session was already established on initial login. A new session is established via the Gatekeeper flow.&lt;br /&gt;
* Baked texture validation skipped.&lt;br /&gt;
* Appearance data arrived via AgentData -- if RestrictAppearanceAbroad was enforced, avatar may arrive in restricted appearance.&lt;br /&gt;
&lt;br /&gt;
=== 3. Foreign Grid Logs Out ===&lt;br /&gt;
&lt;br /&gt;
 HGEntityTransferModule -- AgentHasMovedAway() (foreign grid side)&lt;br /&gt;
 HGEntityTransferModule -- OnConnectionClosed()&lt;br /&gt;
&lt;br /&gt;
# AgentHasMovedAway() with logout=true:&lt;br /&gt;
#* PresenceService.LogoutAgent() on foreign grid (clears foreign presence record if any).&lt;br /&gt;
#* GridUserService.LoggedOut() on foreign grid.&lt;br /&gt;
# OnConnectionClosed() fires when viewer disconnects from foreign grid:&lt;br /&gt;
#* For foreign user: calls UserAgentServiceConnector(homeURI).LogoutAgent() -- HTTP POST to home grid&#039;s UserAgent service notifying of departure.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Part 3: HG Landmark Teleport ==&lt;br /&gt;
&lt;br /&gt;
 HGEntityTransferModule -- RequestTeleportLandmark()&lt;br /&gt;
&lt;br /&gt;
# Landmark contains Gatekeeper URI + RegionID + position.&lt;br /&gt;
# If gatekeeper is local grid: falls back to normal landmark teleport.&lt;br /&gt;
# If foreign gatekeeper:&lt;br /&gt;
#* DNS-resolves the gatekeeper host.&lt;br /&gt;
#* Calls GatekeeperServiceConnector.GetHyperlinkRegion() -- resolves RegionID to GridRegion on foreign grid.&lt;br /&gt;
#* Calls ValidateGenericConditions() (appearance check).&lt;br /&gt;
#* Calls DoTeleport() -- standard HG teleport from here.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Client Verification ==&lt;br /&gt;
&lt;br /&gt;
 HGEntityTransferModule -- VerifyClient()&lt;br /&gt;
&lt;br /&gt;
Called by Scene.CheckClient() on first HTTP contact from a foreign avatar&#039;s viewer.&lt;br /&gt;
&lt;br /&gt;
# Gets HomeURI.&lt;br /&gt;
# Calls UserAgentServiceConnector(homeURI).VerifyClient(SessionID, token).&lt;br /&gt;
#* Home grid&#039;s UserAgent service confirms the session is valid.&lt;br /&gt;
# Returns false → scene removes circuit and closes 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 !! Grid !! Operation !! Step&lt;br /&gt;
|-&lt;br /&gt;
| presence || Home || UPDATE: Online=0 || Source logs out (step 5)&lt;br /&gt;
|-&lt;br /&gt;
| griduser || Home || UPDATE: LastPosition, Logout || Source logs out (step 5)&lt;br /&gt;
|-&lt;br /&gt;
| assets || Foreign || INSERT: fetched attachment assets || Incoming asset fetch (step 6)&lt;br /&gt;
|-&lt;br /&gt;
| presence || Foreign || UPDATE: session cleanup || Return/logout (part 2 step 3)&lt;br /&gt;
|-&lt;br /&gt;
| griduser || Foreign || UPDATE: LastPosition || Return/logout (part 2 step 3)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Key HG-specific Differences from Standard Teleport ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Aspect !! Standard Teleport !! HG Teleport&lt;br /&gt;
|-&lt;br /&gt;
| CreateAgent || SimulationService.CreateAgent() direct || UserAgentService.LoginAgentToGrid() via home grid&lt;br /&gt;
|-&lt;br /&gt;
| logout flag || false || true&lt;br /&gt;
|-&lt;br /&gt;
| Source logs out || No || Yes (PresenceService + GridUserService)&lt;br /&gt;
|-&lt;br /&gt;
| NeedsClosing || Only if OutViewRange || Always&lt;br /&gt;
|-&lt;br /&gt;
| Attachment fetch || Carried in AgentData || Async HGUuidGatherer from foreign AssetServer&lt;br /&gt;
|-&lt;br /&gt;
| Baked texture validation || Yes || No (ViaHGLogin)&lt;br /&gt;
|-&lt;br /&gt;
| OnConnectionClosed || Base handler || Also notifies home UserAgent service&lt;br /&gt;
|-&lt;br /&gt;
| TeleportHome || GridUserService.GetHomeRegion || UserAgentService.GetHomeRegion&lt;br /&gt;
|}&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/HGEntityTransferModule]]&lt;br /&gt;
* [[OpenSimulator Internals/Code Map/EntityTransferModule]]&lt;br /&gt;
* [[OpenSimulator Internals/Code Map/ROBUST/GatekeeperService]]&lt;br /&gt;
* [[OpenSimulator Internals/Code Map/ROBUST/UserAgentService]]&lt;br /&gt;
* [[OpenSimulator Internals/Connector Architecture/Gatekeeper Connector]]&lt;br /&gt;
* [[OpenSimulator Internals/Connector Architecture/UserAgent Connector]]&lt;br /&gt;
* [[OpenSimulator Internals/Walkthroughs/Avatar Transfer Between Regions]]&lt;br /&gt;
* [[OpenSimulator Internals/Walkthroughs/Avatar Rez In Region]]&lt;/div&gt;</summary>
		<author><name>Jwbshaw</name></author>
	</entry>
	<entry>
		<id>http://osimdev.org/wiki/index.php?title=OpenSimulator_Internals/Walkthroughs/Avatar_Transfer_Between_Regions&amp;diff=85</id>
		<title>OpenSimulator Internals/Walkthroughs/Avatar Transfer Between Regions</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"/>
		<updated>2026-07-07T13:09:43Z</updated>

		<summary type="html">&lt;p&gt;Jwbshaw: first&lt;/p&gt;
&lt;hr /&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&#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&#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&#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&#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&#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&#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>
	<entry>
		<id>http://osimdev.org/wiki/index.php?title=OpenSimulator_Internals/Walkthroughs/Avatar_Logs_Out&amp;diff=84</id>
		<title>OpenSimulator Internals/Walkthroughs/Avatar Logs Out</title>
		<link rel="alternate" type="text/html" href="http://osimdev.org/wiki/index.php?title=OpenSimulator_Internals/Walkthroughs/Avatar_Logs_Out&amp;diff=84"/>
		<updated>2026-07-07T13:06:06Z</updated>

		<summary type="html">&lt;p&gt;Jwbshaw: first&lt;/p&gt;
&lt;hr /&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&#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&#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&#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>
	<entry>
		<id>http://osimdev.org/wiki/index.php?title=OpenSimulator_Internals/Walkthroughs/Avatar_Change_Outfit&amp;diff=83</id>
		<title>OpenSimulator Internals/Walkthroughs/Avatar Change Outfit</title>
		<link rel="alternate" type="text/html" href="http://osimdev.org/wiki/index.php?title=OpenSimulator_Internals/Walkthroughs/Avatar_Change_Outfit&amp;diff=83"/>
		<updated>2026-07-07T13:04:31Z</updated>

		<summary type="html">&lt;p&gt;Jwbshaw: first&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= OpenSimulator Internals/Walkthroughs/Avatar Change Outfit =&lt;br /&gt;
&lt;br /&gt;
== Overview ==&lt;br /&gt;
&lt;br /&gt;
Traces what happens in code, connectors, and database when an avatar changes outfit -- replacing wearables and rebaking appearance textures.&lt;br /&gt;
&lt;br /&gt;
This covers the standard viewer-initiated outfit change. The sequence differs slightly between V1-style viewers (AvatarIsWearing only) and V2/3 viewers (AvatarIsWearing followed by AgentSetAppearance with baked textures).&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== 1. Viewer Sends AvatarIsWearing ==&lt;br /&gt;
&lt;br /&gt;
 OpenSim/Region/CoreModules/Avatar/AvatarFactory/AvatarFactoryModule.cs -- Client_OnAvatarNowWearing()&lt;br /&gt;
&lt;br /&gt;
# Avatar selects new outfit or drags wearable items onto avatar in viewer.&lt;br /&gt;
# Viewer sends AvatarIsWearing packet listing new wearable ItemIDs by WearableType slot.&lt;br /&gt;
# AvatarFactoryModule.Client_OnAvatarNowWearing() fires.&lt;br /&gt;
# Makes a copy of current AvatarAppearance (without textures).&lt;br /&gt;
# Updates Wearables array on the copy: sets ItemID for each type, AssetID = UUID.Zero initially.&lt;br /&gt;
# Calls avatAppearance.GetAssetsFrom(sp.Appearance) -- fills in known AssetIDs from current appearance where ItemID matches.&lt;br /&gt;
# Under m_setAppearanceLock: writes sp.Appearance.Wearables only. Does NOT overwrite baked textures or visual params.&lt;br /&gt;
# Calls QueueAppearanceSave() -- schedules async save after m_savetime (default 5s).&lt;br /&gt;
&lt;br /&gt;
Note: No appearance send at this step. The viewer will bake and send new textures next.&lt;br /&gt;
&lt;br /&gt;
; No DB writes yet (save is queued, not executed).&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== 2. Viewer Bakes New Textures Locally ==&lt;br /&gt;
&lt;br /&gt;
This step happens entirely on the viewer side. No server involvement.&lt;br /&gt;
&lt;br /&gt;
* Viewer composites the new wearable assets (clothing layers, skin, etc.) into baked texture images for each BakeType (Head, UpperBody, LowerBody, Eyes, Skirt, Hair, and PBR variants).&lt;br /&gt;
* Viewer uploads baked texture assets to the region&#039;s asset upload cap.&lt;br /&gt;
* Assets arrive at AssetService and are stored (temporary=true, local=true initially).&lt;br /&gt;
&lt;br /&gt;
; DB writes (via AssetService):&lt;br /&gt;
* assets -- INSERT: each new baked texture asset (temporary, local)&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== 3. Viewer Sends AgentSetAppearance ==&lt;br /&gt;
&lt;br /&gt;
 OpenSim/Region/CoreModules/Avatar/AvatarFactory/AvatarFactoryModule.cs -- Client_OnSetAppearance() → SetAppearance()&lt;br /&gt;
&lt;br /&gt;
# Viewer sends AgentSetAppearance packet containing:&lt;br /&gt;
#* New TextureEntry -- baked texture UUIDs for each face index.&lt;br /&gt;
#* New VisualParams -- slider values (height, body shape, etc.).&lt;br /&gt;
#* WearableCacheItems -- CacheId/TextureID pairs for each bake index.&lt;br /&gt;
#* AvatarSize vector.&lt;br /&gt;
# AvatarFactoryModule.SetAppearance() called under m_setAppearanceLock.&lt;br /&gt;
# Calls sp.Appearance.SetVisualParams() -- updates slider bytes, recalculates avatar height if changed.&lt;br /&gt;
# Calls sp.Appearance.SetTextureEntries() -- updates baked texture UUIDs in appearance.&lt;br /&gt;
# Calls UpdateBakedTextureCache():&lt;br /&gt;
#* Checks local IAssetCache for each baked texture asset.&lt;br /&gt;
#* Updates WearableCacheItems with confirmed TextureID and CacheId.&lt;br /&gt;
#* If any textures missing from cache: sends SendRebakeAvatarTextures() -- viewer must re-upload. Throttled to one request per texture per 30 seconds.&lt;br /&gt;
#* If full set valid and changed: stores to IBakedTextureModule (bake server cache).&lt;br /&gt;
# Calls QueueAppearanceSave() (appearance changed).&lt;br /&gt;
# Calls QueueAppearanceSend().&lt;br /&gt;
&lt;br /&gt;
; No immediate DB writes -- both saves are queued.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== 4. Appearance Sent to Other Clients (Deferred) ==&lt;br /&gt;
&lt;br /&gt;
 AvatarFactoryModule.HandleAppearanceUpdateTimer() → SendAppearance()&lt;br /&gt;
&lt;br /&gt;
After m_sendtime (default 2s), timer drains m_sendqueue:&lt;br /&gt;
&lt;br /&gt;
# Calls sp.SendAppearanceToAllOtherAgents():&lt;br /&gt;
#* Iterates all root ScenePresences.&lt;br /&gt;
#* Calls ControllingClient.SendAppearance() for each -- sends AvatarAppearance packet with new VisualParams and baked texture bytes.&lt;br /&gt;
#* Respects parcel visibility (ParcelHideThisAvatar).&lt;br /&gt;
# Calls Animator.SendAnimPack() -- sends current animation state.&lt;br /&gt;
&lt;br /&gt;
Other clients now render the avatar with the new appearance.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== 5. Appearance Saved to AvatarService (Deferred) ==&lt;br /&gt;
&lt;br /&gt;
 AvatarFactoryModule.HandleAppearanceUpdateTimer() → SaveAppearance()&lt;br /&gt;
&lt;br /&gt;
After m_savetime (default 5s), timer drains m_savequeue. Runs on thread pool.&lt;br /&gt;
&lt;br /&gt;
# Calls SetAppearanceAssets():&lt;br /&gt;
#* For each wearable slot: calls InventoryService.GetItem(userID, itemID) -- resolves ItemID to AssetID.&lt;br /&gt;
#* If item not found: removes wearable from appearance, logs warning.&lt;br /&gt;
#* Ignores Ruth default wearables.&lt;br /&gt;
# Calls m_scene.AvatarService.SetAppearance(agentID, sp.Appearance):&lt;br /&gt;
#* Connector: HTTP PUT to ROBUST AvatarService.&lt;br /&gt;
#* ROBUST writes avatarappearance table (wearable list, texture entry, visual params) and avatarattachments table.&lt;br /&gt;
&lt;br /&gt;
; DB writes:&lt;br /&gt;
* inventoryitems -- SELECT: resolve each wearable ItemID to AssetID&lt;br /&gt;
* avatarappearance -- UPDATE: new wearable list, texture entry, visual params&lt;br /&gt;
* avatarattachments -- UPDATE: current attachment list&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== 6. Attachments Changed (if outfit includes attachment changes) ==&lt;br /&gt;
&lt;br /&gt;
 OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs&lt;br /&gt;
&lt;br /&gt;
If the outfit change includes adding or removing attachments, the viewer sends separate RezSingleAttachmentFromInv / DetachAttachmentIntoInv packets independently of the appearance packets above.&lt;br /&gt;
&lt;br /&gt;
Adding an attachment:&lt;br /&gt;
# Client_OnRezSingleAttachmentFromInv() fires.&lt;br /&gt;
# RezSingleAttachmentFromInventory() checks not already worn.&lt;br /&gt;
# RezSingleAttachmentFromInventoryInternal() calls IInventoryAccessModule.RezObject() -- fetches asset, deserialises SOG, adds to scene.&lt;br /&gt;
# AttachObjectInternal() attaches to avatar, displaces any existing attachment at same point (if WearReplacesAll=true).&lt;br /&gt;
# UpdateUserInventoryWithAttachment() updates inventory item to reflect attachment point.&lt;br /&gt;
# ShowAttachInUserInventory() calls sp.Appearance.SetAttachment() and QueueAppearanceSave().&lt;br /&gt;
# Scripts created and started (CreateScriptInstances, ResumeScripts).&lt;br /&gt;
# TriggerOnAttach() fires.&lt;br /&gt;
&lt;br /&gt;
Removing an attachment:&lt;br /&gt;
# Client_OnDetachAttachmentIntoInv() fires.&lt;br /&gt;
# DetachSingleAttachmentToInv() called -- see [[OpenSimulator Internals/Code Map/AttachmentsModule]].&lt;br /&gt;
# Script state snapshotted, object removed from scene, asset and inventory item updated.&lt;br /&gt;
&lt;br /&gt;
; DB writes (per attachment change):&lt;br /&gt;
* assets -- INSERT: updated attachment object asset (serialised XML)&lt;br /&gt;
* inventoryitems -- UPDATE: new assetID, attach point&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 || Viewer uploads baked textures (step 2)&lt;br /&gt;
|-&lt;br /&gt;
| inventoryitems || SELECT || SetAppearanceAssets() resolves wearable AssetIDs (step 5)&lt;br /&gt;
|-&lt;br /&gt;
| avatarappearance || UPDATE || AvatarService.SetAppearance() (step 5)&lt;br /&gt;
|-&lt;br /&gt;
| avatarattachments || UPDATE || AvatarService.SetAppearance() (step 5)&lt;br /&gt;
|-&lt;br /&gt;
| assets || INSERT || Attachment object re-saved (step 6, if attachments changed)&lt;br /&gt;
|-&lt;br /&gt;
| inventoryitems || UPDATE || Attachment inventory item updated (step 6, if attachments changed)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Timing Notes ==&lt;br /&gt;
&lt;br /&gt;
* Appearance send is deferred 2s (m_sendtime) -- prevents flooding if multiple rapid changes.&lt;br /&gt;
* Appearance save is deferred 5s (m_savetime) -- ensures all wearable asset uploads complete before inventory lookup.&lt;br /&gt;
* Both delays are configurable in [Appearance] section of OpenSim.ini.&lt;br /&gt;
* The AvatarIsWearing and AgentSetAppearance packets often arrive nearly simultaneously. m_setAppearanceLock ensures AvatarIsWearing does not overwrite SetAppearance texture changes.&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/AvatarFactoryModule]]&lt;br /&gt;
* [[OpenSimulator Internals/Code Map/AttachmentsModule]]&lt;br /&gt;
* [[OpenSimulator Internals/Code Map/ScenePresence]]&lt;br /&gt;
* [[OpenSimulator Internals/Code Map/ROBUST/AvatarService]]&lt;br /&gt;
* [[OpenSimulator Internals/Walkthroughs/Avatar Rez In Region]]&lt;br /&gt;
* [[OpenSimulator Internals/Walkthroughs/Avatar Logs Out]]&lt;/div&gt;</summary>
		<author><name>Jwbshaw</name></author>
	</entry>
	<entry>
		<id>http://osimdev.org/wiki/index.php?title=OpenSimulator_Internals/Walkthroughs/Avatar_Rez_In_Region&amp;diff=82</id>
		<title>OpenSimulator Internals/Walkthroughs/Avatar Rez In Region</title>
		<link rel="alternate" type="text/html" href="http://osimdev.org/wiki/index.php?title=OpenSimulator_Internals/Walkthroughs/Avatar_Rez_In_Region&amp;diff=82"/>
		<updated>2026-07-07T12:58:51Z</updated>

		<summary type="html">&lt;p&gt;Jwbshaw: first&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= OpenSimulator Internals/Walkthroughs/Avatar Rez In Region =&lt;br /&gt;
&lt;br /&gt;
== Overview ==&lt;br /&gt;
&lt;br /&gt;
Traces what happens in code, connectors, and database from the moment a viewer completes login and connects to a region, through to the avatar standing in-world with appearance applied and scene state sent.&lt;br /&gt;
&lt;br /&gt;
This covers the normal login case (not HG, not region transfer). See [[OpenSimulator Internals/Walkthroughs/Avatar Transfer Between Regions]] and [[OpenSimulator Internals/Walkthroughs/Avatar Goes HG]] for those paths.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== 1. Login Service Issues Seed Capability ==&lt;br /&gt;
&lt;br /&gt;
 OpenSim/Services/LLLoginService/LLLoginService.cs&lt;br /&gt;
 OpenSim/Server/Handlers/Login/LLLoginHandlers.cs&lt;br /&gt;
&lt;br /&gt;
# Viewer POSTs login credentials to ROBUST LoginService (port 8002 by default) via XMLRPC.&lt;br /&gt;
# LLLoginService authenticates via AuthenticationService, loads UserAccount, fetches appearance via AvatarService.&lt;br /&gt;
# LoginService calls PresenceService.LoginAgent() -- writes presence row: UserID, RegionID, SessionID, SecureSessionID, Online=1.&lt;br /&gt;
# LoginService calls GridUserService.SetLastPosition() -- updates griduser: LastRegionID, LastPosition, Login timestamp.&lt;br /&gt;
# LoginService selects destination region via GridService -- reads from regions table.&lt;br /&gt;
# LoginService calls the destination region&#039;s NewUserConnection capability -- passes AgentCircuitData (agent UUID, session UUID, circuit code, appearance, teleport flags). This pre-populates AgentCircuitManager in the region before the viewer connects.&lt;br /&gt;
# LoginService returns login response to viewer: SimIP, SimPort, RegionX/Y, SeedCapability URL, circuit code, session UUIDs.&lt;br /&gt;
&lt;br /&gt;
; DB writes:&lt;br /&gt;
* presence -- INSERT or UPDATE: UserID, RegionID, SessionID, SecureSessionID, Online=1&lt;br /&gt;
* griduser -- UPDATE: LastRegionID, LastPosition, Login timestamp&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== 2. Viewer Establishes UDP Circuit ==&lt;br /&gt;
&lt;br /&gt;
 OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs&lt;br /&gt;
&lt;br /&gt;
# Viewer sends UseCircuitCode packet to region UDP port.&lt;br /&gt;
# LLUDPServer.HandleUseCircuitCode() validates circuit code against AgentCircuitManager (pre-populated in step 1).&lt;br /&gt;
# On match: LLUDPClient created. LLClientView constructed and associated with the circuit.&lt;br /&gt;
# ScenePresence constructed:&lt;br /&gt;
#* IsChildAgent = true initially (set in constructor)&lt;br /&gt;
#* Constructor fetches UserAccount for god level and user flags&lt;br /&gt;
#* Constructor calls RegisterToClientEvents() -- wires OnCompleteMovementToRegion → CompleteMovement, OnAgentUpdate → HandleAgentUpdate, OnRegionHandShakeReply → RegionHandShakeReply, and others&lt;br /&gt;
#* Appearance set from AgentCircuitData appearance passed by LoginService&lt;br /&gt;
#* AdjustKnownSeeds() called -- initialises known neighbour region cap seeds&lt;br /&gt;
&lt;br /&gt;
; No DB writes at this step.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== 3. Viewer Sends CompleteMovementToRegion ==&lt;br /&gt;
&lt;br /&gt;
 OpenSim/Region/Framework/Scenes/ScenePresence.cs -- CompleteMovement()&lt;br /&gt;
&lt;br /&gt;
The viewer fires CompleteMovementToRegion after receiving the circuit acknowledgement. This triggers ScenePresence.CompleteMovement() on the region side.&lt;br /&gt;
&lt;br /&gt;
# For login (IsRealLogin true): does NOT wait for UpdateAgent -- skips WaitForUpdateAgent(). For teleports and crossings: waits up to 10 seconds for the source region&#039;s UpdateAgent call to arrive before proceeding.&lt;br /&gt;
# Checks flying state from AgentControlFlags.&lt;br /&gt;
# Calls MakeRootAgent() (see step 4).&lt;br /&gt;
# If not a cross-update: fetches group title via IGroupsModule.&lt;br /&gt;
# Rotates avatar to look direction.&lt;br /&gt;
# Initialises parcel tracking (m_currentParcelUUID, m_currentParcelHide).&lt;br /&gt;
# Sets m_inTransit = false.&lt;br /&gt;
# Sends RegionHandshake to viewer (ControllingClient.SendRegionHandshake()) if not a crossing.&lt;br /&gt;
# Calls ControllingClient.MoveAgentIntoRegion() -- sends the viewer its position and look.&lt;br /&gt;
# Validates baked texture cache via AvatarFactory. Queues appearance save if invalid.&lt;br /&gt;
# Sends initial avatar data to all presences (SendInitialAvatarDataToAllAgents()).&lt;br /&gt;
# Sends this avatar&#039;s appearance to self (SendAppearanceToAgent(this)).&lt;br /&gt;
# Sends current animation pack to self.&lt;br /&gt;
# Sends appearance and animations to all other presences (parcel visibility respected).&lt;br /&gt;
# Rezzes attachments: for real login, calls Scene.AttachmentsModule.RezAttachments(this).&lt;br /&gt;
# For login (not cross-update): calls IFriendsModule.SendFriendsOnlineIfNeeded().&lt;br /&gt;
# Hooks RegionHeartbeatEnd event for per-frame health regen and movement animation updates.&lt;br /&gt;
&lt;br /&gt;
; No DB writes at this step (appearance save is queued async if needed).&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== 4. MakeRootAgent() ==&lt;br /&gt;
&lt;br /&gt;
 OpenSim/Region/Framework/Scenes/ScenePresence.cs -- MakeRootAgent()&lt;br /&gt;
&lt;br /&gt;
Called from CompleteMovement(). This is the critical path; delay here delays the crossing.&lt;br /&gt;
&lt;br /&gt;
# Acquires m_completeMovementLock. Returns false immediately if already root agent (IsChildAgent == false).&lt;br /&gt;
# Handles pending sit: if ParentUUID is set, resolves the sit target prim and re-seats the avatar.&lt;br /&gt;
# Sets IsChildAgent = false.&lt;br /&gt;
# Updates RegionHandle to this region.&lt;br /&gt;
# Fires EventManager.TriggerSetRootAgentScene().&lt;br /&gt;
# Position adjustment (if not sitting):&lt;br /&gt;
#* Checks and adjusts landing point (telehub, parcel landing point, ban lines) via CheckAndAdjustLandingPoint_OS() or _SL().&lt;br /&gt;
#* Clamps position to region bounds.&lt;br /&gt;
#* Raises position to ground height + avatar half-height.&lt;br /&gt;
#* If ViaLogin or ViaLocation flags set: raycasts downward from PhysSearchHeight (300m) to find surface, adjusts Z to avoid being inside objects.&lt;br /&gt;
#* Sets AbsolutePosition.&lt;br /&gt;
#* Calls AddToPhysicalScene(isFlying) -- creates PhysicsActor, enters physics simulation.&lt;br /&gt;
# Calls m_scene.SwapRootAgentCount(false, IsNPC) -- increments root agent count.&lt;br /&gt;
# Resets MovementFlags to 0.&lt;br /&gt;
# Updates circuit child status: AuthenticateHandler.UpdateAgentChildStatus(circuitCode, false).&lt;br /&gt;
# Fires EventManager.TriggerOnMakeRootAgent(this) -- modules hook here.&lt;br /&gt;
&lt;br /&gt;
; No DB writes at this step.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== 5. RegionHandshake / SendInitialData ==&lt;br /&gt;
&lt;br /&gt;
 OpenSim/Region/Framework/Scenes/ScenePresence.cs -- RegionHandShakeReply(), SendInitialData()&lt;br /&gt;
&lt;br /&gt;
# Viewer sends RegionHandshakeReply in response to the handshake sent in step 3.&lt;br /&gt;
# RegionHandShakeReply() sets m_gotRegionHandShake = true and NeedInitialData = 2.&lt;br /&gt;
# On subsequent heartbeat frames, Update() checks NeedInitialData &amp;gt; 0 and calls SendInitialData().&lt;br /&gt;
# SendInitialData() waits for viewer caps seeds to be sent (ViewerFlags.SentSeeds), then waits a few more frames for the viewer to process them (NeedInitialData incremented to 6 before proceeding).&lt;br /&gt;
# When ready, fires async via Util.FireAndForget:&lt;br /&gt;
#* Releases source region if callback URI present (v1 or v0.7 HG path).&lt;br /&gt;
#* Closes old child agents via IEntityTransferModule.CloseOldChildAgents().&lt;br /&gt;
#* Sends terrain layer data (Scene.SendLayerData()) if not a teleport.&lt;br /&gt;
#* Sends parcel info (LandChannel.sendClientInitialLandInfo()).&lt;br /&gt;
#* Sends full updates for all other root presences&#039; avatars (SendOtherAgentsAvatarFullToMe()).&lt;br /&gt;
#* Sends ObjectUpdate packets for all scene objects within draw distance -- either full updates or cache probes depending on viewer cache state.&lt;br /&gt;
#* Creates child agents in neighbouring regions via IEntityTransferModule.EnableChildAgents(this).&lt;br /&gt;
#* Enables child update processing (m_childUpdatesBusy = false).&lt;br /&gt;
&lt;br /&gt;
; No DB writes at this step.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== 6. Attachments Rezzed ==&lt;br /&gt;
&lt;br /&gt;
 OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs -- RezAttachments()&lt;br /&gt;
&lt;br /&gt;
Called from CompleteMovement() for real logins (IsRealLogin true). For teleports/crossings, attachments are carried in AgentData and scripts restarted via RestartAttachmentScripts() instead.&lt;br /&gt;
&lt;br /&gt;
# For each attachment in appearance data: fetches inventory item from InventoryService.&lt;br /&gt;
# Fetches asset from AssetService.&lt;br /&gt;
# Rezzes SceneObjectGroup in world at attachment point.&lt;br /&gt;
# Note: method name typo IncomingAttechments() exists at Scene.cs line 2976 and AttachmentsModule.cs line 384 (Mantis pending).&lt;br /&gt;
&lt;br /&gt;
; DB reads:&lt;br /&gt;
* inventoryitems -- SELECT by item UUID for each attachment&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== 7. Presence and GridUser Updated ==&lt;br /&gt;
&lt;br /&gt;
 OpenSim/Services/Connectors/Presence/PresenceServicesConnector.cs&lt;br /&gt;
 OpenSim/Services/Connectors/GridUser/GridUserServicesConnector.cs&lt;br /&gt;
&lt;br /&gt;
After MakeRootAgent and CompleteMovement complete, the region confirms the avatar&#039;s position:&lt;br /&gt;
&lt;br /&gt;
# PresenceService.ReportAgent() -- updates presence table, confirms RegionID.&lt;br /&gt;
# GridUserService.SetLastPosition() -- updates griduser with confirmed in-region position and look.&lt;br /&gt;
&lt;br /&gt;
; DB writes:&lt;br /&gt;
* presence -- UPDATE: RegionID confirmed for this session&lt;br /&gt;
* griduser -- UPDATE: LastPosition, LastLookAt, LastRegionID&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;
| presence || INSERT/UPDATE || LoginService (step 1)&lt;br /&gt;
|-&lt;br /&gt;
| griduser || UPDATE || LoginService (step 1), post-rez (step 7)&lt;br /&gt;
|-&lt;br /&gt;
| regions || SELECT || LoginService destination lookup (step 1)&lt;br /&gt;
|-&lt;br /&gt;
| avatarappearance || SELECT || LoginService via AvatarService (step 1)&lt;br /&gt;
|-&lt;br /&gt;
| avatarattachments || SELECT || LoginService via AvatarService (step 1)&lt;br /&gt;
|-&lt;br /&gt;
| inventoryitems || SELECT || AttachmentsModule.RezAttachments() (step 6)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Note: avatarappearance and avatarattachments are read by LoginService, not by the region directly -- the appearance data travels to the region inside AgentCircuitData.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Key Flags ==&lt;br /&gt;
&lt;br /&gt;
* TeleportFlags.ViaLogin | TeleportFlags.ViaRegionID -- set for normal login. Controls landing point behavior, telehub routing, and whether WaitForUpdateAgent() is skipped.&lt;br /&gt;
* TeleportFlags.ViaHGLogin -- HG login path; triggers different appearance handling and skips baked texture validation.&lt;br /&gt;
* IsRealLogin() -- returns true only for ViaLogin without ViaHGLogin. Determines whether attachments are freshly rezzed vs carried from source region.&lt;br /&gt;
* m_gotCrossUpdate -- false for login, true for region crossings. Controls whether SendLayerData and child agent setup are deferred.&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/ROBUST/LoginService]]&lt;br /&gt;
* [[OpenSimulator Internals/Code Map/ROBUST/PresenceService]]&lt;br /&gt;
* [[OpenSimulator Internals/Code Map/ROBUST/AvatarService]]&lt;br /&gt;
* [[OpenSimulator Internals/Code Map/Scene]]&lt;br /&gt;
* [[OpenSimulator Internals/Code Map/LLClientView]]&lt;br /&gt;
* [[OpenSimulator Internals/Connector Architecture/Presence Connector]]&lt;br /&gt;
* [[OpenSimulator Internals/Connector Architecture/Avatar Connector]]&lt;br /&gt;
* [[OpenSimulator Internals/Walkthroughs/Avatar Transfer Between Regions]]&lt;br /&gt;
* [[OpenSimulator Internals/Walkthroughs/Avatar Goes HG]]&lt;/div&gt;</summary>
		<author><name>Jwbshaw</name></author>
	</entry>
	<entry>
		<id>http://osimdev.org/wiki/index.php?title=OpenSimulator_Internals/Connector_Architecture&amp;diff=81</id>
		<title>OpenSimulator Internals/Connector Architecture</title>
		<link rel="alternate" type="text/html" href="http://osimdev.org/wiki/index.php?title=OpenSimulator_Internals/Connector_Architecture&amp;diff=81"/>
		<updated>2026-07-07T12:31:57Z</updated>

		<summary type="html">&lt;p&gt;Jwbshaw: more stuff&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
&lt;br /&gt;
= OpenSimulator Internals/Connector Architecture =&lt;br /&gt;
&lt;br /&gt;
== Overview ==&lt;br /&gt;
&lt;br /&gt;
Connectors are the HTTP client layer that sits between region simulators and ROBUST grid services. Each connector implements a service interface (e.g. IAssetService, IPresenceService) using HTTP calls to the corresponding ROBUST handler.&lt;br /&gt;
&lt;br /&gt;
The same interface may be implemented by:&lt;br /&gt;
* A local connector -- calls the service directly in-process (standalone mode or co-located services).&lt;br /&gt;
* A remote connector -- makes HTTP calls to a ROBUST server.&lt;br /&gt;
* An HG connector -- wraps the remote connector with hypergrid-specific logic.&lt;br /&gt;
&lt;br /&gt;
Region code calls only the interface. Which implementation is loaded depends on configuration ([Architecture] section of the ini files).&lt;br /&gt;
&lt;br /&gt;
See [[OpenSimulator Internals/ROBUST Services]] for the server-side service implementations.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Connector Pattern ==&lt;br /&gt;
&lt;br /&gt;
All remote connectors follow the same pattern:&lt;br /&gt;
&lt;br /&gt;
# Constructor receives IConfigSource and reads the service URL from config.&lt;br /&gt;
# Each method serialises parameters to a REST or XMLRPC request.&lt;br /&gt;
# Sends HTTP POST/GET/DELETE to the ROBUST handler endpoint.&lt;br /&gt;
# Deserialises the response and returns the result.&lt;br /&gt;
&lt;br /&gt;
The HTTP client layer is WebUtil (OpenSim/Framework/WebUtil.cs), which handles serialisation, connection pooling, and error logging.&lt;br /&gt;
&lt;br /&gt;
See [[OpenSimulator Internals/Connector Architecture/Asset Connector]] for a fully worked example of the pattern including both client and server-side handler code.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Individual Connector Pages ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Connector !! Service Interface !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| [[OpenSimulator Internals/Connector Architecture/Asset Connector]] || IAssetService || Includes server-side handler detail. HG variant wraps with foreign asset server logic.&lt;br /&gt;
|-&lt;br /&gt;
| [[OpenSimulator Internals/Connector Architecture/GridUser Connector]] || IGridUserService || Tracks last position, login/logout timestamps, home region.&lt;br /&gt;
|-&lt;br /&gt;
| [[OpenSimulator Internals/Connector Architecture/Presence Connector]] || IPresenceService || Online status, session tracking, region assignment.&lt;br /&gt;
|-&lt;br /&gt;
| [[OpenSimulator Internals/Connector Architecture/UserAccount Connector]] || IUserAccountService || User account CRUD. Known bug: CreateUser() sends first name as email value.&lt;br /&gt;
|-&lt;br /&gt;
| [[OpenSimulator Internals/Connector Architecture/Inventory Connector]] || IInventoryService || XInventory protocol. UpdateFolder() URL-encodes Name; AddFolder() does not.&lt;br /&gt;
|-&lt;br /&gt;
| [[OpenSimulator Internals/Connector Architecture/Authentication Connector]] || IAuthenticationService || Password and token authentication, impersonation mechanism.&lt;br /&gt;
|-&lt;br /&gt;
| [[OpenSimulator Internals/Connector Architecture/Avatar Connector]] || IAvatarService || Appearance storage. ResetAvatar() log erroneously says &amp;quot;SetItems reply&amp;quot;.&lt;br /&gt;
|-&lt;br /&gt;
| [[OpenSimulator Internals/Connector Architecture/Friends Connector]] || IFriendsService || Friend list, online notifications.&lt;br /&gt;
|-&lt;br /&gt;
| [[OpenSimulator Internals/Connector Architecture/Grid Connector]] || IGridService || Region registration, lookup, neighbour queries.&lt;br /&gt;
|-&lt;br /&gt;
| [[OpenSimulator Internals/Connector Architecture/Simulation Connector]] || ISimulationService || Inter-simulator agent and object transfer. QueryAccess, CreateAgent, UpdateAgent, CloseAgent, CreateObject.&lt;br /&gt;
|-&lt;br /&gt;
| [[OpenSimulator Internals/Connector Architecture/UserAgent Connector]] || IUserAgentService || HG-only. Home region lookup, login to foreign grid, session verification.&lt;br /&gt;
|-&lt;br /&gt;
| [[OpenSimulator Internals/Connector Architecture/Gatekeeper Connector]] || IGatekeeperService || HG-only. Foreign grid entry point. GetHyperlinkRegion, LoginAgentToGrid.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== HG Connectors ==&lt;br /&gt;
&lt;br /&gt;
HyperGrid introduces additional connectors that wrap or replace the standard ones:&lt;br /&gt;
&lt;br /&gt;
* UserAgent Connector -- used by the source grid to contact the avatar&#039;s home grid UserAgent service during HG teleport.&lt;br /&gt;
* Gatekeeper Connector -- used to contact a foreign grid&#039;s Gatekeeper during HG destination resolution.&lt;br /&gt;
* HGAsset Connector -- used by HGInventoryAccessModule to fetch/push assets between grids (via HGAssetMapper).&lt;br /&gt;
&lt;br /&gt;
These are documented in the individual connector pages above and in:&lt;br /&gt;
* [[OpenSimulator Internals/Code Map/HGEntityTransferModule]]&lt;br /&gt;
* [[OpenSimulator Internals/Code Map/InventoryAccessModule]]&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Configuration ==&lt;br /&gt;
&lt;br /&gt;
Connectors are selected in the [Architecture] ini include files:&lt;br /&gt;
&lt;br /&gt;
* config-include/StandaloneCommon.ini -- standalone mode, services loaded in-process.&lt;br /&gt;
* config-include/GridCommon.ini -- grid mode, remote connectors used.&lt;br /&gt;
* config-include/HGCommon.ini -- hypergrid additions.&lt;br /&gt;
&lt;br /&gt;
The [ServiceList] section of Robust.ini selects which ROBUST handlers are loaded. The [Modules] section of OpenSim.ini selects which connectors the simulator loads.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== See Also ==&lt;br /&gt;
&lt;br /&gt;
* [[OpenSimulator Internals/Code Map/ROBUST]]&lt;br /&gt;
* [[OpenSimulator Internals/ROBUST Services]]&lt;br /&gt;
* [[OpenSimulator Internals/Reading the Code]]&lt;br /&gt;
* [[OpenSimulator Internals/Code Map]]&lt;/div&gt;</summary>
		<author><name>Jwbshaw</name></author>
	</entry>
	<entry>
		<id>http://osimdev.org/wiki/index.php?title=OpenSimulator_Internals/Connector_Architecture/Gatekeeper_Connector&amp;diff=80</id>
		<title>OpenSimulator Internals/Connector Architecture/Gatekeeper Connector</title>
		<link rel="alternate" type="text/html" href="http://osimdev.org/wiki/index.php?title=OpenSimulator_Internals/Connector_Architecture/Gatekeeper_Connector&amp;diff=80"/>
		<updated>2026-07-07T12:24:34Z</updated>

		<summary type="html">&lt;p&gt;Jwbshaw: first&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= OpenSimulator Internals/Connector Architecture/Gatekeeper Connector =&lt;br /&gt;
&lt;br /&gt;
== Overview ==&lt;br /&gt;
&lt;br /&gt;
GatekeeperServiceConnector is the client-side connector used to talk to a foreign grid&#039;s GatekeeperService. It handles HG region linking, map tile retrieval, and region lookup. It extends SimulationServiceConnector, inheriting the agent and object transfer paths with overridden URL prefixes.&lt;br /&gt;
&lt;br /&gt;
Source file:&lt;br /&gt;
&lt;br /&gt;
 OpenSim/Services/Connectors/Hypergrid/GatekeeperServiceConnector.cs&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
=== Inheritance ===&lt;br /&gt;
&lt;br /&gt;
Extends SimulationServiceConnector. Overrides:&lt;br /&gt;
* AgentPath() -- returns &amp;quot;foreignagent/&amp;quot; instead of &amp;quot;agent/&amp;quot;&lt;br /&gt;
* ObjectPath() -- returns &amp;quot;foreignobject/&amp;quot; instead of &amp;quot;object/&amp;quot;&lt;br /&gt;
&lt;br /&gt;
This means CreateAgent() from the parent sends to destination.ServerURI + &amp;quot;foreignagent/&amp;quot; + agentID + &amp;quot;/&amp;quot; when called through this connector.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
=== Initialisation ===&lt;br /&gt;
&lt;br /&gt;
Two constructors:&lt;br /&gt;
* Default (no args) -- no asset service; GetMapImage() will return the default HG map tile UUID&lt;br /&gt;
* IAssetService argument -- asset service used by GetMapImage() to store downloaded map tiles&lt;br /&gt;
&lt;br /&gt;
No config file reading. The destination URI comes from GridRegion.ServerURI per call.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
=== Transport ===&lt;br /&gt;
&lt;br /&gt;
All non-inherited methods use XML-RPC via Nwc.XmlRpc over HTTP POST to the gatekeeper&#039;s ServerURI. 10-second timeout on all XML-RPC calls.&lt;br /&gt;
&lt;br /&gt;
Agent and object transfer methods are inherited from SimulationServiceConnector and use WebUtil OSD/REST.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
=== LinkRegion() ===&lt;br /&gt;
&lt;br /&gt;
 public bool LinkRegion(GridRegion info, out UUID regionID, out ulong realHandle,&lt;br /&gt;
     out string externalName, out string imageURL, out string reason, out int sizeX, out int sizeY)&lt;br /&gt;
&lt;br /&gt;
XML-RPC method: &amp;quot;link_region&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Sends: region_name&lt;br /&gt;
&lt;br /&gt;
On success parses: uuid, handle (as ulong), region_image, external_name, size_x, size_y. All fields checked for null before parsing. Default sizeX/sizeY is Constants.RegionSize if not provided.&lt;br /&gt;
&lt;br /&gt;
Returns false on connection error, XML-RPC fault, or parse exception.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
=== GetMapImage() ===&lt;br /&gt;
&lt;br /&gt;
 public UUID GetMapImage(UUID regionID, string imageURL, string storagePath)&lt;br /&gt;
&lt;br /&gt;
Downloads and stores a foreign region&#039;s map tile as an asset.&lt;br /&gt;
&lt;br /&gt;
Sequence:&lt;br /&gt;
# If no AssetService: returns m_HGMapImage (00000000-0000-1111-9999-000000000013) immediately&lt;br /&gt;
# Builds filename: storagePath + regionID + &amp;quot;.jpg&amp;quot;&lt;br /&gt;
# If file not on disk: downloads from imageURL via WebClient.DownloadFile()&lt;br /&gt;
# Opens as Bitmap, encodes to JPEG2000 via OpenJPEG.EncodeFromImage()&lt;br /&gt;
# Stores as AssetType.Texture with random UUID, name &amp;quot;region {regionID}&amp;quot;, creator = regionID&lt;br /&gt;
# Returns the stored asset UUID&lt;br /&gt;
&lt;br /&gt;
Exception handling: entire sequence wrapped in bare catch -- logs &amp;quot;probably already in the cache&amp;quot; and returns m_HGMapImage. This catches OpenJPEG p/invoke failures specifically (comment says &amp;quot;LEGIT&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
m_HGMapImage (00000000-0000-1111-9999-000000000013) is the fallback UUID returned on any failure.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
=== GetHyperlinkRegion() ===&lt;br /&gt;
&lt;br /&gt;
 public GridRegion GetHyperlinkRegion(GridRegion gatekeeper, UUID regionID, UUID agentID,&lt;br /&gt;
     string agentHomeURI, out string message)&lt;br /&gt;
&lt;br /&gt;
XML-RPC method: &amp;quot;get_region&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Sends: region_uuid; optionally agent_id and agent_home_uri if agentID is non-zero.&lt;br /&gt;
&lt;br /&gt;
On success parses full GridRegion: uuid, x, y, size_x, size_y, region_name, hostname, http_port, internal_port, server_uri. All fields null-checked before parsing.&lt;br /&gt;
&lt;br /&gt;
message handling:&lt;br /&gt;
* If hash[&amp;quot;message&amp;quot;] present: use it&lt;br /&gt;
* If success and no message: set message = null&lt;br /&gt;
* If failure and no message: set message = &amp;quot;The teleport destination could not be found.&amp;quot; (comment notes this is for old grids that don&#039;t send message)&lt;br /&gt;
&lt;br /&gt;
Returns null on connection error, XML-RPC fault, parse exception, or result == false.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
=== Notes ===&lt;br /&gt;
&lt;br /&gt;
* GetMapImage() uses the deprecated WebClient class for download. The comment &amp;quot;LEGIT&amp;quot; on the bare catch is the only documentation for why all exceptions are swallowed there.&lt;br /&gt;
* The fallback map tile UUID (00000000-0000-1111-9999-000000000013) is a static field -- the same UUID is returned for all failed map tile fetches regardless of region.&lt;br /&gt;
* Agent transfer uses &amp;quot;foreignagent/&amp;quot; path rather than &amp;quot;agent/&amp;quot; -- this is what distinguishes inbound HG agent traffic from local teleport traffic on the receiving simulator.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== See Also ==&lt;br /&gt;
&lt;br /&gt;
* [[OpenSimulator Internals/Connector Architecture]]&lt;br /&gt;
* [[OpenSimulator Internals/Connector Architecture/Simulation Connector]]&lt;br /&gt;
* [[OpenSimulator Internals/Connector Architecture/UserAgent Connector]]&lt;br /&gt;
* [[OpenSimulator Internals/Code Map/ROBUST/GatekeeperService]]&lt;/div&gt;</summary>
		<author><name>Jwbshaw</name></author>
	</entry>
	<entry>
		<id>http://osimdev.org/wiki/index.php?title=OpenSimulator_Internals/Connector_Architecture/UserAgent_Connector&amp;diff=79</id>
		<title>OpenSimulator Internals/Connector Architecture/UserAgent Connector</title>
		<link rel="alternate" type="text/html" href="http://osimdev.org/wiki/index.php?title=OpenSimulator_Internals/Connector_Architecture/UserAgent_Connector&amp;diff=79"/>
		<updated>2026-07-07T12:23:52Z</updated>

		<summary type="html">&lt;p&gt;Jwbshaw: first&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= OpenSimulator Internals/Connector Architecture/UserAgent Connector =&lt;br /&gt;
&lt;br /&gt;
== Overview ==&lt;br /&gt;
&lt;br /&gt;
UserAgentServiceConnector is the remote connector for IUserAgentService. It is used by foreign grids to talk to a home grid&#039;s UserAgentService -- verifying agents, getting home region info, and checking online friends. It extends SimulationServiceConnector, inheriting the agent transfer path and overriding the agent URL path.&lt;br /&gt;
&lt;br /&gt;
Source file:&lt;br /&gt;
&lt;br /&gt;
 OpenSim/Services/Connectors/Hypergrid/UserAgentServiceConnector.cs&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
=== Inheritance ===&lt;br /&gt;
&lt;br /&gt;
Extends SimulationServiceConnector. Overrides:&lt;br /&gt;
* AgentPath() -- returns &amp;quot;homeagent/&amp;quot; instead of &amp;quot;agent/&amp;quot;&lt;br /&gt;
* PackData() -- adds gatekeeper_serveruri, gatekeeper_host, gatekeeper_port, destination_serveruri to the OSD payload&lt;br /&gt;
&lt;br /&gt;
This means CreateAgent() from the parent class sends to destination.ServerURI + &amp;quot;homeagent/&amp;quot; + agentID + &amp;quot;/&amp;quot; when called through this connector.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
=== Initialisation ===&lt;br /&gt;
&lt;br /&gt;
Two constructors:&lt;br /&gt;
* String URL -- validates URI, normalizes to lowercase with trailing slash&lt;br /&gt;
* IConfigSource -- reads HomeURL from GridInfo; throws if missing or invalid&lt;br /&gt;
&lt;br /&gt;
No config section key -- the URL is taken from GridInfo.HomeURL, which reads from [Const], [Startup], or [Hypergrid] sections.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
=== Transport -- Two Protocols ===&lt;br /&gt;
&lt;br /&gt;
This connector uses two different transports depending on the method:&lt;br /&gt;
&lt;br /&gt;
Agent transfer (inherited from SimulationServiceConnector):&lt;br /&gt;
* LoginAgentToGrid() calls CreateAgent() -- uses WebUtil OSD/LLSD over HTTP POST/PUT to &amp;quot;homeagent/&amp;quot; path&lt;br /&gt;
&lt;br /&gt;
All other methods:&lt;br /&gt;
* Use XML-RPC via Nwc.XmlRpc over HTTP POST to m_ServerURL&lt;br /&gt;
* CallServer() is the shared helper for XML-RPC calls that return a Hashtable&lt;br /&gt;
* GetBoolResponse() is the shared helper for XML-RPC calls that return a bool via a &amp;quot;result&amp;quot; key&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
=== LoginAgentToGrid() ===&lt;br /&gt;
&lt;br /&gt;
Two overloads:&lt;br /&gt;
&lt;br /&gt;
 public bool LoginAgentToGrid(GridRegion source, AgentCircuitData aCircuit, GridRegion gatekeeper,&lt;br /&gt;
     GridRegion destination, bool fromLogin, out string reason)&lt;br /&gt;
&lt;br /&gt;
Constructs a synthetic home GridRegion using m_ServerURL as ServerURI, then calls the parent CreateAgent(). Teleport flag is ViaLogin if fromLogin, ViaHome otherwise. Stores gatekeeper in m_Gatekeeper for use by PackData().&lt;br /&gt;
&lt;br /&gt;
 public bool LoginAgentToGrid(GridRegion source, AgentCircuitData aCircuit, GridRegion gatekeeper,&lt;br /&gt;
     GridRegion destination, out string reason)&lt;br /&gt;
&lt;br /&gt;
Always passes fromLogin = false. Used by simulators.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
=== XML-RPC Methods ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Method !! XmlRpc method !! Returns !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| GetHomeRegion(userID, out position, out lookAt) || &amp;quot;get_home_region&amp;quot; || GridRegion || Parses full GridRegion from Hashtable; returns null on failure&lt;br /&gt;
|-&lt;br /&gt;
| IsAgentComingHome(sessionID, thisGridExternalName) || &amp;quot;agent_is_coming_home&amp;quot; || bool || Via GetBoolResponse()&lt;br /&gt;
|-&lt;br /&gt;
| VerifyAgent(sessionID, token) || &amp;quot;verify_agent&amp;quot; || bool || Via GetBoolResponse()&lt;br /&gt;
|-&lt;br /&gt;
| VerifyClient(sessionID, token) || &amp;quot;verify_client&amp;quot; || bool || Via GetBoolResponse()&lt;br /&gt;
|-&lt;br /&gt;
| LogoutAgent(userID, sessionID) || &amp;quot;logout_agent&amp;quot; || void || Calls GetBoolResponse() but discards result&lt;br /&gt;
|-&lt;br /&gt;
| GetUserInfo(userID) || &amp;quot;get_user_info&amp;quot; || Dictionary&amp;lt;string,object&amp;gt; || All non-null Hashtable entries returned&lt;br /&gt;
|-&lt;br /&gt;
| GetServerURLs(userID) || &amp;quot;get_server_urls&amp;quot; || Dictionary&amp;lt;string,object&amp;gt; || Only SRV_-prefixed keys returned; &amp;quot;SRV_&amp;quot; prefix stripped&lt;br /&gt;
|-&lt;br /&gt;
| LocateUser(userID) || &amp;quot;locate_user&amp;quot; || string || Returns hash[&amp;quot;URL&amp;quot;] or empty string&lt;br /&gt;
|-&lt;br /&gt;
| GetUUI(userID, targetUserID) || &amp;quot;get_uui&amp;quot; || string || Returns hash[&amp;quot;UUI&amp;quot;] or empty string&lt;br /&gt;
|-&lt;br /&gt;
| GetUUID(first, last) || &amp;quot;get_uuid&amp;quot; || UUID || Throws on missing or unparseable UUID response&lt;br /&gt;
|-&lt;br /&gt;
| StatusNotification(friends, userID, online) || &amp;quot;status_notification&amp;quot; || List&amp;lt;UUID&amp;gt; || [Obsolete]; friends sent as friend_0, friend_1...; returns online UUIDs&lt;br /&gt;
|-&lt;br /&gt;
| GetOnlineFriends(userID, friends) || &amp;quot;get_online_friends&amp;quot; || List&amp;lt;UUID&amp;gt; || [Obsolete]; same encoding as StatusNotification&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
GetHomeRegion() field parsing: uuid, x, y, size_x, size_y, region_name, hostname, http_port, server_uri, internal_port, position, lookAt. All fields checked for null before parsing. Missing fields silently use zero/default values.&lt;br /&gt;
&lt;br /&gt;
GetServerURLs() strips the &amp;quot;SRV_&amp;quot; prefix from keys, returning just the service type name.&lt;br /&gt;
&lt;br /&gt;
GetUUID() throws on failure -- the only method in this connector that throws instead of returning a sentinel value.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
=== SetClientToken() ===&lt;br /&gt;
&lt;br /&gt;
No-op. Accepted but does nothing.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
=== Notes ===&lt;br /&gt;
&lt;br /&gt;
* This connector uses XML-RPC for most operations and OSD/REST for agent transfer -- two different protocols in the same class.&lt;br /&gt;
* StatusNotification() and GetOnlineFriends() are both marked [Obsolete]. Exception catch blocks in both methods silently swallow all exceptions with no logging.&lt;br /&gt;
* LogoutAgent() discards the bool result from GetBoolResponse() -- callers cannot detect failure.&lt;br /&gt;
* GetUUID() is the only method that throws on error rather than returning null/empty/false.&lt;br /&gt;
* The error message in GetBoolResponse() for &amp;quot;THIS IS BAAAAD&amp;quot; is verbatim from the source.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== See Also ==&lt;br /&gt;
&lt;br /&gt;
* [[OpenSimulator Internals/Connector Architecture]]&lt;br /&gt;
* [[OpenSimulator Internals/Connector Architecture/Simulation Connector]]&lt;br /&gt;
* [[OpenSimulator Internals/Code Map/ROBUST/UserAgentService]]&lt;br /&gt;
* [[OpenSimulator Internals/Code Map/ROBUST/GatekeeperService]]&lt;/div&gt;</summary>
		<author><name>Jwbshaw</name></author>
	</entry>
	<entry>
		<id>http://osimdev.org/wiki/index.php?title=OpenSimulator_Internals/Connector_Architecture/Simulation_Connector&amp;diff=78</id>
		<title>OpenSimulator Internals/Connector Architecture/Simulation Connector</title>
		<link rel="alternate" type="text/html" href="http://osimdev.org/wiki/index.php?title=OpenSimulator_Internals/Connector_Architecture/Simulation_Connector&amp;diff=78"/>
		<updated>2026-07-07T12:23:08Z</updated>

		<summary type="html">&lt;p&gt;Jwbshaw: first&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= OpenSimulator Internals/Connector Architecture/Simulation Connector =&lt;br /&gt;
&lt;br /&gt;
== Overview ==&lt;br /&gt;
&lt;br /&gt;
SimulationServiceConnector is the remote connector for ISimulationService. It handles inter-simulator communication: creating and updating agents during teleport and region crossing, and transferring objects between regions. Unlike the other connectors, it talks directly to region simulators, not to ROBUST.&lt;br /&gt;
&lt;br /&gt;
Source file:&lt;br /&gt;
&lt;br /&gt;
 OpenSim/Services/Connectors/Simulation/SimulationServiceConnector.cs&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
=== Initialisation ===&lt;br /&gt;
&lt;br /&gt;
No config file reading. No service URI -- the destination URI comes from GridRegion.ServerURI on each call.&lt;br /&gt;
&lt;br /&gt;
Two constructors:&lt;br /&gt;
* Default (no args)&lt;br /&gt;
* IConfigSource -- no-op, config argument unused&lt;br /&gt;
&lt;br /&gt;
GetScene() and GetInnerService() always return null.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
=== Transport ===&lt;br /&gt;
&lt;br /&gt;
Unlike all other connectors, SimulationServiceConnector does not use SynchronousRestFormsRequester. It uses WebUtil methods with OSDMap (LLSD) payloads:&lt;br /&gt;
&lt;br /&gt;
* WebUtil.PostToServiceCompressed() -- compressed POST, used for CreateAgent first attempt&lt;br /&gt;
* WebUtil.PostToService() -- uncompressed POST, used as fallback&lt;br /&gt;
* WebUtil.PutToServiceCompressed() / PutToService() -- PUT, used for UpdateAgent&lt;br /&gt;
* WebUtil.ServiceOSDRequest() -- used for QueryAccess (QUERYACCESS method), ReleaseAgent and CloseAgent (DELETE)&lt;br /&gt;
&lt;br /&gt;
URL pattern: destination.ServerURI + &amp;quot;agent/&amp;quot; + agentID + &amp;quot;/&amp;quot;&lt;br /&gt;
&lt;br /&gt;
AgentPath() and ObjectPath() are virtual -- subclasses can override the path segments.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
=== Agent Methods ===&lt;br /&gt;
&lt;br /&gt;
==== CreateAgent() ====&lt;br /&gt;
&lt;br /&gt;
 public bool CreateAgent(GridRegion source, GridRegion destination, AgentCircuitData aCircuit, uint flags, EntityTransferContext ctx, out string reason)&lt;br /&gt;
&lt;br /&gt;
# Packs AgentCircuitData via aCircuit.PackAgentCircuitData(ctx)&lt;br /&gt;
# Adds context, source region info, destination region info, and teleport flags via PackData()&lt;br /&gt;
# Attempts compressed POST first (WebUtil.PostToServiceCompressed)&lt;br /&gt;
# On success: reads _Result map for actual success/reason&lt;br /&gt;
# On failure: falls back to uncompressed POST (WebUtil.PostToService) with warning that destination should be updated&lt;br /&gt;
# Returns false with reason on all failure paths&lt;br /&gt;
&lt;br /&gt;
====  UpdateAgent(destination, AgentData, ctx) ====&lt;br /&gt;
&lt;br /&gt;
Full agent data update (region crossing). Timeout 200 seconds.&lt;br /&gt;
&lt;br /&gt;
==== UpdateAgent(destination, AgentPosition) ====&lt;br /&gt;
&lt;br /&gt;
Position-only update. Called frequently during avatar movement.&lt;br /&gt;
&lt;br /&gt;
Deduplication via m_updateAgentQueue dictionary keyed by URI:&lt;br /&gt;
* First thread for a URI becomes the worker; subsequent threads update the map and return&lt;br /&gt;
* Worker loops, sending the most recent position until no new update arrives&lt;br /&gt;
* On send failure: blacklists the destination URI for 120 seconds via _failedSims ExpiringCache&lt;br /&gt;
* Blacklisted destinations return false immediately without attempting contact&lt;br /&gt;
&lt;br /&gt;
Private UpdateAgent(destination, IAgentData, ctx, timeout) handles the actual PUT:&lt;br /&gt;
* Uses PutToServiceCompressed&lt;br /&gt;
* If OutboundVersion &amp;gt;= 0.3: returns immediately on success&lt;br /&gt;
* If OutboundVersion &amp;lt; 0.2: falls back to uncompressed PutToService on failure&lt;br /&gt;
&lt;br /&gt;
==== QueryAccess() ====&lt;br /&gt;
&lt;br /&gt;
 public bool QueryAccess(GridRegion destination, UUID agentID, string agentHomeURI, bool viaTeleport, Vector3 position, List&amp;lt;UUID&amp;gt; featuresAvailable, EntityTransferContext ctx, out string reason)&lt;br /&gt;
&lt;br /&gt;
URL: destination.ServerURI + &amp;quot;agent/&amp;quot; + agentID + &amp;quot;/&amp;quot; + destination.RegionID + &amp;quot;/&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Sends simulation service version negotiation fields:&lt;br /&gt;
* simulation_service_supported_min/max&lt;br /&gt;
* simulation_service_accepted_min/max&lt;br /&gt;
* my_version (legacy field, set to minimum for safety)&lt;br /&gt;
* features (List of UUID capabilities)&lt;br /&gt;
* context&lt;br /&gt;
&lt;br /&gt;
Response handling:&lt;br /&gt;
* Reads _Result map for success, reason, negotiated_inbound_version, negotiated_outbound_version&lt;br /&gt;
* Falls back to legacy &amp;quot;version&amp;quot; field (SIMULATION/N.N format) if negotiated fields absent&lt;br /&gt;
* Sets ctx.InboundVersion and ctx.OutboundVersion from response&lt;br /&gt;
* If MethodNotAllowed error received: logs it and returns true (legacy simulator compatibility)&lt;br /&gt;
* Sets ctx.WearablesCount based on OutboundVersion:&lt;br /&gt;
** &amp;lt; 0.5: LEGACY_VERSION_MAX_WEARABLES&lt;br /&gt;
** &amp;lt; 0.6: LEGACY_VERSION_MAX_WEARABLES + 1&lt;br /&gt;
** &amp;gt;= 0.6: -1 (send all)&lt;br /&gt;
* Clears featuresAvailable and repopulates from response&lt;br /&gt;
&lt;br /&gt;
Comment in source notes the _Result success/failure is the authoritative one, not the sibling result node -- legacy issue from 0.7.3.1 era labelled &amp;quot;nte4.8 crap&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
==== ReleaseAgent() ====&lt;br /&gt;
&lt;br /&gt;
Sends DELETE to a provided URI (not constructed from destination). Always returns true regardless of result.&lt;br /&gt;
&lt;br /&gt;
==== CloseAgent() ====&lt;br /&gt;
&lt;br /&gt;
URL: destination.ServerURI + &amp;quot;agent/&amp;quot; + id + &amp;quot;/&amp;quot; + destination.RegionID + &amp;quot;/?auth=&amp;quot; + auth_code&lt;br /&gt;
&lt;br /&gt;
Sends DELETE. Always returns true regardless of result.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
=== Object Methods ===&lt;br /&gt;
&lt;br /&gt;
==== CreateObject(destination, newPosition, sog, isLocalCall) ====&lt;br /&gt;
&lt;br /&gt;
URL: destination.ServerURI + &amp;quot;object/&amp;quot; + sog.UUID + &amp;quot;/&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Packs scene object as XML2 via sog.ToXml2(), extra state via ExtraToXmlString() and GetStateSnapshot(). Sends uncompressed POST. Returns false if result is null or success is false.&lt;br /&gt;
&lt;br /&gt;
==== CreateObject(destination, userID, itemID) ====&lt;br /&gt;
&lt;br /&gt;
Not implemented. Always returns false with a TODO comment.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
=== Notes ===&lt;br /&gt;
&lt;br /&gt;
* This connector talks to region simulators, not ROBUST. The destination URI comes from GridRegion.ServerURI per call.&lt;br /&gt;
* The compressed/uncompressed fallback in CreateAgent() exists for backward compatibility with older simulators. A warning is logged when the fallback is needed.&lt;br /&gt;
* UpdateAgent position deduplication means only the most recent position is ever sent -- intermediate positions are silently dropped. This is intentional.&lt;br /&gt;
* The 200-second timeout on full AgentData UpdateAgent is notably long -- comment &amp;quot;yes, 200 seconds&amp;quot; is in the source.&lt;br /&gt;
* ReleaseAgent and CloseAgent always return true -- callers cannot detect failure from return value.&lt;br /&gt;
* CreateObject by userID+itemID is explicitly unimplemented with a &amp;quot;TODO, not that urgent&amp;quot; comment.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== See Also ==&lt;br /&gt;
&lt;br /&gt;
* [[OpenSimulator Internals/Connector Architecture]]&lt;br /&gt;
* [[OpenSimulator Internals/Code Map/ROBUST/GatekeeperService]]&lt;br /&gt;
* [[OpenSimulator Internals/Code Map/Scene]]&lt;/div&gt;</summary>
		<author><name>Jwbshaw</name></author>
	</entry>
	<entry>
		<id>http://osimdev.org/wiki/index.php?title=OpenSimulator_Internals/Connector_Architecture/Grid_Connector&amp;diff=77</id>
		<title>OpenSimulator Internals/Connector Architecture/Grid Connector</title>
		<link rel="alternate" type="text/html" href="http://osimdev.org/wiki/index.php?title=OpenSimulator_Internals/Connector_Architecture/Grid_Connector&amp;diff=77"/>
		<updated>2026-07-07T12:22:18Z</updated>

		<summary type="html">&lt;p&gt;Jwbshaw: first&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= OpenSimulator Internals/Connector Architecture/Grid Connector =&lt;br /&gt;
&lt;br /&gt;
== Overview ==&lt;br /&gt;
&lt;br /&gt;
GridServicesConnector is the simulator-side remote connector for IGridService. It translates IGridService calls into HTTP POST requests to the ROBUST Grid handler at /grid.&lt;br /&gt;
&lt;br /&gt;
Source file:&lt;br /&gt;
&lt;br /&gt;
 OpenSim/Services/Connectors/Grid/GridServicesConnector.cs&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
=== Initialisation ===&lt;br /&gt;
&lt;br /&gt;
Config section: [GridService]&lt;br /&gt;
&lt;br /&gt;
Required key:&lt;br /&gt;
* GridServerURI -- URL of the ROBUST grid endpoint; throws if missing&lt;br /&gt;
&lt;br /&gt;
Two URIs are constructed:&lt;br /&gt;
* m_ServerURI -- base URI (trailing slash trimmed)&lt;br /&gt;
* m_ServerGridURI -- m_ServerURI + &amp;quot;/grid&amp;quot; -- used for all requests&lt;br /&gt;
&lt;br /&gt;
Base class BaseServiceConnector.Initialise() called for auth setup.&lt;br /&gt;
&lt;br /&gt;
Three constructors:&lt;br /&gt;
* Default (no args) -- URIs must be set externally&lt;br /&gt;
* String URI -- sets both m_ServerURI and m_ServerGridURI directly&lt;br /&gt;
* IConfigSource -- calls Initialise(), normal grid mode&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
=== Transport ===&lt;br /&gt;
&lt;br /&gt;
All methods POST to m_ServerGridURI using SynchronousRestFormsRequester.MakePostRequest(). All requests include a METHOD field. Most also include SCOPEID.&lt;br /&gt;
&lt;br /&gt;
List-returning methods iterate all values in the reply dictionary and construct GridRegion from each dictionary entry. Empty list returned on empty reply or exception.&lt;br /&gt;
&lt;br /&gt;
Single-region methods check for a &amp;quot;result&amp;quot; key containing a dictionary and construct GridRegion from it. Null returned if not found.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
=== Methods ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Method !! METHOD field !! Returns !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| RegisterRegion(scopeID, regionInfo) || &amp;quot;register&amp;quot; || string || Empty string on success; error message on failure. Sends full GridRegion via ToKeyValuePairs(). Checks Result field for &amp;quot;success&amp;quot;/&amp;quot;failure&amp;quot;.&lt;br /&gt;
|-&lt;br /&gt;
| DeregisterRegion(regionID) || &amp;quot;deregister&amp;quot; || bool || Checks Result == &amp;quot;success&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
| GetNeighbours(scopeID, regionID) || &amp;quot;get_neighbours&amp;quot; || List&amp;lt;GridRegion&amp;gt; || Returns empty list on failure&lt;br /&gt;
|-&lt;br /&gt;
| GetRegionByUUID(scopeID, regionID) || &amp;quot;get_region_by_uuid&amp;quot; || GridRegion || Null on not found&lt;br /&gt;
|-&lt;br /&gt;
| GetRegionByHandle(scopeID, handle) || (none) || GridRegion || Converts handle to x,y coords; delegates to GetRegionByPosition()&lt;br /&gt;
|-&lt;br /&gt;
| GetRegionByPosition(scopeID, x, y) || &amp;quot;get_region_by_position&amp;quot; || GridRegion || Null on not found&lt;br /&gt;
|-&lt;br /&gt;
| GetRegionByName(scopeID, name) || &amp;quot;get_region_by_name&amp;quot; || GridRegion || Null on not found&lt;br /&gt;
|-&lt;br /&gt;
| GetLocalRegionByName(scopeID, name) || &amp;quot;get_localregion_by_name&amp;quot; || GridRegion || Null on not found; used by GatekeeperService&lt;br /&gt;
|-&lt;br /&gt;
| GetRegionByURI(scopeID, uri) || (none) || GridRegion || Always returns null -- not implemented&lt;br /&gt;
|-&lt;br /&gt;
| GetLocalRegionByURI(scopeID, uri) || (none) || GridRegion || Always returns null -- not implemented&lt;br /&gt;
|-&lt;br /&gt;
| GetRegionsByName(scopeID, name, max) || &amp;quot;get_regions_by_name&amp;quot; || List&amp;lt;GridRegion&amp;gt; || Name prefix search; max limits results&lt;br /&gt;
|-&lt;br /&gt;
| GetRegionsByURI(scopeID, uri, max) || (none) || List&amp;lt;GridRegion&amp;gt; || Always returns null -- not implemented&lt;br /&gt;
|-&lt;br /&gt;
| GetRegionRange(scopeID, xmin, xmax, ymin, ymax) || &amp;quot;get_region_range&amp;quot; || List&amp;lt;GridRegion&amp;gt; || Bounding box query&lt;br /&gt;
|-&lt;br /&gt;
| GetDefaultRegions(scopeID) || &amp;quot;get_default_regions&amp;quot; || List&amp;lt;GridRegion&amp;gt; || Returns empty list on failure&lt;br /&gt;
|-&lt;br /&gt;
| GetDefaultHypergridRegions(scopeID) || &amp;quot;get_default_hypergrid_regions&amp;quot; || List&amp;lt;GridRegion&amp;gt; || Returns empty list on failure&lt;br /&gt;
|-&lt;br /&gt;
| GetFallbackRegions(scopeID, x, y) || &amp;quot;get_fallback_regions&amp;quot; || List&amp;lt;GridRegion&amp;gt; || Returns empty list on failure&lt;br /&gt;
|-&lt;br /&gt;
| GetOnlineRegions(scopeID, x, y, max) || &amp;quot;get_online_regions&amp;quot; || List&amp;lt;GridRegion&amp;gt; || Sends MC for max count; returns empty list on failure&lt;br /&gt;
|-&lt;br /&gt;
| GetHyperlinks(scopeID) || &amp;quot;get_hyperlinks&amp;quot; || List&amp;lt;GridRegion&amp;gt; || Returns empty list on failure&lt;br /&gt;
|-&lt;br /&gt;
| GetRegionFlags(scopeID, regionID) || &amp;quot;get_region_flags&amp;quot; || int || Returns -1 on failure; parses result as int&lt;br /&gt;
|-&lt;br /&gt;
| GetExtraFeatures() || &amp;quot;get_grid_extra_features&amp;quot; || Dictionary&amp;lt;string,object&amp;gt; || Returns all key-value pairs from reply; empty dict on failure&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
RegisterRegion() result handling:&lt;br /&gt;
* &amp;quot;success&amp;quot; (case-insensitive) -- returns empty string&lt;br /&gt;
* &amp;quot;failure&amp;quot; (case-insensitive) -- logs Message field and returns it&lt;br /&gt;
* Anything else -- logs &amp;quot;unexpected result&amp;quot; and returns it&lt;br /&gt;
* All errors return a non-empty string; callers check for empty string to detect success&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
=== Notes ===&lt;br /&gt;
&lt;br /&gt;
* GetRegionByURI(), GetLocalRegionByURI(), and GetRegionsByURI() always return null -- RegionURI queries are not implemented in this connector.&lt;br /&gt;
* GetRegionByHandle() is a local conversion wrapper -- it does not make a separate HTTP call with the handle value.&lt;br /&gt;
* List methods return empty list (not null) on all failure paths.&lt;br /&gt;
* Single-region methods return null on failure.&lt;br /&gt;
* GetRegionFlags() returns -1 on failure, not 0 -- callers should check for negative values.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== See Also ==&lt;br /&gt;
&lt;br /&gt;
* [[OpenSimulator Internals/Connector Architecture]]&lt;br /&gt;
* [[OpenSimulator Internals/Code Map/ROBUST/GridService RegisterRegion]]&lt;br /&gt;
* [[OpenSimulator Internals/Code Map/Shared]]&lt;/div&gt;</summary>
		<author><name>Jwbshaw</name></author>
	</entry>
	<entry>
		<id>http://osimdev.org/wiki/index.php?title=OpenSimulator_Internals/Connector_Architecture/Friends_Connector&amp;diff=76</id>
		<title>OpenSimulator Internals/Connector Architecture/Friends Connector</title>
		<link rel="alternate" type="text/html" href="http://osimdev.org/wiki/index.php?title=OpenSimulator_Internals/Connector_Architecture/Friends_Connector&amp;diff=76"/>
		<updated>2026-07-07T12:21:31Z</updated>

		<summary type="html">&lt;p&gt;Jwbshaw: first&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= OpenSimulator Internals/Connector Architecture/Friends Connector =&lt;br /&gt;
&lt;br /&gt;
== Overview ==&lt;br /&gt;
&lt;br /&gt;
FriendsServicesConnector is the simulator-side remote connector for IFriendsService. It translates IFriendsService calls into HTTP POST requests to the ROBUST Friends handler at /friends.&lt;br /&gt;
&lt;br /&gt;
Source file:&lt;br /&gt;
&lt;br /&gt;
 OpenSim/Services/Connectors/Friends/FriendsServicesConnector.cs&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
=== Initialisation ===&lt;br /&gt;
&lt;br /&gt;
Config section: [FriendsService]&lt;br /&gt;
&lt;br /&gt;
Required key:&lt;br /&gt;
* FriendsServerURI -- URL of the ROBUST friends endpoint; throws if missing&lt;br /&gt;
&lt;br /&gt;
Base class BaseServiceConnector.Initialise() called for auth setup.&lt;br /&gt;
&lt;br /&gt;
Three constructors:&lt;br /&gt;
* Default (no args) -- URI must be set externally&lt;br /&gt;
* String URI -- used by callers that pass the URI directly&lt;br /&gt;
* IConfigSource -- calls Initialise(), normal grid mode&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
=== Transport ===&lt;br /&gt;
&lt;br /&gt;
All methods POST to m_ServerURI + &amp;quot;/friends&amp;quot; using SynchronousRestFormsRequester.&lt;br /&gt;
&lt;br /&gt;
Unlike most other connectors, requests do not include VERSIONMIN / VERSIONMAX fields.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
=== Methods ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Method !! METHOD field !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| GetFriends(UUID principalID) || &amp;quot;getfriends&amp;quot; || UUID overload&lt;br /&gt;
|-&lt;br /&gt;
| GetFriends(string principalID) || &amp;quot;getfriends_string&amp;quot; || String overload -- used for HG UUI identifiers&lt;br /&gt;
|-&lt;br /&gt;
| StoreFriend(principalID, friend, flags) || &amp;quot;storefriend&amp;quot; || Sends PrincipalID, Friend, MyFlags; returns bool from Result field&lt;br /&gt;
|-&lt;br /&gt;
| Delete(UUID principalID, string friend) || &amp;quot;deletefriend&amp;quot; || UUID overload&lt;br /&gt;
|-&lt;br /&gt;
| Delete(string principalID, string friend) || &amp;quot;deletefriend_string&amp;quot; || String overload -- used for HG UUI identifiers&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
GetFriends() (both overloads) delegate to a protected GetFriends(Dictionary, string) helper:&lt;br /&gt;
* Returns empty FriendInfo[] if result == &amp;quot;null&amp;quot;&lt;br /&gt;
* Iterates all values in reply dictionary, constructs FriendInfo for each dictionary entry&lt;br /&gt;
* Returns empty FriendInfo[] on empty reply or exception (never returns null)&lt;br /&gt;
&lt;br /&gt;
StoreFriend() and Delete():&lt;br /&gt;
* Check replyData[&amp;quot;Result&amp;quot;] (capital R -- different from most other connectors which use lowercase &amp;quot;result&amp;quot;)&lt;br /&gt;
* Parse as bool via Boolean.TryParse()&lt;br /&gt;
* Return false on empty reply, null response, or exception&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
=== Notes ===&lt;br /&gt;
&lt;br /&gt;
* Two string overloads exist (GetFriends, Delete) to support HyperGrid UUI identifiers which are not valid UUIDs.&lt;br /&gt;
* Result field key is &amp;quot;Result&amp;quot; (capital R) -- inconsistent with most other ROBUST service connectors which use lowercase &amp;quot;result&amp;quot;.&lt;br /&gt;
* No VERSIONMIN/VERSIONMAX sent -- unlike GridUser, Presence, Avatar, and UserAccount connectors.&lt;br /&gt;
* GetFriends() returns empty array (not null) on all failure paths.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== See Also ==&lt;br /&gt;
&lt;br /&gt;
* [[OpenSimulator Internals/Connector Architecture]]&lt;br /&gt;
* [[OpenSimulator Internals/Code Map/ROBUST]]&lt;br /&gt;
* [[OpenSimulator Internals/Code Map/Shared]]&lt;/div&gt;</summary>
		<author><name>Jwbshaw</name></author>
	</entry>
	<entry>
		<id>http://osimdev.org/wiki/index.php?title=OpenSimulator_Internals/Connector_Architecture/Avatar_Connector&amp;diff=75</id>
		<title>OpenSimulator Internals/Connector Architecture/Avatar Connector</title>
		<link rel="alternate" type="text/html" href="http://osimdev.org/wiki/index.php?title=OpenSimulator_Internals/Connector_Architecture/Avatar_Connector&amp;diff=75"/>
		<updated>2026-07-07T12:20:47Z</updated>

		<summary type="html">&lt;p&gt;Jwbshaw: first&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= OpenSimulator Internals/Connector Architecture/Avatar Connector =&lt;br /&gt;
&lt;br /&gt;
== Overview ==&lt;br /&gt;
&lt;br /&gt;
AvatarServicesConnector is the simulator-side remote connector for IAvatarService. It translates IAvatarService calls into HTTP POST requests to the ROBUST Avatar handler at /avatar.&lt;br /&gt;
&lt;br /&gt;
Source file:&lt;br /&gt;
&lt;br /&gt;
 OpenSim/Services/Connectors/Avatar/AvatarServicesConnector.cs&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
=== Initialisation ===&lt;br /&gt;
&lt;br /&gt;
Config section: [AvatarService]&lt;br /&gt;
&lt;br /&gt;
Required key:&lt;br /&gt;
* AvatarServerURI -- URL of the ROBUST avatar endpoint; throws if missing&lt;br /&gt;
&lt;br /&gt;
Base class BaseServiceConnector.Initialise() called for auth setup.&lt;br /&gt;
&lt;br /&gt;
Three constructors:&lt;br /&gt;
* Default (no args) -- URI must be set externally&lt;br /&gt;
* String URI -- used by callers that pass the URI directly&lt;br /&gt;
* IConfigSource -- calls Initialise(), normal grid mode&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
=== Transport ===&lt;br /&gt;
&lt;br /&gt;
All methods POST to m_ServerURI + &amp;quot;/avatar&amp;quot; using SynchronousRestFormsRequester.&lt;br /&gt;
&lt;br /&gt;
All requests include:&lt;br /&gt;
* VERSIONMIN / VERSIONMAX -- protocol version negotiation&lt;br /&gt;
* METHOD -- identifies the operation&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
=== Methods ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Method !! METHOD field !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| GetAvatar(userID) || &amp;quot;getavatar&amp;quot; || Returns AvatarData constructed from result dictionary; null on empty reply or missing result&lt;br /&gt;
|-&lt;br /&gt;
| GetAppearance(userID) || (none) || Calls GetAvatar(), then avatar.ToAvatarAppearance()&lt;br /&gt;
|-&lt;br /&gt;
| SetAvatar(userID, avatar) || &amp;quot;setavatar&amp;quot; || Serializes avatar via ToKeyValuePairs(); returns bool from result field&lt;br /&gt;
|-&lt;br /&gt;
| SetAppearance(userID, appearance) || (none) || Constructs AvatarData from AvatarAppearance, calls SetAvatar()&lt;br /&gt;
|-&lt;br /&gt;
| ResetAvatar(userID) || &amp;quot;resetavatar&amp;quot; || Returns bool from result field&lt;br /&gt;
|-&lt;br /&gt;
| SetItems(userID, names[], values[]) || &amp;quot;setitems&amp;quot; || Sends Names and Values as parallel List&amp;lt;string&amp;gt;; returns bool&lt;br /&gt;
|-&lt;br /&gt;
| RemoveItems(userID, names[]) || &amp;quot;removeitems&amp;quot; || Sends Names as List&amp;lt;string&amp;gt;; returns bool&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
All write methods (SetAvatar, ResetAvatar, SetItems, RemoveItems) check replyData[&amp;quot;result&amp;quot;].ToLower() == &amp;quot;success&amp;quot; and return false on empty reply, missing result field, or exception.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
=== Notes ===&lt;br /&gt;
&lt;br /&gt;
* The log message in ResetAvatar() says &amp;quot;SetItems reply&amp;quot; in both the missing-result and empty-reply branches -- copy-paste error from SetItems(). The method itself is correct; only the log text is wrong.&lt;br /&gt;
* ScopeID fields are present in the code but commented out throughout.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== See Also ==&lt;br /&gt;
&lt;br /&gt;
* [[OpenSimulator Internals/Connector Architecture]]&lt;br /&gt;
* [[OpenSimulator Internals/Code Map/ROBUST/AvatarService]]&lt;br /&gt;
* [[OpenSimulator Internals/Code Map/Shared]]&lt;/div&gt;</summary>
		<author><name>Jwbshaw</name></author>
	</entry>
	<entry>
		<id>http://osimdev.org/wiki/index.php?title=OpenSimulator_Internals/Connector_Architecture/Authentication_Connector&amp;diff=74</id>
		<title>OpenSimulator Internals/Connector Architecture/Authentication Connector</title>
		<link rel="alternate" type="text/html" href="http://osimdev.org/wiki/index.php?title=OpenSimulator_Internals/Connector_Architecture/Authentication_Connector&amp;diff=74"/>
		<updated>2026-07-07T12:20:00Z</updated>

		<summary type="html">&lt;p&gt;Jwbshaw: first&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= OpenSimulator Internals/Connector Architecture/Authentication Connector =&lt;br /&gt;
&lt;br /&gt;
== Overview ==&lt;br /&gt;
&lt;br /&gt;
AuthenticationServicesConnector is the simulator-side remote connector for IAuthenticationService. It translates authentication calls into HTTP POST requests to the ROBUST Authentication handler at /auth/plain.&lt;br /&gt;
&lt;br /&gt;
Source file:&lt;br /&gt;
&lt;br /&gt;
 OpenSim/Services/Connectors/Authentication/AuthenticationServicesConnector.cs&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
=== Initialisation ===&lt;br /&gt;
&lt;br /&gt;
Config section: [AuthenticationService]&lt;br /&gt;
&lt;br /&gt;
Required key:&lt;br /&gt;
* AuthenticationServerURI -- URL of the ROBUST authentication endpoint; throws if missing&lt;br /&gt;
&lt;br /&gt;
Base class BaseServiceConnector.Initialise() called for auth setup.&lt;br /&gt;
&lt;br /&gt;
Three constructors:&lt;br /&gt;
* Default (no args) -- URI must be set externally&lt;br /&gt;
* String URI -- used by callers that pass the URI directly&lt;br /&gt;
* IConfigSource -- calls Initialise(), normal grid mode&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
=== Transport ===&lt;br /&gt;
&lt;br /&gt;
All methods POST to m_ServerURI + &amp;quot;/auth/plain&amp;quot; using SynchronousRestFormsRequester. All requests include a METHOD field.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
=== Methods ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Method !! METHOD field !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| Authenticate(principalID, password, lifetime) || &amp;quot;authenticate&amp;quot; || Returns token string on success, empty string on failure&lt;br /&gt;
|-&lt;br /&gt;
| Authenticate(principalID, password, lifetime, out realID) || &amp;quot;authenticate&amp;quot; || realID always returns UUID.Zero; delegates to the 3-arg overload&lt;br /&gt;
|-&lt;br /&gt;
| Verify(principalID, token, lifetime) || &amp;quot;verify&amp;quot; || Returns bool&lt;br /&gt;
|-&lt;br /&gt;
| Release(principalID, token) || &amp;quot;release&amp;quot; || Returns bool&lt;br /&gt;
|-&lt;br /&gt;
| SetPassword(principalID, passwd) || (none) || Always returns false -- not done from remote simulators&lt;br /&gt;
|-&lt;br /&gt;
| GetAuthInfo(principalID) || (none) || Always returns null -- not done from remote simulators&lt;br /&gt;
|-&lt;br /&gt;
| SetAuthInfo(info) || (none) || Always returns false -- not done from remote simulators&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Authenticate() sends: PRINCIPAL, PASSWORD, LIFETIME. Returns Token from reply on Success, empty string otherwise.&lt;br /&gt;
&lt;br /&gt;
Verify() sends: PRINCIPAL, TOKEN, LIFETIME. Returns true on Success.&lt;br /&gt;
&lt;br /&gt;
Release() sends: PRINCIPAL, TOKEN. Returns true on Success.&lt;br /&gt;
&lt;br /&gt;
All three parse XML response and check replyData[&amp;quot;Result&amp;quot;] == &amp;quot;Success&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
=== Notes ===&lt;br /&gt;
&lt;br /&gt;
* The out realID overload of Authenticate() always sets realID to UUID.Zero and delegates to the 3-arg version. The realID concept exists in the service interface but is not implemented at the connector level.&lt;br /&gt;
* SetPassword(), GetAuthInfo(), and SetAuthInfo() are explicitly documented in comments as not done from remote simulators.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== See Also ==&lt;br /&gt;
&lt;br /&gt;
* [[OpenSimulator Internals/Connector Architecture]]&lt;br /&gt;
* [[OpenSimulator Internals/Code Map/ROBUST/AuthenticationService]]&lt;br /&gt;
* [[OpenSimulator Internals/Code Map/Shared]]&lt;/div&gt;</summary>
		<author><name>Jwbshaw</name></author>
	</entry>
	<entry>
		<id>http://osimdev.org/wiki/index.php?title=OpenSimulator_Internals/Connector_Architecture/Inventory_Connector&amp;diff=73</id>
		<title>OpenSimulator Internals/Connector Architecture/Inventory Connector</title>
		<link rel="alternate" type="text/html" href="http://osimdev.org/wiki/index.php?title=OpenSimulator_Internals/Connector_Architecture/Inventory_Connector&amp;diff=73"/>
		<updated>2026-07-07T12:19:13Z</updated>

		<summary type="html">&lt;p&gt;Jwbshaw: first&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= OpenSimulator Internals/Connector Architecture/Inventory Connector =&lt;br /&gt;
&lt;br /&gt;
== Overview ==&lt;br /&gt;
&lt;br /&gt;
XInventoryServicesConnector is the simulator-side remote connector for IInventoryService. It translates IInventoryService calls into HTTP POST requests to the ROBUST XInventory handler at /xinventory.&lt;br /&gt;
&lt;br /&gt;
Source file:&lt;br /&gt;
&lt;br /&gt;
 OpenSim/Services/Connectors/Inventory/XInventoryServicesConnector.cs&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
=== Initialisation ===&lt;br /&gt;
&lt;br /&gt;
Config section: [InventoryService] (or configName argument if provided)&lt;br /&gt;
&lt;br /&gt;
Required key:&lt;br /&gt;
* InventoryServerURI -- URL of the ROBUST inventory endpoint; throws if missing&lt;br /&gt;
&lt;br /&gt;
The endpoint URL is always InventoryServerURI + &amp;quot;/xinventory&amp;quot; (trailing slash normalized).&lt;br /&gt;
&lt;br /&gt;
Optional key:&lt;br /&gt;
* RemoteRequestTimeout -- timeout in seconds for HTTP requests; default -1 (100 seconds, not infinite)&lt;br /&gt;
&lt;br /&gt;
A stats counter (RequestsMade) is registered with StatsManager on initialisation.&lt;br /&gt;
&lt;br /&gt;
Four constructors:&lt;br /&gt;
* Default (no args) -- URI must be set externally&lt;br /&gt;
* String URI -- used by callers that pass the URI directly; appends /xinventory&lt;br /&gt;
* IConfigSource -- calls Initialise(), normal grid mode&lt;br /&gt;
* IConfigSource + configName -- used for non-default section names&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
=== Transport ===&lt;br /&gt;
&lt;br /&gt;
Unlike other connectors, XInventoryServicesConnector does not use SynchronousRestFormsRequester. It has its own MakePostDicRequest() method using HttpClient directly.&lt;br /&gt;
&lt;br /&gt;
MakePostDicRequest() features:&lt;br /&gt;
* Uses WebUtil.GetNewGlobalHttpClient() with configured timeout&lt;br /&gt;
* Sends Keep-Alive headers (timeout=30, max=10)&lt;br /&gt;
* Sends Content-Type: application/x-www-form-urlencoded&lt;br /&gt;
* Uses HttpCompletionOption.ResponseHeadersRead -- reads headers first, then streams body&lt;br /&gt;
* Body receive has its own CancellationTokenSource timeout via WebUtil.EstimatedReceiveTimeout()&lt;br /&gt;
* Logs requests taking longer than WebUtil.LongCallTime&lt;br /&gt;
* Logs body timeouts separately from other errors&lt;br /&gt;
* Always disposes request, response, and client in finally block&lt;br /&gt;
* Returns empty Dictionary on null response (never returns null)&lt;br /&gt;
&lt;br /&gt;
All requests are POST to m_InventoryURL. The METHOD and parameters are encoded as URL query string in the POST body.&lt;br /&gt;
&lt;br /&gt;
MakeRequest() increments RequestsMade counter on every call.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
=== Item Cache ===&lt;br /&gt;
&lt;br /&gt;
Static ExpiringCacheOS&amp;lt;UUID, InventoryItemBase&amp;gt; shared across all instances. TTL is 30 seconds.&lt;br /&gt;
&lt;br /&gt;
Cache is checked in GetItem() and GetMultipleItems() before making remote requests. Cache is updated on successful GetItem(), UpdateItem(), and GetMultipleItems(). Cache entries are removed on MoveItems() and DeleteItems().&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
=== CheckReturn() ===&lt;br /&gt;
&lt;br /&gt;
Helper used by most methods. Returns false if the reply dictionary is null or empty. If RESULT key exists and its value parses as bool, returns that bool. If RESULT key exists but is not parseable as bool, returns false. If RESULT key is absent, returns true (assumes success if the server returned any data).&lt;br /&gt;
&lt;br /&gt;
GetAssetPermissions() cannot use CheckReturn() because its RESULT is an int, not a bool -- it has its own inline parse.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
=== Methods ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Method !! METHOD field !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| CreateUserInventory(principalID) || CREATEUSERINVENTORY || Returns bool&lt;br /&gt;
|-&lt;br /&gt;
| GetInventorySkeleton(principalID) || GETINVENTORYSKELETON || Returns List&amp;lt;InventoryFolderBase&amp;gt; from FOLDERS dict&lt;br /&gt;
|-&lt;br /&gt;
| GetRootFolder(principalID) || GETROOTFOLDER || Returns single InventoryFolderBase from &amp;quot;folder&amp;quot; key&lt;br /&gt;
|-&lt;br /&gt;
| GetFolderForType(principalID, type) || GETFOLDERFORTYPE || TYPE sent as int&lt;br /&gt;
|-&lt;br /&gt;
| GetFolderContent(principalID, folderID) || GETFOLDERCONTENT || Returns InventoryCollection with Folders and Items lists&lt;br /&gt;
|-&lt;br /&gt;
| GetMultipleFoldersContent(principalID, folderIDs[]) || GETMULTIPLEFOLDERSCONTENT || Batch; results keyed as F_{uuid}; null entry per missing folder&lt;br /&gt;
|-&lt;br /&gt;
| GetFolderItems(principalID, folderID) || GETFOLDERITEMS || Returns List&amp;lt;InventoryItemBase&amp;gt; from ITEMS dict&lt;br /&gt;
|-&lt;br /&gt;
| AddFolder(folder) || ADDFOLDER || Sends full folder fields as dictionary&lt;br /&gt;
|-&lt;br /&gt;
| UpdateFolder(folder) || UPDATEFOLDER || Sends fields as query string; URL-encodes Name&lt;br /&gt;
|-&lt;br /&gt;
| MoveFolder(folder) || MOVEFOLDER || Sends ParentID, ID, PRINCIPAL only&lt;br /&gt;
|-&lt;br /&gt;
| DeleteFolders(principalID, folderIDs) || DELETEFOLDERS || Sends FOLDERS as List&amp;lt;string&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| PurgeFolder(folder) || PURGEFOLDER || Sends ID only&lt;br /&gt;
|-&lt;br /&gt;
| AddItem(item) || ADDITEM || Sends full item fields; null-coalesces Description, CreatorData, CreatorId&lt;br /&gt;
|-&lt;br /&gt;
| UpdateItem(item) || UPDATEITEM || Updates cache on success&lt;br /&gt;
|-&lt;br /&gt;
| MoveItems(principalID, items) || MOVEITEMS || Sends parallel IDLIST and DESTLIST; removes from cache&lt;br /&gt;
|-&lt;br /&gt;
| DeleteItems(principalID, itemIDs) || DELETEITEMS || Removes from cache&lt;br /&gt;
|-&lt;br /&gt;
| GetItem(principalID, itemID) || GETITEM || Cache-first; updates cache on fetch&lt;br /&gt;
|-&lt;br /&gt;
| GetMultipleItems(principalID, itemIDs[]) || GETMULTIPLEITEMS || Cache-first per item; only fetches uncached IDs; results keyed as item_N&lt;br /&gt;
|-&lt;br /&gt;
| GetFolder(principalID, folderID) || GETFOLDER || Returns single InventoryFolderBase&lt;br /&gt;
|-&lt;br /&gt;
| GetActiveGestures(principalID) || GETACTIVEGESTURES || Returns List&amp;lt;InventoryItemBase&amp;gt; from ITEMS dict&lt;br /&gt;
|-&lt;br /&gt;
| GetAssetPermissions(principalID, assetID) || GETASSETPERMISSIONS || Returns int from RESULT field; 0 on failure&lt;br /&gt;
|-&lt;br /&gt;
| HasInventoryForUser(principalID) || (none) || Always returns false -- not implemented for remote connector&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
=== BuildFolder() / BuildItem() ===&lt;br /&gt;
&lt;br /&gt;
Static helpers that construct InventoryFolderBase and InventoryItemBase from reply dictionaries. Both catch exceptions and return an empty object on parse failure rather than throwing. CreatorData is optional in BuildItem() -- fetched via TryGetValue.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
=== Notes ===&lt;br /&gt;
&lt;br /&gt;
* This is the only connector in the set that uses HttpClient directly rather than SynchronousRestFormsRequester.&lt;br /&gt;
* HasInventoryForUser() always returns false -- not implemented.&lt;br /&gt;
* GetMultipleItems() builds the request body with a StringBuilder, skipping items already in cache. The result index tracking (variable i) carries over between the cache-hit loop and the network-result loop -- order of itemArr entries may not match order of itemIDs if some were cached and some were not.&lt;br /&gt;
* GetMultipleFoldersContent() returns null entries (not omits) for folders not found in the reply, preserving index alignment with the input folderIDs array.&lt;br /&gt;
* UpdateFolder() URL-encodes Name via HttpUtility.UrlEncode() but AddFolder() does not -- inconsistency within the same file.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== See Also ==&lt;br /&gt;
&lt;br /&gt;
* [[OpenSimulator Internals/Connector Architecture]]&lt;br /&gt;
* [[OpenSimulator Internals/Code Map/ROBUST/InventoryService]]&lt;br /&gt;
* [[OpenSimulator Internals/Code Map/Shared]]&lt;/div&gt;</summary>
		<author><name>Jwbshaw</name></author>
	</entry>
	<entry>
		<id>http://osimdev.org/wiki/index.php?title=OpenSimulator_Internals/Connector_Architecture/UserAccount_Connector&amp;diff=72</id>
		<title>OpenSimulator Internals/Connector Architecture/UserAccount Connector</title>
		<link rel="alternate" type="text/html" href="http://osimdev.org/wiki/index.php?title=OpenSimulator_Internals/Connector_Architecture/UserAccount_Connector&amp;diff=72"/>
		<updated>2026-07-07T12:18:02Z</updated>

		<summary type="html">&lt;p&gt;Jwbshaw: first&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= OpenSimulator Internals/Connector Architecture/UserAccount Connector =&lt;br /&gt;
&lt;br /&gt;
== Overview ==&lt;br /&gt;
&lt;br /&gt;
UserAccountServicesConnector is the simulator-side remote connector for IUserAccountService. It translates IUserAccountService calls into HTTP POST requests to the ROBUST UserAccount handler at /accounts.&lt;br /&gt;
&lt;br /&gt;
Source file:&lt;br /&gt;
&lt;br /&gt;
 OpenSim/Services/Connectors/UserAccountServicesConnector.cs&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
=== Initialisation ===&lt;br /&gt;
&lt;br /&gt;
Config section: [UserAccountService]&lt;br /&gt;
&lt;br /&gt;
Required key:&lt;br /&gt;
* UserAccountServerURI -- URL of the ROBUST UserAccount endpoint; throws if missing or unresolvable&lt;br /&gt;
&lt;br /&gt;
Base class BaseServiceConnector.Initialise() called for auth setup.&lt;br /&gt;
&lt;br /&gt;
Three constructors:&lt;br /&gt;
* Default (no args) -- URI must be set externally&lt;br /&gt;
* String URI -- used by callers that pass the URI directly&lt;br /&gt;
* IConfigSource -- calls Initialise(), normal grid mode&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
=== Transport ===&lt;br /&gt;
&lt;br /&gt;
All methods POST to m_ServerURI + &amp;quot;/accounts&amp;quot; using SynchronousRestFormsRequester.&lt;br /&gt;
&lt;br /&gt;
All requests include:&lt;br /&gt;
* VERSIONMIN / VERSIONMAX -- protocol version negotiation&lt;br /&gt;
* METHOD -- identifies the operation&lt;br /&gt;
&lt;br /&gt;
Two internal helpers:&lt;br /&gt;
&lt;br /&gt;
SendAndGetReply() -- used by single-account GET methods and StoreUserAccount():&lt;br /&gt;
* POSTs, parses XML response&lt;br /&gt;
* Returns UserAccount constructed from result dictionary, or null&lt;br /&gt;
&lt;br /&gt;
SendAndGetBoolReply() -- defined but not called by any method in this file. Dead code.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
=== Methods ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Method !! METHOD field !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| GetUserAccount(scopeID, firstName, lastName) || &amp;quot;getaccount&amp;quot; || Lookup by name&lt;br /&gt;
|-&lt;br /&gt;
| GetUserAccount(scopeID, email) || &amp;quot;getaccount&amp;quot; || Lookup by email&lt;br /&gt;
|-&lt;br /&gt;
| GetUserAccount(scopeID, userID) || &amp;quot;getaccount&amp;quot; || Lookup by UUID&lt;br /&gt;
|-&lt;br /&gt;
| GetUserAccounts(scopeID, query) || &amp;quot;getaccounts&amp;quot; || Search by name fragment; returns List&amp;lt;UserAccount&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| GetUserAccounts(scopeID, List&amp;lt;string&amp;gt; IDs) || &amp;quot;getmultiaccounts&amp;quot; || Batch lookup by UUID list; falls back to one-by-one if server returns &amp;quot;Failure&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
| StoreUserAccount(data) || &amp;quot;setaccount&amp;quot; || Serializes UserAccount via ToKeyValuePairs(); returns true if result is non-null&lt;br /&gt;
|-&lt;br /&gt;
| CreateUser(first, last, password, email, scopeID) || &amp;quot;createuser&amp;quot; || Remote user creation; not part of IUserAccountService interface&lt;br /&gt;
|-&lt;br /&gt;
| InvalidateCache(userID) || (none) || No-op -- cache invalidation not implemented for remote connector&lt;br /&gt;
|-&lt;br /&gt;
| GetUserAccountsWhere(scopeID, where) || (none) || Always returns null -- not implemented for regions&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
GetUserAccounts(List&amp;lt;string&amp;gt; IDs) fallback:&lt;br /&gt;
* Tries &amp;quot;getmultiaccounts&amp;quot; first&lt;br /&gt;
* If result == &amp;quot;Failure&amp;quot;: sets suported = false, falls back to calling GetUserAccount(scopeID, uuid) one by one&lt;br /&gt;
* Skips IDs that are not valid non-zero UUIDs in the fallback path&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
=== Notes ===&lt;br /&gt;
&lt;br /&gt;
* CreateUser() has a bug: the email field sends first name instead of the email value. The line reads sendData[&amp;quot;Email&amp;quot;] = first rather than sendData[&amp;quot;Email&amp;quot;] = email.&lt;br /&gt;
* SendAndGetBoolReply() is defined but never called -- dead code.&lt;br /&gt;
* InvalidateCache() is a no-op -- the remote connector has no local cache to invalidate.&lt;br /&gt;
* GetUserAccountsWhere() returns null unconditionally -- SQL WHERE clause queries are not supported over HTTP.&lt;br /&gt;
* ScopeID fields are present in the code but some are commented out.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== See Also ==&lt;br /&gt;
&lt;br /&gt;
* [[OpenSimulator Internals/Connector Architecture]]&lt;br /&gt;
* [[OpenSimulator Internals/Code Map/ROBUST/UserAccountService]]&lt;br /&gt;
* [[OpenSimulator Internals/Code Map/Shared]]&lt;/div&gt;</summary>
		<author><name>Jwbshaw</name></author>
	</entry>
</feed>