aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/CoreModules/World/Archiver/ArchiveWriteRequestPreparation.cs
diff options
context:
space:
mode:
authorOren Hurvitz2012-07-24 19:48:08 +0300
committerJustin Clark-Casey (justincc)2012-09-14 20:25:03 +0100
commitce468215d576cc301a261d85bee9baa68a246ce6 (patch)
treead2c6d7e3156bf8dab596f2772cc712d4f96c698 /OpenSim/Region/CoreModules/World/Archiver/ArchiveWriteRequestPreparation.cs
parentDon't store the unnecessary VERSIONMIN. VERSIONMAX, METHOD or UserID (present... (diff)
downloadopensim-SC_OLD-ce468215d576cc301a261d85bee9baa68a246ce6.zip
opensim-SC_OLD-ce468215d576cc301a261d85bee9baa68a246ce6.tar.gz
opensim-SC_OLD-ce468215d576cc301a261d85bee9baa68a246ce6.tar.bz2
opensim-SC_OLD-ce468215d576cc301a261d85bee9baa68a246ce6.tar.xz
Support multi-region OAR files
Merged ArchiveWriteRequestPreparation.cs and ArchiveWriteRequestExecution.cs. This simplifies the code, and it's faster to write each scene to the archive as it's found rather than all at once at the end.
Diffstat (limited to '')
-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}