OpenSim
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Events Macros
ArchiverTests.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.IO;
31 using System.Reflection;
32 using System.Threading;
33 using log4net.Config;
34 using Nini.Config;
35 using NUnit.Framework;
36 using OpenMetaverse;
37 using OpenMetaverse.Assets;
38 using OpenSim.Framework;
39 using OpenSim.Framework.Serialization;
40 using OpenSim.Framework.Serialization.External;
41 using OpenSim.Region.CoreModules.World.Land;
42 using OpenSim.Region.CoreModules.World.Serialiser;
43 using OpenSim.Region.CoreModules.World.Terrain;
44 using OpenSim.Region.Framework.Scenes;
45 using OpenSim.Region.Framework.Scenes.Serialization;
46 using OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups;
47 using OpenSim.Tests.Common;
52 using OpenSim.Region.Framework.Interfaces;
53 
54 namespace OpenSim.Region.CoreModules.World.Archiver.Tests
55 {
56  [TestFixture]
58  {
59  private Guid m_lastRequestId;
60  private string m_lastErrorMessage;
61 
63  protected TestScene m_scene;
66 
68 
69  private AutoResetEvent m_oarEvent = new AutoResetEvent(false);
70 
71  [SetUp]
72  public override void SetUp()
73  {
74  base.SetUp();
75 
76  m_archiverModule = new ArchiverModule();
77  m_serialiserModule = new SerialiserModule();
78  TerrainModule terrainModule = new TerrainModule();
79 
80  m_sceneHelpers = new SceneHelpers();
81  m_scene = m_sceneHelpers.SetupScene();
82  SceneHelpers.SetupSceneModules(m_scene, m_archiverModule, m_serialiserModule, terrainModule);
83  }
84 
85  private void LoadCompleted(Guid requestId, List<UUID> loadedScenes, string errorMessage)
86  {
87  lock (this)
88  {
89  m_lastRequestId = requestId;
90  m_lastErrorMessage = errorMessage;
91  Console.WriteLine("About to pulse ArchiverTests on LoadCompleted");
92  m_oarEvent.Set();
93  }
94  }
95 
96  private void SaveCompleted(Guid requestId, string errorMessage)
97  {
98  lock (this)
99  {
100  m_lastRequestId = requestId;
101  m_lastErrorMessage = errorMessage;
102  Console.WriteLine("About to pulse ArchiverTests on SaveCompleted");
103  m_oarEvent.Set();
104  }
105  }
106 
108  {
109  string partName = "My Little Pony";
110  UUID ownerId = UUID.Parse("00000000-0000-0000-0000-000000000015");
111  PrimitiveBaseShape shape = PrimitiveBaseShape.CreateSphere();
112  Vector3 groupPosition = new Vector3(10, 20, 30);
113  Quaternion rotationOffset = new Quaternion(20, 30, 40, 50);
114  rotationOffset.Normalize();
115 // Vector3 offsetPosition = new Vector3(5, 10, 15);
116 
117  return new SceneObjectPart(ownerId, shape, groupPosition, rotationOffset, Vector3.Zero) { Name = partName };
118  }
119 
121  {
122  string partName = "Action Man";
123  UUID ownerId = UUID.Parse("00000000-0000-0000-0000-000000000016");
124  PrimitiveBaseShape shape = PrimitiveBaseShape.CreateCylinder();
125  Vector3 groupPosition = new Vector3(90, 80, 70);
126  Quaternion rotationOffset = new Quaternion(60, 70, 80, 90);
127  rotationOffset.Normalize();
128  Vector3 offsetPosition = new Vector3(20, 25, 30);
129 
130  return new SceneObjectPart(ownerId, shape, groupPosition, rotationOffset, offsetPosition) { Name = partName };
131  }
132 
133  private void CreateTestObjects(Scene scene, out SceneObjectGroup sog1, out SceneObjectGroup sog2, out UUID ncAssetUuid)
134  {
135  SceneObjectPart part1 = CreateSceneObjectPart1();
136  sog1 = new SceneObjectGroup(part1);
137  scene.AddNewSceneObject(sog1, false);
138 
139  AssetNotecard nc = new AssetNotecard();
140  nc.BodyText = "Hello World!";
141  nc.Encode();
142  ncAssetUuid = UUID.Random();
143  UUID ncItemUuid = UUID.Random();
144  AssetBase ncAsset
145  = AssetHelpers.CreateAsset(ncAssetUuid, AssetType.Notecard, nc.AssetData, UUID.Zero);
146  m_scene.AssetService.Store(ncAsset);
147 
148  TaskInventoryItem ncItem
149  = new TaskInventoryItem { Name = "ncItem", AssetID = ncAssetUuid, ItemID = ncItemUuid };
150  SceneObjectPart part2 = CreateSceneObjectPart2();
151  sog2 = new SceneObjectGroup(part2);
152  part2.Inventory.AddInventoryItem(ncItem, true);
153 
154  scene.AddNewSceneObject(sog2, false);
155  }
156 
157  private static void CreateSoundAsset(TarArchiveWriter tar, Assembly assembly, string soundDataResourceName, out byte[] soundData, out UUID soundUuid)
158  {
159  using (Stream resource = assembly.GetManifestResourceStream(soundDataResourceName))
160  {
161  using (BinaryReader br = new BinaryReader(resource))
162  {
163  // FIXME: Use the inspector instead
164  soundData = br.ReadBytes(99999999);
165  soundUuid = UUID.Parse("00000000-0000-0000-0000-000000000001");
166  string soundAssetFileName
167  = ArchiveConstants.ASSETS_PATH + soundUuid
168  + ArchiveConstants.ASSET_TYPE_TO_EXTENSION[(sbyte)AssetType.SoundWAV];
169  tar.WriteFile(soundAssetFileName, soundData);
170 
171  /*
172  AssetBase soundAsset = AssetHelpers.CreateAsset(soundUuid, soundData);
173  scene.AssetService.Store(soundAsset);
174  asset1FileName = ArchiveConstants.ASSETS_PATH + soundUuid + ".wav";
175  */
176  }
177  }
178  }
179 
183  [Test]
184  public void TestSaveOar()
185  {
186  TestHelpers.InMethod();
187 // log4net.Config.XmlConfigurator.Configure();
188 
189  SceneObjectGroup sog1;
190  SceneObjectGroup sog2;
191  UUID ncAssetUuid;
192  CreateTestObjects(m_scene, out sog1, out sog2, out ncAssetUuid);
193 
194  MemoryStream archiveWriteStream = new MemoryStream();
195  m_scene.EventManager.OnOarFileSaved += SaveCompleted;
196 
197  Guid requestId = new Guid("00000000-0000-0000-0000-808080808080");
198 
199  m_oarEvent.Reset();
200  m_archiverModule.ArchiveRegion(archiveWriteStream, requestId);
201  //AssetServerBase assetServer = (AssetServerBase)scene.CommsManager.AssetCache.AssetServer;
202  //while (assetServer.HasWaitingRequests())
203  // assetServer.ProcessNextRequest();
204 
205  m_oarEvent.WaitOne(60000);
206 
207  Assert.That(m_lastRequestId, Is.EqualTo(requestId));
208 
209  byte[] archive = archiveWriteStream.ToArray();
210  MemoryStream archiveReadStream = new MemoryStream(archive);
211  TarArchiveReader tar = new TarArchiveReader(archiveReadStream);
212 
213  bool gotNcAssetFile = false;
214 
215  string expectedNcAssetFileName = string.Format("{0}_{1}", ncAssetUuid, "notecard.txt");
216 
217  List<string> foundPaths = new List<string>();
218  List<string> expectedPaths = new List<string>();
219  expectedPaths.Add(ArchiveHelpers.CreateObjectPath(sog1));
220  expectedPaths.Add(ArchiveHelpers.CreateObjectPath(sog2));
221 
222  string filePath;
223  TarArchiveReader.TarEntryType tarEntryType;
224 
225  byte[] data = tar.ReadEntry(out filePath, out tarEntryType);
226  Assert.That(filePath, Is.EqualTo(ArchiveConstants.CONTROL_FILE_PATH));
227 
228  Dictionary<string, object> archiveOptions = new Dictionary<string, object>();
229  ArchiveReadRequest arr = new ArchiveReadRequest(m_scene, (Stream)null, Guid.Empty, archiveOptions);
230  arr.LoadControlFile(filePath, data, new DearchiveScenesInfo());
231 
232  Assert.That(arr.ControlFileLoaded, Is.True);
233 
234  while (tar.ReadEntry(out filePath, out tarEntryType) != null)
235  {
236  if (filePath.StartsWith(ArchiveConstants.ASSETS_PATH))
237  {
238  string fileName = filePath.Remove(0, ArchiveConstants.ASSETS_PATH.Length);
239 
240  Assert.That(fileName, Is.EqualTo(expectedNcAssetFileName));
241  gotNcAssetFile = true;
242  }
243  else if (filePath.StartsWith(ArchiveConstants.OBJECTS_PATH))
244  {
245  foundPaths.Add(filePath);
246  }
247  }
248 
249  Assert.That(gotNcAssetFile, Is.True, "No notecard asset file in archive");
250  Assert.That(foundPaths, Is.EquivalentTo(expectedPaths));
251 
252  // TODO: Test presence of more files and contents of files.
253  }
254 
258  [Test]
259  public void TestSaveOarNoAssets()
260  {
261  TestHelpers.InMethod();
262 // log4net.Config.XmlConfigurator.Configure();
263 
264  SceneObjectPart part1 = CreateSceneObjectPart1();
265  SceneObjectGroup sog1 = new SceneObjectGroup(part1);
266  m_scene.AddNewSceneObject(sog1, false);
267 
268  SceneObjectPart part2 = CreateSceneObjectPart2();
269 
270  AssetNotecard nc = new AssetNotecard();
271  nc.BodyText = "Hello World!";
272  nc.Encode();
273  UUID ncAssetUuid = new UUID("00000000-0000-0000-1000-000000000000");
274  UUID ncItemUuid = new UUID("00000000-0000-0000-1100-000000000000");
275  AssetBase ncAsset
276  = AssetHelpers.CreateAsset(ncAssetUuid, AssetType.Notecard, nc.AssetData, UUID.Zero);
277  m_scene.AssetService.Store(ncAsset);
278  SceneObjectGroup sog2 = new SceneObjectGroup(part2);
279  TaskInventoryItem ncItem
280  = new TaskInventoryItem { Name = "ncItem", AssetID = ncAssetUuid, ItemID = ncItemUuid };
281  part2.Inventory.AddInventoryItem(ncItem, true);
282 
283  m_scene.AddNewSceneObject(sog2, false);
284 
285  MemoryStream archiveWriteStream = new MemoryStream();
286 
287  Guid requestId = new Guid("00000000-0000-0000-0000-808080808080");
288 
289  Dictionary<string, Object> options = new Dictionary<string, Object>();
290  options.Add("noassets", true);
291 
292  m_archiverModule.ArchiveRegion(archiveWriteStream, requestId, options);
293 
294  // Don't wait for completion - with --noassets save oar happens synchronously
295 // Monitor.Wait(this, 60000);
296 
297  Assert.That(m_lastRequestId, Is.EqualTo(requestId));
298 
299  byte[] archive = archiveWriteStream.ToArray();
300  MemoryStream archiveReadStream = new MemoryStream(archive);
301  TarArchiveReader tar = new TarArchiveReader(archiveReadStream);
302 
303  List<string> foundPaths = new List<string>();
304  List<string> expectedPaths = new List<string>();
305  expectedPaths.Add(ArchiveHelpers.CreateObjectPath(sog1));
306  expectedPaths.Add(ArchiveHelpers.CreateObjectPath(sog2));
307 
308  string filePath;
309  TarArchiveReader.TarEntryType tarEntryType;
310 
311  byte[] data = tar.ReadEntry(out filePath, out tarEntryType);
312  Assert.That(filePath, Is.EqualTo(ArchiveConstants.CONTROL_FILE_PATH));
313 
314  Dictionary<string, object> archiveOptions = new Dictionary<string, object>();
315  ArchiveReadRequest arr = new ArchiveReadRequest(m_scene, (Stream)null, Guid.Empty, archiveOptions);
316  arr.LoadControlFile(filePath, data, new DearchiveScenesInfo());
317 
318  Assert.That(arr.ControlFileLoaded, Is.True);
319 
320  while (tar.ReadEntry(out filePath, out tarEntryType) != null)
321  {
322  if (filePath.StartsWith(ArchiveConstants.ASSETS_PATH))
323  {
324  Assert.Fail("Asset was found in saved oar of TestSaveOarNoAssets()");
325  }
326  else if (filePath.StartsWith(ArchiveConstants.OBJECTS_PATH))
327  {
328  foundPaths.Add(filePath);
329  }
330  }
331 
332  Assert.That(foundPaths, Is.EquivalentTo(expectedPaths));
333 
334  // TODO: Test presence of more files and contents of files.
335  }
336 
340  [Test]
341  public void TestLoadOar()
342  {
343  TestHelpers.InMethod();
344 // log4net.Config.XmlConfigurator.Configure();
345 
346  MemoryStream archiveWriteStream = new MemoryStream();
347  TarArchiveWriter tar = new TarArchiveWriter(archiveWriteStream);
348 
349  // Put in a random blank directory to check that this doesn't upset the load process
350  tar.WriteDir("ignoreme");
351 
352  // Also check that direct entries which will also have a file entry containing that directory doesn't
353  // upset load
354  tar.WriteDir(ArchiveConstants.TERRAINS_PATH);
355 
356  tar.WriteFile(
357  ArchiveConstants.CONTROL_FILE_PATH,
358  new ArchiveWriteRequest(m_scene, (Stream)null, Guid.Empty).CreateControlFile(new ArchiveScenesGroup()));
359  SceneObjectPart part1 = CreateSceneObjectPart1();
360 
361  part1.SitTargetOrientation = new Quaternion(0.2f, 0.3f, 0.4f, 0.5f);
362  part1.SitTargetPosition = new Vector3(1, 2, 3);
363 
364  SceneObjectGroup object1 = new SceneObjectGroup(part1);
365 
366  // Let's put some inventory items into our object
367  string soundItemName = "sound-item1";
368  UUID soundItemUuid = UUID.Parse("00000000-0000-0000-0000-000000000002");
369  Type type = GetType();
370  Assembly assembly = type.Assembly;
371  string soundDataResourceName = null;
372  string[] names = assembly.GetManifestResourceNames();
373  foreach (string name in names)
374  {
375  if (name.EndsWith(".Resources.test-sound.wav"))
376  soundDataResourceName = name;
377  }
378  Assert.That(soundDataResourceName, Is.Not.Null);
379 
380  byte[] soundData;
381  UUID soundUuid;
382  CreateSoundAsset(tar, assembly, soundDataResourceName, out soundData, out soundUuid);
383 
384  TaskInventoryItem item1
385  = new TaskInventoryItem { AssetID = soundUuid, ItemID = soundItemUuid, Name = soundItemName };
386  part1.Inventory.AddInventoryItem(item1, true);
387  m_scene.AddNewSceneObject(object1, false);
388 
389  string object1FileName = string.Format(
390  "{0}_{1:000}-{2:000}-{3:000}__{4}.xml",
391  part1.Name,
392  Math.Round(part1.GroupPosition.X), Math.Round(part1.GroupPosition.Y), Math.Round(part1.GroupPosition.Z),
393  part1.UUID);
394  tar.WriteFile(ArchiveConstants.OBJECTS_PATH + object1FileName, SceneObjectSerializer.ToXml2Format(object1));
395 
396  tar.Close();
397 
398  MemoryStream archiveReadStream = new MemoryStream(archiveWriteStream.ToArray());
399 
400  m_scene.EventManager.OnOarFileLoaded += LoadCompleted;
401  m_oarEvent.Reset();
402  m_archiverModule.DearchiveRegion(archiveReadStream);
403 
404  m_oarEvent.WaitOne(60000);
405 
406  Assert.That(m_lastErrorMessage, Is.Null);
407 
408  TestLoadedRegion(part1, soundItemName, soundData);
409  }
410 
415  [Test]
417  {
418  TestHelpers.InMethod();
419 
420  UUID ownerId = TestHelpers.ParseTail(0xaaaa);
421 
422  MemoryStream archiveWriteStream = new MemoryStream();
423  TarArchiveWriter tar = new TarArchiveWriter(archiveWriteStream);
424 
425  tar.WriteFile(
426  ArchiveConstants.CONTROL_FILE_PATH,
427  new ArchiveWriteRequest(m_scene, (Stream)null, Guid.Empty).CreateControlFile(new ArchiveScenesGroup()));
428 
429  SceneObjectGroup sog1 = SceneHelpers.CreateSceneObject(1, ownerId, "obj1-", 0x11);
430  SceneObjectPart sop2
431  = SceneHelpers.CreateSceneObjectPart("obj1-Part2", TestHelpers.ParseTail(0x12), ownerId);
432  SceneObjectPart sop3
433  = SceneHelpers.CreateSceneObjectPart("obj1-Part3", TestHelpers.ParseTail(0x13), ownerId);
434 
435  // Add the parts so they will be written out in reverse order to the oar
436  sog1.AddPart(sop3);
437  sop3.LinkNum = 3;
438  sog1.AddPart(sop2);
439  sop2.LinkNum = 2;
440 
441  tar.WriteFile(
442  ArchiveConstants.CreateOarObjectPath(sog1.Name, sog1.UUID, sog1.AbsolutePosition),
444 
445  tar.Close();
446 
447  MemoryStream archiveReadStream = new MemoryStream(archiveWriteStream.ToArray());
448 
449  m_scene.EventManager.OnOarFileLoaded += LoadCompleted;
450  m_oarEvent.Reset();
451  m_archiverModule.DearchiveRegion(archiveReadStream);
452 
453  m_oarEvent.WaitOne(60000);
454 
455  Assert.That(m_lastErrorMessage, Is.Null);
456 
457  SceneObjectPart part2 = m_scene.GetSceneObjectPart("obj1-Part2");
458  Assert.That(part2.LinkNum, Is.EqualTo(2));
459 
460  SceneObjectPart part3 = m_scene.GetSceneObjectPart("obj1-Part3");
461  Assert.That(part3.LinkNum, Is.EqualTo(3));
462  }
463 
467  [Test]
468  public void TestLoadPublishedOar()
469  {
470  TestHelpers.InMethod();
471 // log4net.Config.XmlConfigurator.Configure();
472 
473  SceneObjectPart part1 = CreateSceneObjectPart1();
474  SceneObjectGroup sog1 = new SceneObjectGroup(part1);
475  m_scene.AddNewSceneObject(sog1, false);
476 
477  SceneObjectPart part2 = CreateSceneObjectPart2();
478 
479  AssetNotecard nc = new AssetNotecard();
480  nc.BodyText = "Hello World!";
481  nc.Encode();
482  UUID ncAssetUuid = new UUID("00000000-0000-0000-1000-000000000000");
483  UUID ncItemUuid = new UUID("00000000-0000-0000-1100-000000000000");
484  AssetBase ncAsset
485  = AssetHelpers.CreateAsset(ncAssetUuid, AssetType.Notecard, nc.AssetData, UUID.Zero);
486  m_scene.AssetService.Store(ncAsset);
487  SceneObjectGroup sog2 = new SceneObjectGroup(part2);
488  TaskInventoryItem ncItem
489  = new TaskInventoryItem { Name = "ncItem", AssetID = ncAssetUuid, ItemID = ncItemUuid };
490  part2.Inventory.AddInventoryItem(ncItem, true);
491 
492  m_scene.AddNewSceneObject(sog2, false);
493 
494  MemoryStream archiveWriteStream = new MemoryStream();
495  m_scene.EventManager.OnOarFileSaved += SaveCompleted;
496 
497  Guid requestId = new Guid("00000000-0000-0000-0000-808080808080");
498 
499  m_oarEvent.Reset();
500  m_archiverModule.ArchiveRegion(
501  archiveWriteStream, requestId, new Dictionary<string, Object>() { { "wipe-owners", Boolean.TrueString } });
502 
503  m_oarEvent.WaitOne(60000);
504 
505  Assert.That(m_lastRequestId, Is.EqualTo(requestId));
506 
507  byte[] archive = archiveWriteStream.ToArray();
508  MemoryStream archiveReadStream = new MemoryStream(archive);
509 
510  {
511  UUID estateOwner = TestHelpers.ParseTail(0x4747);
512  UUID objectOwner = TestHelpers.ParseTail(0x15);
513 
514  // Reload to new scene
515  ArchiverModule archiverModule = new ArchiverModule();
516  SerialiserModule serialiserModule = new SerialiserModule();
517  TerrainModule terrainModule = new TerrainModule();
518 
519  SceneHelpers m_sceneHelpers2 = new SceneHelpers();
520  TestScene scene2 = m_sceneHelpers2.SetupScene();
521  SceneHelpers.SetupSceneModules(scene2, archiverModule, serialiserModule, terrainModule);
522 
523  // Make sure there's a valid owner for the owner we saved (this should have been wiped if the code is
524  // behaving correctly
525  UserAccountHelpers.CreateUserWithInventory(scene2, objectOwner);
526 
527  scene2.RegionInfo.EstateSettings.EstateOwner = estateOwner;
528 
529  scene2.EventManager.OnOarFileLoaded += LoadCompleted;
530  m_oarEvent.Reset();
531  archiverModule.DearchiveRegion(archiveReadStream);
532 
533  m_oarEvent.WaitOne(60000);
534 
535  Assert.That(m_lastErrorMessage, Is.Null);
536 
537  SceneObjectGroup loadedSog = scene2.GetSceneObjectGroup(part1.Name);
538  Assert.That(loadedSog.OwnerID, Is.EqualTo(estateOwner));
539  Assert.That(loadedSog.LastOwnerID, Is.EqualTo(estateOwner));
540  }
541  }
542 
549  [Test]
550  public void TestLoadOarDeededLand()
551  {
552  TestHelpers.InMethod();
553 // TestHelpers.EnableLogging();
554 
555  UUID landID = TestHelpers.ParseTail(0x10);
556 
558 
559  IConfigSource configSource = new IniConfigSource();
560  IConfig config = configSource.AddConfig("Groups");
561  config.Set("Enabled", true);
562  config.Set("Module", "GroupsModule");
563  config.Set("DebugEnabled", true);
564  SceneHelpers.SetupSceneModules(
565  m_scene, configSource, new object[] { new GroupsModule(), groupsService, new LandManagementModule() });
566 
567  // Create group in scene for loading
568  // FIXME: For now we'll put up with the issue that we'll get a group ID that varies across tests.
569  UUID groupID
570  = groupsService.CreateGroup(UUID.Zero, "group1", "", true, UUID.Zero, 3, true, true, true, UUID.Zero);
571 
572  // Construct OAR
573  MemoryStream oarStream = new MemoryStream();
574  TarArchiveWriter tar = new TarArchiveWriter(oarStream);
575 
576  tar.WriteDir(ArchiveConstants.LANDDATA_PATH);
577  tar.WriteFile(
578  ArchiveConstants.CONTROL_FILE_PATH,
579  new ArchiveWriteRequest(m_scene, (Stream)null, Guid.Empty).CreateControlFile(new ArchiveScenesGroup()));
580 
581  LandObject lo = new LandObject(groupID, true, m_scene);
582  lo.SetLandBitmap(lo.BasicFullRegionLandBitmap());
583  LandData ld = lo.LandData;
584  ld.GlobalID = landID;
585 
586  string ldPath = ArchiveConstants.CreateOarLandDataPath(ld);
587  Dictionary<string, object> options = new Dictionary<string, object>();
588  tar.WriteFile(ldPath, LandDataSerializer.Serialize(ld, options));
589  tar.Close();
590 
591  oarStream = new MemoryStream(oarStream.ToArray());
592 
593  // Load OAR
594  m_scene.EventManager.OnOarFileLoaded += LoadCompleted;
595  m_oarEvent.Reset();
596  m_archiverModule.DearchiveRegion(oarStream);
597 
598  m_oarEvent.WaitOne(60000);
599 
600  ILandObject rLo = m_scene.LandChannel.GetLandObject(16, 16);
601  LandData rLd = rLo.LandData;
602 
603  Assert.That(rLd.GlobalID, Is.EqualTo(landID));
604  Assert.That(rLd.OwnerID, Is.EqualTo(groupID));
605  Assert.That(rLd.GroupID, Is.EqualTo(groupID));
606  Assert.That(rLd.IsGroupOwned, Is.EqualTo(true));
607  }
608 
612  [Test]
614  {
615  TestHelpers.InMethod();
616  //log4net.Config.XmlConfigurator.Configure();
617 
618  MemoryStream archiveWriteStream = new MemoryStream();
619  TarArchiveWriter tar = new TarArchiveWriter(archiveWriteStream);
620 
621  tar.WriteDir(ArchiveConstants.TERRAINS_PATH);
622  tar.WriteFile(
623  ArchiveConstants.CONTROL_FILE_PATH,
624  new ArchiveWriteRequest(m_scene, (Stream)null, Guid.Empty).CreateControlFile(new ArchiveScenesGroup()));
625 
626  RegionSettings rs = new RegionSettings();
627  rs.AgentLimit = 17;
628  rs.AllowDamage = true;
629  rs.AllowLandJoinDivide = true;
630  rs.AllowLandResell = true;
631  rs.BlockFly = true;
632  rs.BlockShowInSearch = true;
633  rs.BlockTerraform = true;
634  rs.DisableCollisions = true;
635  rs.DisablePhysics = true;
636  rs.DisableScripts = true;
637  rs.Elevation1NW = 15.9;
638  rs.Elevation1NE = 45.3;
639  rs.Elevation1SE = 49;
640  rs.Elevation1SW = 1.9;
641  rs.Elevation2NW = 4.5;
642  rs.Elevation2NE = 19.2;
643  rs.Elevation2SE = 9.2;
644  rs.Elevation2SW = 2.1;
645  rs.FixedSun = true;
646  rs.SunPosition = 12.0;
647  rs.ObjectBonus = 1.4;
648  rs.RestrictPushing = true;
649  rs.TerrainLowerLimit = 0.4;
650  rs.TerrainRaiseLimit = 17.9;
651  rs.TerrainTexture1 = UUID.Parse("00000000-0000-0000-0000-000000000020");
652  rs.TerrainTexture2 = UUID.Parse("00000000-0000-0000-0000-000000000040");
653  rs.TerrainTexture3 = UUID.Parse("00000000-0000-0000-0000-000000000060");
654  rs.TerrainTexture4 = UUID.Parse("00000000-0000-0000-0000-000000000080");
655  rs.UseEstateSun = true;
656  rs.WaterHeight = 23;
657  rs.TelehubObject = UUID.Parse("00000000-0000-0000-0000-111111111111");
658  rs.AddSpawnPoint(SpawnPoint.Parse("1,-2,0.33"));
659 
660  tar.WriteFile(ArchiveConstants.SETTINGS_PATH + "region1.xml", RegionSettingsSerializer.Serialize(rs));
661 
662  tar.Close();
663 
664  MemoryStream archiveReadStream = new MemoryStream(archiveWriteStream.ToArray());
665 
666  m_scene.EventManager.OnOarFileLoaded += LoadCompleted;
667  m_oarEvent.Reset();
668  m_archiverModule.DearchiveRegion(archiveReadStream);
669 
670  m_oarEvent.WaitOne(60000);
671 
672  Assert.That(m_lastErrorMessage, Is.Null);
674 
675  Assert.That(loadedRs.AgentLimit, Is.EqualTo(17));
676  Assert.That(loadedRs.AllowDamage, Is.True);
677  Assert.That(loadedRs.AllowLandJoinDivide, Is.True);
678  Assert.That(loadedRs.AllowLandResell, Is.True);
679  Assert.That(loadedRs.BlockFly, Is.True);
680  Assert.That(loadedRs.BlockShowInSearch, Is.True);
681  Assert.That(loadedRs.BlockTerraform, Is.True);
682  Assert.That(loadedRs.DisableCollisions, Is.True);
683  Assert.That(loadedRs.DisablePhysics, Is.True);
684  Assert.That(loadedRs.DisableScripts, Is.True);
685  Assert.That(loadedRs.Elevation1NW, Is.EqualTo(15.9));
686  Assert.That(loadedRs.Elevation1NE, Is.EqualTo(45.3));
687  Assert.That(loadedRs.Elevation1SE, Is.EqualTo(49));
688  Assert.That(loadedRs.Elevation1SW, Is.EqualTo(1.9));
689  Assert.That(loadedRs.Elevation2NW, Is.EqualTo(4.5));
690  Assert.That(loadedRs.Elevation2NE, Is.EqualTo(19.2));
691  Assert.That(loadedRs.Elevation2SE, Is.EqualTo(9.2));
692  Assert.That(loadedRs.Elevation2SW, Is.EqualTo(2.1));
693  Assert.That(loadedRs.FixedSun, Is.True);
694  Assert.AreEqual(12.0, loadedRs.SunPosition);
695  Assert.That(loadedRs.ObjectBonus, Is.EqualTo(1.4));
696  Assert.That(loadedRs.RestrictPushing, Is.True);
697  Assert.That(loadedRs.TerrainLowerLimit, Is.EqualTo(0.4));
698  Assert.That(loadedRs.TerrainRaiseLimit, Is.EqualTo(17.9));
699  Assert.That(loadedRs.TerrainTexture1, Is.EqualTo(UUID.Parse("00000000-0000-0000-0000-000000000020")));
700  Assert.That(loadedRs.TerrainTexture2, Is.EqualTo(UUID.Parse("00000000-0000-0000-0000-000000000040")));
701  Assert.That(loadedRs.TerrainTexture3, Is.EqualTo(UUID.Parse("00000000-0000-0000-0000-000000000060")));
702  Assert.That(loadedRs.TerrainTexture4, Is.EqualTo(UUID.Parse("00000000-0000-0000-0000-000000000080")));
703  Assert.That(loadedRs.UseEstateSun, Is.True);
704  Assert.That(loadedRs.WaterHeight, Is.EqualTo(23));
705  Assert.AreEqual(UUID.Zero, loadedRs.TelehubObject); // because no object was found with the original UUID
706  Assert.AreEqual(0, loadedRs.SpawnPoints().Count);
707  }
708 
712  //[Test]
713  public void TestMergeOar()
714  {
715  TestHelpers.InMethod();
716  //XmlConfigurator.Configure();
717 
718  MemoryStream archiveWriteStream = new MemoryStream();
719 
720 // string part2Name = "objectMerge";
721 // PrimitiveBaseShape part2Shape = PrimitiveBaseShape.CreateCylinder();
722 // Vector3 part2GroupPosition = new Vector3(90, 80, 70);
723 // Quaternion part2RotationOffset = new Quaternion(60, 70, 80, 90);
724 // Vector3 part2OffsetPosition = new Vector3(20, 25, 30);
725 
726  SceneObjectPart part2 = CreateSceneObjectPart2();
727 
728  // Create an oar file that we can use for the merge
729  {
730  ArchiverModule archiverModule = new ArchiverModule();
731  SerialiserModule serialiserModule = new SerialiserModule();
732  TerrainModule terrainModule = new TerrainModule();
733 
734  Scene scene = m_sceneHelpers.SetupScene();
735  SceneHelpers.SetupSceneModules(scene, archiverModule, serialiserModule, terrainModule);
736 
737  m_scene.AddNewSceneObject(new SceneObjectGroup(part2), false);
738 
739  // Write out this scene
740 
741  scene.EventManager.OnOarFileSaved += SaveCompleted;
742  m_oarEvent.Reset();
743  m_archiverModule.ArchiveRegion(archiveWriteStream);
744 
745  m_oarEvent.WaitOne(60000);
746  }
747 
748  {
749  SceneObjectPart part1 = CreateSceneObjectPart1();
750  m_scene.AddNewSceneObject(new SceneObjectGroup(part1), false);
751 
752  // Merge in the archive we created earlier
753  byte[] archive = archiveWriteStream.ToArray();
754  MemoryStream archiveReadStream = new MemoryStream(archive);
755 
756  m_scene.EventManager.OnOarFileLoaded += LoadCompleted;
757  Dictionary<string, object> archiveOptions = new Dictionary<string, object>();
758  archiveOptions.Add("merge", null);
759  m_oarEvent.Reset();
760  m_archiverModule.DearchiveRegion(archiveReadStream, Guid.Empty, archiveOptions);
761 
762  m_oarEvent.WaitOne(60000);
763 
764  SceneObjectPart object1Existing = m_scene.GetSceneObjectPart(part1.Name);
765  Assert.That(object1Existing, Is.Not.Null, "object1 was not present after merge");
766  Assert.That(object1Existing.Name, Is.EqualTo(part1.Name), "object1 names not identical after merge");
767  Assert.That(object1Existing.GroupPosition, Is.EqualTo(part1.GroupPosition), "object1 group position not equal after merge");
768 
769  SceneObjectPart object2PartMerged = m_scene.GetSceneObjectPart(part2.Name);
770  Assert.That(object2PartMerged, Is.Not.Null, "object2 was not present after merge");
771  Assert.That(object2PartMerged.Name, Is.EqualTo(part2.Name), "object2 names not identical after merge");
772  Assert.That(object2PartMerged.GroupPosition, Is.EqualTo(part2.GroupPosition), "object2 group position not equal after merge");
773  }
774  }
775 
779  [Test]
781  {
782  TestHelpers.InMethod();
783 
784  // Create test regions
785 
786  int WIDTH = 2;
787  int HEIGHT = 2;
788 
789  List<Scene> scenes = new List<Scene>();
790 
791  // Maps (Directory in OAR file -> scene)
792  Dictionary<string, Scene> regionPaths = new Dictionary<string, Scene>();
793 
794  // Maps (Scene -> expected object paths)
795  Dictionary<UUID, List<string>> expectedPaths = new Dictionary<UUID, List<string>>();
796 
797  // List of expected assets
798  List<UUID> expectedAssets = new List<UUID>();
799 
800  for (uint y = 0; y < HEIGHT; y++)
801  {
802  for (uint x = 0; x < WIDTH; x++)
803  {
804  Scene scene;
805  if (x == 0 && y == 0)
806  {
807  scene = m_scene; // this scene was already created in SetUp()
808  }
809  else
810  {
811  scene = m_sceneHelpers.SetupScene(string.Format("Unit test region {0}", (y * WIDTH) + x + 1), UUID.Random(), 1000 + x, 1000 + y);
812  SceneHelpers.SetupSceneModules(scene, new ArchiverModule(), m_serialiserModule, new TerrainModule());
813  }
814  scenes.Add(scene);
815 
816  string dir = String.Format("{0}_{1}_{2}", x + 1, y + 1, scene.RegionInfo.RegionName.Replace(" ", "_"));
817  regionPaths[dir] = scene;
818 
819  SceneObjectGroup sog1;
820  SceneObjectGroup sog2;
821  UUID ncAssetUuid;
822 
823  CreateTestObjects(scene, out sog1, out sog2, out ncAssetUuid);
824 
825  expectedPaths[scene.RegionInfo.RegionID] = new List<string>();
826  expectedPaths[scene.RegionInfo.RegionID].Add(ArchiveHelpers.CreateObjectPath(sog1));
827  expectedPaths[scene.RegionInfo.RegionID].Add(ArchiveHelpers.CreateObjectPath(sog2));
828 
829  expectedAssets.Add(ncAssetUuid);
830  }
831  }
832 
833  // Save OAR
834  MemoryStream archiveWriteStream = new MemoryStream();
835 
836  Guid requestId = new Guid("00000000-0000-0000-0000-808080808080");
837 
838  Dictionary<string, Object> options = new Dictionary<string, Object>();
839  options.Add("all", true);
840 
841  m_scene.EventManager.OnOarFileSaved += SaveCompleted;
842  m_oarEvent.Reset();
843  m_archiverModule.ArchiveRegion(archiveWriteStream, requestId, options);
844 
845  m_oarEvent.WaitOne(60000);
846 
847 
848  // Check that the OAR contains the expected data
849  Assert.That(m_lastRequestId, Is.EqualTo(requestId));
850 
851  byte[] archive = archiveWriteStream.ToArray();
852  MemoryStream archiveReadStream = new MemoryStream(archive);
853  TarArchiveReader tar = new TarArchiveReader(archiveReadStream);
854 
855  Dictionary<UUID, List<string>> foundPaths = new Dictionary<UUID, List<string>>();
856  List<UUID> foundAssets = new List<UUID>();
857 
858  foreach (Scene scene in scenes)
859  {
860  foundPaths[scene.RegionInfo.RegionID] = new List<string>();
861  }
862 
863  string filePath;
864  TarArchiveReader.TarEntryType tarEntryType;
865 
866  byte[] data = tar.ReadEntry(out filePath, out tarEntryType);
867  Assert.That(filePath, Is.EqualTo(ArchiveConstants.CONTROL_FILE_PATH));
868 
869  Dictionary<string, object> archiveOptions = new Dictionary<string, object>();
870  ArchiveReadRequest arr = new ArchiveReadRequest(m_scene, (Stream)null, Guid.Empty, archiveOptions);
871  arr.LoadControlFile(filePath, data, new DearchiveScenesInfo());
872 
873  Assert.That(arr.ControlFileLoaded, Is.True);
874 
875  while (tar.ReadEntry(out filePath, out tarEntryType) != null)
876  {
877  if (filePath.StartsWith(ArchiveConstants.ASSETS_PATH))
878  {
879  // Assets are shared, so this file doesn't belong to any specific region.
880  string fileName = filePath.Remove(0, ArchiveConstants.ASSETS_PATH.Length);
881  if (fileName.EndsWith("_notecard.txt"))
882  foundAssets.Add(UUID.Parse(fileName.Substring(0, fileName.Length - "_notecard.txt".Length)));
883  }
884  else
885  {
886  // This file belongs to one of the regions. Find out which one.
887  Assert.IsTrue(filePath.StartsWith(ArchiveConstants.REGIONS_PATH));
888  string[] parts = filePath.Split(new Char[] { '/' }, 3);
889  Assert.AreEqual(3, parts.Length);
890  string regionDirectory = parts[1];
891  string relativePath = parts[2];
892  Scene scene = regionPaths[regionDirectory];
893 
894  if (relativePath.StartsWith(ArchiveConstants.OBJECTS_PATH))
895  {
896  foundPaths[scene.RegionInfo.RegionID].Add(relativePath);
897  }
898  }
899  }
900 
901  Assert.AreEqual(scenes.Count, foundPaths.Count);
902  foreach (Scene scene in scenes)
903  {
904  Assert.That(foundPaths[scene.RegionInfo.RegionID], Is.EquivalentTo(expectedPaths[scene.RegionInfo.RegionID]));
905  }
906 
907  Assert.That(foundAssets, Is.EquivalentTo(expectedAssets));
908  }
909 
913  [Test]
915  {
916  TestHelpers.InMethod();
917 
918  // Create an ArchiveScenesGroup with the regions in the OAR. This is needed to generate the control file.
919 
920  int WIDTH = 2;
921  int HEIGHT = 2;
922 
923  for (uint y = 0; y < HEIGHT; y++)
924  {
925  for (uint x = 0; x < WIDTH; x++)
926  {
927  Scene scene;
928  if (x == 0 && y == 0)
929  {
930  scene = m_scene; // this scene was already created in SetUp()
931  }
932  else
933  {
934  scene = m_sceneHelpers.SetupScene(string.Format("Unit test region {0}", (y * WIDTH) + x + 1), UUID.Random(), 1000 + x, 1000 + y);
935  SceneHelpers.SetupSceneModules(scene, new ArchiverModule(), m_serialiserModule, new TerrainModule());
936  }
937  }
938  }
939 
940  ArchiveScenesGroup scenesGroup = new ArchiveScenesGroup();
941  m_sceneHelpers.SceneManager.ForEachScene(delegate(Scene scene)
942  {
943  scenesGroup.AddScene(scene);
944  });
945  scenesGroup.CalcSceneLocations();
946 
947  // Generate the OAR file
948 
949  MemoryStream archiveWriteStream = new MemoryStream();
950  TarArchiveWriter tar = new TarArchiveWriter(archiveWriteStream);
951 
952  ArchiveWriteRequest writeRequest = new ArchiveWriteRequest(m_scene, (Stream)null, Guid.Empty);
953  writeRequest.MultiRegionFormat = true;
954  tar.WriteFile(
955  ArchiveConstants.CONTROL_FILE_PATH, writeRequest.CreateControlFile(scenesGroup));
956 
957  SceneObjectPart part1 = CreateSceneObjectPart1();
958  part1.SitTargetOrientation = new Quaternion(0.2f, 0.3f, 0.4f, 0.5f);
959  part1.SitTargetPosition = new Vector3(1, 2, 3);
960 
961  SceneObjectGroup object1 = new SceneObjectGroup(part1);
962 
963  // Let's put some inventory items into our object
964  string soundItemName = "sound-item1";
965  UUID soundItemUuid = UUID.Parse("00000000-0000-0000-0000-000000000002");
966  Type type = GetType();
967  Assembly assembly = type.Assembly;
968  string soundDataResourceName = null;
969  string[] names = assembly.GetManifestResourceNames();
970  foreach (string name in names)
971  {
972  if (name.EndsWith(".Resources.test-sound.wav"))
973  soundDataResourceName = name;
974  }
975  Assert.That(soundDataResourceName, Is.Not.Null);
976 
977  byte[] soundData;
978  UUID soundUuid;
979  CreateSoundAsset(tar, assembly, soundDataResourceName, out soundData, out soundUuid);
980 
981  TaskInventoryItem item1
982  = new TaskInventoryItem { AssetID = soundUuid, ItemID = soundItemUuid, Name = soundItemName };
983  part1.Inventory.AddInventoryItem(item1, true);
984  m_scene.AddNewSceneObject(object1, false);
985 
986  string object1FileName = string.Format(
987  "{0}_{1:000}-{2:000}-{3:000}__{4}.xml",
988  part1.Name,
989  Math.Round(part1.GroupPosition.X), Math.Round(part1.GroupPosition.Y), Math.Round(part1.GroupPosition.Z),
990  part1.UUID);
991  string path = "regions/1_1_Unit_test_region/" + ArchiveConstants.OBJECTS_PATH + object1FileName;
992  tar.WriteFile(path, SceneObjectSerializer.ToXml2Format(object1));
993 
994  tar.Close();
995 
996 
997  // Delete the current objects, to test that they're loaded from the OAR and didn't
998  // just remain in the scene.
999  m_sceneHelpers.SceneManager.ForEachScene(delegate(Scene scene)
1000  {
1001  scene.DeleteAllSceneObjects();
1002  });
1003 
1004  // Create a "hole", to test that that the corresponding region isn't loaded from the OAR
1005  m_sceneHelpers.SceneManager.CloseScene(SceneManager.Instance.Scenes[1]);
1006 
1007 
1008  // Check thay the OAR file contains the expected data
1009 
1010  MemoryStream archiveReadStream = new MemoryStream(archiveWriteStream.ToArray());
1011 
1012  m_scene.EventManager.OnOarFileLoaded += LoadCompleted;
1013  m_oarEvent.Reset();
1014  m_archiverModule.DearchiveRegion(archiveReadStream);
1015 
1016  m_oarEvent.WaitOne(60000);
1017 
1018  Assert.That(m_lastErrorMessage, Is.Null);
1019 
1020  Assert.AreEqual(3, m_sceneHelpers.SceneManager.Scenes.Count);
1021 
1022  TestLoadedRegion(part1, soundItemName, soundData);
1023  }
1024 
1025  private void TestLoadedRegion(SceneObjectPart part1, string soundItemName, byte[] soundData)
1026  {
1027  SceneObjectPart object1PartLoaded = m_scene.GetSceneObjectPart(part1.Name);
1028 
1029  Assert.That(object1PartLoaded, Is.Not.Null, "object1 was not loaded");
1030  Assert.That(object1PartLoaded.Name, Is.EqualTo(part1.Name), "object1 names not identical");
1031  Assert.That(object1PartLoaded.GroupPosition, Is.EqualTo(part1.GroupPosition), "object1 group position not equal");
1032 
1033  Quaternion qtmp1 = new Quaternion (
1034  (float)Math.Round(object1PartLoaded.RotationOffset.X,5),
1035  (float)Math.Round(object1PartLoaded.RotationOffset.Y,5),
1036  (float)Math.Round(object1PartLoaded.RotationOffset.Z,5),
1037  (float)Math.Round(object1PartLoaded.RotationOffset.W,5));
1038  Quaternion qtmp2 = new Quaternion (
1039  (float)Math.Round(part1.RotationOffset.X,5),
1040  (float)Math.Round(part1.RotationOffset.Y,5),
1041  (float)Math.Round(part1.RotationOffset.Z,5),
1042  (float)Math.Round(part1.RotationOffset.W,5));
1043 
1044  Assert.That(qtmp1, Is.EqualTo(qtmp2), "object1 rotation offset not equal");
1045  Assert.That(
1046  object1PartLoaded.OffsetPosition, Is.EqualTo(part1.OffsetPosition), "object1 offset position not equal");
1047  Assert.That(object1PartLoaded.SitTargetOrientation, Is.EqualTo(part1.SitTargetOrientation));
1048  Assert.That(object1PartLoaded.SitTargetPosition, Is.EqualTo(part1.SitTargetPosition));
1049 
1050  TaskInventoryItem loadedSoundItem = object1PartLoaded.Inventory.GetInventoryItems(soundItemName)[0];
1051  Assert.That(loadedSoundItem, Is.Not.Null, "loaded sound item was null");
1052  AssetBase loadedSoundAsset = m_scene.AssetService.Get(loadedSoundItem.AssetID.ToString());
1053  Assert.That(loadedSoundAsset, Is.Not.Null, "loaded sound asset was null");
1054  Assert.That(loadedSoundAsset.Data, Is.EqualTo(soundData), "saved and loaded sound data do not match");
1055 
1056  Assert.Greater(m_scene.LandChannel.AllParcels().Count, 0, "incorrect number of parcels");
1057  }
1058  }
1059 }
Temporary code to do the bare minimum required to read a tar archive for our purposes ...
void TestLoadOar()
Test loading an OpenSim Region Archive.
A group of regions arranged in a rectangle, possibly with holes.
void TestSaveOarNoAssets()
Test saving an OpenSim Region Archive with the no assets option
Constants for the archiving module
void TestSaveMultiRegionOar()
Test saving a multi-region OAR.
void TestLoadOarRegionSettings()
Test loading the region settings of an OpenSim Region Archive.
OpenSim.Framework.Serialization.TarArchiveReader TarArchiveReader
void TestSaveOar()
Test saving an OpenSim Region Archive.
void TestLoadMultiRegionOar()
Test loading a multi-region OAR.
void TestLoadPublishedOar()
Test loading an OpenSim Region Archive saved with the –publish option.
OpenSim.Framework.RegionSettings RegionSettings
void TestLoadOarDeededLand()
Test OAR loading where the land parcel is group deeded.
A scene object group is conceptually an object in the scene. The object is constituted of SceneObject...
Represents an item in a task inventory
Temporary code to produce a tar archive in tar v7 format
OpenSim.Framework.Serialization.ArchiveConstants ArchiveConstants
Asset class. All Assets are reference by this class or a class derived from this class ...
Definition: AssetBase.cs:49
Keeps track of a specific piece of land's information
Definition: LandObject.cs:43
Details of a Parcel of land
Definition: LandData.cs:47
Helpers for setting up scenes.
Definition: SceneHelpers.cs:60
void WriteFile(string filePath, string data)
Write a file to the tar archive
Interactive OpenSim region server
Definition: OpenSim.cs:55
This module loads and saves OpenSimulator region archives
byte[] ReadEntry(out string filePath, out TarEntryType entryType)
Read the next entry in the tar file.
OpenSim.Framework.Serialization.TarArchiveWriter TarArchiveWriter
static string ToXml2Format(SceneObjectGroup sceneObject)
Serialize a scene object to the 'xml2' format.
void TestMergeOar()
Test merging an OpenSim Region Archive into an existing scene
void TestLoadOarUnorderedParts()
Test loading an OpenSim Region Archive where the scene object parts are not ordered by link number (e...