diff --git a/OpenSim/Framework/Console/ConsoleDisplayTable.cs b/OpenSim/Framework/Console/ConsoleDisplayTable.cs index e9d1628b1d..c620dfe10c 100644 --- a/OpenSim/Framework/Console/ConsoleDisplayTable.cs +++ b/OpenSim/Framework/Console/ConsoleDisplayTable.cs @@ -79,6 +79,16 @@ namespace OpenSim.Framework.Console return sb.ToString(); } + public void AddColumn(string name, int width) + { + Columns.Add(new ConsoleDisplayTableColumn(name, width)); + } + + public void AddRow(params string[] cells) + { + Rows.Add(new ConsoleDisplayTableRow(cells)); + } + public void AddToStringBuilder(StringBuilder sb) { string formatString = GetFormatString(); @@ -135,5 +145,10 @@ namespace OpenSim.Framework.Console { Cells = cells; } + + public ConsoleDisplayTableRow(params string[] cells) : this() + { + Cells = new List(cells); + } } } \ No newline at end of file diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs index 4cb7a3a5d4..8874585625 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs @@ -3808,6 +3808,15 @@ namespace OpenSim.Region.ClientStack.LindenUDP && part.ParentGroup.HasPrivateAttachmentPoint && part.ParentGroup.AttachedAvatar != AgentId) continue; + + // If the part has since been deleted, then drop the update. In the case of attachments, + // this is to avoid spurious updates to other viewers since post-processing of attachments + // has to change the IsAttachment flag for various reasons (which will end up in a pass + // of the test above). + // + // Actual deletions (kills) happen in another method. + if (part.ParentGroup.IsDeleted) + continue; } objectUpdateBlocks.Value.Add(updateBlock); @@ -3815,7 +3824,20 @@ namespace OpenSim.Region.ClientStack.LindenUDP } else if (!canUseImproved) { - compressedUpdateBlocks.Value.Add(CreateCompressedUpdateBlock((SceneObjectPart)update.Entity, updateFlags)); + SceneObjectPart part = (SceneObjectPart)update.Entity; + ObjectUpdateCompressedPacket.ObjectDataBlock compressedBlock + = CreateCompressedUpdateBlock(part, updateFlags); + + // If the part has since been deleted, then drop the update. In the case of attachments, + // this is to avoid spurious updates to other viewers since post-processing of attachments + // has to change the IsAttachment flag for various reasons (which will end up in a pass + // of the test above). + // + // Actual deletions (kills) happen in another method. + if (part.ParentGroup.IsDeleted) + continue; + + compressedUpdateBlocks.Value.Add(compressedBlock); compressedUpdates.Value.Add(update); } else @@ -3842,6 +3864,15 @@ namespace OpenSim.Region.ClientStack.LindenUDP && part.ParentGroup.HasPrivateAttachmentPoint && part.ParentGroup.AttachedAvatar != AgentId) continue; + + // If the part has since been deleted, then drop the update. In the case of attachments, + // this is to avoid spurious updates to other viewers since post-processing of attachments + // has to change the IsAttachment flag for various reasons (which will end up in a pass + // of the test above). + // + // Actual deletions (kills) happen in another method. + if (part.ParentGroup.IsDeleted) + continue; } terseUpdateBlocks.Value.Add(terseUpdateBlock); diff --git a/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs b/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs index a2b95ebb0b..2b0e4ab5b3 100644 --- a/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs @@ -152,31 +152,40 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments } } - public void SaveChangedAttachments(IScenePresence sp, bool saveAllScripted) + public void DeRezAttachments(IScenePresence sp, bool saveChanged, bool saveAllScripted) { -// m_log.DebugFormat("[ATTACHMENTS MODULE]: Saving changed attachments for {0}", sp.Name); - if (!Enabled) return; - foreach (SceneObjectGroup grp in sp.GetAttachments()) +// m_log.DebugFormat("[ATTACHMENTS MODULE]: Saving changed attachments for {0}", sp.Name); + + lock (sp.AttachmentsSyncLock) { - grp.IsAttachment = false; - grp.AbsolutePosition = grp.RootPart.AttachedPos; - UpdateKnownItem(sp, grp, saveAllScripted); - grp.IsAttachment = true; + foreach (SceneObjectGroup grp in sp.GetAttachments()) + { + grp.Scene.DeleteSceneObject(grp, false); + + if (saveChanged || saveAllScripted) + { + grp.IsAttachment = false; + grp.AbsolutePosition = grp.RootPart.AttachedPos; + UpdateKnownItem(sp, grp, saveAllScripted); + } + } + + sp.ClearAttachments(); } } public void DeleteAttachmentsFromScene(IScenePresence sp, bool silent) { -// m_log.DebugFormat( -// "[ATTACHMENTS MODULE]: Deleting attachments from scene {0} for {1}, silent = {2}", -// m_scene.RegionInfo.RegionName, sp.Name, silent); - if (!Enabled) return; +// m_log.DebugFormat( +// "[ATTACHMENTS MODULE]: Deleting attachments from scene {0} for {1}, silent = {2}", +// m_scene.RegionInfo.RegionName, sp.Name, silent); + foreach (SceneObjectGroup sop in sp.GetAttachments()) { sop.Scene.DeleteSceneObject(sop, silent); @@ -628,6 +637,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments { m_scene.EventManager.TriggerOnAttach(group.LocalId, itemID, UUID.Zero); sp.RemoveAttachment(group); + m_scene.DeleteSceneObject(group, false); // Prepare sog for storage group.AttachedAvatar = UUID.Zero; @@ -636,7 +646,6 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments group.AbsolutePosition = group.RootPart.AttachedPos; UpdateKnownItem(sp, group, true); - m_scene.DeleteSceneObject(group, false); return; } diff --git a/OpenSim/Region/CoreModules/Avatar/AvatarFactory/AvatarFactoryModule.cs b/OpenSim/Region/CoreModules/Avatar/AvatarFactory/AvatarFactoryModule.cs index 705233c2d7..68a4cde969 100644 --- a/OpenSim/Region/CoreModules/Avatar/AvatarFactory/AvatarFactoryModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/AvatarFactory/AvatarFactoryModule.cs @@ -128,7 +128,9 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory /// public void SetAppearance(IScenePresence sp, Primitive.TextureEntry textureEntry, byte[] visualParams) { - // m_log.InfoFormat("[AVFACTORY]: start SetAppearance for {0}", client.AgentId); +// m_log.DebugFormat( +// "[AVFACTORY]: start SetAppearance for {0}, te {1}, visualParams {2}", +// sp.Name, textureEntry, visualParams); // TODO: This is probably not necessary any longer, just assume the // textureEntry set implies that the appearance transaction is complete diff --git a/OpenSim/Region/Framework/Interfaces/IAttachmentsModule.cs b/OpenSim/Region/Framework/Interfaces/IAttachmentsModule.cs index eb071650bc..fde5de1561 100644 --- a/OpenSim/Region/Framework/Interfaces/IAttachmentsModule.cs +++ b/OpenSim/Region/Framework/Interfaces/IAttachmentsModule.cs @@ -43,10 +43,15 @@ namespace OpenSim.Region.Framework.Interfaces void RezAttachments(IScenePresence sp); /// - /// Save the attachments that have change on this presence. + /// Derez the attachements for a scene presence that is closing. /// - /// - void SaveChangedAttachments(IScenePresence sp, bool saveAllScripted); + /// + /// Attachment changes are saved. + /// + /// The presence closing + /// Save changed attachments. + /// Save attachments with scripts even if they haven't changed. + void DeRezAttachments(IScenePresence sp, bool saveChanged, bool saveAllScripted); /// /// Delete all the presence's attachments from the scene diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs index 385febf99d..d44911604a 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.cs @@ -500,6 +500,7 @@ namespace OpenSim.Region.Framework.Scenes public IAttachmentsModule AttachmentsModule { get; set; } public IEntityTransferModule EntityTransferModule { get; private set; } public IAgentAssetTransactions AgentTransactionsModule { get; private set; } + public IUserManagement UserManagementModule { get; private set; } public IAvatarFactoryModule AvatarFactory { @@ -1243,6 +1244,7 @@ namespace OpenSim.Region.Framework.Scenes EntityTransferModule = RequestModuleInterface(); m_groupsModule = RequestModuleInterface(); AgentTransactionsModule = RequestModuleInterface(); + UserManagementModule = RequestModuleInterface(); } #endregion @@ -2021,9 +2023,8 @@ namespace OpenSim.Region.Framework.Scenes sceneObject.SetGroup(groupID, null); } - IUserManagement uman = RequestModuleInterface(); - if (uman != null) - sceneObject.RootPart.CreatorIdentification = uman.GetUserUUI(ownerID); + if (UserManagementModule != null) + sceneObject.RootPart.CreatorIdentification = UserManagementModule.GetUserUUI(ownerID); sceneObject.ScheduleGroupForFullUpdate(); @@ -2711,14 +2712,13 @@ namespace OpenSim.Region.Framework.Scenes /// private void CacheUserName(ScenePresence sp, AgentCircuitData aCircuit) { - IUserManagement uMan = RequestModuleInterface(); - if (uMan != null) + if (UserManagementModule != null) { string first = aCircuit.firstname, last = aCircuit.lastname; if (sp.PresenceType == PresenceType.Npc) { - uMan.AddUser(aCircuit.AgentID, first, last); + UserManagementModule.AddUser(aCircuit.AgentID, first, last); } else { @@ -2737,7 +2737,7 @@ namespace OpenSim.Region.Framework.Scenes } } - uMan.AddUser(aCircuit.AgentID, first, last, homeURL); + UserManagementModule.AddUser(aCircuit.AgentID, first, last, homeURL); } } } @@ -3292,17 +3292,19 @@ namespace OpenSim.Region.Framework.Scenes if (!isChildAgent) { - if (AttachmentsModule != null && avatar.PresenceType != PresenceType.Npc) + if (AttachmentsModule != null) { - IUserManagement uMan = RequestModuleInterface(); // Don't save attachments for HG visitors, it // messes up their inventory. When a HG visitor logs // out on a foreign grid, their attachments will be // reloaded in the state they were in when they left // the home grid. This is best anyway as the visited // grid may use an incompatible script engine. - if (uMan == null || uMan.IsLocalGridUser(avatar.UUID)) - AttachmentsModule.SaveChangedAttachments(avatar, false); + bool saveChanged + = avatar.PresenceType != PresenceType.Npc + && (UserManagementModule == null || UserManagementModule.IsLocalGridUser(avatar.UUID)); + + AttachmentsModule.DeRezAttachments(avatar, saveChanged, false); } ForEachClient( diff --git a/OpenSim/Region/Framework/Scenes/ScenePresence.cs b/OpenSim/Region/Framework/Scenes/ScenePresence.cs index 3909fd4706..909c7c86d7 100644 --- a/OpenSim/Region/Framework/Scenes/ScenePresence.cs +++ b/OpenSim/Region/Framework/Scenes/ScenePresence.cs @@ -3416,9 +3416,6 @@ namespace OpenSim.Region.Framework.Scenes public void Close() { - if (!IsChildAgent && m_scene.AttachmentsModule != null) - m_scene.AttachmentsModule.DeleteAttachmentsFromScene(this, false); - // Clear known regions KnownRegions = new Dictionary(); diff --git a/OpenSim/Region/Framework/Scenes/Tests/SceneObjectBasicTests.cs b/OpenSim/Region/Framework/Scenes/Tests/SceneObjectBasicTests.cs index 453e077c8a..81add43062 100644 --- a/OpenSim/Region/Framework/Scenes/Tests/SceneObjectBasicTests.cs +++ b/OpenSim/Region/Framework/Scenes/Tests/SceneObjectBasicTests.cs @@ -187,8 +187,13 @@ namespace OpenSim.Region.Framework.Scenes.Tests TestScene scene = new SceneHelpers().SetupScene(); SceneObjectPart part = SceneHelpers.AddSceneObject(scene); + + Assert.That(part.ParentGroup.IsDeleted, Is.False); + scene.DeleteSceneObject(part.ParentGroup, false); + Assert.That(part.ParentGroup.IsDeleted, Is.True); + SceneObjectPart retrievedPart = scene.GetSceneObjectPart(part.LocalId); Assert.That(retrievedPart, Is.Null); } @@ -219,8 +224,12 @@ namespace OpenSim.Region.Framework.Scenes.Tests Assert.That(retrievedPart, Is.Not.Null); + Assert.That(part.ParentGroup.IsDeleted, Is.False); + sogd.InventoryDeQueueAndDelete(); + Assert.That(part.ParentGroup.IsDeleted, Is.True); + SceneObjectPart retrievedPart2 = scene.GetSceneObjectPart(part.LocalId); Assert.That(retrievedPart2, Is.Null); } diff --git a/OpenSim/Services/GridService/GridService.cs b/OpenSim/Services/GridService/GridService.cs index 11897f8809..842a6979a9 100644 --- a/OpenSim/Services/GridService/GridService.cs +++ b/OpenSim/Services/GridService/GridService.cs @@ -85,19 +85,38 @@ namespace OpenSim.Services.GridService if (MainConsole.Instance != null) { MainConsole.Instance.Commands.AddCommand("Regions", true, - "deregister region", - "deregister region ", + "deregister region id", + "deregister region id ", "Deregister a region manually.", String.Empty, HandleDeregisterRegion); + // A messy way of stopping this command being added if we are in standalone (since the simulator + // has an identically named command + // + // XXX: We're relying on the OpenSimulator version being registered first, which is not well defined. + if (MainConsole.Instance.Commands.Resolve(new string[] { "show", "regions" }).Length == 0) + MainConsole.Instance.Commands.AddCommand("Regions", true, + "show regions", + "show all regions", + "Show details on all regions", + String.Empty, + HandleShowRegions); + MainConsole.Instance.Commands.AddCommand("Regions", true, - "show region", - "show region ", + "show region name", + "show region name ", "Show details on a region", String.Empty, HandleShowRegion); + MainConsole.Instance.Commands.AddCommand("Regions", true, + "show region at", + "show region at ", + "Show details on a region at the given co-ordinate.", + "For example, show region at 1000 1000", + HandleShowRegionAt); + MainConsole.Instance.Commands.AddCommand("Regions", true, "set region flags", "set region flags ", @@ -504,13 +523,13 @@ namespace OpenSim.Services.GridService private void HandleDeregisterRegion(string module, string[] cmd) { - if (cmd.Length != 3) + if (cmd.Length != 4) { - MainConsole.Instance.Output("Syntax: degregister region "); + MainConsole.Instance.Output("Syntax: degregister region id "); return; } - string rawRegionUuid = cmd[2]; + string rawRegionUuid = cmd[3]; UUID regionUuid; if (!UUID.TryParse(rawRegionUuid, out regionUuid)) @@ -540,36 +559,107 @@ namespace OpenSim.Services.GridService return; } + private void HandleShowRegions(string module, string[] cmd) + { + if (cmd.Length != 2) + { + MainConsole.Instance.Output("Syntax: show regions"); + return; + } + + List regions = m_Database.Get(int.MinValue, int.MinValue, int.MaxValue, int.MaxValue, UUID.Zero); + + OutputRegionsToConsoleSummary(regions); + } + + private void HandleShowRegion(string module, string[] cmd) { - if (cmd.Length != 3) + if (cmd.Length != 4) { - MainConsole.Instance.Output("Syntax: show region "); + MainConsole.Instance.Output("Syntax: show region name "); return; } - List regions = m_Database.Get(cmd[2], UUID.Zero); + + string regionName = cmd[3]; + + List regions = m_Database.Get(regionName, UUID.Zero); if (regions == null || regions.Count < 1) { - MainConsole.Instance.Output("Region not found"); + MainConsole.Instance.Output("No region with name {0} found", regionName); return; } + OutputRegionsToConsole(regions); + } + + private void HandleShowRegionAt(string module, string[] cmd) + { + if (cmd.Length != 5) + { + MainConsole.Instance.Output("Syntax: show region at "); + return; + } + + int x, y; + if (!int.TryParse(cmd[3], out x)) + { + MainConsole.Instance.Output("x-coord must be an integer"); + return; + } + + if (!int.TryParse(cmd[4], out y)) + { + MainConsole.Instance.Output("y-coord must be an integer"); + return; + } + + RegionData region = m_Database.Get(x * (int)Constants.RegionSize, y * (int)Constants.RegionSize, UUID.Zero); + if (region == null) + { + MainConsole.Instance.OutputFormat("No region found at {0},{1}", x, y); + return; + } + + OutputRegionToConsole(region); + } + + private void OutputRegionToConsole(RegionData r) + { + OpenSim.Data.RegionFlags flags = (OpenSim.Data.RegionFlags)Convert.ToInt32(r.Data["flags"]); + + ConsoleDisplayList dispList = new ConsoleDisplayList(); + dispList.AddRow("Region Name", r.RegionName); + dispList.AddRow("Region ID", r.RegionID); + dispList.AddRow("Location", string.Format("{0},{1}", r.coordX, r.coordY)); + dispList.AddRow("URI", r.Data["serverURI"]); + dispList.AddRow("Owner ID", r.Data["owner_uuid"]); + dispList.AddRow("Flags", flags); + + MainConsole.Instance.Output(dispList.ToString()); + } + + private void OutputRegionsToConsole(List regions) + { + foreach (RegionData r in regions) + OutputRegionToConsole(r); + } + + private void OutputRegionsToConsoleSummary(List regions) + { + ConsoleDisplayTable dispTable = new ConsoleDisplayTable(); + dispTable.AddColumn("Name", 16); + dispTable.AddColumn("ID", 36); + dispTable.AddColumn("Owner ID", 36); + dispTable.AddColumn("Flags", 60); + foreach (RegionData r in regions) { OpenSim.Data.RegionFlags flags = (OpenSim.Data.RegionFlags)Convert.ToInt32(r.Data["flags"]); - - ConsoleDisplayList dispList = new ConsoleDisplayList(); - dispList.AddRow("Region Name", r.RegionName); - dispList.AddRow("Region ID", r.RegionID); - dispList.AddRow("Location", string.Format("{0},{1}", r.coordX, r.coordY)); - dispList.AddRow("URI", r.Data["serverURI"]); - dispList.AddRow("Owner ID", r.Data["owner_uuid"]); - dispList.AddRow("Flags", flags); - - MainConsole.Instance.Output(dispList.ToString()); + dispTable.AddRow(r.RegionName, r.RegionID.ToString(), r.Data["owner_uuid"].ToString(), flags.ToString()); } - return; + MainConsole.Instance.Output(dispTable.ToString()); } private int ParseFlags(int prev, string flags)