aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/Framework
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Region/Framework')
-rw-r--r--OpenSim/Region/Framework/Scenes/Scene.cs21
-rw-r--r--OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs59
-rw-r--r--OpenSim/Region/Framework/Scenes/ScenePresence.cs2
-rw-r--r--OpenSim/Region/Framework/Scenes/Serialization/CoalescedSceneObjectsSerializer.cs89
-rw-r--r--OpenSim/Region/Framework/Scenes/Serialization/SceneObjectSerializer.cs71
-rw-r--r--OpenSim/Region/Framework/Scenes/Tests/SceneObjectLinkingTests.cs36
6 files changed, 179 insertions, 99 deletions
diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs
index d16b73b..51f6c5e 100644
--- a/OpenSim/Region/Framework/Scenes/Scene.cs
+++ b/OpenSim/Region/Framework/Scenes/Scene.cs
@@ -1757,6 +1757,7 @@ namespace OpenSim.Region.Framework.Scenes
1757 { 1757 {
1758 if (group != null) 1758 if (group != null)
1759 { 1759 {
1760 group.HasGroupChanged = true;
1760 group.ProcessBackup(SimulationDataService, true); 1761 group.ProcessBackup(SimulationDataService, true);
1761 } 1762 }
1762 } 1763 }
@@ -2345,13 +2346,12 @@ namespace OpenSim.Region.Framework.Scenes
2345 { 2346 {
2346 if (!softDelete) 2347 if (!softDelete)
2347 { 2348 {
2348 // Force a database update so that the scene object group ID is accurate. It's possible that the 2349 // If the group contains prims whose SceneGroupID is incorrect then force a
2349 // group has recently been delinked from another group but that this change has not been persisted 2350 // database update, because RemoveObject() works by searching on the SceneGroupID.
2350 // to the DB.
2351 // This is an expensive thing to do so only do it if absolutely necessary. 2351 // This is an expensive thing to do so only do it if absolutely necessary.
2352 if (so.HasGroupChangedDueToDelink) 2352 if (so.GroupContainsForeignPrims)
2353 ForceSceneObjectBackup(so); 2353 ForceSceneObjectBackup(so);
2354 2354
2355 so.DetachFromBackup(); 2355 so.DetachFromBackup();
2356 SimulationDataService.RemoveObject(so.UUID, RegionInfo.RegionID); 2356 SimulationDataService.RemoveObject(so.UUID, RegionInfo.RegionID);
2357 } 2357 }
@@ -3413,6 +3413,7 @@ namespace OpenSim.Region.Framework.Scenes
3413 // TeleportFlags.ViaLandmark | TeleportFlags.ViaLocation | TeleportFlags.ViaLandmark | TeleportFlags.Default - Regular Teleport 3413 // TeleportFlags.ViaLandmark | TeleportFlags.ViaLocation | TeleportFlags.ViaLandmark | TeleportFlags.Default - Regular Teleport
3414 3414
3415 // Don't disable this log message - it's too helpful 3415 // Don't disable this log message - it's too helpful
3416 string curViewer = Util.GetViewerName(acd);
3416 m_log.DebugFormat( 3417 m_log.DebugFormat(
3417 "[SCENE]: Region {0} told of incoming {1} agent {2} {3} {4} (circuit code {5}, IP {6}, viewer {7}, teleportflags ({8}), position {9})", 3418 "[SCENE]: Region {0} told of incoming {1} agent {2} {3} {4} (circuit code {5}, IP {6}, viewer {7}, teleportflags ({8}), position {9})",
3418 RegionInfo.RegionName, 3419 RegionInfo.RegionName,
@@ -3422,7 +3423,7 @@ namespace OpenSim.Region.Framework.Scenes
3422 acd.AgentID, 3423 acd.AgentID,
3423 acd.circuitcode, 3424 acd.circuitcode,
3424 acd.IPAddress, 3425 acd.IPAddress,
3425 acd.Viewer, 3426 curViewer,
3426 ((TPFlags)teleportFlags).ToString(), 3427 ((TPFlags)teleportFlags).ToString(),
3427 acd.startpos 3428 acd.startpos
3428 ); 3429 );
@@ -3442,7 +3443,7 @@ namespace OpenSim.Region.Framework.Scenes
3442 { 3443 {
3443 foreach (string viewer in m_AllowedViewers) 3444 foreach (string viewer in m_AllowedViewers)
3444 { 3445 {
3445 if (viewer == acd.Viewer.Substring(0, viewer.Length).Trim().ToLower()) 3446 if (viewer == curViewer.Substring(0, viewer.Length).Trim().ToLower())
3446 { 3447 {
3447 ViewerDenied = false; 3448 ViewerDenied = false;
3448 break; 3449 break;
@@ -3459,7 +3460,7 @@ namespace OpenSim.Region.Framework.Scenes
3459 { 3460 {
3460 foreach (string viewer in m_BannedViewers) 3461 foreach (string viewer in m_BannedViewers)
3461 { 3462 {
3462 if (viewer == acd.Viewer.Substring(0, viewer.Length).Trim().ToLower()) 3463 if (viewer == curViewer.Substring(0, viewer.Length).Trim().ToLower())
3463 { 3464 {
3464 ViewerDenied = true; 3465 ViewerDenied = true;
3465 break; 3466 break;
@@ -3471,7 +3472,7 @@ namespace OpenSim.Region.Framework.Scenes
3471 { 3472 {
3472 m_log.DebugFormat( 3473 m_log.DebugFormat(
3473 "[SCENE]: Access denied for {0} {1} using {2}", 3474 "[SCENE]: Access denied for {0} {1} using {2}",
3474 acd.firstname, acd.lastname, acd.Viewer); 3475 acd.firstname, acd.lastname, curViewer);
3475 reason = "Access denied, your viewer is banned by the region owner"; 3476 reason = "Access denied, your viewer is banned by the region owner";
3476 return false; 3477 return false;
3477 } 3478 }
diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs
index 6f26176..b70e9df 100644
--- a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs
+++ b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs
@@ -150,12 +150,27 @@ namespace OpenSim.Region.Framework.Scenes
150 150
151 get { return m_hasGroupChanged; } 151 get { return m_hasGroupChanged; }
152 } 152 }
153
154 private bool m_groupContainsForeignPrims = false;
153 155
154 /// <summary> 156 /// <summary>
155 /// Has the group changed due to an unlink operation? We record this in order to optimize deletion, since 157 /// Whether the group contains prims that came from a different group. This happens when
156 /// an unlinked group currently has to be persisted to the database before we can perform an unlink operation. 158 /// linking or delinking groups. The implication is that until the group is persisted,
159 /// the prims in the database still use the old SceneGroupID. That's a problem if the group
160 /// is deleted, because we delete groups by searching for prims by their SceneGroupID.
157 /// </summary> 161 /// </summary>
158 public bool HasGroupChangedDueToDelink { get; private set; } 162 public bool GroupContainsForeignPrims
163 {
164 private set
165 {
166 m_groupContainsForeignPrims = value;
167 if (m_groupContainsForeignPrims)
168 HasGroupChanged = true;
169 }
170
171 get { return m_groupContainsForeignPrims; }
172 }
173
159 174
160 private bool isTimeToPersist() 175 private bool isTimeToPersist()
161 { 176 {
@@ -1624,7 +1639,7 @@ namespace OpenSim.Region.Framework.Scenes
1624 backup_group.RootPart.AngularVelocity = RootPart.AngularVelocity; 1639 backup_group.RootPart.AngularVelocity = RootPart.AngularVelocity;
1625 backup_group.RootPart.ParticleSystem = RootPart.ParticleSystem; 1640 backup_group.RootPart.ParticleSystem = RootPart.ParticleSystem;
1626 HasGroupChanged = false; 1641 HasGroupChanged = false;
1627 HasGroupChangedDueToDelink = false; 1642 GroupContainsForeignPrims = false;
1628 1643
1629 m_scene.EventManager.TriggerOnSceneObjectPreSave(backup_group, this); 1644 m_scene.EventManager.TriggerOnSceneObjectPreSave(backup_group, this);
1630 datastore.StoreObject(backup_group, m_scene.RegionInfo.RegionID); 1645 datastore.StoreObject(backup_group, m_scene.RegionInfo.RegionID);
@@ -1686,28 +1701,7 @@ namespace OpenSim.Region.Framework.Scenes
1686 SceneObjectGroup dupe = (SceneObjectGroup)MemberwiseClone(); 1701 SceneObjectGroup dupe = (SceneObjectGroup)MemberwiseClone();
1687 dupe.Backup = false; 1702 dupe.Backup = false;
1688 dupe.m_parts = new MapAndArray<OpenMetaverse.UUID, SceneObjectPart>(); 1703 dupe.m_parts = new MapAndArray<OpenMetaverse.UUID, SceneObjectPart>();
1689
1690 // Warning, The following code related to previousAttachmentStatus is needed so that clones of
1691 // attachments do not bordercross while they're being duplicated. This is hacktastic!
1692 // Normally, setting AbsolutePosition will bordercross a prim if it's outside the region!
1693 // unless IsAttachment is true!, so to prevent border crossing, we save it's attachment state
1694 // (which should be false anyway) set it as an Attachment and then set it's Absolute Position,
1695 // then restore it's attachment state
1696
1697 // This is only necessary when userExposed is false!
1698
1699 bool previousAttachmentStatus = dupe.IsAttachment;
1700
1701 if (!userExposed)
1702 dupe.IsAttachment = true;
1703
1704 dupe.m_sittingAvatars = new List<UUID>(); 1704 dupe.m_sittingAvatars = new List<UUID>();
1705
1706 if (!userExposed)
1707 {
1708 dupe.IsAttachment = previousAttachmentStatus;
1709 }
1710
1711 dupe.CopyRootPart(m_rootPart, OwnerID, GroupID, userExposed); 1705 dupe.CopyRootPart(m_rootPart, OwnerID, GroupID, userExposed);
1712 dupe.m_rootPart.LinkNum = m_rootPart.LinkNum; 1706 dupe.m_rootPart.LinkNum = m_rootPart.LinkNum;
1713 1707
@@ -2388,6 +2382,8 @@ namespace OpenSim.Region.Framework.Scenes
2388 // If linking prims with different permissions, fix them 2382 // If linking prims with different permissions, fix them
2389 AdjustChildPrimPermissions(); 2383 AdjustChildPrimPermissions();
2390 2384
2385 GroupContainsForeignPrims = true;
2386
2391 AttachToBackup(); 2387 AttachToBackup();
2392 2388
2393 // Here's the deal, this is ABSOLUTELY CRITICAL so the physics scene gets the update about the 2389 // Here's the deal, this is ABSOLUTELY CRITICAL so the physics scene gets the update about the
@@ -2531,9 +2527,16 @@ namespace OpenSim.Region.Framework.Scenes
2531 2527
2532 linkPart.Rezzed = RootPart.Rezzed; 2528 linkPart.Rezzed = RootPart.Rezzed;
2533 2529
2534 // When we delete a group, we currently have to force persist to the database if the object id has changed 2530 // We must persist the delinked group to the database immediately, for safety. The problem
2535 // (since delete works by deleting all rows which have a given object id) 2531 // is that although in memory the new group has a new SceneGroupID, in the database it
2536 objectGroup.HasGroupChangedDueToDelink = true; 2532 // still has the parent group's SceneGroupID (until the next backup). This means that if the
2533 // parent group is deleted then the delinked group will also be deleted from the database.
2534 // This problem will disappear if the region remains alive long enough for another backup,
2535 // since at that time the delinked group's new SceneGroupID will be written to the database.
2536 // But if the region crashes before that then the prims will be permanently gone, and this must
2537 // not happen. (We can't use a just-in-time trick like GroupContainsForeignPrims in this case
2538 // because the delinked group doesn't know when the source group is deleted.)
2539 m_scene.ForceSceneObjectBackup(objectGroup);
2537 2540
2538 return objectGroup; 2541 return objectGroup;
2539 } 2542 }
diff --git a/OpenSim/Region/Framework/Scenes/ScenePresence.cs b/OpenSim/Region/Framework/Scenes/ScenePresence.cs
index 491d0bf..64c464d 100644
--- a/OpenSim/Region/Framework/Scenes/ScenePresence.cs
+++ b/OpenSim/Region/Framework/Scenes/ScenePresence.cs
@@ -848,7 +848,7 @@ namespace OpenSim.Region.Framework.Scenes
848 848
849 public string Viewer 849 public string Viewer
850 { 850 {
851 get { return m_scene.AuthenticateHandler.GetAgentCircuitData(ControllingClient.CircuitCode).Viewer; } 851 get { return Util.GetViewerName(m_scene.AuthenticateHandler.GetAgentCircuitData(ControllingClient.CircuitCode)); }
852 } 852 }
853 853
854 #endregion 854 #endregion
diff --git a/OpenSim/Region/Framework/Scenes/Serialization/CoalescedSceneObjectsSerializer.cs b/OpenSim/Region/Framework/Scenes/Serialization/CoalescedSceneObjectsSerializer.cs
index 5cb271d..a556f9d 100644
--- a/OpenSim/Region/Framework/Scenes/Serialization/CoalescedSceneObjectsSerializer.cs
+++ b/OpenSim/Region/Framework/Scenes/Serialization/CoalescedSceneObjectsSerializer.cs
@@ -119,21 +119,22 @@ namespace OpenSim.Region.Framework.Scenes.Serialization
119 return output; 119 return output;
120 } 120 }
121 } 121 }
122 122
123 public static bool TryFromXml(string xml, out CoalescedSceneObjects coa) 123 public static bool TryFromXml(string xml, out CoalescedSceneObjects coa)
124 { 124 {
125// m_log.DebugFormat("[COALESCED SCENE OBJECTS SERIALIZER]: TryFromXml() deserializing {0}", xml); 125// m_log.DebugFormat("[COALESCED SCENE OBJECTS SERIALIZER]: TryFromXml() deserializing {0}", xml);
126 126
127 coa = null; 127 coa = null;
128 int i = 0;
129 128
130 using (StringReader sr = new StringReader(xml)) 129 try
131 { 130 {
132 using (XmlTextReader reader = new XmlTextReader(sr)) 131 // Quickly check if this is a coalesced object, without fully parsing the XML
133 { 132 using (StringReader sr = new StringReader(xml))
134 try 133 {
134 using (XmlTextReader reader = new XmlTextReader(sr))
135 { 135 {
136 reader.Read(); 136 reader.MoveToContent(); // skip possible xml declaration
137
137 if (reader.Name != "CoalescedObject") 138 if (reader.Name != "CoalescedObject")
138 { 139 {
139 // m_log.DebugFormat( 140 // m_log.DebugFormat(
@@ -142,49 +143,49 @@ namespace OpenSim.Region.Framework.Scenes.Serialization
142 143
143 return false; 144 return false;
144 } 145 }
145 146 }
146 coa = new CoalescedSceneObjects(UUID.Zero); 147 }
147 reader.Read();
148
149 while (reader.NodeType != XmlNodeType.EndElement && reader.Name != "CoalescedObject")
150 {
151 if (reader.Name == "SceneObjectGroup")
152 {
153 string soXml = reader.ReadOuterXml();
154
155 SceneObjectGroup so = SceneObjectSerializer.FromOriginalXmlFormat(soXml);
156
157 if (so != null)
158 {
159 coa.Add(so);
160 }
161 else
162 {
163 // XXX: Possibly we should fail outright here rather than continuing if a particular component of the
164 // coalesced object fails to load.
165 m_log.WarnFormat(
166 "[COALESCED SCENE OBJECTS SERIALIZER]: Deserialization of xml for component {0} failed. Continuing.",
167 i);
168 }
169 148
170 i++; 149 XmlDocument doc = new XmlDocument();
171 } 150 doc.LoadXml(xml);
172 } 151 XmlElement e = (XmlElement)doc.SelectSingleNode("/CoalescedObject");
152 if (e == null)
153 return false;
173 154
174 reader.ReadEndElement(); // CoalescedObject 155 coa = new CoalescedSceneObjects(UUID.Zero);
156
157 XmlNodeList groups = e.SelectNodes("SceneObjectGroup");
158 int i = 0;
159
160 foreach (XmlNode n in groups)
161 {
162 SceneObjectGroup so = SceneObjectSerializer.FromOriginalXmlFormat(n.OuterXml);
163 if (so != null)
164 {
165 coa.Add(so);
175 } 166 }
176 catch (Exception e) 167 else
177 { 168 {
178 m_log.ErrorFormat( 169 // XXX: Possibly we should fail outright here rather than continuing if a particular component of the
179 "[COALESCED SCENE OBJECTS SERIALIZER]: Deserialization of xml failed with {0} {1}", 170 // coalesced object fails to load.
180 e.Message, e.StackTrace); 171 m_log.WarnFormat(
181 172 "[COALESCED SCENE OBJECTS SERIALIZER]: Deserialization of xml for component {0} failed. Continuing.",
182 return false; 173 i);
183 } 174 }
175
176 i++;
184 } 177 }
185 } 178 }
179 catch (Exception e)
180 {
181 m_log.Error(string.Format(
182 "[COALESCED SCENE OBJECTS SERIALIZER]: Deserialization of xml failed with {0} ",
183 e.Message), e);
184
185 return false;
186 }
186 187
187 return true; 188 return true;
188 } 189 }
189 } 190 }
190} \ No newline at end of file 191}
diff --git a/OpenSim/Region/Framework/Scenes/Serialization/SceneObjectSerializer.cs b/OpenSim/Region/Framework/Scenes/Serialization/SceneObjectSerializer.cs
index f07dee9..a93f3c8 100644
--- a/OpenSim/Region/Framework/Scenes/Serialization/SceneObjectSerializer.cs
+++ b/OpenSim/Region/Framework/Scenes/Serialization/SceneObjectSerializer.cs
@@ -299,6 +299,73 @@ namespace OpenSim.Region.Framework.Scenes.Serialization
299 } 299 }
300 } 300 }
301 301
302
303 /// <summary>
304 /// Modifies a SceneObjectGroup.
305 /// </summary>
306 /// <param name="sog">The object</param>
307 /// <returns>Whether the object was actually modified</returns>
308 public delegate bool SceneObjectModifier(SceneObjectGroup sog);
309
310 /// <summary>
311 /// Modifies an object by deserializing it; applying 'modifier' to each SceneObjectGroup; and reserializing.
312 /// </summary>
313 /// <param name="assetId">The object's UUID</param>
314 /// <param name="data">Serialized data</param>
315 /// <param name="modifier">The function to run on each SceneObjectGroup</param>
316 /// <returns>The new serialized object's data, or null if an error occurred</returns>
317 public static byte[] ModifySerializedObject(UUID assetId, byte[] data, SceneObjectModifier modifier)
318 {
319 List<SceneObjectGroup> sceneObjects = new List<SceneObjectGroup>();
320 CoalescedSceneObjects coa = null;
321
322 string xmlData = Utils.BytesToString(data);
323
324 if (CoalescedSceneObjectsSerializer.TryFromXml(xmlData, out coa))
325 {
326 // m_log.DebugFormat("[SERIALIZER]: Loaded coalescence {0} has {1} objects", assetId, coa.Count);
327
328 if (coa.Objects.Count == 0)
329 {
330 m_log.WarnFormat("[SERIALIZER]: Aborting load of coalesced object from asset {0} as it has zero loaded components", assetId);
331 return null;
332 }
333
334 sceneObjects.AddRange(coa.Objects);
335 }
336 else
337 {
338 SceneObjectGroup deserializedObject = FromOriginalXmlFormat(xmlData);
339
340 if (deserializedObject != null)
341 {
342 sceneObjects.Add(deserializedObject);
343 }
344 else
345 {
346 m_log.WarnFormat("[SERIALIZER]: Aborting load of object from asset {0} as deserialization failed", assetId);
347 return null;
348 }
349 }
350
351 bool modified = false;
352 foreach (SceneObjectGroup sog in sceneObjects)
353 {
354 if (modifier(sog))
355 modified = true;
356 }
357
358 if (modified)
359 {
360 if (coa != null)
361 data = Utils.StringToBytes(CoalescedSceneObjectsSerializer.ToXml(coa));
362 else
363 data = Utils.StringToBytes(ToOriginalXmlFormat(sceneObjects[0]));
364 }
365
366 return data;
367 }
368
302 369
303 #region manual serialization 370 #region manual serialization
304 371
@@ -1230,7 +1297,7 @@ namespace OpenSim.Region.Framework.Scenes.Serialization
1230 if (m_UserManagement == null) 1297 if (m_UserManagement == null)
1231 m_UserManagement = sop.ParentGroup.Scene.RequestModuleInterface<IUserManagement>(); 1298 m_UserManagement = sop.ParentGroup.Scene.RequestModuleInterface<IUserManagement>();
1232 string name = m_UserManagement.GetUserName(sop.CreatorID); 1299 string name = m_UserManagement.GetUserName(sop.CreatorID);
1233 writer.WriteElementString("CreatorData", (string)options["home"] + ";" + name); 1300 writer.WriteElementString("CreatorData", ExternalRepresentationUtils.CalcCreatorData((string)options["home"], name));
1234 } 1301 }
1235 1302
1236 WriteUUID(writer, "FolderID", sop.FolderID, options); 1303 WriteUUID(writer, "FolderID", sop.FolderID, options);
@@ -1403,7 +1470,7 @@ namespace OpenSim.Region.Framework.Scenes.Serialization
1403 if (m_UserManagement == null) 1470 if (m_UserManagement == null)
1404 m_UserManagement = scene.RequestModuleInterface<IUserManagement>(); 1471 m_UserManagement = scene.RequestModuleInterface<IUserManagement>();
1405 string name = m_UserManagement.GetUserName(item.CreatorID); 1472 string name = m_UserManagement.GetUserName(item.CreatorID);
1406 writer.WriteElementString("CreatorData", (string)options["home"] + ";" + name); 1473 writer.WriteElementString("CreatorData", ExternalRepresentationUtils.CalcCreatorData((string)options["home"], name));
1407 } 1474 }
1408 1475
1409 writer.WriteElementString("Description", item.Description); 1476 writer.WriteElementString("Description", item.Description);
diff --git a/OpenSim/Region/Framework/Scenes/Tests/SceneObjectLinkingTests.cs b/OpenSim/Region/Framework/Scenes/Tests/SceneObjectLinkingTests.cs
index 9378e20..c928b1e 100644
--- a/OpenSim/Region/Framework/Scenes/Tests/SceneObjectLinkingTests.cs
+++ b/OpenSim/Region/Framework/Scenes/Tests/SceneObjectLinkingTests.cs
@@ -91,7 +91,12 @@ namespace OpenSim.Region.Framework.Scenes.Tests
91 grp2.RootPart.ClearUpdateSchedule(); 91 grp2.RootPart.ClearUpdateSchedule();
92 92
93 // Link grp2 to grp1. part2 becomes child prim to grp1. grp2 is eliminated. 93 // Link grp2 to grp1. part2 becomes child prim to grp1. grp2 is eliminated.
94 Assert.IsFalse(grp1.GroupContainsForeignPrims);
94 grp1.LinkToGroup(grp2); 95 grp1.LinkToGroup(grp2);
96 Assert.IsTrue(grp1.GroupContainsForeignPrims);
97
98 scene.Backup(true);
99 Assert.IsFalse(grp1.GroupContainsForeignPrims);
95 100
96 // FIXME: Can't do this test yet since group 2 still has its root part! We can't yet null this since 101 // FIXME: Can't do this test yet since group 2 still has its root part! We can't yet null this since
97 // it might cause SOG.ProcessBackup() to fail due to the race condition. This really needs to be fixed. 102 // it might cause SOG.ProcessBackup() to fail due to the race condition. This really needs to be fixed.
@@ -143,7 +148,6 @@ namespace OpenSim.Region.Framework.Scenes.Tests
143 148
144 Assert.That(grp1.Parts.Length, Is.EqualTo(1), "Group 1 still contained part2 after delink."); 149 Assert.That(grp1.Parts.Length, Is.EqualTo(1), "Group 1 still contained part2 after delink.");
145 Assert.That(part2.AbsolutePosition == Vector3.Zero, "The absolute position should be zero"); 150 Assert.That(part2.AbsolutePosition == Vector3.Zero, "The absolute position should be zero");
146 Assert.That(grp3.HasGroupChangedDueToDelink, Is.True);
147 } 151 }
148 152
149 [Test] 153 [Test]
@@ -335,30 +339,34 @@ namespace OpenSim.Region.Framework.Scenes.Tests
335 SceneObjectPart rootPart 339 SceneObjectPart rootPart
336 = new SceneObjectPart(UUID.Zero, PrimitiveBaseShape.Default, Vector3.Zero, Quaternion.Identity, Vector3.Zero) 340 = new SceneObjectPart(UUID.Zero, PrimitiveBaseShape.Default, Vector3.Zero, Quaternion.Identity, Vector3.Zero)
337 { Name = rootPartName, UUID = rootPartUuid }; 341 { Name = rootPartName, UUID = rootPartUuid };
342
338 SceneObjectPart linkPart 343 SceneObjectPart linkPart
339 = new SceneObjectPart(UUID.Zero, PrimitiveBaseShape.Default, Vector3.Zero, Quaternion.Identity, Vector3.Zero) 344 = new SceneObjectPart(UUID.Zero, PrimitiveBaseShape.Default, Vector3.Zero, Quaternion.Identity, Vector3.Zero)
340 { Name = linkPartName, UUID = linkPartUuid }; 345 { Name = linkPartName, UUID = linkPartUuid };
346 SceneObjectGroup linkGroup = new SceneObjectGroup(linkPart);
347 scene.AddNewSceneObject(linkGroup, true);
341 348
342 SceneObjectGroup sog = new SceneObjectGroup(rootPart); 349 SceneObjectGroup sog = new SceneObjectGroup(rootPart);
343 sog.AddPart(linkPart); 350 scene.AddNewSceneObject(sog, true);
344 scene.AddNewSceneObject(sog, true); 351
345 352 Assert.IsFalse(sog.GroupContainsForeignPrims);
346 // In a test, we have to crank the backup handle manually. Normally this would be done by the timer invoked 353 sog.LinkToGroup(linkGroup);
347 // scene backup thread. 354 Assert.IsTrue(sog.GroupContainsForeignPrims);
355
348 scene.Backup(true); 356 scene.Backup(true);
349 357 Assert.AreEqual(1, scene.SimulationDataService.LoadObjects(scene.RegionInfo.RegionID).Count);
358
350 // These changes should occur immediately without waiting for a backup pass 359 // These changes should occur immediately without waiting for a backup pass
351 SceneObjectGroup groupToDelete = sog.DelinkFromGroup(linkPart, false); 360 SceneObjectGroup groupToDelete = sog.DelinkFromGroup(linkPart, false);
352 361 Assert.IsFalse(groupToDelete.GroupContainsForeignPrims);
353 Assert.That(groupToDelete.HasGroupChangedDueToDelink, Is.True); 362
354 scene.DeleteSceneObject(groupToDelete, false); 363 scene.DeleteSceneObject(groupToDelete, false);
355 Assert.That(groupToDelete.HasGroupChangedDueToDelink, Is.False);
356 364
357 List<SceneObjectGroup> storedObjects = scene.SimulationDataService.LoadObjects(scene.RegionInfo.RegionID); 365 List<SceneObjectGroup> storedObjects = scene.SimulationDataService.LoadObjects(scene.RegionInfo.RegionID);
358 366
359 Assert.That(storedObjects.Count, Is.EqualTo(1)); 367 Assert.AreEqual(1, storedObjects.Count);
360 Assert.That(storedObjects[0].Parts.Length, Is.EqualTo(1)); 368 Assert.AreEqual(1, storedObjects[0].Parts.Length);
361 Assert.That(storedObjects[0].ContainsPart(rootPartUuid)); 369 Assert.IsTrue(storedObjects[0].ContainsPart(rootPartUuid));
362 } 370 }
363 } 371 }
364} 372}