OpenSim
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Events Macros
ArchiveWriteRequest.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.IO.Compression;
32 using System.Reflection;
33 using System.Text.RegularExpressions;
34 using System.Threading;
35 using System.Xml;
36 using log4net;
37 using OpenMetaverse;
38 using OpenSim.Framework;
39 using OpenSim.Framework.Monitoring;
40 using OpenSim.Framework.Serialization;
41 using OpenSim.Region.CoreModules.World.Terrain;
42 using OpenSim.Region.Framework.Interfaces;
43 using OpenSim.Region.Framework.Scenes;
44 using Ionic.Zlib;
48 using OpenSim.Framework.Serialization.External;
50 
51 namespace OpenSim.Region.CoreModules.World.Archiver
52 {
56  public class ArchiveWriteRequest
57  {
58  private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
59 
63  public static int MIN_MAJOR_VERSION = 0;
64 
68  public static int MAX_MAJOR_VERSION = 1;
69 
73  public bool MultiRegionFormat { get; set; }
74 
78  public bool SaveAssets { get; set; }
79 
84  public string FilterContent { get; set; }
85 
86  protected Scene m_rootScene;
87  protected Stream m_saveStream;
89  protected Guid m_requestId;
90  protected Dictionary<string, object> m_options;
91 
101  public ArchiveWriteRequest(Scene scene, string savePath, Guid requestId) : this(scene, requestId)
102  {
103  try
104  {
105  m_saveStream = new GZipStream(new FileStream(savePath, FileMode.Create), CompressionMode.Compress, CompressionLevel.BestCompression);
106  }
107  catch (EntryPointNotFoundException e)
108  {
109  m_log.ErrorFormat(
110  "[ARCHIVER]: Mismatch between Mono and zlib1g library version when trying to create compression stream."
111  + "If you've manually installed Mono, have you appropriately updated zlib1g as well?");
112  m_log.ErrorFormat("{0} {1}", e.Message, e.StackTrace);
113  }
114  }
115 
122  public ArchiveWriteRequest(Scene scene, Stream saveStream, Guid requestId) : this(scene, requestId)
123  {
124  m_saveStream = saveStream;
125  }
126 
127  protected ArchiveWriteRequest(Scene scene, Guid requestId)
128  {
129  m_rootScene = scene;
130  m_requestId = requestId;
131  m_archiveWriter = null;
132 
133  MultiRegionFormat = false;
134  SaveAssets = true;
135  FilterContent = null;
136  }
137 
142  public void ArchiveRegion(Dictionary<string, object> options)
143  {
144  m_options = options;
145 
146  if (options.ContainsKey("all") && (bool)options["all"])
147  MultiRegionFormat = true;
148 
149  if (options.ContainsKey("noassets") && (bool)options["noassets"])
150  SaveAssets = false;
151 
152  Object temp;
153  if (options.TryGetValue("checkPermissions", out temp))
154  FilterContent = (string)temp;
155 
156 
157  // Find the regions to archive
158  ArchiveScenesGroup scenesGroup = new ArchiveScenesGroup();
159  if (MultiRegionFormat)
160  {
161  m_log.InfoFormat("[ARCHIVER]: Saving {0} regions", SceneManager.Instance.Scenes.Count);
162  SceneManager.Instance.ForEachScene(delegate(Scene scene)
163  {
164  scenesGroup.AddScene(scene);
165  });
166  }
167  else
168  {
169  scenesGroup.AddScene(m_rootScene);
170  }
171  scenesGroup.CalcSceneLocations();
172 
173  m_archiveWriter = new TarArchiveWriter(m_saveStream);
174 
175  try
176  {
177  // Write out control file. It should be first so that it will be found ASAP when loading the file.
178  m_archiveWriter.WriteFile(ArchiveConstants.CONTROL_FILE_PATH, CreateControlFile(scenesGroup));
179  m_log.InfoFormat("[ARCHIVER]: Added control file to archive.");
180 
181  // Archive the regions
182 
183  Dictionary<UUID, sbyte> assetUuids = new Dictionary<UUID, sbyte>();
184 
185  scenesGroup.ForEachScene(delegate(Scene scene)
186  {
187  string regionDir = MultiRegionFormat ? scenesGroup.GetRegionDir(scene.RegionInfo.RegionID) : "";
188  ArchiveOneRegion(scene, regionDir, assetUuids);
189  });
190 
191  // Archive the assets
192 
193  if (SaveAssets)
194  {
195  m_log.DebugFormat("[ARCHIVER]: Saving {0} assets", assetUuids.Count);
196 
197  // Asynchronously request all the assets required to perform this archive operation
198  AssetsRequest ar
199  = new AssetsRequest(
200  new AssetsArchiver(m_archiveWriter), assetUuids,
201  m_rootScene.AssetService, m_rootScene.UserAccountService,
202  m_rootScene.RegionInfo.ScopeID, options, ReceivedAllAssets);
203 
204  WorkManager.RunInThread(o => ar.Execute(), null, "Archive Assets Request");
205 
206  // CloseArchive() will be called from ReceivedAllAssets()
207  }
208  else
209  {
210  m_log.DebugFormat("[ARCHIVER]: Not saving assets since --noassets was specified");
211  CloseArchive(string.Empty);
212  }
213  }
214  catch (Exception e)
215  {
216  CloseArchive(e.Message);
217  throw;
218  }
219  }
220 
221  private void ArchiveOneRegion(Scene scene, string regionDir, Dictionary<UUID, sbyte> assetUuids)
222  {
223  m_log.InfoFormat("[ARCHIVER]: Writing region {0}", scene.Name);
224 
225  EntityBase[] entities = scene.GetEntities();
226  List<SceneObjectGroup> sceneObjects = new List<SceneObjectGroup>();
227 
228  int numObjectsSkippedPermissions = 0;
229 
230  // Filter entities so that we only have scene objects.
231  // FIXME: Would be nicer to have this as a proper list in SceneGraph, since lots of methods
232  // end up having to do this
233  IPermissionsModule permissionsModule = scene.RequestModuleInterface<IPermissionsModule>();
234  foreach (EntityBase entity in entities)
235  {
236  if (entity is SceneObjectGroup)
237  {
238  SceneObjectGroup sceneObject = (SceneObjectGroup)entity;
239 
240  if (!sceneObject.IsDeleted && !sceneObject.IsAttachment)
241  {
242  if (!CanUserArchiveObject(scene.RegionInfo.EstateSettings.EstateOwner, sceneObject, FilterContent, permissionsModule))
243  {
244  // The user isn't allowed to copy/transfer this object, so it will not be included in the OAR.
245  ++numObjectsSkippedPermissions;
246  }
247  else
248  {
249  sceneObjects.Add(sceneObject);
250  }
251  }
252  }
253  }
254 
255  if (SaveAssets)
256  {
257  UuidGatherer assetGatherer = new UuidGatherer(scene.AssetService, assetUuids);
258  int prevAssets = assetUuids.Count;
259 
260  foreach (SceneObjectGroup sceneObject in sceneObjects)
261  assetGatherer.AddForInspection(sceneObject);
262 
263  assetGatherer.GatherAll();
264 
265  m_log.DebugFormat(
266  "[ARCHIVER]: {0} scene objects to serialize requiring save of {1} assets",
267  sceneObjects.Count, assetUuids.Count - prevAssets);
268  }
269 
270  if (numObjectsSkippedPermissions > 0)
271  {
272  m_log.DebugFormat(
273  "[ARCHIVER]: {0} scene objects skipped due to lack of permissions",
274  numObjectsSkippedPermissions);
275  }
276 
277  // Make sure that we also request terrain texture assets
279 
281  assetUuids[regionSettings.TerrainTexture1] = (sbyte)AssetType.Texture;
282 
284  assetUuids[regionSettings.TerrainTexture2] = (sbyte)AssetType.Texture;
285 
287  assetUuids[regionSettings.TerrainTexture3] = (sbyte)AssetType.Texture;
288 
290  assetUuids[regionSettings.TerrainTexture4] = (sbyte)AssetType.Texture;
291 
292  Save(scene, sceneObjects, regionDir);
293  }
294 
303  private bool CanUserArchiveObject(UUID user, SceneObjectGroup objGroup, string filterContent, IPermissionsModule permissionsModule)
304  {
305  if (filterContent == null)
306  return true;
307 
308  if (permissionsModule == null)
309  return true; // this shouldn't happen
310 
311  // Check whether the user is permitted to export all of the parts in the SOG. If any
312  // part can't be exported then the entire SOG can't be exported.
313 
314  bool permitted = true;
315  //int primNumber = 1;
316 
317  foreach (SceneObjectPart obj in objGroup.Parts)
318  {
319  uint perm;
320  PermissionClass permissionClass = permissionsModule.GetPermissionClass(user, obj);
321  switch (permissionClass)
322  {
323  case PermissionClass.Owner:
324  perm = obj.BaseMask;
325  break;
326  case PermissionClass.Group:
327  perm = obj.GroupMask | obj.EveryoneMask;
328  break;
329  case PermissionClass.Everyone:
330  default:
331  perm = obj.EveryoneMask;
332  break;
333  }
334 
335  bool canCopy = (perm & (uint)PermissionMask.Copy) != 0;
336  bool canTransfer = (perm & (uint)PermissionMask.Transfer) != 0;
337 
338  // Special case: if Everyone can copy the object then this implies it can also be
339  // Transferred.
340  // However, if the user is the Owner then we don't check EveryoneMask, because it seems that the mask
341  // always (incorrectly) includes the Copy bit set in this case. But that's a mistake: the viewer
342  // does NOT show that the object has Everyone-Copy permissions, and doesn't allow it to be copied.
343  if (permissionClass != PermissionClass.Owner)
344  canTransfer |= (obj.EveryoneMask & (uint)PermissionMask.Copy) != 0;
345 
346  bool partPermitted = true;
347  if (filterContent.Contains("C") && !canCopy)
348  partPermitted = false;
349  if (filterContent.Contains("T") && !canTransfer)
350  partPermitted = false;
351 
352  // If the user is the Creator of the object then it can always be included in the OAR
353  bool creator = (obj.CreatorID.Guid == user.Guid);
354  if (creator)
355  partPermitted = true;
356 
357  //string name = (objGroup.PrimCount == 1) ? objGroup.Name : string.Format("{0} ({1}/{2})", obj.Name, primNumber, objGroup.PrimCount);
358  //m_log.DebugFormat("[ARCHIVER]: Object permissions: {0}: Base={1:X4}, Owner={2:X4}, Everyone={3:X4}, permissionClass={4}, checkPermissions={5}, canCopy={6}, canTransfer={7}, creator={8}, permitted={9}",
359  // name, obj.BaseMask, obj.OwnerMask, obj.EveryoneMask,
360  // permissionClass, checkPermissions, canCopy, canTransfer, creator, partPermitted);
361 
362  if (!partPermitted)
363  {
364  permitted = false;
365  break;
366  }
367 
368  //++primNumber;
369  }
370 
371  return permitted;
372  }
373 
378  public string CreateControlFile(ArchiveScenesGroup scenesGroup)
379  {
380  int majorVersion;
381  int minorVersion;
382 
383  if (MultiRegionFormat)
384  {
385  majorVersion = MAX_MAJOR_VERSION;
386  minorVersion = 0;
387  }
388  else
389  {
390  // To support older versions of OpenSim, we continue to create single-region OARs
391  // using the old file format. In the future this format will be discontinued.
392  majorVersion = 0;
393  minorVersion = 8;
394  }
395 //
396 // if (m_options.ContainsKey("version"))
397 // {
398 // string[] parts = m_options["version"].ToString().Split('.');
399 // if (parts.Length >= 1)
400 // {
401 // majorVersion = Int32.Parse(parts[0]);
402 //
403 // if (parts.Length >= 2)
404 // minorVersion = Int32.Parse(parts[1]);
405 // }
406 // }
407 //
408 // if (majorVersion < MIN_MAJOR_VERSION || majorVersion > MAX_MAJOR_VERSION)
409 // {
410 // throw new Exception(
411 // string.Format(
412 // "OAR version number for save must be between {0} and {1}",
413 // MIN_MAJOR_VERSION, MAX_MAJOR_VERSION));
414 // }
415 // else if (majorVersion == MAX_MAJOR_VERSION)
416 // {
417 // // Force 1.0
418 // minorVersion = 0;
419 // }
420 // else if (majorVersion == MIN_MAJOR_VERSION)
421 // {
422 // // Force 0.4
423 // minorVersion = 4;
424 // }
425 
426  m_log.InfoFormat("[ARCHIVER]: Creating version {0}.{1} OAR", majorVersion, minorVersion);
427  if (majorVersion == 1)
428  {
429  m_log.WarnFormat("[ARCHIVER]: Please be aware that version 1.0 OARs are not compatible with OpenSim versions prior to 0.7.4. Do not use the --all option if you want to produce a compatible OAR");
430  }
431 
432  String s;
433 
434  using (StringWriter sw = new StringWriter())
435  {
436  using (XmlTextWriter xtw = new XmlTextWriter(sw))
437  {
438  xtw.Formatting = Formatting.Indented;
439  xtw.WriteStartDocument();
440  xtw.WriteStartElement("archive");
441  xtw.WriteAttributeString("major_version", majorVersion.ToString());
442  xtw.WriteAttributeString("minor_version", minorVersion.ToString());
443 
444  xtw.WriteStartElement("creation_info");
445  DateTime now = DateTime.UtcNow;
446  TimeSpan t = now - new DateTime(1970, 1, 1);
447  xtw.WriteElementString("datetime", ((int)t.TotalSeconds).ToString());
448  if (!MultiRegionFormat)
449  xtw.WriteElementString("id", m_rootScene.RegionInfo.RegionID.ToString());
450  xtw.WriteEndElement();
451 
452  xtw.WriteElementString("assets_included", SaveAssets.ToString());
453 
454  if (MultiRegionFormat)
455  {
456  WriteRegionsManifest(scenesGroup, xtw);
457  }
458  else
459  {
460  xtw.WriteStartElement("region_info");
461  WriteRegionInfo(m_rootScene, xtw);
462  xtw.WriteEndElement();
463  }
464 
465  xtw.WriteEndElement();
466 
467  xtw.Flush();
468  }
469 
470  s = sw.ToString();
471  }
472 
473  return s;
474  }
475 
479  private static void WriteRegionsManifest(ArchiveScenesGroup scenesGroup, XmlTextWriter xtw)
480  {
481  xtw.WriteStartElement("regions");
482 
483  // Write the regions in order: rows from South to North, then regions from West to East.
484  // The list of regions can have "holes"; we write empty elements in their position.
485 
486  for (uint y = (uint)scenesGroup.Rect.Top; y < scenesGroup.Rect.Bottom; ++y)
487  {
488  SortedDictionary<uint, Scene> row;
489  if (scenesGroup.Regions.TryGetValue(y, out row))
490  {
491  xtw.WriteStartElement("row");
492 
493  for (uint x = (uint)scenesGroup.Rect.Left; x < scenesGroup.Rect.Right; ++x)
494  {
495  Scene scene;
496  if (row.TryGetValue(x, out scene))
497  {
498  xtw.WriteStartElement("region");
499  xtw.WriteElementString("id", scene.RegionInfo.RegionID.ToString());
500  xtw.WriteElementString("dir", scenesGroup.GetRegionDir(scene.RegionInfo.RegionID));
501  WriteRegionInfo(scene, xtw);
502  xtw.WriteEndElement();
503  }
504  else
505  {
506  // Write a placeholder for a missing region
507  xtw.WriteElementString("region", "");
508  }
509  }
510 
511  xtw.WriteEndElement();
512  }
513  else
514  {
515  // Write a placeholder for a missing row
516  xtw.WriteElementString("row", "");
517  }
518  }
519 
520  xtw.WriteEndElement(); // "regions"
521  }
522 
523  protected static void WriteRegionInfo(Scene scene, XmlTextWriter xtw)
524  {
525  bool isMegaregion;
526  Vector2 size;
527 
528  IRegionCombinerModule rcMod = scene.RequestModuleInterface<IRegionCombinerModule>();
529 
530  if (rcMod != null)
531  isMegaregion = rcMod.IsRootForMegaregion(scene.RegionInfo.RegionID);
532  else
533  isMegaregion = false;
534 
535  if (isMegaregion)
536  size = rcMod.GetSizeOfMegaregion(scene.RegionInfo.RegionID);
537  else
538  size = new Vector2((float)scene.RegionInfo.RegionSizeX, (float)scene.RegionInfo.RegionSizeY);
539 
540  xtw.WriteElementString("is_megaregion", isMegaregion.ToString());
541  xtw.WriteElementString("size_in_meters", string.Format("{0},{1}", size.X, size.Y));
542  }
543 
544  protected void Save(Scene scene, List<SceneObjectGroup> sceneObjects, string regionDir)
545  {
546  if (regionDir != string.Empty)
547  regionDir = ArchiveConstants.REGIONS_PATH + regionDir + "/";
548 
549  m_log.InfoFormat("[ARCHIVER]: Adding region settings to archive.");
550 
551  // Write out region settings
552  string settingsPath = String.Format("{0}{1}{2}.xml",
553  regionDir, ArchiveConstants.SETTINGS_PATH, scene.RegionInfo.RegionName);
554  m_archiveWriter.WriteFile(settingsPath, RegionSettingsSerializer.Serialize(scene.RegionInfo.RegionSettings));
555 
556  m_log.InfoFormat("[ARCHIVER]: Adding parcel settings to archive.");
557 
558  // Write out land data (aka parcel) settings
559  List<ILandObject> landObjects = scene.LandChannel.AllParcels();
560  foreach (ILandObject lo in landObjects)
561  {
562  LandData landData = lo.LandData;
563  string landDataPath
564  = String.Format("{0}{1}", regionDir, ArchiveConstants.CreateOarLandDataPath(landData));
565  m_archiveWriter.WriteFile(landDataPath, LandDataSerializer.Serialize(landData, m_options));
566  }
567 
568  m_log.InfoFormat("[ARCHIVER]: Adding terrain information to archive.");
569 
570  // Write out terrain
571  string terrainPath = String.Format("{0}{1}{2}.r32",
572  regionDir, ArchiveConstants.TERRAINS_PATH, scene.RegionInfo.RegionName);
573 
574  using (MemoryStream ms = new MemoryStream())
575  {
576  scene.RequestModuleInterface<ITerrainModule>().SaveToStream(terrainPath, ms);
577  m_archiveWriter.WriteFile(terrainPath, ms.ToArray());
578  }
579 
580  m_log.InfoFormat("[ARCHIVER]: Adding scene objects to archive.");
581 
582  // Write out scene object metadata
583  IRegionSerialiserModule serializer = scene.RequestModuleInterface<IRegionSerialiserModule>();
584  foreach (SceneObjectGroup sceneObject in sceneObjects)
585  {
586  //m_log.DebugFormat("[ARCHIVER]: Saving {0} {1}, {2}", entity.Name, entity.UUID, entity.GetType());
587 
588  string serializedObject = serializer.SerializeGroupToXml2(sceneObject, m_options);
589  string objectPath = string.Format("{0}{1}", regionDir, ArchiveHelpers.CreateObjectPath(sceneObject));
590  m_archiveWriter.WriteFile(objectPath, serializedObject);
591  }
592  }
593 
594  protected void ReceivedAllAssets(ICollection<UUID> assetsFoundUuids, ICollection<UUID> assetsNotFoundUuids, bool timedOut)
595  {
596  string errorMessage;
597 
598  if (timedOut)
599  {
600  errorMessage = "Loading assets timed out";
601  }
602  else
603  {
604  foreach (UUID uuid in assetsNotFoundUuids)
605  {
606  m_log.DebugFormat("[ARCHIVER]: Could not find asset {0}", uuid);
607  }
608 
609  // m_log.InfoFormat(
610  // "[ARCHIVER]: Received {0} of {1} assets requested",
611  // assetsFoundUuids.Count, assetsFoundUuids.Count + assetsNotFoundUuids.Count);
612 
613  errorMessage = String.Empty;
614  }
615 
616  CloseArchive(errorMessage);
617  }
618 
623  protected void CloseArchive(string errorMessage)
624  {
625  try
626  {
627  if (m_archiveWriter != null)
628  m_archiveWriter.Close();
629  m_saveStream.Close();
630  }
631  catch (Exception e)
632  {
633  m_log.Error(string.Format("[ARCHIVER]: Error closing archive: {0} ", e.Message), e);
634  if (errorMessage == string.Empty)
635  errorMessage = e.Message;
636  }
637 
638  m_log.InfoFormat("[ARCHIVER]: Finished writing out OAR for {0}", m_rootScene.RegionInfo.RegionName);
639 
640  m_rootScene.EventManager.TriggerOarFileSaved(m_requestId, errorMessage);
641  }
642  }
643 }
Ionic.Zlib.CompressionMode CompressionMode
Gather uuids for a given entity.
Definition: UuidGatherer.cs:54
EstateSettings EstateSettings
Definition: RegionInfo.cs:275
Ionic.Zlib.GZipStream GZipStream
void Save(Scene scene, List< SceneObjectGroup > sceneObjects, string regionDir)
A group of regions arranged in a rectangle, possibly with holes.
uint RegionSizeX
X dimension of the region.
Definition: RegionInfo.cs:161
uint RegionSizeY
X dimension of the region.
Definition: RegionInfo.cs:169
OpenSim.Framework.RegionSettings RegionSettings
A scene object group is conceptually an object in the scene. The object is constituted of SceneObject...
OpenSim.Framework.PermissionMask PermissionMask
Ionic.Zlib.GZipStream GZipStream
Temporary code to produce a tar archive in tar v7 format
static readonly UUID DEFAULT_TERRAIN_TEXTURE_2
bool IsDeleted
Signals whether this entity was in a scene but has since been removed from it.
Definition: EntityBase.cs:73
Encapsulate the asynchronous requests for the assets required for an archive operation ...
static readonly UUID DEFAULT_TERRAIN_TEXTURE_1
Details of a Parcel of land
Definition: LandData.cs:47
SortedDictionary< uint, SortedDictionary< uint, Scene > > Regions
All the regions. The outer dictionary contains rows (key: Y coordinate). The inner dictionaries conta...
void ReceivedAllAssets(ICollection< UUID > assetsFoundUuids, ICollection< UUID > assetsNotFoundUuids, bool timedOut)
Ionic.Zlib.CompressionLevel CompressionLevel
static void WriteRegionInfo(Scene scene, XmlTextWriter xtw)
ArchiveWriteRequest(Scene scene, Stream saveStream, Guid requestId)
Constructor.
Ionic.Zlib.CompressionLevel CompressionLevel
Ionic.Zlib.CompressionMode CompressionMode
void CloseArchive(string errorMessage)
Closes the archive and notifies that we're done.
ArchiveWriteRequest(Scene scene, string savePath, Guid requestId)
Constructor
OpenSim.Framework.Serialization.TarArchiveWriter TarArchiveWriter
string CreateControlFile(ArchiveScenesGroup scenesGroup)
Create the control file.
void ArchiveRegion(Dictionary< string, object > options)
Archive the region requested.
static readonly UUID DEFAULT_TERRAIN_TEXTURE_4
bool IsAttachment
Is this scene object acting as an attachment?
static readonly UUID DEFAULT_TERRAIN_TEXTURE_3