From 3829df10595911de9ed1ce2f7b6cdd205828f8d0 Mon Sep 17 00:00:00 2001 From: UbitUmarov Date: Mon, 24 Aug 2015 17:05:16 +0100 Subject: try to implement core load oar options --- .../World/Archiver/ArchiveReadRequest.cs | 289 ++++++++++++++------- .../CoreModules/World/Archiver/ArchiverModule.cs | 118 ++++++++- .../World/Archiver/Tests/ArchiverTests.cs | 17 +- .../CoreModules/World/Land/LandManagementModule.cs | 198 ++++++++------ 4 files changed, 439 insertions(+), 183 deletions(-) (limited to 'OpenSim/Region/CoreModules/World') diff --git a/OpenSim/Region/CoreModules/World/Archiver/ArchiveReadRequest.cs b/OpenSim/Region/CoreModules/World/Archiver/ArchiveReadRequest.cs index efc4998..5d41125 100644 --- a/OpenSim/Region/CoreModules/World/Archiver/ArchiveReadRequest.cs +++ b/OpenSim/Region/CoreModules/World/Archiver/ArchiveReadRequest.cs @@ -100,10 +100,37 @@ namespace OpenSim.Region.CoreModules.World.Archiver protected bool m_merge; /// + /// If true, force the loading of terrain from the oar file + /// + protected bool m_forceTerrain; + + /// + /// If true, force the loading of parcels from the oar file + /// + protected bool m_forceParcels; + + /// /// Should we ignore any assets when reloading the archive? /// protected bool m_skipAssets; + /// + /// Displacement added to each object as it is added to the world + /// + protected Vector3 m_displacement = Vector3.Zero; + + /// + /// Rotation (in radians) to apply to the objects as they are loaded. + /// + protected float m_rotation = 0f; + + /// + /// Center around which to apply the rotation relative to the origional oar position + /// + protected Vector3 m_rotationCenter = new Vector3(Constants.RegionSize / 2f, Constants.RegionSize / 2f, 0f); + + protected bool m_noObjects = false; + /// /// Used to cache lookups for valid uuids. /// @@ -131,11 +158,22 @@ namespace OpenSim.Region.CoreModules.World.Archiver private IAssetService m_assetService = null; + private UUID m_defaultUser; - public ArchiveReadRequest(Scene scene, string loadPath, bool merge, bool skipAssets, Guid requestId) + public ArchiveReadRequest(Scene scene, string loadPath, Guid requestId, Dictionary options) { m_rootScene = scene; + if (options.ContainsKey("default-user")) + { + m_defaultUser = (UUID)options["default-user"]; + m_log.InfoFormat("Using User {0} as default user", m_defaultUser.ToString()); + } + else + { + m_defaultUser = scene.RegionInfo.EstateSettings.EstateOwner; + } + m_loadPath = loadPath; try { @@ -148,28 +186,42 @@ namespace OpenSim.Region.CoreModules.World.Archiver + "If you've manually installed Mono, have you appropriately updated zlib1g as well?"); m_log.Error(e); } - + m_errorMessage = String.Empty; - m_merge = merge; - m_skipAssets = skipAssets; + + m_merge = options.ContainsKey("merge"); + m_forceTerrain = options.ContainsKey("force-terrain"); + m_forceParcels = options.ContainsKey("force-parcels"); + m_noObjects = options.ContainsKey("no-objects"); + m_skipAssets = options.ContainsKey("skipAssets"); m_requestId = requestId; + m_displacement = options.ContainsKey("displacement") ? (Vector3)options["displacement"] : Vector3.Zero; + m_rotation = options.ContainsKey("rotation") ? (float)options["rotation"] : 0f; + m_rotationCenter = options.ContainsKey("rotation-center") ? (Vector3)options["rotation-center"] + : new Vector3(scene.RegionInfo.RegionSizeX / 2f, scene.RegionInfo.RegionSizeY / 2f, 0f); - // Zero can never be a valid user id + m_requestId = requestId; + + // Zero can never be a valid user id (or group) m_validUserUuids[UUID.Zero] = false; + m_validGroupUuids[UUID.Zero] = false; + m_groupsModule = m_rootScene.RequestModuleInterface(); m_assetService = m_rootScene.AssetService; } - public ArchiveReadRequest(Scene scene, Stream loadStream, bool merge, bool skipAssets, Guid requestId) + public ArchiveReadRequest(Scene scene, Stream loadStream, Guid requestId, Dictionary options) { m_rootScene = scene; m_loadPath = null; m_loadStream = loadStream; - m_merge = merge; - m_skipAssets = skipAssets; + m_skipAssets = options.ContainsKey("skipAssets"); + m_merge = options.ContainsKey("merge"); m_requestId = requestId; + m_defaultUser = scene.RegionInfo.EstateSettings.EstateOwner; + // Zero can never be a valid user id m_validUserUuids[UUID.Zero] = false; @@ -229,7 +281,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver // Process the file - if (filePath.StartsWith(ArchiveConstants.OBJECTS_PATH)) + if (filePath.StartsWith(ArchiveConstants.OBJECTS_PATH) && !m_noObjects) { sceneContext.SerialisedSceneObjects.Add(Encoding.UTF8.GetString(data)); } @@ -243,15 +295,15 @@ namespace OpenSim.Region.CoreModules.World.Archiver if ((successfulAssetRestores + failedAssetRestores) % 250 == 0) m_log.Debug("[ARCHIVER]: Loaded " + successfulAssetRestores + " assets and failed to load " + failedAssetRestores + " assets..."); } - else if (!m_merge && filePath.StartsWith(ArchiveConstants.TERRAINS_PATH)) + else if ((!m_merge || m_forceTerrain) && filePath.StartsWith(ArchiveConstants.TERRAINS_PATH)) { LoadTerrain(scene, filePath, data); } else if (!m_merge && filePath.StartsWith(ArchiveConstants.SETTINGS_PATH)) { LoadRegionSettings(scene, filePath, data, dearchivedScenes); - } - else if (!m_merge && filePath.StartsWith(ArchiveConstants.LANDDATA_PATH)) + } + else if ((!m_merge || m_forceParcels) && filePath.StartsWith(ArchiveConstants.LANDDATA_PATH)) { sceneContext.SerialisedParcels.Add(Encoding.UTF8.GetString(data)); } @@ -422,6 +474,8 @@ namespace OpenSim.Region.CoreModules.World.Archiver // Reload serialized prims m_log.InfoFormat("[ARCHIVER]: Loading {0} scene objects. Please wait.", serialisedSceneObjects.Count); + OpenMetaverse.Quaternion rot = OpenMetaverse.Quaternion.CreateFromAxisAngle(0, 0, 1, m_rotation); + UUID oldTelehubUUID = scene.RegionInfo.RegionSettings.TelehubObject; IRegionSerialiserModule serialiser = scene.RequestModuleInterface(); @@ -445,6 +499,31 @@ namespace OpenSim.Region.CoreModules.World.Archiver SceneObjectGroup sceneObject = serialiser.DeserializeGroupFromXml2(serialisedSceneObject); + // Happily this does not do much to the object since it hasn't been added to the scene yet + if (!sceneObject.IsAttachment) + { + if (m_displacement != Vector3.Zero || m_rotation != 0f) + { + Vector3 pos = sceneObject.AbsolutePosition; + if (m_rotation != 0f) + { + // Rotate the object + sceneObject.RootPart.RotationOffset = rot * sceneObject.GroupRotation; + // Get object position relative to rotation axis + Vector3 offset = pos - m_rotationCenter; + // Rotate the object position + offset *= rot; + // Restore the object position back to relative to the region + pos = m_rotationCenter + offset; + } + if (m_displacement != Vector3.Zero) + { + pos += m_displacement; + } + sceneObject.AbsolutePosition = pos; + } + } + bool isTelehub = (sceneObject.UUID == oldTelehubUUID) && (oldTelehubUUID != UUID.Zero); // For now, give all incoming scene objects new uuids. This will allow scenes to be cloned @@ -460,76 +539,8 @@ namespace OpenSim.Region.CoreModules.World.Archiver oldTelehubUUID = UUID.Zero; } - // Try to retain the original creator/owner/lastowner if their uuid is present on this grid - // or creator data is present. Otherwise, use the estate owner instead. - foreach (SceneObjectPart part in sceneObject.Parts) - { - if (string.IsNullOrEmpty(part.CreatorData)) - { - if (!ResolveUserUuid(scene, part.CreatorID)) - part.CreatorID = scene.RegionInfo.EstateSettings.EstateOwner; - } - if (UserManager != null) - UserManager.AddUser(part.CreatorID, part.CreatorData); - - if (!ResolveUserUuid(scene, part.OwnerID)) - part.OwnerID = scene.RegionInfo.EstateSettings.EstateOwner; + ModifySceneObject(scene, sceneObject); - if (!ResolveUserUuid(scene, part.LastOwnerID)) - part.LastOwnerID = scene.RegionInfo.EstateSettings.EstateOwner; - - if (!ResolveGroupUuid(part.GroupID)) - part.GroupID = UUID.Zero; - - // And zap any troublesome sit target information -// part.SitTargetOrientation = new Quaternion(0, 0, 0, 1); -// part.SitTargetPosition = new Vector3(0, 0, 0); - - // Fix ownership/creator of inventory items - // Not doing so results in inventory items - // being no copy/no mod for everyone - lock (part.TaskInventory) - { - if (!ResolveUserUuid(scene, part.CreatorID)) - part.CreatorID = scene.RegionInfo.EstateSettings.EstateOwner; - - if (!ResolveUserUuid(scene, part.OwnerID)) - part.OwnerID = scene.RegionInfo.EstateSettings.EstateOwner; - - if (!ResolveUserUuid(scene, part.LastOwnerID)) - part.LastOwnerID = scene.RegionInfo.EstateSettings.EstateOwner; - - // And zap any troublesome sit target information - part.SitTargetOrientation = new Quaternion(0, 0, 0, 1); - part.SitTargetPosition = new Vector3(0, 0, 0); - - // Fix ownership/creator of inventory items - // Not doing so results in inventory items - // being no copy/no mod for everyone - part.TaskInventory.LockItemsForRead(true); - TaskInventoryDictionary inv = part.TaskInventory; - foreach (KeyValuePair kvp in inv) - { - if (!ResolveUserUuid(scene, kvp.Value.OwnerID)) - { - kvp.Value.OwnerID = scene.RegionInfo.EstateSettings.EstateOwner; - } - - if (string.IsNullOrEmpty(kvp.Value.CreatorData)) - { - if (!ResolveUserUuid(scene, kvp.Value.CreatorID)) - kvp.Value.CreatorID = scene.RegionInfo.EstateSettings.EstateOwner; - } - - if (UserManager != null) - UserManager.AddUser(kvp.Value.CreatorID, kvp.Value.CreatorData); - - if (!ResolveGroupUuid(kvp.Value.GroupID)) - kvp.Value.GroupID = UUID.Zero; - } - part.TaskInventory.LockItemsForRead(false); - } - } if (scene.AddRestoredSceneObject(sceneObject, true, false)) { @@ -553,7 +564,76 @@ namespace OpenSim.Region.CoreModules.World.Archiver scene.RegionInfo.RegionSettings.ClearSpawnPoints(); } } - + + /// + /// Optionally modify a loaded SceneObjectGroup. Currently this just ensures that the + /// User IDs and Group IDs are valid, but other manipulations could be done as well. + /// + private void ModifySceneObject(Scene scene, SceneObjectGroup sceneObject) + { + // Try to retain the original creator/owner/lastowner if their uuid is present on this grid + // or creator data is present. Otherwise, use the estate owner instead. + foreach (SceneObjectPart part in sceneObject.Parts) + { + if (string.IsNullOrEmpty(part.CreatorData)) + { + if (!ResolveUserUuid(scene, part.CreatorID)) + part.CreatorID = m_defaultUser; + } + if (UserManager != null) + UserManager.AddUser(part.CreatorID, part.CreatorData); + + if (!(ResolveUserUuid(scene, part.OwnerID) || ResolveGroupUuid(part.OwnerID))) + part.OwnerID = m_defaultUser; + + if (!(ResolveUserUuid(scene, part.LastOwnerID) || ResolveGroupUuid(part.LastOwnerID))) + part.LastOwnerID = m_defaultUser; + + if (!ResolveGroupUuid(part.GroupID)) + part.GroupID = UUID.Zero; + + // And zap any troublesome sit target information + // part.SitTargetOrientation = new Quaternion(0, 0, 0, 1); + // part.SitTargetPosition = new Vector3(0, 0, 0); + + // Fix ownership/creator of inventory items + // Not doing so results in inventory items + // being no copy/no mod for everyone + lock (part.TaskInventory) + { + // And zap any troublesome sit target information + part.SitTargetOrientation = new Quaternion(0, 0, 0, 1); + part.SitTargetPosition = new Vector3(0, 0, 0); + + // Fix ownership/creator of inventory items + // Not doing so results in inventory items + // being no copy/no mod for everyone + part.TaskInventory.LockItemsForRead(true); + TaskInventoryDictionary inv = part.TaskInventory; + foreach (KeyValuePair kvp in inv) + { + if (!(ResolveUserUuid(scene, kvp.Value.OwnerID) || ResolveGroupUuid(kvp.Value.OwnerID))) + { + kvp.Value.OwnerID = m_defaultUser; + } + + if (string.IsNullOrEmpty(kvp.Value.CreatorData)) + { + if (!ResolveUserUuid(scene, kvp.Value.CreatorID)) + kvp.Value.CreatorID = m_defaultUser; + } + + if (UserManager != null) + UserManager.AddUser(kvp.Value.CreatorID, kvp.Value.CreatorData); + + if (!ResolveGroupUuid(kvp.Value.GroupID)) + kvp.Value.GroupID = UUID.Zero; + } + part.TaskInventory.LockItemsForRead(false); + } + } + } + /// /// Load serialized parcels. /// @@ -567,14 +647,21 @@ namespace OpenSim.Region.CoreModules.World.Archiver foreach (string serialisedParcel in serialisedParcels) { LandData parcel = LandDataSerializer.Deserialize(serialisedParcel); - + + if (m_displacement != Vector3.Zero) + { + Vector3 parcelDisp = new Vector3(m_displacement.X, m_displacement.Y, 0f); + parcel.AABBMin += parcelDisp; + parcel.AABBMax += parcelDisp; + } + // Validate User and Group UUID's if (parcel.IsGroupOwned) { if (!ResolveGroupUuid(parcel.GroupID)) { - parcel.OwnerID = m_rootScene.RegionInfo.EstateSettings.EstateOwner; + parcel.OwnerID = m_defaultUser; parcel.GroupID = UUID.Zero; parcel.IsGroupOwned = false; } @@ -582,7 +669,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver else { if (!ResolveUserUuid(scene, parcel.OwnerID)) - parcel.OwnerID = m_rootScene.RegionInfo.EstateSettings.EstateOwner; + parcel.OwnerID = m_defaultUser; if (!ResolveGroupUuid(parcel.GroupID)) parcel.GroupID = UUID.Zero; @@ -702,8 +789,21 @@ namespace OpenSim.Region.CoreModules.World.Archiver sbyte assetType = ArchiveConstants.EXTENSION_TO_ASSET_TYPE[extension]; if (assetType == (sbyte)AssetType.Unknown) + { m_log.WarnFormat("[ARCHIVER]: Importing {0} byte asset {1} with unknown type", data.Length, uuid); - + } + else if (assetType == (sbyte)AssetType.Object) + { + data = SceneObjectSerializer.ModifySerializedObject(UUID.Parse(uuid), data, + sog => + { + ModifySceneObject(m_rootScene, sog); + return true; + }); + + if (data == null) + return false; + } //m_log.DebugFormat("[ARCHIVER]: Importing asset {0}, type {1}", uuid, assetType); AssetBase asset = new AssetBase(new UUID(uuid), String.Empty, assetType, UUID.Zero.ToString()); @@ -825,10 +925,19 @@ namespace OpenSim.Region.CoreModules.World.Archiver private bool LoadTerrain(Scene scene, string terrainPath, byte[] data) { ITerrainModule terrainModule = scene.RequestModuleInterface(); - - MemoryStream ms = new MemoryStream(data); - terrainModule.LoadFromStream(terrainPath, ms); - ms.Close(); + + using (MemoryStream ms = new MemoryStream(data)) + { + if (m_displacement != Vector3.Zero || m_rotation != 0f) + { + Vector2 rotationCenter = new Vector2(m_rotationCenter.X, m_rotationCenter.Y); + terrainModule.LoadFromStream(terrainPath, m_displacement, m_rotation, rotationCenter, ms); + } + else + { + terrainModule.LoadFromStream(terrainPath, ms); + } + } m_log.DebugFormat("[ARCHIVER]: Restored terrain {0}", terrainPath); diff --git a/OpenSim/Region/CoreModules/World/Archiver/ArchiverModule.cs b/OpenSim/Region/CoreModules/World/Archiver/ArchiverModule.cs index 1be6386..8a8e392 100644 --- a/OpenSim/Region/CoreModules/World/Archiver/ArchiverModule.cs +++ b/OpenSim/Region/CoreModules/World/Archiver/ArchiverModule.cs @@ -38,6 +38,8 @@ using OpenSim.Framework.Console; using OpenSim.Region.Framework.Interfaces; using OpenSim.Region.Framework.Scenes; +using OpenMetaverse; + namespace OpenSim.Region.CoreModules.World.Archiver { /// @@ -101,9 +103,64 @@ namespace OpenSim.Region.CoreModules.World.Archiver { bool mergeOar = false; bool skipAssets = false; - - OptionSet options = new OptionSet().Add("m|merge", delegate (string v) { mergeOar = v != null; }); - options.Add("s|skip-assets", delegate (string v) { skipAssets = v != null; }); + bool forceTerrain = false; + bool forceParcels = false; + bool noObjects = false; + Vector3 displacement = new Vector3(0f, 0f, 0f); + String defaultUser = ""; + float rotation = 0f; + Vector3 rotationCenter = new Vector3(Constants.RegionSize / 2f, Constants.RegionSize / 2f, 0); + + OptionSet options = new OptionSet(); + options.Add("m|merge", delegate(string v) { mergeOar = (v != null); }); + options.Add("s|skip-assets", delegate(string v) { skipAssets = (v != null); }); + options.Add("force-terrain", delegate(string v) { forceTerrain = (v != null); }); + options.Add("forceterrain", delegate(string v) { forceTerrain = (v != null); }); // downward compatibility + options.Add("force-parcels", delegate(string v) { forceParcels = (v != null); }); + options.Add("forceparcels", delegate(string v) { forceParcels = (v != null); }); // downward compatibility + options.Add("no-objects", delegate(string v) { noObjects = (v != null); }); + options.Add("default-user=", delegate(string v) { defaultUser = (v == null) ? "" : v; }); + options.Add("displacement=", delegate(string v) + { + try + { + displacement = v == null ? Vector3.Zero : Vector3.Parse(v); + } + catch + { + m_log.ErrorFormat("[ARCHIVER MODULE] failure parsing displacement"); + m_log.ErrorFormat("[ARCHIVER MODULE] Must be represented as vector3: --displacement \"<128,128,0>\""); + return; + } + }); + options.Add("rotation=", delegate(string v) + { + try + { + rotation = v == null ? 0f : float.Parse(v); + } + catch + { + m_log.ErrorFormat("[ARCHIVER MODULE] failure parsing rotation"); + m_log.ErrorFormat("[ARCHIVER MODULE] Must be an angle in degrees between -360 and +360: --rotation 45"); + return; + } + // Convert to radians for internals + rotation = Util.Clamp(rotation, -359f, 359f) / 180f * (float)Math.PI; + }); + options.Add("rotation-center=", delegate(string v) + { + try + { + rotationCenter = v == null ? Vector3.Zero : Vector3.Parse(v); + } + catch + { + m_log.ErrorFormat("[ARCHIVER MODULE] failure parsing rotation displacement"); + m_log.ErrorFormat("[ARCHIVER MODULE] Must be represented as vector3: --rotation-center \"<128,128,0>\""); + return; + } + }); // Send a message to the region ready module /* bluewall* Disable this for the time being @@ -122,13 +179,44 @@ namespace OpenSim.Region.CoreModules.World.Archiver // foreach (string param in mainParams) // m_log.DebugFormat("GOT PARAM [{0}]", param); + Dictionary archiveOptions = new Dictionary(); + if (mergeOar) archiveOptions.Add("merge", null); + if (skipAssets) archiveOptions.Add("skipAssets", null); + if (forceTerrain) archiveOptions.Add("force-terrain", null); + if (forceParcels) archiveOptions.Add("force-parcels", null); + if (noObjects) archiveOptions.Add("no-objects", null); + if (defaultUser != "") + { + UUID defaultUserUUID = UUID.Zero; + try + { + defaultUserUUID = Scene.UserManagementModule.GetUserIdByName(defaultUser); + } + catch + { + m_log.ErrorFormat("[ARCHIVER MODULE] default user must be in format \"First Last\"", defaultUser); + } + if (defaultUserUUID == UUID.Zero) + { + m_log.ErrorFormat("[ARCHIVER MODULE] cannot find specified default user {0}", defaultUser); + return; + } + else + { + archiveOptions.Add("default-user", defaultUserUUID); + } + } + archiveOptions.Add("displacement", displacement); + archiveOptions.Add("rotation", rotation); + archiveOptions.Add("rotation-center", rotationCenter); + if (mainParams.Count > 2) { - DearchiveRegion(mainParams[2], mergeOar, skipAssets, Guid.Empty); + DearchiveRegion(mainParams[2], Guid.Empty, archiveOptions); } else { - DearchiveRegion(DEFAULT_OAR_BACKUP_FILENAME, mergeOar, skipAssets, Guid.Empty); + DearchiveRegion(DEFAULT_OAR_BACKUP_FILENAME, Guid.Empty, archiveOptions); } } @@ -198,25 +286,27 @@ namespace OpenSim.Region.CoreModules.World.Archiver public void DearchiveRegion(string loadPath) { - DearchiveRegion(loadPath, false, false, Guid.Empty); + Dictionary archiveOptions = new Dictionary(); + DearchiveRegion(loadPath, Guid.Empty, archiveOptions); } - - public void DearchiveRegion(string loadPath, bool merge, bool skipAssets, Guid requestId) + + public void DearchiveRegion(string loadPath, Guid requestId, Dictionary options) { m_log.InfoFormat( "[ARCHIVER]: Loading archive to region {0} from {1}", Scene.RegionInfo.RegionName, loadPath); - - new ArchiveReadRequest(Scene, loadPath, merge, skipAssets, requestId).DearchiveRegion(); + + new ArchiveReadRequest(Scene, loadPath, requestId, options).DearchiveRegion(); } public void DearchiveRegion(Stream loadStream) { - DearchiveRegion(loadStream, false, false, Guid.Empty); + Dictionary archiveOptions = new Dictionary(); + DearchiveRegion(loadStream, Guid.Empty, archiveOptions); } - - public void DearchiveRegion(Stream loadStream, bool merge, bool skipAssets, Guid requestId) + + public void DearchiveRegion(Stream loadStream, Guid requestId, Dictionary options) { - new ArchiveReadRequest(Scene, loadStream, merge, skipAssets, requestId).DearchiveRegion(); + new ArchiveReadRequest(Scene, loadStream, requestId, options).DearchiveRegion(); } } } diff --git a/OpenSim/Region/CoreModules/World/Archiver/Tests/ArchiverTests.cs b/OpenSim/Region/CoreModules/World/Archiver/Tests/ArchiverTests.cs index eec1cec..53f41f9 100644 --- a/OpenSim/Region/CoreModules/World/Archiver/Tests/ArchiverTests.cs +++ b/OpenSim/Region/CoreModules/World/Archiver/Tests/ArchiverTests.cs @@ -224,8 +224,9 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests byte[] data = tar.ReadEntry(out filePath, out tarEntryType); Assert.That(filePath, Is.EqualTo(ArchiveConstants.CONTROL_FILE_PATH)); - - ArchiveReadRequest arr = new ArchiveReadRequest(m_scene, (Stream)null, false, false, Guid.Empty); + + Dictionary archiveOptions = new Dictionary(); + ArchiveReadRequest arr = new ArchiveReadRequest(m_scene, (Stream)null, Guid.Empty, archiveOptions); arr.LoadControlFile(filePath, data, new DearchiveScenesInfo()); Assert.That(arr.ControlFileLoaded, Is.True); @@ -308,8 +309,9 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests byte[] data = tar.ReadEntry(out filePath, out tarEntryType); Assert.That(filePath, Is.EqualTo(ArchiveConstants.CONTROL_FILE_PATH)); - - ArchiveReadRequest arr = new ArchiveReadRequest(m_scene, (Stream)null, false, false, Guid.Empty); + + Dictionary archiveOptions = new Dictionary(); + ArchiveReadRequest arr = new ArchiveReadRequest(m_scene, (Stream)null, Guid.Empty, archiveOptions); arr.LoadControlFile(filePath, data, new DearchiveScenesInfo()); Assert.That(arr.ControlFileLoaded, Is.True); @@ -752,7 +754,9 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests byte[] archive = archiveWriteStream.ToArray(); MemoryStream archiveReadStream = new MemoryStream(archive); - m_archiverModule.DearchiveRegion(archiveReadStream, true, false, Guid.Empty); + Dictionary archiveOptions = new Dictionary(); + archiveOptions.Add("merge", null); + m_archiverModule.DearchiveRegion(archiveReadStream, Guid.Empty, archiveOptions); SceneObjectPart object1Existing = m_scene.GetSceneObjectPart(part1.Name); Assert.That(object1Existing, Is.Not.Null, "object1 was not present after merge"); @@ -860,7 +864,8 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests byte[] data = tar.ReadEntry(out filePath, out tarEntryType); Assert.That(filePath, Is.EqualTo(ArchiveConstants.CONTROL_FILE_PATH)); - ArchiveReadRequest arr = new ArchiveReadRequest(m_scene, (Stream)null, false, false, Guid.Empty); + Dictionary archiveOptions = new Dictionary(); + ArchiveReadRequest arr = new ArchiveReadRequest(m_scene, (Stream)null, Guid.Empty, archiveOptions); arr.LoadControlFile(filePath, data, new DearchiveScenesInfo()); Assert.That(arr.ControlFileLoaded, Is.True); diff --git a/OpenSim/Region/CoreModules/World/Land/LandManagementModule.cs b/OpenSim/Region/CoreModules/World/Land/LandManagementModule.cs index 4aee6a5..83bbf79 100644 --- a/OpenSim/Region/CoreModules/World/Land/LandManagementModule.cs +++ b/OpenSim/Region/CoreModules/World/Land/LandManagementModule.cs @@ -570,17 +570,54 @@ namespace OpenSim.Region.CoreModules.World.Land new_land.LandData.LocalID = newLandLocalID; bool[,] landBitmap = new_land.GetLandBitmap(); - for (int x = 0; x < landBitmap.GetLength(0); x++) + if (landBitmap.GetLength(0) != m_landIDList.GetLength(0) || landBitmap.GetLength(1) != m_landIDList.GetLength(1)) { - for (int y = 0; y < landBitmap.GetLength(1); y++) + // Going to variable sized regions can cause mismatches + m_log.ErrorFormat("{0} AddLandObject. Added land bitmap different size than region ID map. bitmapSize=({1},{2}), landIDSize=({3},{4})", + LogHeader, landBitmap.GetLength(0), landBitmap.GetLength(1), m_landIDList.GetLength(0), m_landIDList.GetLength(1)); + } + else + { + // If other land objects still believe that they occupy any parts of the same space, + // then do not allow the add to proceed. + for (int x = 0; x < landBitmap.GetLength(0); x++) + { + for (int y = 0; y < landBitmap.GetLength(1); y++) + { + if (landBitmap[x, y]) + { + int lastRecordedLandId = m_landIDList[x, y]; + + if (lastRecordedLandId > 0) + { + ILandObject lastRecordedLo = m_landList[lastRecordedLandId]; + + if (lastRecordedLo.LandBitmap[x, y]) + { + m_log.ErrorFormat( + "{0}: Cannot add parcel \"{1}\", local ID {2} at tile {3},{4} because this is still occupied by parcel \"{5}\", local ID {6} in {7}", + LogHeader, new_land.LandData.Name, new_land.LandData.LocalID, x, y, + lastRecordedLo.LandData.Name, lastRecordedLo.LandData.LocalID, m_scene.Name); + + return null; + } + } + } + } + } + + for (int x = 0; x < landBitmap.GetLength(0); x++) { - if (landBitmap[x, y]) + for (int y = 0; y < landBitmap.GetLength(1); y++) { -// m_log.DebugFormat( -// "[LAND MANAGEMENT MODULE]: Registering parcel {0} for land co-ord ({1}, {2}) on {3}", -// new_land.LandData.Name, x, y, m_scene.RegionInfo.RegionName); - - m_landIDList[x, y] = newLandLocalID; + if (landBitmap[x, y]) + { + // m_log.DebugFormat( + // "[LAND MANAGEMENT MODULE]: Registering parcel {0} for land co-ord ({1}, {2}) on {3}", + // new_land.LandData.Name, x, y, m_scene.RegionInfo.RegionName); + + m_landIDList[x, y] = newLandLocalID; + } } } } @@ -693,47 +730,7 @@ namespace OpenSim.Region.CoreModules.World.Land /// Land object at the point supplied public ILandObject GetLandObject(float x_float, float y_float) { - int x; - int y; - - if (x_float >= m_scene.RegionInfo.RegionSizeX || x_float < 0 || y_float >= m_scene.RegionInfo.RegionSizeX || y_float < 0) - return null; - - try - { - x = Convert.ToInt32(Math.Floor(Convert.ToDouble(x_float) / (float)landUnit)); - y = Convert.ToInt32(Math.Floor(Convert.ToDouble(y_float) / (float)landUnit)); - } - catch (OverflowException) - { - return null; - } - - if (x >= (m_scene.RegionInfo.RegionSizeX / landUnit) - || y >= (m_scene.RegionInfo.RegionSizeY / landUnit) - || x < 0 - || y < 0) - { - return null; - } - - lock (m_landList) - { - // Corner case. If an autoreturn happens during sim startup - // we will come here with the list uninitialized - // -// int landId = m_landIDList[x, y]; - -// if (landId == 0) -// m_log.DebugFormat( -// "[LAND MANAGEMENT MODULE]: No land object found at ({0}, {1}) on {2}", -// x, y, m_scene.RegionInfo.RegionName); - - if (m_landList.ContainsKey(m_landIDList[x, y])) - return m_landList[m_landIDList[x, y]]; - - return null; - } + return GetLandObject((int)x_float, (int)y_float, true); } // if x,y is off region this will return the parcel at cliped x,y @@ -768,29 +765,47 @@ namespace OpenSim.Region.CoreModules.World.Land public ILandObject GetLandObject(int x, int y) { + return GetLandObject(x, y, false /* returnNullIfLandObjectNotFound */); + } + + public ILandObject GetLandObject(int x, int y, bool returnNullIfLandObjectOutsideBounds) + { if (x >= m_scene.RegionInfo.RegionSizeX || y >= m_scene.RegionInfo.RegionSizeY || x < 0 || y < 0) { // These exceptions here will cause a lot of complaints from the users specifically because // they happen every time at border crossings - throw new Exception("Error: Parcel not found at point " + x + ", " + y); + if (returnNullIfLandObjectOutsideBounds) + return null; + else + throw new Exception("Error: Parcel not found at point " + x + ", " + y); } lock (m_landIDList) { try { - //if (m_landList.ContainsKey(m_landIDList[x / 4, y / 4])) return m_landList[m_landIDList[x / 4, y / 4]]; - //else - // return null; } catch (IndexOutOfRangeException) { - return null; + return null; } } } + // Create a 'parcel is here' bitmap for the parcel identified by the passed landID + private bool[,] CreateBitmapForID(int landID) + { + bool[,] ret = new bool[m_landIDList.GetLength(0), m_landIDList.GetLength(1)]; + + for (int xx = 0; xx < m_landIDList.GetLength(0); xx++) + for (int yy = 0; yy < m_landIDList.GetLength(0); yy++) + if (m_landIDList[xx, yy] == landID) + ret[xx, yy] = true; + + return ret; + } + #endregion #region Parcel Modification @@ -1432,29 +1447,66 @@ namespace OpenSim.Region.CoreModules.World.Land public void EventManagerOnIncomingLandDataFromStorage(List data) { - Dictionary landworkList; - // move to work pointer since we are deleting it all lock (m_landList) { - landworkList = m_landList; - m_landList = new Dictionary(); - } + for (int i = 0; i < data.Count; i++) + IncomingLandObjectFromStorage(data[i]); - //Remove all the land objects in the sim and then process our new data - foreach (int n in landworkList.Keys) - { - m_scene.EventManager.TriggerLandObjectRemoved(landworkList[n].LandData.GlobalID); - } - landworkList.Clear(); + // Layer data is in landUnit (4m) chunks + for (int y = 0; y < m_scene.RegionInfo.RegionSizeY / Constants.TerrainPatchSize * (Constants.TerrainPatchSize / landUnit); y++) + { + for (int x = 0; x < m_scene.RegionInfo.RegionSizeX / Constants.TerrainPatchSize * (Constants.TerrainPatchSize / landUnit); x++) + { + if (m_landIDList[x, y] == 0) + { + if (m_landList.Count == 1) + { + m_log.DebugFormat( + "[{0}]: Auto-extending land parcel as landID at {1},{2} is 0 and only one land parcel is present in {3}", + LogHeader, x, y, m_scene.Name); - lock (m_landList) - { - m_landIDList.Initialize(); - m_landList.Clear(); - } + int onlyParcelID = 0; + ILandObject onlyLandObject = null; + foreach (KeyValuePair kvp in m_landList) + { + onlyParcelID = kvp.Key; + onlyLandObject = kvp.Value; + break; + } - for (int i = 0; i < data.Count; i++) - IncomingLandObjectFromStorage(data[i]); + // There is only one parcel. Grow it to fill all the unallocated spaces. + for (int xx = 0; xx < m_landIDList.GetLength(0); xx++) + for (int yy = 0; yy < m_landIDList.GetLength(1); yy++) + if (m_landIDList[xx, yy] == 0) + m_landIDList[xx, yy] = onlyParcelID; + + onlyLandObject.LandBitmap = CreateBitmapForID(onlyParcelID); + } + else if (m_landList.Count > 1) + { + m_log.DebugFormat( + "{0}: Auto-creating land parcel as landID at {1},{2} is 0 and more than one land parcel is present in {3}", + LogHeader, x, y, m_scene.Name); + + // There are several other parcels so we must create a new one for the unassigned space + ILandObject newLand = new LandObject(UUID.Zero, false, m_scene); + // Claim all the unclaimed "0" ids + newLand.SetLandBitmap(CreateBitmapForID(0)); + newLand.LandData.OwnerID = m_scene.RegionInfo.EstateSettings.EstateOwner; + newLand.LandData.ClaimDate = Util.UnixTimeSinceEpoch(); + newLand = AddLandObject(newLand); + } + else + { + // We should never reach this point as the separate code path when no land data exists should have fired instead. + m_log.WarnFormat( + "{0}: Ignoring request to auto-create parcel in {1} as there are no other parcels present", + LogHeader, m_scene.Name); + } + } + } + } + } } public void IncomingLandObjectFromStorage(LandData data) @@ -1464,7 +1516,7 @@ namespace OpenSim.Region.CoreModules.World.Land new_land.LandData = data.Copy(); new_land.SetLandBitmapFromByteArray(); AddLandObject(new_land); - new_land.SendLandUpdateToAvatarsOverMe(); +// new_land.SendLandUpdateToAvatarsOverMe(); } public void ReturnObjectsInParcel(int localID, uint returnType, UUID[] agentIDs, UUID[] taskIDs, IClientAPI remoteClient) -- cgit v1.1