diff --git a/OpenSim/Framework/AvatarAppearance.cs b/OpenSim/Framework/AvatarAppearance.cs index be15e1bf92..c0bc47e358 100644 --- a/OpenSim/Framework/AvatarAppearance.cs +++ b/OpenSim/Framework/AvatarAppearance.cs @@ -451,22 +451,33 @@ 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) { lock (m_attachments) { 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) { @@ -478,6 +489,7 @@ namespace OpenSim.Framework { ReplaceAttachment(new AvatarAttachment(attachpoint,item,asset)); } + return true; } public int GetAttachpoint(UUID itemID) @@ -495,7 +507,7 @@ namespace OpenSim.Framework } } - public void DetachAttachment(UUID itemID) + public bool DetachAttachment(UUID itemID) { lock (m_attachments) { @@ -510,10 +522,11 @@ 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/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/Avatar/Attachments/AttachmentsModule.cs b/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs index 25d4f21a38..8c925889cb 100644 --- a/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs @@ -133,8 +133,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) @@ -346,8 +344,9 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments if (m_scene.InventoryService != null) item = m_scene.InventoryService.GetItem(item); - if (presence.Appearance != null) - 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; @@ -397,9 +396,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments if (m_scene.InventoryService == null) m_log.Error("[ATTACHMENT]: m_scene.InventoryService == null"); 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); } } @@ -419,11 +417,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); } @@ -448,9 +446,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); } 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 d9812dff27..cb8c5de670 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 @@ -135,19 +142,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) @@ -156,6 +171,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) { @@ -217,11 +255,6 @@ namespace OpenSim.Region.CoreModules.World.Land } } - - public void PostInitialise() - { - } - public void Close() { } @@ -231,11 +264,6 @@ namespace OpenSim.Region.CoreModules.World.Land get { return "LandManagementModule"; } } - public bool IsSharedModule - { - get { return false; } - } - #endregion #region Parcel Add/Remove/Get/Create @@ -1932,5 +1960,44 @@ namespace OpenSim.Region.CoreModules.World.Land } } } + + 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()); + } } } diff --git a/OpenSim/Region/CoreModules/World/Land/LandObject.cs b/OpenSim/Region/CoreModules/World/Land/LandObject.cs index a00b6b2ad8..7723eb49ed 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..576b645b0e 100644 --- a/OpenSim/Region/Framework/Interfaces/ILandObject.cs +++ b/OpenSim/Region/Framework/Interfaces/ILandObject.cs @@ -43,7 +43,21 @@ 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); + ILandObject Copy(); void SendLandUpdateToAvatarsOverMe(); diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs index 9bad644cc5..56eaf0667e 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.cs @@ -516,12 +516,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 @@ -2584,56 +2578,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(); }); } } @@ -3109,25 +3071,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 7eebb994e9..92fe2ab697 100644 --- a/OpenSim/Region/Framework/Scenes/SceneGraph.cs +++ b/OpenSim/Region/Framework/Scenes/SceneGraph.cs @@ -82,7 +82,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; @@ -629,8 +628,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); @@ -643,6 +642,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)