From dfe5e9d4ebb705d0c20d6260bae5d11659ac904d Mon Sep 17 00:00:00 2001
From: Justin Clarke Casey
Date: Mon, 7 Apr 2008 01:46:00 +0000
Subject: * EXPERIMENTAL ROUGH DRAFT: First rough implementation of avatar to
avatar item giving * Now you can drag an object from your inventory and give
it to another avatar * !!! Use at your own risk !!! Many things are
unimplemented as of yet, including permissions (the person receiving your
item can probably do absolutely everything with it) * Also, items for the
receiving end up in their root folder rather than the objects folder
---
OpenSim/Region/ClientStack/ClientView.cs | 84 ++++++++++-
.../Environment/Modules/InstantMessageModule.cs | 8 +-
.../Region/Environment/Modules/InventoryModule.cs | 158 ++++++++++++++++++++-
.../Region/Environment/Scenes/Scene.Inventory.cs | 87 +++++++++++-
.../Region/Examples/SimpleModule/MyNpcCharacter.cs | 11 ++
5 files changed, 337 insertions(+), 11 deletions(-)
(limited to 'OpenSim/Region')
diff --git a/OpenSim/Region/ClientStack/ClientView.cs b/OpenSim/Region/ClientStack/ClientView.cs
index a67c247..c98eb84 100644
--- a/OpenSim/Region/ClientStack/ClientView.cs
+++ b/OpenSim/Region/ClientStack/ClientView.cs
@@ -482,6 +482,11 @@ namespace OpenSim.Region.ClientStack
return result;
}
+ ///
+ /// Try to process a packet using registered packet handlers
+ ///
+ ///
+ /// True if a handler was found which successfully processed the packet.
protected virtual bool ProcessPacketMethod(Packet packet)
{
bool result = false;
@@ -865,14 +870,30 @@ namespace OpenSim.Region.ClientStack
}
///
- ///
+ /// Send an instant message to this client
///
///
///
public void SendInstantMessage(LLUUID fromAgent, LLUUID fromAgentSession, string message, LLUUID toAgent,
LLUUID imSessionID, string fromName, byte dialog, uint timeStamp)
{
- ImprovedInstantMessagePacket msg = (ImprovedInstantMessagePacket)PacketPool.Instance.GetPacket(PacketType.ImprovedInstantMessage);
+ SendInstantMessage(
+ fromAgent, fromAgentSession, message, toAgent,
+ imSessionID, fromName, dialog, timeStamp, new byte[0]);
+ }
+
+ ///
+ /// Send an instant message to this client
+ ///
+ ///
+ ///
+ public void SendInstantMessage(LLUUID fromAgent, LLUUID fromAgentSession, string message, LLUUID toAgent,
+ LLUUID imSessionID, string fromName, byte dialog, uint timeStamp,
+ byte[] binaryBucket)
+ {
+ ImprovedInstantMessagePacket msg
+ = (ImprovedInstantMessagePacket)PacketPool.Instance.GetPacket(PacketType.ImprovedInstantMessage);
+
msg.AgentData.AgentID = fromAgent;
msg.AgentData.SessionID = fromAgentSession;
msg.MessageBlock.FromAgentName = Helpers.StringToField(fromName);
@@ -886,7 +907,7 @@ namespace OpenSim.Region.ClientStack
msg.MessageBlock.Timestamp = timeStamp;
msg.MessageBlock.ToAgentID = toAgent;
msg.MessageBlock.Message = Helpers.StringToField(message);
- msg.MessageBlock.BinaryBucket = new byte[0];
+ msg.MessageBlock.BinaryBucket = binaryBucket;
OutPacket(msg, ThrottleOutPacketType.Task);
}
@@ -1374,12 +1395,67 @@ namespace OpenSim.Region.ClientStack
OutPacket(inventoryReply, ThrottleOutPacketType.Asset);
}
+
+ /// IClientAPI.SendBulkUpdateInventory(InventoryItemBase)
+ public void SendBulkUpdateInventory(InventoryItemBase item)
+ {
+ uint FULL_MASK_PERMISSIONS = (uint)PermissionMask.All;
+
+ BulkUpdateInventoryPacket bulkUpdate
+ = (BulkUpdateInventoryPacket)PacketPool.Instance.GetPacket(PacketType.BulkUpdateInventory);
+
+ bulkUpdate.AgentData.AgentID = AgentId;
+ bulkUpdate.AgentData.TransactionID = LLUUID.Random();
+
+ bulkUpdate.FolderData = new BulkUpdateInventoryPacket.FolderDataBlock[1];
+ bulkUpdate.FolderData[0] = new BulkUpdateInventoryPacket.FolderDataBlock();
+ bulkUpdate.FolderData[0].FolderID = LLUUID.Zero;
+ bulkUpdate.FolderData[0].ParentID = LLUUID.Zero;
+ bulkUpdate.FolderData[0].Type = -1;
+ bulkUpdate.FolderData[0].Name = new byte[0];
+
+ bulkUpdate.ItemData = new BulkUpdateInventoryPacket.ItemDataBlock[1];
+ bulkUpdate.ItemData[0] = new BulkUpdateInventoryPacket.ItemDataBlock();
+ bulkUpdate.ItemData[0].ItemID = item.inventoryID;
+ bulkUpdate.ItemData[0].AssetID = item.assetID;
+ bulkUpdate.ItemData[0].CreatorID = item.creatorsID;
+ bulkUpdate.ItemData[0].BaseMask = item.inventoryBasePermissions;
+ bulkUpdate.ItemData[0].CreationDate = 1000;
+ bulkUpdate.ItemData[0].Description = Helpers.StringToField(item.inventoryDescription);
+ bulkUpdate.ItemData[0].EveryoneMask = item.inventoryEveryOnePermissions;
+ bulkUpdate.ItemData[0].Flags = 0;
+ bulkUpdate.ItemData[0].FolderID = item.parentFolderID;
+ bulkUpdate.ItemData[0].GroupID = new LLUUID("00000000-0000-0000-0000-000000000000");
+ bulkUpdate.ItemData[0].GroupMask = 0;
+ bulkUpdate.ItemData[0].InvType = (sbyte)item.invType;
+ bulkUpdate.ItemData[0].Name = Helpers.StringToField(item.inventoryName);
+ bulkUpdate.ItemData[0].NextOwnerMask = item.inventoryNextPermissions;
+ bulkUpdate.ItemData[0].OwnerID = item.avatarID;
+ bulkUpdate.ItemData[0].OwnerMask = item.inventoryCurrentPermissions;
+ bulkUpdate.ItemData[0].SalePrice = 100;
+ bulkUpdate.ItemData[0].SaleType = 0;
+ bulkUpdate.ItemData[0].Type = (sbyte)item.assetType;
+ bulkUpdate.ItemData[0].CRC =
+ Helpers.InventoryCRC(1000, 0, bulkUpdate.ItemData[0].InvType,
+ bulkUpdate.ItemData[0].Type, bulkUpdate.ItemData[0].AssetID,
+ bulkUpdate.ItemData[0].GroupID, 100,
+ bulkUpdate.ItemData[0].OwnerID, bulkUpdate.ItemData[0].CreatorID,
+ bulkUpdate.ItemData[0].ItemID, bulkUpdate.ItemData[0].FolderID,
+ FULL_MASK_PERMISSIONS, 1, FULL_MASK_PERMISSIONS, FULL_MASK_PERMISSIONS,
+ FULL_MASK_PERMISSIONS);
+
+ OutPacket(bulkUpdate, ThrottleOutPacketType.Asset);
+ }
/// IClientAPI.SendInventoryItemCreateUpdate(InventoryItemBase)
public void SendInventoryItemCreateUpdate(InventoryItemBase Item)
{
uint FULL_MASK_PERMISSIONS = (uint)PermissionMask.All;
- UpdateCreateInventoryItemPacket InventoryReply = (UpdateCreateInventoryItemPacket)PacketPool.Instance.GetPacket(PacketType.UpdateCreateInventoryItem);
+
+ UpdateCreateInventoryItemPacket InventoryReply
+ = (UpdateCreateInventoryItemPacket)PacketPool.Instance.GetPacket(
+ PacketType.UpdateCreateInventoryItem);
+
// TODO: don't create new blocks if recycling an old packet
InventoryReply.AgentData.AgentID = AgentId;
InventoryReply.AgentData.SimApproved = true;
diff --git a/OpenSim/Region/Environment/Modules/InstantMessageModule.cs b/OpenSim/Region/Environment/Modules/InstantMessageModule.cs
index 53d9fd9..6f7235e 100644
--- a/OpenSim/Region/Environment/Modules/InstantMessageModule.cs
+++ b/OpenSim/Region/Environment/Modules/InstantMessageModule.cs
@@ -70,13 +70,17 @@ namespace OpenSim.Region.Environment.Modules
uint ParentEstateID, LLVector3 Position, LLUUID RegionID,
byte[] binaryBucket)
{
- bool FriendDialog = ((dialog == (byte)38) || (dialog == (byte)39) || (dialog == (byte)40));
+ bool dialogHandledElsewhere
+ = ((dialog == (byte)38) || (dialog == (byte)39) || (dialog == (byte)40)
+ || dialog == (byte)InstantMessageDialog.InventoryOffered
+ || dialog == (byte)InstantMessageDialog.InventoryAccepted
+ || dialog == (byte)InstantMessageDialog.InventoryDeclined);
// IM dialogs need to be pre-processed and have their sessionID filled by the server
// so the sim can match the transaction on the return packet.
// Don't send a Friend Dialog IM with a LLUUID.Zero session.
- if (!(FriendDialog && imSessionID == LLUUID.Zero))
+ if (!(dialogHandledElsewhere && imSessionID == LLUUID.Zero))
{
foreach (Scene scene in m_scenes)
{
diff --git a/OpenSim/Region/Environment/Modules/InventoryModule.cs b/OpenSim/Region/Environment/Modules/InventoryModule.cs
index a0f3832..eadbb4f 100644
--- a/OpenSim/Region/Environment/Modules/InventoryModule.cs
+++ b/OpenSim/Region/Environment/Modules/InventoryModule.cs
@@ -25,7 +25,13 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
+using System;
+using System.Collections.Generic;
+
+using libsecondlife;
using Nini.Config;
+
+using OpenSim.Framework;
using OpenSim.Region.Environment.Interfaces;
using OpenSim.Region.Environment.Scenes;
@@ -33,11 +39,22 @@ namespace OpenSim.Region.Environment.Modules
{
public class InventoryModule : IRegionModule
{
+ private static readonly log4net.ILog m_log
+ = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
+
private Scene m_scene;
+
+ ///
+ /// We need to keep track of the pending item offers between clients since the itemId offered only
+ /// occurs in the initial offer message, not the accept message. So this dictionary links
+ /// IM Session Ids to ItemIds
+ ///
+ private IDictionary m_pendingOffers = new Dictionary();
public void Initialise(Scene scene, IConfigSource config)
- {
+ {
m_scene = scene;
+ scene.EventManager.OnNewClient += OnNewClient;
}
public void PostInitialise()
@@ -57,5 +74,144 @@ namespace OpenSim.Region.Environment.Modules
{
get { return false; }
}
+
+ private void OnNewClient(IClientAPI client)
+ {
+ // Inventory giving is conducted via instant message
+ client.OnInstantMessage += OnInstantMessage;
+ }
+
+ private void OnInstantMessage(IClientAPI client, LLUUID fromAgentID,
+ LLUUID fromAgentSession, LLUUID toAgentID,
+ LLUUID imSessionID, uint timestamp, string fromAgentName,
+ string message, byte dialog, bool fromGroup, byte offline,
+ uint ParentEstateID, LLVector3 Position, LLUUID RegionID,
+ byte[] binaryBucket)
+ {
+ if (dialog == (byte)InstantMessageDialog.InventoryOffered)
+ {
+ m_log.DebugFormat(
+ "[AGENT INVENTORY]: Routing inventory offering message from {0}, {1} to {2}",
+ client.AgentId, client.Name, toAgentID);
+
+ if (m_scene.Entities.ContainsKey(toAgentID) && m_scene.Entities[toAgentID] is ScenePresence)
+ {
+ ScenePresence user = (ScenePresence)m_scene.Entities[toAgentID];
+
+ if (!user.IsChildAgent)
+ {
+ //byte[] rawId = new byte[16];
+
+ // First byte of the array is probably the item type
+ // Next 16 bytes are the UUID
+ //Array.Copy(binaryBucket, 1, rawId, 0, 16);
+
+ //LLUUID itemId = new LLUUID(new Guid(rawId));
+ LLUUID itemId = new LLUUID(binaryBucket, 1);
+
+ m_log.DebugFormat(
+ "[AGENT INVENTORY]: ItemId for giving is {0}", itemId);
+
+ m_pendingOffers[imSessionID] = itemId;
+
+ user.ControllingClient.SendInstantMessage(
+ fromAgentID, fromAgentSession, message, toAgentID, imSessionID, fromAgentName,
+ dialog, timestamp, binaryBucket);
+
+ return;
+ }
+ else
+ {
+ m_log.WarnFormat(
+ "[AGENT INVENTORY]: Agent {0} targeted for inventory give by {1}, {2} of {3} was a child agent!",
+ toAgentID, client.AgentId, client.Name, message);
+ }
+ }
+ else
+ {
+ m_log.WarnFormat(
+ "[AGENT INVENTORY]: Could not find agent {0} for user {1}, {2} to give {3}",
+ toAgentID, client.AgentId, client.Name, message);
+ }
+ }
+ else if (dialog == (byte)InstantMessageDialog.InventoryAccepted)
+ {
+ m_log.DebugFormat(
+ "[AGENT INVENTORY]: Routing inventory accepted message from {0}, {1} to {2}",
+ client.AgentId, client.Name, toAgentID);
+
+ if (m_scene.Entities.ContainsKey(toAgentID) && m_scene.Entities[toAgentID] is ScenePresence)
+ {
+ ScenePresence user = (ScenePresence)m_scene.Entities[toAgentID];
+
+ if (!user.IsChildAgent)
+ {
+ user.ControllingClient.SendInstantMessage(
+ fromAgentID, fromAgentSession, message, toAgentID, imSessionID, fromAgentName,
+ dialog, timestamp, binaryBucket);
+
+ if (m_pendingOffers.ContainsKey(imSessionID))
+ {
+ m_log.DebugFormat(
+ "[AGENT INVENTORY]: Accepted item id {0}", m_pendingOffers[imSessionID]);
+
+ // Since the message originates from the accepting client, the toAgentID is
+ // the agent giving the item.
+ m_scene.GiveInventoryItem(client, toAgentID, m_pendingOffers[imSessionID]);
+
+ m_pendingOffers.Remove(imSessionID);
+ }
+ else
+ {
+ m_log.ErrorFormat(
+ "[AGENT INVENTORY]: Could not find an item associated with session id {0} to accept",
+ imSessionID);
+ }
+
+ return;
+ }
+ else
+ {
+ m_log.WarnFormat(
+ "[AGENT INVENTORY]: Agent {0} targeted for inventory give by {1}, {2} of {3} was a child agent!",
+ toAgentID, client.AgentId, client.Name, message);
+ }
+ }
+ else
+ {
+ m_log.WarnFormat(
+ "[AGENT INVENTORY]: Could not find agent {0} for user {1}, {2} to give {3}",
+ toAgentID, client.AgentId, client.Name, message);
+ }
+ }
+ else if (dialog == (byte)InstantMessageDialog.InventoryDeclined)
+ {
+ if (m_scene.Entities.ContainsKey(toAgentID) && m_scene.Entities[toAgentID] is ScenePresence)
+ {
+ ScenePresence user = (ScenePresence)m_scene.Entities[toAgentID];
+
+ if (!user.IsChildAgent)
+ {
+ user.ControllingClient.SendInstantMessage(
+ fromAgentID, fromAgentSession, message, toAgentID, imSessionID, fromAgentName,
+ dialog, timestamp, binaryBucket);
+
+ if (m_pendingOffers.ContainsKey(imSessionID))
+ {
+ m_log.DebugFormat(
+ "[AGENT INVENTORY]: Declined item id {0}", m_pendingOffers[imSessionID]);
+
+ m_pendingOffers.Remove(imSessionID);
+ }
+ else
+ {
+ m_log.ErrorFormat(
+ "[AGENT INVENTORY]: Could not find an item associated with session id {0} to decline",
+ imSessionID);
+ }
+ }
+ }
+ }
+ }
}
}
diff --git a/OpenSim/Region/Environment/Scenes/Scene.Inventory.cs b/OpenSim/Region/Environment/Scenes/Scene.Inventory.cs
index 2b8f344..f6f1367 100644
--- a/OpenSim/Region/Environment/Scenes/Scene.Inventory.cs
+++ b/OpenSim/Region/Environment/Scenes/Scene.Inventory.cs
@@ -286,10 +286,89 @@ namespace OpenSim.Region.Environment.Scenes
"[AGENT INVENTORY]: Agent ID " + remoteClient.AgentId + " not found for an inventory item update.");
}
}
+
+ ///
+ /// Give an inventory item from one avatar to another
+ ///
+ ///
+ ///
+ ///
+ public void GiveInventoryItem(IClientAPI recipientClient, LLUUID senderId, LLUUID itemId)
+ {
+ // Retrieve the item from the sender
+ CachedUserInfo senderUserInfo = CommsManager.UserProfileCacheService.GetUserDetails(senderId);
+
+ if (senderUserInfo == null)
+ {
+ m_log.ErrorFormat(
+ "[AGENT INVENTORY]: Failed to find sending user {0} for item {1}", senderId, itemId);
+
+ return;
+ }
+
+ if (senderUserInfo.RootFolder != null)
+ {
+ InventoryItemBase item = senderUserInfo.RootFolder.HasItem(itemId);
+ if (item != null)
+ {
+ // TODO get recipient's root folder
+ CachedUserInfo recipientUserInfo
+ = CommsManager.UserProfileCacheService.GetUserDetails(recipientClient.AgentId);
+
+ if (recipientUserInfo != null)
+ {
+ // Insert a copy of the item into the recipient
+ InventoryItemBase itemCopy = new InventoryItemBase();
+ itemCopy.avatarID = recipientClient.AgentId;
+ itemCopy.creatorsID = recipientClient.AgentId;
+ itemCopy.inventoryID = LLUUID.Random();
+ itemCopy.assetID = item.assetID;
+ itemCopy.inventoryDescription = item.inventoryDescription;
+ itemCopy.inventoryName = item.inventoryName;
+ itemCopy.assetType = item.assetType;
+ itemCopy.invType = item.invType;
+ itemCopy.parentFolderID = recipientUserInfo.RootFolder.folderID;
+ itemCopy.inventoryCurrentPermissions = 2147483647;
+ itemCopy.inventoryNextPermissions = 2147483647;
+ itemCopy.inventoryEveryOnePermissions = item.inventoryEveryOnePermissions;
+ itemCopy.inventoryBasePermissions = item.inventoryBasePermissions;
+ itemCopy.inventoryCurrentPermissions = item.inventoryCurrentPermissions;
+
+ recipientUserInfo.AddItem(recipientClient.AgentId, itemCopy);
+
+ // Let the recipient client know about this new item
+ recipientClient.SendBulkUpdateInventory(itemCopy);
+ }
+ else
+ {
+ m_log.ErrorFormat(
+ "[AGENT INVENTORY]: Could not find userinfo for recipient user {0}, {1} of item {2}, {3} from {4}",
+ recipientClient.Name, recipientClient.AgentId, item.inventoryName,
+ item.inventoryID, senderId);
+ }
+ }
+ else
+ {
+ m_log.ErrorFormat(
+ "[AGENT INVENTORY]: Failed to find item {0} to give to {1}", itemId, senderId);
+
+ return;
+ }
+ }
+ else
+ {
+ m_log.Error("[AGENT INVENTORY]: Failed to find item " + itemId.ToString() + ", no root folder");
+ return;
+ }
+ }
public void CopyInventoryItem(IClientAPI remoteClient, uint callbackID, LLUUID oldAgentID, LLUUID oldItemID,
LLUUID newFolderID, string newName)
{
+ m_log.DebugFormat(
+ "[AGENT INVENTORY]: CopyInventoryItem received by {0} with oldAgentID {1}, oldItemID {2}, new FolderID {3}, newName {4}",
+ remoteClient.AgentId, oldAgentID, oldItemID, newFolderID, newName);
+
InventoryItemBase item = CommsManager.UserProfileCacheService.libraryRoot.HasItem(oldItemID);
if (item == null)
{
@@ -349,9 +428,8 @@ namespace OpenSim.Region.Environment.Scenes
public void MoveInventoryItem(IClientAPI remoteClient, LLUUID folderID, LLUUID itemID, int length,
string newName)
{
- m_log.Info(
- "[AGENT INVENTORY]: " +
- "Moving item for " + remoteClient.AgentId.ToString());
+ m_log.DebugFormat(
+ "[AGENT INVENTORY]: Moving item {0} to {1} for {2}", itemID, folderID, remoteClient.AgentId);
CachedUserInfo userInfo = CommsManager.UserProfileCacheService.GetUserDetails(remoteClient.AgentId);
if (userInfo == null)
@@ -429,7 +507,8 @@ namespace OpenSim.Region.Environment.Scenes
}
///
- /// Create a new inventory item.
+ /// Create a new inventory item. Called when the client creates a new item directly within their
+ /// inventory (e.g. by selecting a context inventory menu option).
///
///
///
diff --git a/OpenSim/Region/Examples/SimpleModule/MyNpcCharacter.cs b/OpenSim/Region/Examples/SimpleModule/MyNpcCharacter.cs
index 3f090df..9901a50 100644
--- a/OpenSim/Region/Examples/SimpleModule/MyNpcCharacter.cs
+++ b/OpenSim/Region/Examples/SimpleModule/MyNpcCharacter.cs
@@ -270,6 +270,12 @@ namespace OpenSim.Region.Examples.SimpleModule
LLUUID imSessionID, string fromName, byte dialog, uint timeStamp)
{
}
+
+ public virtual void SendInstantMessage(LLUUID fromAgent, LLUUID fromAgentSession, string message, LLUUID toAgent,
+ LLUUID imSessionID, string fromName, byte dialog, uint timeStamp,
+ byte[] binaryBucket)
+ {
+ }
public virtual void SendLayerData(float[] map)
{
@@ -388,6 +394,11 @@ namespace OpenSim.Region.Examples.SimpleModule
public virtual void SendRemoveInventoryItem(LLUUID itemID)
{
}
+
+ /// IClientAPI.SendBulkUpdateInventory(InventoryItemBase)
+ public virtual void SendBulkUpdateInventory(InventoryItemBase item)
+ {
+ }
public virtual void SendTaskInventory(LLUUID taskID, short serial, byte[] fileName)
{
--
cgit v1.1