* 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
0.6.0-stable
Justin Clarke Casey 2008-04-07 01:46:00 +00:00
parent 7149c8b0c6
commit dfe5e9d4eb
6 changed files with 349 additions and 12 deletions

View File

@ -576,6 +576,9 @@ namespace OpenSim.Framework
void SendInstantMessage(LLUUID fromAgent, LLUUID fromAgentSession, string message, LLUUID toAgent, void SendInstantMessage(LLUUID fromAgent, LLUUID fromAgentSession, string message, LLUUID toAgent,
LLUUID imSessionID, string fromName, byte dialog, uint timeStamp); LLUUID imSessionID, string fromName, byte dialog, uint timeStamp);
void SendInstantMessage(LLUUID fromAgent, LLUUID fromAgentSession, string message, LLUUID toAgent,
LLUUID imSessionID, string fromName, byte dialog, uint timeStamp,
byte[] binaryBucket);
void SendLayerData(float[] map); void SendLayerData(float[] map);
void SendLayerData(int px, int py, float[] map); void SendLayerData(int px, int py, float[] map);
@ -635,6 +638,14 @@ namespace OpenSim.Framework
void SendRemoveInventoryItem(LLUUID itemID); void SendRemoveInventoryItem(LLUUID itemID);
void SendTaskInventory(LLUUID taskID, short serial, byte[] fileName); void SendTaskInventory(LLUUID taskID, short serial, byte[] fileName);
/// <summary>
/// Used by the server to inform the client of a new inventory item. Used when transferring items
/// between avatars, possibly among other things.
/// </summary>
/// <param name="item"></param>
void SendBulkUpdateInventory(InventoryItemBase item);
void SendXferPacket(ulong xferID, uint packet, byte[] data); void SendXferPacket(ulong xferID, uint packet, byte[] data);
void SendAvatarPickerReply(AvatarPickerReplyPacket Pack); void SendAvatarPickerReply(AvatarPickerReplyPacket Pack);

View File

@ -482,6 +482,11 @@ namespace OpenSim.Region.ClientStack
return result; return result;
} }
/// <summary>
/// Try to process a packet using registered packet handlers
/// </summary>
/// <param name="packet"></param>
/// <returns>True if a handler was found which successfully processed the packet.</returns>
protected virtual bool ProcessPacketMethod(Packet packet) protected virtual bool ProcessPacketMethod(Packet packet)
{ {
bool result = false; bool result = false;
@ -865,14 +870,30 @@ namespace OpenSim.Region.ClientStack
} }
/// <summary> /// <summary>
/// /// Send an instant message to this client
/// </summary> /// </summary>
/// <param name="message"></param> /// <param name="message"></param>
/// <param name="target"></param> /// <param name="target"></param>
public void SendInstantMessage(LLUUID fromAgent, LLUUID fromAgentSession, string message, LLUUID toAgent, public void SendInstantMessage(LLUUID fromAgent, LLUUID fromAgentSession, string message, LLUUID toAgent,
LLUUID imSessionID, string fromName, byte dialog, uint timeStamp) 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]);
}
/// <summary>
/// Send an instant message to this client
/// </summary>
/// <param name="message"></param>
/// <param name="target"></param>
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.AgentID = fromAgent;
msg.AgentData.SessionID = fromAgentSession; msg.AgentData.SessionID = fromAgentSession;
msg.MessageBlock.FromAgentName = Helpers.StringToField(fromName); msg.MessageBlock.FromAgentName = Helpers.StringToField(fromName);
@ -886,7 +907,7 @@ namespace OpenSim.Region.ClientStack
msg.MessageBlock.Timestamp = timeStamp; msg.MessageBlock.Timestamp = timeStamp;
msg.MessageBlock.ToAgentID = toAgent; msg.MessageBlock.ToAgentID = toAgent;
msg.MessageBlock.Message = Helpers.StringToField(message); msg.MessageBlock.Message = Helpers.StringToField(message);
msg.MessageBlock.BinaryBucket = new byte[0]; msg.MessageBlock.BinaryBucket = binaryBucket;
OutPacket(msg, ThrottleOutPacketType.Task); OutPacket(msg, ThrottleOutPacketType.Task);
} }
@ -1375,11 +1396,66 @@ namespace OpenSim.Region.ClientStack
OutPacket(inventoryReply, ThrottleOutPacketType.Asset); OutPacket(inventoryReply, ThrottleOutPacketType.Asset);
} }
/// <see>IClientAPI.SendBulkUpdateInventory(InventoryItemBase)</see>
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);
}
/// <see>IClientAPI.SendInventoryItemCreateUpdate(InventoryItemBase)</see> /// <see>IClientAPI.SendInventoryItemCreateUpdate(InventoryItemBase)</see>
public void SendInventoryItemCreateUpdate(InventoryItemBase Item) public void SendInventoryItemCreateUpdate(InventoryItemBase Item)
{ {
uint FULL_MASK_PERMISSIONS = (uint)PermissionMask.All; 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 // TODO: don't create new blocks if recycling an old packet
InventoryReply.AgentData.AgentID = AgentId; InventoryReply.AgentData.AgentID = AgentId;
InventoryReply.AgentData.SimApproved = true; InventoryReply.AgentData.SimApproved = true;

View File

@ -70,13 +70,17 @@ namespace OpenSim.Region.Environment.Modules
uint ParentEstateID, LLVector3 Position, LLUUID RegionID, uint ParentEstateID, LLVector3 Position, LLUUID RegionID,
byte[] binaryBucket) 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 // 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. // so the sim can match the transaction on the return packet.
// Don't send a Friend Dialog IM with a LLUUID.Zero session. // 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) foreach (Scene scene in m_scenes)
{ {

View File

@ -25,7 +25,13 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
using System;
using System.Collections.Generic;
using libsecondlife;
using Nini.Config; using Nini.Config;
using OpenSim.Framework;
using OpenSim.Region.Environment.Interfaces; using OpenSim.Region.Environment.Interfaces;
using OpenSim.Region.Environment.Scenes; using OpenSim.Region.Environment.Scenes;
@ -33,11 +39,22 @@ namespace OpenSim.Region.Environment.Modules
{ {
public class InventoryModule : IRegionModule public class InventoryModule : IRegionModule
{ {
private static readonly log4net.ILog m_log
= log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
private Scene m_scene; private Scene m_scene;
/// <summary>
/// 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
/// </summary>
private IDictionary<LLUUID, LLUUID> m_pendingOffers = new Dictionary<LLUUID, LLUUID>();
public void Initialise(Scene scene, IConfigSource config) public void Initialise(Scene scene, IConfigSource config)
{ {
m_scene = scene; m_scene = scene;
scene.EventManager.OnNewClient += OnNewClient;
} }
public void PostInitialise() public void PostInitialise()
@ -57,5 +74,144 @@ namespace OpenSim.Region.Environment.Modules
{ {
get { return false; } 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);
}
}
}
}
}
} }
} }

