aboutsummaryrefslogtreecommitdiffstatshomepage
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
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.
-rw-r--r--OpenSim/ApplicationPlugins/RemoteController/RemoteAdminPlugin.cs7
-rw-r--r--OpenSim/Framework/Serialization/ArchiveConstants.cs5
-rw-r--r--OpenSim/Region/Application/OpenSim.cs3
-rw-r--r--OpenSim/Region/CoreModules/World/Archiver/ArchiveReadRequest.cs365
-rw-r--r--OpenSim/Region/CoreModules/World/Archiver/ArchiveScenesGroup.cs176
-rw-r--r--OpenSim/Region/CoreModules/World/Archiver/ArchiveWriteRequestExecution.cs153
-rw-r--r--OpenSim/Region/CoreModules/World/Archiver/ArchiveWriteRequestPreparation.cs492
-rw-r--r--OpenSim/Region/CoreModules/World/Archiver/ArchiverModule.cs5
-rw-r--r--OpenSim/Region/CoreModules/World/Archiver/AssetsRequest.cs6
-rw-r--r--OpenSim/Region/CoreModules/World/Archiver/DearchiveScenesGroup.cs232
-rw-r--r--OpenSim/Region/CoreModules/World/Archiver/Tests/ArchiverTests.cs23
-rw-r--r--OpenSim/Region/Framework/Interfaces/IEstateModule.cs5
-rw-r--r--OpenSim/Region/Framework/Scenes/EventManager.cs6
-rw-r--r--OpenSim/Region/OptionalModules/Scripting/RegionReadyModule/RegionReadyModule.cs2
14 files changed, 1080 insertions, 400 deletions
diff --git a/OpenSim/ApplicationPlugins/RemoteController/RemoteAdminPlugin.cs b/OpenSim/ApplicationPlugins/RemoteController/RemoteAdminPlugin.cs
index 24570d6..a5e56f9 100644
--- a/OpenSim/ApplicationPlugins/RemoteController/RemoteAdminPlugin.cs
+++ b/OpenSim/ApplicationPlugins/RemoteController/RemoteAdminPlugin.cs
@@ -1369,6 +1369,8 @@ namespace OpenSim.ApplicationPlugins.RemoteController
1369 /// <description>profile url</description></item> 1369 /// <description>profile url</description></item>
1370 /// <item><term>noassets</term> 1370 /// <item><term>noassets</term>
1371 /// <description>true if no assets should be saved</description></item> 1371 /// <description>true if no assets should be saved</description></item>
1372 /// <item><term>all</term>
1373 /// <description>true to save all the regions in the simulator</description></item>
1372 /// <item><term>perm</term> 1374 /// <item><term>perm</term>
1373 /// <description>C and/or T</description></item> 1375 /// <description>C and/or T</description></item>
1374 /// </list> 1376 /// </list>
@@ -1425,6 +1427,11 @@ namespace OpenSim.ApplicationPlugins.RemoteController
1425 options["checkPermissions"] = (string)requestData["perm"]; 1427 options["checkPermissions"] = (string)requestData["perm"];
1426 } 1428 }
1427 1429
1430 if ((string)requestData["all"] == "true")
1431 {
1432 options["all"] = (string)requestData["all"];
1433 }
1434
1428 IRegionArchiverModule archiver = scene.RequestModuleInterface<IRegionArchiverModule>(); 1435 IRegionArchiverModule archiver = scene.RequestModuleInterface<IRegionArchiverModule>();
1429 1436
1430 if (archiver != null) 1437 if (archiver != null)
diff --git a/OpenSim/Framework/Serialization/ArchiveConstants.cs b/OpenSim/Framework/Serialization/ArchiveConstants.cs
index 2c5e001..48f1c4f 100644
--- a/OpenSim/Framework/Serialization/ArchiveConstants.cs
+++ b/OpenSim/Framework/Serialization/ArchiveConstants.cs
@@ -53,6 +53,11 @@ namespace OpenSim.Framework.Serialization
53 public const string INVENTORY_PATH = "inventory/"; 53 public const string INVENTORY_PATH = "inventory/";
54 54
55 /// <value> 55 /// <value>
56 /// Path for regions in a multi-region archive
57 /// </value>
58 public const string REGIONS_PATH = "regions/";
59
60 /// <value>
56 /// Path for the prims file 61 /// Path for the prims file
57 /// </value> 62 /// </value>
58 public const string OBJECTS_PATH = "objects/"; 63 public const string OBJECTS_PATH = "objects/";
diff --git a/OpenSim/Region/Application/OpenSim.cs b/OpenSim/Region/Application/OpenSim.cs
index ed339fd..c3c612f 100644
--- a/OpenSim/Region/Application/OpenSim.cs
+++ b/OpenSim/Region/Application/OpenSim.cs
@@ -292,7 +292,7 @@ namespace OpenSim
292 292
293 m_console.Commands.AddCommand("Archiving", false, "save oar", 293 m_console.Commands.AddCommand("Archiving", false, "save oar",
294 //"save oar [-v|--version=<N>] [-p|--profile=<url>] [<OAR path>]", 294 //"save oar [-v|--version=<N>] [-p|--profile=<url>] [<OAR path>]",
295 "save oar [-h|--home=<url>] [--noassets] [--publish] [--perm=<permissions>] [<OAR path>]", 295 "save oar [-h|--home=<url>] [--noassets] [--publish] [--perm=<permissions>] [--all] [<OAR path>]",
296 "Save a region's data to an OAR archive.", 296 "Save a region's data to an OAR archive.",
297// "-v|--version=<N> generates scene objects as per older versions of the serialization (e.g. -v=0)" + Environment.NewLine 297// "-v|--version=<N> generates scene objects as per older versions of the serialization (e.g. -v=0)" + Environment.NewLine
298 "-h|--home=<url> adds the url of the profile service to the saved user information.\n" 298 "-h|--home=<url> adds the url of the profile service to the saved user information.\n"
@@ -302,6 +302,7 @@ namespace OpenSim
302 + " this is useful if you're making oars generally available that might be reloaded to the same grid from which you published\n" 302 + " this is useful if you're making oars generally available that might be reloaded to the same grid from which you published\n"
303 + "--perm=<permissions> stops objects with insufficient permissions from being saved to the OAR.\n" 303 + "--perm=<permissions> stops objects with insufficient permissions from being saved to the OAR.\n"
304 + " <permissions> can contain one or more of these characters: \"C\" = Copy, \"T\" = Transfer\n" 304 + " <permissions> can contain one or more of these characters: \"C\" = Copy, \"T\" = Transfer\n"
305 + "--all saves all the regions in the simulator, instead of just the current region.\n"
305 + "The OAR path must be a filesystem path." 306 + "The OAR path must be a filesystem path."
306 + " If this is not given then the oar is saved to region.oar in the current directory.", 307 + " If this is not given then the oar is saved to region.oar in the current directory.",
307 SaveOar); 308 SaveOar);
diff --git a/OpenSim/Region/CoreModules/World/Archiver/ArchiveReadRequest.cs b/OpenSim/Region/CoreModules/World/Archiver/ArchiveReadRequest.cs
index 433166d..a6923ef 100644
--- a/OpenSim/Region/CoreModules/World/Archiver/ArchiveReadRequest.cs
+++ b/OpenSim/Region/CoreModules/World/Archiver/ArchiveReadRequest.cs
@@ -43,6 +43,7 @@ using OpenSim.Region.Framework.Interfaces;
43using OpenSim.Region.Framework.Scenes; 43using OpenSim.Region.Framework.Scenes;
44using OpenSim.Region.Framework.Scenes.Serialization; 44using OpenSim.Region.Framework.Scenes.Serialization;
45using OpenSim.Services.Interfaces; 45using OpenSim.Services.Interfaces;
46using System.Threading;
46 47
47namespace OpenSim.Region.CoreModules.World.Archiver 48namespace OpenSim.Region.CoreModules.World.Archiver
48{ 49{
@@ -52,7 +53,30 @@ namespace OpenSim.Region.CoreModules.World.Archiver
52 public class ArchiveReadRequest 53 public class ArchiveReadRequest
53 { 54 {
54 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 55 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
56
57 /// <summary>
58 /// Contains data used while dearchiving a single scene.
59 /// </summary>
60 private class DearchiveContext
61 {
62 public Scene Scene { get; set; }
63
64 public List<string> SerialisedSceneObjects { get; set; }
65
66 public List<string> SerialisedParcels { get; set; }
67
68 public List<SceneObjectGroup> SceneObjects { get; set; }
69
70 public DearchiveContext(Scene scene)
71 {
72 Scene = scene;
73 SerialisedSceneObjects = new List<string>();
74 SerialisedParcels = new List<string>();
75 SceneObjects = new List<SceneObjectGroup>();
76 }
77 }
55 78
79
56 /// <summary> 80 /// <summary>
57 /// The maximum major version of OAR that we can read. Minor versions shouldn't need a max number since version 81 /// The maximum major version of OAR that we can read. Minor versions shouldn't need a max number since version
58 /// bumps here should be compatible. 82 /// bumps here should be compatible.
@@ -62,9 +86,10 @@ namespace OpenSim.Region.CoreModules.World.Archiver
62 /// <summary> 86 /// <summary>
63 /// Has the control file been loaded for this archive? 87 /// Has the control file been loaded for this archive?
64 /// </summary> 88 /// </summary>
65 public bool ControlFileLoaded { get; private set; } 89 public bool ControlFileLoaded { get; private set; }
66 90
67 protected Scene m_scene; 91 protected string m_loadPath;
92 protected Scene m_rootScene;
68 protected Stream m_loadStream; 93 protected Stream m_loadStream;
69 protected Guid m_requestId; 94 protected Guid m_requestId;
70 protected string m_errorMessage; 95 protected string m_errorMessage;
@@ -91,7 +116,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver
91 { 116 {
92 if (m_UserMan == null) 117 if (m_UserMan == null)
93 { 118 {
94 m_UserMan = m_scene.RequestModuleInterface<IUserManagement>(); 119 m_UserMan = m_rootScene.RequestModuleInterface<IUserManagement>();
95 } 120 }
96 return m_UserMan; 121 return m_UserMan;
97 } 122 }
@@ -104,10 +129,14 @@ namespace OpenSim.Region.CoreModules.World.Archiver
104 129
105 private IGroupsModule m_groupsModule; 130 private IGroupsModule m_groupsModule;
106 131
132 private IAssetService m_assetService = null;
133
134
107 public ArchiveReadRequest(Scene scene, string loadPath, bool merge, bool skipAssets, Guid requestId) 135 public ArchiveReadRequest(Scene scene, string loadPath, bool merge, bool skipAssets, Guid requestId)
108 { 136 {
109 m_scene = scene; 137 m_rootScene = scene;
110 138
139 m_loadPath = loadPath;
111 try 140 try
112 { 141 {
113 m_loadStream = new GZipStream(ArchiveHelpers.GetStream(loadPath), CompressionMode.Decompress); 142 m_loadStream = new GZipStream(ArchiveHelpers.GetStream(loadPath), CompressionMode.Decompress);
@@ -128,12 +157,14 @@ namespace OpenSim.Region.CoreModules.World.Archiver
128 // Zero can never be a valid user id 157 // Zero can never be a valid user id
129 m_validUserUuids[UUID.Zero] = false; 158 m_validUserUuids[UUID.Zero] = false;
130 159
131 m_groupsModule = m_scene.RequestModuleInterface<IGroupsModule>(); 160 m_groupsModule = m_rootScene.RequestModuleInterface<IGroupsModule>();
161 m_assetService = m_rootScene.AssetService;
132 } 162 }
133 163
134 public ArchiveReadRequest(Scene scene, Stream loadStream, bool merge, bool skipAssets, Guid requestId) 164 public ArchiveReadRequest(Scene scene, Stream loadStream, bool merge, bool skipAssets, Guid requestId)
135 { 165 {
136 m_scene = scene; 166 m_rootScene = scene;
167 m_loadPath = null;
137 m_loadStream = loadStream; 168 m_loadStream = loadStream;
138 m_merge = merge; 169 m_merge = merge;
139 m_skipAssets = skipAssets; 170 m_skipAssets = skipAssets;
@@ -142,7 +173,8 @@ namespace OpenSim.Region.CoreModules.World.Archiver
142 // Zero can never be a valid user id 173 // Zero can never be a valid user id
143 m_validUserUuids[UUID.Zero] = false; 174 m_validUserUuids[UUID.Zero] = false;
144 175
145 m_groupsModule = m_scene.RequestModuleInterface<IGroupsModule>(); 176 m_groupsModule = m_rootScene.RequestModuleInterface<IGroupsModule>();
177 m_assetService = m_rootScene.AssetService;
146 } 178 }
147 179
148 /// <summary> 180 /// <summary>
@@ -150,25 +182,25 @@ namespace OpenSim.Region.CoreModules.World.Archiver
150 /// </summary> 182 /// </summary>
151 public void DearchiveRegion() 183 public void DearchiveRegion()
152 { 184 {
153 // The same code can handle dearchiving 0.1 and 0.2 OpenSim Archive versions
154 DearchiveRegion0DotStar();
155 }
156
157 private void DearchiveRegion0DotStar()
158 {
159 int successfulAssetRestores = 0; 185 int successfulAssetRestores = 0;
160 int failedAssetRestores = 0; 186 int failedAssetRestores = 0;
161 List<string> serialisedSceneObjects = new List<string>();
162 List<string> serialisedParcels = new List<string>();
163 string filePath = "NONE";
164 187
165 TarArchiveReader archive = new TarArchiveReader(m_loadStream); 188 DearchiveScenesInfo dearchivedScenes;
189
190 // We dearchive all the scenes at once, because the files in the TAR archive might be mixed.
191 // Therefore, we have to keep track of the dearchive context of all the scenes.
192 Dictionary<UUID, DearchiveContext> sceneContexts = new Dictionary<UUID, DearchiveContext>();
193
194 string fullPath = "NONE";
195 TarArchiveReader archive = null;
166 byte[] data; 196 byte[] data;
167 TarArchiveReader.TarEntryType entryType; 197 TarArchiveReader.TarEntryType entryType;
168 198
169 try 199 try
170 { 200 {
171 while ((data = archive.ReadEntry(out filePath, out entryType)) != null) 201 FindAndLoadControlFile(out archive, out dearchivedScenes);
202
203 while ((data = archive.ReadEntry(out fullPath, out entryType)) != null)
172 { 204 {
173 //m_log.DebugFormat( 205 //m_log.DebugFormat(
174 // "[ARCHIVER]: Successfully read {0} ({1} bytes)", filePath, data.Length); 206 // "[ARCHIVER]: Successfully read {0} ({1} bytes)", filePath, data.Length);
@@ -176,9 +208,30 @@ namespace OpenSim.Region.CoreModules.World.Archiver
176 if (TarArchiveReader.TarEntryType.TYPE_DIRECTORY == entryType) 208 if (TarArchiveReader.TarEntryType.TYPE_DIRECTORY == entryType)
177 continue; 209 continue;
178 210
211
212 // Find the scene that this file belongs to
213
214 Scene scene;
215 string filePath;
216 if (!dearchivedScenes.GetRegionFromPath(fullPath, out scene, out filePath))
217 continue; // this file belongs to a region that we're not loading
218
219 DearchiveContext sceneContext = null;
220 if (scene != null)
221 {
222 if (!sceneContexts.TryGetValue(scene.RegionInfo.RegionID, out sceneContext))
223 {
224 sceneContext = new DearchiveContext(scene);
225 sceneContexts.Add(scene.RegionInfo.RegionID, sceneContext);
226 }
227 }
228
229
230 // Process the file
231
179 if (filePath.StartsWith(ArchiveConstants.OBJECTS_PATH)) 232 if (filePath.StartsWith(ArchiveConstants.OBJECTS_PATH))
180 { 233 {
181 serialisedSceneObjects.Add(Encoding.UTF8.GetString(data)); 234 sceneContext.SerialisedSceneObjects.Add(Encoding.UTF8.GetString(data));
182 } 235 }
183 else if (filePath.StartsWith(ArchiveConstants.ASSETS_PATH) && !m_skipAssets) 236 else if (filePath.StartsWith(ArchiveConstants.ASSETS_PATH) && !m_skipAssets)
184 { 237 {
@@ -192,19 +245,19 @@ namespace OpenSim.Region.CoreModules.World.Archiver
192 } 245 }
193 else if (!m_merge && filePath.StartsWith(ArchiveConstants.TERRAINS_PATH)) 246 else if (!m_merge && filePath.StartsWith(ArchiveConstants.TERRAINS_PATH))
194 { 247 {
195 LoadTerrain(filePath, data); 248 LoadTerrain(scene, filePath, data);
196 } 249 }
197 else if (!m_merge && filePath.StartsWith(ArchiveConstants.SETTINGS_PATH)) 250 else if (!m_merge && filePath.StartsWith(ArchiveConstants.SETTINGS_PATH))
198 { 251 {
199 LoadRegionSettings(filePath, data); 252 LoadRegionSettings(scene, filePath, data, dearchivedScenes);
200 } 253 }
201 else if (!m_merge && filePath.StartsWith(ArchiveConstants.LANDDATA_PATH)) 254 else if (!m_merge && filePath.StartsWith(ArchiveConstants.LANDDATA_PATH))
202 { 255 {
203 serialisedParcels.Add(Encoding.UTF8.GetString(data)); 256 sceneContext.SerialisedParcels.Add(Encoding.UTF8.GetString(data));
204 } 257 }
205 else if (filePath == ArchiveConstants.CONTROL_FILE_PATH) 258 else if (filePath == ArchiveConstants.CONTROL_FILE_PATH)
206 { 259 {
207 LoadControlFile(filePath, data); 260 // Ignore, because we already read the control file
208 } 261 }
209 } 262 }
210 263
@@ -212,15 +265,16 @@ namespace OpenSim.Region.CoreModules.World.Archiver
212 } 265 }
213 catch (Exception e) 266 catch (Exception e)
214 { 267 {
215 m_log.ErrorFormat( 268 m_log.Error(
216 "[ARCHIVER]: Aborting load with error in archive file {0}. {1}", filePath, e); 269 String.Format("[ARCHIVER]: Aborting load with error in archive file {0} ", fullPath), e);
217 m_errorMessage += e.ToString(); 270 m_errorMessage += e.ToString();
218 m_scene.EventManager.TriggerOarFileLoaded(m_requestId, m_errorMessage); 271 m_rootScene.EventManager.TriggerOarFileLoaded(m_requestId, new List<UUID>(), m_errorMessage);
219 return; 272 return;
220 } 273 }
221 finally 274 finally
222 { 275 {
223 archive.Close(); 276 if (archive != null)
277 archive.Close();
224 } 278 }
225 279
226 if (!m_skipAssets) 280 if (!m_skipAssets)
@@ -234,32 +288,143 @@ namespace OpenSim.Region.CoreModules.World.Archiver
234 } 288 }
235 } 289 }
236 290
237 if (!m_merge) 291 foreach (DearchiveContext sceneContext in sceneContexts.Values)
238 { 292 {
239 m_log.Info("[ARCHIVER]: Clearing all existing scene objects"); 293 m_log.InfoFormat("[ARCHIVER:] Loading region {0}", sceneContext.Scene.RegionInfo.RegionName);
240 m_scene.DeleteAllSceneObjects(); 294
295 if (!m_merge)
296 {
297 m_log.Info("[ARCHIVER]: Clearing all existing scene objects");
298 sceneContext.Scene.DeleteAllSceneObjects();
299 }
300
301 try
302 {
303 LoadParcels(sceneContext.Scene, sceneContext.SerialisedParcels);
304 LoadObjects(sceneContext.Scene, sceneContext.SerialisedSceneObjects, sceneContext.SceneObjects);
305
306 // Inform any interested parties that the region has changed. We waited until now so that all
307 // of the region's objects will be loaded when we send this notification.
308 IEstateModule estateModule = sceneContext.Scene.RequestModuleInterface<IEstateModule>();
309 if (estateModule != null)
310 estateModule.TriggerRegionInfoChange();
311 }
312 catch (Exception e)
313 {
314 m_log.Error("[ARCHIVER]: Error loading parcels or objects ", e);
315 m_errorMessage += e.ToString();
316 m_rootScene.EventManager.TriggerOarFileLoaded(m_requestId, new List<UUID>(), m_errorMessage);
317 return;
318 }
241 } 319 }
242 320
243 LoadParcels(serialisedParcels); 321 // Start the scripts. We delayed this because we want the OAR to finish loading ASAP, so
244 LoadObjects(serialisedSceneObjects); 322 // that users can enter the scene. If we allow the scripts to start in the loop above
323 // then they significantly increase the time until the OAR finishes loading.
324 Util.FireAndForget(delegate(object o)
325 {
326 Thread.Sleep(15000);
327 m_log.Info("Starting scripts in scene objects");
328
329 foreach (DearchiveContext sceneContext in sceneContexts.Values)
330 {
331 foreach (SceneObjectGroup sceneObject in sceneContext.SceneObjects)
332 {
333 sceneObject.CreateScriptInstances(0, false, sceneContext.Scene.DefaultScriptEngine, 0); // StateSource.RegionStart
334 sceneObject.ResumeScripts();
335 }
336
337 sceneContext.SceneObjects.Clear();
338 }
339 });
245 340
246 m_log.InfoFormat("[ARCHIVER]: Successfully loaded archive"); 341 m_log.InfoFormat("[ARCHIVER]: Successfully loaded archive");
247 342
248 m_scene.EventManager.TriggerOarFileLoaded(m_requestId, m_errorMessage); 343 m_rootScene.EventManager.TriggerOarFileLoaded(m_requestId, dearchivedScenes.GetLoadedScenes(), m_errorMessage);
344 }
345
346 /// <summary>
347 /// Searches through the files in the archive for the control file, and reads it.
348 /// We must read the control file first, in order to know which regions are available.
349 /// </summary>
350 /// <remarks>
351 /// In most cases the control file *is* first, since that's how we create archives. However,
352 /// it's possible that someone rewrote the archive externally so we can't rely on this fact.
353 /// </remarks>
354 /// <param name="archive"></param>
355 /// <param name="dearchivedScenes"></param>
356 private void FindAndLoadControlFile(out TarArchiveReader archive, out DearchiveScenesInfo dearchivedScenes)
357 {
358 archive = new TarArchiveReader(m_loadStream);
359 dearchivedScenes = new DearchiveScenesInfo();
360
361 string filePath;
362 byte[] data;
363 TarArchiveReader.TarEntryType entryType;
364 bool firstFile = true;
365
366 while ((data = archive.ReadEntry(out filePath, out entryType)) != null)
367 {
368 if (TarArchiveReader.TarEntryType.TYPE_DIRECTORY == entryType)
369 continue;
370
371 if (filePath == ArchiveConstants.CONTROL_FILE_PATH)
372 {
373 LoadControlFile(filePath, data, dearchivedScenes);
374
375 // Find which scenes are available in the simulator
376 ArchiveScenesGroup simulatorScenes = new ArchiveScenesGroup();
377 SceneManager.Instance.ForEachScene(delegate(Scene scene2)
378 {
379 simulatorScenes.AddScene(scene2);
380 });
381 simulatorScenes.CalcSceneLocations();
382 dearchivedScenes.SetSimulatorScenes(m_rootScene, simulatorScenes);
383
384 // If the control file wasn't the first file then reset the read pointer
385 if (!firstFile)
386 {
387 m_log.Warn("Control file wasn't the first file in the archive");
388 if (m_loadStream.CanSeek)
389 {
390 m_loadStream.Seek(0, SeekOrigin.Begin);
391 }
392 else if (m_loadPath != null)
393 {
394 archive.Close();
395 archive = null;
396 m_loadStream.Close();
397 m_loadStream = null;
398 m_loadStream = new GZipStream(ArchiveHelpers.GetStream(m_loadPath), CompressionMode.Decompress);
399 archive = new TarArchiveReader(m_loadStream);
400 }
401 else
402 {
403 // There isn't currently a scenario where this happens, but it's best to add a check just in case
404 throw new Exception("Error reading archive: control file wasn't the first file, and the input stream doesn't allow seeking");
405 }
406 }
407
408 return;
409 }
410
411 firstFile = false;
412 }
413
414 throw new Exception("Control file not found");
249 } 415 }
250 416
251 /// <summary> 417 /// <summary>
252 /// Load serialized scene objects. 418 /// Load serialized scene objects.
253 /// </summary> 419 /// </summary>
254 /// <param name="serialisedSceneObjects"></param> 420 protected void LoadObjects(Scene scene, List<string> serialisedSceneObjects, List<SceneObjectGroup> sceneObjects)
255 protected void LoadObjects(List<string> serialisedSceneObjects)
256 { 421 {
257 // Reload serialized prims 422 // Reload serialized prims
258 m_log.InfoFormat("[ARCHIVER]: Loading {0} scene objects. Please wait.", serialisedSceneObjects.Count); 423 m_log.InfoFormat("[ARCHIVER]: Loading {0} scene objects. Please wait.", serialisedSceneObjects.Count);
259 424
260 UUID oldTelehubUUID = m_scene.RegionInfo.RegionSettings.TelehubObject; 425 UUID oldTelehubUUID = scene.RegionInfo.RegionSettings.TelehubObject;
261 426
262 IRegionSerialiserModule serialiser = m_scene.RequestModuleInterface<IRegionSerialiserModule>(); 427 IRegionSerialiserModule serialiser = scene.RequestModuleInterface<IRegionSerialiserModule>();
263 int sceneObjectsLoadedCount = 0; 428 int sceneObjectsLoadedCount = 0;
264 429
265 foreach (string serialisedSceneObject in serialisedSceneObjects) 430 foreach (string serialisedSceneObject in serialisedSceneObjects)
@@ -280,7 +445,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver
280 445
281 SceneObjectGroup sceneObject = serialiser.DeserializeGroupFromXml2(serialisedSceneObject); 446 SceneObjectGroup sceneObject = serialiser.DeserializeGroupFromXml2(serialisedSceneObject);
282 447
283 bool isTelehub = (sceneObject.UUID == oldTelehubUUID); 448 bool isTelehub = (sceneObject.UUID == oldTelehubUUID) && (oldTelehubUUID != UUID.Zero);
284 449
285 // For now, give all incoming scene objects new uuids. This will allow scenes to be cloned 450 // For now, give all incoming scene objects new uuids. This will allow scenes to be cloned
286 // on the same region server and multiple examples a single object archive to be imported 451 // on the same region server and multiple examples a single object archive to be imported
@@ -290,8 +455,8 @@ namespace OpenSim.Region.CoreModules.World.Archiver
290 if (isTelehub) 455 if (isTelehub)
291 { 456 {
292 // Change the Telehub Object to the new UUID 457 // Change the Telehub Object to the new UUID
293 m_scene.RegionInfo.RegionSettings.TelehubObject = sceneObject.UUID; 458 scene.RegionInfo.RegionSettings.TelehubObject = sceneObject.UUID;
294 m_scene.RegionInfo.RegionSettings.Save(); 459 scene.RegionInfo.RegionSettings.Save();
295 oldTelehubUUID = UUID.Zero; 460 oldTelehubUUID = UUID.Zero;
296 } 461 }
297 462
@@ -301,17 +466,17 @@ namespace OpenSim.Region.CoreModules.World.Archiver
301 { 466 {
302 if (part.CreatorData == null || part.CreatorData == string.Empty) 467 if (part.CreatorData == null || part.CreatorData == string.Empty)
303 { 468 {
304 if (!ResolveUserUuid(part.CreatorID)) 469 if (!ResolveUserUuid(scene, part.CreatorID))
305 part.CreatorID = m_scene.RegionInfo.EstateSettings.EstateOwner; 470 part.CreatorID = scene.RegionInfo.EstateSettings.EstateOwner;
306 } 471 }
307 if (UserManager != null) 472 if (UserManager != null)
308 UserManager.AddUser(part.CreatorID, part.CreatorData); 473 UserManager.AddUser(part.CreatorID, part.CreatorData);
309 474
310 if (!ResolveUserUuid(part.OwnerID)) 475 if (!ResolveUserUuid(scene, part.OwnerID))
311 part.OwnerID = m_scene.RegionInfo.EstateSettings.EstateOwner; 476 part.OwnerID = scene.RegionInfo.EstateSettings.EstateOwner;
312 477
313 if (!ResolveUserUuid(part.LastOwnerID)) 478 if (!ResolveUserUuid(scene, part.LastOwnerID))
314 part.LastOwnerID = m_scene.RegionInfo.EstateSettings.EstateOwner; 479 part.LastOwnerID = scene.RegionInfo.EstateSettings.EstateOwner;
315 480
316 if (!ResolveGroupUuid(part.GroupID)) 481 if (!ResolveGroupUuid(part.GroupID))
317 part.GroupID = UUID.Zero; 482 part.GroupID = UUID.Zero;
@@ -328,15 +493,15 @@ namespace OpenSim.Region.CoreModules.World.Archiver
328 TaskInventoryDictionary inv = part.TaskInventory; 493 TaskInventoryDictionary inv = part.TaskInventory;
329 foreach (KeyValuePair<UUID, TaskInventoryItem> kvp in inv) 494 foreach (KeyValuePair<UUID, TaskInventoryItem> kvp in inv)
330 { 495 {
331 if (!ResolveUserUuid(kvp.Value.OwnerID)) 496 if (!ResolveUserUuid(scene, kvp.Value.OwnerID))
332 { 497 {
333 kvp.Value.OwnerID = m_scene.RegionInfo.EstateSettings.EstateOwner; 498 kvp.Value.OwnerID = scene.RegionInfo.EstateSettings.EstateOwner;
334 } 499 }
335 500
336 if (kvp.Value.CreatorData == null || kvp.Value.CreatorData == string.Empty) 501 if (kvp.Value.CreatorData == null || kvp.Value.CreatorData == string.Empty)
337 { 502 {
338 if (!ResolveUserUuid(kvp.Value.CreatorID)) 503 if (!ResolveUserUuid(scene, kvp.Value.CreatorID))
339 kvp.Value.CreatorID = m_scene.RegionInfo.EstateSettings.EstateOwner; 504 kvp.Value.CreatorID = scene.RegionInfo.EstateSettings.EstateOwner;
340 } 505 }
341 506
342 if (UserManager != null) 507 if (UserManager != null)
@@ -348,10 +513,10 @@ namespace OpenSim.Region.CoreModules.World.Archiver
348 } 513 }
349 } 514 }
350 515
351 if (m_scene.AddRestoredSceneObject(sceneObject, true, false)) 516 if (scene.AddRestoredSceneObject(sceneObject, true, false))
352 { 517 {
353 sceneObjectsLoadedCount++; 518 sceneObjectsLoadedCount++;
354 sceneObject.CreateScriptInstances(0, false, m_scene.DefaultScriptEngine, 0); 519 sceneObject.CreateScriptInstances(0, false, scene.DefaultScriptEngine, 0);
355 sceneObject.ResumeScripts(); 520 sceneObject.ResumeScripts();
356 } 521 }
357 } 522 }
@@ -366,16 +531,17 @@ namespace OpenSim.Region.CoreModules.World.Archiver
366 if (oldTelehubUUID != UUID.Zero) 531 if (oldTelehubUUID != UUID.Zero)
367 { 532 {
368 m_log.WarnFormat("Telehub object not found: {0}", oldTelehubUUID); 533 m_log.WarnFormat("Telehub object not found: {0}", oldTelehubUUID);
369 m_scene.RegionInfo.RegionSettings.TelehubObject = UUID.Zero; 534 scene.RegionInfo.RegionSettings.TelehubObject = UUID.Zero;
370 m_scene.RegionInfo.RegionSettings.ClearSpawnPoints(); 535 scene.RegionInfo.RegionSettings.ClearSpawnPoints();
371 } 536 }
372 } 537 }
373 538
374 /// <summary> 539 /// <summary>
375 /// Load serialized parcels. 540 /// Load serialized parcels.
376 /// </summary> 541 /// </summary>
542 /// <param name="scene"></param>
377 /// <param name="serialisedParcels"></param> 543 /// <param name="serialisedParcels"></param>
378 protected void LoadParcels(List<string> serialisedParcels) 544 protected void LoadParcels(Scene scene, List<string> serialisedParcels)
379 { 545 {
380 // Reload serialized parcels 546 // Reload serialized parcels
381 m_log.InfoFormat("[ARCHIVER]: Loading {0} parcels. Please wait.", serialisedParcels.Count); 547 m_log.InfoFormat("[ARCHIVER]: Loading {0} parcels. Please wait.", serialisedParcels.Count);
@@ -386,8 +552,8 @@ namespace OpenSim.Region.CoreModules.World.Archiver
386 552
387 // Validate User and Group UUID's 553 // Validate User and Group UUID's
388 554
389 if (!ResolveUserUuid(parcel.OwnerID)) 555 if (!ResolveUserUuid(scene, parcel.OwnerID))
390 parcel.OwnerID = m_scene.RegionInfo.EstateSettings.EstateOwner; 556 parcel.OwnerID = m_rootScene.RegionInfo.EstateSettings.EstateOwner;
391 557
392 if (!ResolveGroupUuid(parcel.GroupID)) 558 if (!ResolveGroupUuid(parcel.GroupID))
393 { 559 {
@@ -398,7 +564,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver
398 List<LandAccessEntry> accessList = new List<LandAccessEntry>(); 564 List<LandAccessEntry> accessList = new List<LandAccessEntry>();
399 foreach (LandAccessEntry entry in parcel.ParcelAccessList) 565 foreach (LandAccessEntry entry in parcel.ParcelAccessList)
400 { 566 {
401 if (ResolveUserUuid(entry.AgentID)) 567 if (ResolveUserUuid(scene, entry.AgentID))
402 accessList.Add(entry); 568 accessList.Add(entry);
403 // else, drop this access rule 569 // else, drop this access rule
404 } 570 }
@@ -414,23 +580,24 @@ namespace OpenSim.Region.CoreModules.World.Archiver
414 if (!m_merge) 580 if (!m_merge)
415 { 581 {
416 bool setupDefaultParcel = (landData.Count == 0); 582 bool setupDefaultParcel = (landData.Count == 0);
417 m_scene.LandChannel.Clear(setupDefaultParcel); 583 scene.LandChannel.Clear(setupDefaultParcel);
418 } 584 }
419 585
420 m_scene.EventManager.TriggerIncomingLandDataFromStorage(landData); 586 scene.EventManager.TriggerIncomingLandDataFromStorage(landData);
421 m_log.InfoFormat("[ARCHIVER]: Restored {0} parcels.", landData.Count); 587 m_log.InfoFormat("[ARCHIVER]: Restored {0} parcels.", landData.Count);
422 } 588 }
423 589
424 /// <summary> 590 /// <summary>
425 /// Look up the given user id to check whether it's one that is valid for this grid. 591 /// Look up the given user id to check whether it's one that is valid for this grid.
426 /// </summary> 592 /// </summary>
593 /// <param name="scene"></param>
427 /// <param name="uuid"></param> 594 /// <param name="uuid"></param>
428 /// <returns></returns> 595 /// <returns></returns>
429 private bool ResolveUserUuid(UUID uuid) 596 private bool ResolveUserUuid(Scene scene, UUID uuid)
430 { 597 {
431 if (!m_validUserUuids.ContainsKey(uuid)) 598 if (!m_validUserUuids.ContainsKey(uuid))
432 { 599 {
433 UserAccount account = m_scene.UserAccountService.GetUserAccount(m_scene.RegionInfo.ScopeID, uuid); 600 UserAccount account = scene.UserAccountService.GetUserAccount(scene.RegionInfo.ScopeID, uuid);
434 m_validUserUuids.Add(uuid, account != null); 601 m_validUserUuids.Add(uuid, account != null);
435 } 602 }
436 603
@@ -485,7 +652,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver
485 string extension = filename.Substring(i); 652 string extension = filename.Substring(i);
486 string uuid = filename.Remove(filename.Length - extension.Length); 653 string uuid = filename.Remove(filename.Length - extension.Length);
487 654
488 if (m_scene.AssetService.GetMetadata(uuid) != null) 655 if (m_assetService.GetMetadata(uuid) != null)
489 { 656 {
490 // m_log.DebugFormat("[ARCHIVER]: found existing asset {0}",uuid); 657 // m_log.DebugFormat("[ARCHIVER]: found existing asset {0}",uuid);
491 return true; 658 return true;
@@ -505,7 +672,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver
505 672
506 // We're relying on the asset service to do the sensible thing and not store the asset if it already 673 // We're relying on the asset service to do the sensible thing and not store the asset if it already
507 // exists. 674 // exists.
508 m_scene.AssetService.Store(asset); 675 m_assetService.Store(asset);
509 676
510 /** 677 /**
511 * Create layers on decode for image assets. This is likely to significantly increase the time to load archives so 678 * Create layers on decode for image assets. This is likely to significantly increase the time to load archives so
@@ -533,12 +700,14 @@ namespace OpenSim.Region.CoreModules.World.Archiver
533 /// <summary> 700 /// <summary>
534 /// Load region settings data 701 /// Load region settings data
535 /// </summary> 702 /// </summary>
703 /// <param name="scene"></param>
536 /// <param name="settingsPath"></param> 704 /// <param name="settingsPath"></param>
537 /// <param name="data"></param> 705 /// <param name="data"></param>
706 /// <param name="dearchivedScenes"></param>
538 /// <returns> 707 /// <returns>
539 /// true if settings were loaded successfully, false otherwise 708 /// true if settings were loaded successfully, false otherwise
540 /// </returns> 709 /// </returns>
541 private bool LoadRegionSettings(string settingsPath, byte[] data) 710 private bool LoadRegionSettings(Scene scene, string settingsPath, byte[] data, DearchiveScenesInfo dearchivedScenes)
542 { 711 {
543 RegionSettings loadedRegionSettings; 712 RegionSettings loadedRegionSettings;
544 713
@@ -554,7 +723,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver
554 return false; 723 return false;
555 } 724 }
556 725
557 RegionSettings currentRegionSettings = m_scene.RegionInfo.RegionSettings; 726 RegionSettings currentRegionSettings = scene.RegionInfo.RegionSettings;
558 727
559 currentRegionSettings.AgentLimit = loadedRegionSettings.AgentLimit; 728 currentRegionSettings.AgentLimit = loadedRegionSettings.AgentLimit;
560 currentRegionSettings.AllowDamage = loadedRegionSettings.AllowDamage; 729 currentRegionSettings.AllowDamage = loadedRegionSettings.AllowDamage;
@@ -591,12 +760,14 @@ namespace OpenSim.Region.CoreModules.World.Archiver
591 foreach (SpawnPoint sp in loadedRegionSettings.SpawnPoints()) 760 foreach (SpawnPoint sp in loadedRegionSettings.SpawnPoints())
592 currentRegionSettings.AddSpawnPoint(sp); 761 currentRegionSettings.AddSpawnPoint(sp);
593 762
763 currentRegionSettings.LoadedCreationDateTime = dearchivedScenes.LoadedCreationDateTime;
764 currentRegionSettings.LoadedCreationID = dearchivedScenes.GetOriginalRegionID(scene.RegionInfo.RegionID).ToString();
765
594 currentRegionSettings.Save(); 766 currentRegionSettings.Save();
595 767
596 m_scene.TriggerEstateSunUpdate(); 768 scene.TriggerEstateSunUpdate();
597 769
598 IEstateModule estateModule = m_scene.RequestModuleInterface<IEstateModule>(); 770 IEstateModule estateModule = scene.RequestModuleInterface<IEstateModule>();
599
600 if (estateModule != null) 771 if (estateModule != null)
601 estateModule.sendRegionHandshakeToAll(); 772 estateModule.sendRegionHandshakeToAll();
602 773
@@ -606,14 +777,15 @@ namespace OpenSim.Region.CoreModules.World.Archiver
606 /// <summary> 777 /// <summary>
607 /// Load terrain data 778 /// Load terrain data
608 /// </summary> 779 /// </summary>
780 /// <param name="scene"></param>
609 /// <param name="terrainPath"></param> 781 /// <param name="terrainPath"></param>
610 /// <param name="data"></param> 782 /// <param name="data"></param>
611 /// <returns> 783 /// <returns>
612 /// true if terrain was resolved successfully, false otherwise. 784 /// true if terrain was resolved successfully, false otherwise.
613 /// </returns> 785 /// </returns>
614 private bool LoadTerrain(string terrainPath, byte[] data) 786 private bool LoadTerrain(Scene scene, string terrainPath, byte[] data)
615 { 787 {
616 ITerrainModule terrainModule = m_scene.RequestModuleInterface<ITerrainModule>(); 788 ITerrainModule terrainModule = scene.RequestModuleInterface<ITerrainModule>();
617 789
618 MemoryStream ms = new MemoryStream(data); 790 MemoryStream ms = new MemoryStream(data);
619 terrainModule.LoadFromStream(terrainPath, ms); 791 terrainModule.LoadFromStream(terrainPath, ms);
@@ -629,17 +801,18 @@ namespace OpenSim.Region.CoreModules.World.Archiver
629 /// </summary> 801 /// </summary>
630 /// <param name="path"></param> 802 /// <param name="path"></param>
631 /// <param name="data"></param> 803 /// <param name="data"></param>
632 public void LoadControlFile(string path, byte[] data) 804 /// <param name="dearchivedScenes"></param>
805 public DearchiveScenesInfo LoadControlFile(string path, byte[] data, DearchiveScenesInfo dearchivedScenes)
633 { 806 {
634 XmlNamespaceManager nsmgr = new XmlNamespaceManager(new NameTable()); 807 XmlNamespaceManager nsmgr = new XmlNamespaceManager(new NameTable());
635 XmlParserContext context = new XmlParserContext(null, nsmgr, null, XmlSpace.None); 808 XmlParserContext context = new XmlParserContext(null, nsmgr, null, XmlSpace.None);
636 XmlTextReader xtr = new XmlTextReader(Encoding.ASCII.GetString(data), XmlNodeType.Document, context); 809 XmlTextReader xtr = new XmlTextReader(Encoding.ASCII.GetString(data), XmlNodeType.Document, context);
637 810
638 RegionSettings currentRegionSettings = m_scene.RegionInfo.RegionSettings; 811 // Loaded metadata will be empty if no information exists in the archive
812 dearchivedScenes.LoadedCreationDateTime = 0;
813 dearchivedScenes.DefaultOriginalID = "";
639 814
640 // Loaded metadata will empty if no information exists in the archive 815 bool multiRegion = false;
641 currentRegionSettings.LoadedCreationDateTime = 0;
642 currentRegionSettings.LoadedCreationID = "";
643 816
644 while (xtr.Read()) 817 while (xtr.Read())
645 { 818 {
@@ -665,18 +838,44 @@ namespace OpenSim.Region.CoreModules.World.Archiver
665 { 838 {
666 int value; 839 int value;
667 if (Int32.TryParse(xtr.ReadElementContentAsString(), out value)) 840 if (Int32.TryParse(xtr.ReadElementContentAsString(), out value))
668 currentRegionSettings.LoadedCreationDateTime = value; 841 dearchivedScenes.LoadedCreationDateTime = value;
669 } 842 }
670 else if (xtr.Name.ToString() == "id") 843 else if (xtr.Name.ToString() == "row")
844 {
845 multiRegion = true;
846 dearchivedScenes.StartRow();
847 }
848 else if (xtr.Name.ToString() == "region")
671 { 849 {
672 currentRegionSettings.LoadedCreationID = xtr.ReadElementContentAsString(); 850 dearchivedScenes.StartRegion();
851 }
852 else if (xtr.Name.ToString() == "id")
853 {
854 string id = xtr.ReadElementContentAsString();
855 dearchivedScenes.DefaultOriginalID = id;
856 if (multiRegion)
857 dearchivedScenes.SetRegionOriginalID(id);
858 }
859 else if (xtr.Name.ToString() == "dir")
860 {
861 dearchivedScenes.SetRegionDirectory(xtr.ReadElementContentAsString());
673 } 862 }
674 } 863 }
675 } 864 }
676 865
677 currentRegionSettings.Save(); 866 dearchivedScenes.MultiRegionFormat = multiRegion;
678 867 if (!multiRegion)
868 {
869 // Add the single scene
870 dearchivedScenes.StartRow();
871 dearchivedScenes.StartRegion();
872 dearchivedScenes.SetRegionOriginalID(dearchivedScenes.DefaultOriginalID);
873 dearchivedScenes.SetRegionDirectory("");
874 }
875
679 ControlFileLoaded = true; 876 ControlFileLoaded = true;
877
878 return dearchivedScenes;
680 } 879 }
681 } 880 }
682} \ No newline at end of file 881} \ No newline at end of file
diff --git a/OpenSim/Region/CoreModules/World/Archiver/ArchiveScenesGroup.cs b/OpenSim/Region/CoreModules/World/Archiver/ArchiveScenesGroup.cs
new file mode 100644
index 0000000..a66ed88
--- /dev/null
+++ b/OpenSim/Region/CoreModules/World/Archiver/ArchiveScenesGroup.cs
@@ -0,0 +1,176 @@
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
28using System;
29using System.Collections.Generic;
30using System.Linq;
31using System.Text;
32using OpenSim.Region.Framework.Scenes;
33using OpenMetaverse;
34using System.Drawing;
35
36namespace OpenSim.Region.CoreModules.World.Archiver
37{
38 /// <summary>
39 /// A group of regions arranged in a rectangle, possibly with holes.
40 /// </summary>
41 /// <remarks>
42 /// The regions usually (but not necessarily) belong to an archive file, in which case we
43 /// store additional information used to create the archive (e.g., each region's
44 /// directory within the archive).
45 /// </remarks>
46 public class ArchiveScenesGroup
47 {
48 /// <summary>
49 /// All the regions. The outer dictionary contains rows (key: Y coordinate).
50 /// The inner dictionaries contain each row's regions (key: X coordinate).
51 /// </summary>
52 public SortedDictionary<uint, SortedDictionary<uint, Scene>> Regions { get; set; }
53
54 /// <summary>
55 /// The subdirectory where each region is stored in the archive.
56 /// </summary>
57 protected Dictionary<UUID, string> m_regionDirs;
58
59 /// <summary>
60 /// The grid coordinates of the regions' bounding box.
61 /// </summary>
62 public Rectangle Rect { get; set; }
63
64
65 public ArchiveScenesGroup()
66 {
67 Regions = new SortedDictionary<uint, SortedDictionary<uint, Scene>>();
68 m_regionDirs = new Dictionary<UUID, string>();
69 Rect = new Rectangle(0, 0, 0, 0);
70 }
71
72 public void AddScene(Scene scene)
73 {
74 uint x = scene.RegionInfo.RegionLocX;
75 uint y = scene.RegionInfo.RegionLocY;
76
77 SortedDictionary<uint, Scene> row;
78 if (!Regions.TryGetValue(y, out row))
79 {
80 row = new SortedDictionary<uint, Scene>();
81 Regions[y] = row;
82 }
83
84 row[x] = scene;
85 }
86
87 /// <summary>
88 /// Called after all the scenes have been added. Performs calculations that require
89 /// knowledge of all the scenes.
90 /// </summary>
91 public void CalcSceneLocations()
92 {
93 if (Regions.Count == 0)
94 return;
95
96 // Find the bounding rectangle
97
98 uint firstY = Regions.First().Key;
99 uint lastY = Regions.Last().Key;
100
101 uint? firstX = null;
102 uint? lastX = null;
103
104 foreach (SortedDictionary<uint, Scene> row in Regions.Values)
105 {
106 uint curFirstX = row.First().Key;
107 uint curLastX = row.Last().Key;
108
109 firstX = (firstX == null) ? curFirstX : (firstX < curFirstX) ? firstX : curFirstX;
110 lastX = (lastX == null) ? curLastX : (lastX > curLastX) ? lastX : curLastX;
111 }
112
113 Rect = new Rectangle((int)firstX, (int)firstY, (int)(lastY - firstY + 1), (int)(lastX - firstX + 1));
114
115
116 // Calculate the subdirectory in which each region will be stored in the archive
117
118 m_regionDirs.Clear();
119 ForEachScene(delegate(Scene scene)
120 {
121 // We add the region's coordinates to ensure uniqueness even if multiple regions have the same name
122 string path = string.Format("{0}_{1}_{2}",
123 scene.RegionInfo.RegionLocX - Rect.X + 1,
124 scene.RegionInfo.RegionLocY - Rect.Y + 1,
125 scene.RegionInfo.RegionName.Replace(' ', '_'));
126 m_regionDirs[scene.RegionInfo.RegionID] = path;
127 });
128 }
129
130 /// <summary>
131 /// Returns the subdirectory where the region is stored.
132 /// </summary>
133 /// <param name="regionID"></param>
134 /// <returns></returns>
135 public string GetRegionDir(UUID regionID)
136 {
137 return m_regionDirs[regionID];
138 }
139
140 /// <summary>
141 /// Performs an action on all the scenes in this order: rows from South to North,
142 /// and within each row West to East.
143 /// </summary>
144 /// <param name="action"></param>
145 public void ForEachScene(Action<Scene> action)
146 {
147 foreach (SortedDictionary<uint, Scene> row in Regions.Values)
148 {
149 foreach (Scene scene in row.Values)
150 {
151 action(scene);
152 }
153 }
154 }
155
156 /// <summary>
157 /// Returns the scene at position 'location'.
158 /// </summary>
159 /// <param name="location">A location in the grid</param>
160 /// <param name="scene">The scene at this location</param>
161 /// <returns>Whether the scene was found</returns>
162 public bool TryGetScene(Point location, out Scene scene)
163 {
164 SortedDictionary<uint, Scene> row;
165 if (Regions.TryGetValue((uint)location.Y, out row))
166 {
167 if (row.TryGetValue((uint)location.X, out scene))
168 return true;
169 }
170
171 scene = null;
172 return false;
173 }
174
175 }
176}
diff --git a/OpenSim/Region/CoreModules/World/Archiver/ArchiveWriteRequestExecution.cs b/OpenSim/Region/CoreModules/World/Archiver/ArchiveWriteRequestExecution.cs
deleted file mode 100644
index 0780d86..0000000
--- a/OpenSim/Region/CoreModules/World/Archiver/ArchiveWriteRequestExecution.cs
+++ /dev/null
@@ -1,153 +0,0 @@
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
28using System;
29using System.Collections.Generic;
30using System.IO;
31using System.Reflection;
32using System.Xml;
33using log4net;
34using OpenMetaverse;
35using OpenSim.Framework;
36using OpenSim.Framework.Serialization;
37using OpenSim.Framework.Serialization.External;
38using OpenSim.Region.CoreModules.World.Terrain;
39using OpenSim.Region.Framework.Interfaces;
40using OpenSim.Region.Framework.Scenes;
41
42namespace OpenSim.Region.CoreModules.World.Archiver
43{
44 /// <summary>
45 /// Method called when all the necessary assets for an archive request have been received.
46 /// </summary>
47 public delegate void AssetsRequestCallback(
48 ICollection<UUID> assetsFoundUuids, ICollection<UUID> assetsNotFoundUuids);
49
50 /// <summary>
51 /// Execute the write of an archive once we have received all the necessary data
52 /// </summary>
53 public class ArchiveWriteRequestExecution
54 {
55 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
56
57 protected ITerrainModule m_terrainModule;
58 protected IRegionSerialiserModule m_serialiser;
59 protected List<SceneObjectGroup> m_sceneObjects;
60 protected Scene m_scene;
61 protected TarArchiveWriter m_archiveWriter;
62 protected Guid m_requestId;
63 protected Dictionary<string, object> m_options;
64
65 public ArchiveWriteRequestExecution(
66 List<SceneObjectGroup> sceneObjects,
67 ITerrainModule terrainModule,
68 IRegionSerialiserModule serialiser,
69 Scene scene,
70 TarArchiveWriter archiveWriter,
71 Guid requestId,
72 Dictionary<string, object> options)
73 {
74 m_sceneObjects = sceneObjects;
75 m_terrainModule = terrainModule;
76 m_serialiser = serialiser;
77 m_scene = scene;
78 m_archiveWriter = archiveWriter;
79 m_requestId = requestId;
80 m_options = options;
81 }
82
83 protected internal void ReceivedAllAssets(
84 ICollection<UUID> assetsFoundUuids, ICollection<UUID> assetsNotFoundUuids)
85 {
86 try
87 {
88 Save(assetsFoundUuids, assetsNotFoundUuids);
89 }
90 finally
91 {
92 m_archiveWriter.Close();
93 }
94
95 m_log.InfoFormat("[ARCHIVER]: Finished writing out OAR for {0}", m_scene.RegionInfo.RegionName);
96
97 m_scene.EventManager.TriggerOarFileSaved(m_requestId, String.Empty);
98 }
99
100 protected internal void Save(ICollection<UUID> assetsFoundUuids, ICollection<UUID> assetsNotFoundUuids)
101 {
102 foreach (UUID uuid in assetsNotFoundUuids)
103 {
104 m_log.DebugFormat("[ARCHIVER]: Could not find asset {0}", uuid);
105 }
106
107// m_log.InfoFormat(
108// "[ARCHIVER]: Received {0} of {1} assets requested",
109// assetsFoundUuids.Count, assetsFoundUuids.Count + assetsNotFoundUuids.Count);
110
111 m_log.InfoFormat("[ARCHIVER]: Adding region settings to archive.");
112
113 // Write out region settings
114 string settingsPath
115 = String.Format("{0}{1}.xml", ArchiveConstants.SETTINGS_PATH, m_scene.RegionInfo.RegionName);
116 m_archiveWriter.WriteFile(settingsPath, RegionSettingsSerializer.Serialize(m_scene.RegionInfo.RegionSettings));
117
118 m_log.InfoFormat("[ARCHIVER]: Adding parcel settings to archive.");
119
120 // Write out land data (aka parcel) settings
121 List<ILandObject>landObjects = m_scene.LandChannel.AllParcels();
122 foreach (ILandObject lo in landObjects)
123 {
124 LandData landData = lo.LandData;
125 string landDataPath = String.Format("{0}{1}.xml", ArchiveConstants.LANDDATA_PATH,
126 landData.GlobalID.ToString());
127 m_archiveWriter.WriteFile(landDataPath, LandDataSerializer.Serialize(landData, m_options));
128 }
129
130 m_log.InfoFormat("[ARCHIVER]: Adding terrain information to archive.");
131
132 // Write out terrain
133 string terrainPath
134 = String.Format("{0}{1}.r32", ArchiveConstants.TERRAINS_PATH, m_scene.RegionInfo.RegionName);
135
136 MemoryStream ms = new MemoryStream();
137 m_terrainModule.SaveToStream(terrainPath, ms);
138 m_archiveWriter.WriteFile(terrainPath, ms.ToArray());
139 ms.Close();
140
141 m_log.InfoFormat("[ARCHIVER]: Adding scene objects to archive.");
142
143 // Write out scene object metadata
144 foreach (SceneObjectGroup sceneObject in m_sceneObjects)
145 {
146 //m_log.DebugFormat("[ARCHIVER]: Saving {0} {1}, {2}", entity.Name, entity.UUID, entity.GetType());
147
148 string serializedObject = m_serialiser.SerializeGroupToXml2(sceneObject, m_options);
149 m_archiveWriter.WriteFile(ArchiveHelpers.CreateObjectPath(sceneObject), serializedObject);
150 }
151 }
152 }
153} \ No newline at end of file
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}
diff --git a/OpenSim/Region/CoreModules/World/Archiver/ArchiverModule.cs b/OpenSim/Region/CoreModules/World/Archiver/ArchiverModule.cs
index bf3b124..26535a9 100644
--- a/OpenSim/Region/CoreModules/World/Archiver/ArchiverModule.cs
+++ b/OpenSim/Region/CoreModules/World/Archiver/ArchiverModule.cs
@@ -146,6 +146,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver
146 ops.Add("noassets", delegate(string v) { options["noassets"] = v != null; }); 146 ops.Add("noassets", delegate(string v) { options["noassets"] = v != null; });
147 ops.Add("publish", v => options["wipe-owners"] = v != null); 147 ops.Add("publish", v => options["wipe-owners"] = v != null);
148 ops.Add("perm=", delegate(string v) { options["checkPermissions"] = v; }); 148 ops.Add("perm=", delegate(string v) { options["checkPermissions"] = v; });
149 ops.Add("all", delegate(string v) { options["all"] = v != null; });
149 150
150 List<string> mainParams = ops.Parse(cmdparams); 151 List<string> mainParams = ops.Parse(cmdparams);
151 152
@@ -169,7 +170,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver
169 m_log.InfoFormat( 170 m_log.InfoFormat(
170 "[ARCHIVER]: Writing archive for region {0} to {1}", Scene.RegionInfo.RegionName, savePath); 171 "[ARCHIVER]: Writing archive for region {0} to {1}", Scene.RegionInfo.RegionName, savePath);
171 172
172 new ArchiveWriteRequestPreparation(this, savePath, requestId).ArchiveRegion(options); 173 new ArchiveWriteRequestPreparation(Scene, savePath, requestId).ArchiveRegion(options);
173 } 174 }
174 175
175 public void ArchiveRegion(Stream saveStream) 176 public void ArchiveRegion(Stream saveStream)
@@ -184,7 +185,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver
184 185
185 public void ArchiveRegion(Stream saveStream, Guid requestId, Dictionary<string, object> options) 186 public void ArchiveRegion(Stream saveStream, Guid requestId, Dictionary<string, object> options)
186 { 187 {
187 new ArchiveWriteRequestPreparation(this, saveStream, requestId).ArchiveRegion(options); 188 new ArchiveWriteRequestPreparation(Scene, saveStream, requestId).ArchiveRegion(options);
188 } 189 }
189 190
190 public void DearchiveRegion(string loadPath) 191 public void DearchiveRegion(string loadPath)
diff --git a/OpenSim/Region/CoreModules/World/Archiver/AssetsRequest.cs b/OpenSim/Region/CoreModules/World/Archiver/AssetsRequest.cs
index a073cb9..5787279 100644
--- a/OpenSim/Region/CoreModules/World/Archiver/AssetsRequest.cs
+++ b/OpenSim/Region/CoreModules/World/Archiver/AssetsRequest.cs
@@ -46,6 +46,12 @@ namespace OpenSim.Region.CoreModules.World.Archiver
46 { 46 {
47 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 47 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
48 48
49 /// <summary>
50 /// Method called when all the necessary assets for an archive request have been received.
51 /// </summary>
52 public delegate void AssetsRequestCallback(
53 ICollection<UUID> assetsFoundUuids, ICollection<UUID> assetsNotFoundUuids);
54
49 enum RequestState 55 enum RequestState
50 { 56 {
51 Initial, 57 Initial,
diff --git a/OpenSim/Region/CoreModules/World/Archiver/DearchiveScenesGroup.cs b/OpenSim/Region/CoreModules/World/Archiver/DearchiveScenesGroup.cs
new file mode 100644
index 0000000..3dcc020
--- /dev/null
+++ b/OpenSim/Region/CoreModules/World/Archiver/DearchiveScenesGroup.cs
@@ -0,0 +1,232 @@
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
28using System;
29using System.Collections.Generic;
30using System.Linq;
31using System.Text;
32using OpenSim.Region.Framework.Scenes;
33using OpenMetaverse;
34using System.Drawing;
35using log4net;
36using System.Reflection;
37using OpenSim.Framework.Serialization;
38
39namespace OpenSim.Region.CoreModules.World.Archiver
40{
41 /// <summary>
42 /// The regions included in an OAR file.
43 /// </summary>
44 public class DearchiveScenesInfo
45 {
46 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
47
48 /// <summary>
49 /// One region in the archive.
50 /// </summary>
51 public class RegionInfo
52 {
53 /// <summary>
54 /// The subdirectory in which the region is stored.
55 /// </summary>
56 public string Directory { get; set; }
57
58 /// <summary>
59 /// The region's coordinates (relative to the South-West corner of the block).
60 /// </summary>
61 public Point Location { get; set; }
62
63 /// <summary>
64 /// The UUID of the original scene from which this archived region was saved.
65 /// </summary>
66 public string OriginalID { get; set; }
67
68 /// <summary>
69 /// The scene in the current simulator into which this region is loaded.
70 /// If null then the region doesn't have a corresponding scene, and it won't be loaded.
71 /// </summary>
72 public Scene Scene { get; set; }
73 }
74
75 /// <summary>
76 /// Whether this archive uses the multi-region format.
77 /// </summary>
78 public Boolean MultiRegionFormat { get; set; }
79
80 /// <summary>
81 /// Maps (Region directory -> region)
82 /// </summary>
83 protected Dictionary<string, RegionInfo> m_directory2region = new Dictionary<string, RegionInfo>();
84
85 /// <summary>
86 /// Maps (UUID of the scene in the simulator where the region will be loaded -> region)
87 /// </summary>
88 protected Dictionary<UUID, RegionInfo> m_newId2region = new Dictionary<UUID, RegionInfo>();
89
90 public int LoadedCreationDateTime { get; set; }
91 public string DefaultOriginalID { get; set; }
92
93 // These variables are used while reading the archive control file
94 protected int? m_curY = null;
95 protected int? m_curX = null;
96 protected RegionInfo m_curRegion;
97
98
99 public DearchiveScenesInfo()
100 {
101 MultiRegionFormat = false;
102 }
103
104
105 // The following methods are used while reading the archive control file
106
107 public void StartRow()
108 {
109 m_curY = (m_curY == null) ? 0 : m_curY + 1;
110 m_curX = null;
111 }
112
113 public void StartRegion()
114 {
115 m_curX = (m_curX == null) ? 0 : m_curX + 1;
116 // Note: this doesn't mean we have a real region in this location; this could just be a "hole"
117 }
118
119 public void SetRegionOriginalID(string id)
120 {
121 m_curRegion = new RegionInfo();
122 m_curRegion.Location = new Point((int)m_curX, (int)m_curY);
123 m_curRegion.OriginalID = id;
124 // 'curRegion' will be saved in 'm_directory2region' when SetRegionDir() is called
125 }
126
127 public void SetRegionDirectory(string directory)
128 {
129 m_curRegion.Directory = directory;
130 m_directory2region[directory] = m_curRegion;
131 }
132
133
134 /// <summary>
135 /// Sets all the scenes present in the simulator.
136 /// </summary>
137 /// <remarks>
138 /// This method matches regions in the archive to scenes in the simulator according to
139 /// their relative position. We only load regions if there's an existing Scene in the
140 /// grid location where the region should be loaded.
141 /// </remarks>
142 /// <param name="rootScene">The scene where the Load OAR operation was run</param>
143 /// <param name="simulatorScenes">All the scenes in the simulator</param>
144 public void SetSimulatorScenes(Scene rootScene, ArchiveScenesGroup simulatorScenes)
145 {
146 foreach (RegionInfo archivedRegion in m_directory2region.Values)
147 {
148 Point location = new Point((int)rootScene.RegionInfo.RegionLocX, (int)rootScene.RegionInfo.RegionLocY);
149 location.Offset(archivedRegion.Location);
150
151 Scene scene;
152 if (simulatorScenes.TryGetScene(location, out scene))
153 {
154 archivedRegion.Scene = scene;
155 m_newId2region[scene.RegionInfo.RegionID] = archivedRegion;
156 }
157 else
158 {
159 m_log.WarnFormat("[ARCHIVER]: Not loading archived region {0} because there's no existing region at location {1},{2}",
160 archivedRegion.Directory, location.X, location.Y);
161 }
162 }
163 }
164
165 /// <summary>
166 /// Returns the archived region according to the path of a file in the archive.
167 /// Also, converts the full path into a path that is relative to the region's directory.
168 /// </summary>
169 /// <param name="fullPath">The path of a file in the archive</param>
170 /// <param name="scene">The corresponding Scene, or null if none</param>
171 /// <param name="relativePath">The path relative to the region's directory. (Or the original
172 /// path, if this file doesn't belong to a region.)</param>
173 /// <returns>True: use this file; False: skip it</returns>
174 public bool GetRegionFromPath(string fullPath, out Scene scene, out string relativePath)
175 {
176 scene = null;
177 relativePath = fullPath;
178
179 if (!MultiRegionFormat)
180 {
181 if (m_newId2region.Count > 0)
182 scene = m_newId2region.First().Value.Scene;
183 return true;
184 }
185
186 if (!fullPath.StartsWith(ArchiveConstants.REGIONS_PATH))
187 return true; // this file doesn't belong to a region
188
189 string[] parts = fullPath.Split(new Char[] { '/' }, 3);
190 if (parts.Length != 3)
191 return false;
192 string regionDirectory = parts[1];
193 relativePath = parts[2];
194
195 RegionInfo region;
196 if (m_directory2region.TryGetValue(regionDirectory, out region))
197 {
198 scene = region.Scene;
199 return (scene != null);
200 }
201 else
202 {
203 return false;
204 }
205 }
206
207 /// <summary>
208 /// Returns the original UUID of a region (from the simulator where the OAR was saved),
209 /// given the UUID of the scene it was loaded into in the current simulator.
210 /// </summary>
211 /// <param name="newID"></param>
212 /// <returns></returns>
213 public string GetOriginalRegionID(UUID newID)
214 {
215 RegionInfo region;
216 if (m_newId2region.TryGetValue(newID, out region))
217 return region.OriginalID;
218 else
219 return DefaultOriginalID;
220 }
221
222 /// <summary>
223 /// Returns the scenes that have been (or will be) loaded.
224 /// </summary>
225 /// <returns></returns>
226 public List<UUID> GetLoadedScenes()
227 {
228 return m_newId2region.Keys.ToList();
229 }
230
231 }
232}
diff --git a/OpenSim/Region/CoreModules/World/Archiver/Tests/ArchiverTests.cs b/OpenSim/Region/CoreModules/World/Archiver/Tests/ArchiverTests.cs
index 904110e..cfdfd8c 100644
--- a/OpenSim/Region/CoreModules/World/Archiver/Tests/ArchiverTests.cs
+++ b/OpenSim/Region/CoreModules/World/Archiver/Tests/ArchiverTests.cs
@@ -47,6 +47,7 @@ using ArchiveConstants = OpenSim.Framework.Serialization.ArchiveConstants;
47using TarArchiveReader = OpenSim.Framework.Serialization.TarArchiveReader; 47using TarArchiveReader = OpenSim.Framework.Serialization.TarArchiveReader;
48using TarArchiveWriter = OpenSim.Framework.Serialization.TarArchiveWriter; 48using TarArchiveWriter = OpenSim.Framework.Serialization.TarArchiveWriter;
49using RegionSettings = OpenSim.Framework.RegionSettings; 49using RegionSettings = OpenSim.Framework.RegionSettings;
50using OpenSim.Region.Framework.Interfaces;
50 51
51namespace OpenSim.Region.CoreModules.World.Archiver.Tests 52namespace OpenSim.Region.CoreModules.World.Archiver.Tests
52{ 53{
@@ -70,9 +71,12 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests
70 71
71 m_scene = new SceneHelpers().SetupScene(); 72 m_scene = new SceneHelpers().SetupScene();
72 SceneHelpers.SetupSceneModules(m_scene, m_archiverModule, serialiserModule, terrainModule); 73 SceneHelpers.SetupSceneModules(m_scene, m_archiverModule, serialiserModule, terrainModule);
74
75 new SceneManager();
76 SceneManager.Instance.Add(m_scene);
73 } 77 }
74 78
75 private void LoadCompleted(Guid requestId, string errorMessage) 79 private void LoadCompleted(Guid requestId, List<UUID> loadedScenes, string errorMessage)
76 { 80 {
77 lock (this) 81 lock (this)
78 { 82 {
@@ -186,7 +190,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests
186 Assert.That(filePath, Is.EqualTo(ArchiveConstants.CONTROL_FILE_PATH)); 190 Assert.That(filePath, Is.EqualTo(ArchiveConstants.CONTROL_FILE_PATH));
187 191
188 ArchiveReadRequest arr = new ArchiveReadRequest(m_scene, (Stream)null, false, false, Guid.Empty); 192 ArchiveReadRequest arr = new ArchiveReadRequest(m_scene, (Stream)null, false, false, Guid.Empty);
189 arr.LoadControlFile(filePath, data); 193 arr.LoadControlFile(filePath, data, new DearchiveScenesInfo());
190 194
191 Assert.That(arr.ControlFileLoaded, Is.True); 195 Assert.That(arr.ControlFileLoaded, Is.True);
192 196
@@ -270,7 +274,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests
270 Assert.That(filePath, Is.EqualTo(ArchiveConstants.CONTROL_FILE_PATH)); 274 Assert.That(filePath, Is.EqualTo(ArchiveConstants.CONTROL_FILE_PATH));
271 275
272 ArchiveReadRequest arr = new ArchiveReadRequest(m_scene, (Stream)null, false, false, Guid.Empty); 276 ArchiveReadRequest arr = new ArchiveReadRequest(m_scene, (Stream)null, false, false, Guid.Empty);
273 arr.LoadControlFile(filePath, data); 277 arr.LoadControlFile(filePath, data, new DearchiveScenesInfo());
274 278
275 Assert.That(arr.ControlFileLoaded, Is.True); 279 Assert.That(arr.ControlFileLoaded, Is.True);
276 280
@@ -307,7 +311,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests
307 311
308 tar.WriteFile( 312 tar.WriteFile(
309 ArchiveConstants.CONTROL_FILE_PATH, 313 ArchiveConstants.CONTROL_FILE_PATH,
310 new ArchiveWriteRequestPreparation(null, (Stream)null, Guid.Empty).CreateControlFile(new Dictionary<string, Object>())); 314 new ArchiveWriteRequestPreparation(m_scene, (Stream)null, Guid.Empty).CreateControlFile(new ArchiveScenesGroup()));
311 315
312 SceneObjectGroup sog1 = SceneHelpers.CreateSceneObject(1, ownerId, "obj1-", 0x11); 316 SceneObjectGroup sog1 = SceneHelpers.CreateSceneObject(1, ownerId, "obj1-", 0x11);
313 SceneObjectPart sop2 317 SceneObjectPart sop2
@@ -362,11 +366,10 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests
362 // Also check that direct entries which will also have a file entry containing that directory doesn't 366 // Also check that direct entries which will also have a file entry containing that directory doesn't
363 // upset load 367 // upset load
364 tar.WriteDir(ArchiveConstants.TERRAINS_PATH); 368 tar.WriteDir(ArchiveConstants.TERRAINS_PATH);
365 369
366 tar.WriteFile( 370 tar.WriteFile(
367 ArchiveConstants.CONTROL_FILE_PATH, 371 ArchiveConstants.CONTROL_FILE_PATH,
368 new ArchiveWriteRequestPreparation(null, (Stream)null, Guid.Empty).CreateControlFile(new Dictionary<string, Object>())); 372 new ArchiveWriteRequestPreparation(m_scene, (Stream)null, Guid.Empty).CreateControlFile(new ArchiveScenesGroup()));
369
370 SceneObjectPart part1 = CreateSceneObjectPart1(); 373 SceneObjectPart part1 = CreateSceneObjectPart1();
371 374
372 part1.SitTargetOrientation = new Quaternion(0.2f, 0.3f, 0.4f, 0.5f); 375 part1.SitTargetOrientation = new Quaternion(0.2f, 0.3f, 0.4f, 0.5f);
@@ -519,6 +522,8 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests
519 TestScene scene2 = new SceneHelpers().SetupScene(); 522 TestScene scene2 = new SceneHelpers().SetupScene();
520 SceneHelpers.SetupSceneModules(scene2, archiverModule, serialiserModule, terrainModule); 523 SceneHelpers.SetupSceneModules(scene2, archiverModule, serialiserModule, terrainModule);
521 524
525 SceneManager.Instance.Add(scene2);
526
522 // Make sure there's a valid owner for the owner we saved (this should have been wiped if the code is 527 // Make sure there's a valid owner for the owner we saved (this should have been wiped if the code is
523 // behaving correctly 528 // behaving correctly
524 UserAccountHelpers.CreateUserWithInventory(scene2, objectOwner); 529 UserAccountHelpers.CreateUserWithInventory(scene2, objectOwner);
@@ -554,7 +559,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests
554 tar.WriteDir(ArchiveConstants.TERRAINS_PATH); 559 tar.WriteDir(ArchiveConstants.TERRAINS_PATH);
555 tar.WriteFile( 560 tar.WriteFile(
556 ArchiveConstants.CONTROL_FILE_PATH, 561 ArchiveConstants.CONTROL_FILE_PATH,
557 new ArchiveWriteRequestPreparation(null, (Stream)null, Guid.Empty).CreateControlFile(new Dictionary<string, Object>())); 562 new ArchiveWriteRequestPreparation(m_scene, (Stream)null, Guid.Empty).CreateControlFile(new ArchiveScenesGroup()));
558 563
559 RegionSettings rs = new RegionSettings(); 564 RegionSettings rs = new RegionSettings();
560 rs.AgentLimit = 17; 565 rs.AgentLimit = 17;
diff --git a/OpenSim/Region/Framework/Interfaces/IEstateModule.cs b/OpenSim/Region/Framework/Interfaces/IEstateModule.cs
index 15cd238..1983984 100644
--- a/OpenSim/Region/Framework/Interfaces/IEstateModule.cs
+++ b/OpenSim/Region/Framework/Interfaces/IEstateModule.cs
@@ -46,6 +46,11 @@ namespace OpenSim.Region.Framework.Interfaces
46 /// </summary> 46 /// </summary>
47 void sendRegionHandshakeToAll(); 47 void sendRegionHandshakeToAll();
48 48
49 /// <summary>
50 /// Fires the OnRegionInfoChange event.
51 /// </summary>
52 void TriggerRegionInfoChange();
53
49 void setEstateTerrainBaseTexture(int level, UUID texture); 54 void setEstateTerrainBaseTexture(int level, UUID texture);
50 void setEstateTerrainTextureHeights(int corner, float lowValue, float highValue); 55 void setEstateTerrainTextureHeights(int corner, float lowValue, float highValue);
51 } 56 }
diff --git a/OpenSim/Region/Framework/Scenes/EventManager.cs b/OpenSim/Region/Framework/Scenes/EventManager.cs
index 2f34785..e1c9c8e 100644
--- a/OpenSim/Region/Framework/Scenes/EventManager.cs
+++ b/OpenSim/Region/Framework/Scenes/EventManager.cs
@@ -531,7 +531,7 @@ namespace OpenSim.Region.Framework.Scenes
531 /// the scripts may not have started yet 531 /// the scripts may not have started yet
532 /// Message is non empty string if there were problems loading the oar file 532 /// Message is non empty string if there were problems loading the oar file
533 /// </summary> 533 /// </summary>
534 public delegate void OarFileLoaded(Guid guid, string message); 534 public delegate void OarFileLoaded(Guid guid, List<UUID> loadedScenes, string message);
535 public event OarFileLoaded OnOarFileLoaded; 535 public event OarFileLoaded OnOarFileLoaded;
536 536
537 /// <summary> 537 /// <summary>
@@ -2195,7 +2195,7 @@ namespace OpenSim.Region.Framework.Scenes
2195 return 6; 2195 return 6;
2196 } 2196 }
2197 2197
2198 public void TriggerOarFileLoaded(Guid requestId, string message) 2198 public void TriggerOarFileLoaded(Guid requestId, List<UUID> loadedScenes, string message)
2199 { 2199 {
2200 OarFileLoaded handlerOarFileLoaded = OnOarFileLoaded; 2200 OarFileLoaded handlerOarFileLoaded = OnOarFileLoaded;
2201 if (handlerOarFileLoaded != null) 2201 if (handlerOarFileLoaded != null)
@@ -2204,7 +2204,7 @@ namespace OpenSim.Region.Framework.Scenes
2204 { 2204 {
2205 try 2205 try
2206 { 2206 {
2207 d(requestId, message); 2207 d(requestId, loadedScenes, message);
2208 } 2208 }
2209 catch (Exception e) 2209 catch (Exception e)
2210 { 2210 {
diff --git a/OpenSim/Region/OptionalModules/Scripting/RegionReadyModule/RegionReadyModule.cs b/OpenSim/Region/OptionalModules/Scripting/RegionReadyModule/RegionReadyModule.cs
index fff3a32..bad75f7 100644
--- a/OpenSim/Region/OptionalModules/Scripting/RegionReadyModule/RegionReadyModule.cs
+++ b/OpenSim/Region/OptionalModules/Scripting/RegionReadyModule/RegionReadyModule.cs
@@ -181,7 +181,7 @@ namespace OpenSim.Region.OptionalModules.Scripting.RegionReady
181 } 181 }
182 } 182 }
183 183
184 void OnOarFileLoaded(Guid requestId, string message) 184 void OnOarFileLoaded(Guid requestId, List<UUID> loadedScenes, string message)
185 { 185 {
186 m_oarFileLoading = true; 186 m_oarFileLoading = true;
187 187