From c4727645b864a92fc489427c516ccab3a21c2d91 Mon Sep 17 00:00:00 2001 From: Mic Bowman Date: Tue, 25 Jan 2011 14:23:58 -0800 Subject: [PATCH 1/4] Removed a few more spurious appearance saves. When an avatar enters a region the attachments module tries to update the appearance with attachments that are already part of the appearance. Just added a check to only save if the attachments weren't there before. --- OpenSim/Framework/AvatarAppearance.cs | 23 +++++++++++++++---- .../Avatar/Attachments/AttachmentsModule.cs | 22 ++++++++---------- .../AvatarFactory/AvatarFactoryModule.cs | 4 +++- 3 files changed, 31 insertions(+), 18 deletions(-) diff --git a/OpenSim/Framework/AvatarAppearance.cs b/OpenSim/Framework/AvatarAppearance.cs index 18a5733bda..5a6b265aad 100644 --- a/OpenSim/Framework/AvatarAppearance.cs +++ b/OpenSim/Framework/AvatarAppearance.cs @@ -427,19 +427,30 @@ namespace OpenSim.Framework /// 0x80 bit set then we assume this is an append /// operation otherwise we replace whatever is /// currently attached at the attachpoint + /// return true if something actually changed /// - public void SetAttachment(int attachpoint, UUID item, UUID asset) + public bool SetAttachment(int attachpoint, UUID item, UUID asset) { if (attachpoint == 0) - return; + return false; if (item == UUID.Zero) { if (m_attachments.ContainsKey(attachpoint)) + { m_attachments.Remove(attachpoint); - return; + return true; + } + return false; } + // check if the item is already attached at this point + if (GetAttachpoint(item) == (attachpoint & 0x7F)) + { + // m_log.DebugFormat("[AVATAR APPEARANCE] attempt to attach an already attached item {0}",item); + return false; + } + // check if this is an append or a replace, 0x80 marks it as an append if ((attachpoint & 0x80) > 0) { @@ -451,6 +462,7 @@ namespace OpenSim.Framework { ReplaceAttachment(new AvatarAttachment(attachpoint,item,asset)); } + return true; } public int GetAttachpoint(UUID itemID) @@ -465,7 +477,7 @@ namespace OpenSim.Framework return 0; } - public void DetachAttachment(UUID itemID) + public bool DetachAttachment(UUID itemID) { foreach (KeyValuePair> kvp in m_attachments) { @@ -478,9 +490,10 @@ namespace OpenSim.Framework // And remove the list if there are no more attachments here if (m_attachments[kvp.Key].Count == 0) m_attachments.Remove(kvp.Key); - return; + return true; } } + return false; } public void ClearAttachments() diff --git a/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs b/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs index 360a0145ff..ff262648e5 100644 --- a/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs @@ -132,8 +132,6 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments "[ATTACHMENTS MODULE]: Saving avatar attachment. AgentID: " + remoteClient.AgentId + ", AttachmentPoint: " + AttachmentPt); - if (m_scene.AvatarFactory != null) - m_scene.AvatarFactory.QueueAppearanceSave(remoteClient.AgentId); } } catch (Exception e) @@ -336,7 +334,9 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments InventoryItemBase item = new InventoryItemBase(itemID, remoteClient.AgentId); item = m_scene.InventoryService.GetItem(item); - presence.Appearance.SetAttachment((int)AttachmentPt, itemID, item.AssetID /*att.UUID*/); + bool changed = presence.Appearance.SetAttachment((int)AttachmentPt, itemID, item.AssetID); + if (changed && m_scene.AvatarFactory != null) + m_scene.AvatarFactory.QueueAppearanceSave(remoteClient.AgentId); } return att.UUID; @@ -380,9 +380,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments // XXYY!! InventoryItemBase item = new InventoryItemBase(itemID, remoteClient.AgentId); item = m_scene.InventoryService.GetItem(item); - presence.Appearance.SetAttachment((int)AttachmentPt, itemID, item.AssetID /* att.UUID */); - - if (m_scene.AvatarFactory != null) + bool changed = presence.Appearance.SetAttachment((int)AttachmentPt, itemID, item.AssetID); + if (changed && m_scene.AvatarFactory != null) m_scene.AvatarFactory.QueueAppearanceSave(remoteClient.AgentId); } } @@ -402,11 +401,11 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments ScenePresence presence; if (m_scene.TryGetScenePresence(remoteClient.AgentId, out presence)) { - presence.Appearance.DetachAttachment(itemID); - // Save avatar attachment information m_log.Debug("[ATTACHMENTS MODULE]: Detaching from UserID: " + remoteClient.AgentId + ", ItemID: " + itemID); - if (m_scene.AvatarFactory != null) + + bool changed = presence.Appearance.DetachAttachment(itemID); + if (changed && m_scene.AvatarFactory != null) m_scene.AvatarFactory.QueueAppearanceSave(remoteClient.AgentId); } @@ -431,9 +430,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments part.ParentGroup.PrimCount, remoteClient.AgentId, presence.AbsolutePosition)) return; - presence.Appearance.DetachAttachment(itemID); - - if (m_scene.AvatarFactory != null) + bool changed = presence.Appearance.DetachAttachment(itemID); + if (changed && m_scene.AvatarFactory != null) m_scene.AvatarFactory.QueueAppearanceSave(remoteClient.AgentId); part.ParentGroup.DetachToGround(); diff --git a/OpenSim/Region/CoreModules/Avatar/AvatarFactory/AvatarFactoryModule.cs b/OpenSim/Region/CoreModules/Avatar/AvatarFactory/AvatarFactoryModule.cs index ed0a290fd4..f8ce444b50 100644 --- a/OpenSim/Region/CoreModules/Avatar/AvatarFactory/AvatarFactoryModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/AvatarFactory/AvatarFactoryModule.cs @@ -217,7 +217,9 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory // update transaction. In theory, we should be able to do an immediate // appearance send and save here. - QueueAppearanceSave(client.AgentId); + // save only if there were changes, send no matter what (doesn't hurt to send twice) + if (changed) + QueueAppearanceSave(client.AgentId); QueueAppearanceSend(client.AgentId); } From a0469daf759d09de040aa8b5287fab9a83555cc1 Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Wed, 26 Jan 2011 21:12:41 +0000 Subject: [PATCH 2/4] Implement command "land show". This shows all the parcels on the currently selected region/s This is useful for diagnostics. The command is "land show" rather than "show land" because it's implemented as a module specific subcommand. --- OpenSim/Framework/Console/ConsoleBase.cs | 2 +- .../CoreModules/World/Land/LandChannel.cs | 2 +- .../World/Land/LandManagementModule.cs | 97 ++++++++++++++++--- .../CoreModules/World/Land/LandObject.cs | 40 +++++++- .../Framework/Interfaces/ILandObject.cs | 4 + 5 files changed, 126 insertions(+), 19 deletions(-) diff --git a/OpenSim/Framework/Console/ConsoleBase.cs b/OpenSim/Framework/Console/ConsoleBase.cs index 3ef76cf588..c59fbca074 100755 --- a/OpenSim/Framework/Console/ConsoleBase.cs +++ b/OpenSim/Framework/Console/ConsoleBase.cs @@ -76,7 +76,7 @@ namespace OpenSim.Framework.Console System.Console.WriteLine(text); } - public virtual void OutputFormat(string format, params string[] components) + public virtual void OutputFormat(string format, params object[] components) { Output(string.Format(format, components)); } diff --git a/OpenSim/Region/CoreModules/World/Land/LandChannel.cs b/OpenSim/Region/CoreModules/World/Land/LandChannel.cs index 1ad4db2404..9e27ef07f8 100644 --- a/OpenSim/Region/CoreModules/World/Land/LandChannel.cs +++ b/OpenSim/Region/CoreModules/World/Land/LandChannel.cs @@ -64,7 +64,7 @@ namespace OpenSim.Region.CoreModules.World.Land #endregion private readonly Scene m_scene; - private readonly LandManagementModule m_landManagementModule; + private readonly LandManagementModule m_landManagementModule; public LandChannel(Scene scene, LandManagementModule landManagementMod) { diff --git a/OpenSim/Region/CoreModules/World/Land/LandManagementModule.cs b/OpenSim/Region/CoreModules/World/Land/LandManagementModule.cs index 4f8e2059e5..70767f7b4c 100644 --- a/OpenSim/Region/CoreModules/World/Land/LandManagementModule.cs +++ b/OpenSim/Region/CoreModules/World/Land/LandManagementModule.cs @@ -30,6 +30,7 @@ using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; +using System.Text; using log4net; using Nini.Config; using OpenMetaverse; @@ -37,19 +38,22 @@ using OpenMetaverse.StructuredData; using OpenMetaverse.Messages.Linden; using OpenSim.Framework; using OpenSim.Framework.Capabilities; +using OpenSim.Framework.Console; using OpenSim.Framework.Servers; using OpenSim.Framework.Servers.HttpServer; -using OpenSim.Services.Interfaces; +using OpenSim.Region.CoreModules.Framework.InterfaceCommander; using OpenSim.Region.Framework.Interfaces; using OpenSim.Region.Framework.Scenes; using OpenSim.Region.Physics.Manager; -using Caps=OpenSim.Framework.Capabilities.Caps; +using OpenSim.Services.Interfaces; +using Caps = OpenSim.Framework.Capabilities.Caps; using GridRegion = OpenSim.Services.Interfaces.GridRegion; namespace OpenSim.Region.CoreModules.World.Land { // used for caching - internal class ExtendedLandData { + internal class ExtendedLandData + { public LandData LandData; public ulong RegionHandle; public uint X, Y; @@ -65,6 +69,9 @@ namespace OpenSim.Region.CoreModules.World.Land private LandChannel landChannel; private Scene m_scene; + protected Commander m_commander = new Commander("land"); + + protected IUserManagement m_userManager; // Minimum for parcels to work is 64m even if we don't actually use them. #pragma warning disable 0429 @@ -127,19 +134,27 @@ namespace OpenSim.Region.CoreModules.World.Land m_scene.EventManager.OnRequestParcelPrimCountUpdate += EventManagerOnRequestParcelPrimCountUpdate; m_scene.EventManager.OnParcelPrimCountTainted += EventManagerOnParcelPrimCountTainted; m_scene.EventManager.OnRegisterCaps += EventManagerOnRegisterCaps; + m_scene.EventManager.OnPluginConsole += EventManagerOnPluginConsole; lock (m_scene) { m_scene.LandChannel = (ILandChannel)landChannel; } + + InstallInterfaces(); } public void RegionLoaded(Scene scene) { + m_userManager = m_scene.RequestModuleInterface(); } public void RemoveRegion(Scene scene) - { + { + // TODO: Also release other event manager listeners here + + m_scene.EventManager.OnPluginConsole -= EventManagerOnPluginConsole; + m_scene.UnregisterModuleCommander(m_commander.Name); } // private bool OnVerifyUserConnection(ScenePresence scenePresence, out string reason) @@ -148,6 +163,29 @@ namespace OpenSim.Region.CoreModules.World.Land // reason = "You are not allowed to enter this sim."; // return nearestParcel != null; // } + + /// + /// Processes commandline input. Do not call directly. + /// + /// Commandline arguments + protected void EventManagerOnPluginConsole(string[] args) + { + if (args[0] == "land") + { + if (args.Length == 1) + { + m_commander.ProcessConsoleCommand("help", new string[0]); + return; + } + + string[] tmpArgs = new string[args.Length - 2]; + int i; + for (i = 2; i < args.Length; i++) + tmpArgs[i - 2] = args[i]; + + m_commander.ProcessConsoleCommand(args[1], tmpArgs); + } + } void EventManagerOnNewClient(IClientAPI client) { @@ -209,11 +247,6 @@ namespace OpenSim.Region.CoreModules.World.Land } } - - public void PostInitialise() - { - } - public void Close() { } @@ -223,11 +256,6 @@ namespace OpenSim.Region.CoreModules.World.Land get { return "LandManagementModule"; } } - public bool IsSharedModule - { - get { return false; } - } - #endregion #region Parcel Add/Remove/Get/Create @@ -1591,5 +1619,44 @@ namespace OpenSim.Region.CoreModules.World.Land UpdateLandObject(localID, land.LandData); } + + protected void InstallInterfaces() + { + Command showCommand = + new Command("show", CommandIntentions.COMMAND_STATISTICAL, ShowParcelsCommand, "Shows all parcels on the current region."); + + m_commander.RegisterCommand("show", showCommand); + + // Add this to our scene so scripts can call these functions + m_scene.RegisterModuleCommander(m_commander); + } + + protected void ShowParcelsCommand(Object[] args) + { + StringBuilder report = new StringBuilder(); + + report.AppendFormat("Land information for {0}\n", m_scene.RegionInfo.RegionName); + report.AppendFormat( + "{0,-20} {1,-9} {2,-18} {3,-18} {4,-20}\n", + "Parcel Name", + "Area", + "Starts", + "Ends", + "Owner"); + + lock (m_landList) + { + foreach (ILandObject lo in m_landList.Values) + { + LandData ld = lo.LandData; + + report.AppendFormat( + "{0,-20} {1,-9} {2,-18} {3,-18} {4,-20}\n", + ld.Name, ld.Area, lo.StartPoint, lo.EndPoint, m_userManager.GetUserName(ld.OwnerID)); + } + } + + MainConsole.Instance.Output(report.ToString()); + } } -} +} \ No newline at end of file diff --git a/OpenSim/Region/CoreModules/World/Land/LandObject.cs b/OpenSim/Region/CoreModules/World/Land/LandObject.cs index 4e1f9c5c43..b90e3078e2 100644 --- a/OpenSim/Region/CoreModules/World/Land/LandObject.cs +++ b/OpenSim/Region/CoreModules/World/Land/LandObject.cs @@ -77,7 +77,43 @@ namespace OpenSim.Region.CoreModules.World.Land { get { return m_scene.RegionInfo.RegionID; } } - + + public Vector3 StartPoint + { + get + { + for (int y = 0; y < landArrayMax; y++) + { + for (int x = 0; x < landArrayMax; x++) + { + if (LandBitmap[x, y]) + return new Vector3(x * 4, y * 4, 0); + } + } + + return new Vector3(-1, -1, -1); + } + } + + public Vector3 EndPoint + { + get + { + for (int y = landArrayMax - 1; y >= 0; y--) + { + for (int x = landArrayMax - 1; x >= 0; x--) + { + if (LandBitmap[x, y]) + { + return new Vector3(x * 4, y * 4, 0); + } + } + } + + return new Vector3(-1, -1, -1); + } + } + #region Constructors public LandObject(UUID owner_id, bool is_group_owned, Scene scene) @@ -96,7 +132,7 @@ namespace OpenSim.Region.CoreModules.World.Land #region Member Functions #region General Functions - + /// /// Checks to see if this land object contains a point /// diff --git a/OpenSim/Region/Framework/Interfaces/ILandObject.cs b/OpenSim/Region/Framework/Interfaces/ILandObject.cs index 585eb004fa..b7487e8d3c 100644 --- a/OpenSim/Region/Framework/Interfaces/ILandObject.cs +++ b/OpenSim/Region/Framework/Interfaces/ILandObject.cs @@ -43,7 +43,11 @@ namespace OpenSim.Region.Framework.Interfaces LandData LandData { get; set; } bool[,] LandBitmap { get; set; } UUID RegionUUID { get; } + Vector3 StartPoint { get; } + Vector3 EndPoint { get; } + bool ContainsPoint(int x, int y); + ILandObject Copy(); void SendLandUpdateToAvatarsOverMe(); From 8eb2789ae1d1f94ea9dfe4bf25b1c69065f0f960 Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Wed, 26 Jan 2011 21:19:22 +0000 Subject: [PATCH 3/4] Add some comments on ILandObject.StartPoint and EndPoint --- OpenSim/Region/Framework/Interfaces/ILandObject.cs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/OpenSim/Region/Framework/Interfaces/ILandObject.cs b/OpenSim/Region/Framework/Interfaces/ILandObject.cs index b7487e8d3c..576b645b0e 100644 --- a/OpenSim/Region/Framework/Interfaces/ILandObject.cs +++ b/OpenSim/Region/Framework/Interfaces/ILandObject.cs @@ -43,7 +43,17 @@ namespace OpenSim.Region.Framework.Interfaces LandData LandData { get; set; } bool[,] LandBitmap { get; set; } UUID RegionUUID { get; } + + /// + /// The start point for the land object. This is the western-most point as one scans land working from + /// north to south. + /// Vector3 StartPoint { get; } + + /// + /// The end point for the land object. This is the eastern-most point as one scans land working from + /// south to north. + /// Vector3 EndPoint { get; } bool ContainsPoint(int x, int y); From 240c0eaf1d8886378829e32a68aa9d2534f31a09 Mon Sep 17 00:00:00 2001 From: Mic Bowman Date: Wed, 26 Jan 2011 13:33:34 -0800 Subject: [PATCH 4/4] Remove the RestorePresences functions (which don't seem to be doing anything) and clean up the code in AddNewClient (so Appearance only gets assigned once, not three times). --- OpenSim/Region/Framework/Scenes/Scene.cs | 77 +++---------------- OpenSim/Region/Framework/Scenes/SceneGraph.cs | 4 +- 2 files changed, 12 insertions(+), 69 deletions(-) diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs index 12fd813e0c..71d0f09440 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.cs @@ -498,12 +498,6 @@ namespace OpenSim.Region.Framework.Scenes get { return m_sceneGraph.Entities; } } - public Dictionary m_restorePresences - { - get { return m_sceneGraph.RestorePresences; } - set { m_sceneGraph.RestorePresences = value; } - } - #endregion Properties #region Constructors @@ -2483,56 +2477,24 @@ namespace OpenSim.Region.Framework.Scenes (aCircuit.teleportFlags & (uint)Constants.TeleportFlags.ViaLogin) != 0; CheckHeartbeat(); - ScenePresence presence; - if (m_restorePresences.ContainsKey(client.AgentId)) + if (GetScenePresence(client.AgentId) == null) // ensure there is no SP here { - m_log.DebugFormat("[SCENE]: Restoring agent {0} {1} in {2}", client.Name, client.AgentId, RegionInfo.RegionName); + m_log.Debug("[SCENE]: Adding new agent " + client.Name + " to scene " + RegionInfo.RegionName); m_clientManager.Add(client); SubscribeToClientEvents(client); - presence = m_restorePresences[client.AgentId]; - m_restorePresences.Remove(client.AgentId); + ScenePresence sp = m_sceneGraph.CreateAndAddChildScenePresence(client, aCircuit.Appearance); + m_eventManager.TriggerOnNewPresence(sp); - // This is one of two paths to create avatars that are - // used. This tends to get called more in standalone - // than grid, not really sure why, but as such needs - // an explicity appearance lookup here. - AvatarAppearance appearance = null; - GetAvatarAppearance(client, out appearance); - presence.Appearance = appearance; - - presence.initializeScenePresence(client, RegionInfo, this); - - m_sceneGraph.AddScenePresence(presence); - - lock (m_restorePresences) + // HERE!!! Do the initial attachments right here + // first agent upon login is a root agent by design. + // All other AddNewClient calls find aCircuit.child to be true + if (aCircuit.child == false) { - Monitor.PulseAll(m_restorePresences); - } - } - else - { - if (GetScenePresence(client.AgentId) == null) // ensure there is no SP here - { - m_log.Debug("[SCENE]: Adding new agent " + client.Name + " to scene " + RegionInfo.RegionName); - - m_clientManager.Add(client); - SubscribeToClientEvents(client); - - ScenePresence sp = CreateAndAddScenePresence(client); - if (aCircuit != null) - sp.Appearance = aCircuit.Appearance; - - // HERE!!! Do the initial attachments right here - // first agent upon login is a root agent by design. - // All other AddNewClient calls find aCircuit.child to be true - if (aCircuit == null || (aCircuit != null && aCircuit.child == false)) - { - sp.IsChildAgent = false; - Util.FireAndForget(delegate(object o) { sp.RezAttachments(); }); - } + sp.IsChildAgent = false; + Util.FireAndForget(delegate(object o) { sp.RezAttachments(); }); } } @@ -2996,25 +2958,6 @@ namespace OpenSim.Region.Framework.Scenes m_dialogModule.SendAlertToUser(remoteClient, "Set Home request Failed."); } - /// - /// Create a child agent scene presence and add it to this scene. - /// - /// - /// - protected virtual ScenePresence CreateAndAddScenePresence(IClientAPI client) - { - CheckHeartbeat(); - AvatarAppearance appearance = null; - GetAvatarAppearance(client, out appearance); - - ScenePresence avatar = m_sceneGraph.CreateAndAddChildScenePresence(client, appearance); - //avatar.KnownRegions = GetChildrenSeeds(avatar.UUID); - - m_eventManager.TriggerOnNewPresence(avatar); - - return avatar; - } - /// /// Get the avatar apperance for the given client. /// diff --git a/OpenSim/Region/Framework/Scenes/SceneGraph.cs b/OpenSim/Region/Framework/Scenes/SceneGraph.cs index a2ed54ff9b..969ff13ac7 100644 --- a/OpenSim/Region/Framework/Scenes/SceneGraph.cs +++ b/OpenSim/Region/Framework/Scenes/SceneGraph.cs @@ -73,7 +73,6 @@ namespace OpenSim.Region.Framework.Scenes protected List m_scenePresenceArray = new List(); protected internal EntityManager Entities = new EntityManager(); - protected internal Dictionary RestorePresences = new Dictionary(); protected RegionInfo m_regInfo; protected Scene m_parentScene; @@ -564,8 +563,8 @@ namespace OpenSim.Region.Framework.Scenes { ScenePresence newAvatar = null; + // ScenePresence always defaults to child agent newAvatar = new ScenePresence(client, m_parentScene, m_regInfo, appearance); - newAvatar.IsChildAgent = true; AddScenePresence(newAvatar); @@ -578,6 +577,7 @@ namespace OpenSim.Region.Framework.Scenes /// protected internal void AddScenePresence(ScenePresence presence) { + // Always a child when added to the scene bool child = presence.IsChildAgent; if (child)