From b4680f653dbc1c6f712898af79c4ea22bca3f678 Mon Sep 17 00:00:00 2001 From: Justin Clarke Casey Date: Wed, 17 Dec 2008 16:11:03 +0000 Subject: * Implement 'Save Object Back to My Inventory'. On the Linden client this is in the Tools menu available when editing an object * This facility allows you to save changes to an object that you've rezzed into a region back into their original inventory item without having to take a copy of the rezzed object. --- .../Region/ClientStack/LindenUDP/LLClientView.cs | 2 +- .../Modules/Avatar/Friends/FriendsModule.cs | 17 ++- .../Modules/World/Permissions/PermissionsModule.cs | 2 +- .../Scenes/AsyncSceneObjectGroupDeleter.cs | 10 +- .../Region/Environment/Scenes/Scene.Inventory.cs | 170 +++++++++++++-------- OpenSim/Region/Environment/Scenes/Scene.cs | 9 -- .../Region/Environment/Scenes/SceneObjectGroup.cs | 13 +- .../Region/Environment/Scenes/SceneObjectPart.cs | 49 +++++- 8 files changed, 186 insertions(+), 86 deletions(-) (limited to 'OpenSim/Region') diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs index 9fb3c55..e34c8ec 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs @@ -7286,7 +7286,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP } public void SendAgentOnline(UUID[] agentIDs) - { + { OnlineNotificationPacket onp = new OnlineNotificationPacket(); OnlineNotificationPacket.AgentBlockBlock[] onpb = new OnlineNotificationPacket.AgentBlockBlock[agentIDs.Length]; for (int i = 0; i < agentIDs.Length; i++) diff --git a/OpenSim/Region/Environment/Modules/Avatar/Friends/FriendsModule.cs b/OpenSim/Region/Environment/Modules/Avatar/Friends/FriendsModule.cs index 5bdf32c..e4ed9fa 100644 --- a/OpenSim/Region/Environment/Modules/Avatar/Friends/FriendsModule.cs +++ b/OpenSim/Region/Environment/Modules/Avatar/Friends/FriendsModule.cs @@ -124,6 +124,7 @@ namespace OpenSim.Region.Environment.Modules.Avatar.Friends if (!m_scenes.ContainsKey(scene.RegionInfo.RegionHandle)) m_scenes[scene.RegionInfo.RegionHandle] = scene; } + scene.EventManager.OnNewClient += OnNewClient; scene.EventManager.OnIncomingInstantMessage += OnGridInstantMessage; scene.EventManager.OnAvatarEnteringNewParcel += AvatarEnteringParcel; @@ -157,6 +158,11 @@ namespace OpenSim.Region.Environment.Modules.Avatar.Friends #endregion + /// + /// Receive presence information changes about clients in other regions. + /// + /// + /// public XmlRpcResponse processPresenceUpdateBulk(XmlRpcRequest req) { Hashtable requestData = (Hashtable)req.Params[0]; @@ -171,6 +177,7 @@ namespace OpenSim.Region.Environment.Modules.Avatar.Friends lock (m_rootAgents) { List friendsHere = new List(); + try { UUID agentID = new UUID((string)requestData["agentID"]); @@ -728,6 +735,12 @@ namespace OpenSim.Region.Environment.Modules.Avatar.Friends if (destAgent != null) destAgent.ControllingClient.SendDeclineCallingCard(transactionID); } + /// + /// Send presence information about a client to other clients in both this region and others. + /// + /// + /// + /// private void SendPresenceState(IClientAPI client, List friendList, bool iAmOnline) { m_log.DebugFormat("[FRIEND]: {0} logged {1}; sending presence updates", client.Name, iAmOnline ? "in" : "out"); @@ -756,8 +769,6 @@ namespace OpenSim.Region.Environment.Modules.Avatar.Friends } } - - // we now have a list of "interesting" friends (which we have to find out on-/offline state for), // friends we want to send our online state to (if *they* are online, too), and // friends we want to receive online state for (currently unknown whether online or not) @@ -799,8 +810,10 @@ namespace OpenSim.Region.Environment.Modules.Avatar.Friends friendIDsToReceiveFromOnline.Add(uuid); } } + m_log.DebugFormat("[FRIEND]: Sending {0} offline and {1} online friends to {2}", friendIDsToReceiveFromOffline.Count, friendIDsToReceiveFromOnline.Count, client.Name); + if (friendIDsToReceiveFromOffline.Count > 0) client.SendAgentOffline(friendIDsToReceiveFromOffline.ToArray()); if (friendIDsToReceiveFromOnline.Count > 0) client.SendAgentOnline(friendIDsToReceiveFromOnline.ToArray()); diff --git a/OpenSim/Region/Environment/Modules/World/Permissions/PermissionsModule.cs b/OpenSim/Region/Environment/Modules/World/Permissions/PermissionsModule.cs index e2ca975..36f5965 100644 --- a/OpenSim/Region/Environment/Modules/World/Permissions/PermissionsModule.cs +++ b/OpenSim/Region/Environment/Modules/World/Permissions/PermissionsModule.cs @@ -1106,7 +1106,6 @@ namespace OpenSim.Region.Environment.Modules.World.Permissions // the administrator object permissions to take effect. // UUID objectOwner = task.OwnerID; - if ((task.RootPart.EveryoneMask & PERM_COPY) != 0) permission = true; @@ -1120,6 +1119,7 @@ namespace OpenSim.Region.Environment.Modules.World.Permissions if ((task.GetEffectivePermissions() & PERM_COPY) == 0) permission = false; } + return permission; } diff --git a/OpenSim/Region/Environment/Scenes/AsyncSceneObjectGroupDeleter.cs b/OpenSim/Region/Environment/Scenes/AsyncSceneObjectGroupDeleter.cs index 03b3977..1429452 100644 --- a/OpenSim/Region/Environment/Scenes/AsyncSceneObjectGroupDeleter.cs +++ b/OpenSim/Region/Environment/Scenes/AsyncSceneObjectGroupDeleter.cs @@ -110,7 +110,7 @@ namespace OpenSim.Region.Environment.Scenes while (InventoryDeQueueAndDelete()) { - m_log.Debug("[SCENE]: Returned item successfully to inventory, continuing..."); + m_log.Debug("[SCENE]: Sent item successfully to inventory, continuing..."); } } @@ -130,7 +130,7 @@ namespace OpenSim.Region.Environment.Scenes if (left > 0) { m_log.DebugFormat( - "[SCENE]: Sending deleted object to user's inventory, {0} item(s) remaining.", left); + "[SCENE]: Sending object to user's inventory, {0} item(s) remaining.", left); x = m_inventoryDeletes.Dequeue(); @@ -142,7 +142,7 @@ namespace OpenSim.Region.Environment.Scenes } catch (Exception e) { - m_log.DebugFormat("Exception background deleting object: " + e); + m_log.DebugFormat("Exception background sending object: " + e); } return true; @@ -154,11 +154,11 @@ namespace OpenSim.Region.Environment.Scenes // We can't put the object group details in here since the root part may have disappeared (which is where these sit). // FIXME: This needs to be fixed. m_log.ErrorFormat( - "[SCENE]: Queued deletion of scene object to agent {0} {1} failed: {2}", + "[SCENE]: Queued sending of scene object to agent {0} {1} failed: {2}", (x != null ? x.remoteClient.Name : "unavailable"), (x != null ? x.remoteClient.AgentId.ToString() : "unavailable"), e.ToString()); } - m_log.Debug("[SCENE]: No objects left in inventory delete queue."); + m_log.Debug("[SCENE]: No objects left in inventory send queue."); return false; } } diff --git a/OpenSim/Region/Environment/Scenes/Scene.Inventory.cs b/OpenSim/Region/Environment/Scenes/Scene.Inventory.cs index 7c518c4..c1decaa 100644 --- a/OpenSim/Region/Environment/Scenes/Scene.Inventory.cs +++ b/OpenSim/Region/Environment/Scenes/Scene.Inventory.cs @@ -1686,7 +1686,15 @@ namespace OpenSim.Region.Environment.Scenes bool permissionToTake = false; bool permissionToDelete = false; - if (action == DeRezAction.TakeCopy) + if (action == DeRezAction.SaveToExistingUserInventoryItem) + { + if (grp.OwnerID == remoteClient.AgentId && grp.RootPart.FromUserInventoryItemID != UUID.Zero) + { + permissionToTake = true; + permissionToDelete = false; + } + } + else if (action == DeRezAction.TakeCopy) { permissionToTake = Permissions.CanTakeCopyObject( @@ -1726,6 +1734,7 @@ namespace OpenSim.Region.Environment.Scenes grp.UUID, remoteClient.AgentId); permissionToDelete = permissionToTake; + if (permissionToDelete) { AddReturn(grp.OwnerID, grp.Name, grp.AbsolutePosition, "parcel owner return"); @@ -1737,6 +1746,12 @@ namespace OpenSim.Region.Environment.Scenes permissionToDelete = true; } } + else + { + m_log.DebugFormat( + "[AGENT INVENTORY]: Ignoring unexpected derez action {0} for {1}", action, remoteClient.Name); + return; + } if (permissionToTake) { @@ -1769,13 +1784,11 @@ namespace OpenSim.Region.Environment.Scenes if (remoteClient == null) { - userInfo = CommsManager.UserProfileCacheService.GetUserDetails( - objectGroup.RootPart.OwnerID); + userInfo = CommsManager.UserProfileCacheService.GetUserDetails(objectGroup.RootPart.OwnerID); } else { - userInfo = CommsManager.UserProfileCacheService.GetUserDetails( - remoteClient.AgentId); + userInfo = CommsManager.UserProfileCacheService.GetUserDetails(remoteClient.AgentId); } if (userInfo != null) @@ -1785,8 +1798,8 @@ namespace OpenSim.Region.Environment.Scenes // If we're returning someone's item, it goes back to the // owner's Lost And Found folder. - if (folderID == UUID.Zero || (action == DeRezAction.Delete && - objectGroup.OwnerID != remoteClient.AgentId)) + if (folderID == UUID.Zero + || (action == DeRezAction.Delete && objectGroup.OwnerID != remoteClient.AgentId)) { InventoryFolderBase folder = userInfo.FindFolderForType( @@ -1811,6 +1824,21 @@ namespace OpenSim.Region.Environment.Scenes } } + InventoryItemBase item = null; + + if (DeRezAction.SaveToExistingUserInventoryItem == action) + { + item = userInfo.RootFolder.FindItem(objectGroup.RootPart.FromUserInventoryItemID); + + if (null == item) + { + m_log.DebugFormat( + "[AGENT INVENTORY]: Object {0} {1} scheduled for save to inventory has already been deleted.", + objectGroup.Name, objectGroup.UUID); + return UUID.Zero; + } + } + AssetBase asset = CreateAsset( objectGroup.GetPartName(objectGroup.RootPart.LocalId), objectGroup.GetPartDescription(objectGroup.RootPart.LocalId), @@ -1818,65 +1846,74 @@ namespace OpenSim.Region.Environment.Scenes Utils.StringToBytes(sceneObjectXml)); AssetCache.AddAsset(asset); assetID = asset.FullID; - - InventoryItemBase item = new InventoryItemBase(); - item.Creator = objectGroup.RootPart.CreatorID; - - if (action == DeRezAction.TakeCopy || action == DeRezAction.Take) - item.Owner = remoteClient.AgentId; - else // Delete / Return - item.Owner = objectGroup.OwnerID; - - item.ID = UUID.Random(); - item.AssetID = asset.FullID; - item.Description = asset.Description; - item.Name = asset.Name; - item.AssetType = asset.Type; - item.InvType = (int)InventoryType.Object; - item.Folder = folderID; - if (remoteClient != null && (remoteClient.AgentId != objectGroup.RootPart.OwnerID) && Permissions.PropagatePermissions()) - { - uint perms=objectGroup.GetEffectivePermissions(); - uint nextPerms=(perms & 7) << 13; - if ((nextPerms & (uint)PermissionMask.Copy) == 0) - perms &= ~(uint)PermissionMask.Copy; - if ((nextPerms & (uint)PermissionMask.Transfer) == 0) - perms &= ~(uint)PermissionMask.Transfer; - if ((nextPerms & (uint)PermissionMask.Modify) == 0) - perms &= ~(uint)PermissionMask.Modify; - - item.BasePermissions = perms & objectGroup.RootPart.NextOwnerMask; - item.CurrentPermissions = item.BasePermissions; - item.NextPermissions = objectGroup.RootPart.NextOwnerMask; - item.EveryOnePermissions = objectGroup.RootPart.EveryoneMask & objectGroup.RootPart.NextOwnerMask; - item.GroupPermissions = objectGroup.RootPart.GroupMask & objectGroup.RootPart.NextOwnerMask; - item.CurrentPermissions |= 8; // Slam! + if (DeRezAction.SaveToExistingUserInventoryItem == action) + { + item.AssetID = asset.FullID; + userInfo.UpdateItem(item); } else { - item.BasePermissions = objectGroup.GetEffectivePermissions(); - item.CurrentPermissions = objectGroup.GetEffectivePermissions(); - item.NextPermissions = objectGroup.RootPart.NextOwnerMask; - item.EveryOnePermissions = objectGroup.RootPart.EveryoneMask; - item.GroupPermissions = objectGroup.RootPart.GroupMask; - } + item = new InventoryItemBase(); + item.Creator = objectGroup.RootPart.CreatorID; - // TODO: add the new fields (Flags, Sale info, etc) - item.CreationDate = Util.UnixTimeSinceEpoch(); + if (action == DeRezAction.TakeCopy || action == DeRezAction.Take) + item.Owner = remoteClient.AgentId; + else // Delete / Return + item.Owner = objectGroup.OwnerID; - userInfo.AddItem(item); - if (remoteClient != null && item.Owner == remoteClient.AgentId) - { - remoteClient.SendInventoryItemCreateUpdate(item); - } - else - { - ScenePresence notifyUser = GetScenePresence(item.Owner); - if (notifyUser != null) + item.ID = UUID.Random(); + item.AssetID = asset.FullID; + item.Description = asset.Description; + item.Name = asset.Name; + item.AssetType = asset.Type; + item.InvType = (int)InventoryType.Object; + item.Folder = folderID; + + if (remoteClient != null && (remoteClient.AgentId != objectGroup.RootPart.OwnerID) && Permissions.PropagatePermissions()) + { + uint perms=objectGroup.GetEffectivePermissions(); + uint nextPerms=(perms & 7) << 13; + if ((nextPerms & (uint)PermissionMask.Copy) == 0) + perms &= ~(uint)PermissionMask.Copy; + if ((nextPerms & (uint)PermissionMask.Transfer) == 0) + perms &= ~(uint)PermissionMask.Transfer; + if ((nextPerms & (uint)PermissionMask.Modify) == 0) + perms &= ~(uint)PermissionMask.Modify; + + item.BasePermissions = perms & objectGroup.RootPart.NextOwnerMask; + item.CurrentPermissions = item.BasePermissions; + item.NextPermissions = objectGroup.RootPart.NextOwnerMask; + item.EveryOnePermissions = objectGroup.RootPart.EveryoneMask & objectGroup.RootPart.NextOwnerMask; + item.GroupPermissions = objectGroup.RootPart.GroupMask & objectGroup.RootPart.NextOwnerMask; + item.CurrentPermissions |= 8; // Slam! + } + else + { + item.BasePermissions = objectGroup.GetEffectivePermissions(); + item.CurrentPermissions = objectGroup.GetEffectivePermissions(); + item.NextPermissions = objectGroup.RootPart.NextOwnerMask; + item.EveryOnePermissions = objectGroup.RootPart.EveryoneMask; + item.GroupPermissions = objectGroup.RootPart.GroupMask; + } + + // TODO: add the new fields (Flags, Sale info, etc) + item.CreationDate = Util.UnixTimeSinceEpoch(); + + userInfo.AddItem(item); + + if (remoteClient != null && item.Owner == remoteClient.AgentId) { - notifyUser.ControllingClient.SendInventoryItemCreateUpdate(item); + remoteClient.SendInventoryItemCreateUpdate(item); } + else + { + ScenePresence notifyUser = GetScenePresence(item.Owner); + if (notifyUser != null) + { + notifyUser.ControllingClient.SendInventoryItemCreateUpdate(item); + } + } } } @@ -2093,7 +2130,7 @@ namespace OpenSim.Region.Environment.Scenes CachedUserInfo userInfo = CommsManager.UserProfileCacheService.GetUserDetails(remoteClient.AgentId); if (userInfo != null) { - if (userInfo.RootFolder != null) + if (userInfo.HasReceivedInventory) { InventoryItemBase item = userInfo.RootFolder.FindItem(itemID); @@ -2103,8 +2140,21 @@ namespace OpenSim.Region.Environment.Scenes if (rezAsset != null) { + UUID itemId = UUID.Zero; + + // If we have permission to copy then link the rezzed object back to the user inventory + // item that it came from. This allows us to enable 'save object to inventory' + if (!Permissions.BypassPermissions()) + { + if ((item.CurrentPermissions & (uint)PermissionMask.Copy) == (uint)PermissionMask.Copy) + { + itemId = item.ID; + } + } + string xmlData = Utils.BytesToString(rezAsset.Data); - SceneObjectGroup group = new SceneObjectGroup(xmlData, true); + SceneObjectGroup group = new SceneObjectGroup(itemId, xmlData, true); + if (!Permissions.CanRezObject( group.Children.Count, remoteClient.AgentId, pos) && !attachment) diff --git a/OpenSim/Region/Environment/Scenes/Scene.cs b/OpenSim/Region/Environment/Scenes/Scene.cs index 5502f97..6831885 100644 --- a/OpenSim/Region/Environment/Scenes/Scene.cs +++ b/OpenSim/Region/Environment/Scenes/Scene.cs @@ -3480,28 +3480,19 @@ namespace OpenSim.Region.Environment.Scenes public virtual void StoreAddFriendship(UUID ownerID, UUID friendID, uint perms) { - // TODO: m_sceneGridService.DoStuff; m_sceneGridService.AddNewUserFriend(ownerID, friendID, perms); } public virtual void StoreUpdateFriendship(UUID ownerID, UUID friendID, uint perms) { - // TODO: m_sceneGridService.DoStuff; m_sceneGridService.UpdateUserFriendPerms(ownerID, friendID, perms); } public virtual void StoreRemoveFriendship(UUID ownerID, UUID ExfriendID) { - // TODO: m_sceneGridService.DoStuff; m_sceneGridService.RemoveUserFriend(ownerID, ExfriendID); } - public virtual List StoreGetFriendsForUser(UUID ownerID) - { - // TODO: m_sceneGridService.DoStuff; - return m_sceneGridService.GetUserFriendList(ownerID); - } - public void AddPacketStats(int inPackets, int outPackets, int unAckedBytes) { m_statsReporter.AddInPackets(inPackets); diff --git a/OpenSim/Region/Environment/Scenes/SceneObjectGroup.cs b/OpenSim/Region/Environment/Scenes/SceneObjectGroup.cs index cc99929..5456282 100644 --- a/OpenSim/Region/Environment/Scenes/SceneObjectGroup.cs +++ b/OpenSim/Region/Environment/Scenes/SceneObjectGroup.cs @@ -401,16 +401,25 @@ namespace OpenSim.Region.Environment.Scenes { SetRootPart(part); } + + public SceneObjectGroup(string xmlData, bool isOriginalXmlFormat) + : this(UUID.Zero, xmlData, isOriginalXmlFormat) + { + } /// /// Create an object using serialized data in OpenSim's original xml format. /// + /// + /// If applicable, the user inventory item id from which this object was rezzed. If not applicable then this + /// should be UUID.Zero + /// /// /// /// This parameter only exists to separate the two different xml constructors. In the future, versions should /// be specified within the xml itself. /// - public SceneObjectGroup(string xmlData, bool isOriginalXmlFormat) + public SceneObjectGroup(UUID fromUserInventoryItemID, string xmlData, bool isOriginalXmlFormat) { if (!isOriginalXmlFormat) throw new Exception("This constructor must specify the xml is in OpenSim's original format"); @@ -430,7 +439,7 @@ namespace OpenSim.Region.Environment.Scenes reader.Read(); reader.ReadStartElement("SceneObjectGroup"); reader.ReadStartElement("RootPart"); - SetRootPart(SceneObjectPart.FromXml(reader)); + SetRootPart(SceneObjectPart.FromXml(fromUserInventoryItemID, reader)); reader.ReadEndElement(); diff --git a/OpenSim/Region/Environment/Scenes/SceneObjectPart.cs b/OpenSim/Region/Environment/Scenes/SceneObjectPart.cs index 10a37ee..3547cd4 100644 --- a/OpenSim/Region/Environment/Scenes/SceneObjectPart.cs +++ b/OpenSim/Region/Environment/Scenes/SceneObjectPart.cs @@ -116,30 +116,55 @@ namespace OpenSim.Region.Environment.Scenes // for SL compatibility it should be persisted though (set sound / displaytext / particlesystem, kill script) [XmlIgnore] public UUID Sound; + [XmlIgnore] public byte SoundFlags; + [XmlIgnore] public double SoundGain; + [XmlIgnore] public double SoundRadius; + [XmlIgnore] public uint TimeStampFull = 0; + [XmlIgnore] public uint TimeStampLastActivity = 0; // Will be used for AutoReturn + [XmlIgnore] public uint TimeStampTerse = 0; + [XmlIgnore] public UUID FromAssetID = UUID.Zero; + + /// + /// The UUID of the user inventory item from which this object was rezzed if this is a root part. + /// If UUID.Zero then either this is not a root part or there is no connection with a user inventory item. + /// + private UUID m_fromUserInventoryItemID = UUID.Zero; + + [XmlIgnore] + public UUID FromUserInventoryItemID + { + get { return m_fromUserInventoryItemID; } + } + [XmlIgnore] public bool IsAttachment = false; + [XmlIgnore] public scriptEvents AggregateScriptEvents = 0; + [XmlIgnore] public UUID AttachedAvatar = UUID.Zero; + [XmlIgnore] public Vector3 AttachedPos = Vector3.Zero; + [XmlIgnore] public uint AttachmentPoint = (byte)0; + [XmlIgnore] public PhysicsVector RotationAxis = new PhysicsVector(1f,1f,1f); @@ -1428,15 +1453,27 @@ if (m_shape != null) { /// /// Restore this part from the serialized xml representation. /// + /// /// public static SceneObjectPart FromXml(XmlReader xmlReader) { - // It's not necessary to persist this - - XmlSerializer serializer = new XmlSerializer(typeof (SceneObjectPart)); - SceneObjectPart newobject = (SceneObjectPart) serializer.Deserialize(xmlReader); - return newobject; + return FromXml(UUID.Zero, xmlReader); } + + /// + /// Restore this part from the serialized xml representation. + /// + /// The inventory id from which this part came, if applicable + /// + /// + public static SceneObjectPart FromXml(UUID fromUserInventoryItemId, XmlReader xmlReader) + { + XmlSerializer serializer = new XmlSerializer(typeof (SceneObjectPart)); + SceneObjectPart part = (SceneObjectPart)serializer.Deserialize(xmlReader); + part.m_fromUserInventoryItemID = fromUserInventoryItemId; + + return part; + } public UUID GetAvatarOnSitTarget() { @@ -1603,7 +1640,7 @@ if (m_shape != null) { public void GetProperties(IClientAPI client) { client.SendObjectPropertiesReply( - UUID.Zero, (ulong)_creationDate, _creatorID, UUID.Zero, UUID.Zero, + m_fromUserInventoryItemID, (ulong)_creationDate, _creatorID, UUID.Zero, UUID.Zero, _groupID, (short)InventorySerial, _lastOwnerID, UUID, _ownerID, ParentGroup.RootPart.TouchName, new byte[0], ParentGroup.RootPart.SitName, Name, Description, ParentGroup.RootPart._ownerMask, ParentGroup.RootPart._nextOwnerMask, ParentGroup.RootPart._groupMask, ParentGroup.RootPart._everyoneMask, -- cgit v1.1