public UUID attachObjectAssetStore(IClientAPI remoteClient, SceneObjectGroup grp, UUID AgentId, out UUID itemID) { itemID = UUID.Zero; if (grp != null) { Vector3 inventoryStoredPosition = new Vector3 (((grp.AbsolutePosition.X > (int)Constants.RegionSize) ? 250 : grp.AbsolutePosition.X) , (grp.AbsolutePosition.X > (int)Constants.RegionSize) ? 250 : grp.AbsolutePosition.X, grp.AbsolutePosition.Z); Vector3 originalPosition = grp.AbsolutePosition; grp.AbsolutePosition = inventoryStoredPosition; string sceneObjectXml = SceneObjectSerializer.ToOriginalXmlFormat(grp); grp.AbsolutePosition = originalPosition; AssetBase asset = CreateAsset( grp.GetPartName(grp.LocalId), grp.GetPartDescription(grp.LocalId), (sbyte)AssetType.Object, Utils.StringToBytes(sceneObjectXml), remoteClient.AgentId); AssetService.Store(asset); InventoryItemBase item = new InventoryItemBase(); item.CreatorId = grp.RootPart.CreatorID.ToString(); item.Owner = remoteClient.AgentId; 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; InventoryFolderBase folder = InventoryService.GetFolderForType(remoteClient.AgentId, AssetType.Object); if (folder != null) item.Folder = folder.ID; else // oopsies item.Folder = UUID.Zero; if ((remoteClient.AgentId != grp.RootPart.OwnerID) && Permissions.PropagatePermissions()) { item.BasePermissions = grp.RootPart.NextOwnerMask; item.CurrentPermissions = grp.RootPart.NextOwnerMask; item.NextPermissions = grp.RootPart.NextOwnerMask; item.EveryOnePermissions = grp.RootPart.EveryoneMask & grp.RootPart.NextOwnerMask; item.GroupPermissions = grp.RootPart.GroupMask & grp.RootPart.NextOwnerMask; } else { item.BasePermissions = grp.RootPart.BaseMask; item.CurrentPermissions = grp.RootPart.OwnerMask; item.NextPermissions = grp.RootPart.NextOwnerMask; item.EveryOnePermissions = grp.RootPart.EveryoneMask; item.GroupPermissions = grp.RootPart.GroupMask; } item.CreationDate = Util.UnixTimeSinceEpoch(); // sets itemID so client can show item as 'attached' in inventory grp.SetFromItemID(item.ID); if (AddInventoryItem(item)) remoteClient.SendInventoryItemCreateUpdate(item, 0); else { IDialogModule module = RequestModuleInterface<IDialogModule>(); if (module != null) module.SendAlertToUser(remoteClient, "Operation failed"); } itemID = item.ID; return item.AssetID; } return UUID.Zero; }
private SceneObjectGroup RezSingleObjectToWorld(IClientAPI remoteClient, UUID itemID, SceneObjectGroup group, Vector3 RayEnd, Vector3 RayStart, UUID RayTargetID, byte BypassRayCast, byte bRayEndIsIntersection, bool RezSelected, bool attachment, Vector3 pos, string name, string description, IInventoryItem item, ItemPermissionBlock itemPermissions, int? startParam, UUID? newAvatarGroupId, UUID? rezzedByObjectUUID) { bool ownerChanged = false; // record this for the CHANGED_OWNER changed event if (IsBadUserLoad(group)) { if (remoteClient != null) remoteClient.SendAgentAlertMessage("You are currently not allowed to rez objects in this region.", false); return null; // already reported above } if (IsBlacklistedLoad(group)) { if (remoteClient != null) remoteClient.SendAgentAlertMessage("Cannot rez blacklisted object '" + group.Name + "'.", false); return null; // already reported above } //set the group here so that positioning in world will enable/disable the //script correctly based on the group the use is currently in // Initialize the server weight (LI) group.RecalcPrimWeights(); group.RezzedFromFolderId = item.Folder; //group.FromAssetId = item.AssetID; //not needed yet if (newAvatarGroupId.HasValue) { //set the object's land group group.SetGroup(newAvatarGroupId.Value, null); } if (attachment) { group.SetFromItemID(itemID); } else { group.RootPart.SetGroupPositionDirect(pos); if (RezSelected) { //also tell the client there is a new object being rezzed foreach (SceneObjectPart part in group.GetParts()) { part.AddFlag(PrimFlags.CreateSelected); } } } SceneObjectPart rootPart = group.GetChildPart(group.UUID); if (rootPart == null) { string what = "object "; if (attachment) what = " attachment "; m_log.Error("[AGENT INVENTORY]: Error rezzing ItemID: " + itemID + what + " root part not found."); return null; } // Since renaming the item in the inventory does not affect the name stored // in the serialization, transfer the correct name from the inventory to the // object itself before we rez. rootPart.Name = name; rootPart.Description = description; var partList = group.GetParts(); foreach (SceneObjectPart part in partList) { /// This fixes inconsistencies between this part and the root part. /// In the past, there was a bug in Link operations that did not force /// these permissions on child prims when linking. part.SyncChildPermsWithRoot(); } if (rootPart.OwnerID != item.Owner) { if (Permissions.PropagatePermissions()) { if ((itemPermissions.CurrentPermissions & ScenePermBits.SLAM) != 0) { // enforce slam bit, apply item perms to the group parts foreach (SceneObjectPart part in partList) { part.EveryoneMask = item.EveryOnePermissions; part.NextOwnerMask = item.NextPermissions; part.GroupMask = 0; // DO NOT propagate here } } group.ApplyNextOwnerPermissions(); } } ownerChanged |= group.Rationalize(item.Owner, false); foreach (SceneObjectPart part in partList) { if (part.OwnerID != item.Owner) { part.LastOwnerID = part.OwnerID; part.OwnerID = item.Owner; part.Inventory.ChangeInventoryOwner(item.Owner); ownerChanged = true; } else if (((itemPermissions.CurrentPermissions & ScenePermBits.SLAM) != 0) && (!attachment)) // Slam! { part.EveryoneMask = itemPermissions.EveryOnePermissions; part.NextOwnerMask = itemPermissions.NextPermissions; part.GroupMask = 0; // DO NOT propagate here } } rootPart.TrimPermissions(); if (!attachment) { if (group.RootPart.IsPrim) { group.ClearPartAttachmentData(); } } if (this.AddObjectToSceneIfPermitted(group, remoteClient, pos, attachment, rezzedByObjectUUID)) { if (ownerChanged) { foreach (SceneObjectPart part in partList) part.TriggerScriptChangedEvent(Changed.OWNER); } if (!attachment) { // Fire on_rez group.CreateScriptInstances(startParam, ScriptStartFlags.PostOnRez, DefaultScriptEngine, (int)ScriptStateSource.PrimData, null); rootPart.ScheduleFullUpdate(PrimUpdateFlags.ForcedFullUpdate); } } else { // The viewer automatically removes no-copy items from inventory on a rez attempt. // Since this one did not rez, it's still in inventory so let's "put it back". if (remoteClient != null) { InventoryItemBase ib = item as InventoryItemBase; if (item != null) { //this is a folder item, not a task item. update the user remoteClient.SendInventoryItemCreateUpdate(ib, 0); } } return null; } return rootPart.ParentGroup; }
public UUID AttachObjectAssetStore(IClientAPI remoteClient, SceneObjectGroup grp, UUID AgentId, UUID destFolderID, out UUID itemID) { itemID = UUID.Zero; if (grp != null) { byte[] sceneObjectData = this.DoSerializeSingleGroup(grp, SerializationFlags.None); CachedUserInfo userInfo = CommsManager.UserService.GetUserDetails(AgentId); if (userInfo != null) { AssetBase asset = CreateAsset( grp.GetPartName(grp.LocalId), grp.GetPartDescription(grp.LocalId), (sbyte)AssetType.Object, sceneObjectData); try { CommsManager.AssetCache.AddAsset(asset, AssetRequestInfo.InternalRequest()); } catch (AssetServerException e) { m_log.ErrorFormat("[ATTACHMENT] Unable to attach object. Storing asset failed: {0}", e); return UUID.Zero; } if (destFolderID != UUID.Zero) { //make sure we own the folder this item is headed to and that it exists try { //will throw InventorySecurityException, or InventoryObjectMissingException //if something is wrong userInfo.GetFolderAttributesChecked(destFolderID); } catch (Exception) { destFolderID = UUID.Zero; } } if (destFolderID == UUID.Zero) { InventoryFolderBase objFolder = userInfo.FindFolderForType((int)InventoryType.Object); destFolderID = objFolder.ID; } InventoryItemBase item = new InventoryItemBase(); item.CreatorId = grp.RootPart.CreatorID.ToString(); item.Owner = remoteClient.AgentId; 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 = destFolderID; item.CreationDate = Util.UnixTimeSinceEpoch(); ItemPermissionBlock newPerms = grp.GetNewItemPermissions(remoteClient.AgentId); newPerms.ApplyToOther(item); // sets assetID so client can show asset as 'attached' in inventory grp.SetFromItemID(item.ID); userInfo.AddItem(item); remoteClient.SendInventoryItemCreateUpdate(item, 0); itemID = item.ID; return item.AssetID; } return UUID.Zero; } return UUID.Zero; }
/// <summary> /// Add a scene object as a new attachment in the user inventory. /// </summary> /// <param name="remoteClient"></param> /// <param name="grp"></param> /// <returns>The user inventory item created that holds the attachment.</returns> private InventoryItemBase AddSceneObjectAsNewAttachmentInInv(IScenePresence sp, SceneObjectGroup grp) { // m_log.DebugFormat( // "[ATTACHMENTS MODULE]: Called AddSceneObjectAsAttachment for object {0} {1} for {2}", // grp.Name, grp.LocalId, remoteClient.Name); Vector3 inventoryStoredPosition = new Vector3 (((grp.AbsolutePosition.X > (int)Constants.RegionSize) ? Constants.RegionSize - 6 : grp.AbsolutePosition.X) , (grp.AbsolutePosition.Y > (int)Constants.RegionSize) ? Constants.RegionSize - 6 : grp.AbsolutePosition.Y, grp.AbsolutePosition.Z); Vector3 originalPosition = grp.AbsolutePosition; grp.AbsolutePosition = inventoryStoredPosition; // If we're being called from a script, then trying to serialize that same script's state will not complete // in any reasonable time period. Therefore, we'll avoid it. The worst that can happen is that if // the client/server crashes rather than logging out normally, the attachment's scripts will resume // without state on relog. Arguably, this is what we want anyway. string sceneObjectXml = SceneObjectSerializer.ToOriginalXmlFormat(grp, false); grp.AbsolutePosition = originalPosition; AssetBase asset = m_scene.CreateAsset( grp.GetPartName(grp.LocalId), grp.GetPartDescription(grp.LocalId), (sbyte)AssetType.Object, Utils.StringToBytes(sceneObjectXml), sp.UUID); m_scene.AssetService.Store(asset); InventoryItemBase item = new InventoryItemBase(); item.CreatorId = grp.RootPart.CreatorID.ToString(); item.CreatorData = grp.RootPart.CreatorData; item.Owner = sp.UUID; 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; InventoryFolderBase folder = m_scene.InventoryService.GetFolderForType(sp.UUID, AssetType.Object); if (folder != null) item.Folder = folder.ID; else // oopsies item.Folder = UUID.Zero; if ((sp.UUID != grp.RootPart.OwnerID) && m_scene.Permissions.PropagatePermissions()) { item.BasePermissions = grp.RootPart.NextOwnerMask; item.CurrentPermissions = grp.RootPart.NextOwnerMask; item.NextPermissions = grp.RootPart.NextOwnerMask; item.EveryOnePermissions = grp.RootPart.EveryoneMask & grp.RootPart.NextOwnerMask; item.GroupPermissions = grp.RootPart.GroupMask & grp.RootPart.NextOwnerMask; } else { item.BasePermissions = grp.RootPart.BaseMask; item.CurrentPermissions = grp.RootPart.OwnerMask; item.NextPermissions = grp.RootPart.NextOwnerMask; item.EveryOnePermissions = grp.RootPart.EveryoneMask; item.GroupPermissions = grp.RootPart.GroupMask; } item.CreationDate = Util.UnixTimeSinceEpoch(); // sets itemID so client can show item as 'attached' in inventory grp.SetFromItemID(item.ID); if (m_scene.AddInventoryItem(item)) { sp.ControllingClient.SendInventoryItemCreateUpdate(item, 0); } else { if (m_dialogModule != null) m_dialogModule.SendAlertToUser(sp.ControllingClient, "Operation failed"); } return item; }
/// <summary> /// Attach the object to the avatar /// </summary> /// <param name="remoteClient">The client that is having the attachment done</param> /// <param name="localID">The localID (SceneObjectPart) that is being attached (for the attach script event)</param> /// <param name="group">The group (SceneObjectGroup) that is being attached</param> /// <param name="AttachmentPt">The point to where the attachment will go</param> /// <param name="item">If this is not null, it saves a query in this method to the InventoryService /// This is the Item that the object is in (if it is in one yet)</param> protected void FindAttachmentPoint(IClientAPI remoteClient, uint localID, SceneObjectGroup group, int AttachmentPt, InventoryItemBase item) { //Make sure that we arn't over the limit of attachments SceneObjectGroup[] attachments = GetAttachmentsForAvatar(remoteClient.AgentId); if (attachments.Length + 1 > m_maxNumberOfAttachments) { //Too many remoteClient.SendAgentAlertMessage( "You are wearing too many attachments. Take one off to attach this object", false); return; } Vector3 attachPos = group.GetAttachmentPos(); if(!m_allowMultipleAttachments) AttachmentPt &= 0x7f; //Disable it! //Did the attachment change position or attachment point? bool changedPositionPoint = false; // If the attachment point isn't the same as the one previously used // set it's offset position = 0 so that it appears on the attachment point // and not in a weird location somewhere unknown. //Simplier terms: the attachment point changed, set it to the default 0,0,0 location if ((AttachmentPt & 0x7f) != 0 && (AttachmentPt & 0x7f) != (int)group.GetAttachmentPoint()) { attachPos = Vector3.Zero; changedPositionPoint = true; } else { // AttachmentPt 0 means the client chose to 'wear' the attachment. if ((AttachmentPt & 0x7f) == 0) { // Check object for stored attachment point AttachmentPt = (int)group.GetSavedAttachmentPoint(); attachPos = group.GetAttachmentPos(); } //Check state afterwards... use the newer GetSavedAttachmentPoint and Pos above first if ((AttachmentPt & 0x7f) == 0) { // Check object for older stored attachment point AttachmentPt = group.RootPart.Shape.State; //attachPos = group.AbsolutePosition; } // if we still didn't find a suitable attachment point, force it to the default //This happens on the first time an avatar 'wears' an object if ((AttachmentPt & 0x7f) == 0) { // Stick it on right hand with Zero Offset from the attachment point. AttachmentPt = (int)AttachmentPoint.RightHand; //Default location attachPos = Vector3.Zero; changedPositionPoint = true; } } group.HasGroupChanged = changedPositionPoint; //Update where we are put group.SetAttachmentPoint((byte)AttachmentPt); //Fix the position with the one we found group.AbsolutePosition = attachPos; // Remove any previous attachments ScenePresence presence = m_scene.GetScenePresence(remoteClient.AgentId); if (presence == null) return; UUID itemID = UUID.Zero; //Check for multiple attachment bits //If the numbers are the same, it wants to have the old attachment taken off if ((AttachmentPt & 0x7f) == AttachmentPt) { foreach (SceneObjectGroup grp in attachments) { if (grp.GetAttachmentPoint() == (byte)AttachmentPt) { itemID = grp.GetFromItemID(); break; } } if (itemID != UUID.Zero) DetachSingleAttachmentToInventory(itemID, remoteClient); } itemID = group.GetFromItemID(); group.RootPart.AttachedAvatar = presence.UUID; //Anakin Lohner bug #3839 SceneObjectPart[] parts = group.Parts; for (int i = 0; i < parts.Length; i++) parts[i].AttachedAvatar = presence.UUID; if (group.RootPart.PhysActor != null) { m_scene.SceneGraph.PhysicsScene.RemovePrim(group.RootPart.PhysActor); group.RootPart.PhysActor = null; } group.AbsolutePosition = attachPos; group.RootPart.AttachedPos = attachPos; group.RootPart.IsAttachment = true; group.RootPart.SetParentLocalId(presence.LocalId); group.SetAttachmentPoint(Convert.ToByte(AttachmentPt)); AvatarAttachments attPlugin = presence.RequestModuleInterface<AvatarAttachments>(); if (attPlugin != null) attPlugin.AddAttachment(group); // Killing it here will cause the client to deselect it // It then reappears on the avatar, deselected // through the full update below // if (group.IsSelected) { foreach (SceneObjectPart part in group.ChildrenList) { part.CreateSelected = true; } } //Kill the previous entity so that it will be selected SendKillEntity(group.RootPart); //NOTE: This MUST be here, otherwise we limit full updates during attachments when they are selected and it will block the first update. // So until that is changed, this MUST stay. The client will instantly reselect it, so this value doesn't stay borked for long. group.IsSelected = false; if (itemID == UUID.Zero) { //Delete the object inworld to inventory List<SceneObjectGroup> groups = new List<SceneObjectGroup>(1) { group }; IInventoryAccessModule inventoryAccess = m_scene.RequestModuleInterface<IInventoryAccessModule>(); if (inventoryAccess != null) inventoryAccess.DeleteToInventory(DeRezAction.AcquireToUserInventory, UUID.Zero, groups, remoteClient.AgentId, out itemID); } else { //it came from an item, we need to start the scripts // Fire after attach, so we don't get messy perms dialogs // 4 == AttachedRez group.CreateScriptInstances(0, true, 4, UUID.Zero); group.ResumeScripts(); } if (UUID.Zero == itemID) { m_log.Error("[ATTACHMENTS MODULE]: Unable to save attachment. Error inventory item ID."); remoteClient.SendAgentAlertMessage( "Unable to save attachment. Error inventory item ID.", false); return; } // XXYY!! if (item == null) { item = new InventoryItemBase(itemID, remoteClient.AgentId); item = m_scene.InventoryService.GetItem(item); } //Update the ItemID with the new item group.SetFromItemID(item.ID); //If we updated the attachment, we need to save the change if (presence.Appearance.SetAttachment((int)AttachmentPt, itemID, item.AssetID)) AvatarFactory.QueueAppearanceSave(remoteClient.AgentId); //Now recreate it so that it is selected group.ScheduleGroupUpdate(PrimUpdateFlags.FullUpdate); // In case it is later dropped again, don't let // it get cleaned up group.RootPart.RemFlag(PrimFlags.TemporaryOnRez); group.HasGroupChanged = false; m_scene.EventManager.TriggerOnAttach(localID, group.GetFromItemID(), remoteClient.AgentId); }
/// <summary> /// Update the user inventory to reflect an attachment /// </summary> /// <param name="remoteClient"></param> /// <param name="AttachmentPt"></param> /// <param name="itemID"></param> /// <param name="att"></param> protected void ShowAttachInUserInventory( IClientAPI remoteClient, int AttachmentPt, UUID itemID, SceneObjectGroup att) { // m_log.DebugFormat( // "[USER INVENTORY]: Updating attachment {0} for {1} at {2} using item ID {3}", // att.Name, remoteClient.Name, AttachmentPt, itemID); if (UUID.Zero == itemID) { m_log.Error("[ATTACHMENTS MODULE]: Unable to save attachment. Error inventory item ID."); return; } if (0 == AttachmentPt) { m_log.Error("[ATTACHMENTS MODULE]: Unable to save attachment. Error attachment point."); return; } if (null == att.RootPart) { m_log.Error("[ATTACHMENTS MODULE]: Unable to save attachment for a prim without the rootpart!"); return; } ScenePresence presence; if (m_scene.TryGetScenePresence(remoteClient.AgentId, out presence)) { // XXYY!! InventoryItemBase item = new InventoryItemBase(itemID, remoteClient.AgentId); item = m_scene.InventoryService.GetItem(item); att.SetFromItemID(itemID); presence.Appearance.SetAttachment((int)AttachmentPt, itemID, item.AssetID); AvatarFactory.QueueAppearanceSave(remoteClient.AgentId); } }