diff --git a/OpenSim/Region/CoreModules/World/Archiver/ArchiveReadRequest.cs b/OpenSim/Region/CoreModules/World/Archiver/ArchiveReadRequest.cs
index 3218abc695..0cc1f86951 100644
--- a/OpenSim/Region/CoreModules/World/Archiver/ArchiveReadRequest.cs
+++ b/OpenSim/Region/CoreModules/World/Archiver/ArchiveReadRequest.cs
@@ -51,26 +51,33 @@ namespace OpenSim.Region.CoreModules.World.Archiver
private static System.Text.ASCIIEncoding m_asciiEncoding = new System.Text.ASCIIEncoding();
- private Scene m_scene;
+ private Scene m_scene;
private Stream m_loadStream;
private string m_errorMessage;
+
+ ///
+ /// Should the archive being loaded be merged with what is already on the region?
+ ///
+ private bool m_merge;
///
/// Used to cache lookups for valid uuids.
///
private IDictionary m_validUserUuids = new Dictionary();
- public ArchiveReadRequest(Scene scene, string loadPath)
+ public ArchiveReadRequest(Scene scene, string loadPath, bool merge)
{
m_scene = scene;
m_loadStream = new GZipStream(GetStream(loadPath), CompressionMode.Decompress);
m_errorMessage = String.Empty;
+ m_merge = merge;
}
- public ArchiveReadRequest(Scene scene, Stream loadStream)
+ public ArchiveReadRequest(Scene scene, Stream loadStream, bool merge)
{
m_scene = scene;
m_loadStream = loadStream;
+ m_merge = merge;
}
///
@@ -92,8 +99,6 @@ namespace OpenSim.Region.CoreModules.World.Archiver
{
TarArchiveReader archive = new TarArchiveReader(m_loadStream);
- //AssetsDearchiver dearchiver = new AssetsDearchiver(m_scene.AssetCache);
-
string filePath = "ERROR";
byte[] data;
@@ -103,6 +108,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver
{
//m_log.DebugFormat(
// "[ARCHIVER]: Successfully read {0} ({1} bytes)}", filePath, data.Length);
+
if (TarArchiveReader.TarEntryType.TYPE_DIRECTORY == entryType)
{
m_log.WarnFormat("[ARCHIVER]: Ignoring directory entry {0}",
@@ -112,11 +118,6 @@ namespace OpenSim.Region.CoreModules.World.Archiver
{
serialisedSceneObjects.Add(m_asciiEncoding.GetString(data));
}
-// else if (filePath.Equals(ArchiveConstants.ASSETS_METADATA_PATH))
-// {
-// string xml = m_asciiEncoding.GetString(data);
-// dearchiver.AddAssetMetadata(xml);
-// }
else if (filePath.StartsWith(ArchiveConstants.ASSETS_PATH))
{
if (LoadAsset(filePath, data))
@@ -124,11 +125,11 @@ namespace OpenSim.Region.CoreModules.World.Archiver
else
failedAssetRestores++;
}
- else if (filePath.StartsWith(ArchiveConstants.TERRAINS_PATH))
+ else if (!m_merge && filePath.StartsWith(ArchiveConstants.TERRAINS_PATH))
{
LoadTerrain(filePath, data);
}
- else if (filePath.StartsWith(ArchiveConstants.SETTINGS_PATH))
+ else if (!m_merge && filePath.StartsWith(ArchiveConstants.SETTINGS_PATH))
{
LoadRegionSettings(filePath, data);
}
@@ -155,8 +156,11 @@ namespace OpenSim.Region.CoreModules.World.Archiver
m_errorMessage += String.Format("Failed to load {0} assets", failedAssetRestores);
}
- m_log.Info("[ARCHIVER]: Clearing all existing scene objects");
- m_scene.DeleteAllSceneObjects();
+ if (!m_merge)
+ {
+ m_log.Info("[ARCHIVER]: Clearing all existing scene objects");
+ m_scene.DeleteAllSceneObjects();
+ }
// Reload serialized prims
m_log.InfoFormat("[ARCHIVER]: Loading {0} scene objects. Please wait.", serialisedSceneObjects.Count);
@@ -182,13 +186,13 @@ namespace OpenSim.Region.CoreModules.World.Archiver
foreach (SceneObjectPart part in sceneObject.Children.Values)
{
- if (!resolveUserUuid(part.CreatorID))
+ if (!ResolveUserUuid(part.CreatorID))
part.CreatorID = masterAvatarId;
- if (!resolveUserUuid(part.OwnerID))
+ if (!ResolveUserUuid(part.OwnerID))
part.OwnerID = masterAvatarId;
- if (!resolveUserUuid(part.LastOwnerID))
+ if (!ResolveUserUuid(part.LastOwnerID))
part.LastOwnerID = masterAvatarId;
// And zap any troublesome sit target information
@@ -201,11 +205,11 @@ namespace OpenSim.Region.CoreModules.World.Archiver
TaskInventoryDictionary inv = part.TaskInventory;
foreach (KeyValuePair kvp in inv)
{
- if (!resolveUserUuid(kvp.Value.OwnerID))
+ if (!ResolveUserUuid(kvp.Value.OwnerID))
{
kvp.Value.OwnerID = masterAvatarId;
}
- if (!resolveUserUuid(kvp.Value.CreatorID))
+ if (!ResolveUserUuid(kvp.Value.CreatorID))
{
kvp.Value.CreatorID = masterAvatarId;
}
@@ -242,7 +246,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver
///
///
///
- private bool resolveUserUuid(UUID uuid)
+ private bool ResolveUserUuid(UUID uuid)
{
if (!m_validUserUuids.ContainsKey(uuid))
{
diff --git a/OpenSim/Region/CoreModules/World/Archiver/ArchiverModule.cs b/OpenSim/Region/CoreModules/World/Archiver/ArchiverModule.cs
index c1f5b18d75..6259662c08 100644
--- a/OpenSim/Region/CoreModules/World/Archiver/ArchiverModule.cs
+++ b/OpenSim/Region/CoreModules/World/Archiver/ArchiverModule.cs
@@ -80,16 +80,26 @@ namespace OpenSim.Region.CoreModules.World.Archiver
}
public void DearchiveRegion(string loadPath)
+ {
+ DearchiveRegion(loadPath, false);
+ }
+
+ public void DearchiveRegion(string loadPath, bool merge)
{
m_log.InfoFormat(
"[ARCHIVER]: Loading archive to region {0} from {1}", m_scene.RegionInfo.RegionName, loadPath);
- new ArchiveReadRequest(m_scene, loadPath).DearchiveRegion();
- }
+ new ArchiveReadRequest(m_scene, loadPath, merge).DearchiveRegion();
+ }
public void DearchiveRegion(Stream loadStream)
{
- new ArchiveReadRequest(m_scene, loadStream).DearchiveRegion();
+ DearchiveRegion(loadStream, false);
}
+
+ public void DearchiveRegion(Stream loadStream, bool merge)
+ {
+ new ArchiveReadRequest(m_scene, loadStream, merge).DearchiveRegion();
+ }
}
}
diff --git a/OpenSim/Region/CoreModules/World/Archiver/Tests/ArchiverTests.cs b/OpenSim/Region/CoreModules/World/Archiver/Tests/ArchiverTests.cs
index 77a3044c52..f201e74248 100644
--- a/OpenSim/Region/CoreModules/World/Archiver/Tests/ArchiverTests.cs
+++ b/OpenSim/Region/CoreModules/World/Archiver/Tests/ArchiverTests.cs
@@ -167,14 +167,13 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests
[Test]
public void TestLoadOarV0p2()
{
- log4net.Config.XmlConfigurator.Configure();
+ //log4net.Config.XmlConfigurator.Configure();
MemoryStream archiveWriteStream = new MemoryStream();
TarArchiveWriter tar = new TarArchiveWriter();
tar.AddFile(ArchiveConstants.CONTROL_FILE_PATH, ArchiveWriteRequestExecution.Create0p2ControlFile());
- UUID ownerId = UUID.Parse("00000000-0000-0000-0000-000000000020");
string part1Name = "object1";
PrimitiveBaseShape shape = PrimitiveBaseShape.CreateCylinder();
Vector3 groupPosition = new Vector3(90, 80, 70);
@@ -216,5 +215,84 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests
Assert.That(
object1PartLoaded.OffsetPosition, Is.EqualTo(offsetPosition), "object1 offset position not equal");
}
+
+ ///
+ /// Test merging a V0.2 OpenSim Region Archive into an existing scene
+ ///
+ [Test]
+ public void TestMergeOarV0p2()
+ {
+ log4net.Config.XmlConfigurator.Configure();
+
+ MemoryStream archiveWriteStream = new MemoryStream();
+
+ string part2Name = "objectMerge";
+ PrimitiveBaseShape part2Shape = PrimitiveBaseShape.CreateCylinder();
+ Vector3 part2GroupPosition = new Vector3(90, 80, 70);
+ Quaternion part2RotationOffset = new Quaternion(60, 70, 80, 90);
+ Vector3 part2OffsetPosition = new Vector3(20, 25, 30);
+
+ // Create an oar file that we can use for the merge
+ {
+ ArchiverModule archiverModule = new ArchiverModule();
+ SerialiserModule serialiserModule = new SerialiserModule();
+ TerrainModule terrainModule = new TerrainModule();
+
+ Scene scene = SceneSetupHelpers.SetupScene();
+ SceneSetupHelpers.SetupSceneModules(scene, archiverModule, serialiserModule, terrainModule);
+
+ SceneObjectPart part2
+ = new SceneObjectPart(
+ UUID.Zero, part2Shape, part2GroupPosition, part2RotationOffset, part2OffsetPosition);
+ part2.Name = part2Name;
+ SceneObjectGroup object2 = new SceneObjectGroup(part2);
+
+ scene.AddNewSceneObject(object2, false);
+
+ // Write out this scene
+ scene.EventManager.OnOarFileSaved += SaveCompleted;
+ archiverModule.ArchiveRegion(archiveWriteStream);
+ m_waitHandle.WaitOne(60000, true);
+ }
+
+ {
+ ArchiverModule archiverModule = new ArchiverModule();
+ SerialiserModule serialiserModule = new SerialiserModule();
+ TerrainModule terrainModule = new TerrainModule();
+
+ Scene scene = SceneSetupHelpers.SetupScene();
+ SceneSetupHelpers.SetupSceneModules(scene, archiverModule, serialiserModule, terrainModule);
+
+ string part1Name = "objectExisting";
+ PrimitiveBaseShape part1Shape = PrimitiveBaseShape.CreateCylinder();
+ Vector3 part1GroupPosition = new Vector3(80, 70, 60);
+ Quaternion part1RotationOffset = new Quaternion(50, 60, 70, 80);
+ Vector3 part1OffsetPosition = new Vector3(15, 20, 25);
+
+ SceneObjectPart part1
+ = new SceneObjectPart(
+ UUID.Zero, part1Shape, part1GroupPosition, part1RotationOffset, part1OffsetPosition);
+ part1.Name = part1Name;
+ SceneObjectGroup object1 = new SceneObjectGroup(part1);
+
+ scene.AddNewSceneObject(object1, false);
+
+ // Merge in the archive we created earlier
+ byte[] archive = archiveWriteStream.ToArray();
+ MemoryStream archiveReadStream = new MemoryStream(archive);
+
+ archiverModule.DearchiveRegion(archiveReadStream, true);
+
+ SceneObjectPart object1Existing = scene.GetSceneObjectPart(part1Name);
+ Assert.That(object1Existing, Is.Not.Null, "object1 was not present after merge");
+ Assert.That(object1Existing.Name, Is.EqualTo(part1Name), "object1 names not identical after merge");
+ Assert.That(object1Existing.GroupPosition, Is.EqualTo(part1GroupPosition), "object1 group position not equal after merge");
+
+ SceneObjectPart object2PartMerged = scene.GetSceneObjectPart(part2Name);
+ Assert.That(object2PartMerged, Is.Not.Null, "object2 was not present after merge");
+ Assert.That(object2PartMerged.Name, Is.EqualTo(part2Name), "object2 names not identical after merge");
+ Assert.That(object2PartMerged.GroupPosition, Is.EqualTo(part2GroupPosition), "object2 group position not equal after merge");
+ }
+ }
}
}
\ No newline at end of file
diff --git a/OpenSim/Region/Framework/Interfaces/IRegionArchiverModule.cs b/OpenSim/Region/Framework/Interfaces/IRegionArchiverModule.cs
index 97afe8d6c4..601b83e249 100644
--- a/OpenSim/Region/Framework/Interfaces/IRegionArchiverModule.cs
+++ b/OpenSim/Region/Framework/Interfaces/IRegionArchiverModule.cs
@@ -55,7 +55,7 @@ namespace OpenSim.Region.Framework.Interfaces
void ArchiveRegion(Stream saveStream);
///
- /// Dearchive the given region archive into the scene
+ /// Dearchive the given region archive. This replaces the existing scene.
///
///
/// If you want notification of when it has completed then subscribe to the EventManager.OnOarFileLoaded event.
@@ -64,12 +64,38 @@ namespace OpenSim.Region.Framework.Interfaces
void DearchiveRegion(string loadPath);
///
- /// Dearchive a region from a stream.
+ /// Dearchive the given region archive. This replaces the existing scene.
+ ///
+ ///
+ /// If you want notification of when it has completed then subscribe to the EventManager.OnOarFileLoaded event.
+ ///
+ ///
+ ///
+ /// If true, the loaded region merges with the existing one rather than replacing it. Any terrain or region
+ /// settings in the archive will be ignored.
+ ///
+ void DearchiveRegion(string loadPath, bool merge);
+
+ ///
+ /// Dearchive a region from a stream. This replaces the existing scene.
///
///
/// If you want notification of when it has completed then subscribe to the EventManager.OnOarFileLoaded event.
///
///
void DearchiveRegion(Stream loadStream);
+
+ ///
+ /// Dearchive a region from a stream. This replaces the existing scene.
+ ///
+ ///
+ /// If you want notification of when it has completed then subscribe to the EventManager.OnOarFileLoaded event.
+ ///
+ ///
+ ///
+ /// If true, the loaded region merges with the existing one rather than replacing it. Any terrain or region
+ /// settings in the archive will be ignored.
+ ///
+ void DearchiveRegion(Stream loadStream, bool merge);
}
}