* 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,
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(int px, int py, float[] map);
@ -620,7 +623,7 @@ namespace OpenSim.Framework
void SendPrimTerseUpdate(ulong regionHandle, ushort timeDilation, uint localID, LLVector3 position,
LLQuaternion rotation, LLVector3 velocity, LLVector3 rotationalvelocity);
void SendInventoryFolderDetails(LLUUID ownerID, LLUUID folderID, List<InventoryItemBase> items,
List<InventoryFolderBase> folders, bool fetchFolders,
bool fetchItems);
@ -635,6 +638,14 @@ namespace OpenSim.Framework
void SendRemoveInventoryItem(LLUUID itemID);
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 SendAvatarPickerReply(AvatarPickerReplyPacket Pack);

View File

@ -482,6 +482,11 @@ namespace OpenSim.Region.ClientStack
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)
{
bool result = false;
@ -865,14 +870,30 @@ namespace OpenSim.Region.ClientStack
}
/// <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)
{
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.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);
}
/// <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>
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;

View File

@ -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)
{

View File

@ -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;
/// <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)
{
{
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);
}
}
}
}
}
}
}

View File

@ -286,10 +286,89 @@ namespace OpenSim.Region.Environment.Scenes
"[AGENT INVENTORY]: Agent ID " + remoteClient.AgentId + " not found for an inventory item update.");
}
}
/// <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,
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
}
/// <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>
/// <param name="remoteClient"></param>
/// <param name="transactionID"></param>

View File

@ -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)
{
}
/// <see>IClientAPI.SendBulkUpdateInventory(InventoryItemBase)</see>
public virtual void SendBulkUpdateInventory(InventoryItemBase item)
{
}
public virtual void SendTaskInventory(LLUUID taskID, short serial, byte[] fileName)
{