OpenSim
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Events Macros
SceneObjectLinkingTests.cs
Go to the documentation of this file.
1 /*
2  * Copyright (c) Contributors, http://opensimulator.org/
3  * See CONTRIBUTORS.TXT for a full list of copyright holders.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  * * Redistributions of source code must retain the above copyright
8  * notice, this list of conditions and the following disclaimer.
9  * * Redistributions in binary form must reproduce the above copyright
10  * notice, this list of conditions and the following disclaimer in the
11  * documentation and/or other materials provided with the distribution.
12  * * Neither the name of the OpenSimulator Project nor the
13  * names of its contributors may be used to endorse or promote products
14  * derived from this software without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19  * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27 
28 using System;
29 using System.Collections.Generic;
30 using System.Reflection;
31 using NUnit.Framework;
32 using OpenMetaverse;
33 using OpenSim.Framework;
34 using OpenSim.Region.Framework.Scenes;
35 using OpenSim.Tests.Common;
36 using log4net;
37 
38 namespace OpenSim.Region.Framework.Scenes.Tests
39 {
40  [TestFixture]
42  {
43  private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
44 
48  [Test]
49  public void TestLinkToSelf()
50  {
51  TestHelpers.InMethod();
52 
53  UUID ownerId = TestHelpers.ParseTail(0x1);
54  int nParts = 3;
55 
56  TestScene scene = new SceneHelpers().SetupScene();
57  SceneObjectGroup sog1 = SceneHelpers.CreateSceneObject(nParts, ownerId, "TestLinkToSelf_", 0x10);
58  scene.AddSceneObject(sog1);
59  scene.LinkObjects(ownerId, sog1.LocalId, new List<uint>() { sog1.Parts[1].LocalId });
60 // sog1.LinkToGroup(sog1);
61 
62  Assert.That(sog1.Parts.Length, Is.EqualTo(nParts));
63  }
64 
65  [Test]
67  {
68  TestHelpers.InMethod();
69 
70  bool debugtest = false;
71 
72  Scene scene = new SceneHelpers().SetupScene();
73  SceneObjectGroup grp1 = SceneHelpers.AddSceneObject(scene);
74  SceneObjectPart part1 = grp1.RootPart;
75  SceneObjectGroup grp2 = SceneHelpers.AddSceneObject(scene);
76  SceneObjectPart part2 = grp2.RootPart;
77 
78  grp1.AbsolutePosition = new Vector3(10, 10, 10);
79  grp2.AbsolutePosition = Vector3.Zero;
80 
81  // <90,0,0>
82 // grp1.UpdateGroupRotationR(Quaternion.CreateFromEulers(90 * Utils.DEG_TO_RAD, 0, 0));
83 
84  // <180,0,0>
85  grp2.UpdateGroupRotationR(Quaternion.CreateFromEulers(180 * Utils.DEG_TO_RAD, 0, 0));
86 
87  // Required for linking
88  grp1.RootPart.ClearUpdateSchedule();
89  grp2.RootPart.ClearUpdateSchedule();
90 
91  // Link grp2 to grp1. part2 becomes child prim to grp1. grp2 is eliminated.
92  Assert.IsFalse(grp1.GroupContainsForeignPrims);
93  grp1.LinkToGroup(grp2);
94  Assert.IsTrue(grp1.GroupContainsForeignPrims);
95 
96  scene.Backup(true);
97  Assert.IsFalse(grp1.GroupContainsForeignPrims);
98 
99  // FIXME: Can't do this test yet since group 2 still has its root part! We can't yet null this since
100  // it might cause SOG.ProcessBackup() to fail due to the race condition. This really needs to be fixed.
101  Assert.That(grp2.IsDeleted, "SOG 2 was not registered as deleted after link.");
102  Assert.That(grp2.Parts.Length, Is.EqualTo(0), "Group 2 still contained children after delink.");
103  Assert.That(grp1.Parts.Length == 2);
104 
105  if (debugtest)
106  {
107  m_log.Debug("parts: " + grp1.Parts.Length);
108  m_log.Debug("Group1: Pos:"+grp1.AbsolutePosition+", Rot:"+grp1.GroupRotation);
109  m_log.Debug("Group1: Prim1: OffsetPosition:"+ part1.OffsetPosition+", OffsetRotation:"+part1.RotationOffset);
110  m_log.Debug("Group1: Prim2: OffsetPosition:"+part2.OffsetPosition+", OffsetRotation:"+part2.RotationOffset);
111  }
112 
113  // root part should have no offset position or rotation
114  Assert.That(part1.OffsetPosition == Vector3.Zero && part1.RotationOffset == Quaternion.Identity,
115  "root part should have no offset position or rotation");
116 
117  // offset position should be root part position - part2.absolute position.
118  Assert.That(part2.OffsetPosition == new Vector3(-10, -10, -10),
119  "offset position should be root part position - part2.absolute position.");
120 
121  float roll = 0;
122  float pitch = 0;
123  float yaw = 0;
124 
125  // There's a euler anomoly at 180, 0, 0 so expect 180 to turn into -180.
126  part1.RotationOffset.GetEulerAngles(out roll, out pitch, out yaw);
127  Vector3 rotEuler1 = new Vector3(roll * Utils.RAD_TO_DEG, pitch * Utils.RAD_TO_DEG, yaw * Utils.RAD_TO_DEG);
128 
129  if (debugtest)
130  m_log.Debug(rotEuler1);
131 
132  part2.RotationOffset.GetEulerAngles(out roll, out pitch, out yaw);
133  Vector3 rotEuler2 = new Vector3(roll * Utils.RAD_TO_DEG, pitch * Utils.RAD_TO_DEG, yaw * Utils.RAD_TO_DEG);
134 
135  if (debugtest)
136  m_log.Debug(rotEuler2);
137 
138  Assert.That(rotEuler2.ApproxEquals(new Vector3(-180, 0, 0), 0.001f) || rotEuler2.ApproxEquals(new Vector3(180, 0, 0), 0.001f),
139  "Not exactly sure what this is asserting...");
140 
141  // Delink part 2
142  SceneObjectGroup grp3 = grp1.DelinkFromGroup(part2.LocalId);
143 
144  if (debugtest)
145  m_log.Debug("Group2: Prim2: OffsetPosition:" + part2.AbsolutePosition + ", OffsetRotation:" + part2.RotationOffset);
146 
147  Assert.That(grp1.Parts.Length, Is.EqualTo(1), "Group 1 still contained part2 after delink.");
148  Assert.That(part2.AbsolutePosition == Vector3.Zero, "The absolute position should be zero");
149  Assert.NotNull(grp3);
150  }
151 
152  [Test]
154  {
155  TestHelpers.InMethod();
156 
157  bool debugtest = false;
158 
159  Scene scene = new SceneHelpers().SetupScene();
160  SceneObjectGroup grp1 = SceneHelpers.AddSceneObject(scene);
161  SceneObjectPart part1 = grp1.RootPart;
162  SceneObjectGroup grp2 = SceneHelpers.AddSceneObject(scene);
163  SceneObjectPart part2 = grp2.RootPart;
164  SceneObjectGroup grp3 = SceneHelpers.AddSceneObject(scene);
165  SceneObjectPart part3 = grp3.RootPart;
166  SceneObjectGroup grp4 = SceneHelpers.AddSceneObject(scene);
167  SceneObjectPart part4 = grp4.RootPart;
168 
169  grp1.AbsolutePosition = new Vector3(10, 10, 10);
170  grp2.AbsolutePosition = Vector3.Zero;
171  grp3.AbsolutePosition = new Vector3(20, 20, 20);
172  grp4.AbsolutePosition = new Vector3(40, 40, 40);
173 
174  // <90,0,0>
175 // grp1.UpdateGroupRotationR(Quaternion.CreateFromEulers(90 * Utils.DEG_TO_RAD, 0, 0));
176 
177  // <180,0,0>
178  grp2.UpdateGroupRotationR(Quaternion.CreateFromEulers(180 * Utils.DEG_TO_RAD, 0, 0));
179 
180  // <270,0,0>
181 // grp3.UpdateGroupRotationR(Quaternion.CreateFromEulers(270 * Utils.DEG_TO_RAD, 0, 0));
182 
183  // <0,90,0>
184  grp4.UpdateGroupRotationR(Quaternion.CreateFromEulers(0, 90 * Utils.DEG_TO_RAD, 0));
185 
186  // Required for linking
187  grp1.RootPart.ClearUpdateSchedule();
188  grp2.RootPart.ClearUpdateSchedule();
189  grp3.RootPart.ClearUpdateSchedule();
190  grp4.RootPart.ClearUpdateSchedule();
191 
192  // Link grp2 to grp1. part2 becomes child prim to grp1. grp2 is eliminated.
193  grp1.LinkToGroup(grp2);
194 
195  // Link grp4 to grp3.
196  grp3.LinkToGroup(grp4);
197 
198  // At this point we should have 4 parts total in two groups.
199  Assert.That(grp1.Parts.Length == 2, "Group1 children count should be 2");
200  Assert.That(grp2.IsDeleted, "Group 2 was not registered as deleted after link.");
201  Assert.That(grp2.Parts.Length, Is.EqualTo(0), "Group 2 still contained parts after delink.");
202  Assert.That(grp3.Parts.Length == 2, "Group3 children count should be 2");
203  Assert.That(grp4.IsDeleted, "Group 4 was not registered as deleted after link.");
204  Assert.That(grp4.Parts.Length, Is.EqualTo(0), "Group 4 still contained parts after delink.");
205 
206  if (debugtest)
207  {
208  m_log.Debug("--------After Link-------");
209  m_log.Debug("Group1: parts:" + grp1.Parts.Length);
210  m_log.Debug("Group1: Pos:"+grp1.AbsolutePosition+", Rot:"+grp1.GroupRotation);
211  m_log.Debug("Group1: Prim1: OffsetPosition:" + part1.OffsetPosition + ", OffsetRotation:" + part1.RotationOffset);
212  m_log.Debug("Group1: Prim2: OffsetPosition:"+part2.OffsetPosition+", OffsetRotation:"+ part2.RotationOffset);
213 
214  m_log.Debug("Group3: parts:" + grp3.Parts.Length);
215  m_log.Debug("Group3: Pos:"+grp3.AbsolutePosition+", Rot:"+grp3.GroupRotation);
216  m_log.Debug("Group3: Prim1: OffsetPosition:"+part3.OffsetPosition+", OffsetRotation:"+part3.RotationOffset);
217  m_log.Debug("Group3: Prim2: OffsetPosition:"+part4.OffsetPosition+", OffsetRotation:"+part4.RotationOffset);
218  }
219 
220  // Required for linking
221  grp1.RootPart.ClearUpdateSchedule();
222  grp3.RootPart.ClearUpdateSchedule();
223 
224  // root part should have no offset position or rotation
225  Assert.That(part1.OffsetPosition == Vector3.Zero && part1.RotationOffset == Quaternion.Identity,
226  "root part should have no offset position or rotation (again)");
227 
228  // offset position should be root part position - part2.absolute position.
229  Assert.That(part2.OffsetPosition == new Vector3(-10, -10, -10),
230  "offset position should be root part position - part2.absolute position (again)");
231 
232  float roll = 0;
233  float pitch = 0;
234  float yaw = 0;
235 
236  // There's a euler anomoly at 180, 0, 0 so expect 180 to turn into -180.
237  part1.RotationOffset.GetEulerAngles(out roll, out pitch, out yaw);
238  Vector3 rotEuler1 = new Vector3(roll * Utils.RAD_TO_DEG, pitch * Utils.RAD_TO_DEG, yaw * Utils.RAD_TO_DEG);
239 
240  if (debugtest)
241  m_log.Debug(rotEuler1);
242 
243  part2.RotationOffset.GetEulerAngles(out roll, out pitch, out yaw);
244  Vector3 rotEuler2 = new Vector3(roll * Utils.RAD_TO_DEG, pitch * Utils.RAD_TO_DEG, yaw * Utils.RAD_TO_DEG);
245 
246  if (debugtest)
247  m_log.Debug(rotEuler2);
248 
249  Assert.That(rotEuler2.ApproxEquals(new Vector3(-180, 0, 0), 0.001f) || rotEuler2.ApproxEquals(new Vector3(180, 0, 0), 0.001f),
250  "Not sure what this assertion is all about...");
251 
252  // Now we're linking the first group to the third group. This will make the first group child parts of the third one.
253  grp3.LinkToGroup(grp1);
254 
255  // Delink parts 2 and 3
256  grp3.DelinkFromGroup(part2.LocalId);
257  grp3.DelinkFromGroup(part3.LocalId);
258 
259  if (debugtest)
260  {
261  m_log.Debug("--------After De-Link-------");
262  m_log.Debug("Group1: parts:" + grp1.Parts.Length);
263  m_log.Debug("Group1: Pos:" + grp1.AbsolutePosition + ", Rot:" + grp1.GroupRotation);
264  m_log.Debug("Group1: Prim1: OffsetPosition:" + part1.OffsetPosition + ", OffsetRotation:" + part1.RotationOffset);
265  m_log.Debug("Group1: Prim2: OffsetPosition:" + part2.OffsetPosition + ", OffsetRotation:" + part2.RotationOffset);
266 
267  m_log.Debug("Group3: parts:" + grp3.Parts.Length);
268  m_log.Debug("Group3: Pos:" + grp3.AbsolutePosition + ", Rot:" + grp3.GroupRotation);
269  m_log.Debug("Group3: Prim1: OffsetPosition:" + part3.OffsetPosition + ", OffsetRotation:" + part3.RotationOffset);
270  m_log.Debug("Group3: Prim2: OffsetPosition:" + part4.OffsetPosition + ", OffsetRotation:" + part4.RotationOffset);
271  }
272 
273  Assert.That(part2.AbsolutePosition == Vector3.Zero, "Badness 1");
274  Assert.That(part4.OffsetPosition == new Vector3(20, 20, 20), "Badness 2");
275  Quaternion compareQuaternion = new Quaternion(0, 0.7071068f, 0, 0.7071068f);
276  Assert.That((part4.RotationOffset.X - compareQuaternion.X < 0.00003)
277  && (part4.RotationOffset.Y - compareQuaternion.Y < 0.00003)
278  && (part4.RotationOffset.Z - compareQuaternion.Z < 0.00003)
279  && (part4.RotationOffset.W - compareQuaternion.W < 0.00003),
280  "Badness 3");
281  }
282 
286  [Test]
288  {
289  TestHelpers.InMethod();
290  //log4net.Config.XmlConfigurator.Configure();
291 
292  TestScene scene = new SceneHelpers().SetupScene();
293 
294  string rootPartName = "rootpart";
295  UUID rootPartUuid = new UUID("00000000-0000-0000-0000-000000000001");
296  string linkPartName = "linkpart";
297  UUID linkPartUuid = new UUID("00000000-0000-0000-0001-000000000000");
298 
299  SceneObjectPart rootPart
300  = new SceneObjectPart(UUID.Zero, PrimitiveBaseShape.Default, Vector3.Zero, Quaternion.Identity, Vector3.Zero)
301  { Name = rootPartName, UUID = rootPartUuid };
302  SceneObjectPart linkPart
303  = new SceneObjectPart(UUID.Zero, PrimitiveBaseShape.Default, Vector3.Zero, Quaternion.Identity, Vector3.Zero)
304  { Name = linkPartName, UUID = linkPartUuid };
305 
306  SceneObjectGroup sog = new SceneObjectGroup(rootPart);
307  sog.AddPart(linkPart);
308  scene.AddNewSceneObject(sog, true);
309 
310  // In a test, we have to crank the backup handle manually. Normally this would be done by the timer invoked
311  // scene backup thread.
312  scene.Backup(true);
313 
314  List<SceneObjectGroup> storedObjects = scene.SimulationDataService.LoadObjects(scene.RegionInfo.RegionID);
315 
316  Assert.That(storedObjects.Count, Is.EqualTo(1));
317  Assert.That(storedObjects[0].Parts.Length, Is.EqualTo(2));
318  Assert.That(storedObjects[0].ContainsPart(rootPartUuid));
319  Assert.That(storedObjects[0].ContainsPart(linkPartUuid));
320  }
321 
325  [Test]
326  public void TestDelinkPersistence()
327  {
328  TestHelpers.InMethod();
329  //log4net.Config.XmlConfigurator.Configure();
330 
331  TestScene scene = new SceneHelpers().SetupScene();
332 
333  string rootPartName = "rootpart";
334  UUID rootPartUuid = new UUID("00000000-0000-0000-0000-000000000001");
335  string linkPartName = "linkpart";
336  UUID linkPartUuid = new UUID("00000000-0000-0000-0001-000000000000");
337 
338  SceneObjectPart rootPart
339  = new SceneObjectPart(UUID.Zero, PrimitiveBaseShape.Default, Vector3.Zero, Quaternion.Identity, Vector3.Zero)
340  { Name = rootPartName, UUID = rootPartUuid };
341 
342  SceneObjectPart linkPart
343  = new SceneObjectPart(UUID.Zero, PrimitiveBaseShape.Default, Vector3.Zero, Quaternion.Identity, Vector3.Zero)
344  { Name = linkPartName, UUID = linkPartUuid };
345  SceneObjectGroup linkGroup = new SceneObjectGroup(linkPart);
346  scene.AddNewSceneObject(linkGroup, true);
347 
348  SceneObjectGroup sog = new SceneObjectGroup(rootPart);
349  scene.AddNewSceneObject(sog, true);
350 
351  Assert.IsFalse(sog.GroupContainsForeignPrims);
352  sog.LinkToGroup(linkGroup);
353  Assert.IsTrue(sog.GroupContainsForeignPrims);
354 
355  scene.Backup(true);
356  Assert.AreEqual(1, scene.SimulationDataService.LoadObjects(scene.RegionInfo.RegionID).Count);
357 
358  // These changes should occur immediately without waiting for a backup pass
359  SceneObjectGroup groupToDelete = sog.DelinkFromGroup(linkPart, false);
360  Assert.IsFalse(groupToDelete.GroupContainsForeignPrims);
361 
362 /* backup is async
363  scene.DeleteSceneObject(groupToDelete, false);
364 
365  List<SceneObjectGroup> storedObjects = scene.SimulationDataService.LoadObjects(scene.RegionInfo.RegionID);
366 
367  Assert.AreEqual(1, storedObjects.Count);
368  Assert.AreEqual(1, storedObjects[0].Parts.Length);
369  Assert.IsTrue(storedObjects[0].ContainsPart(rootPartUuid));
370 */
371  }
372  }
373 }
OpenSim.Server.Handlers.Simulation.Utils Utils
A scene object group is conceptually an object in the scene. The object is constituted of SceneObject...
void TestNewSceneObjectLinkPersistence()
Test that a new scene object which is already linked is correctly persisted to the persistence layer...
Helpers for setting up scenes.
Definition: SceneHelpers.cs:60
void TestDelinkPersistence()
Test that a delink of a previously linked object is correctly persisted to the database ...