diff --git a/CONTRIBUTORS.txt b/CONTRIBUTORS.txt index ee3d7c7141..6fa116d27d 100644 --- a/CONTRIBUTORS.txt +++ b/CONTRIBUTORS.txt @@ -1,5 +1,4 @@ - <<<>>>>The following people have contributed to OpenSim (Thank you -for your effort!) +The following people have contributed to OpenSim (Thank you for your effort!) = Current OpenSim Developers (in very rough order of appearance) = These folks represent the current core team for OpenSim, and are the @@ -61,8 +60,9 @@ where we are today. These folks have contributed code patches or content to OpenSimulator to help make it what it is today. -* aduffy70 * A_Biondi +* aduffy70 +* Ai Austin * alex_carnell * Alan Webb (IBM) * Aleric @@ -75,7 +75,7 @@ what it is today. * Chris Yeoh (IBM) * controlbreak * coyled -* ctrlaltdavid +* ctrlaltdavid (David Rowe) * Daedius * daTwitch * devalnor-#708 @@ -173,23 +173,18 @@ what it is today. * Zha Ewry * ziah - = LSL Devs = - * Alondria * CharlieO * Tedd * Melanie Thielker - = Testers = - * Ai Austin * CharlieO (LSL) * Ckrinke * openlifegrid.com - This software uses components from the following developers: * Sleepycat Software (Berkeley DB) * Aurora-Sim (http://aurora-sim.org) diff --git a/OpenSim/Addons/OfflineIM/OfflineIMRegionModule.cs b/OpenSim/Addons/OfflineIM/OfflineIMRegionModule.cs index 050ebd20f0..5ef068a251 100644 --- a/OpenSim/Addons/OfflineIM/OfflineIMRegionModule.cs +++ b/OpenSim/Addons/OfflineIM/OfflineIMRegionModule.cs @@ -261,6 +261,11 @@ namespace OpenSim.OfflineIM return m_OfflineIMService.StoreMessage(im, out reason); } + public void DeleteMessages(UUID userID) + { + m_OfflineIMService.DeleteMessages(userID); + } + #endregion } } diff --git a/OpenSim/Addons/OfflineIM/Remote/OfflineIMServiceRemoteConnector.cs b/OpenSim/Addons/OfflineIM/Remote/OfflineIMServiceRemoteConnector.cs index 69feb762f9..f6b17e5a5d 100644 --- a/OpenSim/Addons/OfflineIM/Remote/OfflineIMServiceRemoteConnector.cs +++ b/OpenSim/Addons/OfflineIM/Remote/OfflineIMServiceRemoteConnector.cs @@ -117,6 +117,14 @@ namespace OpenSim.OfflineIM return true; } + public void DeleteMessages(UUID userID) + { + Dictionary sendData = new Dictionary(); + sendData["UserID"] = userID; + + MakeRequest("DELETE", sendData); + } + #endregion diff --git a/OpenSim/Addons/OfflineIM/Remote/OfflineIMServiceRobustConnector.cs b/OpenSim/Addons/OfflineIM/Remote/OfflineIMServiceRobustConnector.cs index 32c24db42d..13b0e7e6a8 100644 --- a/OpenSim/Addons/OfflineIM/Remote/OfflineIMServiceRobustConnector.cs +++ b/OpenSim/Addons/OfflineIM/Remote/OfflineIMServiceRobustConnector.cs @@ -1,4 +1,4 @@ -/* +/* * Copyright (c) Contributors, http://opensimulator.org/ * See CONTRIBUTORS.TXT for a full list of copyright holders. * @@ -96,13 +96,14 @@ namespace OpenSim.OfflineIM string method = request["METHOD"].ToString(); request.Remove("METHOD"); - m_log.DebugFormat("[OfflineIM.V2.Handler]: {0}", method); switch (method) { case "GET": return HandleGet(request); case "STORE": return HandleStore(request); + case "DELETE": + return HandleDelete(request); } m_log.DebugFormat("[OFFLINE IM HANDLER]: unknown method request: {0}", method); } @@ -159,6 +160,21 @@ namespace OpenSim.OfflineIM return Util.UTF8NoBomEncoding.GetBytes(xmlString); } + byte[] HandleDelete(Dictionary request) + { + if (!request.ContainsKey("UserID")) + { + return FailureResult(); + } + else + { + UUID userID = new UUID(request["UserID"].ToString()); + m_OfflineIMService.DeleteMessages(userID); + + return SuccessResult(); + } + } + #region Helpers private void NullResult(Dictionary result, string reason) diff --git a/OpenSim/Addons/OfflineIM/Service/OfflineIMService.cs b/OpenSim/Addons/OfflineIM/Service/OfflineIMService.cs index 6731923c3b..690c955660 100644 --- a/OpenSim/Addons/OfflineIM/Service/OfflineIMService.cs +++ b/OpenSim/Addons/OfflineIM/Service/OfflineIMService.cs @@ -1,4 +1,4 @@ -/* +/* * Copyright (c) Contributors, http://opensimulator.org/ * See CONTRIBUTORS.TXT for a full list of copyright holders. * @@ -91,7 +91,7 @@ namespace OpenSim.OfflineIM { reason = string.Empty; - // TODO Check limits + // Check limits UUID principalID = new UUID(im.toAgentID); long count = m_Database.GetCount("PrincipalID", principalID.ToString()); if (count >= MAX_IM) @@ -100,7 +100,7 @@ namespace OpenSim.OfflineIM return false; } - string imXml = string.Empty; + string imXml; using (MemoryStream mstream = new MemoryStream()) { XmlWriterSettings settings = new XmlWriterSettings(); @@ -110,22 +110,26 @@ namespace OpenSim.OfflineIM { m_serializer.Serialize(writer, im); writer.Flush(); - - mstream.Position = 0; - using (StreamReader sreader = new StreamReader(mstream)) - { - imXml = sreader.ReadToEnd(); - } } + + imXml = Util.UTF8.GetString(mstream.ToArray()); } OfflineIMData data = new OfflineIMData(); data.PrincipalID = principalID; + data.FromID = new UUID(im.fromAgentID); data.Data = new Dictionary(); data.Data["Message"] = imXml; return m_Database.Store(data); } + + public void DeleteMessages(UUID userID) + { + m_Database.Delete("PrincipalID", userID.ToString()); + m_Database.Delete("FromID", userID.ToString()); + } + } } diff --git a/OpenSim/Data/IOfflineIMData.cs b/OpenSim/Data/IOfflineIMData.cs index e780304ec8..58501a3b7d 100644 --- a/OpenSim/Data/IOfflineIMData.cs +++ b/OpenSim/Data/IOfflineIMData.cs @@ -1,4 +1,4 @@ -/* +/* * Copyright (c) Contributors, http://opensimulator.org/ * See CONTRIBUTORS.TXT for a full list of copyright holders. * @@ -34,6 +34,7 @@ namespace OpenSim.Data public class OfflineIMData { public UUID PrincipalID; + public UUID FromID; public Dictionary Data; } diff --git a/OpenSim/Data/MySQL/Resources/IM_Store.migrations b/OpenSim/Data/MySQL/Resources/IM_Store.migrations index 7cfcd43888..f73475ee33 100644 --- a/OpenSim/Data/MySQL/Resources/IM_Store.migrations +++ b/OpenSim/Data/MySQL/Resources/IM_Store.migrations @@ -21,4 +21,14 @@ INSERT INTO `im_offline` SELECT * from `diva_im_offline`; DROP TABLE `diva_im_offline`; DELETE FROM `migrations` WHERE name='diva_im_Store'; -COMMIT; \ No newline at end of file +COMMIT; + +:VERSION 3 # -------------------------- + +BEGIN; + +ALTER TABLE `im_offline` + ADD `FromID` char(36) NOT NULL default '' AFTER `PrincipalID`, + ADD KEY `FromID` (`FromID`); + +COMMIT; diff --git a/OpenSim/Framework/IImprovedAssetCache.cs b/OpenSim/Framework/IImprovedAssetCache.cs index a0b8b55aaa..a853e9015d 100644 --- a/OpenSim/Framework/IImprovedAssetCache.cs +++ b/OpenSim/Framework/IImprovedAssetCache.cs @@ -31,10 +31,34 @@ namespace OpenSim.Framework { public interface IImprovedAssetCache { + /// + /// Cache the specified asset. + /// + /// void Cache(AssetBase asset); + + /// + /// Get an asset by its id. + /// + /// + /// null if the asset does not exist. AssetBase Get(string id); + + /// + /// Check whether an asset with the specified id exists in the cache. + /// + /// bool Check(string id); + + /// + /// Expire an asset from the cache. + /// + /// void Expire(string id); + + /// + /// Clear the cache. + /// void Clear(); } -} +} \ No newline at end of file diff --git a/OpenSim/Region/CoreModules/Asset/CenomeAssetCache.cs b/OpenSim/Region/CoreModules/Asset/CenomeAssetCache.cs index f43305ff40..9b0e1f4804 100644 --- a/OpenSim/Region/CoreModules/Asset/CenomeAssetCache.cs +++ b/OpenSim/Region/CoreModules/Asset/CenomeAssetCache.cs @@ -194,10 +194,12 @@ namespace OpenSim.Region.CoreModules.Asset #region IImprovedAssetCache Members - public bool Check(string id) { - return false; + AssetBase asset; + + // XXX:This is probably not an efficient implementation. + return m_cache.TryGetValue(id, out asset); } /// diff --git a/OpenSim/Region/CoreModules/Asset/CoreAssetCache.cs b/OpenSim/Region/CoreModules/Asset/CoreAssetCache.cs index 58ce61ac4e..f72074851e 100644 --- a/OpenSim/Region/CoreModules/Asset/CoreAssetCache.cs +++ b/OpenSim/Region/CoreModules/Asset/CoreAssetCache.cs @@ -114,7 +114,8 @@ namespace OpenSim.Region.CoreModules.Asset // public bool Check(string id) { - return false; + // XXX This is probably not an efficient implementation. + return Get(id) != null; } public void Cache(AssetBase asset) diff --git a/OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs b/OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs index f1fee6322c..6a5f8f397e 100644 --- a/OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs +++ b/OpenSim/Region/CoreModules/Asset/FlotsamAssetCache.cs @@ -248,70 +248,67 @@ namespace OpenSim.Region.CoreModules.Asset private void UpdateFileCache(string key, AssetBase asset) { - // TODO: Spawn this off to some seperate thread to do the actual writing - if (asset != null) + string filename = GetFileName(key); + + try { - string filename = GetFileName(key); - - try + // If the file is already cached, don't cache it, just touch it so access time is updated + if (File.Exists(filename)) { - // If the file is already cached, don't cache it, just touch it so access time is updated - if (File.Exists(filename)) + // We don't really want to know about sharing + // violations here. If the file is locked, then + // the other thread has updated the time for us. + try { - // We don't really want to know about sharing - // violations here. If the file is locked, then - // the other thread has updated the time for us. - try - { - lock (m_CurrentlyWriting) - { - if (!m_CurrentlyWriting.Contains(filename)) - File.SetLastAccessTime(filename, DateTime.Now); - } - } - catch - { - } - } else { - - // Once we start writing, make sure we flag that we're writing - // that object to the cache so that we don't try to write the - // same file multiple times. lock (m_CurrentlyWriting) { + if (!m_CurrentlyWriting.Contains(filename)) + File.SetLastAccessTime(filename, DateTime.Now); + } + } + catch + { + } + } + else + { + // Once we start writing, make sure we flag that we're writing + // that object to the cache so that we don't try to write the + // same file multiple times. + lock (m_CurrentlyWriting) + { #if WAIT_ON_INPROGRESS_REQUESTS - if (m_CurrentlyWriting.ContainsKey(filename)) - { - return; - } - else - { - m_CurrentlyWriting.Add(filename, new ManualResetEvent(false)); - } - -#else - if (m_CurrentlyWriting.Contains(filename)) - { - return; - } - else - { - m_CurrentlyWriting.Add(filename); - } -#endif - + if (m_CurrentlyWriting.ContainsKey(filename)) + { + return; + } + else + { + m_CurrentlyWriting.Add(filename, new ManualResetEvent(false)); } - Util.FireAndForget( - delegate { WriteFileCache(filename, asset); }); +#else + if (m_CurrentlyWriting.Contains(filename)) + { + return; + } + else + { + m_CurrentlyWriting.Add(filename); + } +#endif + } + + Util.FireAndForget( + delegate { WriteFileCache(filename, asset); }); } - catch (Exception e) - { - m_log.ErrorFormat( - "[FLOTSAM ASSET CACHE]: Failed to update cache for asset {0}. Exception {1} {2}", - asset.ID, e.Message, e.StackTrace); - } + } + catch (Exception e) + { + m_log.ErrorFormat( + "[FLOTSAM ASSET CACHE]: Failed to update cache for asset {0}. Exception {1} {2}", + asset.ID, e.Message, e.StackTrace); } } @@ -347,15 +344,9 @@ namespace OpenSim.Region.CoreModules.Asset private bool CheckFromMemoryCache(string id) { - AssetBase asset = null; - - if (m_MemoryCache.TryGetValue(id, out asset)) - return true; - - return false; + return m_MemoryCache.Contains(id); } - /// /// Try to get an asset from the file cache. /// @@ -393,15 +384,16 @@ namespace OpenSim.Region.CoreModules.Asset if (File.Exists(filename)) { - FileStream stream = null; try { - stream = File.Open(filename, FileMode.Open, FileAccess.Read, FileShare.Read); - BinaryFormatter bformatter = new BinaryFormatter(); + using (FileStream stream = File.Open(filename, FileMode.Open, FileAccess.Read, FileShare.Read)) + { + BinaryFormatter bformatter = new BinaryFormatter(); - asset = (AssetBase)bformatter.Deserialize(stream); + asset = (AssetBase)bformatter.Deserialize(stream); - m_DiskHits++; + m_DiskHits++; + } } catch (System.Runtime.Serialization.SerializationException e) { @@ -420,12 +412,6 @@ namespace OpenSim.Region.CoreModules.Asset m_log.WarnFormat( "[FLOTSAM ASSET CACHE]: Failed to get file {0} for asset {1}. Exception {2} {3}", filename, id, e.Message, e.StackTrace); - - } - finally - { - if (stream != null) - stream.Close(); } } @@ -437,36 +423,19 @@ namespace OpenSim.Region.CoreModules.Asset bool found = false; string filename = GetFileName(id); + if (File.Exists(filename)) { - // actually check if we can open it, and so update expire - FileStream stream = null; try { - stream = File.Open(filename, FileMode.Open, FileAccess.Read, FileShare.Read); - if (stream != null) + using (FileStream stream = File.Open(filename, FileMode.Open, FileAccess.Read, FileShare.Read)) { - found = true; - stream.Close(); + if (stream != null) + found = true; } - - } - catch (System.Runtime.Serialization.SerializationException e) - { - found = false; - m_log.ErrorFormat( - "[FLOTSAM ASSET CACHE]: Failed to check file {0} for asset {1}. Exception {2} {3}", - filename, id, e.Message, e.StackTrace); - - // If there was a problem deserializing the asset, the asset may - // either be corrupted OR was serialized under an old format - // {different version of AssetBase} -- we should attempt to - // delete it and re-cache - File.Delete(filename); } catch (Exception e) { - found = false; m_log.ErrorFormat( "[FLOTSAM ASSET CACHE]: Failed to check file {0} for asset {1}. Exception {2} {3}", filename, id, e.Message, e.StackTrace); @@ -518,11 +487,6 @@ namespace OpenSim.Region.CoreModules.Asset return Get(id); } - public AssetBase CheckCached(string id) - { - return Get(id); - } - public void Expire(string id) { if (m_LogLevel >= 2) @@ -1067,11 +1031,6 @@ namespace OpenSim.Region.CoreModules.Asset return asset.Data; } - public bool CheckData(string id) - { - return Check(id); ; - } - public bool Get(string id, object sender, AssetRetrieved handler) { AssetBase asset = Get(id); diff --git a/OpenSim/Region/CoreModules/Asset/GlynnTuckerAssetCache.cs b/OpenSim/Region/CoreModules/Asset/GlynnTuckerAssetCache.cs index ce9b5467f6..5f76ac2c9e 100644 --- a/OpenSim/Region/CoreModules/Asset/GlynnTuckerAssetCache.cs +++ b/OpenSim/Region/CoreModules/Asset/GlynnTuckerAssetCache.cs @@ -117,7 +117,7 @@ namespace OpenSim.Region.CoreModules.Asset public bool Check(string id) { - return false; + return m_Cache.Contains(id); } public void Cache(AssetBase asset) diff --git a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs index 4ab36a538e..85e81591ab 100644 --- a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs +++ b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs @@ -1433,7 +1433,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer public GridRegion GetDestination(Scene scene, UUID agentID, Vector3 pos, out string version, out Vector3 newpos) { version = String.Empty; - newpos = new Vector3(pos.X, pos.Y, pos.Z); + newpos = pos; // m_log.DebugFormat( // "[ENTITY TRANSFER MODULE]: Crossing agent {0} at pos {1} in {2}", agent.Name, pos, scene.Name); diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/LocalSimulationConnector.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/LocalSimulationConnector.cs index 678f3dc3a5..4dcb99f0ac 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/LocalSimulationConnector.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/LocalSimulationConnector.cs @@ -174,7 +174,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation #endregion - #region ISimulation + #region ISimulationService public IScene GetScene(UUID regionId) { @@ -353,7 +353,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation return false; } - #endregion /* IInterregionComms */ + #endregion #region Misc diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/RemoteSimulationConnector.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/RemoteSimulationConnector.cs index f45f560a96..cc014307af 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/RemoteSimulationConnector.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/RemoteSimulationConnector.cs @@ -146,7 +146,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation #endregion - #region IInterregionComms + #region ISimulationService public IScene GetScene(UUID regionId) { @@ -279,6 +279,6 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation return false; } - #endregion /* IInterregionComms */ + #endregion } } diff --git a/OpenSim/Region/Framework/Interfaces/IEntityTransferModule.cs b/OpenSim/Region/Framework/Interfaces/IEntityTransferModule.cs index 966916a4b2..709d8fc2ee 100644 --- a/OpenSim/Region/Framework/Interfaces/IEntityTransferModule.cs +++ b/OpenSim/Region/Framework/Interfaces/IEntityTransferModule.cs @@ -47,13 +47,33 @@ namespace OpenSim.Region.Framework.Interfaces /// The handle of the destination region. If it's the same as the region currently /// occupied by the agent then the teleport will be within that region. /// + /// + /// /// /// /// void Teleport(ScenePresence agent, ulong regionHandle, Vector3 position, Vector3 lookAt, uint teleportFlags); + /// + /// Teleports the agent for the given client to their home destination. + /// + /// + /// bool TeleportHome(UUID id, IClientAPI client); + /// + /// Teleport an agent directly to a given region without checking whether the region should be substituted. + /// + /// + /// Please use Teleport() instead unless you know exactly what you're doing. + /// Do not use for same region teleports. + /// + /// + /// + /// /param> + /// + /// + /// void DoTeleport(ScenePresence sp, GridRegion reg, GridRegion finalDestination, Vector3 position, Vector3 lookAt, uint teleportFlags); diff --git a/OpenSim/Region/Framework/Interfaces/IInterregionComms.cs b/OpenSim/Region/Framework/Interfaces/IInterregionComms.cs deleted file mode 100644 index 2d6287f87d..0000000000 --- a/OpenSim/Region/Framework/Interfaces/IInterregionComms.cs +++ /dev/null @@ -1,111 +0,0 @@ -/* - * Copyright (c) Contributors, http://opensimulator.org/ - * See CONTRIBUTORS.TXT for a full list of copyright holders. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the OpenSimulator Project nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -using OpenMetaverse; -using OpenSim.Framework; -using OpenSim.Region.Framework.Scenes; - -namespace OpenSim.Region.Framework.Interfaces -{ - public delegate bool ChildAgentUpdateReceived(AgentData data); - - public interface IInterregionCommsOut - { - #region Agents - - bool SendCreateChildAgent(ulong regionHandle, AgentCircuitData aCircuit, uint teleportFlags, out string reason); - - /// - /// Full child agent update. - /// - /// - /// - /// - bool SendChildAgentUpdate(ulong regionHandle, AgentData data); - - /// - /// Short child agent update, mostly for position. - /// - /// - /// - /// - bool SendChildAgentUpdate(ulong regionHandle, AgentPosition data); - - bool SendRetrieveRootAgent(ulong regionHandle, UUID id, out IAgentData agent); - - /// - /// Message from receiving region to departing region, telling it got contacted by the client. - /// When sent over REST, it invokes the opaque uri. - /// - /// - /// - /// - /// - bool SendReleaseAgent(ulong regionHandle, UUID id, string uri); - - /// - /// Close agent. - /// - /// - /// - /// - bool SendCloseAgent(ulong regionHandle, UUID id); - - #endregion Agents - - #region Objects - - /// - /// Create an object in the destination region. This message is used primarily for prim crossing. - /// - /// - /// - /// - /// - bool SendCreateObject(ulong regionHandle, SceneObjectGroup sog, bool isLocalCall); - - /// - /// Create an object from the user's inventory in the destination region. - /// This message is used primarily by clients. - /// - /// - /// - /// - /// - bool SendCreateObject(ulong regionHandle, UUID userID, UUID itemID); - - #endregion Objects - - } - - // This may not be needed, but having it here for now. - public interface IInterregionCommsIn - { - event ChildAgentUpdateReceived OnChildAgentUpdate; - } - -} diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs index d8a4ed175b..aee621f533 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.cs @@ -4389,18 +4389,6 @@ namespace OpenSim.Region.Framework.Scenes return sp; } - public virtual bool IncomingRetrieveRootAgent(UUID id, out IAgentData agent) - { - agent = null; - ScenePresence sp = GetScenePresence(id); - if ((sp != null) && (!sp.IsChildAgent)) - { - sp.IsChildAgent = true; - return sp.CopyAgent(out agent); - } - - return false; - } /// /// Authenticated close (via network) /// diff --git a/OpenSim/Region/Framework/Scenes/ScenePresence.cs b/OpenSim/Region/Framework/Scenes/ScenePresence.cs index d2c7c76e1c..b4274ba256 100644 --- a/OpenSim/Region/Framework/Scenes/ScenePresence.cs +++ b/OpenSim/Region/Framework/Scenes/ScenePresence.cs @@ -110,6 +110,16 @@ namespace OpenSim.Region.Framework.Scenes } } + /// + /// This exists to prevent race conditions between two CompleteMovement threads if the simulator is slow and + /// the viewer fires these in quick succession. + /// + /// + /// TODO: The child -> agent transition should be folded into LifecycleState and the CompleteMovement + /// regulation done there. + /// + private object m_completeMovementLock = new object(); + // private static readonly byte[] DEFAULT_TEXTURE = AvatarAppearance.GetDefaultTexture().GetBytes(); private static readonly Array DIR_CONTROL_FLAGS = Enum.GetValues(typeof(Dir_ControlFlags)); private static readonly Vector3 HEAD_ADJUSTMENT = new Vector3(0f, 0f, 0.3f); @@ -980,6 +990,7 @@ namespace OpenSim.Region.Framework.Scenes /// /// Turns a child agent into a root agent. /// + /// /// Child agents are logged into neighbouring sims largely to observe changes. Root agents exist when the /// avatar is actual in the sim. They can perform all actions. /// This change is made whenever an avatar enters a region, whether by crossing over from a neighbouring sim, @@ -987,48 +998,51 @@ namespace OpenSim.Region.Framework.Scenes /// /// This method is on the critical path for transferring an avatar from one region to another. Delay here /// delays that crossing. - /// - private void MakeRootAgent(Vector3 pos, bool isFlying) + /// + private bool MakeRootAgent(Vector3 pos, bool isFlying) { -// m_log.InfoFormat( -// "[SCENE]: Upgrading child to root agent for {0} in {1}", -// Name, m_scene.RegionInfo.RegionName); - - if (ParentUUID != UUID.Zero) + lock (m_completeMovementLock) { - m_log.DebugFormat("[SCENE PRESENCE]: Sitting avatar back on prim {0}", ParentUUID); - SceneObjectPart part = m_scene.GetSceneObjectPart(ParentUUID); - if (part == null) + if (!IsChildAgent) + return false; + + //m_log.DebugFormat("[SCENE]: known regions in {0}: {1}", Scene.RegionInfo.RegionName, KnownChildRegionHandles.Count); + + // m_log.InfoFormat( + // "[SCENE]: Upgrading child to root agent for {0} in {1}", + // Name, m_scene.RegionInfo.RegionName); + + if (ParentUUID != UUID.Zero) { - m_log.ErrorFormat("[SCENE PRESENCE]: Can't find prim {0} to sit on", ParentUUID); + m_log.DebugFormat("[SCENE PRESENCE]: Sitting avatar back on prim {0}", ParentUUID); + SceneObjectPart part = m_scene.GetSceneObjectPart(ParentUUID); + if (part == null) + { + m_log.ErrorFormat("[SCENE PRESENCE]: Can't find prim {0} to sit on", ParentUUID); + } + else + { + part.ParentGroup.AddAvatar(UUID); + if (part.SitTargetPosition != Vector3.Zero) + part.SitTargetAvatar = UUID; + // ParentPosition = part.GetWorldPosition(); + ParentID = part.LocalId; + ParentPart = part; + m_pos = PrevSitOffset; + // pos = ParentPosition; + pos = part.GetWorldPosition(); + } + ParentUUID = UUID.Zero; + + // Animator.TrySetMovementAnimation("SIT"); } else { - part.ParentGroup.AddAvatar(UUID); - if (part.SitTargetPosition != Vector3.Zero) - part.SitTargetAvatar = UUID; -// ParentPosition = part.GetWorldPosition(); - ParentID = part.LocalId; - ParentPart = part; - m_pos = PrevSitOffset; -// pos = ParentPosition; - pos = part.GetWorldPosition(); + IsLoggingIn = false; } - ParentUUID = UUID.Zero; IsChildAgent = false; - -// Animator.TrySetMovementAnimation("SIT"); } - else - { - IsChildAgent = false; - IsLoggingIn = false; - } - - //m_log.DebugFormat("[SCENE]: known regions in {0}: {1}", Scene.RegionInfo.RegionName, KnownChildRegionHandles.Count); - - IsChildAgent = false; // Must reset this here so that a teleport to a region next to an existing region does not keep the flag // set and prevent the close of the connection on a subsequent re-teleport. @@ -1216,6 +1230,7 @@ namespace OpenSim.Region.Framework.Scenes m_scene.EventManager.TriggerOnMakeRootAgent(this); + return true; } public int GetStateSource() @@ -1639,7 +1654,14 @@ namespace OpenSim.Region.Framework.Scenes } bool flying = ((m_AgentControlFlags & AgentManager.ControlFlags.AGENT_CONTROL_FLY) != 0); - MakeRootAgent(AbsolutePosition, flying); + if (!MakeRootAgent(AbsolutePosition, flying)) + { + m_log.DebugFormat( + "[SCENE PRESENCE]: Aborting CompleteMovement call for {0} in {1} as they are already root", + Name, Scene.Name); + + return; + } // Tell the client that we're totally ready ControllingClient.MoveAgentIntoRegion(m_scene.RegionInfo, AbsolutePosition, look); diff --git a/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceAgentTests.cs b/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceAgentTests.cs index d1aeaeef16..1ff1329d71 100644 --- a/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceAgentTests.cs +++ b/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceAgentTests.cs @@ -111,6 +111,45 @@ namespace OpenSim.Region.Framework.Scenes.Tests Assert.That(scene.GetScenePresences().Count, Is.EqualTo(1)); } + /// + /// Test that duplicate complete movement calls are ignored. + /// + /// + /// If duplicate calls are not ignored then there is a risk of race conditions or other unexpected effects. + /// + [Test] + public void TestDupeCompleteMovementCalls() + { + TestHelpers.InMethod(); +// TestHelpers.EnableLogging(); + + UUID spUuid = TestHelpers.ParseTail(0x1); + + TestScene scene = new SceneHelpers().SetupScene(); + + int makeRootAgentEvents = 0; + scene.EventManager.OnMakeRootAgent += spi => makeRootAgentEvents++; + + ScenePresence sp = SceneHelpers.AddScenePresence(scene, spUuid); + + Assert.That(makeRootAgentEvents, Is.EqualTo(1)); + + // Normally these would be invoked by a CompleteMovement message coming in to the UDP stack. But for + // convenience, here we will invoke it manually. + sp.CompleteMovement(sp.ControllingClient, true); + + Assert.That(makeRootAgentEvents, Is.EqualTo(1)); + + // Check rest of exepcted parameters. + Assert.That(scene.AuthenticateHandler.GetAgentCircuitData(spUuid), Is.Not.Null); + Assert.That(scene.AuthenticateHandler.GetAgentCircuits().Count, Is.EqualTo(1)); + + Assert.That(sp.IsChildAgent, Is.False); + Assert.That(sp.UUID, Is.EqualTo(spUuid)); + + Assert.That(scene.GetScenePresences().Count, Is.EqualTo(1)); + } + [Test] public void TestCreateDuplicateRootScenePresence() { @@ -249,58 +288,5 @@ namespace OpenSim.Region.Framework.Scenes.Tests // Assert.That(childPresence, Is.Not.Null); // Assert.That(childPresence.IsChildAgent, Is.True); } - -// /// -// /// Test adding a root agent to a scene. Doesn't yet actually complete crossing the agent into the scene. -// /// -// [Test] -// public void T010_TestAddRootAgent() -// { -// TestHelpers.InMethod(); -// -// string firstName = "testfirstname"; -// -// AgentCircuitData agent = new AgentCircuitData(); -// agent.AgentID = agent1; -// agent.firstname = firstName; -// agent.lastname = "testlastname"; -// agent.SessionID = UUID.Random(); -// agent.SecureSessionID = UUID.Random(); -// agent.circuitcode = 123; -// agent.BaseFolder = UUID.Zero; -// agent.InventoryFolder = UUID.Zero; -// agent.startpos = Vector3.Zero; -// agent.CapsPath = GetRandomCapsObjectPath(); -// agent.ChildrenCapSeeds = new Dictionary(); -// agent.child = true; -// -// scene.PresenceService.LoginAgent(agent.AgentID.ToString(), agent.SessionID, agent.SecureSessionID); -// -// string reason; -// scene.NewUserConnection(agent, (uint)TeleportFlags.ViaLogin, out reason); -// testclient = new TestClient(agent, scene); -// scene.AddNewAgent(testclient); -// -// ScenePresence presence = scene.GetScenePresence(agent1); -// -// Assert.That(presence, Is.Not.Null, "presence is null"); -// Assert.That(presence.Firstname, Is.EqualTo(firstName), "First name not same"); -// acd1 = agent; -// } -// -// /// -// /// Test removing an uncrossed root agent from a scene. -// /// -// [Test] -// public void T011_TestRemoveRootAgent() -// { -// TestHelpers.InMethod(); -// -// scene.RemoveClient(agent1); -// -// ScenePresence presence = scene.GetScenePresence(agent1); -// -// Assert.That(presence, Is.Null, "presence is not null"); -// } } } \ No newline at end of file diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LS_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LS_Api.cs index 1d6cb6d4dc..b13a5ae57e 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LS_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LS_Api.cs @@ -434,6 +434,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api } return wl; } + /// /// Set the current Windlight scene /// @@ -446,13 +447,21 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api LSShoutError("LightShare functions are not enabled."); return 0; } - if (!World.RegionInfo.EstateSettings.IsEstateManagerOrOwner(m_host.OwnerID) && World.GetScenePresence(m_host.OwnerID).GodLevel < 200) + + if (!World.RegionInfo.EstateSettings.IsEstateManagerOrOwner(m_host.OwnerID)) { - LSShoutError("lsSetWindlightScene can only be used by estate managers or owners."); - return 0; + ScenePresence sp = World.GetScenePresence(m_host.OwnerID); + + if (sp == null || sp.GodLevel < 200) + { + LSShoutError("lsSetWindlightScene can only be used by estate managers or owners."); + return 0; + } } + int success = 0; m_host.AddScriptLPS(1); + if (LightShareModule.EnableWindlight) { RegionLightShareData wl = getWindlightProfileFromRules(rules); @@ -465,8 +474,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api LSShoutError("Windlight module is disabled"); return 0; } + return success; } + public void lsClearWindlightScene() { if (!m_LSFunctionsEnabled) @@ -474,17 +485,25 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api LSShoutError("LightShare functions are not enabled."); return; } - if (!World.RegionInfo.EstateSettings.IsEstateManagerOrOwner(m_host.OwnerID) && World.GetScenePresence(m_host.OwnerID).GodLevel < 200) + + if (!World.RegionInfo.EstateSettings.IsEstateManagerOrOwner(m_host.OwnerID)) { - LSShoutError("lsSetWindlightScene can only be used by estate managers or owners."); - return; + ScenePresence sp = World.GetScenePresence(m_host.OwnerID); + + if (sp == null || sp.GodLevel < 200) + { + LSShoutError("lsSetWindlightScene can only be used by estate managers or owners."); + return; + } } m_host.ParentGroup.Scene.RegionInfo.WindlightSettings.valid = false; if (m_host.ParentGroup.Scene.SimulationDataService != null) m_host.ParentGroup.Scene.SimulationDataService.RemoveRegionWindlightSettings(m_host.ParentGroup.Scene.RegionInfo.RegionID); + m_host.ParentGroup.Scene.EventManager.TriggerOnSaveNewWindlightProfile(); } + /// /// Set the current Windlight scene to a target avatar /// @@ -497,13 +516,21 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api LSShoutError("LightShare functions are not enabled."); return 0; } - if (!World.RegionInfo.EstateSettings.IsEstateManagerOrOwner(m_host.OwnerID) && World.GetScenePresence(m_host.OwnerID).GodLevel < 200) + + if (!World.RegionInfo.EstateSettings.IsEstateManagerOrOwner(m_host.OwnerID)) { - LSShoutError("lsSetWindlightSceneTargeted can only be used by estate managers or owners."); - return 0; + ScenePresence sp = World.GetScenePresence(m_host.OwnerID); + + if (sp == null || sp.GodLevel < 200) + { + LSShoutError("lsSetWindlightSceneTargeted can only be used by estate managers or owners."); + return 0; + } } + int success = 0; m_host.AddScriptLPS(1); + if (LightShareModule.EnableWindlight) { RegionLightShareData wl = getWindlightProfileFromRules(rules); @@ -515,8 +542,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api LSShoutError("Windlight module is disabled"); return 0; } + return success; - } - + } } -} +} \ No newline at end of file diff --git a/OpenSim/Services/Interfaces/IOfflineIMService.cs b/OpenSim/Services/Interfaces/IOfflineIMService.cs index 28489670fc..588aaafb6b 100644 --- a/OpenSim/Services/Interfaces/IOfflineIMService.cs +++ b/OpenSim/Services/Interfaces/IOfflineIMService.cs @@ -35,7 +35,14 @@ namespace OpenSim.Services.Interfaces public interface IOfflineIMService { List GetMessages(UUID principalID); + bool StoreMessage(GridInstantMessage im, out string reason); + + /// + /// Delete messages to or from this user (or group). + /// + /// A user or group ID + void DeleteMessages(UUID userID); } public class OfflineIMDataUtils