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

		<summary type="html">&lt;p&gt;first&lt;/p&gt;
&lt;p&gt;&lt;b&gt;New page&lt;/b&gt;&lt;/p&gt;&lt;div&gt;= OpenSimulator Internals/Walkthroughs/Avatar 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&amp;#039;s inventory to buyer&amp;#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&amp;#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&amp;#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>
</feed>