aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim')
-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