diff --git a/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs b/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs index 0ec957520b..831922eda7 100644 --- a/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs +++ b/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs @@ -757,64 +757,29 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess SceneObjectGroup group = null; - string xmlData = Utils.BytesToString(rezAsset.Data); - List objlist = new List(); - List veclist = new List(); + List objlist; + List veclist; + Vector3 bbox; + float offsetHeight; byte bRayEndIsIntersection = (byte)(RayEndIsIntersection ? 1 : 0); Vector3 pos; - XmlDocument doc = new XmlDocument(); - doc.LoadXml(xmlData); - XmlElement e = (XmlElement)doc.SelectSingleNode("/CoalescedObject"); - if (e == null || attachment) // Single + bool single = m_Scene.GetObjectsToRez(rezAsset.Data, attachment, out objlist, out veclist, out bbox, out offsetHeight); + + if (single) { - SceneObjectGroup g = SceneObjectSerializer.FromOriginalXmlFormat(xmlData); - - objlist.Add(g); - veclist.Add(Vector3.Zero); - - float offsetHeight = 0; pos = m_Scene.GetNewRezLocation( RayStart, RayEnd, RayTargetID, Quaternion.Identity, - BypassRayCast, bRayEndIsIntersection, true, g.GetAxisAlignedBoundingBox(out offsetHeight), false); + BypassRayCast, bRayEndIsIntersection, true, bbox, false); pos.Z += offsetHeight; } else { - XmlElement coll = (XmlElement)e; - float bx = Convert.ToSingle(coll.GetAttribute("x")); - float by = Convert.ToSingle(coll.GetAttribute("y")); - float bz = Convert.ToSingle(coll.GetAttribute("z")); - Vector3 bbox = new Vector3(bx, by, bz); - pos = m_Scene.GetNewRezLocation(RayStart, RayEnd, RayTargetID, Quaternion.Identity, BypassRayCast, bRayEndIsIntersection, true, bbox, false); - pos -= bbox / 2; - - XmlNodeList groups = e.SelectNodes("SceneObjectGroup"); - foreach (XmlNode n in groups) - { - SceneObjectGroup g = SceneObjectSerializer.FromOriginalXmlFormat(n.OuterXml); - - objlist.Add(g); - XmlElement el = (XmlElement)n; - - string rawX = el.GetAttribute("offsetx"); - string rawY = el.GetAttribute("offsety"); - string rawZ = el.GetAttribute("offsetz"); -// -// m_log.DebugFormat( -// "[INVENTORY ACCESS MODULE]: Converting coalesced object {0} offset <{1}, {2}, {3}>", -// g.Name, rawX, rawY, rawZ); - - float x = Convert.ToSingle(rawX); - float y = Convert.ToSingle(rawY); - float z = Convert.ToSingle(rawZ); - veclist.Add(new Vector3(x, y, z)); - } } if (item != null && !DoPreRezWhenFromItem(remoteClient, item, objlist, pos, veclist, attachment)) diff --git a/OpenSim/Region/Framework/Interfaces/IEntityInventory.cs b/OpenSim/Region/Framework/Interfaces/IEntityInventory.cs index 150193da5b..9ffda51677 100644 --- a/OpenSim/Region/Framework/Interfaces/IEntityInventory.cs +++ b/OpenSim/Region/Framework/Interfaces/IEntityInventory.cs @@ -234,15 +234,17 @@ namespace OpenSim.Region.Framework.Interfaces List GetInventoryItems(InventoryType type); /// - /// Get the scene object referenced by an inventory item. + /// Get the scene object(s) referenced by an inventory item. /// /// /// This is returned in a 'rez ready' state. That is, name, description, permissions and other details have /// been adjusted to reflect the part and item from which it originates. /// - /// - /// The scene object. Null if the scene object asset couldn't be found - SceneObjectGroup GetRezReadySceneObject(TaskInventoryItem item); + /// Inventory item + /// The scene objects + /// Relative offsets for each object + /// true = success, false = the scene object asset couldn't be found + bool GetRezReadySceneObjects(TaskInventoryItem item, out List objlist, out List veclist); /// /// Update an existing inventory item. diff --git a/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs b/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs index 4bebbe8c05..65536dbdbc 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs @@ -31,6 +31,7 @@ using System.Collections; using System.Reflection; using System.Text; using System.Timers; +using System.Xml; using OpenMetaverse; using OpenMetaverse.Packets; using log4net; @@ -2134,6 +2135,69 @@ namespace OpenSim.Region.Framework.Scenes } } + /// + /// Returns the list of Scene Objects in an asset. + /// + /// + /// Returns one object if the asset is a regular object, and multiple objects for a coalesced object. + /// + /// Asset data + /// Whether the item is an attachment + /// The objects included in the asset + /// Relative positions of the objects + /// Bounding box of all the objects + /// Offset in the Z axis from the centre of the bounding box + /// to the centre of the root prim (relevant only when returning a single object) + /// true = returning a single object; false = multiple objects + public bool GetObjectsToRez(byte[] assetData, bool attachment, out List objlist, out List veclist, + out Vector3 bbox, out float offsetHeight) + { + objlist = new List(); + veclist = new List(); + + XmlDocument doc = new XmlDocument(); + string xmlData = Utils.BytesToString(assetData); + doc.LoadXml(xmlData); + XmlElement e = (XmlElement)doc.SelectSingleNode("/CoalescedObject"); + + if (e == null || attachment) // Single + { + SceneObjectGroup g = SceneObjectSerializer.FromOriginalXmlFormat(xmlData); + objlist.Add(g); + veclist.Add(new Vector3(0, 0, 0)); + bbox = g.GetAxisAlignedBoundingBox(out offsetHeight); + return true; + } + else + { + XmlElement coll = (XmlElement)e; + float bx = Convert.ToSingle(coll.GetAttribute("x")); + float by = Convert.ToSingle(coll.GetAttribute("y")); + float bz = Convert.ToSingle(coll.GetAttribute("z")); + bbox = new Vector3(bx, by, bz); + offsetHeight = 0; + + XmlNodeList groups = e.SelectNodes("SceneObjectGroup"); + foreach (XmlNode n in groups) + { + SceneObjectGroup g = SceneObjectSerializer.FromOriginalXmlFormat(n.OuterXml); + objlist.Add(g); + + XmlElement el = (XmlElement)n; + string rawX = el.GetAttribute("offsetx"); + string rawY = el.GetAttribute("offsety"); + string rawZ = el.GetAttribute("offsetz"); + + float x = Convert.ToSingle(rawX); + float y = Convert.ToSingle(rawY); + float z = Convert.ToSingle(rawZ); + veclist.Add(new Vector3(x, y, z)); + } + } + + return false; + } + /// /// Event Handler Rez an object into a scene /// Calls the non-void event handler @@ -2209,19 +2273,25 @@ namespace OpenSim.Region.Framework.Scenes /// will be used if it exists. /// The velocity of the rezzed object. /// - /// The SceneObjectGroup rezzed or null if rez was unsuccessful - public virtual SceneObjectGroup RezObject( + /// The SceneObjectGroup(s) rezzed, or null if rez was unsuccessful + public virtual List RezObject( SceneObjectPart sourcePart, TaskInventoryItem item, Vector3 pos, Quaternion? rot, Vector3 vel, int param) { if (null == item) return null; + + List objlist; + List veclist; - SceneObjectGroup group = sourcePart.Inventory.GetRezReadySceneObject(item); - - if (null == group) + bool success = sourcePart.Inventory.GetRezReadySceneObjects(item, out objlist, out veclist); + if (!success) return null; - - if (!Permissions.CanRezObject(group.PrimCount, item.OwnerID, pos)) + + int totalPrims = 0; + foreach (SceneObjectGroup group in objlist) + totalPrims += group.PrimCount; + + if (!Permissions.CanRezObject(totalPrims, item.OwnerID, pos)) return null; if (!Permissions.BypassPermissions()) @@ -2230,23 +2300,28 @@ namespace OpenSim.Region.Framework.Scenes sourcePart.Inventory.RemoveInventoryItem(item.ItemID); } - - if (group.IsAttachment == false && group.RootPart.Shape.State != 0) + for (int i = 0; i < objlist.Count; i++) { - group.RootPart.AttachedPos = group.AbsolutePosition; - group.RootPart.Shape.LastAttachPoint = (byte)group.AttachmentPoint; + SceneObjectGroup group = objlist[i]; + Vector3 curpos = pos + veclist[i]; + + if (group.IsAttachment == false && group.RootPart.Shape.State != 0) + { + group.RootPart.AttachedPos = group.AbsolutePosition; + group.RootPart.Shape.LastAttachPoint = (byte)group.AttachmentPoint; + } + + group.FromPartID = sourcePart.UUID; + AddNewSceneObject(group, true, curpos, rot, vel); + + // We can only call this after adding the scene object, since the scene object references the scene + // to find out if scripts should be activated at all. + group.CreateScriptInstances(param, true, DefaultScriptEngine, 3); + + group.ScheduleGroupForFullUpdate(); } - - group.FromPartID = sourcePart.UUID; - AddNewSceneObject(group, true, pos, rot, vel); - - // We can only call this after adding the scene object, since the scene object references the scene - // to find out if scripts should be activated at all. - group.CreateScriptInstances(param, true, DefaultScriptEngine, 3); - - group.ScheduleGroupForFullUpdate(); - - return group; + + return objlist; } public virtual bool returnObjects(SceneObjectGroup[] returnobjects, diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectPartInventory.cs b/OpenSim/Region/Framework/Scenes/SceneObjectPartInventory.cs index 3f223a3c73..380e402d16 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectPartInventory.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectPartInventory.cs @@ -733,8 +733,8 @@ namespace OpenSim.Region.Framework.Scenes return items; } - - public SceneObjectGroup GetRezReadySceneObject(TaskInventoryItem item) + + public bool GetRezReadySceneObjects(TaskInventoryItem item, out List objlist, out List veclist) { AssetBase rezAsset = m_part.ParentGroup.Scene.AssetService.Get(item.AssetID.ToString()); @@ -743,66 +743,75 @@ namespace OpenSim.Region.Framework.Scenes m_log.WarnFormat( "[PRIM INVENTORY]: Could not find asset {0} for inventory item {1} in {2}", item.AssetID, item.Name, m_part.Name); - return null; + objlist = null; + veclist = null; + return false; } - string xmlData = Utils.BytesToString(rezAsset.Data); - SceneObjectGroup group = SceneObjectSerializer.FromOriginalXmlFormat(xmlData); + Vector3 bbox; + float offsetHeight; - group.ResetIDs(); + bool single = m_part.ParentGroup.Scene.GetObjectsToRez(rezAsset.Data, false, out objlist, out veclist, out bbox, out offsetHeight); - SceneObjectPart rootPart = group.GetPart(group.UUID); - - // 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 = item.Name; - rootPart.Description = item.Description; - - SceneObjectPart[] partList = group.Parts; - - group.SetGroup(m_part.GroupID, null); - - // TODO: Remove magic number badness - if ((rootPart.OwnerID != item.OwnerID) || (item.CurrentPermissions & 16) != 0 || (item.Flags & (uint)InventoryItemFlags.ObjectSlamPerm) != 0) // Magic number + for (int i = 0; i < objlist.Count; i++) { - if (m_part.ParentGroup.Scene.Permissions.PropagatePermissions()) - { - foreach (SceneObjectPart part in partList) - { - if ((item.Flags & (uint)InventoryItemFlags.ObjectOverwriteEveryone) != 0) - part.EveryoneMask = item.EveryonePermissions; - if ((item.Flags & (uint)InventoryItemFlags.ObjectOverwriteNextOwner) != 0) - part.NextOwnerMask = item.NextPermissions; - if ((item.Flags & (uint)InventoryItemFlags.ObjectOverwriteGroup) != 0) - part.GroupMask = item.GroupPermissions; - } - - group.ApplyNextOwnerPermissions(); - } - } + SceneObjectGroup group = objlist[i]; + + group.ResetIDs(); + + SceneObjectPart rootPart = group.GetPart(group.UUID); + + // 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 = item.Name; + rootPart.Description = item.Description; + + SceneObjectPart[] partList = group.Parts; + + group.SetGroup(m_part.GroupID, null); - foreach (SceneObjectPart part in partList) - { // TODO: Remove magic number badness - if ((part.OwnerID != item.OwnerID) || (item.CurrentPermissions & 16) != 0 || (item.Flags & (uint)InventoryItemFlags.ObjectSlamPerm) != 0) // Magic number + if ((rootPart.OwnerID != item.OwnerID) || (item.CurrentPermissions & 16) != 0 || (item.Flags & (uint)InventoryItemFlags.ObjectSlamPerm) != 0) // Magic number { - part.LastOwnerID = part.OwnerID; - part.OwnerID = item.OwnerID; - part.Inventory.ChangeInventoryOwner(item.OwnerID); + if (m_part.ParentGroup.Scene.Permissions.PropagatePermissions()) + { + foreach (SceneObjectPart part in partList) + { + if ((item.Flags & (uint)InventoryItemFlags.ObjectOverwriteEveryone) != 0) + part.EveryoneMask = item.EveryonePermissions; + if ((item.Flags & (uint)InventoryItemFlags.ObjectOverwriteNextOwner) != 0) + part.NextOwnerMask = item.NextPermissions; + if ((item.Flags & (uint)InventoryItemFlags.ObjectOverwriteGroup) != 0) + part.GroupMask = item.GroupPermissions; + } + + group.ApplyNextOwnerPermissions(); + } } - - if ((item.Flags & (uint)InventoryItemFlags.ObjectOverwriteEveryone) != 0) - part.EveryoneMask = item.EveryonePermissions; - if ((item.Flags & (uint)InventoryItemFlags.ObjectOverwriteNextOwner) != 0) - part.NextOwnerMask = item.NextPermissions; - if ((item.Flags & (uint)InventoryItemFlags.ObjectOverwriteGroup) != 0) - part.GroupMask = item.GroupPermissions; + + foreach (SceneObjectPart part in partList) + { + // TODO: Remove magic number badness + if ((part.OwnerID != item.OwnerID) || (item.CurrentPermissions & 16) != 0 || (item.Flags & (uint)InventoryItemFlags.ObjectSlamPerm) != 0) // Magic number + { + part.LastOwnerID = part.OwnerID; + part.OwnerID = item.OwnerID; + part.Inventory.ChangeInventoryOwner(item.OwnerID); + } + + if ((item.Flags & (uint)InventoryItemFlags.ObjectOverwriteEveryone) != 0) + part.EveryoneMask = item.EveryonePermissions; + if ((item.Flags & (uint)InventoryItemFlags.ObjectOverwriteNextOwner) != 0) + part.NextOwnerMask = item.NextPermissions; + if ((item.Flags & (uint)InventoryItemFlags.ObjectOverwriteGroup) != 0) + part.GroupMask = item.GroupPermissions; + } + + rootPart.TrimPermissions(); } - - rootPart.TrimPermissions(); - - return group; + + return true; } /// diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs index 975bf2dafb..b19ed0a18f 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs @@ -2970,37 +2970,40 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api // need the magnitude later // float velmag = (float)Util.GetMagnitude(llvel); - SceneObjectGroup new_group = World.RezObject(m_host, item, pos, rot, vel, param); + List new_groups = World.RezObject(m_host, item, pos, rot, vel, param); // If either of these are null, then there was an unknown error. - if (new_group == null) + if (new_groups == null) return; - // objects rezzed with this method are die_at_edge by default. - new_group.RootPart.SetDieAtEdge(true); - - new_group.ResumeScripts(); - - m_ScriptEngine.PostObjectEvent(m_host.LocalId, new EventParams( - "object_rez", new Object[] { - new LSL_String( - new_group.RootPart.UUID.ToString()) }, - new DetectParams[0])); - - float groupmass = new_group.GetMass(); - - PhysicsActor pa = new_group.RootPart.PhysActor; - - //Recoil. - if (pa != null && pa.IsPhysical && (Vector3)vel != Vector3.Zero) + foreach (SceneObjectGroup group in new_groups) { - Vector3 recoil = -vel * groupmass * m_recoilScaleFactor; - if (recoil != Vector3.Zero) + // objects rezzed with this method are die_at_edge by default. + group.RootPart.SetDieAtEdge(true); + + group.ResumeScripts(); + + m_ScriptEngine.PostObjectEvent(m_host.LocalId, new EventParams( + "object_rez", new Object[] { + new LSL_String( + group.RootPart.UUID.ToString()) }, + new DetectParams[0])); + + float groupmass = group.GetMass(); + + PhysicsActor pa = group.RootPart.PhysActor; + + //Recoil. + if (pa != null && pa.IsPhysical && (Vector3)vel != Vector3.Zero) { - llApplyImpulse(recoil, 0); + Vector3 recoil = -vel * groupmass * m_recoilScaleFactor; + if (recoil != Vector3.Zero) + { + llApplyImpulse(recoil, 0); + } } + // Variable script delay? (see (http://wiki.secondlife.com/wiki/LSL_Delay) } - // Variable script delay? (see (http://wiki.secondlife.com/wiki/LSL_Delay) }); //ScriptSleep((int)((groupmass * velmag) / 10));