aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/CoreModules/World/Archiver/ArchiveWriteRequestPreparation.cs
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Region/CoreModules/World/Archiver/ArchiveWriteRequestPreparation.cs')
-rw-r--r--OpenSim/Region/CoreModules/World/Archiver/ArchiveWriteRequestPreparation.cs492
1 files changed, 344 insertions, 148 deletions
diff --git a/OpenSim/Region/CoreModules/World/Archiver/ArchiveWriteRequestPreparation.cs b/OpenSim/Region/CoreModules/World/Archiver/ArchiveWriteRequestPreparation.cs
index 4edaaca..2c34f4b 100644
--- a/OpenSim/Region/CoreModules/World/Archiver/ArchiveWriteRequestPreparation.cs
+++ b/OpenSim/Region/CoreModules/World/Archiver/ArchiveWriteRequestPreparation.cs
@@ -43,6 +43,7 @@ using OpenSim.Region.Framework.Scenes;
43using Ionic.Zlib; 43using Ionic.Zlib;
44using GZipStream = Ionic.Zlib.GZipStream; 44using GZipStream = Ionic.Zlib.GZipStream;
45using CompressionMode = Ionic.Zlib.CompressionMode; 45using CompressionMode = Ionic.Zlib.CompressionMode;
46using OpenSim.Framework.Serialization.External;
46 47
47namespace OpenSim.Region.CoreModules.World.Archiver 48namespace OpenSim.Region.CoreModules.World.Archiver
48{ 49{
@@ -61,17 +62,29 @@ namespace OpenSim.Region.CoreModules.World.Archiver
61 /// <summary> 62 /// <summary>
62 /// The maximum major version of OAR that we can write. 63 /// The maximum major version of OAR that we can write.
63 /// </summary> 64 /// </summary>
64 public static int MAX_MAJOR_VERSION = 0; 65 public static int MAX_MAJOR_VERSION = 1;
66
67 /// <summary>
68 /// Whether we're saving a multi-region archive.
69 /// </summary>
70 public bool MultiRegionFormat { get; set; }
65 71
66 /// <summary> 72 /// <summary>
67 /// Determine whether this archive will save assets. Default is true. 73 /// Determine whether this archive will save assets. Default is true.
68 /// </summary> 74 /// </summary>
69 public bool SaveAssets { get; set; } 75 public bool SaveAssets { get; set; }
70 76
71 protected ArchiverModule m_module; 77 /// <summary>
72 protected Scene m_scene; 78 /// Determines which objects will be included in the archive, according to their permissions.
79 /// Default is null, meaning no permission checks.
80 /// </summary>
81 public string CheckPermissions { get; set; }
82
83 protected Scene m_rootScene;
73 protected Stream m_saveStream; 84 protected Stream m_saveStream;
85 protected TarArchiveWriter m_archiveWriter;
74 protected Guid m_requestId; 86 protected Guid m_requestId;
87 protected Dictionary<string, object> m_options;
75 88
76 /// <summary> 89 /// <summary>
77 /// Constructor 90 /// Constructor
@@ -82,7 +95,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver
82 /// <exception cref="System.IO.IOException"> 95 /// <exception cref="System.IO.IOException">
83 /// If there was a problem opening a stream for the file specified by the savePath 96 /// If there was a problem opening a stream for the file specified by the savePath
84 /// </exception> 97 /// </exception>
85 public ArchiveWriteRequestPreparation(ArchiverModule module, string savePath, Guid requestId) : this(module, requestId) 98 public ArchiveWriteRequestPreparation(Scene scene, string savePath, Guid requestId) : this(scene, requestId)
86 { 99 {
87 try 100 try
88 { 101 {
@@ -100,26 +113,23 @@ namespace OpenSim.Region.CoreModules.World.Archiver
100 /// <summary> 113 /// <summary>
101 /// Constructor. 114 /// Constructor.
102 /// </summary> 115 /// </summary>
103 /// <param name="module">Calling module</param> 116 /// <param name="scene">The root scene to archive</param>
104 /// <param name="saveStream">The stream to which to save data.</param> 117 /// <param name="saveStream">The stream to which to save data.</param>
105 /// <param name="requestId">The id associated with this request</param> 118 /// <param name="requestId">The id associated with this request</param>
106 public ArchiveWriteRequestPreparation(ArchiverModule module, Stream saveStream, Guid requestId) : this(module, requestId) 119 public ArchiveWriteRequestPreparation(Scene scene, Stream saveStream, Guid requestId) : this(scene, requestId)
107 { 120 {
108 m_saveStream = saveStream; 121 m_saveStream = saveStream;
109 } 122 }
110 123
111 protected ArchiveWriteRequestPreparation(ArchiverModule module, Guid requestId) 124 protected ArchiveWriteRequestPreparation(Scene scene, Guid requestId)
112 { 125 {
113 m_module = module; 126 m_rootScene = scene;
114
115 // FIXME: This is only here for regression test purposes since they do not supply a module. Need to fix
116 // this.
117 if (m_module != null)
118 m_scene = m_module.Scene;
119
120 m_requestId = requestId; 127 m_requestId = requestId;
128 m_archiveWriter = null;
121 129
130 MultiRegionFormat = false;
122 SaveAssets = true; 131 SaveAssets = true;
132 CheckPermissions = null;
123 } 133 }
124 134
125 /// <summary> 135 /// <summary>
@@ -128,126 +138,157 @@ namespace OpenSim.Region.CoreModules.World.Archiver
128 /// <exception cref="System.IO.IOException">if there was an io problem with creating the file</exception> 138 /// <exception cref="System.IO.IOException">if there was an io problem with creating the file</exception>
129 public void ArchiveRegion(Dictionary<string, object> options) 139 public void ArchiveRegion(Dictionary<string, object> options)
130 { 140 {
141 m_options = options;
142
143 if (options.ContainsKey("all") && (bool)options["all"])
144 MultiRegionFormat = true;
145
131 if (options.ContainsKey("noassets") && (bool)options["noassets"]) 146 if (options.ContainsKey("noassets") && (bool)options["noassets"])
132 SaveAssets = false; 147 SaveAssets = false;
133 148
149 Object temp;
150 if (options.TryGetValue("checkPermissions", out temp))
151 CheckPermissions = (string)temp;
152
153
154 // Find the regions to archive
155 ArchiveScenesGroup scenesGroup = new ArchiveScenesGroup();
156 if (MultiRegionFormat)
157 {
158 m_log.InfoFormat("[ARCHIVER]: Saving {0} regions", SceneManager.Instance.Scenes.Count);
159 SceneManager.Instance.ForEachScene(delegate(Scene scene)
160 {
161 scenesGroup.AddScene(scene);
162 });
163 }
164 else
165 {
166 scenesGroup.AddScene(m_rootScene);
167 }
168 scenesGroup.CalcSceneLocations();
169
170
171 m_archiveWriter = new TarArchiveWriter(m_saveStream);
172
134 try 173 try
135 { 174 {
175 // Write out control file. It should be first so that it will be found ASAP when loading the file.
176 m_archiveWriter.WriteFile(ArchiveConstants.CONTROL_FILE_PATH, CreateControlFile(scenesGroup));
177 m_log.InfoFormat("[ARCHIVER]: Added control file to archive.");
178
179 // Archive the regions
180
136 Dictionary<UUID, AssetType> assetUuids = new Dictionary<UUID, AssetType>(); 181 Dictionary<UUID, AssetType> assetUuids = new Dictionary<UUID, AssetType>();
137 182
138 EntityBase[] entities = m_scene.GetEntities(); 183 scenesGroup.ForEachScene(delegate(Scene scene)
139 List<SceneObjectGroup> sceneObjects = new List<SceneObjectGroup>();
140
141 string checkPermissions = null;
142 int numObjectsSkippedPermissions = 0;
143 Object temp;
144 if (options.TryGetValue("checkPermissions", out temp))
145 checkPermissions = (string)temp;
146
147 // Filter entities so that we only have scene objects.
148 // FIXME: Would be nicer to have this as a proper list in SceneGraph, since lots of methods
149 // end up having to do this
150 foreach (EntityBase entity in entities)
151 { 184 {
152 if (entity is SceneObjectGroup) 185 string regionDir = MultiRegionFormat ? scenesGroup.GetRegionDir(scene.RegionInfo.RegionID) : "";
153 { 186 ArchiveOneRegion(scene, regionDir, assetUuids);
154 SceneObjectGroup sceneObject = (SceneObjectGroup)entity; 187 });
155 188
156 if (!sceneObject.IsDeleted && !sceneObject.IsAttachment) 189 // Archive the assets
157 {
158 if (!CanUserArchiveObject(m_scene.RegionInfo.EstateSettings.EstateOwner, sceneObject, checkPermissions))
159 {
160 // The user isn't allowed to copy/transfer this object, so it will not be included in the OAR.
161 ++numObjectsSkippedPermissions;
162 }
163 else
164 {
165 sceneObjects.Add(sceneObject);
166 }
167 }
168 }
169 }
170 190
171 if (SaveAssets) 191 if (SaveAssets)
172 { 192 {
173 UuidGatherer assetGatherer = new UuidGatherer(m_scene.AssetService); 193 m_log.DebugFormat("[ARCHIVER]: Saving {0} assets", assetUuids.Count);
174 194
175 foreach (SceneObjectGroup sceneObject in sceneObjects) 195 // Asynchronously request all the assets required to perform this archive operation
176 { 196 AssetsRequest ar
177 assetGatherer.GatherAssetUuids(sceneObject, assetUuids); 197 = new AssetsRequest(
178 } 198 new AssetsArchiver(m_archiveWriter), assetUuids,
199 m_rootScene.AssetService, m_rootScene.UserAccountService,
200 m_rootScene.RegionInfo.ScopeID, options, ReceivedAllAssets);
179 201
180 m_log.DebugFormat( 202 Util.FireAndForget(o => ar.Execute());
181 "[ARCHIVER]: {0} scene objects to serialize requiring save of {1} assets", 203
182 sceneObjects.Count, assetUuids.Count); 204 // CloseArchive() will be called from ReceivedAllAssets()
183 } 205 }
184 else 206 else
185 { 207 {
186 m_log.DebugFormat("[ARCHIVER]: Not saving assets since --noassets was specified"); 208 m_log.DebugFormat("[ARCHIVER]: Not saving assets since --noassets was specified");
209 CloseArchive(string.Empty);
187 } 210 }
211 }
212 catch (Exception e)
213 {
214 CloseArchive(e.Message);
215 throw;
216 }
217 }
188 218
189 if (numObjectsSkippedPermissions > 0)
190 {
191 m_log.DebugFormat(
192 "[ARCHIVER]: {0} scene objects skipped due to lack of permissions",
193 numObjectsSkippedPermissions);
194 }
195 219
196 // Make sure that we also request terrain texture assets 220 private void ArchiveOneRegion(Scene scene, string regionDir, Dictionary<UUID, AssetType> assetUuids)
197 RegionSettings regionSettings = m_scene.RegionInfo.RegionSettings; 221 {
198 222 m_log.InfoFormat("[ARCHIVER]: Writing region {0}", scene.RegionInfo.RegionName);
199 if (regionSettings.TerrainTexture1 != RegionSettings.DEFAULT_TERRAIN_TEXTURE_1)
200 assetUuids[regionSettings.TerrainTexture1] = AssetType.Texture;
201
202 if (regionSettings.TerrainTexture2 != RegionSettings.DEFAULT_TERRAIN_TEXTURE_2)
203 assetUuids[regionSettings.TerrainTexture2] = AssetType.Texture;
204
205 if (regionSettings.TerrainTexture3 != RegionSettings.DEFAULT_TERRAIN_TEXTURE_3)
206 assetUuids[regionSettings.TerrainTexture3] = AssetType.Texture;
207
208 if (regionSettings.TerrainTexture4 != RegionSettings.DEFAULT_TERRAIN_TEXTURE_4)
209 assetUuids[regionSettings.TerrainTexture4] = AssetType.Texture;
210
211 TarArchiveWriter archiveWriter = new TarArchiveWriter(m_saveStream);
212
213 // Asynchronously request all the assets required to perform this archive operation
214 ArchiveWriteRequestExecution awre
215 = new ArchiveWriteRequestExecution(
216 sceneObjects,
217 m_scene.RequestModuleInterface<ITerrainModule>(),
218 m_scene.RequestModuleInterface<IRegionSerialiserModule>(),
219 m_scene,
220 archiveWriter,
221 m_requestId,
222 options);
223
224 m_log.InfoFormat("[ARCHIVER]: Creating archive file. This may take some time.");
225
226 // Write out control file. This has to be done first so that subsequent loaders will see this file first
227 // XXX: I know this is a weak way of doing it since external non-OAR aware tar executables will not do this
228 archiveWriter.WriteFile(ArchiveConstants.CONTROL_FILE_PATH, CreateControlFile(options));
229 m_log.InfoFormat("[ARCHIVER]: Added control file to archive.");
230 223
231 if (SaveAssets) 224 EntityBase[] entities = scene.GetEntities();
225 List<SceneObjectGroup> sceneObjects = new List<SceneObjectGroup>();
226
227 int numObjectsSkippedPermissions = 0;
228
229 // Filter entities so that we only have scene objects.
230 // FIXME: Would be nicer to have this as a proper list in SceneGraph, since lots of methods
231 // end up having to do this
232 IPermissionsModule permissionsModule = scene.RequestModuleInterface<IPermissionsModule>();
233 foreach (EntityBase entity in entities)
234 {
235 if (entity is SceneObjectGroup)
232 { 236 {
233 AssetsRequest ar 237 SceneObjectGroup sceneObject = (SceneObjectGroup)entity;
234 = new AssetsRequest(
235 new AssetsArchiver(archiveWriter), assetUuids,
236 m_scene.AssetService, m_scene.UserAccountService,
237 m_scene.RegionInfo.ScopeID, options, awre.ReceivedAllAssets);
238 238
239 Util.FireAndForget(o => ar.Execute()); 239 if (!sceneObject.IsDeleted && !sceneObject.IsAttachment)
240 {
241 if (!CanUserArchiveObject(scene.RegionInfo.EstateSettings.EstateOwner, sceneObject, CheckPermissions, permissionsModule))
242 {
243 // The user isn't allowed to copy/transfer this object, so it will not be included in the OAR.
244 ++numObjectsSkippedPermissions;
245 }
246 else
247 {
248 sceneObjects.Add(sceneObject);
249 }
250 }
240 } 251 }
241 else 252 }
253
254 if (SaveAssets)
255 {
256 UuidGatherer assetGatherer = new UuidGatherer(scene.AssetService);
257 int prevAssets = assetUuids.Count;
258
259 foreach (SceneObjectGroup sceneObject in sceneObjects)
242 { 260 {
243 awre.ReceivedAllAssets(new List<UUID>(), new List<UUID>()); 261 assetGatherer.GatherAssetUuids(sceneObject, assetUuids);
244 } 262 }
263
264 m_log.DebugFormat(
265 "[ARCHIVER]: {0} scene objects to serialize requiring save of {1} assets",
266 sceneObjects.Count, assetUuids.Count - prevAssets);
245 } 267 }
246 catch (Exception) 268
269 if (numObjectsSkippedPermissions > 0)
247 { 270 {
248 m_saveStream.Close(); 271 m_log.DebugFormat(
249 throw; 272 "[ARCHIVER]: {0} scene objects skipped due to lack of permissions",
250 } 273 numObjectsSkippedPermissions);
274 }
275
276 // Make sure that we also request terrain texture assets
277 RegionSettings regionSettings = scene.RegionInfo.RegionSettings;
278
279 if (regionSettings.TerrainTexture1 != RegionSettings.DEFAULT_TERRAIN_TEXTURE_1)
280 assetUuids[regionSettings.TerrainTexture1] = AssetType.Texture;
281
282 if (regionSettings.TerrainTexture2 != RegionSettings.DEFAULT_TERRAIN_TEXTURE_2)
283 assetUuids[regionSettings.TerrainTexture2] = AssetType.Texture;
284
285 if (regionSettings.TerrainTexture3 != RegionSettings.DEFAULT_TERRAIN_TEXTURE_3)
286 assetUuids[regionSettings.TerrainTexture3] = AssetType.Texture;
287
288 if (regionSettings.TerrainTexture4 != RegionSettings.DEFAULT_TERRAIN_TEXTURE_4)
289 assetUuids[regionSettings.TerrainTexture4] = AssetType.Texture;
290
291 Save(scene, sceneObjects, regionDir);
251 } 292 }
252 293
253 /// <summary> 294 /// <summary>
@@ -256,14 +297,14 @@ namespace OpenSim.Region.CoreModules.World.Archiver
256 /// <param name="user">The user</param> 297 /// <param name="user">The user</param>
257 /// <param name="objGroup">The object group</param> 298 /// <param name="objGroup">The object group</param>
258 /// <param name="checkPermissions">Which permissions to check: "C" = Copy, "T" = Transfer</param> 299 /// <param name="checkPermissions">Which permissions to check: "C" = Copy, "T" = Transfer</param>
300 /// <param name="permissionsModule">The scene's permissions module</param>
259 /// <returns>Whether the user is allowed to export the object to an OAR</returns> 301 /// <returns>Whether the user is allowed to export the object to an OAR</returns>
260 private bool CanUserArchiveObject(UUID user, SceneObjectGroup objGroup, string checkPermissions) 302 private bool CanUserArchiveObject(UUID user, SceneObjectGroup objGroup, string checkPermissions, IPermissionsModule permissionsModule)
261 { 303 {
262 if (checkPermissions == null) 304 if (checkPermissions == null)
263 return true; 305 return true;
264 306
265 IPermissionsModule module = m_scene.RequestModuleInterface<IPermissionsModule>(); 307 if (permissionsModule == null)
266 if (module == null)
267 return true; // this shouldn't happen 308 return true; // this shouldn't happen
268 309
269 // Check whether the user is permitted to export all of the parts in the SOG. If any 310 // Check whether the user is permitted to export all of the parts in the SOG. If any
@@ -275,7 +316,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver
275 foreach (SceneObjectPart obj in objGroup.Parts) 316 foreach (SceneObjectPart obj in objGroup.Parts)
276 { 317 {
277 uint perm; 318 uint perm;
278 PermissionClass permissionClass = module.GetPermissionClass(user, obj); 319 PermissionClass permissionClass = permissionsModule.GetPermissionClass(user, obj);
279 switch (permissionClass) 320 switch (permissionClass)
280 { 321 {
281 case PermissionClass.Owner: 322 case PermissionClass.Owner:
@@ -330,16 +371,30 @@ namespace OpenSim.Region.CoreModules.World.Archiver
330 } 371 }
331 372
332 /// <summary> 373 /// <summary>
333 /// Create the control file for the most up to date archive 374 /// Create the control file.
334 /// </summary> 375 /// </summary>
335 /// <returns></returns> 376 /// <returns></returns>
336 public string CreateControlFile(Dictionary<string, object> options) 377 public string CreateControlFile(ArchiveScenesGroup scenesGroup)
337 { 378 {
338 int majorVersion = MAX_MAJOR_VERSION, minorVersion = 8; 379 int majorVersion;
380 int minorVersion;
381
382 if (MultiRegionFormat)
383 {
384 majorVersion = MAX_MAJOR_VERSION;
385 minorVersion = 0;
386 }
387 else
388 {
389 // To support older versions of OpenSim, we continue to create single-region OARs
390 // using the old file format. In the future this format will be discontinued.
391 majorVersion = 0;
392 minorVersion = 8;
393 }
339// 394//
340// if (options.ContainsKey("version")) 395// if (m_options.ContainsKey("version"))
341// { 396// {
342// string[] parts = options["version"].ToString().Split('.'); 397// string[] parts = m_options["version"].ToString().Split('.');
343// if (parts.Length >= 1) 398// if (parts.Length >= 1)
344// { 399// {
345// majorVersion = Int32.Parse(parts[0]); 400// majorVersion = Int32.Parse(parts[0]);
@@ -368,10 +423,10 @@ namespace OpenSim.Region.CoreModules.World.Archiver
368// } 423// }
369 424
370 m_log.InfoFormat("[ARCHIVER]: Creating version {0}.{1} OAR", majorVersion, minorVersion); 425 m_log.InfoFormat("[ARCHIVER]: Creating version {0}.{1} OAR", majorVersion, minorVersion);
371 //if (majorVersion == 1) 426 if (majorVersion == 1)
372 //{ 427 {
373 // m_log.WarnFormat("[ARCHIVER]: Please be aware that version 1.0 OARs are not compatible with OpenSim 0.7.0.2 and earlier. Please use the --version=0 option if you want to produce a compatible OAR"); 428 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");
374 //} 429 }
375 430
376 String s; 431 String s;
377 432
@@ -389,50 +444,191 @@ namespace OpenSim.Region.CoreModules.World.Archiver
389 DateTime now = DateTime.UtcNow; 444 DateTime now = DateTime.UtcNow;
390 TimeSpan t = now - new DateTime(1970, 1, 1); 445 TimeSpan t = now - new DateTime(1970, 1, 1);
391 xtw.WriteElementString("datetime", ((int)t.TotalSeconds).ToString()); 446 xtw.WriteElementString("datetime", ((int)t.TotalSeconds).ToString());
392 xtw.WriteElementString("id", UUID.Random().ToString()); 447 if (!MultiRegionFormat)
448 xtw.WriteElementString("id", m_rootScene.RegionInfo.RegionID.ToString());
393 xtw.WriteEndElement(); 449 xtw.WriteEndElement();
450
451 xtw.WriteElementString("assets_included", SaveAssets.ToString());
394 452
395 xtw.WriteStartElement("region_info"); 453 if (MultiRegionFormat)
454 {
455 WriteRegionsManifest(scenesGroup, xtw);
456 }
457 else
458 {
459 xtw.WriteStartElement("region_info");
460 WriteRegionInfo(m_rootScene, xtw);
461 xtw.WriteEndElement();
462 }
396 463
397 bool isMegaregion; 464 xtw.WriteEndElement();
398 Vector2 size; 465
399 IRegionCombinerModule rcMod = null; 466 xtw.Flush();
467 }
400 468
401 // FIXME: This is only here for regression test purposes since they do not supply a module. Need to fix 469 s = sw.ToString();
402 // this, possibly by doing control file creation somewhere else. 470 }
403 if (m_module != null)
404 rcMod = m_module.RegionCombinerModule;
405 471
406 if (rcMod != null) 472 return s;
407 isMegaregion = rcMod.IsRootForMegaregion(m_scene.RegionInfo.RegionID); 473 }
408 else
409 isMegaregion = false;
410 474
411 if (isMegaregion) 475 /// <summary>
412 size = rcMod.GetSizeOfMegaregion(m_scene.RegionInfo.RegionID); 476 /// Writes the list of regions included in a multi-region OAR.
413 else 477 /// </summary>
414 size = new Vector2((float)Constants.RegionSize, (float)Constants.RegionSize); 478 private static void WriteRegionsManifest(ArchiveScenesGroup scenesGroup, XmlTextWriter xtw)
479 {
480 xtw.WriteStartElement("regions");
415 481
416 xtw.WriteElementString("is_megaregion", isMegaregion.ToString()); 482 // Write the regions in order: rows from South to North, then regions from West to East.
417 xtw.WriteElementString("size_in_meters", string.Format("{0},{1}", size.X, size.Y)); 483 // The list of regions can have "holes"; we write empty elements in their position.
418 484
419 xtw.WriteEndElement(); 485 for (uint y = (uint)scenesGroup.Rect.Top; y < scenesGroup.Rect.Bottom; ++y)
420 486 {
421 xtw.WriteElementString("assets_included", SaveAssets.ToString()); 487 SortedDictionary<uint, Scene> row;
488 if (scenesGroup.Regions.TryGetValue(y, out row))
489 {
490 xtw.WriteStartElement("row");
491
492 for (uint x = (uint)scenesGroup.Rect.Left; x < scenesGroup.Rect.Right; ++x)
493 {
494 Scene scene;
495 if (row.TryGetValue(x, out scene))
496 {
497 xtw.WriteStartElement("region");
498 xtw.WriteElementString("id", scene.RegionInfo.RegionID.ToString());
499 xtw.WriteElementString("dir", scenesGroup.GetRegionDir(scene.RegionInfo.RegionID));
500 WriteRegionInfo(scene, xtw);
501 xtw.WriteEndElement();
502 }
503 else
504 {
505 // Write a placeholder for a missing region
506 xtw.WriteElementString("region", "");
507 }
508 }
422 509
423 xtw.WriteEndElement(); 510 xtw.WriteEndElement();
424
425 xtw.Flush();
426 } 511 }
512 else
513 {
514 // Write a placeholder for a missing row
515 xtw.WriteElementString("row", "");
516 }
517 }
427 518
428 s = sw.ToString(); 519 xtw.WriteEndElement(); // "regions"
520 }
521
522 protected static void WriteRegionInfo(Scene scene, XmlTextWriter xtw)
523 {
524 bool isMegaregion;
525 Vector2 size;
526
527 IRegionCombinerModule rcMod = scene.RequestModuleInterface<IRegionCombinerModule>();
528
529 if (rcMod != null)
530 isMegaregion = rcMod.IsRootForMegaregion(scene.RegionInfo.RegionID);
531 else
532 isMegaregion = false;
533
534 if (isMegaregion)
535 size = rcMod.GetSizeOfMegaregion(scene.RegionInfo.RegionID);
536 else
537 size = new Vector2((float)Constants.RegionSize, (float)Constants.RegionSize);
538
539 xtw.WriteElementString("is_megaregion", isMegaregion.ToString());
540 xtw.WriteElementString("size_in_meters", string.Format("{0},{1}", size.X, size.Y));
541 }
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 = String.Format("{0}{1}{2}.xml",
564 regionDir, ArchiveConstants.LANDDATA_PATH, landData.GlobalID.ToString());
565 m_archiveWriter.WriteFile(landDataPath, LandDataSerializer.Serialize(landData, m_options));
429 } 566 }
430 567
431// if (m_scene != null) 568 m_log.InfoFormat("[ARCHIVER]: Adding terrain information to archive.");
432// Console.WriteLine(
433// "[ARCHIVE WRITE REQUEST PREPARATION]: Control file for {0} is: {1}", m_scene.RegionInfo.RegionName, s);
434 569
435 return s; 570 // Write out terrain
571 string terrainPath = String.Format("{0}{1}{2}.r32",
572 regionDir, ArchiveConstants.TERRAINS_PATH, scene.RegionInfo.RegionName);
573
574 MemoryStream ms = new MemoryStream();
575 scene.RequestModuleInterface<ITerrainModule>().SaveToStream(terrainPath, ms);
576 m_archiveWriter.WriteFile(terrainPath, ms.ToArray());
577 ms.Close();
578
579 m_log.InfoFormat("[ARCHIVER]: Adding scene objects to archive.");
580
581 // Write out scene object metadata
582 IRegionSerialiserModule serializer = scene.RequestModuleInterface<IRegionSerialiserModule>();
583 foreach (SceneObjectGroup sceneObject in sceneObjects)
584 {
585 //m_log.DebugFormat("[ARCHIVER]: Saving {0} {1}, {2}", entity.Name, entity.UUID, entity.GetType());
586
587 string serializedObject = serializer.SerializeGroupToXml2(sceneObject, m_options);
588 string objectPath = string.Format("{0}{1}", regionDir, ArchiveHelpers.CreateObjectPath(sceneObject));
589 m_archiveWriter.WriteFile(objectPath, serializedObject);
590 }
436 } 591 }
592
593 protected void ReceivedAllAssets(
594 ICollection<UUID> assetsFoundUuids, ICollection<UUID> assetsNotFoundUuids)
595 {
596 foreach (UUID uuid in assetsNotFoundUuids)
597 {
598 m_log.DebugFormat("[ARCHIVER]: Could not find asset {0}", uuid);
599 }
600
601 // m_log.InfoFormat(
602 // "[ARCHIVER]: Received {0} of {1} assets requested",
603 // assetsFoundUuids.Count, assetsFoundUuids.Count + assetsNotFoundUuids.Count);
604
605 CloseArchive(String.Empty);
606 }
607
608
609 /// <summary>
610 /// Closes the archive and notifies that we're done.
611 /// </summary>
612 /// <param name="errorMessage">The error that occurred, or empty for success</param>
613 protected void CloseArchive(string errorMessage)
614 {
615 try
616 {
617 if (m_archiveWriter != null)
618 m_archiveWriter.Close();
619 m_saveStream.Close();
620 }
621 catch (Exception e)
622 {
623 m_log.Error(string.Format("[ARCHIVER]: Error closing archive: {0} ", e.Message), e);
624 if (errorMessage == string.Empty)
625 errorMessage = e.Message;
626 }
627
628 m_log.InfoFormat("[ARCHIVER]: Finished writing out OAR for {0}", m_rootScene.RegionInfo.RegionName);
629
630 m_rootScene.EventManager.TriggerOarFileSaved(m_requestId, errorMessage);
631 }
632
437 } 633 }
438} 634}