View File

@ -287,9 +287,88 @@ namespace OpenSim.Region.Environment.Scenes
} }
} }
/// <summary>
/// Give an inventory item from one avatar to another
/// </summary>
/// <param name="recipientClient"></param>
/// <param name="sender"></param>
/// <param name="itemId"></param>
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, public void CopyInventoryItem(IClientAPI remoteClient, uint callbackID, LLUUID oldAgentID, LLUUID oldItemID,
LLUUID newFolderID, string newName) 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); InventoryItemBase item = CommsManager.UserProfileCacheService.libraryRoot.HasItem(oldItemID);
if (item == null) if (item == null)
{ {
@ -349,9 +428,8 @@ namespace OpenSim.Region.Environment.Scenes
public void MoveInventoryItem(IClientAPI remoteClient, LLUUID folderID, LLUUID itemID, int length, public void MoveInventoryItem(IClientAPI remoteClient, LLUUID folderID, LLUUID itemID, int length,
string newName) string newName)
{ {
m_log.Info( m_log.DebugFormat(
"[AGENT INVENTORY]: " + "[AGENT INVENTORY]: Moving item {0} to {1} for {2}", itemID, folderID, remoteClient.AgentId);
"Moving item for " + remoteClient.AgentId.ToString());
CachedUserInfo userInfo = CommsManager.UserProfileCacheService.GetUserDetails(remoteClient.AgentId); CachedUserInfo userInfo = CommsManager.UserProfileCacheService.GetUserDetails(remoteClient.AgentId);
if (userInfo == null) if (userInfo == null)
@ -429,7 +507,8 @@ namespace OpenSim.Region.Environment.Scenes
} }
/// <summary> /// <summary>
/// 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).
/// </summary> /// </summary>
/// <param name="remoteClient"></param> /// <param name="remoteClient"></param>
/// <param name="transactionID"></param> /// <param name="transactionID"></param>

View File

@ -271,6 +271,12 @@ namespace OpenSim.Region.Examples.SimpleModule
{ {
} }
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) public virtual void SendLayerData(float[] map)
{ {
} }
@ -389,6 +395,11 @@ namespace OpenSim.Region.Examples.SimpleModule
{ {
} }
/// <see>IClientAPI.SendBulkUpdateInventory(InventoryItemBase)</see>
public virtual void SendBulkUpdateInventory(InventoryItemBase item)
{
}
public virtual void SendTaskInventory(LLUUID taskID, short serial, byte[] fileName) public virtual void SendTaskInventory(LLUUID taskID, short serial, byte[] fileName)
{ {
} }