* Initial framework support for multiple simulators. Currently only the first region config is loaded, but the framework is there
* Big reorganization of config and data files
* Started renaming extensions that handle LLUDP packets to start with the LL prefix. Work in progress
* Initial SSL support

git-svn-id: http://libopenmetaverse.googlecode.com/svn/libopenmetaverse/trunk@2482 52acb1d6-8a22-11de-b505-999d5b087335
This commit is contained in:
John Hurliman
2009-03-12 23:02:42 +00:00
parent 627e0dbef7
commit 70fe1f8f2a
101 changed files with 3083 additions and 1746 deletions

View File

@@ -5,7 +5,7 @@ using OpenMetaverse;
using OpenMetaverse.StructuredData;
using OpenMetaverse.Packets;
namespace Simian.Extensions
namespace Simian
{
public class InventoryManager : IExtension<Simian>, IInventoryProvider, IPersistable
{
@@ -14,620 +14,23 @@ namespace Simian.Extensions
/// is also a dictionary itself</summary>
Dictionary<UUID, Dictionary<UUID, InventoryObject>> Inventory =
new Dictionary<UUID, Dictionary<UUID, InventoryObject>>();
/// <summary>Global shared inventory for all agent</summary>
/// <summary>Global shared inventory for all agents</summary>
Dictionary<UUID, InventoryObject> Library = new Dictionary<UUID, InventoryObject>();
public InventoryManager()
{
}
public void Start(Simian server)
public bool Start(Simian server)
{
this.server = server;
server.UDP.RegisterPacketCallback(PacketType.CreateInventoryItem, new PacketCallback(CreateInventoryItemHandler));
server.UDP.RegisterPacketCallback(PacketType.CreateInventoryFolder, new PacketCallback(CreateInventoryFolderHandler));
server.UDP.RegisterPacketCallback(PacketType.UpdateInventoryItem, new PacketCallback(UpdateInventoryItemHandler));
server.UDP.RegisterPacketCallback(PacketType.FetchInventoryDescendents, new PacketCallback(FetchInventoryDescendentsHandler));
server.UDP.RegisterPacketCallback(PacketType.FetchInventory, new PacketCallback(FetchInventoryHandler));
server.UDP.RegisterPacketCallback(PacketType.CopyInventoryItem, new PacketCallback(CopyInventoryItemHandler));
server.UDP.RegisterPacketCallback(PacketType.MoveInventoryItem, new PacketCallback(MoveInventoryItemHandler));
server.UDP.RegisterPacketCallback(PacketType.MoveInventoryFolder, new PacketCallback(MoveInventoryFolderHandler));
server.UDP.RegisterPacketCallback(PacketType.PurgeInventoryDescendents, new PacketCallback(PurgeInventoryDescendentsHandler));
return true;
}
public void Stop()
{
}
Dictionary<UUID, InventoryObject> GetAgentInventory(UUID agentID)
{
Dictionary<UUID, InventoryObject> agentInventory;
if (!Inventory.TryGetValue(agentID, out agentInventory))
{
Logger.Log("Creating an empty inventory store for agent " + agentID.ToString(),
Helpers.LogLevel.Info);
agentInventory = new Dictionary<UUID, InventoryObject>();
lock (Inventory)
Inventory[agentID] = agentInventory;
}
return agentInventory;
}
void CreateInventoryItemHandler(Packet packet, Agent agent)
{
CreateInventoryItemPacket create = (CreateInventoryItemPacket)packet;
UUID assetID;
if (create.InventoryBlock.TransactionID != UUID.Zero)
assetID = UUID.Combine(create.InventoryBlock.TransactionID, agent.SecureSessionID);
else
assetID = UUID.Random();
UUID parentID = (create.InventoryBlock.FolderID != UUID.Zero) ? create.InventoryBlock.FolderID : agent.InventoryRoot;
AssetType assetType = (AssetType)create.InventoryBlock.Type;
switch (assetType)
{
case AssetType.Gesture:
Logger.Log("Need to create a default gesture asset!", Helpers.LogLevel.Warning);
break;
}
if (parentID == UUID.Zero)
parentID = agent.InventoryRoot;
// Create the inventory item
CreateItem(agent.ID, Utils.BytesToString(create.InventoryBlock.Name), "Created in Simian",
(InventoryType)create.InventoryBlock.InvType, assetType, assetID, parentID,
PermissionMask.All, (PermissionMask)create.InventoryBlock.NextOwnerMask, agent.ID,
agent.ID, create.InventoryBlock.TransactionID, create.InventoryBlock.CallbackID, true);
}
void CreateInventoryFolderHandler(Packet packet, Agent agent)
{
CreateInventoryFolderPacket create = (CreateInventoryFolderPacket)packet;
UUID folderID = create.FolderData.FolderID;
if (folderID == UUID.Zero)
folderID = agent.InventoryRoot;
CreateFolder(agent.ID, folderID, Utils.BytesToString(create.FolderData.Name),
(AssetType)create.FolderData.Type, create.FolderData.ParentID, agent.ID);
}
void UpdateInventoryItemHandler(Packet packet, Agent agent)
{
UpdateInventoryItemPacket update = (UpdateInventoryItemPacket)packet;
// No packet is sent back to the client, we just need to update the
// inventory item locally
for (int i = 0; i < update.InventoryData.Length; i++)
{
UpdateInventoryItemPacket.InventoryDataBlock block = update.InventoryData[i];
Dictionary<UUID, InventoryObject> agentInventory = GetAgentInventory(agent.ID);
InventoryObject obj;
if (agentInventory.TryGetValue(block.ItemID, out obj) && obj is InventoryItem)
{
InventoryItem item = (InventoryItem)obj;
//item.Permissions.BaseMask = (PermissionMask)block.BaseMask;
item.Permissions.BaseMask = PermissionMask.All;
//item.Permissions.EveryoneMask = (PermissionMask)block.EveryoneMask;
item.Permissions.EveryoneMask = PermissionMask.All;
//item.Permissions.GroupMask = (PermissionMask)block.GroupMask;
item.Permissions.GroupMask = PermissionMask.All;
//item.Permissions.NextOwnerMask = (PermissionMask)block.NextOwnerMask;
item.Permissions.NextOwnerMask = PermissionMask.All;
//item.Permissions.OwnerMask = (PermissionMask)block.OwnerMask;
item.Permissions.OwnerMask = PermissionMask.All;
//block.CRC;
item.CreationDate = Utils.UnixTimeToDateTime(block.CreationDate);
item.CreatorID = block.CreatorID;
item.Name = Utils.BytesToString(block.Description);
item.Flags = block.Flags;
item.ParentID = block.FolderID;
item.GroupID = block.GroupID;
item.GroupOwned = block.GroupOwned;
item.InventoryType = (InventoryType)block.InvType;
item.Name = Utils.BytesToString(block.Name);
item.OwnerID = block.OwnerID;
item.SalePrice = block.SalePrice;
item.SaleType = (SaleType)block.SaleType;
item.AssetType = (AssetType)block.Type;
item.AssetID = UUID.Combine(block.TransactionID, agent.SecureSessionID);
Logger.DebugLog(String.Format(
"UpdateInventoryItem: CallbackID: {0}, TransactionID: {1}",
block.CallbackID, block.TransactionID));
}
else
{
Logger.Log("Received an UpdateInventoryItem packet for unknown inventory item " +
block.ItemID.ToString(), Helpers.LogLevel.Warning);
}
}
}
void FetchInventoryDescendentsHandler(Packet packet, Agent agent)
{
// A very safe estimate of the fixed minimum packet size
const int PACKET_OVERHEAD = 96;
FetchInventoryDescendentsPacket fetch = (FetchInventoryDescendentsPacket)packet;
bool sendFolders = fetch.InventoryData.FetchFolders;
bool sendItems = fetch.InventoryData.FetchItems;
// TODO: Obey SortOrder
//InventorySortOrder order = (InventorySortOrder)fetch.InventoryData.SortOrder;
Dictionary<UUID, InventoryObject> agentInventory = GetAgentInventory(agent.ID);
// TODO: Use OwnerID
// TODO: Do we need to obey InventorySortOrder?
InventoryObject invObject;
if (agentInventory.TryGetValue(fetch.InventoryData.FolderID, out invObject) && invObject is InventoryFolder)
{
InventoryFolder folder = (InventoryFolder)invObject;
int descendCount;
int version;
List<InventoryItem> items = new List<InventoryItem>();
List<InventoryFolder> folders = new List<InventoryFolder>();
InventoryDescendentsPacket.FolderDataBlock[] folderBlocks;
InventoryDescendentsPacket.ItemDataBlock[] itemBlocks;
lock (folder.Children.Dictionary)
{
// These two are coupled to the actual items in the dictionary,
// so they are set inside the lock
descendCount = folder.Children.Count;
version = folder.Version;
if (sendItems || sendFolders)
{
// Create a list of all of the folders and items under this folder
folder.Children.ForEach(
delegate(InventoryObject obj)
{
if (obj is InventoryItem)
items.Add((InventoryItem)obj);
else
folders.Add((InventoryFolder)obj);
}
);
}
}
if (sendFolders)
{
folderBlocks = new InventoryDescendentsPacket.FolderDataBlock[folders.Count];
for (int i = 0; i < folders.Count; i++)
{
InventoryFolder currentFolder = folders[i];
folderBlocks[i] = new InventoryDescendentsPacket.FolderDataBlock();
folderBlocks[i].FolderID = currentFolder.ID;
folderBlocks[i].Name = Utils.StringToBytes(currentFolder.Name);
folderBlocks[i].ParentID = currentFolder.ParentID;
folderBlocks[i].Type = (sbyte)currentFolder.PreferredType;
}
}
else
{
folderBlocks = new InventoryDescendentsPacket.FolderDataBlock[0];
}
if (sendItems)
{
itemBlocks = new InventoryDescendentsPacket.ItemDataBlock[items.Count];
for (int i = 0; i < items.Count; i++)
{
InventoryItem currentItem = items[i];
itemBlocks[i] = new InventoryDescendentsPacket.ItemDataBlock();
itemBlocks[i].AssetID = currentItem.AssetID;
itemBlocks[i].BaseMask = (uint)currentItem.Permissions.BaseMask;
itemBlocks[i].CRC = currentItem.CRC;
itemBlocks[i].CreationDate = (int)Utils.DateTimeToUnixTime(currentItem.CreationDate);
itemBlocks[i].CreatorID = currentItem.CreatorID;
itemBlocks[i].Description = Utils.StringToBytes(currentItem.Description);
itemBlocks[i].EveryoneMask = (uint)currentItem.Permissions.EveryoneMask;
itemBlocks[i].Flags = currentItem.Flags;
itemBlocks[i].FolderID = currentItem.ParentID;
itemBlocks[i].GroupID = currentItem.GroupID;
itemBlocks[i].GroupMask = (uint)currentItem.Permissions.GroupMask;
itemBlocks[i].GroupOwned = currentItem.GroupOwned;
itemBlocks[i].InvType = (sbyte)currentItem.InventoryType;
itemBlocks[i].ItemID = currentItem.ID;
itemBlocks[i].Name = Utils.StringToBytes(currentItem.Name);
itemBlocks[i].NextOwnerMask = (uint)currentItem.Permissions.NextOwnerMask;
itemBlocks[i].OwnerID = currentItem.OwnerID;
itemBlocks[i].OwnerMask = (uint)currentItem.Permissions.OwnerMask;
itemBlocks[i].SalePrice = currentItem.SalePrice;
itemBlocks[i].SaleType = (byte)currentItem.SaleType;
itemBlocks[i].Type = (sbyte)currentItem.AssetType;
}
}
else
{
itemBlocks = new InventoryDescendentsPacket.ItemDataBlock[0];
}
// FolderDataBlock and ItemDataBlock are both variable and possibly very large,
// so we handle the splitting separately. This could be replaced by some custom
// splitting
if (folderBlocks.Length > 0)
{
List<int> splitPoints = Helpers.SplitBlocks(folderBlocks, PACKET_OVERHEAD);
Logger.DebugLog(String.Format("Sending {0} InventoryDescendents packets containing {1} folders",
splitPoints.Count, folderBlocks.Length));
for (int i = 0; i < splitPoints.Count; i++)
{
int count = (i != splitPoints.Count - 1) ? splitPoints[i + 1] - splitPoints[i] :
folderBlocks.Length - splitPoints[i];
InventoryDescendentsPacket descendents = new InventoryDescendentsPacket();
descendents.AgentData.AgentID = agent.ID;
descendents.AgentData.FolderID = folder.ID;
descendents.AgentData.OwnerID = folder.OwnerID;
descendents.AgentData.Descendents = descendCount;
descendents.AgentData.Version = version;
descendents.FolderData = new InventoryDescendentsPacket.FolderDataBlock[count];
descendents.ItemData = new InventoryDescendentsPacket.ItemDataBlock[0];
for (int j = 0; j < count; j++)
descendents.FolderData[j] = folderBlocks[splitPoints[i] + j];
server.UDP.SendPacket(agent.ID, descendents, PacketCategory.Inventory);
}
}
else
{
Logger.DebugLog("Sending a single InventoryDescendents for folders");
InventoryDescendentsPacket descendents = new InventoryDescendentsPacket();
descendents.AgentData.AgentID = agent.ID;
descendents.AgentData.FolderID = folder.ID;
descendents.AgentData.OwnerID = folder.OwnerID;
descendents.AgentData.Descendents = descendCount;
descendents.AgentData.Version = version;
descendents.FolderData = new InventoryDescendentsPacket.FolderDataBlock[0];
descendents.ItemData = new InventoryDescendentsPacket.ItemDataBlock[0];
server.UDP.SendPacket(agent.ID, descendents, PacketCategory.Inventory);
}
if (itemBlocks.Length > 0)
{
List<int> splitPoints = Helpers.SplitBlocks(itemBlocks, PACKET_OVERHEAD);
Logger.DebugLog(String.Format("Sending {0} InventoryDescendents packets containing {1} items",
splitPoints.Count, itemBlocks.Length));
for (int i = 0; i < splitPoints.Count; i++)
{
int count = (i != splitPoints.Count - 1) ? splitPoints[i + 1] - splitPoints[i] :
itemBlocks.Length - splitPoints[i];
InventoryDescendentsPacket descendents = new InventoryDescendentsPacket();
descendents.AgentData.AgentID = agent.ID;
descendents.AgentData.FolderID = folder.ID;
descendents.AgentData.OwnerID = folder.OwnerID;
descendents.AgentData.Descendents = descendCount;
descendents.AgentData.Version = version;
descendents.FolderData = new InventoryDescendentsPacket.FolderDataBlock[0];
descendents.ItemData = new InventoryDescendentsPacket.ItemDataBlock[count];
for (int j = 0; j < count; j++)
descendents.ItemData[j] = itemBlocks[splitPoints[i] + j];
server.UDP.SendPacket(agent.ID, descendents, PacketCategory.Inventory);
}
}
}
else
{
Logger.Log("FetchInventoryDescendents called for an unknown folder " + fetch.InventoryData.FolderID,
Helpers.LogLevel.Warning);
}
}
void FetchInventoryHandler(Packet packet, Agent agent)
{
// This is probably too large, but better to be on the safe side
const int PACKET_OVERHEAD = 32;
FetchInventoryPacket fetch = (FetchInventoryPacket)packet;
// Create all of the blocks first. These will be split up into different packets
FetchInventoryReplyPacket.InventoryDataBlock[] blocks =
new FetchInventoryReplyPacket.InventoryDataBlock[fetch.InventoryData.Length];
for (int i = 0; i < fetch.InventoryData.Length; i++)
{
UUID itemID = fetch.InventoryData[i].ItemID;
Dictionary<UUID, InventoryObject> agentInventory = GetAgentInventory(agent.ID);
blocks[i] = new FetchInventoryReplyPacket.InventoryDataBlock();
blocks[i].ItemID = itemID;
InventoryObject obj;
if (agentInventory.TryGetValue(itemID, out obj) && obj is InventoryItem)
{
InventoryItem item = (InventoryItem)obj;
blocks[i].AssetID = item.AssetID;
blocks[i].BaseMask = (uint)item.Permissions.BaseMask;
blocks[i].CRC = item.CRC;
blocks[i].CreationDate = (int)Utils.DateTimeToUnixTime(item.CreationDate);
blocks[i].CreatorID = item.CreatorID;
blocks[i].Description = Utils.StringToBytes(item.Description);
blocks[i].EveryoneMask = (uint)item.Permissions.EveryoneMask;
blocks[i].Flags = item.Flags;
blocks[i].FolderID = item.ParentID;
blocks[i].GroupID = item.GroupID;
blocks[i].GroupMask = (uint)item.Permissions.GroupMask;
blocks[i].GroupOwned = item.GroupOwned;
blocks[i].InvType = (sbyte)item.InventoryType;
blocks[i].Name = Utils.StringToBytes(item.Name);
blocks[i].NextOwnerMask = (uint)item.Permissions.NextOwnerMask;
blocks[i].OwnerID = item.OwnerID;
blocks[i].OwnerMask = (uint)item.Permissions.OwnerMask;
blocks[i].SalePrice = item.SalePrice;
blocks[i].SaleType = (byte)item.SaleType;
blocks[i].Type = (sbyte)item.AssetType;
}
else
{
Logger.Log("FetchInventory called for an unknown item " + itemID.ToString(),
Helpers.LogLevel.Warning);
blocks[i].Name = Utils.EmptyBytes;
blocks[i].Description = Utils.EmptyBytes;
}
}
// Split the blocks up into multiple packets
List<int> splitPoints = Helpers.SplitBlocks(blocks, PACKET_OVERHEAD);
for (int i = 0; i < splitPoints.Count; i++)
{
int count = (i != splitPoints.Count - 1) ? splitPoints[i + 1] - splitPoints[i] :
blocks.Length - splitPoints[i];
FetchInventoryReplyPacket reply = new FetchInventoryReplyPacket();
reply.AgentData.AgentID = agent.ID;
reply.InventoryData = new FetchInventoryReplyPacket.InventoryDataBlock[count];
for (int j = 0; j < count; j++)
reply.InventoryData[j] = blocks[splitPoints[i] + j];
server.UDP.SendPacket(agent.ID, reply, PacketCategory.Inventory);
}
}
void CopyInventoryItemHandler(Packet packet, Agent agent)
{
CopyInventoryItemPacket copy = (CopyInventoryItemPacket)packet;
for (int i = 0; i < copy.InventoryData.Length; i++)
{
CopyInventoryItemPacket.InventoryDataBlock block = copy.InventoryData[i];
// TODO: This allows someone to copy objects from another
// agent's inventory. Should we allow that, or do any
// permission checks?
Dictionary<UUID, InventoryObject> agentInventory = GetAgentInventory(block.OldAgentID);
// Get the original object
InventoryObject obj;
if (agentInventory.TryGetValue(block.OldItemID, out obj) && obj is InventoryItem)
{
InventoryItem item = (InventoryItem)obj;
// Get the new folder
InventoryObject folderObj;
if (agentInventory.TryGetValue(block.NewFolderID, out folderObj) && folderObj is InventoryFolder)
{
string newName = Utils.BytesToString(block.NewName);
if (String.IsNullOrEmpty(newName))
newName = item.Name;
// Create the copy
CreateItem(agent.ID, newName, item.Description, item.InventoryType, item.AssetType,
item.AssetID, folderObj.ID, item.Permissions.OwnerMask, item.Permissions.NextOwnerMask,
agent.ID, item.CreatorID, UUID.Zero, block.CallbackID, true);
}
else
{
Logger.Log("CopyInventoryItem called with an unknown target folder " + block.NewFolderID,
Helpers.LogLevel.Warning);
}
}
else
{
Logger.Log("CopyInventoryItem called for an unknown item " + block.OldItemID,
Helpers.LogLevel.Warning);
}
}
}
void MoveInventoryItemHandler(Packet packet, Agent agent)
{
MoveInventoryItemPacket move = (MoveInventoryItemPacket)packet;
// TODO: What is move.AgentData.Stamp for?
Dictionary<UUID, InventoryObject> agentInventory = GetAgentInventory(agent.ID);
for (int i = 0; i < move.InventoryData.Length; i++)
{
MoveInventoryItemPacket.InventoryDataBlock block = move.InventoryData[i];
UUID newFolderID = block.FolderID;
if (newFolderID == UUID.Zero)
newFolderID = agent.InventoryRoot;
MoveInventory(agent, agentInventory, block.ItemID, newFolderID, Utils.BytesToString(block.NewName),
UUID.Zero, 0);
}
}
void MoveInventoryFolderHandler(Packet packet, Agent agent)
{
MoveInventoryFolderPacket move = (MoveInventoryFolderPacket)packet;
// TODO: What is move.AgentData.Stamp for?
Dictionary<UUID, InventoryObject> agentInventory = GetAgentInventory(agent.ID);
for (int i = 0; i < move.InventoryData.Length; i++)
{
MoveInventoryFolderPacket.InventoryDataBlock block = move.InventoryData[i];
UUID newFolderID = block.ParentID;
if (newFolderID == UUID.Zero)
newFolderID = agent.InventoryRoot;
MoveInventory(agent, agentInventory, block.FolderID, newFolderID, null, UUID.Zero, 0);
}
}
void SendBulkUpdate(Agent agent, InventoryObject obj, UUID transactionID, uint callbackID)
{
BulkUpdateInventoryPacket update = new BulkUpdateInventoryPacket();
update.AgentData.AgentID = agent.ID;
update.AgentData.TransactionID = transactionID;
if (obj is InventoryItem)
{
InventoryItem item = (InventoryItem)obj;
update.FolderData = new BulkUpdateInventoryPacket.FolderDataBlock[0];
update.ItemData = new BulkUpdateInventoryPacket.ItemDataBlock[1];
update.ItemData[0] = new BulkUpdateInventoryPacket.ItemDataBlock();
update.ItemData[0].AssetID = item.AssetID;
update.ItemData[0].BaseMask = (uint)item.Permissions.BaseMask;
update.ItemData[0].CallbackID = callbackID;
update.ItemData[0].CRC = item.CRC;
update.ItemData[0].CreationDate = (int)Utils.DateTimeToUnixTime(item.CreationDate);
update.ItemData[0].CreatorID = item.CreatorID;
update.ItemData[0].Description = Utils.StringToBytes(item.Description);
update.ItemData[0].EveryoneMask = (uint)item.Permissions.EveryoneMask;
update.ItemData[0].Flags = item.Flags;
update.ItemData[0].FolderID = item.ParentID;
update.ItemData[0].GroupID = item.GroupID;
update.ItemData[0].GroupMask = (uint)item.Permissions.GroupMask;
update.ItemData[0].GroupOwned = item.GroupOwned;
update.ItemData[0].InvType = (sbyte)item.InventoryType;
update.ItemData[0].ItemID = item.ID;
update.ItemData[0].Name = Utils.StringToBytes(item.Name);
update.ItemData[0].NextOwnerMask = (uint)item.Permissions.NextOwnerMask;
update.ItemData[0].OwnerID = item.OwnerID;
update.ItemData[0].OwnerMask = (uint)item.Permissions.OwnerMask;
update.ItemData[0].SalePrice = item.SalePrice;
update.ItemData[0].SaleType = (byte)item.SaleType;
update.ItemData[0].Type = (sbyte)item.InventoryType;
}
else
{
InventoryFolder folder = (InventoryFolder)obj;
update.ItemData = new BulkUpdateInventoryPacket.ItemDataBlock[0];
update.FolderData = new BulkUpdateInventoryPacket.FolderDataBlock[1];
update.FolderData[0] = new BulkUpdateInventoryPacket.FolderDataBlock();
update.FolderData[0].FolderID = folder.ID;
update.FolderData[0].Name = Utils.StringToBytes(folder.Name);
update.FolderData[0].ParentID = folder.ParentID;
update.FolderData[0].Type = (sbyte)folder.PreferredType;
}
Logger.DebugLog("Sending bulk update for inventory object " + obj.ID);
server.UDP.SendPacket(agent.ID, update, PacketCategory.Inventory);
}
void MoveInventory(Agent agent, Dictionary<UUID, InventoryObject> agentInventory, UUID objectID,
UUID newFolderID, string newName, UUID transactionID, uint callbackID)
{
InventoryObject obj;
if (agentInventory.TryGetValue(objectID, out obj))
{
lock (agentInventory)
{
InventoryObject newParentObj;
if (agentInventory.TryGetValue(newFolderID, out newParentObj) && newParentObj is InventoryFolder)
{
// Remove this item from the current parent
if (obj.Parent != null)
{
InventoryFolder parent = (InventoryFolder)obj.Parent;
lock (parent.Children.Dictionary)
parent.Children.Dictionary.Remove(obj.ID);
}
// Update the new parent
InventoryFolder newParent = (InventoryFolder)newParentObj;
newParent.Children.Dictionary[obj.ID] = obj;
// Update the object
obj.ParentID = newParent.ID;
obj.Parent = newParent;
if (!String.IsNullOrEmpty(newName))
obj.Name = newName;
}
else
{
Logger.Log("MoveInventory called with an unknown destination folder " + newFolderID,
Helpers.LogLevel.Warning);
}
SendBulkUpdate(agent, obj, transactionID, callbackID);
}
}
else
{
Logger.Log("MoveInventory called for an unknown object " + objectID,
Helpers.LogLevel.Warning);
}
}
void PurgeInventoryDescendentsHandler(Packet packet, Agent agent)
{
PurgeInventoryDescendentsPacket purge = (PurgeInventoryDescendentsPacket)packet;
Dictionary<UUID, InventoryObject> agentInventory = GetAgentInventory(agent.ID);
InventoryObject obj;
if (agentInventory.TryGetValue(purge.InventoryData.FolderID, out obj) && obj is InventoryFolder)
{
lock (agentInventory)
PurgeFolder(agentInventory, (InventoryFolder)obj);
}
else
{
Logger.Log("PurgeInventoryDescendents called on a missing folder " + purge.InventoryData.FolderID,
Helpers.LogLevel.Warning);
}
}
void PurgeFolder(Dictionary<UUID, InventoryObject> inventory, InventoryFolder folder)
{
folder.Children.ForEach(
delegate(InventoryObject child)
{
inventory.Remove(child.ID);
if (child is InventoryFolder)
{
InventoryFolder childFolder = (InventoryFolder)child;
PurgeFolder(inventory, childFolder);
}
}
);
lock (folder.Children.Dictionary)
folder.Children.Dictionary.Clear();
}
public bool CreateRootFolder(UUID agentID, UUID folderID, string name, UUID ownerID)
{
Dictionary<UUID, InventoryObject> agentInventory = GetAgentInventory(agentID);
@@ -710,9 +113,9 @@ namespace Simian.Extensions
return false;
}
public UUID CreateItem(UUID agentID, string name, string description, InventoryType invType, AssetType type,
public InventoryItem CreateItem(UUID agentID, string name, string description, InventoryType invType, AssetType type,
UUID assetID, UUID parentID, PermissionMask ownerMask, PermissionMask nextOwnerMask, UUID ownerID,
UUID creatorID, UUID transactionID, uint callbackID, bool sendPacket)
UUID creatorID, UUID transactionID, uint callbackID)
{
Dictionary<UUID, InventoryObject> agentInventory = GetAgentInventory(agentID);
@@ -752,43 +155,7 @@ namespace Simian.Extensions
lock (parentFolder.Children.Dictionary)
parentFolder.Children.Dictionary[item.ID] = item;
// Send a success response
UpdateCreateInventoryItemPacket update = new UpdateCreateInventoryItemPacket();
update.AgentData.AgentID = agentID;
update.AgentData.SimApproved = true;
if (transactionID != UUID.Zero)
update.AgentData.TransactionID = transactionID;
else
update.AgentData.TransactionID = UUID.Random();
update.InventoryData = new UpdateCreateInventoryItemPacket.InventoryDataBlock[1];
update.InventoryData[0] = new UpdateCreateInventoryItemPacket.InventoryDataBlock();
update.InventoryData[0].AssetID = assetID;
update.InventoryData[0].BaseMask = (uint)PermissionMask.All;
update.InventoryData[0].CallbackID = callbackID;
update.InventoryData[0].CreationDate = (int)Utils.DateTimeToUnixTime(item.CreationDate);
update.InventoryData[0].CRC = item.CRC;
update.InventoryData[0].CreatorID = item.CreatorID;
update.InventoryData[0].Description = Utils.StringToBytes(item.Description);
update.InventoryData[0].EveryoneMask = (uint)item.Permissions.EveryoneMask;
update.InventoryData[0].Flags = item.Flags;
update.InventoryData[0].FolderID = item.ParentID;
update.InventoryData[0].GroupID = item.GroupID;
update.InventoryData[0].GroupMask = (uint)item.Permissions.GroupMask;
update.InventoryData[0].GroupOwned = item.GroupOwned;
update.InventoryData[0].InvType = (sbyte)item.InventoryType;
update.InventoryData[0].ItemID = item.ID;
update.InventoryData[0].Name = Utils.StringToBytes(item.Name);
update.InventoryData[0].NextOwnerMask = (uint)item.Permissions.NextOwnerMask;
update.InventoryData[0].OwnerID = item.OwnerID;
update.InventoryData[0].OwnerMask = (uint)item.Permissions.OwnerMask;
update.InventoryData[0].SalePrice = item.SalePrice;
update.InventoryData[0].SaleType = (byte)item.SaleType;
update.InventoryData[0].Type = (sbyte)item.AssetType;
if (sendPacket)
server.UDP.SendPacket(agentID, update, PacketCategory.Inventory);
return item.ID;
return item;
}
else
{
@@ -796,11 +163,87 @@ namespace Simian.Extensions
"Cannot create new inventory item, folder {0} does not exist",
parentID), Helpers.LogLevel.Warning);
return UUID.Zero;
return null;
}
}
}
public InventoryObject MoveInventory(UUID agentID, UUID objectID, UUID newFolderID, string newName, UUID transactionID, uint callbackID)
{
Dictionary<UUID, InventoryObject> agentInventory = GetAgentInventory(agentID);
InventoryObject obj;
if (agentInventory.TryGetValue(objectID, out obj))
{
lock (agentInventory)
{
InventoryObject newParentObj;
if (agentInventory.TryGetValue(newFolderID, out newParentObj) && newParentObj is InventoryFolder)
{
// Remove this item from the current parent
if (obj.Parent != null)
{
InventoryFolder parent = (InventoryFolder)obj.Parent;
lock (parent.Children.Dictionary)
parent.Children.Dictionary.Remove(obj.ID);
}
// Update the new parent
InventoryFolder newParent = (InventoryFolder)newParentObj;
newParent.Children.Dictionary[obj.ID] = obj;
// Update the object
obj.ParentID = newParent.ID;
obj.Parent = newParent;
if (!String.IsNullOrEmpty(newName))
obj.Name = newName;
return obj;
}
else
{
Logger.Log("MoveInventory called with an unknown destination folder " + newFolderID,
Helpers.LogLevel.Warning);
return null;
}
}
}
else
{
Logger.Log("MoveInventory called for an unknown object " + objectID,
Helpers.LogLevel.Warning);
return null;
}
}
public void PurgeFolder(UUID agentID, UUID folderID)
{
Dictionary<UUID, InventoryObject> agentInventory = GetAgentInventory(agentID);
InventoryObject obj;
if (TryGetInventory(agentID, folderID, out obj) && obj is InventoryFolder)
{
InventoryFolder folder = (InventoryFolder)obj;
folder.Children.ForEach(
delegate(InventoryObject child)
{
agentInventory.Remove(child.ID);
if (child is InventoryFolder)
PurgeFolder(agentID, child.ID);
}
);
lock (folder.Children.Dictionary)
folder.Children.Dictionary.Clear();
}
else
{
Logger.Log("PurgeFolder called on a missing folder " + folderID, Helpers.LogLevel.Warning);
}
}
public bool TryGetInventory(UUID agentID, UUID objectID, out InventoryObject obj)
{
Dictionary<UUID, InventoryObject> inventory;
@@ -856,6 +299,27 @@ namespace Simian.Extensions
}
}
public bool InventoryExists(UUID agentID)
{
return Inventory.ContainsKey(agentID);
}
Dictionary<UUID, InventoryObject> GetAgentInventory(UUID agentID)
{
Dictionary<UUID, InventoryObject> agentInventory;
if (!Inventory.TryGetValue(agentID, out agentInventory))
{
Logger.Log("Creating an empty inventory store for agent " + agentID.ToString(),
Helpers.LogLevel.Info);
agentInventory = new Dictionary<UUID, InventoryObject>();
lock (Inventory)
Inventory[agentID] = agentInventory;
}
return agentInventory;
}
#region Persistence
OSDMap SerializeItem(InventoryItem item)