diff --git a/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs b/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs
index 73b0a35b7c..cfcfc79c11 100644
--- a/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs
+++ b/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs
@@ -274,7 +274,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
float minX, minY, minZ;
float maxX, maxY, maxZ;
- Vector3[] offsets = m_Scene.GetCombinedBoundingBox(objlist,
+ Vector3[] offsets = Scene.GetCombinedBoundingBox(objlist,
out minX, out maxX, out minY, out maxY,
out minZ, out maxZ);
@@ -289,7 +289,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
XmlDocument doc = new XmlDocument();
SceneObjectGroup g = objlist[i];
doc.LoadXml(xmlStrings[g.UUID]);
- XmlElement e = (XmlElement)doc.SelectSingleNode("/SceneObjectGroup");
+ XmlElement e = (XmlElement)doc.SelectSingleNode("/SceneObjectGroup");
e.SetAttribute("offsetx", offsets[i].X.ToString());
e.SetAttribute("offsety", offsets[i].Y.ToString());
e.SetAttribute("offsetz", offsets[i].Z.ToString());
@@ -659,9 +659,18 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess
itemId, n.OuterXml);
objlist.Add(g);
XmlElement el = (XmlElement)n;
- float x = Convert.ToSingle(el.GetAttribute("offsetx"));
- float y = Convert.ToSingle(el.GetAttribute("offsety"));
- float z = Convert.ToSingle(el.GetAttribute("offsetz"));
+
+ 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));
}
}
diff --git a/OpenSim/Region/CoreModules/Framework/InventoryAccess/Tests/InventoryAccessModuleTests.cs b/OpenSim/Region/CoreModules/Framework/InventoryAccess/Tests/InventoryAccessModuleTests.cs
index 5eca753d03..f8fa424738 100644
--- a/OpenSim/Region/CoreModules/Framework/InventoryAccess/Tests/InventoryAccessModuleTests.cs
+++ b/OpenSim/Region/CoreModules/Framework/InventoryAccess/Tests/InventoryAccessModuleTests.cs
@@ -80,6 +80,85 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess.Tests
m_tc = new TestClient(acd, m_scene);
}
+ [Test]
+ public void TestRezCoalescedObject()
+ {
+ TestHelper.InMethod();
+ log4net.Config.XmlConfigurator.Configure();
+
+ // Create asset
+ SceneObjectGroup object1;
+ {
+ string partName = "Object1";
+ UUID ownerId = UUID.Parse("00000000-0000-0000-0000-000000000040");
+ PrimitiveBaseShape shape = PrimitiveBaseShape.CreateSphere();
+ Vector3 groupPosition = new Vector3(10, 20, 30);
+ Quaternion rotationOffset = new Quaternion(20, 30, 40, 50);
+ Vector3 offsetPosition = new Vector3(5, 10, 15);
+
+ SceneObjectPart part1
+ = new SceneObjectPart(
+ ownerId, shape, groupPosition, rotationOffset, offsetPosition);
+ part1.Name = partName;
+
+ object1 = new SceneObjectGroup(part1);
+ }
+
+ SceneObjectGroup object2;
+ {
+ string partName = "Object2";
+ UUID ownerId = UUID.Parse("00000000-0000-0000-0000-000000000040");
+ PrimitiveBaseShape shape = PrimitiveBaseShape.CreateSphere();
+ Vector3 groupPosition = new Vector3(10, 20, 30);
+ Quaternion rotationOffset = new Quaternion(20, 30, 40, 50);
+ Vector3 offsetPosition = new Vector3(5, 10, 15);
+
+ SceneObjectPart part1
+ = new SceneObjectPart(
+ ownerId, shape, groupPosition, rotationOffset, offsetPosition);
+ part1.Name = partName;
+
+ object2 = new SceneObjectGroup(part1);
+ }
+
+ CoalescedSceneObjects coa = new CoalescedSceneObjects(m_userId, object1, object2);
+
+ UUID asset1Id = UUID.Parse("00000000-0000-0000-0000-000000000060");
+ AssetBase asset1 = AssetHelpers.CreateAsset(asset1Id, coa);
+ m_scene.AssetService.Store(asset1);
+
+ // Create item
+ UUID item1Id = UUID.Parse("00000000-0000-0000-0000-000000000080");
+ string item1Name = "My Little Dog";
+ InventoryItemBase item1 = new InventoryItemBase();
+ item1.Name = item1Name;
+ item1.AssetID = asset1.FullID;
+ item1.ID = item1Id;
+ InventoryFolderBase objsFolder
+ = InventoryArchiveUtils.FindFolderByPath(m_scene.InventoryService, m_userId, "Objects")[0];
+ item1.Folder = objsFolder.ID;
+ m_scene.AddInventoryItem(item1);
+
+ SceneObjectGroup so
+ = m_iam.RezObject(
+ m_tc, item1Id, Vector3.Zero, Vector3.Zero, UUID.Zero, 1, false, false, false, UUID.Zero, false);
+
+ Assert.That(so, Is.Not.Null);
+
+ Assert.That(m_scene.SceneGraph.GetTotalObjectsCount(), Is.EqualTo(2));
+
+ SceneObjectPart retrievedObj1Part = m_scene.GetSceneObjectPart(object1.Name);
+ Assert.That(retrievedObj1Part, Is.Null);
+
+ retrievedObj1Part = m_scene.GetSceneObjectPart(item1.Name);
+ Assert.That(retrievedObj1Part, Is.Not.Null);
+ Assert.That(retrievedObj1Part.Name, Is.EqualTo(item1.Name));
+
+ // FIXME: Can't test yet due to a bug where objects in coalescence all get the item name when rerezzed.
+// SceneObjectPart retrievedObj2Part = m_scene.GetSceneObjectPart(object2.Name);
+// Assert.That(retrievedObj2Part, Is.Not.Null);
+ }
+
[Test]
public void TestRezObject()
{
diff --git a/OpenSim/Region/Framework/Scenes/CoalescedSceneObjects.cs b/OpenSim/Region/Framework/Scenes/CoalescedSceneObjects.cs
new file mode 100644
index 0000000000..51eac5f3f6
--- /dev/null
+++ b/OpenSim/Region/Framework/Scenes/CoalescedSceneObjects.cs
@@ -0,0 +1,128 @@
+/*
+ * Copyright (c) Contributors, http://opensimulator.org/
+ * See CONTRIBUTORS.TXT for a full list of copyright holders.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the OpenSimulator Project nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using OpenMetaverse;
+
+namespace OpenSim.Region.Framework.Scenes
+{
+ ///
+ /// Represents a coalescene of scene objects. A coalescence occurs when objects that are not in the same linkset
+ /// are grouped together.
+ ///
+ public class CoalescedSceneObjects
+ {
+ ///
+ /// The creator of this coalesence, though not necessarily the objects within it.
+ ///
+ public UUID CreatorId { get; set; }
+
+ ///
+ /// The number of objects in this coalesence
+ ///
+ public int Count
+ {
+ get
+ {
+ lock (m_memberObjects)
+ return m_memberObjects.Count;
+ }
+ }
+
+ ///
+ /// Does this coalesence have any member objects?
+ ///
+ public bool HasObjects { get { return Count > 0; } }
+
+ ///
+ /// Get the objects currently in this coalescence
+ ///
+ public List Objects
+ {
+ get
+ {
+ lock (m_memberObjects)
+ return new List(m_memberObjects);
+ }
+ }
+
+ ///
+ /// Get the scene that contains the objects in this coalescence. If there are no objects then null is returned.
+ ///
+ public Scene Scene
+ {
+ get
+ {
+ if (!HasObjects)
+ return null;
+ else
+ return Objects[0].Scene;
+ }
+ }
+
+ ///
+ /// At this point, we need to preserve the order of objects added to the coalescence, since the first
+ /// one will end up matching the item name when rerezzed.
+ ///
+ protected List m_memberObjects = new List();
+
+ public CoalescedSceneObjects(UUID creatorId)
+ {
+ CreatorId = creatorId;
+ }
+
+ public CoalescedSceneObjects(UUID creatorId, params SceneObjectGroup[] objs) : this(creatorId)
+ {
+ foreach (SceneObjectGroup obj in objs)
+ Add(obj);
+ }
+
+ ///
+ /// Add an object to the coalescence.
+ ///
+ ///
+ /// The offset of the object within the group
+ public void Add(SceneObjectGroup obj)
+ {
+ lock (m_memberObjects)
+ m_memberObjects.Add(obj);
+ }
+
+ ///
+ /// Removes a scene object from the coalescene
+ ///
+ ///
+ /// true if the object was there to be removed, false if not.
+ public bool Remove(SceneObjectGroup obj)
+ {
+ lock (m_memberObjects)
+ return m_memberObjects.Remove(obj);
+ }
+ }
+}
\ No newline at end of file
diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs
index f0acc38820..e6dd48940f 100644
--- a/OpenSim/Region/Framework/Scenes/Scene.cs
+++ b/OpenSim/Region/Framework/Scenes/Scene.cs
@@ -4839,7 +4839,20 @@ namespace OpenSim.Region.Framework.Scenes
}
}
- public Vector3[] GetCombinedBoundingBox(List objects, out float minX, out float maxX, out float minY, out float maxY, out float minZ, out float maxZ)
+ ///
+ /// Get the volume of space that will encompass all the given objects.
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ public static Vector3[] GetCombinedBoundingBox(
+ List objects,
+ out float minX, out float maxX, out float minY, out float maxY, out float minZ, out float maxZ)
{
minX = 256;
maxX = -256;
diff --git a/OpenSim/Region/Framework/Scenes/SceneGraph.cs b/OpenSim/Region/Framework/Scenes/SceneGraph.cs
index 97af0a0b47..72f040252f 100644
--- a/OpenSim/Region/Framework/Scenes/SceneGraph.cs
+++ b/OpenSim/Region/Framework/Scenes/SceneGraph.cs
@@ -997,6 +997,8 @@ namespace OpenSim.Region.Framework.Scenes
{
foreach (SceneObjectPart p in ((SceneObjectGroup)entity).Parts)
{
+// m_log.DebugFormat("[SCENE GRAPH]: Part {0} has name {1}", p.UUID, p.Name);
+
if (p.Name == name)
{
sop = p;
diff --git a/OpenSim/Region/Framework/Scenes/Serialization/CoalescedSceneObjectsSerializer.cs b/OpenSim/Region/Framework/Scenes/Serialization/CoalescedSceneObjectsSerializer.cs
new file mode 100644
index 0000000000..3af2f76340
--- /dev/null
+++ b/OpenSim/Region/Framework/Scenes/Serialization/CoalescedSceneObjectsSerializer.cs
@@ -0,0 +1,117 @@
+/*
+ * Copyright (c) Contributors, http://opensimulator.org/
+ * See CONTRIBUTORS.TXT for a full list of copyright holders.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the OpenSimulator Project nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+using System;
+using System.Collections.Generic;
+using System.Drawing;
+using System.IO;
+using System.Reflection;
+using System.Xml;
+using log4net;
+using OpenMetaverse;
+using OpenSim.Framework;
+using OpenSim.Region.Framework.Interfaces;
+using OpenSim.Region.Framework.Scenes;
+
+namespace OpenSim.Region.Framework.Scenes.Serialization
+{
+ ///
+ /// Serialize and deserialize coalesced scene objects.
+ ///
+ public class CoalescedSceneObjectsSerializer
+ {
+ private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
+
+ ///
+ /// Serialize coalesced objects to Xml
+ ///
+ ///
+ ///
+ public static string ToXml(CoalescedSceneObjects coa)
+ {
+ // TODO: Should probably return an empty xml serialization rather than a blank string
+ if (!coa.HasObjects)
+ return "";
+
+ using (StringWriter sw = new StringWriter())
+ {
+ using (XmlTextWriter writer = new XmlTextWriter(sw))
+ {
+ List coaObjects = coa.Objects;
+
+// m_log.DebugFormat(
+// "[COALESCED SCENE OBJECTS SERIALIZER]: Writing {0} objects for coalesced object",
+// coaObjects.Count);
+
+ float minX, minY, minZ;
+ float maxX, maxY, maxZ;
+
+ Vector3[] offsets = Scene.GetCombinedBoundingBox(coaObjects,
+ out minX, out maxX, out minY, out maxY,
+ out minZ, out maxZ);
+
+ writer.WriteStartElement("CoalescedObject");
+
+ float sizeX = maxX - minX;
+ float sizeY = maxY - minY;
+ float sizeZ = maxZ - minZ;
+
+ writer.WriteAttributeString("x", sizeX.ToString());
+ writer.WriteAttributeString("y", sizeY.ToString());
+ writer.WriteAttributeString("z", sizeZ.ToString());
+
+ // Embed the offsets into the group XML
+ for (int i = 0; i < coaObjects.Count; i++)
+ {
+ SceneObjectGroup obj = coaObjects[i];
+
+// m_log.DebugFormat(
+// "[COALESCED SCENE OBJECTS SERIALIZER]: Writing offset for object {0}, {1}",
+// i, obj.Name);
+
+ writer.WriteStartElement("SceneObjectGroup");
+ writer.WriteAttributeString("offsetx", offsets[i].X.ToString());
+ writer.WriteAttributeString("offsety", offsets[i].Y.ToString());
+ writer.WriteAttributeString("offsetz", offsets[i].Z.ToString());
+
+ SceneObjectSerializer.ToOriginalXmlFormat(obj, writer, true);
+
+ writer.WriteEndElement();
+ }
+
+ writer.WriteEndElement(); // CoalescedObject
+ }
+
+ string output = sw.ToString();
+
+// m_log.Debug(output);
+
+ return output;
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/OpenSim/Region/Framework/Scenes/Serialization/SceneObjectSerializer.cs b/OpenSim/Region/Framework/Scenes/Serialization/SceneObjectSerializer.cs
index b412e25579..bb8a83a1af 100644
--- a/OpenSim/Region/Framework/Scenes/Serialization/SceneObjectSerializer.cs
+++ b/OpenSim/Region/Framework/Scenes/Serialization/SceneObjectSerializer.cs
@@ -139,6 +139,7 @@ namespace OpenSim.Region.Framework.Scenes.Serialization
return sw.ToString();
}
}
+
///
/// Serialize a scene object to the original xml format
@@ -146,11 +147,25 @@ namespace OpenSim.Region.Framework.Scenes.Serialization
///
///
public static void ToOriginalXmlFormat(SceneObjectGroup sceneObject, XmlTextWriter writer)
+ {
+ ToOriginalXmlFormat(sceneObject, writer, false);
+ }
+
+ ///
+ /// Serialize a scene object to the original xml format
+ ///
+ ///
+ ///
+ /// If false, don't write the enclosing SceneObjectGroup element
+ ///
+ public static void ToOriginalXmlFormat(SceneObjectGroup sceneObject, XmlTextWriter writer, bool noRootElement)
{
//m_log.DebugFormat("[SERIALIZER]: Starting serialization of {0}", Name);
//int time = System.Environment.TickCount;
- writer.WriteStartElement(String.Empty, "SceneObjectGroup", String.Empty);
+ if (!noRootElement)
+ writer.WriteStartElement(String.Empty, "SceneObjectGroup", String.Empty);
+
writer.WriteStartElement(String.Empty, "RootPart", String.Empty);
ToXmlFormat(sceneObject.RootPart, writer);
writer.WriteEndElement();
@@ -170,10 +185,12 @@ namespace OpenSim.Region.Framework.Scenes.Serialization
writer.WriteEndElement(); // OtherParts
sceneObject.SaveScriptedState(writer);
- writer.WriteEndElement(); // SceneObjectGroup
+
+ if (!noRootElement)
+ writer.WriteEndElement(); // SceneObjectGroup
//m_log.DebugFormat("[SERIALIZER]: Finished serialization of SOG {0}, {1}ms", Name, System.Environment.TickCount - time);
- }
+ }
protected static void ToXmlFormat(SceneObjectPart part, XmlTextWriter writer)
{
diff --git a/OpenSim/Tests/Common/Setup/AssetHelpers.cs b/OpenSim/Tests/Common/Setup/AssetHelpers.cs
index ff4423f7ab..af66d7f0a7 100644
--- a/OpenSim/Tests/Common/Setup/AssetHelpers.cs
+++ b/OpenSim/Tests/Common/Setup/AssetHelpers.cs
@@ -71,6 +71,21 @@ namespace OpenSim.Tests.Common
Encoding.ASCII.GetBytes(SceneObjectSerializer.ToOriginalXmlFormat(sog)),
sog.OwnerID);
}
+
+ ///
+ /// Create an asset from the given scene object.
+ ///
+ ///
+ ///
+ ///
+ public static AssetBase CreateAsset(UUID assetUuid, CoalescedSceneObjects coa)
+ {
+ return CreateAsset(
+ assetUuid,
+ AssetType.Object,
+ Encoding.ASCII.GetBytes(CoalescedSceneObjectsSerializer.ToXml(coa)),
+ coa.CreatorId);
+ }
///
/// Create an asset from the given data.