diff --git a/OpenSim/Region/CoreModules/World/Archiver/ArchiveReadRequest.cs b/OpenSim/Region/CoreModules/World/Archiver/ArchiveReadRequest.cs index bf0ff7516b..2b61800c94 100644 --- a/OpenSim/Region/CoreModules/World/Archiver/ArchiveReadRequest.cs +++ b/OpenSim/Region/CoreModules/World/Archiver/ArchiveReadRequest.cs @@ -41,6 +41,7 @@ using OpenSim.Framework.Serialization.External; using OpenSim.Region.CoreModules.World.Terrain; using OpenSim.Region.Framework.Interfaces; using OpenSim.Region.Framework.Scenes; +using OpenSim.Region.Framework.Scenes.Serialization; using OpenSim.Services.Interfaces; namespace OpenSim.Region.CoreModules.World.Archiver diff --git a/OpenSim/Region/CoreModules/World/Archiver/Tests/ArchiverTests.cs b/OpenSim/Region/CoreModules/World/Archiver/Tests/ArchiverTests.cs index 394ca27123..5deaf5264b 100644 --- a/OpenSim/Region/CoreModules/World/Archiver/Tests/ArchiverTests.cs +++ b/OpenSim/Region/CoreModules/World/Archiver/Tests/ArchiverTests.cs @@ -291,6 +291,59 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests // TODO: Test presence of more files and contents of files. } + /// + /// Test loading an OpenSim Region Archive where the scene object parts are not ordered by link number (e.g. + /// 2 can come after 3). + /// + [Test] + public void TestLoadOarUnorderedParts() + { + TestHelpers.InMethod(); + + UUID ownerId = TestHelpers.ParseTail(0xaaaa); + + MemoryStream archiveWriteStream = new MemoryStream(); + TarArchiveWriter tar = new TarArchiveWriter(archiveWriteStream); + + tar.WriteFile( + ArchiveConstants.CONTROL_FILE_PATH, + new ArchiveWriteRequestPreparation(null, (Stream)null, Guid.Empty).CreateControlFile(new Dictionary())); + + SceneObjectGroup sog1 = SceneHelpers.CreateSceneObject(1, ownerId, "obj1-", 0x11); + SceneObjectPart sop2 + = SceneHelpers.CreateSceneObjectPart("obj1-Part2", TestHelpers.ParseTail(0x12), ownerId); + SceneObjectPart sop3 + = SceneHelpers.CreateSceneObjectPart("obj1-Part3", TestHelpers.ParseTail(0x13), ownerId); + + // Add the parts so they will be written out in reverse order to the oar + sog1.AddPart(sop3); + sop3.LinkNum = 3; + sog1.AddPart(sop2); + sop2.LinkNum = 2; + + tar.WriteFile( + ArchiveConstants.CreateOarObjectPath(sog1.Name, sog1.UUID, sog1.AbsolutePosition), + SceneObjectSerializer.ToXml2Format(sog1)); + + tar.Close(); + + MemoryStream archiveReadStream = new MemoryStream(archiveWriteStream.ToArray()); + + lock (this) + { + m_scene.EventManager.OnOarFileLoaded += LoadCompleted; + m_archiverModule.DearchiveRegion(archiveReadStream); + } + + Assert.That(m_lastErrorMessage, Is.Null); + + SceneObjectPart part2 = m_scene.GetSceneObjectPart("obj1-Part2"); + Assert.That(part2.LinkNum, Is.EqualTo(2)); + + SceneObjectPart part3 = m_scene.GetSceneObjectPart("obj1-Part3"); + Assert.That(part3.LinkNum, Is.EqualTo(3)); + } + /// /// Test loading an OpenSim Region Archive. /// diff --git a/OpenSim/Region/CoreModules/World/Objects/Commands/ObjectCommandsModule.cs b/OpenSim/Region/CoreModules/World/Objects/Commands/ObjectCommandsModule.cs index 5e928f3e8f..830d9cbc1b 100644 --- a/OpenSim/Region/CoreModules/World/Objects/Commands/ObjectCommandsModule.cs +++ b/OpenSim/Region/CoreModules/World/Objects/Commands/ObjectCommandsModule.cs @@ -29,8 +29,10 @@ using System; using System.Collections.Generic; using System.Reflection; using System.Text; +using System.Text.RegularExpressions; using log4net; using Mono.Addins; +using NDesk.Options; using Nini.Config; using OpenMetaverse; using OpenSim.Framework; @@ -78,25 +80,31 @@ namespace OpenSim.Region.CoreModules.World.Objects.Commands m_scene = scene; m_console = MainConsole.Instance; - m_console.Commands.AddCommand("Objects", false, "delete object owner", - "delete object owner ", - "Delete a scene object by owner", HandleDeleteObject); + m_console.Commands.AddCommand( + "Objects", false, "delete object owner", + "delete object owner ", + "Delete a scene object by owner", HandleDeleteObject); - m_console.Commands.AddCommand("Objects", false, "delete object creator", - "delete object creator ", - "Delete a scene object by creator", HandleDeleteObject); + m_console.Commands.AddCommand( + "Objects", false, "delete object creator", + "delete object creator ", + "Delete a scene object by creator", HandleDeleteObject); - m_console.Commands.AddCommand("Objects", false, "delete object uuid", - "delete object uuid ", - "Delete a scene object by uuid", HandleDeleteObject); + m_console.Commands.AddCommand( + "Objects", false, "delete object uuid", + "delete object uuid ", + "Delete a scene object by uuid", HandleDeleteObject); - m_console.Commands.AddCommand("Objects", false, "delete object name", - "delete object name ", - "Delete a scene object by name", HandleDeleteObject); + m_console.Commands.AddCommand( + "Objects", false, "delete object name", + "delete object name [--regex] ", + "Delete a scene object by name.\nIf --regex is specified then the name is treatead as a regular expression", + HandleDeleteObject); - m_console.Commands.AddCommand("Objects", false, "delete object outside", - "delete object outside", - "Delete all scene objects outside region boundaries", HandleDeleteObject); + m_console.Commands.AddCommand( + "Objects", false, "delete object outside", + "delete object outside", + "Delete all scene objects outside region boundaries", HandleDeleteObject); m_console.Commands.AddCommand( "Objects", @@ -109,8 +117,9 @@ namespace OpenSim.Region.CoreModules.World.Objects.Commands "Objects", false, "show object name", - "show object name ", - "Show details of scene objects with the given name", HandleShowObjectByName); + "show object name [--regex] ", + "Show details of scene objects with the given name.\nIf --regex is specified then the name is treatead as a regular expression", + HandleShowObjectByName); m_console.Commands.AddCommand( "Objects", @@ -123,8 +132,9 @@ namespace OpenSim.Region.CoreModules.World.Objects.Commands "Objects", false, "show part name", - "show part name ", - "Show details of scene object parts with the given name", HandleShowPartByName); + "show part name [--regex] ", + "Show details of scene object parts with the given name.\nIf --regex is specified then the name is treatead as a regular expression", + HandleShowPartByName); } public void RemoveRegion(Scene scene) @@ -169,22 +179,38 @@ namespace OpenSim.Region.CoreModules.World.Objects.Commands m_console.OutputFormat(sb.ToString()); } - private void HandleShowObjectByName(string module, string[] cmd) + private void HandleShowObjectByName(string module, string[] cmdparams) { if (!(m_console.ConsoleScene == null || m_console.ConsoleScene == m_scene)) return; - if (cmd.Length < 4) + bool useRegex = false; + OptionSet options = new OptionSet().Add("regex", v=> useRegex = v != null ); + + List mainParams = options.Parse(cmdparams); + + if (mainParams.Count < 4) { - m_console.OutputFormat("Usage: show object name "); + m_console.OutputFormat("Usage: show object name [--regex] "); return; } - string name = cmd[3]; + string name = mainParams[3]; List sceneObjects = new List(); + Action searchAction; - m_scene.ForEachSOG(so => { if (so.Name == name) { sceneObjects.Add(so); }}); + if (useRegex) + { + Regex nameRegex = new Regex(name); + searchAction = so => { if (nameRegex.IsMatch(so.Name)) { sceneObjects.Add(so); }}; + } + else + { + searchAction = so => { if (so.Name == name) { sceneObjects.Add(so); }}; + } + + m_scene.ForEachSOG(searchAction); if (sceneObjects.Count == 0) { @@ -235,22 +261,39 @@ namespace OpenSim.Region.CoreModules.World.Objects.Commands m_console.OutputFormat(sb.ToString()); } - private void HandleShowPartByName(string module, string[] cmd) + private void HandleShowPartByName(string module, string[] cmdparams) { if (!(m_console.ConsoleScene == null || m_console.ConsoleScene == m_scene)) return; - if (cmd.Length < 4) + bool useRegex = false; + OptionSet options = new OptionSet().Add("regex", v=> useRegex = v != null ); + + List mainParams = options.Parse(cmdparams); + + if (mainParams.Count < 4) { - m_console.OutputFormat("Usage: show part name "); + m_console.OutputFormat("Usage: show part name [--regex] "); return; } - string name = cmd[3]; + string name = mainParams[3]; List parts = new List(); - m_scene.ForEachSOG(so => so.ForEachPart(sop => { if (sop.Name == name) { parts.Add(sop); } })); + Action searchAction; + + if (useRegex) + { + Regex nameRegex = new Regex(name); + searchAction = so => so.ForEachPart(sop => { if (nameRegex.IsMatch(sop.Name)) { parts.Add(sop); } }); + } + else + { + searchAction = so => so.ForEachPart(sop => { if (sop.Name == name) { parts.Add(sop); } }); + } + + m_scene.ForEachSOG(searchAction); if (parts.Count == 0) { @@ -312,96 +355,121 @@ namespace OpenSim.Region.CoreModules.World.Objects.Commands o = cmd[3]; } - List deletes = new List(); - + List deletes = null; UUID match; + bool requireConfirmation = true; switch (mode) { - case "owner": - if (!UUID.TryParse(o, out match)) - return; + case "owner": + if (!UUID.TryParse(o, out match)) + return; - m_scene.ForEachSOG(delegate (SceneObjectGroup g) - { - if (g.OwnerID == match && !g.IsAttachment) - deletes.Add(g); - }); + deletes = new List(); -// if (deletes.Count == 0) -// m_console.OutputFormat("No objects were found with owner {0}", match); - - break; - - case "creator": - if (!UUID.TryParse(o, out match)) - return; - - m_scene.ForEachSOG(delegate (SceneObjectGroup g) - { - if (g.RootPart.CreatorID == match && !g.IsAttachment) - deletes.Add(g); - }); - -// if (deletes.Count == 0) -// m_console.OutputFormat("No objects were found with creator {0}", match); - - break; - - case "uuid": - if (!UUID.TryParse(o, out match)) - return; - - m_scene.ForEachSOG(delegate (SceneObjectGroup g) - { - if (g.UUID == match && !g.IsAttachment) - deletes.Add(g); - }); - -// if (deletes.Count == 0) -// m_console.OutputFormat("No objects were found with uuid {0}", match); - - break; - - case "name": - m_scene.ForEachSOG(delegate (SceneObjectGroup g) - { - if (g.RootPart.Name == o && !g.IsAttachment) - deletes.Add(g); - }); - -// if (deletes.Count == 0) -// m_console.OutputFormat("No objects were found with name {0}", o); - - break; - - case "outside": - m_scene.ForEachSOG(delegate (SceneObjectGroup g) - { - SceneObjectPart rootPart = g.RootPart; - bool delete = false; - - if (rootPart.GroupPosition.Z < 0.0 || rootPart.GroupPosition.Z > 10000.0) + m_scene.ForEachSOG(delegate (SceneObjectGroup g) { - delete = true; - } - else - { - ILandObject parcel - = m_scene.LandChannel.GetLandObject(rootPart.GroupPosition.X, rootPart.GroupPosition.Y); + if (g.OwnerID == match && !g.IsAttachment) + deletes.Add(g); + }); + + // if (deletes.Count == 0) + // m_console.OutputFormat("No objects were found with owner {0}", match); + + break; + + case "creator": + if (!UUID.TryParse(o, out match)) + return; - if (parcel == null || parcel.LandData.Name == "NO LAND") + deletes = new List(); + + m_scene.ForEachSOG(delegate (SceneObjectGroup g) + { + if (g.RootPart.CreatorID == match && !g.IsAttachment) + deletes.Add(g); + }); + + // if (deletes.Count == 0) + // m_console.OutputFormat("No objects were found with creator {0}", match); + + break; + + case "uuid": + if (!UUID.TryParse(o, out match)) + return; + + requireConfirmation = false; + deletes = new List(); + + m_scene.ForEachSOG(delegate (SceneObjectGroup g) + { + if (g.UUID == match && !g.IsAttachment) + deletes.Add(g); + }); + + // if (deletes.Count == 0) + // m_console.OutputFormat("No objects were found with uuid {0}", match); + + break; + + case "name": + deletes = GetDeleteCandidatesByName(module, cmd); + break; + + case "outside": + deletes = new List(); + + m_scene.ForEachSOG(delegate (SceneObjectGroup g) + { + SceneObjectPart rootPart = g.RootPart; + bool delete = false; + + if (rootPart.GroupPosition.Z < 0.0 || rootPart.GroupPosition.Z > 10000.0) + { delete = true; - } + } + else + { + ILandObject parcel + = m_scene.LandChannel.GetLandObject(rootPart.GroupPosition.X, rootPart.GroupPosition.Y); + + if (parcel == null || parcel.LandData.Name == "NO LAND") + delete = true; + } + + if (delete && !g.IsAttachment && !deletes.Contains(g)) + deletes.Add(g); + }); + + if (deletes.Count == 0) + m_console.OutputFormat("No objects were found outside region bounds"); + + break; - if (delete && !g.IsAttachment && !deletes.Contains(g)) - deletes.Add(g); - }); + default: + m_console.OutputFormat("Unrecognized mode {0}", mode); + return; + } -// if (deletes.Count == 0) -// m_console.OutputFormat("No objects were found outside region bounds"); + if (deletes == null || deletes.Count <= 0) + return; - break; + if (requireConfirmation) + { + string response = MainConsole.Instance.CmdPrompt( + string.Format( + "Are you sure that you want to delete {0} objects from {1}", + deletes.Count, m_scene.RegionInfo.RegionName), + "n"); + + if (response.ToLower() != "y") + { + MainConsole.Instance.OutputFormat( + "Aborting delete of {0} objects from {1}", deletes.Count, m_scene.RegionInfo.RegionName); + + return; + } } m_console.OutputFormat("Deleting {0} objects in {1}", deletes.Count, m_scene.RegionInfo.RegionName); @@ -412,5 +480,44 @@ namespace OpenSim.Region.CoreModules.World.Objects.Commands m_scene.DeleteSceneObject(g, false); } } + + private List GetDeleteCandidatesByName(string module, string[] cmdparams) + { + if (!(m_console.ConsoleScene == null || m_console.ConsoleScene == m_scene)) + return null; + + bool useRegex = false; + OptionSet options = new OptionSet().Add("regex", v=> useRegex = v != null ); + + List mainParams = options.Parse(cmdparams); + + if (mainParams.Count < 4) + { + m_console.OutputFormat("Usage: delete object name [--regex] "); + return null; + } + + string name = mainParams[3]; + + List sceneObjects = new List(); + Action searchAction; + + if (useRegex) + { + Regex nameRegex = new Regex(name); + searchAction = so => { if (nameRegex.IsMatch(so.Name)) { sceneObjects.Add(so); }}; + } + else + { + searchAction = so => { if (so.Name == name) { sceneObjects.Add(so); }}; + } + + m_scene.ForEachSOG(searchAction); + + if (sceneObjects.Count == 0) + m_console.OutputFormat("No objects with name {0} found in {1}", name, m_scene.RegionInfo.RegionName); + + return sceneObjects; + } } } \ No newline at end of file diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs index e3f06f8fbc..dc76d22931 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs @@ -944,7 +944,18 @@ namespace OpenSim.Region.Framework.Scenes public int LinkNum { get { return m_linkNum; } - set { m_linkNum = value; } + set + { +// if (ParentGroup != null) +// { +// m_log.DebugFormat( +// "[SCENE OBJECT PART]: Setting linknum of {0}@{1} to {2} from {3}", +// Name, AbsolutePosition, value, m_linkNum); +// Util.PrintCallStack(); +// } + + m_linkNum = value; + } } public byte ClickAction diff --git a/OpenSim/Region/Framework/Scenes/Serialization/SceneObjectSerializer.cs b/OpenSim/Region/Framework/Scenes/Serialization/SceneObjectSerializer.cs index a11dc4965d..0b34156495 100644 --- a/OpenSim/Region/Framework/Scenes/Serialization/SceneObjectSerializer.cs +++ b/OpenSim/Region/Framework/Scenes/Serialization/SceneObjectSerializer.cs @@ -1424,51 +1424,6 @@ namespace OpenSim.Region.Framework.Scenes.Serialization } } - //////// Read ///////// - public static bool Xml2ToSOG(XmlTextReader reader, SceneObjectGroup sog) - { - reader.Read(); - reader.ReadStartElement("SceneObjectGroup"); - SceneObjectPart root = Xml2ToSOP(reader); - if (root != null) - sog.SetRootPart(root); - else - { - return false; - } - - if (sog.UUID == UUID.Zero) - sog.UUID = sog.RootPart.UUID; - - reader.Read(); // OtherParts - - while (!reader.EOF) - { - switch (reader.NodeType) - { - case XmlNodeType.Element: - if (reader.Name == "SceneObjectPart") - { - SceneObjectPart child = Xml2ToSOP(reader); - if (child != null) - sog.AddPart(child); - } - else - { - //Logger.Log("Found unexpected prim XML element " + reader.Name, Helpers.LogLevel.Debug); - reader.Read(); - } - break; - case XmlNodeType.EndElement: - default: - reader.Read(); - break; - } - - } - return true; - } - public static SceneObjectPart Xml2ToSOP(XmlTextReader reader) { SceneObjectPart obj = new SceneObjectPart(); diff --git a/OpenSim/Region/Framework/Scenes/Serialization/SceneXmlLoader.cs b/OpenSim/Region/Framework/Scenes/Serialization/SceneXmlLoader.cs index d214eba1fc..a3485d29e6 100644 --- a/OpenSim/Region/Framework/Scenes/Serialization/SceneXmlLoader.cs +++ b/OpenSim/Region/Framework/Scenes/Serialization/SceneXmlLoader.cs @@ -223,50 +223,7 @@ namespace OpenSim.Region.Framework.Scenes.Serialization public static SceneObjectGroup DeserializeGroupFromXml2(string xmlString) { - XmlDocument doc = new XmlDocument(); - XmlNode rootNode; - - XmlTextReader reader = new XmlTextReader(new StringReader(xmlString)); - reader.WhitespaceHandling = WhitespaceHandling.None; - doc.Load(reader); - reader.Close(); - rootNode = doc.FirstChild; - - // This is to deal with neighbouring regions that are still surrounding the group xml with the - // tag. It should be possible to remove the first part of this if statement once we go past 0.5.9 (or - // when some other changes forces all regions to upgrade). - // This might seem rather pointless since prim crossing from this revision to an earlier revision remains - // broken. But it isn't much work to accomodate the old format here. - if (rootNode.LocalName.Equals("scene")) - { - foreach (XmlNode aPrimNode in rootNode.ChildNodes) - { - // There is only ever one prim. This oddity should be removeable post 0.5.9 - //return SceneObjectSerializer.FromXml2Format(aPrimNode.OuterXml); - using (reader = new XmlTextReader(new StringReader(aPrimNode.OuterXml))) - { - SceneObjectGroup obj = new SceneObjectGroup(); - if (SceneObjectSerializer.Xml2ToSOG(reader, obj)) - return obj; - - return null; - } - } - - return null; - } - else - { - //return SceneObjectSerializer.FromXml2Format(rootNode.OuterXml); - using (reader = new XmlTextReader(new StringReader(rootNode.OuterXml))) - { - SceneObjectGroup obj = new SceneObjectGroup(); - if (SceneObjectSerializer.Xml2ToSOG(reader, obj)) - return obj; - - return null; - } - } + return SceneObjectSerializer.FromXml2Format(xmlString); } /// @@ -307,8 +264,8 @@ namespace OpenSim.Region.Framework.Scenes.Serialization ICollection sceneObjects = new List(); foreach (XmlNode aPrimNode in rootNode.ChildNodes) { - SceneObjectGroup obj = CreatePrimFromXml2(scene, aPrimNode.OuterXml); - if (obj != null && startScripts) + SceneObjectGroup obj = DeserializeGroupFromXml2(aPrimNode.OuterXml); + if (startScripts) sceneObjects.Add(obj); } @@ -319,27 +276,6 @@ namespace OpenSim.Region.Framework.Scenes.Serialization } } - /// - /// Create a prim from the xml2 representation. - /// - /// - /// - /// The scene object created. null if the scene object already existed - protected static SceneObjectGroup CreatePrimFromXml2(Scene scene, string xmlData) - { - //SceneObjectGroup obj = SceneObjectSerializer.FromXml2Format(xmlData); - using (XmlTextReader reader = new XmlTextReader(new StringReader(xmlData))) - { - SceneObjectGroup obj = new SceneObjectGroup(); - SceneObjectSerializer.Xml2ToSOG(reader, obj); - - if (scene.AddRestoredSceneObject(obj, true, false)) - return obj; - else - return null; - } - } - #endregion } -} +} \ No newline at end of file diff --git a/OpenSim/Tests/Common/Helpers/SceneHelpers.cs b/OpenSim/Tests/Common/Helpers/SceneHelpers.cs index 78f94347bd..59829d994f 100644 --- a/OpenSim/Tests/Common/Helpers/SceneHelpers.cs +++ b/OpenSim/Tests/Common/Helpers/SceneHelpers.cs @@ -624,7 +624,7 @@ namespace OpenSim.Tests.Common /// /// /// The prefix to be given to part names. This will be suffixed with "Part" - /// (e.g. mynamePart0 for the root part) + /// (e.g. mynamePart1 for the root part) /// /// /// The hexadecimal last part of the UUID for parts created. A UUID of the form "00000000-0000-0000-0000-{0:XD12}" @@ -637,14 +637,14 @@ namespace OpenSim.Tests.Common SceneObjectGroup sog = new SceneObjectGroup( - CreateSceneObjectPart(string.Format("{0}Part0", partNamePrefix), new UUID(rawSogId), ownerId)); + CreateSceneObjectPart(string.Format("{0}Part1", partNamePrefix), new UUID(rawSogId), ownerId)); if (parts > 1) - for (int i = 1; i < parts; i++) + for (int i = 2; i <= parts; i++) sog.AddPart( CreateSceneObjectPart( string.Format("{0}Part{1}", partNamePrefix, i), - new UUID(string.Format("00000000-0000-0000-0000-{0:X12}", uuidTail + i)), + new UUID(string.Format("00000000-0000-0000-0000-{0:X12}", uuidTail + i - 1)), ownerId)); return sog; diff --git a/bin/Ionic.Zip.dll b/bin/Ionic.Zip.dll old mode 100755 new mode 100644