From 5e4d6cab00cb29cd088ab7b62ab13aff103b64cb Mon Sep 17 00:00:00 2001 From: onefang Date: Sun, 19 May 2019 21:24:15 +1000 Subject: Dump OpenSim 0.9.0.1 into it's own branch. --- .../Framework/Caps/CapabilitiesModule.cs | 150 +- .../Framework/DynamicAttributes/DAExampleModule.cs | 30 +- .../Framework/DynamicAttributes/DOExampleModule.cs | 24 +- .../EntityTransfer/EntityTransferModule.cs | 1709 ++++++++++---------- .../EntityTransfer/EntityTransferStateMachine.cs | 44 +- .../EntityTransfer/HGEntityTransferModule.cs | 84 +- .../Framework/InterfaceCommander/Commander.cs | 20 +- .../Framework/InventoryAccess/HGAssetMapper.cs | 8 +- .../InventoryAccess/HGInventoryAccessModule.cs | 86 +- .../InventoryAccess/InventoryAccessModule.cs | 557 ++++--- .../InventoryAccess/Tests/HGAssetMapperTests.cs | 9 +- .../Tests/InventoryAccessModuleTests.cs | 64 +- .../CoreModules/Framework/Library/LibraryModule.cs | 6 +- .../Framework/Library/LocalInventoryService.cs | 15 +- .../Framework/Monitoring/MonitorModule.cs | 12 +- .../Framework/Search/BasicSearchModule.cs | 2 +- .../ServiceThrottle/ServiceThrottleModule.cs | 148 +- .../Statistics/Logging/BinaryLoggingModule.cs | 24 +- .../UserManagement/HGUserManagementModule.cs | 14 +- .../Tests/HGUserManagementModuleTests.cs | 2 +- .../UserManagement/UserManagementModule.cs | 345 +++- 21 files changed, 1879 insertions(+), 1474 deletions(-) (limited to 'OpenSim/Region/CoreModules/Framework') diff --git a/OpenSim/Region/CoreModules/Framework/Caps/CapabilitiesModule.cs b/OpenSim/Region/CoreModules/Framework/Caps/CapabilitiesModule.cs index 817ef85..c0afe7c 100644 --- a/OpenSim/Region/CoreModules/Framework/Caps/CapabilitiesModule.cs +++ b/OpenSim/Region/CoreModules/Framework/Caps/CapabilitiesModule.cs @@ -47,23 +47,23 @@ namespace OpenSim.Region.CoreModules.Framework { [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "CapabilitiesModule")] public class CapabilitiesModule : INonSharedRegionModule, ICapabilitiesModule - { + { private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); private string m_showCapsCommandFormat = " {0,-38} {1,-60}\n"; - + protected Scene m_scene; - + /// /// Each agent has its own capabilities handler. /// - protected Dictionary m_capsObjects = new Dictionary(); - + protected Dictionary m_capsObjects = new Dictionary(); + protected Dictionary m_capsPaths = new Dictionary(); - protected Dictionary> m_childrenSeeds + protected Dictionary> m_childrenSeeds = new Dictionary>(); - + public void Initialise(IConfigSource source) { } @@ -101,16 +101,16 @@ namespace OpenSim.Region.CoreModules.Framework { m_scene.UnregisterModuleInterface(this); } - - public void PostInitialise() + + public void PostInitialise() { } public void Close() {} - public string Name - { - get { return "Capabilities Module"; } + public string Name + { + get { return "Capabilities Module"; } } public Type ReplaceableInterface @@ -118,23 +118,46 @@ namespace OpenSim.Region.CoreModules.Framework get { return null; } } - public void CreateCaps(UUID agentId) + public void CreateCaps(UUID agentId, uint circuitCode) { - if (m_scene.RegionInfo.EstateSettings.IsBanned(agentId)) - return; + int ts = Util.EnvironmentTickCount(); +/* this as no business here... + * must be done elsewhere ( and is ) + int flags = m_scene.GetUserFlags(agentId); + + m_log.ErrorFormat("[CreateCaps]: banCheck {0} ", Util.EnvironmentTickCountSubtract(ts)); + if (m_scene.RegionInfo.EstateSettings.IsBanned(agentId, flags)) + return; +*/ Caps caps; String capsObjectPath = GetCapsPath(agentId); lock (m_capsObjects) { - if (m_capsObjects.ContainsKey(agentId)) + if (m_capsObjects.ContainsKey(circuitCode)) { - Caps oldCaps = m_capsObjects[agentId]; - - //m_log.WarnFormat( - // "[CAPS]: Recreating caps for agent {0} in region {1}. Old caps path {2}, new caps path {3}. ", - // agentId, m_scene.RegionInfo.RegionName, oldCaps.CapsObjectPath, capsObjectPath); + Caps oldCaps = m_capsObjects[circuitCode]; + + + if (capsObjectPath == oldCaps.CapsObjectPath) + { +// m_log.WarnFormat( +// "[CAPS]: Reusing caps for agent {0} in region {1}. Old caps path {2}, new caps path {3}. ", +// agentId, m_scene.RegionInfo.RegionName, oldCaps.CapsObjectPath, capsObjectPath); + return; + } + else + { + // not reusing add extra melanie cleanup + // Remove tge handlers. They may conflict with the + // new object created below + oldCaps.DeregisterHandlers(); + + // Better safe ... should not be needed but also + // no big deal + m_capsObjects.Remove(circuitCode); + } } // m_log.DebugFormat( @@ -145,13 +168,17 @@ namespace OpenSim.Region.CoreModules.Framework (MainServer.Instance == null) ? 0: MainServer.Instance.Port, capsObjectPath, agentId, m_scene.RegionInfo.RegionName); - m_capsObjects[agentId] = caps; - } + m_log.DebugFormat("[CreateCaps]: new caps agent {0}, circuit {1}, path {2}, time {3} ",agentId, + circuitCode,caps.CapsObjectPath, Util.EnvironmentTickCountSubtract(ts)); + m_capsObjects[circuitCode] = caps; + } m_scene.EventManager.TriggerOnRegisterCaps(agentId, caps); +// m_log.ErrorFormat("[CreateCaps]: end {0} ", Util.EnvironmentTickCountSubtract(ts)); + } - public void RemoveCaps(UUID agentId) + public void RemoveCaps(UUID agentId, uint circuitCode) { m_log.DebugFormat("[CAPS]: Remove caps for agent {0} in region {1}", agentId, m_scene.RegionInfo.RegionName); lock (m_childrenSeeds) @@ -164,44 +191,65 @@ namespace OpenSim.Region.CoreModules.Framework lock (m_capsObjects) { - if (m_capsObjects.ContainsKey(agentId)) + if (m_capsObjects.ContainsKey(circuitCode)) { - m_capsObjects[agentId].DeregisterHandlers(); - m_scene.EventManager.TriggerOnDeregisterCaps(agentId, m_capsObjects[agentId]); - m_capsObjects.Remove(agentId); + m_capsObjects[circuitCode].DeregisterHandlers(); + m_scene.EventManager.TriggerOnDeregisterCaps(agentId, m_capsObjects[circuitCode]); + m_capsObjects.Remove(circuitCode); } else { + foreach (KeyValuePair kvp in m_capsObjects) + { + if (kvp.Value.AgentID == agentId) + { + kvp.Value.DeregisterHandlers(); + m_scene.EventManager.TriggerOnDeregisterCaps(agentId, kvp.Value); + m_capsObjects.Remove(kvp.Key); + return; + } + } m_log.WarnFormat( "[CAPS]: Received request to remove CAPS handler for root agent {0} in {1}, but no such CAPS handler found!", agentId, m_scene.RegionInfo.RegionName); } } } - - public Caps GetCapsForUser(UUID agentId) + + public Caps GetCapsForUser(uint circuitCode) { lock (m_capsObjects) { - if (m_capsObjects.ContainsKey(agentId)) + if (m_capsObjects.ContainsKey(circuitCode)) { - return m_capsObjects[agentId]; + return m_capsObjects[circuitCode]; } } - + return null; } - + + public void ActivateCaps(uint circuitCode) + { + lock (m_capsObjects) + { + if (m_capsObjects.ContainsKey(circuitCode)) + { + m_capsObjects[circuitCode].Activate(); + } + } + } + public void SetAgentCapsSeeds(AgentCircuitData agent) { lock (m_capsPaths) m_capsPaths[agent.AgentID] = agent.CapsPath; lock (m_childrenSeeds) - m_childrenSeeds[agent.AgentID] + m_childrenSeeds[agent.AgentID] = ((agent.ChildrenCapSeeds == null) ? new Dictionary() : agent.ChildrenCapSeeds); } - + public string GetCapsPath(UUID agentId) { lock (m_capsPaths) @@ -214,7 +262,7 @@ namespace OpenSim.Region.CoreModules.Framework return null; } - + public Dictionary GetChildrenSeeds(UUID agentID) { Dictionary seeds = null; @@ -289,9 +337,9 @@ namespace OpenSim.Region.CoreModules.Framework lock (m_capsObjects) { - foreach (KeyValuePair kvp in m_capsObjects) + foreach (KeyValuePair kvp in m_capsObjects) { - capsReport.AppendFormat("** User {0}:\n", kvp.Key); + capsReport.AppendFormat("** Circuit {0}:\n", kvp.Key); Caps caps = kvp.Value; for (IDictionaryEnumerator kvp2 = caps.CapsHandlers.GetCapsDetails(false, null).GetEnumerator(); kvp2.MoveNext(); ) @@ -339,6 +387,7 @@ namespace OpenSim.Region.CoreModules.Framework private void BuildDetailedStatsByCapReport(StringBuilder sb, string capName) { + /* sb.AppendFormat("Capability name {0}\n", capName); ConsoleDisplayTable cdt = new ConsoleDisplayTable(); @@ -365,8 +414,8 @@ namespace OpenSim.Region.CoreModules.Framework { receivedStats[sp.Name] = reqHandler.RequestsReceived; handledStats[sp.Name] = reqHandler.RequestsHandled; - } - else + } + else { PollServiceEventArgs pollHandler = null; if (caps.TryGetPollHandler(capName, out pollHandler)) @@ -384,10 +433,12 @@ namespace OpenSim.Region.CoreModules.Framework } sb.Append(cdt.ToString()); + */ } private void BuildSummaryStatsByCapReport(StringBuilder sb) { + /* ConsoleDisplayTable cdt = new ConsoleDisplayTable(); cdt.AddColumn("Name", 34); cdt.AddColumn("Req Received", 12); @@ -403,7 +454,7 @@ namespace OpenSim.Region.CoreModules.Framework Caps caps = m_scene.CapsModule.GetCapsForUser(sp.UUID); if (caps == null) - return; + return; foreach (IRequestHandler reqHandler in caps.CapsHandlers.GetCapsHandlers().Values) { @@ -439,15 +490,17 @@ namespace OpenSim.Region.CoreModules.Framework } } ); - + foreach (KeyValuePair kvp in receivedStats.OrderByDescending(kp => kp.Value)) cdt.AddRow(kvp.Key, kvp.Value, handledStats[kvp.Key]); sb.Append(cdt.ToString()); + */ } private void HandleShowCapsStatsByUserCommand(string module, string[] cmdParams) { + /* if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_scene) return; @@ -478,10 +531,12 @@ namespace OpenSim.Region.CoreModules.Framework } MainConsole.Instance.Output(sb.ToString()); + */ } private void BuildDetailedStatsByUserReport(StringBuilder sb, ScenePresence sp) { + /* sb.AppendFormat("Avatar name {0}, type {1}\n", sp.Name, sp.IsChildAgent ? "child" : "root"); ConsoleDisplayTable cdt = new ConsoleDisplayTable(); @@ -504,13 +559,15 @@ namespace OpenSim.Region.CoreModules.Framework capRows.Add(new CapTableRow(kvp.Key, kvp.Value.RequestsReceived, kvp.Value.RequestsHandled)); foreach (CapTableRow ctr in capRows.OrderByDescending(ctr => ctr.RequestsReceived)) - cdt.AddRow(ctr.Name, ctr.RequestsReceived, ctr.RequestsHandled); + cdt.AddRow(ctr.Name, ctr.RequestsReceived, ctr.RequestsHandled); sb.Append(cdt.ToString()); + */ } private void BuildSummaryStatsByUserReport(StringBuilder sb) { + /* ConsoleDisplayTable cdt = new ConsoleDisplayTable(); cdt.AddColumn("Name", 32); cdt.AddColumn("Type", 5); @@ -544,12 +601,13 @@ namespace OpenSim.Region.CoreModules.Framework totalRequestsReceived += handler.RequestsReceived; totalRequestsHandled += handler.RequestsHandled; } - + cdt.AddRow(sp.Name, sp.IsChildAgent ? "child" : "root", totalRequestsReceived, totalRequestsHandled); } ); sb.Append(cdt.ToString()); + */ } private class CapTableRow @@ -566,4 +624,4 @@ namespace OpenSim.Region.CoreModules.Framework } } } -} \ No newline at end of file +} diff --git a/OpenSim/Region/CoreModules/Framework/DynamicAttributes/DAExampleModule.cs b/OpenSim/Region/CoreModules/Framework/DynamicAttributes/DAExampleModule.cs index 0c632b1..d652f43 100644 --- a/OpenSim/Region/CoreModules/Framework/DynamicAttributes/DAExampleModule.cs +++ b/OpenSim/Region/CoreModules/Framework/DynamicAttributes/DAExampleModule.cs @@ -53,12 +53,12 @@ namespace OpenSim.Region.CoreModules.Framework.DynamicAttributes.DAExampleModule protected Scene m_scene; protected IDialogModule m_dialogMod; - - public string Name { get { return "DAExample Module"; } } - public Type ReplaceableInterface { get { return null; } } + + public string Name { get { return "DAExample Module"; } } + public Type ReplaceableInterface { get { return null; } } public void Initialise(IConfigSource source) {} - + public void AddRegion(Scene scene) { if (ENABLED) @@ -70,22 +70,22 @@ namespace OpenSim.Region.CoreModules.Framework.DynamicAttributes.DAExampleModule m_log.DebugFormat("[DA EXAMPLE MODULE]: Added region {0}", m_scene.Name); } } - - public void RemoveRegion(Scene scene) + + public void RemoveRegion(Scene scene) { if (ENABLED) { m_scene.EventManager.OnSceneGroupMove -= OnSceneGroupMove; } } - + public void RegionLoaded(Scene scene) {} - - public void Close() + + public void Close() { RemoveRegion(m_scene); } - + protected bool OnSceneGroupMove(UUID groupId, Vector3 delta) { OSDMap attrs = null; @@ -96,28 +96,28 @@ namespace OpenSim.Region.CoreModules.Framework.DynamicAttributes.DAExampleModule if (!sop.DynAttrs.TryGetStore(Namespace, StoreName, out attrs)) attrs = new OSDMap(); - + OSDInteger newValue; // We have to lock on the entire dynamic attributes map to avoid race conditions with serialization code. - lock (sop.DynAttrs) + lock (sop.DynAttrs) { if (!attrs.ContainsKey("moves")) newValue = new OSDInteger(1); else newValue = new OSDInteger(attrs["moves"].AsInteger() + 1); - + attrs["moves"] = newValue; sop.DynAttrs.SetStore(Namespace, StoreName, attrs); } sop.ParentGroup.HasGroupChanged = true; - + string msg = string.Format("{0} {1} moved {2} times", sop.Name, sop.UUID, newValue); m_log.DebugFormat("[DA EXAMPLE MODULE]: {0}", msg); m_dialogMod.SendGeneralAlert(msg); - + return true; } } diff --git a/OpenSim/Region/CoreModules/Framework/DynamicAttributes/DOExampleModule.cs b/OpenSim/Region/CoreModules/Framework/DynamicAttributes/DOExampleModule.cs index 166a994..3364cbc 100644 --- a/OpenSim/Region/CoreModules/Framework/DynamicAttributes/DOExampleModule.cs +++ b/OpenSim/Region/CoreModules/Framework/DynamicAttributes/DOExampleModule.cs @@ -65,11 +65,11 @@ namespace OpenSim.Region.Framework.DynamicAttributes.DOExampleModule private Scene m_scene; private IDialogModule m_dialogMod; - public string Name { get { return "DO"; } } - public Type ReplaceableInterface { get { return null; } } + public string Name { get { return "DO"; } } + public Type ReplaceableInterface { get { return null; } } public void Initialise(IConfigSource source) {} - + public void AddRegion(Scene scene) { if (ENABLED) @@ -80,18 +80,18 @@ namespace OpenSim.Region.Framework.DynamicAttributes.DOExampleModule m_dialogMod = m_scene.RequestModuleInterface(); } } - - public void RemoveRegion(Scene scene) + + public void RemoveRegion(Scene scene) { if (ENABLED) { m_scene.EventManager.OnSceneGroupMove -= OnSceneGroupMove; } } - + public void RegionLoaded(Scene scene) {} - - public void Close() + + public void Close() { RemoveRegion(m_scene); } @@ -116,7 +116,7 @@ namespace OpenSim.Region.Framework.DynamicAttributes.DOExampleModule rootPart.DynObjs.Add(DAExampleModule.Namespace, Name, new MyObject(movesSoFar)); } - + private bool OnSceneGroupMove(UUID groupId, Vector3 delta) { SceneObjectGroup so = m_scene.GetSceneObjectGroup(groupId); @@ -129,11 +129,11 @@ namespace OpenSim.Region.Framework.DynamicAttributes.DOExampleModule if (rawObj != null) { MyObject myObj = (MyObject)rawObj; - + m_dialogMod.SendGeneralAlert(string.Format("{0} {1} moved {2} times", so.Name, so.UUID, ++myObj.Moves)); } - + return true; - } + } } } \ No newline at end of file diff --git a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs index 1b4b5e6..2334e0b 100644 --- a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs +++ b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs @@ -54,9 +54,15 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); private static readonly string LogHeader = "[ENTITY TRANSFER MODULE]"; + public const int DefaultMaxTransferDistance = 4095; public const bool WaitForAgentArrivedAtDestinationDefault = true; /// + /// The maximum distance, in standard region units (256m) that an agent is allowed to transfer. + /// + public int MaxTransferDistance { get; set; } + + /// /// If true then on a teleport, the source region waits for a callback from the destination region. If /// a callback fails to arrive within a set time then the user is pulled back into the source region. /// @@ -66,9 +72,9 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer /// If true then we ask the viewer to disable teleport cancellation and ignore teleport requests. /// /// - /// This is useful in situations where teleport is very likely to always succeed and we want to avoid a + /// This is useful in situations where teleport is very likely to always succeed and we want to avoid a /// situation where avatars can be come 'stuck' due to a failed teleport cancellation. Unfortunately, the - /// nature of the teleport protocol makes it extremely difficult (maybe impossible) to make teleport + /// nature of the teleport protocol makes it extremely difficult (maybe impossible) to make teleport /// cancellation consistently suceed. /// public bool DisableInterRegionTeleportCancellation { get; set; } @@ -130,7 +136,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer { if (m_idCache.TryGetValue(pRegionHandle, out m_banUntil)) { - if (DateTime.Now < m_banUntil) + if (DateTime.UtcNow < m_banUntil) { ret = true; } @@ -141,13 +147,19 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer // Add this agent in this region as a banned person public void Add(ulong pRegionHandle, UUID pAgentID) { + this.Add(pRegionHandle, pAgentID, 45, 15); + } + + public void Add(ulong pRegionHandle, UUID pAgentID, double newTime, double extendTime) + { if (!m_bannedRegions.TryGetValue(pAgentID, out m_idCache)) { m_idCache = new ExpiringCache(); - m_bannedRegions.Add(pAgentID, m_idCache, TimeSpan.FromSeconds(45)); + m_bannedRegions.Add(pAgentID, m_idCache, TimeSpan.FromSeconds(newTime)); } - m_idCache.Add(pRegionHandle, DateTime.Now + TimeSpan.FromSeconds(15), TimeSpan.FromSeconds(15)); + m_idCache.Add(pRegionHandle, DateTime.UtcNow + TimeSpan.FromSeconds(extendTime), extendTime); } + // Remove the agent from the region's banned list public void Remove(ulong pRegionHandle, UUID pAgentID) { @@ -157,10 +169,10 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer } } } + private BannedRegionCache m_bannedRegionCache = new BannedRegionCache(); private IEventQueue m_eqModule; - private IRegionCombinerModule m_regionCombinerModule; #region ISharedRegionModule @@ -209,11 +221,17 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer IConfig transferConfig = source.Configs["EntityTransfer"]; if (transferConfig != null) { - DisableInterRegionTeleportCancellation + DisableInterRegionTeleportCancellation = transferConfig.GetBoolean("DisableInterRegionTeleportCancellation", false); WaitForAgentArrivedAtDestination = transferConfig.GetBoolean("wait_for_callback", WaitForAgentArrivedAtDestinationDefault); + + MaxTransferDistance = transferConfig.GetInt("max_distance", DefaultMaxTransferDistance); + } + else + { + MaxTransferDistance = DefaultMaxTransferDistance; } m_entityTransferStateMachine = new EntityTransferStateMachine(this); @@ -232,7 +250,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer Scene = scene; - m_interRegionTeleportAttempts = + m_interRegionTeleportAttempts = new Stat( "InterRegionTeleportAttempts", "Number of inter-region teleports attempted.", @@ -245,7 +263,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer null, StatVerbosity.Debug); - m_interRegionTeleportAborts = + m_interRegionTeleportAborts = new Stat( "InterRegionTeleportAborts", "Number of inter-region teleports aborted due to client actions.", @@ -257,7 +275,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer null, StatVerbosity.Debug); - m_interRegionTeleportCancels = + m_interRegionTeleportCancels = new Stat( "InterRegionTeleportCancels", "Number of inter-region teleports cancelled by the client.", @@ -269,7 +287,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer null, StatVerbosity.Debug); - m_interRegionTeleportFailures = + m_interRegionTeleportFailures = new Stat( "InterRegionTeleportFailures", "Number of inter-region teleports that failed due to server/client/network issues.", @@ -303,7 +321,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer public virtual void Close() {} - public virtual void RemoveRegion(Scene scene) + public virtual void RemoveRegion(Scene scene) { if (m_Enabled) { @@ -320,7 +338,6 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer return; m_eqModule = Scene.RequestModuleInterface(); - m_regionCombinerModule = Scene.RequestModuleInterface(); } #endregion @@ -332,7 +349,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer if (client.IsLoggingOut && m_entityTransferStateMachine.UpdateInTransit(client.AgentId, AgentTransferState.Aborting)) { m_log.DebugFormat( - "[ENTITY TRANSFER MODULE]: Aborted teleport request from {0} in {1} due to simultaneous logout", + "[ENTITY TRANSFER MODULE]: Aborted teleport request from {0} in {1} due to simultaneous logout", client.Name, Scene.Name); } } @@ -354,7 +371,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer teleportFlags |= (uint)TeleportFlags.Godlike; } - if (!sp.Scene.Permissions.CanTeleport(sp.UUID)) + else if (!sp.Scene.Permissions.CanTeleport(sp.UUID)) return; string destinationRegionName = "(not found)"; @@ -374,17 +391,27 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer try { - // Reset animations; the viewer does that in teleports. - sp.Animator.ResetAnimations(); if (regionHandle == sp.Scene.RegionInfo.RegionHandle) { + if(!sp.AllowMovement) + { + sp.ControllingClient.SendTeleportFailed("You are frozen"); + m_entityTransferStateMachine.ResetFromTransit(sp.UUID); + return; + } + + // Reset animations; the viewer does that in teleports. + sp.Animator.ResetAnimations(); destinationRegionName = sp.Scene.RegionInfo.RegionName; TeleportAgentWithinRegion(sp, position, lookAt, teleportFlags); } else // Another region possibly in another simulator { + // Reset animations; the viewer does that in teleports. + sp.Animator.ResetAnimations(); + GridRegion finalDestination = null; try { @@ -400,12 +427,13 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer } catch (Exception e) { + m_log.ErrorFormat( "[ENTITY TRANSFER MODULE]: Exception on teleport of {0} from {1}@{2} to {3}@{4}: {5}{6}", sp.Name, sp.AbsolutePosition, sp.Scene.RegionInfo.RegionName, position, destinationRegionName, e.Message, e.StackTrace); - - sp.ControllingClient.SendTeleportFailed("Internal error"); + if(sp != null && sp.ControllingClient != null && !sp.IsDeleted) + sp.ControllingClient.SendTeleportFailed("Internal error"); } finally { @@ -438,17 +466,25 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer position = emergencyPos; } + // Check Default Location (Also See ScenePresence.CompleteMovement) + if (position.X == 128f && position.Y == 128f && position.Z == 22.5f) + position = sp.Scene.RegionInfo.DefaultLandingPoint; + // TODO: Get proper AVG Height - float localAVHeight = 1.56f; + float localHalfAVHeight = 0.8f; + if (sp.Appearance != null) + localHalfAVHeight = sp.Appearance.AvatarHeight / 2; + float posZLimit = 22; // TODO: Check other Scene HeightField posZLimit = (float)sp.Scene.Heightmap[(int)position.X, (int)position.Y]; - float newPosZ = posZLimit + localAVHeight; - if (posZLimit >= (position.Z - (localAVHeight / 2)) && !(Single.IsInfinity(newPosZ) || Single.IsNaN(newPosZ))) + posZLimit += localHalfAVHeight + 0.1f; + + if ((position.Z < posZLimit) && !(Single.IsInfinity(posZLimit) || Single.IsNaN(posZLimit))) { - position.Z = newPosZ; + position.Z = posZLimit; } if (sp.Flying) @@ -457,9 +493,17 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer m_entityTransferStateMachine.UpdateInTransit(sp.UUID, AgentTransferState.Transferring); sp.ControllingClient.SendTeleportStart(teleportFlags); + lookAt.Z = 0f; + + if(Math.Abs(lookAt.X) < 0.01f && Math.Abs(lookAt.Y) < 0.01f) + { + lookAt.X = 1.0f; + lookAt.Y = 0; + } sp.ControllingClient.SendLocalTeleport(position, lookAt, teleportFlags); sp.TeleportFlags = (Constants.TeleportFlags)teleportFlags; + sp.RotateToLookAt(lookAt); sp.Velocity = Vector3.Zero; sp.Teleport(position); @@ -494,15 +538,15 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer { string homeURI = Scene.GetAgentHomeURI(sp.ControllingClient.AgentId); - string message; - finalDestination = GetFinalDestination(reg, sp.ControllingClient.AgentId, homeURI, out message); + string reason = String.Empty; + finalDestination = GetFinalDestination(reg, sp.ControllingClient.AgentId, homeURI, out reason); if (finalDestination == null) { m_log.WarnFormat( "{0} Final destination is having problems. Unable to teleport {1} {2}: {3}", - LogHeader, sp.Name, sp.UUID, message); + LogHeader, sp.Name, sp.UUID, reason); - sp.ControllingClient.SendTeleportFailed(message); + sp.ControllingClient.SendTeleportFailed(reason); return; } @@ -515,17 +559,12 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer return; } - // Validate assorted conditions - string reason = string.Empty; if (!ValidateGenericConditions(sp, reg, finalDestination, teleportFlags, out reason)) { sp.ControllingClient.SendTeleportFailed(reason); return; } - if (message != null) - sp.ControllingClient.SendAgentAlertMessage(message, true); - // // This is it // @@ -547,9 +586,9 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer Util.RegionHandleToRegionLoc(regionHandle, out regX, out regY); MapBlockData block = new MapBlockData(); - block.X = (ushort)regX; - block.Y = (ushort)regY; - block.Access = (byte)SimAccess.Down; + block.X = (ushort)(regX); + block.Y = (ushort)(regY); + block.Access = (byte)SimAccess.Down; // == not there List blocks = new List(); blocks.Add(block); @@ -565,12 +604,22 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer uint x = 0, y = 0; Util.RegionHandleToWorldLoc(regionHandle, out x, out y); + GridRegion reg; + + // handle legacy HG. linked regions are mapped into y = 0 and have no size information + // so we can only search by base handle + if( y == 0) + { + reg = gridService.GetRegionByPosition(scope, (int)x, (int)y); + return reg; + } + // Compute the world location we're teleporting to double worldX = (double)x + position.X; double worldY = (double)y + position.Y; // Find the region that contains the position - GridRegion reg = GetRegionContainingWorldLocation(gridService, scope, worldX, worldY); + reg = GetRegionContainingWorldLocation(gridService, scope, worldX, worldY); if (reg != null) { @@ -589,6 +638,28 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer return true; } + /// + /// Determines whether this instance is within the max transfer distance. + /// + /// + /// + /// + /// true if this instance is within max transfer distance; otherwise, false. + /// + private bool IsWithinMaxTeleportDistance(RegionInfo sourceRegion, GridRegion destRegion) + { + if(MaxTransferDistance == 0) + return true; + +// m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Source co-ords are x={0} y={1}", curRegionX, curRegionY); +// +// m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Final dest is x={0} y={1} {2}@{3}", +// destRegionX, destRegionY, finalDestination.RegionID, finalDestination.ServerURI); + + // Insanely, RegionLoc on RegionInfo is the 256m map co-ord whilst GridRegion.RegionLoc is the raw meters position. + return Math.Abs(sourceRegion.RegionLocX - destRegion.RegionCoordX) <= MaxTransferDistance + && Math.Abs(sourceRegion.RegionLocY - destRegion.RegionCoordY) <= MaxTransferDistance; + } /// /// Wraps DoTeleportInternal() and manages the transfer state. @@ -607,7 +678,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer sp.ControllingClient.SendTeleportFailed("Agent is already in transit."); return; } - + try { DoTeleportInternal(sp, reg, finalDestination, position, lookAt, teleportFlags); @@ -650,10 +721,17 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer RegionInfo sourceRegion = sp.Scene.RegionInfo; + if (!IsWithinMaxTeleportDistance(sourceRegion, finalDestination)) + { + sp.ControllingClient.SendTeleportFailed( + string.Format( + "Can't teleport to {0} ({1},{2}) from {3} ({4},{5}), destination is more than {6} regions way", + finalDestination.RegionName, finalDestination.RegionCoordX, finalDestination.RegionCoordY, + sourceRegion.RegionName, sourceRegion.RegionLocX, sourceRegion.RegionLocY, + MaxTransferDistance)); - uint newRegionX, newRegionY, oldRegionX, oldRegionY; - Util.RegionHandleToRegionLoc(reg.RegionHandle, out newRegionX, out newRegionY); - Util.RegionHandleToRegionLoc(sp.Scene.RegionInfo.RegionHandle, out oldRegionX, out oldRegionY); + return; + } ulong destinationHandle = finalDestination.RegionHandle; @@ -663,8 +741,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer IPEndPoint endPoint = finalDestination.ExternalEndPoint; if (endPoint == null || endPoint.Address == null) { - sp.ControllingClient.SendTeleportFailed("Remote Region appears to be down"); - + sp.ControllingClient.SendTeleportFailed("Could not resolve destination Address"); return; } @@ -694,7 +771,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer m_interRegionTeleportAttempts.Value++; m_log.DebugFormat( - "[ENTITY TRANSFER MODULE]: {0} transfer protocol version to {1} is {2} / {3}", + "[ENTITY TRANSFER MODULE]: {0} transfer protocol version to {1} is {2} / {3}", sp.Scene.Name, finalDestination.RegionName, ctx.OutboundVersion, ctx.InboundVersion); // Fixing a bug where teleporting while sitting results in the avatar ending up removed from @@ -704,27 +781,25 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer else if (sp.Flying) teleportFlags |= (uint)TeleportFlags.IsFlying; + sp.IsInLocalTransit = finalDestination.RegionLocY != 0; // HG + sp.IsInTransit = true; + + if (DisableInterRegionTeleportCancellation) teleportFlags |= (uint)TeleportFlags.DisableCancel; // At least on LL 3.3.4, this is not strictly necessary - a teleport will succeed without sending this to // the viewer. However, it might mean that the viewer does not see the black teleport screen (untested). sp.ControllingClient.SendTeleportStart(teleportFlags); - - // the avatar.Close below will clear the child region list. We need this below for (possibly) - // closing the child agents, so save it here (we need a copy as it is Clear()-ed). - //List childRegions = avatar.KnownRegionHandles; - // Compared to ScenePresence.CrossToNewRegion(), there's no obvious code to handle a teleport - // failure at this point (unlike a border crossing failure). So perhaps this can never fail - // once we reach here... - //avatar.Scene.RemoveCapsHandler(avatar.UUID); - + AgentCircuitData currentAgentCircuit = sp.Scene.AuthenticateHandler.GetAgentCircuitData(sp.ControllingClient.CircuitCode); AgentCircuitData agentCircuit = sp.ControllingClient.RequestClientInfo(); agentCircuit.startpos = position; agentCircuit.child = true; + agentCircuit.Appearance = new AvatarAppearance(); - agentCircuit.Appearance.PackLegacyWearables = true; + agentCircuit.Appearance.AvatarHeight = sp.Appearance.AvatarHeight; + if (currentAgentCircuit != null) { agentCircuit.ServiceURLs = currentAgentCircuit.ServiceURLs; @@ -735,36 +810,64 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer agentCircuit.Id0 = currentAgentCircuit.Id0; } - // if (NeedsNewAgent(sp.DrawDistance, oldRegionX, newRegionX, oldRegionY, newRegionY)) - float dist = (float)Math.Max(sp.Scene.DefaultDrawDistance, - (float)Math.Max(sp.Scene.RegionInfo.RegionSizeX, sp.Scene.RegionInfo.RegionSizeY)); - if (NeedsNewAgent(dist, oldRegionX, newRegionX, oldRegionY, newRegionY)) + uint newRegionX, newRegionY, oldRegionX, oldRegionY; + Util.RegionHandleToRegionLoc(destinationHandle, out newRegionX, out newRegionY); + Util.RegionHandleToRegionLoc(sourceRegion.RegionHandle, out oldRegionX, out oldRegionY); + int oldSizeX = (int)sourceRegion.RegionSizeX; + int oldSizeY = (int)sourceRegion.RegionSizeY; + int newSizeX = finalDestination.RegionSizeX; + int newSizeY = finalDestination.RegionSizeY; + + bool OutSideViewRange = NeedsNewAgent(sp.RegionViewDistance, oldRegionX, newRegionX, oldRegionY, newRegionY, + oldSizeX, oldSizeY, newSizeX, newSizeY); + + if (OutSideViewRange) { - // brand new agent, let's create a new caps seed + m_log.DebugFormat( + "[ENTITY TRANSFER MODULE]: Determined that region {0} at {1},{2} size {3},{4} needs new child agent for agent {5} from {6}", + finalDestination.RegionName, newRegionX, newRegionY,newSizeX, newSizeY, sp.Name, Scene.Name); + + //sp.ControllingClient.SendTeleportProgress(teleportFlags, "Creating agent..."); agentCircuit.CapsPath = CapsUtil.GetRandomCapsObjectPath(); } + else + { + agentCircuit.CapsPath = sp.Scene.CapsModule.GetChildSeed(sp.UUID, reg.RegionHandle); + if (agentCircuit.CapsPath == null) + agentCircuit.CapsPath = CapsUtil.GetRandomCapsObjectPath(); + } // We're going to fallback to V1 if the destination gives us anything smaller than 0.2 if (ctx.OutboundVersion >= 0.2f) - TransferAgent_V2(sp, agentCircuit, reg, finalDestination, endPoint, teleportFlags, oldRegionX, newRegionX, oldRegionY, newRegionY, ctx, out reason); + TransferAgent_V2(sp, agentCircuit, reg, finalDestination, endPoint, teleportFlags, OutSideViewRange , ctx, out reason); else - TransferAgent_V1(sp, agentCircuit, reg, finalDestination, endPoint, teleportFlags, oldRegionX, newRegionX, oldRegionY, newRegionY, ctx, out reason); + TransferAgent_V1(sp, agentCircuit, reg, finalDestination, endPoint, teleportFlags, OutSideViewRange, ctx, out reason); } private void TransferAgent_V1(ScenePresence sp, AgentCircuitData agentCircuit, GridRegion reg, GridRegion finalDestination, - IPEndPoint endPoint, uint teleportFlags, uint oldRegionX, uint newRegionX, uint oldRegionY, uint newRegionY, EntityTransferContext ctx, out string reason) + IPEndPoint endPoint, uint teleportFlags, bool OutSideViewRange, EntityTransferContext ctx, out string reason) { ulong destinationHandle = finalDestination.RegionHandle; AgentCircuitData currentAgentCircuit = sp.Scene.AuthenticateHandler.GetAgentCircuitData(sp.ControllingClient.CircuitCode); m_log.DebugFormat( - "[ENTITY TRANSFER MODULE]: Using TP V1 for {0} going from {1} to {2}", + "[ENTITY TRANSFER MODULE]: Using TP V1 for {0} going from {1} to {2}", sp.Name, Scene.Name, finalDestination.RegionName); - // Let's create an agent there if one doesn't exist yet. + string capsPath = finalDestination.ServerURI + CapsUtil.GetCapsSeedPath(agentCircuit.CapsPath); + List childRegionsToClose = sp.GetChildAgentsToClose(destinationHandle, finalDestination.RegionSizeX, finalDestination.RegionSizeY); + if(agentCircuit.ChildrenCapSeeds != null) + { + foreach(ulong handler in childRegionsToClose) + { + agentCircuit.ChildrenCapSeeds.Remove(handler); + } + } + + // Let's create an agent there if one doesn't exist yet. // NOTE: logout will always be false for a non-HG teleport. bool logout = false; - if (!CreateAgent(sp, reg, finalDestination, agentCircuit, teleportFlags, out reason, out logout)) + if (!CreateAgent(sp, reg, finalDestination, agentCircuit, teleportFlags, ctx, out reason, out logout)) { m_interRegionTeleportFailures.Value++; @@ -773,7 +876,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer sp.Name, sp.Scene.RegionInfo.RegionName, finalDestination.RegionName, reason); sp.ControllingClient.SendTeleportFailed(reason); - + sp.IsInTransit = false; return; } @@ -784,7 +887,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer m_log.DebugFormat( "[ENTITY TRANSFER MODULE]: Cancelled teleport of {0} to {1} from {2} after CreateAgent on client request", sp.Name, finalDestination.RegionName, sp.Scene.Name); - + sp.IsInTransit = false; return; } else if (m_entityTransferStateMachine.GetAgentTransferState(sp.UUID) == AgentTransferState.Aborting) @@ -794,7 +897,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer m_log.DebugFormat( "[ENTITY TRANSFER MODULE]: Aborted teleport of {0} to {1} from {2} after CreateAgent due to previous client close.", sp.Name, finalDestination.RegionName, sp.Scene.Name); - + sp.IsInTransit = false; return; } @@ -802,28 +905,9 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer m_entityTransferStateMachine.UpdateInTransit(sp.UUID, AgentTransferState.Transferring); // OK, it got this agent. Let's close some child agents - sp.CloseChildAgents(newRegionX, newRegionY); - IClientIPEndpoint ipepClient; - string capsPath = String.Empty; - float dist = (float)Math.Max(sp.Scene.DefaultDrawDistance, - (float)Math.Max(sp.Scene.RegionInfo.RegionSizeX, sp.Scene.RegionInfo.RegionSizeY)); - if (NeedsNewAgent(dist, oldRegionX, newRegionX, oldRegionY, newRegionY)) + if (OutSideViewRange) { - m_log.DebugFormat( - "[ENTITY TRANSFER MODULE]: Determined that region {0} at {1},{2} needs new child agent for incoming agent {3} from {4}", - finalDestination.RegionName, newRegionX, newRegionY, sp.Name, Scene.Name); - - //sp.ControllingClient.SendTeleportProgress(teleportFlags, "Creating agent..."); - #region IP Translation for NAT - // Uses ipepClient above - if (sp.ClientView.TryGet(out ipepClient)) - { - endPoint.Address = NetworkUtil.GetIPFor(ipepClient.EndPoint, endPoint.Address); - } - #endregion - capsPath = finalDestination.ServerURI + CapsUtil.GetCapsSeedPath(agentCircuit.CapsPath); - if (m_eqModule != null) { // The EnableSimulator message makes the client establish a connection with the destination @@ -853,22 +937,18 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer sp.ControllingClient.InformClientOfNeighbour(destinationHandle, endPoint); } } - else - { - agentCircuit.CapsPath = sp.Scene.CapsModule.GetChildSeed(sp.UUID, reg.RegionHandle); - capsPath = finalDestination.ServerURI + CapsUtil.GetCapsSeedPath(agentCircuit.CapsPath); - } // Let's send a full update of the agent. This is a synchronous call. AgentData agent = new AgentData(); - sp.CopyTo(agent); - if (ctx.OutboundVersion < 0.5f) - agent.Appearance.PackLegacyWearables = true; + sp.CopyTo(agent,false); + + if ((teleportFlags & (uint)TeleportFlags.IsFlying) != 0) + agent.ControlFlags |= (uint)AgentManager.ControlFlags.AGENT_CONTROL_FLY; + agent.Position = agentCircuit.startpos; SetCallbackURL(agent, sp.Scene.RegionInfo); - - // We will check for an abort before UpdateAgent since UpdateAgent will require an active viewer to + // We will check for an abort before UpdateAgent since UpdateAgent will require an active viewer to // establish th econnection to the destination which makes it return true. if (m_entityTransferStateMachine.GetAgentTransferState(sp.UUID) == AgentTransferState.Aborting) { @@ -877,15 +957,15 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer m_log.DebugFormat( "[ENTITY TRANSFER MODULE]: Aborted teleport of {0} to {1} from {2} before UpdateAgent", sp.Name, finalDestination.RegionName, sp.Scene.Name); - + sp.IsInTransit = false; return; } - // A common teleport failure occurs when we can send CreateAgent to the + // A common teleport failure occurs when we can send CreateAgent to the // destination region but the viewer cannot establish the connection (e.g. due to network issues between // the viewer and the destination). In this case, UpdateAgent timesout after 10 seconds, although then // there's a further 10 second wait whilst we attempt to tell the destination to delete the agent in Fail(). - if (!UpdateAgent(reg, finalDestination, agent, sp)) + if (!UpdateAgent(reg, finalDestination, agent, sp, ctx)) { if (m_entityTransferStateMachine.GetAgentTransferState(sp.UUID) == AgentTransferState.Aborting) { @@ -894,7 +974,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer m_log.DebugFormat( "[ENTITY TRANSFER MODULE]: Aborted teleport of {0} to {1} from {2} after UpdateAgent due to previous client close.", sp.Name, finalDestination.RegionName, sp.Scene.Name); - + sp.IsInTransit = false; return; } @@ -903,6 +983,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer sp.Name, finalDestination.RegionName, sp.Scene.Name); Fail(sp, finalDestination, logout, currentAgentCircuit.SessionID.ToString(), "Connection between viewer and destination region could not be established."); + sp.IsInTransit = false; return; } @@ -915,7 +996,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer sp.Name, finalDestination.RegionName, sp.Scene.Name); CleanupFailedInterRegionTeleport(sp, currentAgentCircuit.SessionID.ToString(), finalDestination); - + sp.IsInTransit = false; return; } @@ -924,7 +1005,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer capsPath, sp.Scene.RegionInfo.RegionName, sp.Name); // We need to set this here to avoid an unlikely race condition when teleporting to a neighbour simulator, - // where that neighbour simulator could otherwise request a child agent create on the source which then + // where that neighbour simulator could otherwise request a child agent create on the source which then // closes our existing agent which is still signalled as root. sp.IsChildAgent = true; @@ -952,7 +1033,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer m_log.DebugFormat( "[ENTITY TRANSFER MODULE]: Aborted teleport of {0} to {1} from {2} after WaitForAgentArrivedAtDestination due to previous client close.", sp.Name, finalDestination.RegionName, sp.Scene.Name); - + sp.IsInTransit = false; return; } @@ -961,12 +1042,10 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer sp.Name, finalDestination.RegionName, sp.Scene.RegionInfo.RegionName); Fail(sp, finalDestination, logout, currentAgentCircuit.SessionID.ToString(), "Destination region did not signal teleport completion."); - + sp.IsInTransit = false; return; } - m_entityTransferStateMachine.UpdateInTransit(sp.UUID, AgentTransferState.CleaningUp); - /* // TODO: This may be 0.6. Check if still needed // For backwards compatibility @@ -978,18 +1057,26 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer } */ - // May need to logout or other cleanup + m_entityTransferStateMachine.UpdateInTransit(sp.UUID, AgentTransferState.CleaningUp); + + if(logout) + sp.closeAllChildAgents(); + else + sp.CloseChildAgents(childRegionsToClose); + + // call HG hook AgentHasMovedAway(sp, logout); - // Well, this is it. The agent is over there. - KillEntity(sp.Scene, sp.LocalId); + sp.HasMovedAway(!(OutSideViewRange || logout)); - // Now let's make it officially a child agent - sp.MakeChildAgent(); +// ulong sourceRegionHandle = sp.RegionHandle; + + // Now let's make it officially a child agent + sp.MakeChildAgent(destinationHandle); // Finally, let's close this previously-known-as-root agent, when the jump is outside the view zone - if (NeedsClosing(sp.Scene.DefaultDrawDistance, oldRegionX, newRegionX, oldRegionY, newRegionY, reg)) + if (NeedsClosing(reg, OutSideViewRange)) { if (!sp.Scene.IncomingPreCloseClient(sp)) return; @@ -1001,26 +1088,32 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer // This sleep can be increased if necessary. However, whilst it's active, // an agent cannot teleport back to this region if it has teleported away. Thread.Sleep(2000); - sp.Scene.CloseAgent(sp.UUID, false); } - else - { - // now we have a child agent in this region. - sp.Reset(); - } + sp.IsInTransit = false; } private void TransferAgent_V2(ScenePresence sp, AgentCircuitData agentCircuit, GridRegion reg, GridRegion finalDestination, - IPEndPoint endPoint, uint teleportFlags, uint oldRegionX, uint newRegionX, uint oldRegionY, uint newRegionY, EntityTransferContext ctx, out string reason) + IPEndPoint endPoint, uint teleportFlags, bool OutSideViewRange, EntityTransferContext ctx, out string reason) { ulong destinationHandle = finalDestination.RegionHandle; - AgentCircuitData currentAgentCircuit = sp.Scene.AuthenticateHandler.GetAgentCircuitData(sp.ControllingClient.CircuitCode); - // Let's create an agent there if one doesn't exist yet. + List childRegionsToClose = sp.GetChildAgentsToClose(destinationHandle, finalDestination.RegionSizeX, finalDestination.RegionSizeY); + + if(agentCircuit.ChildrenCapSeeds != null) + { + foreach(ulong handler in childRegionsToClose) + { + agentCircuit.ChildrenCapSeeds.Remove(handler); + } + } + + string capsPath = finalDestination.ServerURI + CapsUtil.GetCapsSeedPath(agentCircuit.CapsPath);; + + // Let's create an agent there if one doesn't exist yet. // NOTE: logout will always be false for a non-HG teleport. bool logout = false; - if (!CreateAgent(sp, reg, finalDestination, agentCircuit, teleportFlags, out reason, out logout)) + if (!CreateAgent(sp, reg, finalDestination, agentCircuit, teleportFlags, ctx, out reason, out logout)) { m_interRegionTeleportFailures.Value++; @@ -1029,7 +1122,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer sp.Name, sp.Scene.RegionInfo.RegionName, finalDestination.RegionName, reason); sp.ControllingClient.SendTeleportFailed(reason); - + sp.IsInTransit = false; return; } @@ -1041,6 +1134,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer "[ENTITY TRANSFER MODULE]: Cancelled teleport of {0} to {1} from {2} after CreateAgent on client request", sp.Name, finalDestination.RegionName, sp.Scene.Name); + sp.IsInTransit = false; return; } else if (m_entityTransferStateMachine.GetAgentTransferState(sp.UUID) == AgentTransferState.Aborting) @@ -1051,40 +1145,15 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer "[ENTITY TRANSFER MODULE]: Aborted teleport of {0} to {1} from {2} after CreateAgent due to previous client close.", sp.Name, finalDestination.RegionName, sp.Scene.Name); + sp.IsInTransit = false; return; } // Past this point we have to attempt clean up if the teleport fails, so update transfer state. m_entityTransferStateMachine.UpdateInTransit(sp.UUID, AgentTransferState.Transferring); - IClientIPEndpoint ipepClient; - string capsPath = String.Empty; - float dist = (float)Math.Max(sp.Scene.DefaultDrawDistance, - (float)Math.Max(sp.Scene.RegionInfo.RegionSizeX, sp.Scene.RegionInfo.RegionSizeY)); - if (NeedsNewAgent(dist, oldRegionX, newRegionX, oldRegionY, newRegionY)) - { - m_log.DebugFormat( - "[ENTITY TRANSFER MODULE]: Determined that region {0} at {1},{2} needs new child agent for agent {3} from {4}", - finalDestination.RegionName, newRegionX, newRegionY, sp.Name, Scene.Name); - - //sp.ControllingClient.SendTeleportProgress(teleportFlags, "Creating agent..."); - #region IP Translation for NAT - // Uses ipepClient above - if (sp.ClientView.TryGet(out ipepClient)) - { - endPoint.Address = NetworkUtil.GetIPFor(ipepClient.EndPoint, endPoint.Address); - } - #endregion - capsPath = finalDestination.ServerURI + CapsUtil.GetCapsSeedPath(agentCircuit.CapsPath); - } - else - { - agentCircuit.CapsPath = sp.Scene.CapsModule.GetChildSeed(sp.UUID, reg.RegionHandle); - capsPath = finalDestination.ServerURI + CapsUtil.GetCapsSeedPath(agentCircuit.CapsPath); - } - // We need to set this here to avoid an unlikely race condition when teleporting to a neighbour simulator, - // where that neighbour simulator could otherwise request a child agent create on the source which then + // where that neighbour simulator could otherwise request a child agent create on the source which then // closes our existing agent which is still signalled as root. //sp.IsChildAgent = true; @@ -1100,13 +1169,16 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer "[ENTITY TRANSFER MODULE]: Sending new CAPS seed url {0} from {1} to {2}", capsPath, sp.Scene.RegionInfo.RegionName, sp.Name); - // Let's send a full update of the agent. + // Let's send a full update of the agent. AgentData agent = new AgentData(); - sp.CopyTo(agent); - if (ctx.OutboundVersion < 0.5f) - agent.Appearance.PackLegacyWearables = true; + sp.CopyTo(agent,false); agent.Position = agentCircuit.startpos; + + if ((teleportFlags & (uint)TeleportFlags.IsFlying) != 0) + agent.ControlFlags |= (uint)AgentManager.ControlFlags.AGENT_CONTROL_FLY; + agent.SenderWantsToWaitForRoot = true; + //SetCallbackURL(agent, sp.Scene.RegionInfo); // Reset the do not close flag. This must be done before the destination opens child connections (here @@ -1118,7 +1190,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer // Send the Update. If this returns true, we know the client has contacted the destination // via CompleteMovementIntoRegion, so we can let go. // If it returns false, something went wrong, and we need to abort. - if (!UpdateAgent(reg, finalDestination, agent, sp)) + if (!UpdateAgent(reg, finalDestination, agent, sp, ctx)) { if (m_entityTransferStateMachine.GetAgentTransferState(sp.UUID) == AgentTransferState.Aborting) { @@ -1127,7 +1199,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer m_log.DebugFormat( "[ENTITY TRANSFER MODULE]: Aborted teleport of {0} to {1} from {2} after UpdateAgent due to previous client close.", sp.Name, finalDestination.RegionName, sp.Scene.Name); - + sp.IsInTransit = false; return; } @@ -1135,31 +1207,31 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer "[ENTITY TRANSFER MODULE]: UpdateAgent failed on teleport of {0} to {1}. Keeping avatar in {2}", sp.Name, finalDestination.RegionName, sp.Scene.Name); - Fail(sp, finalDestination, logout, currentAgentCircuit.SessionID.ToString(), "Connection between viewer and destination region could not be established."); + Fail(sp, finalDestination, logout, agentCircuit.SessionID.ToString(), "Connection between viewer and destination region could not be established."); + sp.IsInTransit = false; return; } - + m_entityTransferStateMachine.UpdateInTransit(sp.UUID, AgentTransferState.CleaningUp); - // Need to signal neighbours whether child agents may need closing irrespective of whether this - // one needed closing. We also need to close child agents as quickly as possible to avoid complicated - // race conditions with rapid agent releporting (e.g. from A1 to a non-neighbour B, back - // to a neighbour A2 then off to a non-neighbour C). Closing child agents any later requires complex - // distributed checks to avoid problems in rapid reteleporting scenarios and where child agents are - // abandoned without proper close by viewer but then re-used by an incoming connection. - sp.CloseChildAgents(newRegionX, newRegionY); + if(logout) + sp.closeAllChildAgents(); + else + sp.CloseChildAgents(childRegionsToClose); + + sp.HasMovedAway(!(OutSideViewRange || logout)); - // May need to logout or other cleanup + //HG hook AgentHasMovedAway(sp, logout); - // Well, this is it. The agent is over there. - KillEntity(sp.Scene, sp.LocalId); +// ulong sourceRegionHandle = sp.RegionHandle; // Now let's make it officially a child agent - sp.MakeChildAgent(); + sp.MakeChildAgent(destinationHandle); // Finally, let's close this previously-known-as-root agent, when the jump is outside the view zone - if (NeedsClosing(sp.Scene.DefaultDrawDistance, oldRegionX, newRegionX, oldRegionY, newRegionY, reg)) + // go by HG hook + if (NeedsClosing(reg, OutSideViewRange)) { if (!sp.Scene.IncomingPreCloseClient(sp)) return; @@ -1170,21 +1242,18 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer // BEFORE THEY SETTLE IN THE NEW REGION. // DECREASING THE WAIT TIME HERE WILL EITHER RESULT IN A VIEWER CRASH OR // IN THE AVIE BEING PLACED IN INFINITY FOR A COUPLE OF SECONDS. + Thread.Sleep(15000); - + // OK, it got this agent. Let's close everything - // If we shouldn't close the agent due to some other region renewing the connection + // If we shouldn't close the agent due to some other region renewing the connection // then this will be handled in IncomingCloseAgent under lock conditions m_log.DebugFormat( "[ENTITY TRANSFER MODULE]: Closing agent {0} in {1} after teleport", sp.Name, Scene.Name); sp.Scene.CloseAgent(sp.UUID, false); } - else - { - // now we have a child agent in this region. - sp.Reset(); - } + sp.IsInTransit = false; } /// @@ -1232,13 +1301,13 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer sp.Scene.EventManager.TriggerTeleportFail(sp.ControllingClient, logout); } - protected virtual bool CreateAgent(ScenePresence sp, GridRegion reg, GridRegion finalDestination, AgentCircuitData agentCircuit, uint teleportFlags, out string reason, out bool logout) + protected virtual bool CreateAgent(ScenePresence sp, GridRegion reg, GridRegion finalDestination, AgentCircuitData agentCircuit, uint teleportFlags, EntityTransferContext ctx, out string reason, out bool logout) { GridRegion source = new GridRegion(Scene.RegionInfo); source.RawServerURI = m_GatekeeperURI; logout = false; - bool success = Scene.SimulationService.CreateAgent(source, finalDestination, agentCircuit, teleportFlags, out reason); + bool success = Scene.SimulationService.CreateAgent(source, finalDestination, agentCircuit, teleportFlags, ctx, out reason); if (success) sp.Scene.EventManager.TriggerTeleportStart(sp.ControllingClient, reg, finalDestination, teleportFlags, logout); @@ -1246,9 +1315,9 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer return success; } - protected virtual bool UpdateAgent(GridRegion reg, GridRegion finalDestination, AgentData agent, ScenePresence sp) + protected virtual bool UpdateAgent(GridRegion reg, GridRegion finalDestination, AgentData agent, ScenePresence sp, EntityTransferContext ctx) { - return Scene.SimulationService.UpdateAgent(finalDestination, agent); + return Scene.SimulationService.UpdateAgent(finalDestination, agent, ctx); } protected virtual void SetCallbackURL(AgentData agent, RegionInfo region) @@ -1265,10 +1334,12 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer /// /// /// + /// + /// now just a HG hook protected virtual void AgentHasMovedAway(ScenePresence sp, bool logout) { - if (sp.Scene.AttachmentsModule != null) - sp.Scene.AttachmentsModule.DeleteAttachmentsFromScene(sp, true); +// if (sp.Scene.AttachmentsModule != null) +// sp.Scene.AttachmentsModule.DeleteAttachmentsFromScene(sp, logout); } protected void KillEntity(Scene scene, uint localID) @@ -1276,6 +1347,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer scene.SendKillObject(new List { localID }); } + // HG hook protected virtual GridRegion GetFinalDestination(GridRegion region, UUID agentID, string agentHomeURI, out string message) { message = null; @@ -1285,28 +1357,18 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer // This returns 'true' if the new region already has a child agent for our // incoming agent. The implication is that, if 'false', we have to create the // child and then teleport into the region. - protected virtual bool NeedsNewAgent(float drawdist, uint oldRegionX, uint newRegionX, uint oldRegionY, uint newRegionY) + protected virtual bool NeedsNewAgent(float viewdist, uint oldRegionX, uint newRegionX, uint oldRegionY, uint newRegionY, + int oldsizeX, int oldsizeY, int newsizeX, int newsizeY) { - if (m_regionCombinerModule != null && m_regionCombinerModule.IsRootForMegaregion(Scene.RegionInfo.RegionID)) - { - Vector2 swCorner, neCorner; - GetMegaregionViewRange(out swCorner, out neCorner); - - m_log.DebugFormat( - "[ENTITY TRANSFER MODULE]: Megaregion view of {0} is from {1} to {2} with new agent check for {3},{4}", - Scene.Name, swCorner, neCorner, newRegionX, newRegionY); - - return !(newRegionX >= swCorner.X && newRegionX <= neCorner.X && newRegionY >= swCorner.Y && newRegionY <= neCorner.Y); - } - else - { - return Util.IsOutsideView(drawdist, oldRegionX, newRegionX, oldRegionY, newRegionY); - } + return Util.IsOutsideView(viewdist, oldRegionX, newRegionX, oldRegionY, newRegionY, + oldsizeX, oldsizeY, newsizeX, newsizeY); } - protected virtual bool NeedsClosing(float drawdist, uint oldRegionX, uint newRegionX, uint oldRegionY, uint newRegionY, GridRegion reg) + // HG Hook + protected virtual bool NeedsClosing(GridRegion reg, bool OutViewRange) + { - return Util.IsOutsideView(drawdist, oldRegionX, newRegionX, oldRegionY, newRegionY); + return OutViewRange; } #endregion @@ -1328,11 +1390,11 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer remoteClient.SendTeleportFailed("The teleport destination could not be found."); return; } - ((Scene)(remoteClient.Scene)).RequestTeleportLocation(remoteClient, info.RegionHandle, lm.Position, + ((Scene)(remoteClient.Scene)).RequestTeleportLocation(remoteClient, info.RegionHandle, lm.Position, Vector3.Zero, (uint)(Constants.TeleportFlags.SetLastToTarget | Constants.TeleportFlags.ViaLandmark)); } - #endregion + #endregion #region Teleport Home @@ -1366,7 +1428,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer client.SendTeleportFailed("Your home region could not be found."); return false; } - + m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Home region of {0} is {1} ({2}-{3})", client.Name, regionInfo.RegionName, regionInfo.RegionCoordX, regionInfo.RegionCoordY); @@ -1389,105 +1451,146 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer #region Agent Crossings - // Given a position relative to the current region (which has previously been tested to - // see that it is actually outside the current region), find the new region that the - // point is actually in. - // Returns the coordinates and information of the new region or 'null' of it doesn't exist. + public bool checkAgentAccessToRegion(ScenePresence agent, GridRegion destiny, Vector3 position, + EntityTransferContext ctx, out string reason) + { + reason = String.Empty; + + UUID agentID = agent.UUID; + ulong destinyHandle = destiny.RegionHandle; + + if (m_bannedRegionCache.IfBanned(destinyHandle, agentID)) + { + return false; + } + + Scene ascene = agent.Scene; + string homeURI = ascene.GetAgentHomeURI(agentID); + + + if (!ascene.SimulationService.QueryAccess(destiny, agentID, homeURI, false, position, + agent.Scene.GetFormatsOffered(), ctx, out reason)) + { + m_bannedRegionCache.Add(destinyHandle, agentID, 30.0, 30.0); + return false; + } + return true; + } + + + // Given a position relative to the current region and outside of it + // find the new region that the point is actually in. + // returns 'null' if new region not found or if information + // and new position relative to it + // now only works for crossings + public GridRegion GetDestination(Scene scene, UUID agentID, Vector3 pos, EntityTransferContext ctx, out Vector3 newpos, out string failureReason) { newpos = pos; failureReason = string.Empty; - string homeURI = scene.GetAgentHomeURI(agentID); // m_log.DebugFormat( // "[ENTITY TRANSFER MODULE]: Crossing agent {0} at pos {1} in {2}", agent.Name, pos, scene.Name); - // Compute world location of the object's position + // Compute world location of the agent's position double presenceWorldX = (double)scene.RegionInfo.WorldLocX + pos.X; double presenceWorldY = (double)scene.RegionInfo.WorldLocY + pos.Y; // Call the grid service to lookup the region containing the new position. - GridRegion neighbourRegion = GetRegionContainingWorldLocation(scene.GridService, scene.RegionInfo.ScopeID, - presenceWorldX, presenceWorldY, - Math.Max(scene.RegionInfo.RegionSizeX, scene.RegionInfo.RegionSizeY)); + GridRegion neighbourRegion = GetRegionContainingWorldLocation( + scene.GridService, scene.RegionInfo.ScopeID, + presenceWorldX, presenceWorldY, + Math.Max(scene.RegionInfo.RegionSizeX, scene.RegionInfo.RegionSizeY)); + + if (neighbourRegion == null) + return null; - if (neighbourRegion != null) + if (m_bannedRegionCache.IfBanned(neighbourRegion.RegionHandle, agentID)) { - // Compute the entity's position relative to the new region - newpos = new Vector3((float)(presenceWorldX - (double)neighbourRegion.RegionLocX), + failureReason = "Access Denied or Temporary not possible"; + return null; + } + + m_bannedRegionCache.Remove(neighbourRegion.RegionHandle, agentID); + + // Compute the entity's position relative to the new region + newpos = new Vector3((float)(presenceWorldX - (double)neighbourRegion.RegionLocX), (float)(presenceWorldY - (double)neighbourRegion.RegionLocY), pos.Z); - if (m_bannedRegionCache.IfBanned(neighbourRegion.RegionHandle, agentID)) - { - failureReason = "Cannot region cross into banned parcel"; - neighbourRegion = null; - } - else - { - // If not banned, make sure this agent is not in the list. - m_bannedRegionCache.Remove(neighbourRegion.RegionHandle, agentID); - } - - // Check to see if we have access to the target region. - if (neighbourRegion != null - && !scene.SimulationService.QueryAccess(neighbourRegion, agentID, homeURI, false, newpos, scene.GetFormatsOffered(), ctx, out failureReason)) - { - // remember banned - m_bannedRegionCache.Add(neighbourRegion.RegionHandle, agentID); - neighbourRegion = null; - } + string homeURI = scene.GetAgentHomeURI(agentID); + + if (!scene.SimulationService.QueryAccess( + neighbourRegion, agentID, homeURI, false, newpos, + scene.GetFormatsOffered(), ctx, out failureReason)) + { + // remember the fail + m_bannedRegionCache.Add(neighbourRegion.RegionHandle, agentID); + if(String.IsNullOrWhiteSpace(failureReason)) + failureReason = "Access Denied"; + return null; } - else + + return neighbourRegion; + } + + public bool Cross(ScenePresence agent, bool isFlying) + { + agent.IsInLocalTransit = true; + agent.IsInTransit = true; + CrossAsyncDelegate d = CrossAsync; + d.BeginInvoke(agent, isFlying, CrossCompleted, d); + return true; + } + + private void CrossCompleted(IAsyncResult iar) + { + CrossAsyncDelegate icon = (CrossAsyncDelegate)iar.AsyncState; + ScenePresence agent = icon.EndInvoke(iar); + + if(agent == null || agent.IsDeleted) + return; + + if(!agent.IsChildAgent) { - // The destination region just doesn't exist - failureReason = "Cannot cross into non-existent region"; + // crossing failed + agent.CrossToNewRegionFail(); } - - if (neighbourRegion == null) - m_log.DebugFormat("{0} GetDestination: region not found. Old region name={1} at <{2},{3}> of size <{4},{5}>. Old pos={6}", - LogHeader, scene.RegionInfo.RegionName, - scene.RegionInfo.RegionLocX, scene.RegionInfo.RegionLocY, - scene.RegionInfo.RegionSizeX, scene.RegionInfo.RegionSizeY, - pos); else - m_log.DebugFormat("{0} GetDestination: new region={1} at <{2},{3}> of size <{4},{5}>, newpos=<{6},{7}>", - LogHeader, neighbourRegion.RegionName, - neighbourRegion.RegionLocX, neighbourRegion.RegionLocY, neighbourRegion.RegionSizeX, neighbourRegion.RegionSizeY, - newpos.X, newpos.Y); + m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Crossing agent {0} {1} completed.", agent.Firstname, agent.Lastname); - return neighbourRegion; + agent.IsInTransit = false; } - public bool Cross(ScenePresence agent, bool isFlying) + public ScenePresence CrossAsync(ScenePresence agent, bool isFlying) { Vector3 newpos; EntityTransferContext ctx = new EntityTransferContext(); string failureReason; - GridRegion neighbourRegion = GetDestination(agent.Scene, agent.UUID, agent.AbsolutePosition, + // We need this because of decimal number parsing of the protocols. + Culture.SetCurrentCulture(); + + Vector3 pos = agent.AbsolutePosition + agent.Velocity * 0.2f; + + GridRegion neighbourRegion = GetDestination(agent.Scene, agent.UUID, pos, ctx, out newpos, out failureReason); if (neighbourRegion == null) { - agent.ControllingClient.SendAlertMessage(failureReason); - return false; + if (!agent.IsDeleted && failureReason != String.Empty && agent.ControllingClient != null) + agent.ControllingClient.SendAlertMessage(failureReason); + return agent; } - agent.IsInTransit = true; - - CrossAgentToNewRegionDelegate d = CrossAgentToNewRegionAsync; - d.BeginInvoke(agent, newpos, neighbourRegion, isFlying, ctx, CrossAgentToNewRegionCompleted, d); +// agent.IsInTransit = true; - Scene.EventManager.TriggerCrossAgentToNewRegion(agent, isFlying, neighbourRegion); - - return true; + CrossAgentToNewRegionAsync(agent, newpos, neighbourRegion, isFlying, ctx); + agent.IsInTransit = false; + return agent; } - - public delegate void InformClientToInitiateTeleportToLocationDelegate(ScenePresence agent, uint regionX, uint regionY, - Vector3 position, - Scene initiatingScene); + public delegate void InformClientToInitiateTeleportToLocationDelegate(ScenePresence agent, uint regionX, uint regionY, Vector3 position, Scene initiatingScene); private void InformClientToInitiateTeleportToLocation(ScenePresence agent, uint regionX, uint regionY, Vector3 position, Scene initiatingScene) { @@ -1506,14 +1609,14 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer Thread.Sleep(10000); m_log.DebugFormat( - "[ENTITY TRANSFER MODULE]: Auto-reteleporting {0} to correct megaregion location {1},{2},{3} from {4}", + "[ENTITY TRANSFER MODULE]: Auto-reteleporting {0} to correct megaregion location {1},{2},{3} from {4}", agent.Name, regionX, regionY, position, initiatingScene.Name); agent.Scene.RequestTeleportLocation( - agent.ControllingClient, - Util.RegionLocToHandle(regionX, regionY), - position, - agent.Lookat, + agent.ControllingClient, + Util.RegionGridLocToHandle(regionX, regionY), + position, + agent.Lookat, (uint)Constants.TeleportFlags.ViaLocation); /* @@ -1557,15 +1660,71 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer icon.EndInvoke(iar); } - public bool CrossAgentToNewRegionPrep(ScenePresence agent, GridRegion neighbourRegion) + public bool CrossAgentCreateFarChild(ScenePresence agent, GridRegion neighbourRegion, Vector3 pos, EntityTransferContext ctx) { - if (neighbourRegion == null) + ulong regionhandler = neighbourRegion.RegionHandle; + + if(agent.knowsNeighbourRegion(regionhandler)) + return true; + + string reason; + ulong currentRegionHandler = agent.Scene.RegionInfo.RegionHandle; + GridRegion source = new GridRegion(agent.Scene.RegionInfo); + + AgentCircuitData currentAgentCircuit = + agent.Scene.AuthenticateHandler.GetAgentCircuitData(agent.ControllingClient.CircuitCode); + AgentCircuitData agentCircuit = agent.ControllingClient.RequestClientInfo(); + agentCircuit.startpos = pos; + agentCircuit.child = true; + + agentCircuit.Appearance = new AvatarAppearance(); + agentCircuit.Appearance.AvatarHeight = agent.Appearance.AvatarHeight; + + if (currentAgentCircuit != null) + { + agentCircuit.ServiceURLs = currentAgentCircuit.ServiceURLs; + agentCircuit.IPAddress = currentAgentCircuit.IPAddress; + agentCircuit.Viewer = currentAgentCircuit.Viewer; + agentCircuit.Channel = currentAgentCircuit.Channel; + agentCircuit.Mac = currentAgentCircuit.Mac; + agentCircuit.Id0 = currentAgentCircuit.Id0; + } + + agentCircuit.CapsPath = CapsUtil.GetRandomCapsObjectPath(); + agent.AddNeighbourRegion(neighbourRegion, agentCircuit.CapsPath); + + IPEndPoint endPoint = neighbourRegion.ExternalEndPoint; + if(endPoint == null) + { + m_log.DebugFormat("CrossAgentCreateFarChild failed to resolve neighbour address {0}", neighbourRegion.ExternalHostName); return false; - - m_entityTransferStateMachine.SetInTransit(agent.UUID); + } + if (!Scene.SimulationService.CreateAgent(source, neighbourRegion, agentCircuit, (int)TeleportFlags.Default, ctx, out reason)) + { + agent.RemoveNeighbourRegion(regionhandler); + return false; + } - agent.RemoveFromPhysicalScene(); + string capsPath = neighbourRegion.ServerURI + CapsUtil.GetCapsSeedPath(agentCircuit.CapsPath); + int newSizeX = neighbourRegion.RegionSizeX; + int newSizeY = neighbourRegion.RegionSizeY; + if (m_eqModule != null) + { + m_log.DebugFormat("{0} {1} is sending {2} EnableSimulator for neighbour region {3}(loc=<{4},{5}>,siz=<{6},{7}>) " + + "and EstablishAgentCommunication with seed cap {8}", LogHeader, + source.RegionName, agent.Name, + neighbourRegion.RegionName, neighbourRegion.RegionLocX, neighbourRegion.RegionLocY, newSizeX, newSizeY , capsPath); + + m_eqModule.EnableSimulator(regionhandler, + endPoint, agent.UUID, newSizeX, newSizeY); + m_eqModule.EstablishAgentCommunication(agent.UUID, endPoint, capsPath, + regionhandler, newSizeX, newSizeY); + } + else + { + agent.ControllingClient.InformClientOfNeighbour(regionhandler, endPoint); + } return true; } @@ -1582,37 +1741,56 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer m_log.DebugFormat("{0}: CrossAgentToNewRegionAsync: new region={1} at <{2},{3}>. newpos={4}", LogHeader, neighbourRegion.RegionName, neighbourRegion.RegionLocX, neighbourRegion.RegionLocY, pos); - if (!CrossAgentToNewRegionPrep(agent, neighbourRegion)) + if (neighbourRegion == null) { - m_log.DebugFormat("{0}: CrossAgentToNewRegionAsync: prep failed. Resetting transfer state", LogHeader); - m_entityTransferStateMachine.ResetFromTransit(agent.UUID); + m_log.DebugFormat("{0}: CrossAgentToNewRegionAsync: invalid destiny", LogHeader); + return agent; } - if (!CrossAgentIntoNewRegionMain(agent, pos, neighbourRegion, isFlying, ctx)) + IPEndPoint endpoint = neighbourRegion.ExternalEndPoint; + if(endpoint == null) + { + m_log.DebugFormat("{0}: CrossAgentToNewRegionAsync: failed to resolve neighbour address {0} ",neighbourRegion.ExternalHostName); + return agent; + } + + m_entityTransferStateMachine.SetInTransit(agent.UUID); + agent.RemoveFromPhysicalScene(); + + if (!CrossAgentIntoNewRegionMain(agent, pos, neighbourRegion, endpoint, isFlying, ctx)) { m_log.DebugFormat("{0}: CrossAgentToNewRegionAsync: cross main failed. Resetting transfer state", LogHeader); m_entityTransferStateMachine.ResetFromTransit(agent.UUID); } - - CrossAgentToNewRegionPost(agent, pos, neighbourRegion, isFlying, ctx); } catch (Exception e) { m_log.Error(string.Format("{0}: CrossAgentToNewRegionAsync: failed with exception ", LogHeader), e); } - return agent; } - public bool CrossAgentIntoNewRegionMain(ScenePresence agent, Vector3 pos, GridRegion neighbourRegion, bool isFlying, EntityTransferContext ctx) + public bool CrossAgentIntoNewRegionMain(ScenePresence agent, Vector3 pos, GridRegion neighbourRegion, + IPEndPoint endpoint, bool isFlying, EntityTransferContext ctx) { + int ts = Util.EnvironmentTickCount(); + bool sucess = true; + string reason = String.Empty; + List childRegionsToClose = null; try { - AgentData cAgent = new AgentData(); - agent.CopyTo(cAgent); - if (ctx.OutboundVersion < 0.5f) - cAgent.Appearance.PackLegacyWearables = true; + AgentData cAgent = new AgentData(); + agent.CopyTo(cAgent,true); + cAgent.Position = pos; + cAgent.ChildrenCapSeeds = agent.KnownRegions; + + childRegionsToClose = agent.GetChildAgentsToClose(neighbourRegion.RegionHandle, neighbourRegion.RegionSizeX, neighbourRegion.RegionSizeY); + if(cAgent.ChildrenCapSeeds != null) + { + foreach(ulong regh in childRegionsToClose) + cAgent.ChildrenCapSeeds.Remove(regh); + } if (isFlying) cAgent.ControlFlags |= (uint)AgentManager.ControlFlags.AGENT_CONTROL_FLY; @@ -1623,21 +1801,31 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer // Beyond this point, extra cleanup is needed beyond removing transit state m_entityTransferStateMachine.UpdateInTransit(agent.UUID, AgentTransferState.Transferring); - if (!agent.Scene.SimulationService.UpdateAgent(neighbourRegion, cAgent)) + if (sucess && !agent.Scene.SimulationService.UpdateAgent(neighbourRegion, cAgent, ctx)) + { + sucess = false; + reason = "agent update failed"; + } + + if(!sucess) { // region doesn't take it m_entityTransferStateMachine.UpdateInTransit(agent.UUID, AgentTransferState.CleaningUp); m_log.WarnFormat( - "[ENTITY TRANSFER MODULE]: Region {0} would not accept update for agent {1} on cross attempt. Returning to original region.", - neighbourRegion.RegionName, agent.Name); + "[ENTITY TRANSFER MODULE]: agent {0} crossing to {1} failed: {2}", + agent.Name, neighbourRegion.RegionName, reason); ReInstantiateScripts(agent); - agent.AddToPhysicalScene(isFlying); + if(agent.ParentID == 0 && agent.ParentUUID == UUID.Zero) + { + agent.AddToPhysicalScene(isFlying); + } return false; } + m_log.DebugFormat("[CrossAgentIntoNewRegionMain] ok, time {0}ms",Util.EnvironmentTickCountSubtract(ts)); } catch (Exception e) { @@ -1649,44 +1837,38 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer return false; } - return true; - } - - public void CrossAgentToNewRegionPost(ScenePresence agent, Vector3 pos, GridRegion neighbourRegion, - bool isFlying, EntityTransferContext ctx) - { - agent.ControllingClient.RequestClientInfo(); - string agentcaps; if (!agent.KnownRegions.TryGetValue(neighbourRegion.RegionHandle, out agentcaps)) { m_log.ErrorFormat("[ENTITY TRANSFER MODULE]: No ENTITY TRANSFER MODULE information for region handle {0}, exiting CrossToNewRegion.", neighbourRegion.RegionHandle); - return; + return false; } // No turning back + agent.IsChildAgent = true; string capsPath = neighbourRegion.ServerURI + CapsUtil.GetCapsSeedPath(agentcaps); m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Sending new CAPS seed url {0} to client {1}", capsPath, agent.UUID); - Vector3 vel2 = new Vector3(agent.Velocity.X, agent.Velocity.Y, 0); + Vector3 vel2 = Vector3.Zero; + if((agent.crossingFlags & 2) != 0) + vel2 = new Vector3(agent.Velocity.X, agent.Velocity.Y, 0); if (m_eqModule != null) { m_eqModule.CrossRegion( - neighbourRegion.RegionHandle, pos + agent.Velocity, vel2 /* agent.Velocity */, - neighbourRegion.ExternalEndPoint, - capsPath, agent.UUID, agent.ControllingClient.SessionId, + neighbourRegion.RegionHandle, pos, vel2 /* agent.Velocity */, + endpoint, capsPath, agent.UUID, agent.ControllingClient.SessionId, neighbourRegion.RegionSizeX, neighbourRegion.RegionSizeY); } else { m_log.ErrorFormat("{0} Using old CrossRegion packet. Varregion will not work!!", LogHeader); - agent.ControllingClient.CrossRegion(neighbourRegion.RegionHandle, pos + agent.Velocity, agent.Velocity, neighbourRegion.ExternalEndPoint, - capsPath); + agent.ControllingClient.CrossRegion(neighbourRegion.RegionHandle, pos, agent.Velocity, + endpoint,capsPath); } // SUCCESS! @@ -1695,51 +1877,23 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer // Unlike a teleport, here we do not wait for the destination region to confirm the receipt. m_entityTransferStateMachine.UpdateInTransit(agent.UUID, AgentTransferState.CleaningUp); - agent.MakeChildAgent(); - - // FIXME: Possibly this should occur lower down after other commands to close other agents, - // but not sure yet what the side effects would be. - m_entityTransferStateMachine.ResetFromTransit(agent.UUID); - - // now we have a child agent in this region. Request all interesting data about other (root) agents - agent.SendOtherAgentsAvatarDataToClient(); - agent.SendOtherAgentsAppearanceToClient(); + if(childRegionsToClose != null) + agent.CloseChildAgents(childRegionsToClose); - // TODO: Check since what version this wasn't needed anymore. May be as old as 0.6 -/* - // Backwards compatibility. Best effort - if (version == 0f) - { - m_log.DebugFormat("[ENTITY TRANSFER MODULE]: neighbor with old version, passing attachments one by one..."); - Thread.Sleep(3000); // wait a little now that we're not waiting for the callback - CrossAttachmentsIntoNewRegion(neighbourRegion, agent, true); - } -*/ - // Next, let's close the child agent connections that are too far away. - uint neighbourx; - uint neighboury; - Util.RegionHandleToRegionLoc(neighbourRegion.RegionHandle, out neighbourx, out neighboury); - - agent.CloseChildAgents(neighbourx, neighboury); + if((agent.crossingFlags & 8) == 0) + agent.ClearControls(); // don't let attachments delete (called in HasMovedAway) disturb taken controls on viewers - AgentHasMovedAway(agent, false); + agent.HasMovedAway((agent.crossingFlags & 8) == 0); - // the user may change their profile information in other region, - // so the userinfo in UserProfileCache is not reliable any more, delete it - // REFACTORING PROBLEM. Well, not a problem, but this method is HORRIBLE! -// if (agent.Scene.NeedSceneCacheClear(agent.UUID)) -// { -// m_log.DebugFormat( -// "[ENTITY TRANSFER MODULE]: User {0} is going to another region", agent.UUID); -// } + agent.MakeChildAgent(neighbourRegion.RegionHandle); - //m_log.Debug("AFTER CROSS"); - //Scene.DumpChildrenSeeds(UUID); - //DumpKnownRegions(); + // FIXME: Possibly this should occur lower down after other commands to close other agents, + // but not sure yet what the side effects would be. + m_entityTransferStateMachine.ResetFromTransit(agent.UUID); - return; + return true; } - + private void CrossAgentToNewRegionCompleted(IAsyncResult iar) { CrossAgentToNewRegionDelegate icon = (CrossAgentToNewRegionDelegate)iar.AsyncState; @@ -1754,7 +1908,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer // In any case agent.IsInTransit = false; - m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Crossing agent {0} {1} completed.", agent.Firstname, agent.Lastname); +// m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Crossing agent {0} {1} completed.", agent.Firstname, agent.Lastname); } #endregion @@ -1762,7 +1916,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer #region Enable Child Agent /// - /// This informs a single neighbouring region about agent "avatar". + /// This informs a single neighbouring region about agent "avatar", and avatar about it /// Calls an asynchronous method to do so.. so it doesn't lag the sim. /// /// @@ -1771,42 +1925,46 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer { m_log.DebugFormat("[ENTITY TRANSFER]: Enabling child agent in new neighbour {0}", region.RegionName); + ulong currentRegionHandler = sp.Scene.RegionInfo.RegionHandle; + ulong regionhandler = region.RegionHandle; + + Dictionary seeds = new Dictionary(sp.Scene.CapsModule.GetChildrenSeeds(sp.UUID)); + + if (seeds.ContainsKey(regionhandler)) + seeds.Remove(regionhandler); +/* + List oldregions = new List(seeds.Keys); + + if (oldregions.Contains(currentRegionHandler)) + oldregions.Remove(currentRegionHandler); +*/ + if (!seeds.ContainsKey(currentRegionHandler)) + seeds.Add(currentRegionHandler, sp.ControllingClient.RequestClientInfo().CapsPath); + AgentCircuitData currentAgentCircuit = sp.Scene.AuthenticateHandler.GetAgentCircuitData(sp.ControllingClient.CircuitCode); AgentCircuitData agent = sp.ControllingClient.RequestClientInfo(); agent.BaseFolder = UUID.Zero; agent.InventoryFolder = UUID.Zero; - agent.startpos = new Vector3(128, 128, 70); + agent.startpos = sp.AbsolutePosition + CalculateOffset(sp, region); agent.child = true; agent.Appearance = new AvatarAppearance(); - agent.Appearance.PackLegacyWearables = true; - agent.CapsPath = CapsUtil.GetRandomCapsObjectPath(); - - agent.ChildrenCapSeeds = new Dictionary(sp.Scene.CapsModule.GetChildrenSeeds(sp.UUID)); - //m_log.DebugFormat("[XXX] Seeds 1 {0}", agent.ChildrenCapSeeds.Count); + agent.Appearance.AvatarHeight = sp.Appearance.AvatarHeight; - if (!agent.ChildrenCapSeeds.ContainsKey(sp.Scene.RegionInfo.RegionHandle)) - agent.ChildrenCapSeeds.Add(sp.Scene.RegionInfo.RegionHandle, sp.ControllingClient.RequestClientInfo().CapsPath); - //m_log.DebugFormat("[XXX] Seeds 2 {0}", agent.ChildrenCapSeeds.Count); + agent.CapsPath = CapsUtil.GetRandomCapsObjectPath(); - sp.AddNeighbourRegion(region.RegionHandle, agent.CapsPath); - //foreach (ulong h in agent.ChildrenCapSeeds.Keys) - // m_log.DebugFormat("[XXX] --> {0}", h); - //m_log.DebugFormat("[XXX] Adding {0}", region.RegionHandle); - if (agent.ChildrenCapSeeds.ContainsKey(region.RegionHandle)) - { - m_log.WarnFormat( - "[ENTITY TRANSFER]: Overwriting caps seed {0} with {1} for region {2} (handle {3}) for {4} in {5}", - agent.ChildrenCapSeeds[region.RegionHandle], agent.CapsPath, - region.RegionName, region.RegionHandle, sp.Name, Scene.Name); - } + seeds.Add(regionhandler, agent.CapsPath); - agent.ChildrenCapSeeds[region.RegionHandle] = agent.CapsPath; +// agent.ChildrenCapSeeds = new Dictionary(seeds); + agent.ChildrenCapSeeds = null; if (sp.Scene.CapsModule != null) { - sp.Scene.CapsModule.SetChildrenSeed(sp.UUID, agent.ChildrenCapSeeds); + sp.Scene.CapsModule.SetChildrenSeed(sp.UUID, seeds); } + sp.KnownRegions = seeds; + sp.AddNeighbourRegionSizeInfo(region); + if (currentAgentCircuit != null) { agent.ServiceURLs = currentAgentCircuit.ServiceURLs; @@ -1816,7 +1974,24 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer agent.Mac = currentAgentCircuit.Mac; agent.Id0 = currentAgentCircuit.Id0; } - +/* + AgentPosition agentpos = null; + + if (oldregions.Count > 0) + { + agentpos = new AgentPosition(); + agentpos.AgentID = new UUID(sp.UUID.Guid); + agentpos.SessionID = sp.ControllingClient.SessionId; + agentpos.Size = sp.Appearance.AvatarSize; + agentpos.Center = sp.CameraPosition; + agentpos.Far = sp.DrawDistance; + agentpos.Position = sp.AbsolutePosition; + agentpos.Velocity = sp.Velocity; + agentpos.RegionHandle = currentRegionHandler; + agentpos.Throttles = sp.ControllingClient.GetThrottlesPacked(1); + agentpos.ChildrenCapSeeds = seeds; + } +*/ IPEndPoint external = region.ExternalEndPoint; if (external != null) { @@ -1825,7 +2000,22 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer InformClientOfNeighbourCompleted, d); } +/* + if(oldregions.Count >0) + { + uint neighbourx; + uint neighboury; + UUID scope = sp.Scene.RegionInfo.ScopeID; + foreach (ulong handler in oldregions) + { + Utils.LongToUInts(handler, out neighbourx, out neighboury); + GridRegion neighbour = sp.Scene.GridService.GetRegionByPosition(scope, (int)neighbourx, (int)neighboury); + sp.Scene.SimulationService.UpdateAgent(neighbour, agentpos); + } + } + */ } + #endregion #region Enable Child Agents @@ -1835,167 +2025,175 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer /// /// This informs all neighbouring regions about agent "avatar". + /// and as important informs the avatar about then /// /// public void EnableChildAgents(ScenePresence sp) { + // assumes that out of view range regions are disconnected by the previus region + List neighbours = new List(); - RegionInfo m_regionInfo = sp.Scene.RegionInfo; + Scene spScene = sp.Scene; + RegionInfo m_regionInfo = spScene.RegionInfo; if (m_regionInfo != null) { - neighbours = GetNeighbours(sp, m_regionInfo.RegionLocX, m_regionInfo.RegionLocY); + neighbours = GetNeighbors(sp, m_regionInfo.RegionLocX, m_regionInfo.RegionLocY); } else { m_log.Debug("[ENTITY TRANSFER MODULE]: m_regionInfo was null in EnableChildAgents, is this a NPC?"); } - /// We need to find the difference between the new regions where there are no child agents - /// and the regions where there are already child agents. We only send notification to the former. - List neighbourHandles = NeighbourHandles(neighbours); // on this region - neighbourHandles.Add(sp.Scene.RegionInfo.RegionHandle); // add this region too - List previousRegionNeighbourHandles; + ulong currentRegionHandler = m_regionInfo.RegionHandle; - if (sp.Scene.CapsModule != null) + LinkedList previousRegionNeighbourHandles; + Dictionary seeds; + ICapabilitiesModule capsModule = spScene.CapsModule; + + if (capsModule != null) { - previousRegionNeighbourHandles = - new List(sp.Scene.CapsModule.GetChildrenSeeds(sp.UUID).Keys); + seeds = new Dictionary(capsModule.GetChildrenSeeds(sp.UUID)); + previousRegionNeighbourHandles = new LinkedList(seeds.Keys); } else { - previousRegionNeighbourHandles = new List(); + seeds = new Dictionary(); + previousRegionNeighbourHandles = new LinkedList(); } - List newRegions = NewNeighbours(neighbourHandles, previousRegionNeighbourHandles); - List oldRegions = OldNeighbours(neighbourHandles, previousRegionNeighbourHandles); - -// Dump("Current Neighbors", neighbourHandles); -// Dump("Previous Neighbours", previousRegionNeighbourHandles); -// Dump("New Neighbours", newRegions); -// Dump("Old Neighbours", oldRegions); - - /// Update the scene presence's known regions here on this region - sp.DropOldNeighbours(oldRegions); + IClientAPI spClient = sp.ControllingClient; - /// Collect as many seeds as possible - Dictionary seeds; - if (sp.Scene.CapsModule != null) - seeds = new Dictionary(sp.Scene.CapsModule.GetChildrenSeeds(sp.UUID)); - else - seeds = new Dictionary(); + // This will fail if the user aborts login + try + { + if (!seeds.ContainsKey(currentRegionHandler)) + seeds.Add(currentRegionHandler, spClient.RequestClientInfo().CapsPath); + } + catch + { + return; + } - //m_log.Debug(" !!! No. of seeds: " + seeds.Count); - if (!seeds.ContainsKey(sp.Scene.RegionInfo.RegionHandle)) - seeds.Add(sp.Scene.RegionInfo.RegionHandle, sp.ControllingClient.RequestClientInfo().CapsPath); + AgentCircuitData currentAgentCircuit = + spScene.AuthenticateHandler.GetAgentCircuitData(sp.ControllingClient.CircuitCode); - /// Create the necessary child agents List cagents = new List(); + List newneighbours = new List(); + foreach (GridRegion neighbour in neighbours) { - if (neighbour.RegionHandle != sp.Scene.RegionInfo.RegionHandle) + ulong handler = neighbour.RegionHandle; + + if (previousRegionNeighbourHandles.Contains(handler)) { - AgentCircuitData currentAgentCircuit = sp.Scene.AuthenticateHandler.GetAgentCircuitData(sp.ControllingClient.CircuitCode); - AgentCircuitData agent = sp.ControllingClient.RequestClientInfo(); - agent.BaseFolder = UUID.Zero; - agent.InventoryFolder = UUID.Zero; - agent.startpos = sp.AbsolutePosition + CalculateOffset(sp, neighbour); - agent.child = true; - agent.Appearance = new AvatarAppearance(); - agent.Appearance.PackLegacyWearables = true; - if (currentAgentCircuit != null) - { - agent.ServiceURLs = currentAgentCircuit.ServiceURLs; - agent.IPAddress = currentAgentCircuit.IPAddress; - agent.Viewer = currentAgentCircuit.Viewer; - agent.Channel = currentAgentCircuit.Channel; - agent.Mac = currentAgentCircuit.Mac; - agent.Id0 = currentAgentCircuit.Id0; - } + // agent already knows this region + previousRegionNeighbourHandles.Remove(handler); + continue; + } - if (newRegions.Contains(neighbour.RegionHandle)) - { - agent.CapsPath = CapsUtil.GetRandomCapsObjectPath(); - sp.AddNeighbourRegion(neighbour.RegionHandle, agent.CapsPath); - seeds.Add(neighbour.RegionHandle, agent.CapsPath); - } - else - { - agent.CapsPath = sp.Scene.CapsModule.GetChildSeed(sp.UUID, neighbour.RegionHandle); - } + if (handler == currentRegionHandler) + continue; - cagents.Add(agent); + // a new region to add + AgentCircuitData agent = spClient.RequestClientInfo(); + agent.BaseFolder = UUID.Zero; + agent.InventoryFolder = UUID.Zero; + agent.startpos = sp.AbsolutePosition + CalculateOffset(sp, neighbour); + agent.child = true; + agent.Appearance = new AvatarAppearance(); + agent.Appearance.AvatarHeight = sp.Appearance.AvatarHeight; + + if (currentAgentCircuit != null) + { + agent.ServiceURLs = currentAgentCircuit.ServiceURLs; + agent.IPAddress = currentAgentCircuit.IPAddress; + agent.Viewer = currentAgentCircuit.Viewer; + agent.Channel = currentAgentCircuit.Channel; + agent.Mac = currentAgentCircuit.Mac; + agent.Id0 = currentAgentCircuit.Id0; } - } - /// Update all child agent with everyone's seeds - foreach (AgentCircuitData a in cagents) - { - a.ChildrenCapSeeds = new Dictionary(seeds); - } + newneighbours.Add(handler); + agent.CapsPath = CapsUtil.GetRandomCapsObjectPath(); + seeds.Add(handler, agent.CapsPath); - if (sp.Scene.CapsModule != null) - { - sp.Scene.CapsModule.SetChildrenSeed(sp.UUID, seeds); + agent.ChildrenCapSeeds = null; + cagents.Add(agent); } - sp.KnownRegions = seeds; - //avatar.Scene.DumpChildrenSeeds(avatar.UUID); - //avatar.DumpKnownRegions(); - bool newAgent = false; - int count = 0; - foreach (GridRegion neighbour in neighbours) - { - //m_log.WarnFormat("--> Going to send child agent to {0}", neighbour.RegionName); - // Don't do it if there's already an agent in that region - if (newRegions.Contains(neighbour.RegionHandle)) - newAgent = true; - else - newAgent = false; -// continue; + if (previousRegionNeighbourHandles.Contains(currentRegionHandler)) + previousRegionNeighbourHandles.Remove(currentRegionHandler); - if (neighbour.RegionHandle != sp.Scene.RegionInfo.RegionHandle) - { - try - { - // Let's put this back at sync, so that it doesn't clog - // the network, especially for regions in the same physical server. - // We're really not in a hurry here. - InformClientOfNeighbourAsync(sp, cagents[count], neighbour, neighbour.ExternalEndPoint, newAgent); - //InformClientOfNeighbourDelegate d = InformClientOfNeighbourAsync; - //d.BeginInvoke(sp, cagents[count], neighbour, neighbour.ExternalEndPoint, newAgent, - // InformClientOfNeighbourCompleted, - // d); - } + // previousRegionNeighbourHandles now contains regions to forget + foreach (ulong handler in previousRegionNeighbourHandles) + seeds.Remove(handler); - catch (ArgumentOutOfRangeException) - { - m_log.ErrorFormat( - "[ENTITY TRANSFER MODULE]: Neighbour Regions response included the current region in the neighbour list. The following region will not display to the client: {0} for region {1} ({2}, {3}).", - neighbour.ExternalHostName, - neighbour.RegionHandle, - neighbour.RegionLocX, - neighbour.RegionLocY); - } - catch (Exception e) - { - m_log.ErrorFormat( - "[ENTITY TRANSFER MODULE]: Could not resolve external hostname {0} for region {1} ({2}, {3}). {4}", - neighbour.ExternalHostName, - neighbour.RegionHandle, - neighbour.RegionLocX, - neighbour.RegionLocY, - e); + /// Update all child agent with everyone's seeds + // foreach (AgentCircuitData a in cagents) + // a.ChildrenCapSeeds = new Dictionary(seeds); - // FIXME: Okay, even though we've failed, we're still going to throw the exception on, - // since I don't know what will happen if we just let the client continue + if (capsModule != null) + capsModule.SetChildrenSeed(sp.UUID, seeds); - // XXX: Well, decided to swallow the exception instead for now. Let us see how that goes. - // throw e; + sp.KnownRegions = seeds; + sp.SetNeighbourRegionSizeInfo(neighbours); + + if(newneighbours.Count > 0 || previousRegionNeighbourHandles.Count > 0) + { + AgentPosition agentpos = new AgentPosition(); + agentpos.AgentID = new UUID(sp.UUID.Guid); + agentpos.SessionID = spClient.SessionId; + agentpos.Size = sp.Appearance.AvatarSize; + agentpos.Center = sp.CameraPosition; + agentpos.Far = sp.DrawDistance; + agentpos.Position = sp.AbsolutePosition; + agentpos.Velocity = sp.Velocity; + agentpos.RegionHandle = currentRegionHandler; + //agentpos.GodLevel = sp.GodLevel; + agentpos.GodData = sp.GodController.State(); + agentpos.Throttles = spClient.GetThrottlesPacked(1); + // agentpos.ChildrenCapSeeds = seeds; + + Util.FireAndForget(delegate + { + Thread.Sleep(200); // the original delay that was at InformClientOfNeighbourAsync start + int count = 0; + IPEndPoint ipe; + foreach (GridRegion neighbour in neighbours) + { + ulong handler = neighbour.RegionHandle; + try + { + if (newneighbours.Contains(handler)) + { + ipe = neighbour.ExternalEndPoint; + if (ipe != null) + InformClientOfNeighbourAsync(sp, cagents[count], neighbour, ipe, true); + else + { + m_log.DebugFormat("[ENTITY TRANSFER MODULE]: lost DNS resolution for neighbour {0}", neighbour.ExternalHostName); + } + count++; + } + else if (!previousRegionNeighbourHandles.Contains(handler)) + { + spScene.SimulationService.UpdateAgent(neighbour, agentpos); + } + } + catch (Exception e) + { + m_log.ErrorFormat( + "[ENTITY TRANSFER MODULE]: Error creating child agent at {0} ({1} ({2}, {3}). {4}", + neighbour.ExternalHostName, + neighbour.RegionHandle, + neighbour.RegionLocX, + neighbour.RegionLocY, + e); + } } - } - count++; + }); } } @@ -2004,26 +2202,11 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer // The first region is the home region of the passed scene presence. Vector3 CalculateOffset(ScenePresence sp, GridRegion neighbour) { - /* - int rRegionX = (int)sp.Scene.RegionInfo.LegacyRegionLocX; - int rRegionY = (int)sp.Scene.RegionInfo.LegacyRegionLocY; - int tRegionX = neighbour.RegionLocX / (int)Constants.RegionSize; - int tRegionY = neighbour.RegionLocY / (int)Constants.RegionSize; - int shiftx = (rRegionX - tRegionX) * (int)Constants.RegionSize; - int shifty = (rRegionY - tRegionY) * (int)Constants.RegionSize; - return new Vector3(shiftx, shifty, 0f); - */ - return new Vector3( sp.Scene.RegionInfo.WorldLocX - neighbour.RegionLocX, + return new Vector3(sp.Scene.RegionInfo.WorldLocX - neighbour.RegionLocX, sp.Scene.RegionInfo.WorldLocY - neighbour.RegionLocY, 0f); } - - public GridRegion GetRegionContainingWorldLocation(IGridService pGridService, UUID pScopeID, double px, double py) - { - // Since we don't know how big the regions could be, we have to search a very large area - // to find possible regions. - return GetRegionContainingWorldLocation(pGridService, pScopeID, px, py, Constants.MaximumRegionSize); - } + #endregion #region NotFoundLocationCache class // A collection of not found locations to make future lookups 'not found' lookups quick. @@ -2032,162 +2215,131 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer // contains that point. A conservitive estimate. private class NotFoundLocationCache { - private struct NotFoundLocation - { - public double minX, maxX, minY, maxY; - public DateTime expireTime; - } - private List m_notFoundLocations = new List(); + private Dictionary m_notFoundLocations = new Dictionary(); public NotFoundLocationCache() { } - // Add an area to the list of 'not found' places. The area is the snapped region - // area around the added point. + // just use normal regions handlers and sizes public void Add(double pX, double pY) { + ulong psh = (ulong)pX & 0xffffff00ul; + psh <<= 32; + psh |= (ulong)pY & 0xffffff00ul; + lock (m_notFoundLocations) - { - if (!LockedContains(pX, pY)) - { - NotFoundLocation nfl = new NotFoundLocation(); - // A not found location is not found for at least a whole region sized area - nfl.minX = pX - (pX % (double)Constants.RegionSize); - nfl.minY = pY - (pY % (double)Constants.RegionSize); - nfl.maxX = nfl.minX + (double)Constants.RegionSize; - nfl.maxY = nfl.minY + (double)Constants.RegionSize; - nfl.expireTime = DateTime.Now + TimeSpan.FromSeconds(30); - m_notFoundLocations.Add(nfl); - } - } - + m_notFoundLocations[psh] = DateTime.UtcNow + TimeSpan.FromSeconds(30); } // Test to see of this point is in any of the 'not found' areas. // Return 'true' if the point is found inside the 'not found' areas. public bool Contains(double pX, double pY) { - bool ret = false; + ulong psh = (ulong)pX & 0xffffff00ul; + psh <<= 32; + psh |= (ulong)pY & 0xffffff00ul; + lock (m_notFoundLocations) - ret = LockedContains(pX, pY); - return ret; - } - private bool LockedContains(double pX, double pY) - { - bool ret = false; - this.DoExpiration(); - foreach (NotFoundLocation nfl in m_notFoundLocations) { - if (pX >= nfl.minX && pX < nfl.maxX && pY >= nfl.minY && pY < nfl.maxY) + if(m_notFoundLocations.ContainsKey(psh)) { - ret = true; - break; + if(m_notFoundLocations[psh] > DateTime.UtcNow) + return true; + m_notFoundLocations.Remove(psh); } + return false; } - return ret; } + private void DoExpiration() { - List m_toRemove = null; - DateTime now = DateTime.Now; - foreach (NotFoundLocation nfl in m_notFoundLocations) + List m_toRemove = new List();; + DateTime now = DateTime.UtcNow; + lock (m_notFoundLocations) { - if (nfl.expireTime < now) + foreach (KeyValuePair kvp in m_notFoundLocations) { - if (m_toRemove == null) - m_toRemove = new List(); - m_toRemove.Add(nfl); + if (kvp.Value < now) + m_toRemove.Add(kvp.Key); + } + + if (m_toRemove.Count > 0) + { + foreach (ulong u in m_toRemove) + m_notFoundLocations.Remove(u); + m_toRemove.Clear(); } - } - if (m_toRemove != null) - { - foreach (NotFoundLocation nfl in m_toRemove) - m_notFoundLocations.Remove(nfl); - m_toRemove.Clear(); } } } + #endregion // NotFoundLocationCache class + #region getregions private NotFoundLocationCache m_notFoundLocationCache = new NotFoundLocationCache(); - // Given a world position (fractional meter coordinate), get the GridRegion info for + protected GridRegion GetRegionContainingWorldLocation(IGridService pGridService, UUID pScopeID, double px, double py) + { + // Since we don't know how big the regions could be, we have to search a very large area + // to find possible regions. + return GetRegionContainingWorldLocation(pGridService, pScopeID, px, py, Constants.MaximumRegionSize); + } + + // Given a world position, get the GridRegion info for // the region containing that point. - // Someday this should be a method on GridService. - // 'pSizeHint' is the size of the source region but since the destination point can be anywhere - // the size of the target region is unknown thus the search area might have to be very large. - // Return 'null' if no such region exists. - public GridRegion GetRegionContainingWorldLocation(IGridService pGridService, UUID pScopeID, + // for compatibility with old grids it does a scan to find large regions + // 0.9 grids to that + + protected GridRegion GetRegionContainingWorldLocation(IGridService pGridService, UUID pScopeID, double px, double py, uint pSizeHint) { - m_log.DebugFormat("{0} GetRegionContainingWorldLocation: query, loc=<{1},{2}>", LogHeader, px, py); +// m_log.DebugFormat("{0} GetRegionContainingWorldLocation: call, XY=<{1},{2}>", LogHeader, px, py); GridRegion ret = null; - const double fudge = 2.0; - // One problem with this routine is negative results. That is, this can be called lots of times - // for regions that don't exist. m_notFoundLocationCache remembers 'not found' results so they - // will be quick 'not found's next time. - // NotFoundLocationCache is an expiring cache so it will eventually forget about 'not found' and - // thus re-ask the GridService about the location. if (m_notFoundLocationCache.Contains(px, py)) { - m_log.DebugFormat("{0} GetRegionContainingWorldLocation: Not found via cache. loc=<{1},{2}>", LogHeader, px, py); +// m_log.DebugFormat("{0} GetRegionContainingWorldLocation: Not found via cache. loc=<{1},{2}>", LogHeader, px, py); return null; } // As an optimization, since most regions will be legacy sized regions (256x256), first try to get // the region at the appropriate legacy region location. - uint possibleX = (uint)Math.Floor(px); - possibleX -= possibleX % Constants.RegionSize; - uint possibleY = (uint)Math.Floor(py); - possibleY -= possibleY % Constants.RegionSize; + // this is all that is needed on 0.9 grids + uint possibleX = (uint)px & 0xffffff00u; + uint possibleY = (uint)py & 0xffffff00u; ret = pGridService.GetRegionByPosition(pScopeID, (int)possibleX, (int)possibleY); if (ret != null) { - m_log.DebugFormat("{0} GetRegionContainingWorldLocation: Found region using legacy size. rloc=<{1},{2}>. Rname={3}", - LogHeader, possibleX, possibleY, ret.RegionName); +// m_log.DebugFormat("{0} GetRegionContainingWorldLocation: Found region using legacy size. rloc=<{1},{2}>. Rname={3}", +// LogHeader, possibleX, possibleY, ret.RegionName); + return ret; } - if (ret == null) + // for 0.8 regions just make a BIG area request. old code whould do it plus 4 more smaller on region open edges + // this is what 0.9 grids now do internally + List possibleRegions = pGridService.GetRegionRange(pScopeID, + (int)(px - Constants.MaximumRegionSize), (int)(px + 1), // +1 bc left mb not part of range + (int)(py - Constants.MaximumRegionSize), (int)(py + 1)); +// m_log.DebugFormat("{0} GetRegionContainingWorldLocation: possibleRegions cnt={1}, range={2}", +// LogHeader, possibleRegions.Count, range); + if (possibleRegions != null && possibleRegions.Count > 0) { - // If the simple lookup failed, search the larger area for a region that contains this point - double range = (double)pSizeHint + fudge; - while (ret == null && range <= (Constants.MaximumRegionSize + Constants.RegionSize)) + // If we found some regions, check to see if the point is within + foreach (GridRegion gr in possibleRegions) { - // Get from the grid service a list of regions that might contain this point. - // The region origin will be in the zero direction so only subtract the range. - List possibleRegions = pGridService.GetRegionRange(pScopeID, - (int)(px - range), (int)(px), - (int)(py - range), (int)(py)); - m_log.DebugFormat("{0} GetRegionContainingWorldLocation: possibleRegions cnt={1}, range={2}", - LogHeader, possibleRegions.Count, range); - if (possibleRegions != null && possibleRegions.Count > 0) - { - // If we found some regions, check to see if the point is within - foreach (GridRegion gr in possibleRegions) - { - m_log.DebugFormat("{0} GetRegionContainingWorldLocation: possibleRegion nm={1}, regionLoc=<{2},{3}>, regionSize=<{4},{5}>", - LogHeader, gr.RegionName, gr.RegionLocX, gr.RegionLocY, gr.RegionSizeX, gr.RegionSizeY); - if (px >= (double)gr.RegionLocX && px < (double)(gr.RegionLocX + gr.RegionSizeX) +// m_log.DebugFormat("{0} GetRegionContainingWorldLocation: possibleRegion nm={1}, regionLoc=<{2},{3}>, regionSize=<{4},{5}>", +// LogHeader, gr.RegionName, gr.RegionLocX, gr.RegionLocY, gr.RegionSizeX, gr.RegionSizeY); + if (px >= (double)gr.RegionLocX && px < (double)(gr.RegionLocX + gr.RegionSizeX) && py >= (double)gr.RegionLocY && py < (double)(gr.RegionLocY + gr.RegionSizeY)) - { - // Found a region that contains the point - ret = gr; - m_log.DebugFormat("{0} GetRegionContainingWorldLocation: found. RegionName={1}", LogHeader, ret.RegionName); - break; - } - } + { + // Found a region that contains the point + return gr; +// m_log.DebugFormat("{0} GetRegionContainingWorldLocation: found. RegionName={1}", LogHeader, ret.RegionName); } - // Larger search area for next time around if not found - range *= 2; } } - if (ret == null) - { - // remember this location was not found so we can quickly not find it next time - m_notFoundLocationCache.Add(px, py); - m_log.DebugFormat("{0} GetRegionContainingWorldLocation: Not found. Remembering loc=<{1},{2}>", LogHeader, px, py); - } - - return ret; + // remember this location was not found so we can quickly not find it next time + m_notFoundLocationCache.Add(px, py); +// m_log.DebugFormat("{0} GetRegionContainingWorldLocation: Not found. Remembering loc=<{1},{2}>", LogHeader, px, py); + return null; } private void InformClientOfNeighbourCompleted(IAsyncResult iar) @@ -2207,81 +2359,65 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer /// /// /// - private void InformClientOfNeighbourAsync(ScenePresence sp, AgentCircuitData a, GridRegion reg, + private void InformClientOfNeighbourAsync(ScenePresence sp, AgentCircuitData agentCircData, GridRegion reg, IPEndPoint endPoint, bool newAgent) { - // Let's wait just a little to give time to originating regions to catch up with closing child agents - // after a cross here - Thread.Sleep(500); - Scene scene = sp.Scene; - - m_log.DebugFormat( - "[ENTITY TRANSFER MODULE]: Informing {0} {1} about neighbour {2} {3} at ({4},{5})", - sp.Name, sp.UUID, reg.RegionName, endPoint, reg.RegionCoordX, reg.RegionCoordY); + if (newAgent) + { + // we may already had lost this sp + if(sp == null || sp.IsDeleted || sp.ClientView == null) // something bad already happened + return; - string capsPath = reg.ServerURI + CapsUtil.GetCapsSeedPath(a.CapsPath); + Scene scene = sp.Scene; - string reason = String.Empty; + m_log.DebugFormat( + "[ENTITY TRANSFER MODULE]: Informing {0} {1} about neighbour {2} {3} at ({4},{5})", + sp.Name, sp.UUID, reg.RegionName, endPoint, reg.RegionCoordX, reg.RegionCoordY); - bool regionAccepted = scene.SimulationService.CreateAgent(null, reg, a, (uint)TeleportFlags.Default, out reason); + string capsPath = reg.ServerURI + CapsUtil.GetCapsSeedPath(agentCircData.CapsPath); - if (regionAccepted && newAgent) - { - if (m_eqModule != null) + string reason = String.Empty; + + EntityTransferContext ctx = new EntityTransferContext(); + bool regionAccepted = scene.SimulationService.CreateAgent(reg, reg, agentCircData, (uint)TeleportFlags.Default, ctx, out reason); + + if (regionAccepted) { - #region IP Translation for NAT - IClientIPEndpoint ipepClient; - if (sp.ClientView.TryGet(out ipepClient)) + // give time for createAgent to finish, since it is async and does grid services access + Thread.Sleep(500); + + if (m_eqModule != null) { - endPoint.Address = NetworkUtil.GetIPFor(ipepClient.EndPoint, endPoint.Address); - } - #endregion + if(sp == null || sp.IsDeleted || sp.ClientView == null) // something bad already happened + return; + + m_log.DebugFormat("{0} {1} is sending {2} EnableSimulator for neighbour region {3}(loc=<{4},{5}>,siz=<{6},{7}>) " + + "and EstablishAgentCommunication with seed cap {8}", LogHeader, + scene.RegionInfo.RegionName, sp.Name, + reg.RegionName, reg.RegionLocX, reg.RegionLocY, reg.RegionSizeX, reg.RegionSizeY, capsPath); - m_log.DebugFormat("{0} {1} is sending {2} EnableSimulator for neighbour region {3}(loc=<{4},{5}>,siz=<{6},{7}>) " + - "and EstablishAgentCommunication with seed cap {8}", LogHeader, - scene.RegionInfo.RegionName, sp.Name, - reg.RegionName, reg.RegionLocX, reg.RegionLocY, reg.RegionSizeX, reg.RegionSizeY , capsPath); + m_eqModule.EnableSimulator(reg.RegionHandle, endPoint, sp.UUID, reg.RegionSizeX, reg.RegionSizeY); + m_eqModule.EstablishAgentCommunication(sp.UUID, endPoint, capsPath, reg.RegionHandle, reg.RegionSizeX, reg.RegionSizeY); + } + else + { + sp.ControllingClient.InformClientOfNeighbour(reg.RegionHandle, endPoint); + // TODO: make Event Queue disablable! + } - m_eqModule.EnableSimulator(reg.RegionHandle, endPoint, sp.UUID, reg.RegionSizeX, reg.RegionSizeY); - m_eqModule.EstablishAgentCommunication(sp.UUID, endPoint, capsPath, reg.RegionHandle, reg.RegionSizeX, reg.RegionSizeY); + m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Completed inform {0} {1} about neighbour {2}", sp.Name, sp.UUID, endPoint); } + else { - sp.ControllingClient.InformClientOfNeighbour(reg.RegionHandle, endPoint); - // TODO: make Event Queue disablable! + sp.RemoveNeighbourRegion(reg.RegionHandle); + m_log.WarnFormat( + "[ENTITY TRANSFER MODULE]: Region {0} did not accept {1} {2}: {3}", + reg.RegionName, sp.Name, sp.UUID, reason); } - - m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Completed inform {0} {1} about neighbour {2}", sp.Name, sp.UUID, endPoint); } - if (!regionAccepted) - m_log.WarnFormat( - "[ENTITY TRANSFER MODULE]: Region {0} did not accept {1} {2}: {3}", - reg.RegionName, sp.Name, sp.UUID, reason); - } - - /// - /// Gets the range considered in view of this megaregion (assuming this is a megaregion). - /// - /// Expressed in 256m units - /// - /// - private void GetMegaregionViewRange(out Vector2 swCorner, out Vector2 neCorner) - { - Vector2 extent = Vector2.Zero; - - if (m_regionCombinerModule != null) - { - Vector2 megaRegionSize = m_regionCombinerModule.GetSizeOfMegaregion(Scene.RegionInfo.RegionID); - extent.X = (float)Util.WorldToRegionLoc((uint)megaRegionSize.X); - extent.Y = (float)Util.WorldToRegionLoc((uint)megaRegionSize.Y); - } - - swCorner.X = Scene.RegionInfo.RegionLocX - 1; - swCorner.Y = Scene.RegionInfo.RegionLocY - 1; - neCorner.X = Scene.RegionInfo.RegionLocX + extent.X; - neCorner.Y = Scene.RegionInfo.RegionLocY + extent.Y; } /// @@ -2290,98 +2426,42 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer /// /// /// - /// - protected List GetNeighbours(ScenePresence avatar, uint pRegionLocX, uint pRegionLocY) + /// + protected List GetNeighbors(ScenePresence avatar, uint pRegionLocX, uint pRegionLocY) { Scene pScene = avatar.Scene; RegionInfo m_regionInfo = pScene.RegionInfo; List neighbours; - // Leaving this as a "megaregions" computation vs "non-megaregions" computation; it isn't - // clear what should be done with a "far view" given that megaregions already extended the - // view to include everything in the megaregion - if (m_regionCombinerModule == null || !m_regionCombinerModule.IsRootForMegaregion(Scene.RegionInfo.RegionID)) - { - // The area to check is as big as the current region. - // We presume all adjacent regions are the same size as this region. - uint dd = Math.Max((uint)avatar.Scene.DefaultDrawDistance, - Math.Max(Scene.RegionInfo.RegionSizeX, Scene.RegionInfo.RegionSizeY)); + uint dd = (uint)avatar.RegionViewDistance; - uint startX = Util.RegionToWorldLoc(pRegionLocX) - dd + Constants.RegionSize/2; - uint startY = Util.RegionToWorldLoc(pRegionLocY) - dd + Constants.RegionSize/2; + // until avatar movement updates client connections, we need to seend at least this current region imediate neighbors + uint ddX = Math.Max(dd, Constants.RegionSize); + uint ddY = Math.Max(dd, Constants.RegionSize); - uint endX = Util.RegionToWorldLoc(pRegionLocX) + dd + Constants.RegionSize/2; - uint endY = Util.RegionToWorldLoc(pRegionLocY) + dd + Constants.RegionSize/2; + ddX--; + ddY--; - neighbours - = avatar.Scene.GridService.GetRegionRange( - m_regionInfo.ScopeID, (int)startX, (int)endX, (int)startY, (int)endY); - } - else - { - Vector2 swCorner, neCorner; - GetMegaregionViewRange(out swCorner, out neCorner); + // reference to region edges. Should be avatar position + uint startX = Util.RegionToWorldLoc(pRegionLocX); + uint endX = startX + m_regionInfo.RegionSizeX; + uint startY = Util.RegionToWorldLoc(pRegionLocY); + uint endY = startY + m_regionInfo.RegionSizeY; - neighbours - = pScene.GridService.GetRegionRange( - m_regionInfo.ScopeID, - (int)Util.RegionToWorldLoc((uint)swCorner.X), (int)Util.RegionToWorldLoc((uint)neCorner.X), - (int)Util.RegionToWorldLoc((uint)swCorner.Y), (int)Util.RegionToWorldLoc((uint)neCorner.Y)); - } + startX -= ddX; + startY -= ddY; + endX += ddX; + endY += ddY; -// neighbours.ForEach( -// n => -// m_log.DebugFormat( -// "[ENTITY TRANSFER MODULE]: Region flags for {0} as seen by {1} are {2}", -// n.RegionName, Scene.Name, n.RegionFlags != null ? n.RegionFlags.ToString() : "not present")); + neighbours + = avatar.Scene.GridService.GetRegionRange( + m_regionInfo.ScopeID, (int)startX, (int)endX, (int)startY, (int)endY); // The r.RegionFlags == null check only needs to be made for simulators before 2015-01-14 (pre 0.8.1). - neighbours.RemoveAll( - r => - r.RegionID == m_regionInfo.RegionID - || (r.RegionFlags != null && (r.RegionFlags & OpenSim.Framework.RegionFlags.RegionOnline) == 0)); + neighbours.RemoveAll( r => r.RegionID == m_regionInfo.RegionID ); return neighbours; } - - private List NewNeighbours(List currentNeighbours, List previousNeighbours) - { - return currentNeighbours.FindAll(delegate(ulong handle) { return !previousNeighbours.Contains(handle); }); - } - - // private List CommonNeighbours(List currentNeighbours, List previousNeighbours) - // { - // return currentNeighbours.FindAll(delegate(ulong handle) { return previousNeighbours.Contains(handle); }); - // } - - private List OldNeighbours(List currentNeighbours, List previousNeighbours) - { - return previousNeighbours.FindAll(delegate(ulong handle) { return !currentNeighbours.Contains(handle); }); - } - - private List NeighbourHandles(List neighbours) - { - List handles = new List(); - foreach (GridRegion reg in neighbours) - { - handles.Add(reg.RegionHandle); - } - return handles; - } - -// private void Dump(string msg, List handles) -// { -// m_log.InfoFormat("-------------- HANDLE DUMP ({0}) ---------", msg); -// foreach (ulong handle in handles) -// { -// uint x, y; -// Utils.LongToUInts(handle, out x, out y); -// x = x / Constants.RegionSize; -// y = y / Constants.RegionSize; -// m_log.InfoFormat("({0}, {1})", x, y); -// } -// } - #endregion #region Agent Arrived @@ -2395,83 +2475,47 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer #region Object Transfers - /// - /// Move the given scene object into a new region depending on which region its absolute position has moved - /// into. - /// - /// Using the objects new world location, ask the grid service for a the new region and adjust the prim - /// position to be relative to the new region. - /// - /// the scene object that we're crossing - /// the attempted out of region position of the scene object. This position is - /// relative to the region the object currently is in. - /// if 'true', the deletion of the client from the region is not broadcast to the clients - public void Cross(SceneObjectGroup grp, Vector3 attemptedPosition, bool silent) + public GridRegion GetObjectDestination(SceneObjectGroup grp, Vector3 targetPosition,out Vector3 newpos) { - if (grp == null) - return; - if (grp.IsDeleted) - return; + newpos = targetPosition; Scene scene = grp.Scene; if (scene == null) - return; - - if (grp.RootPart.DIE_AT_EDGE) - { - // We remove the object here - try - { - scene.DeleteSceneObject(grp, false); - } - catch (Exception) - { - m_log.Warn("[DATABASE]: exception when trying to remove the prim that crossed the border."); - } - return; - } - - // Remember the old group position in case the region lookup fails so position can be restored. - Vector3 oldGroupPosition = grp.RootPart.GroupPosition; + return null; - // Compute the absolute position of the object. - double objectWorldLocX = (double)scene.RegionInfo.WorldLocX + attemptedPosition.X; - double objectWorldLocY = (double)scene.RegionInfo.WorldLocY + attemptedPosition.Y; + int x = (int)targetPosition.X + (int)scene.RegionInfo.WorldLocX; + if (targetPosition.X >= 0) + x++; + else + x--; - // Ask the grid service for the region that contains the passed address - GridRegion destination = GetRegionContainingWorldLocation(scene.GridService, scene.RegionInfo.ScopeID, - objectWorldLocX, objectWorldLocY); + int y = (int)targetPosition.Y + (int)scene.RegionInfo.WorldLocY; + if (targetPosition.Y >= 0) + y++; + else + y--; - Vector3 pos = Vector3.Zero; - if (destination != null) + GridRegion neighbourRegion = scene.GridService.GetRegionByPosition(scene.RegionInfo.ScopeID,x,y); + if (neighbourRegion == null) { - // Adjust the object's relative position from the old region (attemptedPosition) - // to be relative to the new region (pos). - pos = new Vector3( (float)(objectWorldLocX - (double)destination.RegionLocX), - (float)(objectWorldLocY - (double)destination.RegionLocY), - attemptedPosition.Z); + return null; } - if (destination == null || !CrossPrimGroupIntoNewRegion(destination, pos, grp, silent)) - { - m_log.InfoFormat("[ENTITY TRANSFER MODULE] cross region transfer failed for object {0}", grp.UUID); - - // We are going to move the object back to the old position so long as the old position - // is in the region - oldGroupPosition.X = Util.Clamp(oldGroupPosition.X, 1.0f, (float)(scene.RegionInfo.RegionSizeX - 1)); - oldGroupPosition.Y = Util.Clamp(oldGroupPosition.Y, 1.0f, (float)(scene.RegionInfo.RegionSizeY - 1)); - oldGroupPosition.Z = Util.Clamp(oldGroupPosition.Z, 1.0f, Constants.RegionHeight); + float newRegionSizeX = neighbourRegion.RegionSizeX; + float newRegionSizeY = neighbourRegion.RegionSizeY; + if (newRegionSizeX == 0) + newRegionSizeX = Constants.RegionSize; + if (newRegionSizeY == 0) + newRegionSizeY = Constants.RegionSize; - grp.AbsolutePosition = oldGroupPosition; - grp.Velocity = Vector3.Zero; - if (grp.RootPart.PhysActor != null) - grp.RootPart.PhysActor.CrossingFailure(); + newpos.X = targetPosition.X - (neighbourRegion.RegionLocX - (int)scene.RegionInfo.WorldLocX); + newpos.Y = targetPosition.Y - (neighbourRegion.RegionLocY - (int)scene.RegionInfo.WorldLocY); - if (grp.RootPart.KeyframeMotion != null) - grp.RootPart.KeyframeMotion.CrossingFailure(); + const float enterDistance = 0.2f; + newpos.X = Util.Clamp(newpos.X, enterDistance, newRegionSizeX - enterDistance); + newpos.Y = Util.Clamp(newpos.Y, enterDistance, newRegionSizeY - enterDistance); - grp.ScheduleGroupForFullUpdate(); - } + return neighbourRegion; } /// @@ -2483,10 +2527,12 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer /// true if the crossing itself was successful, false on failure /// FIMXE: we still return true if the crossing object was not successfully deleted from the originating region /// - protected bool CrossPrimGroupIntoNewRegion(GridRegion destination, Vector3 newPosition, SceneObjectGroup grp, bool silent) + public bool CrossPrimGroupIntoNewRegion(GridRegion destination, Vector3 newPosition, SceneObjectGroup grp, bool silent, bool removeScripts) { //m_log.Debug(" >>> CrossPrimGroupIntoNewRegion <<<"); + Culture.SetCurrentCulture(); + bool successYN = false; grp.RootPart.ClearUpdateSchedule(); //int primcrossingXMLmethod = 0; @@ -2515,7 +2561,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer // We remove the object here try { - grp.Scene.DeleteSceneObject(grp, silent); + grp.Scene.DeleteSceneObject(grp, silent, removeScripts); } catch (Exception e) { @@ -2524,30 +2570,6 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer grp, e); } } -/* - * done on caller ( not in attachments crossing for now) - else - { - - if (!grp.IsDeleted) - { - PhysicsActor pa = grp.RootPart.PhysActor; - if (pa != null) - { - pa.CrossingFailure(); - if (grp.RootPart.KeyframeMotion != null) - { - // moved to KeyframeMotion.CrossingFailure -// grp.RootPart.Velocity = Vector3.Zero; - grp.RootPart.KeyframeMotion.CrossingFailure(); -// grp.SendGroupRootTerseUpdate(); - } - } - } - - m_log.ErrorFormat("[ENTITY TRANSFER MODULE]: Prim crossing failed for {0}", grp); - } - */ } else { @@ -2589,7 +2611,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer "[ENTITY TRANSFER MODULE]: Sending attachment {0} to region {1}", clone.UUID, destination.RegionName); - CrossPrimGroupIntoNewRegion(destination, Vector3.Zero, clone, silent); + CrossPrimGroupIntoNewRegion(destination, Vector3.Zero, clone, silent,true); } } @@ -2639,7 +2661,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer if (Scene.RegionInfo.EstateSettings.IsBanned(so.OwnerID)) { m_log.DebugFormat( - "[ENTITY TRANSFER MODULE]: Denied prim crossing of {0} {1} into {2} for banned avatar {3}", + "[ENTITY TRANSFER MODULE]: Denied prim crossing of {0} {1} into {2} for banned avatar {3}", so.Name, so.UUID, Scene.Name, so.OwnerID); return false; @@ -2651,7 +2673,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer if (!Scene.AddSceneObject(so)) { m_log.DebugFormat( - "[ENTITY TRANSFER MODULE]: Problem adding scene object {0} {1} into {2} ", + "[ENTITY TRANSFER MODULE]: Problem adding scene object {0} {1} into {2} ", so.Name, so.UUID, Scene.Name); return false; @@ -2661,7 +2683,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer { // FIXME: It would be better to never add the scene object at all rather than add it and then delete // it - if (!Scene.Permissions.CanObjectEntry(so.UUID, true, so.AbsolutePosition)) + if (!Scene.Permissions.CanObjectEntry(so, true, so.AbsolutePosition)) { // Deny non attachments based on parcel settings // @@ -2679,8 +2701,9 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer so.ResumeScripts(); - if (so.RootPart.KeyframeMotion != null) - so.RootPart.KeyframeMotion.UpdateSceneObject(so); + // AddSceneObject already does this and doing it again messes + //if (so.RootPart.KeyframeMotion != null) + // so.RootPart.KeyframeMotion.UpdateSceneObject(so); } return true; diff --git a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferStateMachine.cs b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferStateMachine.cs index a3109e0..0a24555 100644 --- a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferStateMachine.cs +++ b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferStateMachine.cs @@ -101,7 +101,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer /// true if the agent was not already in transit, false if it was internal bool SetInTransit(UUID id) { - m_log.DebugFormat("{0} SetInTransit. agent={1}, newState=Preparing", LogHeader, id); +// m_log.DebugFormat("{0} SetInTransit. agent={1}, newState=Preparing", LogHeader, id); lock (m_agentsInTransit) { if (!m_agentsInTransit.ContainsKey(id)) @@ -123,7 +123,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer /// Illegal transitions will throw an Exception internal bool UpdateInTransit(UUID id, AgentTransferState newState) { - m_log.DebugFormat("{0} UpdateInTransit. agent={1}, newState={2}", LogHeader, id, newState); + // m_log.DebugFormat("{0} UpdateInTransit. agent={1}, newState={2}", LogHeader, id, newState); bool transitionOkay = false; @@ -169,7 +169,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer } else { - if (newState == AgentTransferState.Cancelling + if (newState == AgentTransferState.Cancelling && (oldState == AgentTransferState.Preparing || oldState == AgentTransferState.Transferring)) { transitionOkay = true; @@ -181,7 +181,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer } if (!transitionOkay) - failureMessage + failureMessage = string.Format( "Agent with ID {0} is not allowed to move from old transit state {1} to new state {2} in {3}", id, oldState, newState, m_mod.Scene.RegionInfo.RegionName); @@ -192,7 +192,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer m_agentsInTransit[id] = newState; // m_log.DebugFormat( -// "[ENTITY TRANSFER STATE MACHINE]: Changed agent with id {0} from state {1} to {2} in {3}", +// "[ENTITY TRANSFER STATE MACHINE]: Changed agent with id {0} from state {1} to {2} in {3}", // id, oldState, newState, m_mod.Scene.Name); } else if (failIfNotOkay) @@ -204,11 +204,11 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer // { // if (oldState != null) // m_log.DebugFormat( -// "[ENTITY TRANSFER STATE MACHINE]: Ignored change of agent with id {0} from state {1} to {2} in {3}", +// "[ENTITY TRANSFER STATE MACHINE]: Ignored change of agent with id {0} from state {1} to {2} in {3}", // id, oldState, newState, m_mod.Scene.Name); // else // m_log.DebugFormat( -// "[ENTITY TRANSFER STATE MACHINE]: Ignored change of agent with id {0} to state {1} in {2} since agent not in transit", +// "[ENTITY TRANSFER STATE MACHINE]: Ignored change of agent with id {0} to state {1} in {2} since agent not in transit", // id, newState, m_mod.Scene.Name); // } } @@ -247,32 +247,32 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer { AgentTransferState state = m_agentsInTransit[id]; - if (state == AgentTransferState.Transferring || state == AgentTransferState.ReceivedAtDestination) - { +// if (state == AgentTransferState.Transferring || state == AgentTransferState.ReceivedAtDestination) +// { // FIXME: For now, we allow exit from any state since a thrown exception in teleport is now guranteed // to be handled properly - ResetFromTransit() could be invoked at any step along the process - m_log.WarnFormat( - "[ENTITY TRANSFER STATE MACHINE]: Agent with ID {0} should not exit directly from state {1}, should go to {2} state first in {3}", - id, state, AgentTransferState.CleaningUp, m_mod.Scene.RegionInfo.RegionName); +// m_log.WarnFormat( +// "[ENTITY TRANSFER STATE MACHINE]: Agent with ID {0} should not exit directly from state {1}, should go to {2} state first in {3}", +// id, state, AgentTransferState.CleaningUp, m_mod.Scene.RegionInfo.RegionName); // throw new Exception( // "Agent with ID {0} cannot exit directly from state {1}, it must go to {2} state first", // state, AgentTransferState.CleaningUp); - } +// } m_agentsInTransit.Remove(id); - m_log.DebugFormat( - "[ENTITY TRANSFER STATE MACHINE]: Agent {0} cleared from transit in {1}", - id, m_mod.Scene.RegionInfo.RegionName); +// m_log.DebugFormat( +// "[ENTITY TRANSFER STATE MACHINE]: Agent {0} cleared from transit in {1}", +// id, m_mod.Scene.RegionInfo.RegionName); return true; } } - m_log.WarnFormat( - "[ENTITY TRANSFER STATE MACHINE]: Agent {0} requested to clear from transit in {1} but was already cleared", - id, m_mod.Scene.RegionInfo.RegionName); +// m_log.WarnFormat( +// "[ENTITY TRANSFER STATE MACHINE]: Agent {0} requested to clear from transit in {1} but was already cleared", +// id, m_mod.Scene.RegionInfo.RegionName); return false; } @@ -281,7 +281,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer { if (!m_mod.WaitForAgentArrivedAtDestination) return true; - + lock (m_agentsInTransit) { AgentTransferState? currentState = GetAgentTransferState(id); @@ -299,7 +299,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer id, m_mod.Scene.RegionInfo.RegionName, currentState)); } - int count = 200; + int count = 400; // There should be no race condition here since no other code should be removing the agent transfer or // changing the state to another other than Transferring => ReceivedAtDestination. @@ -354,4 +354,4 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer } } } -} \ No newline at end of file +} diff --git a/OpenSim/Region/CoreModules/Framework/EntityTransfer/HGEntityTransferModule.cs b/OpenSim/Region/CoreModules/Framework/EntityTransfer/HGEntityTransferModule.cs index fa23590..56c654f 100644 --- a/OpenSim/Region/CoreModules/Framework/EntityTransfer/HGEntityTransferModule.cs +++ b/OpenSim/Region/CoreModules/Framework/EntityTransfer/HGEntityTransferModule.cs @@ -95,8 +95,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer foreach (AvatarAttachment att in a.GetAttachments()) { - InventoryItemBase item = new InventoryItemBase(att.ItemID, account.PrincipalID); - item = Scene.InventoryService.GetItem(item); + InventoryItemBase item = Scene.InventoryService.GetItem(account.PrincipalID, att.ItemID); if (item != null) a.SetAttachment(att.AttachPoint, att.ItemID, item.AssetID); else @@ -161,10 +160,10 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer scene.RegisterModuleInterface(this); //scene.EventManager.OnIncomingSceneObject += OnIncomingSceneObject; - m_incomingSceneObjectEngine + m_incomingSceneObjectEngine = new JobEngine( - string.Format("HG Incoming Scene Object Engine ({0})", scene.Name), - "HG INCOMING SCENE OBJECT ENGINE"); + string.Format("HG Incoming Scene Object Engine ({0})", scene.Name), + "HG INCOMING SCENE OBJECT ENGINE", 30000); StatsManager.RegisterStat( new Stat( @@ -239,13 +238,13 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer return region; } - protected override bool NeedsClosing(float drawdist, uint oldRegionX, uint newRegionX, uint oldRegionY, uint newRegionY, GridRegion reg) + protected override bool NeedsClosing(GridRegion reg, bool OutViewRange) { - if (base.NeedsClosing(drawdist, oldRegionX, newRegionX, oldRegionY, newRegionY, reg)) + if (OutViewRange) return true; int flags = Scene.GridService.GetRegionFlags(Scene.RegionInfo.ScopeID, reg.RegionID); - if (flags == -1 /* no region in DB */ || (flags & (int)OpenSim.Framework.RegionFlags.Hyperlink) != 0) + if (flags == -1 || (flags & (int)OpenSim.Framework.RegionFlags.Hyperlink) != 0) return true; return false; @@ -263,7 +262,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer } } - protected override bool CreateAgent(ScenePresence sp, GridRegion reg, GridRegion finalDestination, AgentCircuitData agentCircuit, uint teleportFlags, out string reason, out bool logout) + protected override bool CreateAgent(ScenePresence sp, GridRegion reg, GridRegion finalDestination, AgentCircuitData agentCircuit, uint teleportFlags, EntityTransferContext ctx, out string reason, out bool logout) { m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: CreateAgent {0} {1}", reg.ServerURI, finalDestination.ServerURI); reason = string.Empty; @@ -273,7 +272,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer { // this user is going to another grid // for local users, check if HyperGrid teleport is allowed, based on user level - if (Scene.UserManagementModule.IsLocalGridUser(sp.UUID) && sp.UserLevel < m_levelHGTeleport) + if (Scene.UserManagementModule.IsLocalGridUser(sp.UUID) && sp.GodController.UserLevel < m_levelHGTeleport) { m_log.WarnFormat("[HG ENTITY TRANSFER MODULE]: Unable to HG teleport agent due to insufficient UserLevel."); reason = "Hypergrid teleport not allowed"; @@ -292,7 +291,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer GridRegion source = new GridRegion(Scene.RegionInfo); source.RawServerURI = m_GatekeeperURI; - + bool success = connector.LoginAgentToGrid(source, agentCircuit, reg, finalDestination, false, out reason); logout = success; // flag for later logout from this grid; this is an HG TP @@ -308,7 +307,12 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer } } - return base.CreateAgent(sp, reg, finalDestination, agentCircuit, teleportFlags, out reason, out logout); + return base.CreateAgent(sp, reg, finalDestination, agentCircuit, teleportFlags, ctx, out reason, out logout); + } + + public override void TriggerTeleportHome(UUID id, IClientAPI client) + { + TeleportHome(id, client); } protected override bool ValidateGenericConditions(ScenePresence sp, GridRegion reg, GridRegion finalDestination, uint teleportFlags, out string reason) @@ -328,7 +332,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: RestrictAppearanceAbroad is ON. Checking generic appearance"); // Check wearables - for (int i = 0; i < AvatarWearable.MAX_WEARABLES; i++) + for (int i = 0; i < sp.Appearance.Wearables.Length ; i++) { for (int j = 0; j < sp.Appearance.Wearables[i].Count; j++) { @@ -337,13 +341,13 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer bool found = false; foreach (AvatarAppearance a in ExportedAppearance) - if (a.Wearables[i] != null) + if (i < a.Wearables.Length && a.Wearables[i] != null) { found = true; break; } - if (!found) + if (!found) { m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: Wearable not allowed to go outside {0}", i); return false; @@ -351,7 +355,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer found = false; foreach (AvatarAppearance a in ExportedAppearance) - if (sp.Appearance.Wearables[i][j].AssetID == a.Wearables[i][j].AssetID) + if (i < a.Wearables.Length && sp.Appearance.Wearables[i][j].AssetID == a.Wearables[i][j].AssetID) { found = true; break; @@ -412,7 +416,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer // // Rez needed npc attachments // Scene.AttachmentsModule.RezAttachments(sp); - + // IAvatarFactoryModule module = Scene.RequestModuleInterface(); // //module.SendAppearance(sp.UUID); // module.RequestRebake(sp, false); @@ -429,11 +433,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer // return base.UpdateAgent(reg, finalDestination, agentData, sp); //} - public override void TriggerTeleportHome(UUID id, IClientAPI client) - { - TeleportHome(id, client); - } - + public override bool TeleportHome(UUID id, IClientAPI client) { m_log.DebugFormat( @@ -449,7 +449,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer } // Foreign user wants to go home - // + // AgentCircuitData aCircuit = ((Scene)(client.Scene)).AuthenticateHandler.GetAgentCircuitData(client.CircuitCode); if (aCircuit == null || (aCircuit != null && !aCircuit.ServiceURLs.ContainsKey("HomeURI"))) { @@ -470,7 +470,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer { m_log.Debug("[HG ENTITY TRANSFER MODULE]: GetHomeRegion call failed ", e); } - + if (finalDestination == null) { client.SendTeleportFailed("Your home region could not be found"); @@ -487,13 +487,11 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer } GridRegion homeGatekeeper = MakeRegion(aCircuit); - + m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: teleporting user {0} {1} home to {2} via {3}:{4}", aCircuit.firstname, aCircuit.lastname, finalDestination.RegionName, homeGatekeeper.ServerURI, homeGatekeeper.RegionName); - DoTeleport( - sp, homeGatekeeper, finalDestination, - position, lookAt, (uint)(Constants.TeleportFlags.SetLastToTarget | Constants.TeleportFlags.ViaHome)); + DoTeleport(sp, homeGatekeeper, finalDestination, position, lookAt, (uint)(Constants.TeleportFlags.SetLastToTarget | Constants.TeleportFlags.ViaHome)); return true; } @@ -505,7 +503,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer /// public override void RequestTeleportLandmark(IClientAPI remoteClient, AssetLandmark lm) { - m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: Teleporting agent via landmark to {0} region {1} position {2}", + m_log.DebugFormat("[HG ENTITY TRANSFER MODULE]: Teleporting agent via landmark to {0} region {1} position {2}", (lm.Gatekeeper == string.Empty) ? "local" : lm.Gatekeeper, lm.RegionID, lm.Position); if (lm.Gatekeeper == string.Empty) @@ -523,7 +521,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer remoteClient, info.RegionHandle, lm.Position, Vector3.Zero, (uint)(Constants.TeleportFlags.SetLastToTarget | Constants.TeleportFlags.ViaLandmark)); } - else + else { // Foreign region GatekeeperServiceConnector gConn = new GatekeeperServiceConnector(); @@ -583,7 +581,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer jobsRemoved, commonIdToRemove, jobsToReinsert.Count); if (jobsToReinsert.Count > 0) - { + { foreach (JobEngine.Job jobToReinsert in jobsToReinsert) m_incomingSceneObjectEngine.QueueJob(jobToReinsert); } @@ -613,16 +611,16 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer if (aCircuit.ServiceURLs != null && aCircuit.ServiceURLs.ContainsKey("AssetServerURI")) { m_incomingSceneObjectEngine.QueueJob( - string.Format("HG UUID Gather for attachment {0} for {1}", so.Name, aCircuit.Name), - () => + string.Format("HG UUID Gather for attachment {0} for {1}", so.Name, aCircuit.Name), + () => { string url = aCircuit.ServiceURLs["AssetServerURI"].ToString(); // m_log.DebugFormat( - // "[HG ENTITY TRANSFER MODULE]: Incoming attachment {0} for HG user {1} with asset service {2}", + // "[HG ENTITY TRANSFER MODULE]: Incoming attachment {0} for HG user {1} with asset service {2}", // so.Name, so.AttachedAvatar, url); IDictionary ids = new Dictionary(); - HGUuidGatherer uuidGatherer + HGUuidGatherer uuidGatherer = new HGUuidGatherer(Scene.AssetService, url, ids); uuidGatherer.AddForInspection(so); @@ -648,7 +646,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer RemoveIncomingSceneObjectJobs(so.OwnerID.ToString()); return; - } + } } // m_log.DebugFormat( @@ -659,7 +657,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer { int tickStart = Util.EnvironmentTickCount(); - uuidGatherer.FetchAsset(kvp.Key); + uuidGatherer.FetchAsset(kvp.Key); int ticksElapsed = Util.EnvironmentTickCountSubtract(tickStart); @@ -672,15 +670,15 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer RemoveIncomingSceneObjectJobs(so.OwnerID.ToString()); return; - } + } } base.HandleIncomingSceneObject(so, newPosition); // m_log.DebugFormat( - // "[HG ENTITY TRANSFER MODULE]: Completed incoming attachment {0} for HG user {1} with asset server {2}", + // "[HG ENTITY TRANSFER MODULE]: Completed incoming attachment {0} for HG user {1} with asset server {2}", // so.Name, so.OwnerID, url); - }, + }, so.OwnerID.ToString()); } } @@ -700,7 +698,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer string url = aCircuit.ServiceURLs["HomeURI"].ToString(); IUserAgentService security = new UserAgentServiceConnector(url); return security.VerifyClient(aCircuit.SessionID, token); - } + } else { m_log.DebugFormat( @@ -748,7 +746,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer GridRegion region = new GridRegion(); Uri uri = null; - if (!aCircuit.ServiceURLs.ContainsKey("HomeURI") || + if (!aCircuit.ServiceURLs.ContainsKey("HomeURI") || (aCircuit.ServiceURLs.ContainsKey("HomeURI") && !Uri.TryCreate(aCircuit.ServiceURLs["HomeURI"].ToString(), UriKind.Absolute, out uri))) return null; @@ -760,4 +758,4 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer return region; } } -} \ No newline at end of file +} diff --git a/OpenSim/Region/CoreModules/Framework/InterfaceCommander/Commander.cs b/OpenSim/Region/CoreModules/Framework/InterfaceCommander/Commander.cs index b5a4005..63dbb19 100644 --- a/OpenSim/Region/CoreModules/Framework/InterfaceCommander/Commander.cs +++ b/OpenSim/Region/CoreModules/Framework/InterfaceCommander/Commander.cs @@ -41,34 +41,34 @@ namespace OpenSim.Region.CoreModules.Framework.InterfaceCommander public class Commander : ICommander { private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); - + /// /// Used in runtime class generation /// private string m_generatedApiClassName; - + public string Name { get { return m_name; } } private string m_name; - + public string Help { get { StringBuilder sb = new StringBuilder(); - + sb.AppendLine("=== " + m_name + " ==="); - + foreach (ICommand com in m_commands.Values) { sb.AppendLine("* " + Name + " " + com.Name + " - " + com.Help); } - + return sb.ToString(); } - } + } /// /// Constructor @@ -78,7 +78,7 @@ namespace OpenSim.Region.CoreModules.Framework.InterfaceCommander { m_name = name; m_generatedApiClassName = m_name[0].ToString().ToUpper(); - + if (m_name.Length > 1) m_generatedApiClassName += m_name.Substring(1); } @@ -87,7 +87,7 @@ namespace OpenSim.Region.CoreModules.Framework.InterfaceCommander { get { return m_commands; } } - private Dictionary m_commands = new Dictionary(); + private Dictionary m_commands = new Dictionary(); #region ICommander Members @@ -162,7 +162,7 @@ namespace OpenSim.Region.CoreModules.Framework.InterfaceCommander { if (function != "help") Console.WriteLine("ERROR: Invalid command - No such command exists"); - + Console.Write(Help); } } diff --git a/OpenSim/Region/CoreModules/Framework/InventoryAccess/HGAssetMapper.cs b/OpenSim/Region/CoreModules/Framework/InventoryAccess/HGAssetMapper.cs index f54298c..51ae217 100644 --- a/OpenSim/Region/CoreModules/Framework/InventoryAccess/HGAssetMapper.cs +++ b/OpenSim/Region/CoreModules/Framework/InventoryAccess/HGAssetMapper.cs @@ -178,7 +178,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess { UUID uuid = UUID.Zero; UUID.TryParse(meta.CreatorID, out uuid); - UserAccount creator = m_scene.UserAccountService.GetUserAccount(m_scene.RegionInfo.ScopeID, uuid); + UserAccount creator = m_scene.UserAccountService.GetUserAccount(m_scene.RegionInfo.ScopeID, uuid); if (creator != null) meta.CreatorID = m_HomeURI + ";" + creator.FirstName + " " + creator.LastName; } @@ -300,8 +300,8 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess { m_log.Error( string.Format( - "[HG ASSET MAPPER]: Failed to post asset {0} (type {1}, length {2}) referenced from {3} to {4} with exception ", - asset.ID, asset.Type, asset.Data.Length, assetID, userAssetURL), + "[HG ASSET MAPPER]: Failed to post asset {0} (type {1}, length {2}) referenced from {3} to {4} with exception ", + asset.ID, asset.Type, asset.Data.Length, assetID, userAssetURL), e); // For debugging purposes for now we will continue to throw the exception up the stack as was already happening. However, after @@ -315,7 +315,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess else { m_log.DebugFormat( - "[HG ASSET MAPPER]: Didn't post asset {0} referenced from {1} because it already exists in asset server {2}", + "[HG ASSET MAPPER]: Didn't post asset {0} referenced from {1} because it already exists in asset server {2}", uuid, assetID, userAssetURL); } } diff --git a/OpenSim/Region/CoreModules/Framework/InventoryAccess/HGInventoryAccessModule.cs b/OpenSim/Region/CoreModules/Framework/InventoryAccess/HGInventoryAccessModule.cs index 582b267..ba3a7c9 100644 --- a/OpenSim/Region/CoreModules/Framework/InventoryAccess/HGInventoryAccessModule.cs +++ b/OpenSim/Region/CoreModules/Framework/InventoryAccess/HGInventoryAccessModule.cs @@ -91,9 +91,9 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess if (name == Name) { m_Enabled = true; - + InitialiseCommon(source); - + m_log.InfoFormat("[HG INVENTORY ACCESS MODULE]: {0} enabled.", Name); IConfig thisModuleConfig = source.Configs["HGInventoryAccessModule"]; @@ -117,7 +117,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess m_log.Warn("[HG INVENTORY ACCESS MODULE]: HGInventoryAccessModule configs not found. ProfileServerURI not set!"); m_bypassPermissions = !Util.GetConfigVarFromSections(source, "serverside_object_permissions", - new string[] { "Startup", "Permissions" }, true); + new string[] { "Startup", "Permissions" }, true); } } @@ -209,7 +209,14 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess } } - public void PostInventoryAsset(UUID avatarID, AssetType type, UUID assetID, string name, int userlevel) + private void PostInventoryAsset(InventoryItemBase item, int userlevel) + { + InventoryFolderBase f = m_Scene.InventoryService.GetFolderForType(item.Owner, FolderType.Trash); + if (f == null || (f != null && item.Folder != f.ID)) + PostInventoryAsset(item.Owner, (AssetType)item.AssetType, item.AssetID, item.Name, userlevel); + } + + private void PostInventoryAsset(UUID avatarID, AssetType type, UUID assetID, string name, int userlevel) { if (type == AssetType.Link) return; @@ -241,26 +248,34 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess } - /// + /// /// CapsUpdateInventoryItemAsset /// public override UUID CapsUpdateInventoryItemAsset(IClientAPI remoteClient, UUID itemID, byte[] data) { UUID newAssetID = base.CapsUpdateInventoryItemAsset(remoteClient, itemID, data); - PostInventoryAsset(remoteClient.AgentId, AssetType.Unknown, newAssetID, "", 0); + // We need to construct this here to satisfy the calling convention. + // Better this in two places than five formal params in all others. + InventoryItemBase item = new InventoryItemBase(); + item.Owner = remoteClient.AgentId; + item.AssetType = (int)AssetType.Unknown; + item.AssetID = newAssetID; + item.Name = String.Empty; + + PostInventoryAsset(item, 0); return newAssetID; } - /// + /// /// UpdateInventoryItemAsset /// public override bool UpdateInventoryItemAsset(UUID ownerID, InventoryItemBase item, AssetBase asset) { if (base.UpdateInventoryItemAsset(ownerID, item, asset)) { - PostInventoryAsset(ownerID, (AssetType)asset.Type, asset.FullID, asset.Name, 0); + PostInventoryAsset(item, 0); return true; } @@ -273,25 +288,45 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess protected override void ExportAsset(UUID agentID, UUID assetID) { if (!assetID.Equals(UUID.Zero)) - PostInventoryAsset(agentID, AssetType.Unknown, assetID, "", 0); + { + InventoryItemBase item = new InventoryItemBase(); + item.Owner = agentID; + item.AssetType = (int)AssetType.Unknown; + item.AssetID = assetID; + item.Name = String.Empty; + + PostInventoryAsset(item, 0); + } else + { m_log.Debug("[HGScene]: Scene.Inventory did not create asset"); + } } /// /// RezObject /// - public override SceneObjectGroup RezObject(IClientAPI remoteClient, UUID itemID, Vector3 RayEnd, Vector3 RayStart, - UUID RayTargetID, byte BypassRayCast, bool RayEndIsIntersection, - bool RezSelected, bool RemoveItem, UUID fromTaskID, bool attachment) + // compatibility do not use + public override SceneObjectGroup RezObject( + IClientAPI remoteClient, UUID itemID, Vector3 RayEnd, Vector3 RayStart, + UUID RayTargetID, byte BypassRayCast, bool RayEndIsIntersection, + bool RezSelected, bool RemoveItem, UUID fromTaskID, bool attachment) + { + return RezObject(remoteClient, itemID, UUID.Zero, RayEnd, RayStart, + RayTargetID, BypassRayCast, RayEndIsIntersection, + RezSelected, RemoveItem, fromTaskID, attachment); + } + + public override SceneObjectGroup RezObject(IClientAPI remoteClient, UUID itemID, + UUID groupID, Vector3 RayEnd, Vector3 RayStart, + UUID RayTargetID, byte BypassRayCast, bool RayEndIsIntersection, + bool RezSelected, bool RemoveItem, UUID fromTaskID, bool attachment) { - m_log.DebugFormat("[HGScene]: RezObject itemID={0} fromTaskID={1}", itemID, fromTaskID); + //m_log.DebugFormat("[HGScene]: RezObject itemID={0} fromTaskID={1}", itemID, fromTaskID); //if (fromTaskID.Equals(UUID.Zero)) //{ - InventoryItemBase item = new InventoryItemBase(itemID); - item.Owner = remoteClient.AgentId; - item = m_Scene.InventoryService.GetItem(item); + InventoryItemBase item = m_Scene.InventoryService.GetItem(remoteClient.AgentId, itemID); //if (item == null) //{ // Fetch the item // item = new InventoryItemBase(); @@ -308,7 +343,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess //} // OK, we're done fetching. Pass it up to the default RezObject - SceneObjectGroup sog = base.RezObject(remoteClient, itemID, RayEnd, RayStart, RayTargetID, BypassRayCast, RayEndIsIntersection, + SceneObjectGroup sog = base.RezObject(remoteClient, itemID, groupID, RayEnd, RayStart, RayTargetID, BypassRayCast, RayEndIsIntersection, RezSelected, RemoveItem, fromTaskID, attachment); return sog; @@ -351,7 +386,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess if (!m_CheckSeparateAssets) { if (!UserManagementModule.IsLocalGridUser(userID)) - { // foreign + { // foreign ScenePresence sp = null; if (m_Scene.TryGetScenePresence(userID, out sp)) { @@ -489,7 +524,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess foreach (InventoryItemBase it in content.Items) it.Name = it.Name + " (Unavailable)"; ; - // Send the new names + // Send the new names inv.SendBulkUpdateInventory(keep.ToArray(), content.Items.ToArray()); } @@ -506,16 +541,17 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess #region Permissions - private bool CanTakeObject(UUID objectID, UUID stealer, Scene scene) + private bool CanTakeObject(SceneObjectGroup sog, ScenePresence sp) { if (m_bypassPermissions) return true; - if (!m_OutboundPermission && !UserManagementModule.IsLocalGridUser(stealer)) + if(sp == null || sog == null) + return false; + + if (!m_OutboundPermission && !UserManagementModule.IsLocalGridUser(sp.UUID)) { - SceneObjectGroup sog = null; - if (m_Scene.TryGetSceneObjectGroup(objectID, out sog) && sog.OwnerID == stealer) + if (sog.OwnerID == sp.UUID) return true; - return false; } @@ -535,4 +571,4 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess #endregion } -} \ No newline at end of file +} diff --git a/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs b/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs index 5a9efb8..788ed1c 100644 --- a/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs +++ b/OpenSim/Region/CoreModules/Framework/InventoryAccess/InventoryAccessModule.cs @@ -68,7 +68,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess return m_UserManagement; } } - + public bool CoalesceMultipleObjectsToInventory { get; set; } #region INonSharedRegionModule @@ -92,14 +92,14 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess if (name == Name) { m_Enabled = true; - + InitialiseCommon(source); - - m_log.InfoFormat("[INVENTORY ACCESS MODULE]: {0} enabled.", Name); + + m_log.InfoFormat("[INVENTORY ACCESS MODULE]: {0} enabled.", Name); } } } - + /// /// Common module config for both this and descendant classes. /// @@ -107,9 +107,9 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess protected virtual void InitialiseCommon(IConfigSource source) { IConfig inventoryConfig = source.Configs["Inventory"]; - + if (inventoryConfig != null) - CoalesceMultipleObjectsToInventory + CoalesceMultipleObjectsToInventory = inventoryConfig.GetBoolean("CoalesceMultipleObjectsToInventory", true); else CoalesceMultipleObjectsToInventory = true; @@ -175,53 +175,73 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess /// public void CreateNewInventoryItem(IClientAPI remoteClient, UUID transactionID, UUID folderID, uint callbackID, string description, string name, sbyte invType, - sbyte assetType, - byte wearableType, uint nextOwnerMask, int creationDate) + sbyte assetType, byte wearableType, + uint nextOwnerMask, int creationDate) { - m_log.DebugFormat("[INVENTORY ACCESS MODULE]: Received request to create inventory item {0} in folder {1}", name, folderID); + m_log.DebugFormat("[INVENTORY ACCESS MODULE]: Received request to create inventory item {0} in folder {1}, transactionID {2}", name, + folderID, transactionID); if (!m_Scene.Permissions.CanCreateUserInventory(invType, remoteClient.AgentId)) return; - if (transactionID == UUID.Zero) + InventoryFolderBase folder = m_Scene.InventoryService.GetFolder(remoteClient.AgentId, folderID); + + if (folder == null && Enum.IsDefined(typeof(FolderType), (sbyte)invType)) { - ScenePresence presence; - if (m_Scene.TryGetScenePresence(remoteClient.AgentId, out presence)) - { - byte[] data = null; + folder = m_Scene.InventoryService.GetFolderForType(remoteClient.AgentId, (FolderType)invType); + if (folder != null) + m_log.DebugFormat("[INVENTORY ACCESS MODULE]: Requested folder not found but found folder for type {0}", invType); + } - if (invType == (sbyte)InventoryType.Landmark && presence != null) - { - string suffix = string.Empty, prefix = string.Empty; - string strdata = GenerateLandmark(presence, out prefix, out suffix); - data = Encoding.ASCII.GetBytes(strdata); - name = prefix + name; - description += suffix; - } + if (folder == null || folder.Owner != remoteClient.AgentId) + return; - AssetBase asset = m_Scene.CreateAsset(name, description, assetType, data, remoteClient.AgentId); - m_Scene.AssetService.Store(asset); - m_Scene.CreateNewInventoryItem( - remoteClient, remoteClient.AgentId.ToString(), string.Empty, folderID, - name, description, 0, callbackID, asset.FullID, asset.Type, invType, nextOwnerMask, creationDate); - } - else - { - m_log.ErrorFormat( - "[INVENTORY ACCESS MODULE]: ScenePresence for agent uuid {0} unexpectedly not found in CreateNewInventoryItem", - remoteClient.AgentId); - } - } - else + if (transactionID != UUID.Zero) { IAgentAssetTransactions agentTransactions = m_Scene.AgentTransactionsModule; if (agentTransactions != null) { - agentTransactions.HandleItemCreationFromTransaction( + if (agentTransactions.HandleItemCreationFromTransaction( remoteClient, transactionID, folderID, callbackID, description, - name, invType, assetType, wearableType, nextOwnerMask); + name, invType, assetType, wearableType, nextOwnerMask)) + return; } } + + ScenePresence presence; + if (m_Scene.TryGetScenePresence(remoteClient.AgentId, out presence)) + { + byte[] data = null; + uint everyonemask = 0; + uint groupmask = 0; + + if (invType == (sbyte)InventoryType.Landmark && presence != null) + { + string suffix = string.Empty, prefix = string.Empty; + string strdata = GenerateLandmark(presence, out prefix, out suffix); + data = Encoding.ASCII.GetBytes(strdata); + name = prefix + name; + description += suffix; + groupmask = (uint)PermissionMask.AllAndExport; + everyonemask = (uint)(PermissionMask.AllAndExport & ~PermissionMask.Modify); + } + + AssetBase asset = m_Scene.CreateAsset(name, description, assetType, data, remoteClient.AgentId); + m_Scene.AssetService.Store(asset); + m_Scene.CreateNewInventoryItem( + remoteClient, remoteClient.AgentId.ToString(), string.Empty, folderID, + name, description, 0, callbackID, asset.FullID, asset.Type, invType, + (uint)PermissionMask.AllAndExport, // Base + (uint)PermissionMask.AllAndExport, // Current + everyonemask, + nextOwnerMask, groupmask, creationDate, false); // Data from viewer + } + else + { + m_log.ErrorFormat( + "[INVENTORY ACCESS MODULE]: ScenePresence for agent uuid {0} unexpectedly not found in CreateNewInventoryItem", + remoteClient.AgentId); + } } protected virtual string GenerateLandmark(ScenePresence presence, out string prefix, out string suffix) @@ -244,53 +264,65 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess /// public virtual UUID CapsUpdateInventoryItemAsset(IClientAPI remoteClient, UUID itemID, byte[] data) { - InventoryItemBase item = new InventoryItemBase(itemID, remoteClient.AgentId); - item = m_Scene.InventoryService.GetItem(item); + InventoryItemBase item = m_Scene.InventoryService.GetItem(remoteClient.AgentId, itemID); + + if (item == null) + { + m_log.ErrorFormat( + "[INVENTORY ACCESS MODULE]: Could not find item {0} for caps inventory update", itemID); + return UUID.Zero; + } if (item.Owner != remoteClient.AgentId) return UUID.Zero; - if (item != null) + if ((InventoryType)item.InvType == InventoryType.Notecard) { - if ((InventoryType)item.InvType == InventoryType.Notecard) + if (!m_Scene.Permissions.CanEditNotecard(itemID, UUID.Zero, remoteClient.AgentId)) { - if (!m_Scene.Permissions.CanEditNotecard(itemID, UUID.Zero, remoteClient.AgentId)) - { - remoteClient.SendAgentAlertMessage("Insufficient permissions to edit notecard", false); - return UUID.Zero; - } - - remoteClient.SendAlertMessage("Notecard saved"); + remoteClient.SendAgentAlertMessage("Insufficient permissions to edit notecard", false); + return UUID.Zero; } - else if ((InventoryType)item.InvType == InventoryType.LSL) - { - if (!m_Scene.Permissions.CanEditScript(itemID, UUID.Zero, remoteClient.AgentId)) - { - remoteClient.SendAgentAlertMessage("Insufficient permissions to edit script", false); - return UUID.Zero; - } - remoteClient.SendAlertMessage("Script saved"); + remoteClient.SendAlertMessage("Notecard saved"); + } + else if ((InventoryType)item.InvType == InventoryType.LSL) + { + if (!m_Scene.Permissions.CanEditScript(itemID, UUID.Zero, remoteClient.AgentId)) + { + remoteClient.SendAgentAlertMessage("Insufficient permissions to edit script", false); + return UUID.Zero; } - AssetBase asset = - CreateAsset(item.Name, item.Description, (sbyte)item.AssetType, data, remoteClient.AgentId.ToString()); - item.AssetID = asset.FullID; - m_Scene.AssetService.Store(asset); - - m_Scene.InventoryService.UpdateItem(item); - - // remoteClient.SendInventoryItemCreateUpdate(item); - return (asset.FullID); + remoteClient.SendAlertMessage("Script saved"); } - else + else if ((CustomInventoryType)item.InvType == CustomInventoryType.AnimationSet) { - m_log.ErrorFormat( - "[INVENTORY ACCESS MODULE]: Could not find item {0} for caps inventory update", - itemID); + AnimationSet animSet = new AnimationSet(data); + uint res = animSet.Validate(x => { + const int required = (int)(PermissionMask.Transfer | PermissionMask.Copy); + int perms = m_Scene.InventoryService.GetAssetPermissions(remoteClient.AgentId, x); + // enforce previus perm rule + if ((perms & required) != required) + return 0; + return (uint) perms; + }); + if(res == 0) + { + remoteClient.SendAgentAlertMessage("Not enought permissions on asset(s) referenced by animation set '{0}', update failed", false); + return UUID.Zero; + } } - return UUID.Zero; + AssetBase asset = + CreateAsset(item.Name, item.Description, (sbyte)item.AssetType, data, remoteClient.AgentId.ToString()); + item.AssetID = asset.FullID; + m_Scene.AssetService.Store(asset); + + m_Scene.InventoryService.UpdateItem(item); + + // remoteClient.SendInventoryItemCreateUpdate(item); + return (asset.FullID); } public virtual bool UpdateInventoryItemAsset(UUID ownerID, InventoryItemBase item, AssetBase asset) @@ -298,7 +330,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess if (item != null && item.Owner == ownerID && asset != null) { // m_log.DebugFormat( -// "[INVENTORY ACCESS MODULE]: Updating item {0} {1} with new asset {2}", +// "[INVENTORY ACCESS MODULE]: Updating item {0} {1} with new asset {2}", // item.Name, item.ID, asset.ID); item.AssetID = asset.FullID; @@ -327,7 +359,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess List copiedItems = new List(); Dictionary> bundlesToCopy = new Dictionary>(); - + if (CoalesceMultipleObjectsToInventory) { // The following code groups the SOG's by owner. No objects @@ -337,7 +369,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess { if (!bundlesToCopy.ContainsKey(g.OwnerID)) bundlesToCopy[g.OwnerID] = new List(); - + bundlesToCopy[g.OwnerID].Add(g); } } @@ -348,7 +380,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess { List bundle = new List(); bundle.Add(g); - bundlesToCopy[g.UUID] = bundle; + bundlesToCopy[g.UUID] = bundle; } } @@ -360,10 +392,10 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess // with distinct destinations as well. foreach (List bundle in bundlesToCopy.Values) copiedItems.Add(CopyBundleToInventory(action, folderID, bundle, remoteClient, asAttachment)); - + return copiedItems; } - + /// /// Copy a bundle of objects to inventory. If there is only one object, then this will create an object /// item. If there are multiple objects then these will be saved as a single coalesced item. @@ -379,33 +411,42 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess DeRezAction action, UUID folderID, List objlist, IClientAPI remoteClient, bool asAttachment) { - CoalescedSceneObjects coa = new CoalescedSceneObjects(UUID.Zero); -// Dictionary originalPositions = new Dictionary(); - - Dictionary group2Keyframe = new Dictionary(); + CoalescedSceneObjects coa = new CoalescedSceneObjects(UUID.Zero); + Dictionary originalPositions = new Dictionary(); + Dictionary originalRotations = new Dictionary(); + // this possible is not needed if keyframes are saved +// Dictionary originalKeyframes = new Dictionary(); foreach (SceneObjectGroup objectGroup in objlist) { if (objectGroup.RootPart.KeyframeMotion != null) { - objectGroup.RootPart.KeyframeMotion.Pause(); - group2Keyframe.Add(objectGroup, objectGroup.RootPart.KeyframeMotion); - objectGroup.RootPart.KeyframeMotion = null; + objectGroup.RootPart.KeyframeMotion.Suspend(); } + objectGroup.RootPart.SetForce(Vector3.Zero); + objectGroup.RootPart.SetAngularImpulse(Vector3.Zero, false); -// Vector3 inventoryStoredPosition = new Vector3 -// (((objectGroup.AbsolutePosition.X > (int)Constants.RegionSize) -// ? 250 -// : objectGroup.AbsolutePosition.X) -// , -// (objectGroup.AbsolutePosition.Y > (int)Constants.RegionSize) -// ? 250 -// : objectGroup.AbsolutePosition.Y, -// objectGroup.AbsolutePosition.Z); -// -// originalPositions[objectGroup.UUID] = objectGroup.AbsolutePosition; -// -// objectGroup.AbsolutePosition = inventoryStoredPosition; +// originalKeyframes[objectGroup.UUID] = objectGroup.RootPart.KeyframeMotion; +// objectGroup.RootPart.KeyframeMotion = null; + + Vector3 inventoryStoredPosition = objectGroup.AbsolutePosition; + originalPositions[objectGroup.UUID] = inventoryStoredPosition; + Quaternion inventoryStoredRotation = objectGroup.GroupRotation; + originalRotations[objectGroup.UUID] = inventoryStoredRotation; + + // Restore attachment data after trip through the sim + if (objectGroup.AttachmentPoint > 0) + { + inventoryStoredPosition = objectGroup.RootPart.AttachedPos; + inventoryStoredRotation = objectGroup.RootPart.AttachRotation; + if (objectGroup.RootPart.Shape.PCode != (byte) PCode.Tree && + objectGroup.RootPart.Shape.PCode != (byte) PCode.NewTree) + objectGroup.RootPart.Shape.LastAttachPoint = (byte)objectGroup.AttachmentPoint; + + } + + objectGroup.AbsolutePosition = inventoryStoredPosition; + objectGroup.RootPart.RotationOffset = inventoryStoredRotation; // Make sure all bits but the ones we want are clear // on take. @@ -418,7 +459,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess (uint)PermissionMask.Export); objectGroup.RootPart.NextOwnerMask |= (uint)PermissionMask.Move; - + coa.Add(objectGroup); } @@ -432,10 +473,16 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess itemXml = CoalescedSceneObjectsSerializer.ToXml(coa, !asAttachment); else itemXml = SceneObjectSerializer.ToOriginalXmlFormat(objlist[0], !asAttachment); - -// // Restore the position of each group now that it has been stored to inventory. -// foreach (SceneObjectGroup objectGroup in objlist) -// objectGroup.AbsolutePosition = originalPositions[objectGroup.UUID]; + + // Restore the position of each group now that it has been stored to inventory. + foreach (SceneObjectGroup objectGroup in objlist) + { + objectGroup.AbsolutePosition = originalPositions[objectGroup.UUID]; + objectGroup.RootPart.RotationOffset = originalRotations[objectGroup.UUID]; +// objectGroup.RootPart.KeyframeMotion = originalKeyframes[objectGroup.UUID]; + if (objectGroup.RootPart.KeyframeMotion != null) + objectGroup.RootPart.KeyframeMotion.Resume(); + } InventoryItemBase item = CreateItemForObject(action, remoteClient, objlist[0], folderID); @@ -448,11 +495,11 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess item.CreatorId = objlist[0].RootPart.CreatorID.ToString(); item.CreatorData = objlist[0].RootPart.CreatorData; - + if (objlist.Count > 1) { item.Flags = (uint)InventoryItemFlags.ObjectHasMultipleItems; - + // If the objects have different creators then don't specify a creator at all foreach (SceneObjectGroup objectGroup in objlist) { @@ -468,8 +515,8 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess else { item.SaleType = objlist[0].RootPart.ObjectSaleType; - item.SalePrice = objlist[0].RootPart.SalePrice; - } + item.SalePrice = objlist[0].RootPart.SalePrice; + } AssetBase asset = CreateAsset( objlist[0].GetPartName(objlist[0].RootPart.LocalId), @@ -478,7 +525,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess Utils.StringToBytes(itemXml), objlist[0].OwnerID.ToString()); m_Scene.AssetService.Store(asset); - + item.AssetID = asset.FullID; if (DeRezAction.SaveToExistingUserInventoryItem == action) @@ -487,13 +534,13 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess } else { + AddPermissions(item, objlist[0], objlist, remoteClient); + item.CreationDate = Util.UnixTimeSinceEpoch(); item.Description = asset.Description; item.Name = asset.Name; item.AssetType = asset.Type; - AddPermissions(item, objlist[0], objlist, remoteClient); - m_Scene.AddInventoryItem(item); if (remoteClient != null && item.Owner == remoteClient.AgentId) @@ -510,17 +557,10 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess } } - // Restore KeyframeMotion - foreach (SceneObjectGroup objectGroup in group2Keyframe.Keys) - { - objectGroup.RootPart.KeyframeMotion = group2Keyframe[objectGroup]; - objectGroup.RootPart.KeyframeMotion.Start(); - } - // This is a hook to do some per-asset post-processing for subclasses that need that - if (remoteClient != null) + if (remoteClient != null && action != DeRezAction.Delete) ExportAsset(remoteClient.AgentId, asset.FullID); - + return item; } @@ -538,56 +578,41 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess /// /// protected InventoryItemBase AddPermissions( - InventoryItemBase item, SceneObjectGroup so, List objsForEffectivePermissions, + InventoryItemBase item, SceneObjectGroup so, List objsForEffectivePermissions, IClientAPI remoteClient) { - uint effectivePerms = (uint)(PermissionMask.Copy | PermissionMask.Transfer | PermissionMask.Modify | PermissionMask.Move | PermissionMask.Export) | 7; - uint allObjectsNextOwnerPerms = 0x7fffffff; - uint allObjectsEveryOnePerms = 0x7fffffff; - uint allObjectsGroupPerms = 0x7fffffff; - + uint effectivePerms = (uint)(PermissionMask.Copy | PermissionMask.Transfer | PermissionMask.Modify | PermissionMask.Move | PermissionMask.Export | PermissionMask.FoldedMask); + foreach (SceneObjectGroup grp in objsForEffectivePermissions) { - effectivePerms &= grp.GetEffectivePermissions(); - allObjectsNextOwnerPerms &= grp.RootPart.NextOwnerMask; - allObjectsEveryOnePerms &= grp.RootPart.EveryoneMask; - allObjectsGroupPerms &= grp.RootPart.GroupMask; + effectivePerms &= grp.CurrentAndFoldedNextPermissions(); } - effectivePerms |= (uint)PermissionMask.Move; - - //PermissionsUtil.LogPermissions(item.Name, "Before AddPermissions", item.BasePermissions, item.CurrentPermissions, item.NextPermissions); - + if (remoteClient != null && (remoteClient.AgentId != so.RootPart.OwnerID) && m_Scene.Permissions.PropagatePermissions()) { - // Changing ownership, so apply the "Next Owner" permissions to all of the - // inventory item's permissions. - - uint perms = effectivePerms; - PermissionsUtil.ApplyFoldedPermissions(effectivePerms, ref perms); - - item.BasePermissions = perms & allObjectsNextOwnerPerms; - item.CurrentPermissions = item.BasePermissions; - item.NextPermissions = perms & allObjectsNextOwnerPerms; - item.EveryOnePermissions = allObjectsEveryOnePerms & allObjectsNextOwnerPerms; - item.GroupPermissions = allObjectsGroupPerms & allObjectsNextOwnerPerms; - + // apply parts inventory items next owner + PermissionsUtil.ApplyNoModFoldedPermissions(effectivePerms, ref effectivePerms); + // change to next owner + uint basePerms = effectivePerms & so.RootPart.NextOwnerMask; + // fix and update folded + basePerms = PermissionsUtil.FixAndFoldPermissions(basePerms); + + item.BasePermissions = basePerms; + item.CurrentPermissions = basePerms; + item.NextPermissions = basePerms & so.RootPart.NextOwnerMask; + item.EveryOnePermissions = basePerms & so.RootPart.EveryoneMask; + item.GroupPermissions = basePerms & so.RootPart.GroupMask; + // apply next owner perms on rez - item.CurrentPermissions |= SceneObjectGroup.SLAM; + item.Flags |= (uint)InventoryItemFlags.ObjectSlamPerm; } else { - // Not changing ownership. - // In this case we apply the permissions in the object's items ONLY to the inventory - // item's "Next Owner" permissions, but NOT to its "Current", "Base", etc. permissions. - // E.g., if the object contains a No-Transfer item then the item's "Next Owner" - // permissions are also No-Transfer. - PermissionsUtil.ApplyFoldedPermissions(effectivePerms, ref allObjectsNextOwnerPerms); - item.BasePermissions = effectivePerms; item.CurrentPermissions = effectivePerms; - item.NextPermissions = allObjectsNextOwnerPerms & effectivePerms; - item.EveryOnePermissions = allObjectsEveryOnePerms & effectivePerms; - item.GroupPermissions = allObjectsGroupPerms & effectivePerms; + item.NextPermissions = so.RootPart.NextOwnerMask & effectivePerms; + item.EveryOnePermissions = so.RootPart.EveryoneMask & effectivePerms; + item.GroupPermissions = so.RootPart.GroupMask & effectivePerms; item.CurrentPermissions &= ((uint)PermissionMask.Copy | @@ -595,14 +620,12 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess (uint)PermissionMask.Modify | (uint)PermissionMask.Move | (uint)PermissionMask.Export | - 7); // Preserve folded permissions - } - - //PermissionsUtil.LogPermissions(item.Name, "After AddPermissions", item.BasePermissions, item.CurrentPermissions, item.NextPermissions); - + (uint)PermissionMask.FoldedMask); // Preserve folded permissions ?? + } + return item; } - + /// /// Create an item using details for the given scene object. /// @@ -615,7 +638,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess DeRezAction action, IClientAPI remoteClient, SceneObjectGroup so, UUID folderID) { // m_log.DebugFormat( -// "[BASIC INVENTORY ACCESS MODULE]: Creating item for object {0} {1} for folder {2}, action {3}", +// "[BASIC INVENTORY ACCESS MODULE]: Creating item for object {0} {1} for folder {2}, action {3}", // so.Name, so.UUID, folderID, action); // // Get the user info of the item destination @@ -663,14 +686,13 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess // Delete is treated like return in this case // Deleting your own items makes them go to trash // - + InventoryFolderBase folder = null; InventoryItemBase item = null; if (DeRezAction.SaveToExistingUserInventoryItem == action) { - item = new InventoryItemBase(so.RootPart.FromUserInventoryItemID, userID); - item = m_Scene.InventoryService.GetItem(item); + item = m_Scene.InventoryService.GetItem(userID, so.RootPart.FromUserInventoryItemID); //item = userInfo.RootFolder.FindItem( // objectGroup.RootPart.FromUserInventoryItemID); @@ -680,7 +702,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess m_log.DebugFormat( "[INVENTORY ACCESS MODULE]: Object {0} {1} scheduled for save to inventory has already been deleted.", so.Name, so.UUID); - + return null; } } @@ -742,8 +764,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess { if (so.FromFolderID != UUID.Zero && so.RootPart.OwnerID == remoteClient.AgentId) { - InventoryFolderBase f = new InventoryFolderBase(so.FromFolderID, userID); - folder = m_Scene.InventoryService.GetFolder(f); + folder = m_Scene.InventoryService.GetFolder(userID, so.FromFolderID); if(folder.Type == 14 || folder.Type == 16) { @@ -763,49 +784,65 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess } } - item = new InventoryItemBase(); + item = new InventoryItemBase(); item.ID = UUID.Random(); item.InvType = (int)InventoryType.Object; item.Folder = folder.ID; item.Owner = userID; - } - + } + return item; } - + // compatibility do not use public virtual SceneObjectGroup RezObject( IClientAPI remoteClient, UUID itemID, Vector3 RayEnd, Vector3 RayStart, UUID RayTargetID, byte BypassRayCast, bool RayEndIsIntersection, bool RezSelected, bool RemoveItem, UUID fromTaskID, bool attachment) { -// m_log.DebugFormat("[INVENTORY ACCESS MODULE]: RezObject for {0}, item {1}", remoteClient.Name, itemID); + return RezObject(remoteClient, itemID, UUID.Zero, RayEnd, RayStart, + RayTargetID, BypassRayCast, RayEndIsIntersection, + RezSelected, RemoveItem, fromTaskID, attachment); + } - InventoryItemBase item = new InventoryItemBase(itemID, remoteClient.AgentId); - item = m_Scene.InventoryService.GetItem(item); + public virtual SceneObjectGroup RezObject( + IClientAPI remoteClient, UUID itemID, UUID rezGroupID, Vector3 RayEnd, Vector3 RayStart, + UUID RayTargetID, byte BypassRayCast, bool RayEndIsIntersection, + bool RezSelected, bool RemoveItem, UUID fromTaskID, bool attachment) + { +// m_log.DebugFormat("[INVENTORY ACCESS MODULE]: RezObject for {0}, item {1}", remoteClient.Name, itemID); + InventoryItemBase item = m_Scene.InventoryService.GetItem(remoteClient.AgentId, itemID); if (item == null) { - m_log.WarnFormat( - "[INVENTORY ACCESS MODULE]: Could not find item {0} for {1} in RezObject()", - itemID, remoteClient.Name); - return null; } item.Owner = remoteClient.AgentId; return RezObject( - remoteClient, item, item.AssetID, + remoteClient, item, rezGroupID, item.AssetID, RayEnd, RayStart, RayTargetID, BypassRayCast, RayEndIsIntersection, RezSelected, RemoveItem, fromTaskID, attachment); } - + // compatility public virtual SceneObjectGroup RezObject( IClientAPI remoteClient, InventoryItemBase item, UUID assetID, Vector3 RayEnd, Vector3 RayStart, UUID RayTargetID, byte BypassRayCast, bool RayEndIsIntersection, bool RezSelected, bool RemoveItem, UUID fromTaskID, bool attachment) { - AssetBase rezAsset = m_Scene.AssetService.Get(assetID.ToString()); + return RezObject(remoteClient, item, UUID.Zero, assetID, + RayEnd, RayStart, RayTargetID, + BypassRayCast, RayEndIsIntersection, + RezSelected, RemoveItem, fromTaskID, attachment); + } + + public virtual SceneObjectGroup RezObject( + IClientAPI remoteClient, InventoryItemBase item, UUID groupID, UUID assetID, + Vector3 RayEnd, Vector3 RayStart, UUID RayTargetID, + byte BypassRayCast, bool RayEndIsIntersection, + bool RezSelected, bool RemoveItem, UUID fromTaskID, bool attachment) + { + AssetBase rezAsset = m_Scene.AssetService.Get(assetID.ToString()); if (rezAsset == null) { @@ -827,6 +864,15 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess return null; } + if(rezAsset.Data == null || rezAsset.Data.Length == 0) + { + m_log.WarnFormat( + "[INVENTORY ACCESS MODULE]: missing data in asset {0} to RezObject()", + assetID, remoteClient.Name); + remoteClient.SendAgentAlertMessage(string.Format("Unable to rez: missing data in asset {0} ", assetID), false); + return null; + } + SceneObjectGroup group = null; List objlist; @@ -836,7 +882,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess byte bRayEndIsIntersection = (byte)(RayEndIsIntersection ? 1 : 0); Vector3 pos; - bool single + bool single = m_Scene.GetObjectsToRez( rezAsset.Data, attachment, out objlist, out veclist, out bbox, out offsetHeight); @@ -856,12 +902,35 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess pos -= bbox / 2; } + int primcount = 0; + foreach (SceneObjectGroup g in objlist) + primcount += g.PrimCount; + + if (!m_Scene.Permissions.CanRezObject( + primcount, remoteClient.AgentId, pos) + && !attachment) + { + // The client operates in no fail mode. It will + // have already removed the item from the folder + // if it's no copy. + // Put it back if it's not an attachment + // + if (item != null) + { + if (((item.CurrentPermissions & (uint)PermissionMask.Copy) == 0) && (!attachment)) + remoteClient.SendBulkUpdateInventory(item); + } + + return null; + } + if (item != null && !DoPreRezWhenFromItem(remoteClient, item, objlist, pos, veclist, attachment)) return null; for (int i = 0; i < objlist.Count; i++) { group = objlist[i]; + SceneObjectPart rootPart = group.RootPart; // m_log.DebugFormat( // "[INVENTORY ACCESS MODULE]: Preparing to rez {0} {1} {2} ownermask={3:X} nextownermask={4:X} groupmask={5:X} everyonemask={6:X} for {7}", @@ -891,9 +960,12 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess // Make the rezzer the owner, as this is not necessarily set correctly in the serialized asset. part.LastOwnerID = part.OwnerID; part.OwnerID = remoteClient.AgentId; + part.RezzerID = remoteClient.AgentId; } } + group.ResetIDs(); + if (!attachment) { // If it's rezzed in world, select it. Much easier to @@ -903,48 +975,38 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess { part.CreateSelected = true; } - } - group.ResetIDs(); - - if (attachment) + if (rootPart.Shape.PCode == (byte)PCode.Prim) + group.ClearPartAttachmentData(); + } + else { - group.RootPart.Flags |= PrimFlags.Phantom; group.IsAttachment = true; } + group.SetGroup(groupID, remoteClient); + // If we're rezzing an attachment then don't ask // AddNewSceneObject() to update the client since // we'll be doing that later on. Scheduling more than // one full update during the attachment // process causes some clients to fail to display the // attachment properly. - m_Scene.AddNewSceneObject(group, !attachment, false); - // if attachment we set it's asset id so object updates - // can reflect that, if not, we set it's position in world. if (!attachment) { - group.ScheduleGroupForFullUpdate(); - group.AbsolutePosition = pos + veclist[i]; - } - - group.SetGroup(remoteClient.ActiveGroupId, remoteClient); - - if (!attachment) - { - SceneObjectPart rootPart = group.RootPart; - - if (rootPart.Shape.PCode == (byte)PCode.Prim) - group.ClearPartAttachmentData(); + m_Scene.AddNewSceneObject(group, true, false); // Fire on_rez group.CreateScriptInstances(0, true, m_Scene.DefaultScriptEngine, 1); rootPart.ParentGroup.ResumeScripts(); - rootPart.ScheduleFullUpdate(); + group.ScheduleGroupForFullUpdate(); } + else + m_Scene.AddNewSceneObject(group, true, false); + // m_log.DebugFormat( // "[INVENTORY ACCESS MODULE]: Rezzed {0} {1} {2} ownermask={3:X} nextownermask={4:X} groupmask={5:X} everyonemask={6:X} for {7}", @@ -953,6 +1015,8 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess // remoteClient.Name); } +// group.SetGroup(remoteClient.ActiveGroupId, remoteClient); + if (item != null) DoPostRezWhenFromItem(item, attachment); @@ -973,7 +1037,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess /// /// true if we can processed with rezzing, false if we need to abort private bool DoPreRezWhenFromItem( - IClientAPI remoteClient, InventoryItemBase item, List objlist, + IClientAPI remoteClient, InventoryItemBase item, List objlist, Vector3 pos, List veclist, bool isAttachment) { UUID fromUserInventoryItemId = UUID.Zero; @@ -1033,10 +1097,16 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess // object itself before we rez. // // Only do these for the first object if we are rezzing a coalescence. - if (i == 0) + // nahh dont mess with coalescence objects, + // the name in inventory can be change for inventory purpuses only + if (objlist.Count == 1) { rootPart.Name = item.Name; rootPart.Description = item.Description; + } + + if ((item.Flags & (uint)InventoryItemFlags.ObjectSlamSale) != 0) + { rootPart.ObjectSaleType = item.SaleType; rootPart.SalePrice = item.SalePrice; } @@ -1047,20 +1117,78 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess // "[INVENTORY ACCESS MODULE]: rootPart.OwnedID {0}, item.Owner {1}, item.CurrentPermissions {2:X}", // rootPart.OwnerID, item.Owner, item.CurrentPermissions); - if ((rootPart.OwnerID != item.Owner) || (item.CurrentPermissions & SceneObjectGroup.SLAM) != 0) + if ((rootPart.OwnerID != item.Owner) || + (item.CurrentPermissions & (uint)PermissionMask.Slam) != 0 || + (item.Flags & (uint)InventoryItemFlags.ObjectSlamPerm) != 0) { //Need to kill the for sale here rootPart.ObjectSaleType = 0; rootPart.SalePrice = 10; - } - foreach (SceneObjectPart part in so.Parts) + if (m_Scene.Permissions.PropagatePermissions()) + { + foreach (SceneObjectPart part in so.Parts) + { + part.GroupMask = 0; // DO NOT propagate here + if( part.OwnerID != part.GroupID) + part.LastOwnerID = part.OwnerID; + part.OwnerID = item.Owner; + part.RezzerID = item.Owner; + part.Inventory.ChangeInventoryOwner(item.Owner); + + // Reconstruct the original item's base permissions. They + // can be found in the lower (folded) bits. + if ((item.BasePermissions & (uint)PermissionMask.FoldedMask) != 0) + { + // We have permissions stored there so use them + part.NextOwnerMask = ((item.BasePermissions & (uint)PermissionMask.FoldedMask) << (int)PermissionMask.FoldingShift); + part.NextOwnerMask |= (uint)PermissionMask.Move; + } + else + { + // This is a legacy object and we can't avoid the issues that + // caused perms loss or escalation before, treat it the legacy + // way. + part.NextOwnerMask = item.NextPermissions; + } + } + + so.ApplyNextOwnerPermissions(); + + // In case the user has changed flags on a received item + // we have to apply those changes after the slam. Else we + // get a net loss of permissions. + // On legacy objects, this opts for a loss of permissions rather + // than the previous handling that allowed escalation. + foreach (SceneObjectPart part in so.Parts) + { + if ((item.Flags & (uint)InventoryItemFlags.ObjectHasMultipleItems) == 0) + { + part.GroupMask = item.GroupPermissions & part.BaseMask; + part.EveryoneMask = item.EveryOnePermissions & part.BaseMask; + part.NextOwnerMask = item.NextPermissions & part.BaseMask; + } + } + + } + } + else { - part.FromUserInventoryItemID = fromUserInventoryItemId; - part.ApplyPermissionsOnRez(item, true, m_Scene); + foreach (SceneObjectPart part in so.Parts) + { + part.FromUserInventoryItemID = fromUserInventoryItemId; + + if ((item.Flags & (uint)InventoryItemFlags.ObjectOverwriteEveryone) != 0) + part.EveryoneMask = item.EveryOnePermissions; + if ((item.Flags & (uint)InventoryItemFlags.ObjectOverwriteNextOwner) != 0) + part.NextOwnerMask = item.NextPermissions; + if ((item.Flags & (uint)InventoryItemFlags.ObjectOverwriteGroup) != 0) + part.GroupMask = item.GroupPermissions; + } } rootPart.TrimPermissions(); + so.InvalidateDeepEffectivePerms(); if (isAttachment) so.FromItemID = item.ID; @@ -1184,9 +1312,8 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess protected virtual InventoryItemBase GetItem(UUID agentID, UUID itemID) { IInventoryService invService = m_Scene.RequestModuleInterface(); - InventoryItemBase item = new InventoryItemBase(itemID, agentID); - item = invService.GetItem(item); - + InventoryItemBase item = invService.GetItem(agentID, itemID); + if (item != null && item.CreatorData != null && item.CreatorData != string.Empty) UserManagementModule.AddUser(item.CreatorIdAsUuid, item.CreatorData); diff --git a/OpenSim/Region/CoreModules/Framework/InventoryAccess/Tests/HGAssetMapperTests.cs b/OpenSim/Region/CoreModules/Framework/InventoryAccess/Tests/HGAssetMapperTests.cs index 007ff63..01c5d3b 100644 --- a/OpenSim/Region/CoreModules/Framework/InventoryAccess/Tests/HGAssetMapperTests.cs +++ b/OpenSim/Region/CoreModules/Framework/InventoryAccess/Tests/HGAssetMapperTests.cs @@ -77,7 +77,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess.Tests scene.StartScripts(); HGAssetMapper hgam = new HGAssetMapper(scene, homeUrl); - UserAccount ua + UserAccount ua = UserAccountHelpers.CreateUserWithInventory(scene, userFirstName, userLastName, userId, "password"); SceneObjectGroup so = SceneHelpers.AddSceneObject(scene, soPartsCount, ua.PrincipalID, "part", soIdTail); @@ -93,6 +93,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess.Tests Assert.AreEqual(foreignUrl, ncAssetGet.CreatorID); string xmlData = Utils.BytesToString(ncAssetGet.Data); XmlDocument ncAssetGetXmlDoc = new XmlDocument(); + ncAssetGetXmlDoc.XmlResolver=null; ncAssetGetXmlDoc.LoadXml(xmlData); // Console.WriteLine(ncAssetGetXmlDoc.OuterXml); @@ -116,7 +117,7 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess.Tests XmlNode uuidAttribute = savedScriptStateNodes[0].Attributes.GetNamedItem("UUID"); Assert.NotNull(uuidAttribute); // XXX: To check the actual UUID attribute we would have to do some work to retreive the UUID of the task - // item created earlier. + // item created earlier. } private void RezScript(Scene scene, UUID soId, string script, string itemName, UUID userId) @@ -131,9 +132,9 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess.Tests // immediately for tests rather than chunter through it's threaded mechanisms. AutoResetEvent chatEvent = new AutoResetEvent(false); - scene.EventManager.OnChatFromWorld += (s, c) => + scene.EventManager.OnChatFromWorld += (s, c) => { -// Console.WriteLine("Got chat [{0}]", c.Message); +// Console.WriteLine("Got chat [{0}]", c.Message); chatEvent.Set(); }; diff --git a/OpenSim/Region/CoreModules/Framework/InventoryAccess/Tests/InventoryAccessModuleTests.cs b/OpenSim/Region/CoreModules/Framework/InventoryAccess/Tests/InventoryAccessModuleTests.cs index 1d91165..de29ae9 100644 --- a/OpenSim/Region/CoreModules/Framework/InventoryAccess/Tests/InventoryAccessModuleTests.cs +++ b/OpenSim/Region/CoreModules/Framework/InventoryAccess/Tests/InventoryAccessModuleTests.cs @@ -48,12 +48,12 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess.Tests { [TestFixture] public class InventoryAccessModuleTests : OpenSimTestCase - { + { protected TestScene m_scene; protected BasicInventoryAccessModule m_iam; protected UUID m_userId = UUID.Parse("00000000-0000-0000-0000-000000000020"); protected TestClient m_tc; - + [SetUp] public override void SetUp() { @@ -68,31 +68,32 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess.Tests SceneHelpers sceneHelpers = new SceneHelpers(); m_scene = sceneHelpers.SetupScene(); SceneHelpers.SetupSceneModules(m_scene, config, m_iam); - + // Create user string userFirstName = "Jock"; string userLastName = "Stirrup"; string userPassword = "troll"; - UserAccountHelpers.CreateUserWithInventory(m_scene, userFirstName, userLastName, m_userId, userPassword); - + UserAccountHelpers.CreateUserWithInventory(m_scene, userFirstName, userLastName, m_userId, userPassword); + AgentCircuitData acd = new AgentCircuitData(); acd.AgentID = m_userId; m_tc = new TestClient(acd, m_scene); } - + [Test] public void TestRezCoalescedObject() { +/* TestHelpers.InMethod(); // log4net.Config.XmlConfigurator.Configure(); - + // Create asset SceneObjectGroup object1 = SceneHelpers.CreateSceneObject(1, m_userId, "Object1", 0x20); object1.AbsolutePosition = new Vector3(15, 30, 45); - + SceneObjectGroup object2 = SceneHelpers.CreateSceneObject(1, m_userId, "Object2", 0x40); - object2.AbsolutePosition = new Vector3(25, 50, 75); - + object2.AbsolutePosition = new Vector3(25, 50, 75); + CoalescedSceneObjects coa = new CoalescedSceneObjects(m_userId, object1, object2); UUID asset1Id = UUID.Parse("00000000-0000-0000-0000-000000000060"); @@ -106,45 +107,46 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess.Tests item1.Name = item1Name; item1.AssetID = asset1.FullID; item1.ID = item1Id; - InventoryFolderBase objsFolder + InventoryFolderBase objsFolder = InventoryArchiveUtils.FindFoldersByPath(m_scene.InventoryService, m_userId, "Objects")[0]; item1.Folder = objsFolder.ID; item1.Flags |= (uint)InventoryItemFlags.ObjectHasMultipleItems; m_scene.AddInventoryItem(item1); - - SceneObjectGroup so + + SceneObjectGroup so = m_iam.RezObject( - m_tc, item1Id, new Vector3(100, 100, 100), Vector3.Zero, UUID.Zero, 1, false, false, false, UUID.Zero, false); - + m_tc, item1Id, new Vector3(100, 100, 100), Vector3.Zero, UUID.Zero, 1, false, false, false, UUID.Zero, false); + Assert.That(so, Is.Not.Null); - + Assert.That(m_scene.SceneGraph.GetTotalObjectsCount(), Is.EqualTo(2)); - + SceneObjectPart retrievedObj1Part = m_scene.GetSceneObjectPart(object1.Name); Assert.That(retrievedObj1Part, Is.Null); - + retrievedObj1Part = m_scene.GetSceneObjectPart(item1.Name); Assert.That(retrievedObj1Part, Is.Not.Null); Assert.That(retrievedObj1Part.Name, Is.EqualTo(item1.Name)); - + // Bottom of coalescence is placed on ground, hence we end up with 100.5 rather than 85 since the bottom // object is unit square. Assert.That(retrievedObj1Part.AbsolutePosition, Is.EqualTo(new Vector3(95, 90, 100.5f))); - + SceneObjectPart retrievedObj2Part = m_scene.GetSceneObjectPart(object2.Name); - Assert.That(retrievedObj2Part, Is.Not.Null); + Assert.That(retrievedObj2Part, Is.Not.Null); Assert.That(retrievedObj2Part.Name, Is.EqualTo(object2.Name)); Assert.That(retrievedObj2Part.AbsolutePosition, Is.EqualTo(new Vector3(105, 110, 130.5f))); - } - +*/ + } + [Test] public void TestRezObject() { TestHelpers.InMethod(); // log4net.Config.XmlConfigurator.Configure(); - + // Create asset - SceneObjectGroup object1 = SceneHelpers.CreateSceneObject(1, m_userId, "My Little Dog Object", 0x40); + SceneObjectGroup object1 = SceneHelpers.CreateSceneObject(1, m_userId, "My Little Dog Object", 0x40); UUID asset1Id = UUID.Parse("00000000-0000-0000-0000-000000000060"); AssetBase asset1 = AssetHelpers.CreateAsset(asset1Id, object1); @@ -157,17 +159,17 @@ namespace OpenSim.Region.CoreModules.Framework.InventoryAccess.Tests item1.Name = item1Name; item1.AssetID = asset1.FullID; item1.ID = item1Id; - InventoryFolderBase objsFolder + InventoryFolderBase objsFolder = InventoryArchiveUtils.FindFoldersByPath(m_scene.InventoryService, m_userId, "Objects")[0]; item1.Folder = objsFolder.ID; m_scene.AddInventoryItem(item1); - - SceneObjectGroup so + + SceneObjectGroup so = m_iam.RezObject( - m_tc, item1Id, Vector3.Zero, Vector3.Zero, UUID.Zero, 1, false, false, false, UUID.Zero, false); - + m_tc, item1Id, UUID.Zero, Vector3.Zero, Vector3.Zero, UUID.Zero, 1, false, false, false, UUID.Zero, false); + Assert.That(so, Is.Not.Null); - + SceneObjectPart retrievedPart = m_scene.GetSceneObjectPart(so.UUID); Assert.That(retrievedPart, Is.Not.Null); } diff --git a/OpenSim/Region/CoreModules/Framework/Library/LibraryModule.cs b/OpenSim/Region/CoreModules/Framework/Library/LibraryModule.cs index 862f0b7..5d77201 100644 --- a/OpenSim/Region/CoreModules/Framework/Library/LibraryModule.cs +++ b/OpenSim/Region/CoreModules/Framework/Library/LibraryModule.cs @@ -126,7 +126,7 @@ namespace OpenSim.Region.CoreModules.Framework.Library return; // This will never run more than once, even if the region is restarted - if (!m_HasRunOnce) + if (!m_HasRunOnce) { LoadLibrariesFromArchives(); //DumpLibrary(); @@ -178,7 +178,7 @@ namespace OpenSim.Region.CoreModules.Framework.Library InventoryArchiveReadRequest archread = new InventoryArchiveReadRequest(m_MockScene.InventoryService, m_MockScene.AssetService, m_MockScene.UserAccountService, uinfo, simpleName, iarFileName, false); try { - HashSet nodes = archread.Execute(); + Dictionary nodes = archread.Execute(); if (nodes != null && nodes.Count == 0) { // didn't find the subfolder with the given name; place it on the top @@ -188,7 +188,7 @@ namespace OpenSim.Region.CoreModules.Framework.Library archread.Execute(); } - foreach (InventoryNodeBase node in nodes) + foreach (InventoryNodeBase node in nodes.Values) FixPerms(node); } catch (Exception e) diff --git a/OpenSim/Region/CoreModules/Framework/Library/LocalInventoryService.cs b/OpenSim/Region/CoreModules/Framework/Library/LocalInventoryService.cs index e1e1838..c1a9457 100644 --- a/OpenSim/Region/CoreModules/Framework/Library/LocalInventoryService.cs +++ b/OpenSim/Region/CoreModules/Framework/Library/LocalInventoryService.cs @@ -103,13 +103,8 @@ namespace OpenSim.Region.CoreModules.Framework.Library { InventoryItemBase[] itemColl = new InventoryItemBase[itemIDs.Length]; int i = 0; - InventoryItemBase item = new InventoryItemBase(); - item.Owner = principalID; foreach (UUID fid in itemIDs) - { - item.ID = fid; - itemColl[i++] = GetItem(item); - } + itemColl[i++] = GetItem(principalID, fid); return itemColl; } @@ -239,14 +234,14 @@ namespace OpenSim.Region.CoreModules.Framework.Library /// /// /// - public InventoryItemBase GetItem(InventoryItemBase item) { return null; } + public InventoryItemBase GetItem(UUID principalID, UUID itemID) { return null; } /// /// Get a folder, given by its UUID /// /// /// - public InventoryFolderBase GetFolder(InventoryFolderBase folder) { return null; } + public InventoryFolderBase GetFolder(UUID principalID, UUID folderID) { return null; } /// /// Does the given user have an inventory structure? @@ -264,11 +259,11 @@ namespace OpenSim.Region.CoreModules.Framework.Library /// /// Get the union of permissions of all inventory items - /// that hold the given assetID. + /// that hold the given assetID. /// /// /// - /// The permissions or 0 if no such asset is found in + /// The permissions or 0 if no such asset is found in /// the user's inventory public int GetAssetPermissions(UUID userID, UUID assetID) { return 0; } } diff --git a/OpenSim/Region/CoreModules/Framework/Monitoring/MonitorModule.cs b/OpenSim/Region/CoreModules/Framework/Monitoring/MonitorModule.cs index 64feec1..fb3d31c 100644 --- a/OpenSim/Region/CoreModules/Framework/Monitoring/MonitorModule.cs +++ b/OpenSim/Region/CoreModules/Framework/Monitoring/MonitorModule.cs @@ -44,7 +44,7 @@ using Mono.Addins; namespace OpenSim.Region.CoreModules.Framework.Monitoring { [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "MonitorModule")] - public class MonitorModule : INonSharedRegionModule + public class MonitorModule : INonSharedRegionModule { /// /// Is this module enabled? @@ -78,7 +78,7 @@ namespace OpenSim.Region.CoreModules.Framework.Monitoring if (cnfg != null) Enabled = cnfg.GetBoolean("Enabled", true); - + if (!Enabled) return; @@ -205,7 +205,7 @@ namespace OpenSim.Region.CoreModules.Framework.Monitoring m_scene, "ScriptEventsPerSecondMonitor", "Script Events", - m => m.Scene.StatsReporter.LastReportedSimStats[20], + m => m.Scene.StatsReporter.LastReportedSimStats[23], m => string.Format("{0} per second", m.GetValue()))); m_staticMonitors.Add( @@ -301,7 +301,7 @@ namespace OpenSim.Region.CoreModules.Framework.Monitoring m_scene, "SpareFrameTimeMonitor", "Spare Frame Time", - m => m.Scene.StatsReporter.LastReportedSimStats[21], + m => m.Scene.StatsReporter.LastReportedSimStats[38], m => string.Format("{0} ms", m.GetValue()))); m_alerts.Add(new DeadlockAlert(m_staticMonitors.Find(x => x is LastFrameTimeMonitor) as LastFrameTimeMonitor)); @@ -433,7 +433,7 @@ namespace OpenSim.Region.CoreModules.Framework.Monitoring MakeStat("ScriptLines", "lines/sec", (s) => { s.Value = m_scene.StatsReporter.LastReportedSimStats[20]; }); MakeStat("SimSpareMS", "ms/sec", (s) => { s.Value = m_scene.StatsReporter.LastReportedSimStats[21]; }); } - + private void UnRegisterStatsManagerRegionStatistics() { foreach (Stat stat in registeredStats) @@ -443,6 +443,6 @@ namespace OpenSim.Region.CoreModules.Framework.Monitoring } registeredStats.Clear(); } - + } } \ No newline at end of file diff --git a/OpenSim/Region/CoreModules/Framework/Search/BasicSearchModule.cs b/OpenSim/Region/CoreModules/Framework/Search/BasicSearchModule.cs index 3849996..c04d856 100644 --- a/OpenSim/Region/CoreModules/Framework/Search/BasicSearchModule.cs +++ b/OpenSim/Region/CoreModules/Framework/Search/BasicSearchModule.cs @@ -135,7 +135,7 @@ namespace OpenSim.Region.CoreModules.Framework.Search #endregion ISharedRegionModule - + #region Event Handlers void EventManager_OnMakeRootAgent(ScenePresence sp) diff --git a/OpenSim/Region/CoreModules/Framework/ServiceThrottle/ServiceThrottleModule.cs b/OpenSim/Region/CoreModules/Framework/ServiceThrottle/ServiceThrottleModule.cs index 3abacbd..2c74c0e 100644 --- a/OpenSim/Region/CoreModules/Framework/ServiceThrottle/ServiceThrottleModule.cs +++ b/OpenSim/Region/CoreModules/Framework/ServiceThrottle/ServiceThrottleModule.cs @@ -48,31 +48,16 @@ namespace OpenSim.Region.CoreModules.Framework MethodBase.GetCurrentMethod().DeclaringType); private readonly List m_scenes = new List(); - private System.Timers.Timer m_timer = new System.Timers.Timer(); - - private Queue m_RequestQueue = new Queue(); - private Dictionary> m_Pending = new Dictionary>(); - private int m_Interval; + private JobEngine m_processorJobEngine; #region ISharedRegionModule public void Initialise(IConfigSource config) { - m_Interval = Util.GetConfigVarFromSections(config, "Interval", new string[] { "ServiceThrottle" }, 5000); - - m_timer = new System.Timers.Timer(); - m_timer.AutoReset = false; - m_timer.Enabled = true; - m_timer.Interval = 15000; // 15 secs at first - m_timer.Elapsed += ProcessQueue; - m_timer.Start(); - - //WorkManager.StartThread( - // ProcessQueue, - // "GridServiceRequestThread", - // ThreadPriority.BelowNormal, - // true, - // false); + m_processorJobEngine = new JobEngine( + "ServiceThrottle","ServiceThrottle"); + m_processorJobEngine.RequestProcessTimeoutOnStop = 31000; // many webrequests have 30s expire + m_processorJobEngine.Start(); } public void AddRegion(Scene scene) @@ -82,7 +67,6 @@ namespace OpenSim.Region.CoreModules.Framework m_scenes.Add(scene); scene.RegisterModuleInterface(this); scene.EventManager.OnNewClient += OnNewClient; - scene.EventManager.OnMakeRootAgent += OnMakeRootAgent; } } @@ -105,6 +89,7 @@ namespace OpenSim.Region.CoreModules.Framework public void Close() { + m_processorJobEngine.Stop(); } public string Name @@ -126,38 +111,32 @@ namespace OpenSim.Region.CoreModules.Framework client.OnRegionHandleRequest += OnRegionHandleRequest; } - void OnMakeRootAgent(ScenePresence obj) - { - lock (m_timer) - { - if (!m_timer.Enabled) - { - m_timer.Interval = m_Interval; - m_timer.Enabled = true; - m_timer.Start(); - } - } - } - public void OnRegionHandleRequest(IClientAPI client, UUID regionID) { //m_log.DebugFormat("[SERVICE THROTTLE]: RegionHandleRequest {0}", regionID); - ulong handle = 0; - if (IsLocalRegionHandle(regionID, out handle)) - { - client.SendRegionHandle(regionID, handle); - return; - } - Action action = delegate { - GridRegion r = m_scenes[0].GridService.GetRegionByUUID(UUID.Zero, regionID); + if(!client.IsActive) + return; + + if(m_scenes.Count == 0) + return; + + Scene baseScene = m_scenes[0]; + + if(baseScene == null || baseScene.ShuttingDown) + return; + + GridRegion r = baseScene.GridService.GetRegionByUUID(UUID.Zero, regionID); + + if(!client.IsActive) + return; if (r != null && r.RegionHandle != 0) client.SendRegionHandle(regionID, r.RegionHandle); }; - Enqueue("region", regionID.ToString(), action); + m_processorJobEngine.QueueJob("regionHandle", action, regionID.ToString()); } #endregion Events @@ -166,91 +145,10 @@ namespace OpenSim.Region.CoreModules.Framework public void Enqueue(string category, string itemid, Action continuation) { - lock (m_RequestQueue) - { - if (m_Pending.ContainsKey(category)) - { - if (m_Pending[category].Contains(itemid)) - // Don't enqueue, it's already pending - return; - } - else - m_Pending.Add(category, new List()); - - m_Pending[category].Add(itemid); - - m_RequestQueue.Enqueue(delegate - { - lock (m_RequestQueue) - m_Pending[category].Remove(itemid); - - continuation(); - }); - } + m_processorJobEngine.QueueJob(category, continuation, itemid); } #endregion IServiceThrottleModule - - #region Process Continuation Queue - - private void ProcessQueue(object sender, System.Timers.ElapsedEventArgs e) - { - //m_log.DebugFormat("[YYY]: Process queue with {0} continuations", m_RequestQueue.Count); - - while (m_RequestQueue.Count > 0) - { - Action continuation = null; - lock (m_RequestQueue) - continuation = m_RequestQueue.Dequeue(); - - if (continuation != null) - continuation(); - } - - if (AreThereRootAgents()) - { - lock (m_timer) - { - m_timer.Interval = 1000; // 1 sec - m_timer.Enabled = true; - m_timer.Start(); - } - } - else - lock (m_timer) - m_timer.Enabled = false; - - } - - #endregion Process Continuation Queue - - #region Misc - - private bool IsLocalRegionHandle(UUID regionID, out ulong regionHandle) - { - regionHandle = 0; - foreach (Scene s in m_scenes) - if (s.RegionInfo.RegionID == regionID) - { - regionHandle = s.RegionInfo.RegionHandle; - return true; - } - return false; - } - - private bool AreThereRootAgents() - { - foreach (Scene s in m_scenes) - { - foreach (ScenePresence sp in s.GetScenePresences()) - if (!sp.IsChildAgent) - return true; - } - - return false; - } - - #endregion Misc } } diff --git a/OpenSim/Region/CoreModules/Framework/Statistics/Logging/BinaryLoggingModule.cs b/OpenSim/Region/CoreModules/Framework/Statistics/Logging/BinaryLoggingModule.cs index f3436d1..3e6c8b5 100644 --- a/OpenSim/Region/CoreModules/Framework/Statistics/Logging/BinaryLoggingModule.cs +++ b/OpenSim/Region/CoreModules/Framework/Statistics/Logging/BinaryLoggingModule.cs @@ -45,14 +45,14 @@ namespace OpenSim.Region.CoreModules.Framework.Statistics.Logging public class BinaryLoggingModule : INonSharedRegionModule { private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); - + protected bool m_collectStats; protected Scene m_scene = null; - + public string Name { get { return "Binary Statistics Logging Module"; } } public Type ReplaceableInterface { get { return null; } } - public void Initialise(IConfigSource source) + public void Initialise(IConfigSource source) { try { @@ -81,23 +81,23 @@ namespace OpenSim.Region.CoreModules.Framework.Statistics.Logging // if it doesn't work, we don't collect anything } } - + public void AddRegion(Scene scene) { m_scene = scene; } - - public void RemoveRegion(Scene scene) + + public void RemoveRegion(Scene scene) { } - - public void RegionLoaded(Scene scene) + + public void RegionLoaded(Scene scene) { if (m_collectStats) m_scene.StatsReporter.OnSendStatsResult += LogSimStats; } - - public void Close() + + public void Close() { } @@ -107,12 +107,12 @@ namespace OpenSim.Region.CoreModules.Framework.Statistics.Logging public string Path; public System.IO.BinaryWriter Log; } - + static StatLogger m_statLog = null; static TimeSpan m_statLogPeriod = TimeSpan.FromSeconds(300); static string m_statsDir = String.Empty; static Object m_statLockObject = new Object(); - + private void LogSimStats(SimStats stats) { SimStatsPacket pack = new SimStatsPacket(); diff --git a/OpenSim/Region/CoreModules/Framework/UserManagement/HGUserManagementModule.cs b/OpenSim/Region/CoreModules/Framework/UserManagement/HGUserManagementModule.cs index 7b89c2c..3e0a610 100644 --- a/OpenSim/Region/CoreModules/Framework/UserManagement/HGUserManagementModule.cs +++ b/OpenSim/Region/CoreModules/Framework/UserManagement/HGUserManagementModule.cs @@ -52,7 +52,7 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement #region ISharedRegionModule - public new void Initialise(IConfigSource config) + public override void Initialise(IConfigSource config) { string umanmod = config.Configs["Modules"].GetString("UserManagementModule", null); if (umanmod == Name) @@ -111,7 +111,7 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement } // This is it! Let's ask the other world - if (words[0].Contains(".")) + if (words[0].Contains(".")) { string[] names = words[0].Split(new char[] { '.' }); if (names.Length >= 2) @@ -130,7 +130,7 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement } UserAgentServiceConnector uasConn = new UserAgentServiceConnector(uriStr); - + UUID userID = UUID.Zero; try { @@ -140,7 +140,7 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement { m_log.Debug("[USER MANAGEMENT MODULE]: GetUUID call failed ", e); } - + if (!userID.Equals(UUID.Zero)) { UserData ud = new UserData(); @@ -163,8 +163,8 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement //{ // foreach (UserData d in m_UserCache.Values) // { - // if (d.LastName.StartsWith("@") && - // (d.FirstName.ToLower().StartsWith(query.ToLower()) || + // if (d.LastName.StartsWith("@") && + // (d.FirstName.ToLower().StartsWith(query.ToLower()) || // d.LastName.ToLower().StartsWith(query.ToLower()))) // users.Add(d); // } @@ -172,4 +172,4 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement } } -} \ No newline at end of file +} diff --git a/OpenSim/Region/CoreModules/Framework/UserManagement/Tests/HGUserManagementModuleTests.cs b/OpenSim/Region/CoreModules/Framework/UserManagement/Tests/HGUserManagementModuleTests.cs index 4e3b7e5..9d91aa3 100644 --- a/OpenSim/Region/CoreModules/Framework/UserManagement/Tests/HGUserManagementModuleTests.cs +++ b/OpenSim/Region/CoreModules/Framework/UserManagement/Tests/HGUserManagementModuleTests.cs @@ -37,7 +37,7 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement.Tests { [TestFixture] public class HGUserManagementModuleTests : OpenSimTestCase - { + { /// /// Test that a new HG agent (i.e. one without a user account) has their name cached in the UMM upon creation. /// diff --git a/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs b/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs index 7ecbd26..2695464 100644 --- a/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs +++ b/OpenSim/Region/CoreModules/Framework/UserManagement/UserManagementModule.cs @@ -66,7 +66,7 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement #region ISharedRegionModule - public void Initialise(IConfigSource config) + public virtual void Initialise(IConfigSource config) { string umanmod = config.Configs["Modules"].GetString("UserManagementModule", Name); if (umanmod == Name) @@ -88,7 +88,7 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement m_DisplayChangingHomeURI = userManagementConfig.GetBoolean("DisplayChangingHomeURI", false); } - public bool IsSharedModule + public virtual bool IsSharedModule { get { return true; } } @@ -98,12 +98,12 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement get { return "BasicUserManagementModule"; } } - public Type ReplaceableInterface + public virtual Type ReplaceableInterface { get { return null; } } - public void AddRegion(Scene scene) + public virtual void AddRegion(Scene scene) { if (m_Enabled) { @@ -119,7 +119,7 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement } } - public void RemoveRegion(Scene scene) + public virtual void RemoveRegion(Scene scene) { if (m_Enabled) { @@ -131,17 +131,17 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement } } - public void RegionLoaded(Scene s) + public virtual void RegionLoaded(Scene s) { if (m_Enabled && m_ServiceThrottle == null) m_ServiceThrottle = s.RequestModuleInterface(); } - public void PostInitialise() + public virtual void PostInitialise() { } - public void Close() + public virtual void Close() { lock (m_Scenes) { @@ -157,31 +157,34 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement #region Event Handlers - void EventManager_OnPrimsLoaded(Scene s) + protected virtual void EventManager_OnPrimsLoaded(Scene s) { // let's sniff all the user names referenced by objects in the scene m_log.DebugFormat("[USER MANAGEMENT MODULE]: Caching creators' data from {0} ({1} objects)...", s.RegionInfo.RegionName, s.GetEntities().Length); s.ForEachSOG(delegate(SceneObjectGroup sog) { CacheCreators(sog); }); } - void EventManager_OnNewClient(IClientAPI client) + protected virtual void EventManager_OnNewClient(IClientAPI client) { client.OnConnectionClosed += new Action(HandleConnectionClosed); client.OnNameFromUUIDRequest += new UUIDNameRequest(HandleUUIDNameRequest); client.OnAvatarPickerRequest += new AvatarPickerRequest(HandleAvatarPickerRequest); } - void HandleConnectionClosed(IClientAPI client) + protected virtual void HandleConnectionClosed(IClientAPI client) { client.OnNameFromUUIDRequest -= new UUIDNameRequest(HandleUUIDNameRequest); client.OnAvatarPickerRequest -= new AvatarPickerRequest(HandleAvatarPickerRequest); + client.OnConnectionClosed -= new Action(HandleConnectionClosed); } - void HandleUUIDNameRequest(UUID uuid, IClientAPI client) + protected virtual void HandleUUIDNameRequest(UUID uuid, IClientAPI client) { // m_log.DebugFormat( // "[USER MANAGEMENT MODULE]: Handling request for name binding of UUID {0} from {1}", // uuid, remote_client.Name); + if(m_Scenes.Count <= 0) + return; if (m_Scenes[0].LibraryService != null && (m_Scenes[0].LibraryService.LibraryRootFolder.Owner == uuid)) { @@ -204,7 +207,7 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement } // Not found in cache, queue continuation - m_ServiceThrottle.Enqueue("name", uuid.ToString(), delegate + m_ServiceThrottle.Enqueue("uuidname", uuid.ToString(), delegate { //m_log.DebugFormat("[YYY]: Name request {0}", uuid); @@ -214,9 +217,12 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement // So to avoid clients // (particularly Hypergrid clients) permanently binding "Unknown User" to a given UUID, we will // instead drop the request entirely. + if(!client.IsActive) + return; if (GetUser(uuid, out user)) { - client.SendNameReply(uuid, user.FirstName, user.LastName); + if(client.IsActive) + client.SendNameReply(uuid, user.FirstName, user.LastName); } // else // m_log.DebugFormat( @@ -226,7 +232,7 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement } } - public void HandleAvatarPickerRequest(IClientAPI client, UUID avatarID, UUID RequestID, string query) + public virtual void HandleAvatarPickerRequest(IClientAPI client, UUID avatarID, UUID RequestID, string query) { //EventManager.TriggerAvatarPickerRequest(); @@ -286,8 +292,11 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement #region IPeople - public List GetUserData(string query, int page_size, int page_number) + public virtual List GetUserData(string query, int page_size, int page_number) { + if(m_Scenes.Count <= 0) + return new List();; + // search the user accounts service List accs = m_Scenes[0].UserAccountService.GetUserAccounts(m_Scenes[0].RegionInfo.ScopeID, query); @@ -323,7 +332,7 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement #endregion IPeople - private void CacheCreators(SceneObjectGroup sog) + protected virtual void CacheCreators(SceneObjectGroup sog) { //m_log.DebugFormat("[USER MANAGEMENT MODULE]: processing {0} {1}; {2}", sog.RootPart.Name, sog.RootPart.CreatorData, sog.RootPart.CreatorIdentification); AddUser(sog.RootPart.CreatorID, sog.RootPart.CreatorData); @@ -336,9 +345,108 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement } } + /// + /// + /// + /// + /// Caller please provide a properly instantiated array for names, string[2] + /// + protected virtual bool TryGetUserNames(UUID uuid, string[] names) + { + if (names == null) + names = new string[2]; + + if (TryGetUserNamesFromCache(uuid, names)) + return true; + + if (TryGetUserNamesFromServices(uuid, names)) + return true; + + return false; + } + + protected virtual bool TryGetUserNamesFromCache(UUID uuid, string[] names) + { + lock (m_UserCache) + { + if (m_UserCache.ContainsKey(uuid)) + { + names[0] = m_UserCache[uuid].FirstName; + names[1] = m_UserCache[uuid].LastName; + + return true; + } + } + + return false; + } + + /// + /// Try to get the names bound to the given uuid, from the services. + /// + /// True if the name was found, false if not. + /// + /// The array of names if found. If not found, then names[0] = "Unknown" and names[1] = "User" + protected virtual bool TryGetUserNamesFromServices(UUID uuid, string[] names) + { + if(m_Scenes.Count <= 0) + return false; + + UserAccount account = m_Scenes[0].UserAccountService.GetUserAccount(UUID.Zero, uuid); + + if (account != null) + { + names[0] = account.FirstName; + names[1] = account.LastName; + + UserData user = new UserData(); + user.FirstName = account.FirstName; + user.LastName = account.LastName; + + lock (m_UserCache) + m_UserCache[uuid] = user; + + return true; + } + else + { + // Let's try the GridUser service + GridUserInfo uInfo = m_Scenes[0].GridUserService.GetGridUserInfo(uuid.ToString()); + if (uInfo != null) + { + string url, first, last, tmp; + UUID u; + if (Util.ParseUniversalUserIdentifier(uInfo.UserID, out u, out url, out first, out last, out tmp)) + { + AddUser(uuid, first, last, url); + + if (m_UserCache.ContainsKey(uuid)) + { + names[0] = m_UserCache[uuid].FirstName; + names[1] = m_UserCache[uuid].LastName; + + return true; + } + } + else + m_log.DebugFormat("[USER MANAGEMENT MODULE]: Unable to parse UUI {0}", uInfo.UserID); + } +// else +// { +// m_log.DebugFormat("[USER MANAGEMENT MODULE]: No grid user found for {0}", uuid); +// } + + names[0] = "Unknown"; + names[1] = "UserUMMTGUN9"; + + return false; + } + } + + #region IUserManagement - public UUID GetUserIdByName(string name) + public virtual UUID GetUserIdByName(string name) { string[] parts = name.Split(new string[] { " " }, StringSplitOptions.RemoveEmptyEntries); if (parts.Length < 2) @@ -347,8 +455,11 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement return GetUserIdByName(parts[0], parts[1]); } - public UUID GetUserIdByName(string firstName, string lastName) + public virtual UUID GetUserIdByName(string firstName, string lastName) { + if(m_Scenes.Count <= 0) + return UUID.Zero; + // TODO: Optimize for reverse lookup if this gets used by non-console commands. lock (m_UserCache) { @@ -367,14 +478,159 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement return UUID.Zero; } - public string GetUserName(UUID uuid) + public virtual string GetUserName(UUID uuid) { UserData user; GetUser(uuid, out user); return user.FirstName + " " + user.LastName; } - public string GetUserHomeURL(UUID userID) + public virtual Dictionary GetUsersNames(string[] ids) + { + Dictionary ret = new Dictionary(); + if(m_Scenes.Count <= 0) + return ret; + + List missing = new List(); + Dictionary untried = new Dictionary(); + + // look in cache + UserData userdata = new UserData(); + + UUID uuid = UUID.Zero; + foreach(string id in ids) + { + if(UUID.TryParse(id, out uuid)) + { + lock (m_UserCache) + { + if (m_UserCache.TryGetValue(uuid, out userdata) && + userdata.FirstName != "Unknown" && userdata.FirstName != string.Empty) + { + string name = userdata.FirstName + " " + userdata.LastName; + + if(userdata.HasGridUserTried) + ret[uuid] = name; + else + { + untried[uuid] = name; + missing.Add(id); + } + } + else + missing.Add(id); + } + } + } + + if(missing.Count == 0) + return ret; + + // try user account service + List accounts = m_Scenes[0].UserAccountService.GetUserAccounts( + m_Scenes[0].RegionInfo.ScopeID, missing); + + if(accounts.Count != 0) + { + foreach(UserAccount uac in accounts) + { + if(uac != null) + { + string name = uac.FirstName + " " + uac.LastName; + ret[uac.PrincipalID] = name; + missing.Remove(uac.PrincipalID.ToString()); // slowww + untried.Remove(uac.PrincipalID); + + userdata = new UserData(); + userdata.Id = uac.PrincipalID; + userdata.FirstName = uac.FirstName; + userdata.LastName = uac.LastName; + userdata.HomeURL = string.Empty; + userdata.IsUnknownUser = false; + userdata.HasGridUserTried = true; + lock (m_UserCache) + m_UserCache[uac.PrincipalID] = userdata; + } + } + } + + if (missing.Count == 0 || m_Scenes[0].GridUserService == null) + return ret; + + // try grid user service + + GridUserInfo[] pinfos = m_Scenes[0].GridUserService.GetGridUserInfo(missing.ToArray()); + if(pinfos.Length > 0) + { + foreach(GridUserInfo uInfo in pinfos) + { + if (uInfo != null) + { + string url, first, last, tmp; + + if(uInfo.UserID.Length <= 36) + continue; + + if (Util.ParseUniversalUserIdentifier(uInfo.UserID, out uuid, out url, out first, out last, out tmp)) + { + if (url != string.Empty) + { + try + { + userdata = new UserData(); + userdata.FirstName = first.Replace(" ", ".") + "." + last.Replace(" ", "."); + userdata.LastName = "@" + new Uri(url).Authority; + userdata.Id = uuid; + userdata.HomeURL = url; + userdata.IsUnknownUser = false; + userdata.HasGridUserTried = true; + lock (m_UserCache) + m_UserCache[uuid] = userdata; + + string name = userdata.FirstName + " " + userdata.LastName; + ret[uuid] = name; + missing.Remove(uuid.ToString()); + untried.Remove(uuid); + } + catch + { + } + } + } + } + } + } + + // add the untried in cache that still failed + if(untried.Count > 0) + { + foreach(KeyValuePair kvp in untried) + { + ret[kvp.Key] = kvp.Value; + missing.Remove((kvp.Key).ToString()); + } + } + + // add the UMMthings ( not sure we should) + if(missing.Count > 0) + { + foreach(string id in missing) + { + if(UUID.TryParse(id, out uuid) && uuid != UUID.Zero) + { + if (m_Scenes[0].LibraryService != null && + (m_Scenes[0].LibraryService.LibraryRootFolder.Owner == uuid)) + ret[uuid] = "Mr OpenSim"; + else + ret[uuid] = "Unknown UserUMMAU43"; + } + } + } + + return ret; + } + + public virtual string GetUserHomeURL(UUID userID) { UserData user; if(GetUser(userID, out user)) @@ -384,7 +640,7 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement return string.Empty; } - public string GetUserServerURL(UUID userID, string serverType) + public virtual string GetUserServerURL(UUID userID, string serverType) { UserData userdata; if(!GetUser(userID, out userdata)) @@ -424,14 +680,14 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement return string.Empty; } - public string GetUserUUI(UUID userID) + public virtual string GetUserUUI(UUID userID) { string uui; GetUserUUI(userID, out uui); return uui; } - public bool GetUserUUI(UUID userID, out string uui) + public virtual bool GetUserUUI(UUID userID, out string uui) { UserData ud; bool result = GetUser(userID, out ud); @@ -449,6 +705,7 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement last = parts[1]; } uui = userID + ";" + homeURL + ";" + first + " " + last; + return result; } } @@ -457,8 +714,14 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement } #region Cache Management - public bool GetUser(UUID uuid, out UserData userdata) + public virtual bool GetUser(UUID uuid, out UserData userdata) { + if(m_Scenes.Count <= 0) + { + userdata = new UserData(); + return false; + } + lock (m_UserCache) { if (m_UserCache.TryGetValue(uuid, out userdata)) @@ -471,7 +734,6 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement else { userdata = new UserData(); - userdata.HasGridUserTried = false; userdata.Id = uuid; userdata.FirstName = "Unknown"; userdata.LastName = "UserUMMAU42"; @@ -544,7 +806,7 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement return !userdata.IsUnknownUser; } - public void AddUser(UUID uuid, string first, string last) + public virtual void AddUser(UUID uuid, string first, string last, bool isNPC = false) { lock(m_UserCache) { @@ -555,13 +817,13 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement user.FirstName = first; user.LastName = last; user.IsUnknownUser = false; - user.HasGridUserTried = false; + user.HasGridUserTried = isNPC; m_UserCache.Add(uuid, user); } } } - public void AddUser(UUID uuid, string first, string last, string homeURL) + public virtual void AddUser(UUID uuid, string first, string last, string homeURL) { //m_log.DebugFormat("[USER MANAGEMENT MODULE]: Adding user with id {0}, first {1}, last {2}, url {3}", uuid, first, last, homeURL); @@ -611,7 +873,7 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement } } - public void AddUser(UUID id, string creatorData) + public virtual void AddUser(UUID id, string creatorData) { // m_log.InfoFormat("[USER MANAGEMENT MODULE]: Adding user with id {0}, creatorData {1}", id, creatorData); @@ -694,24 +956,29 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement } #endregion - public bool IsLocalGridUser(UUID uuid) + public virtual bool IsLocalGridUser(UUID uuid) { - UserAccount account = m_Scenes[0].UserAccountService.GetUserAccount(m_Scenes[0].RegionInfo.ScopeID, uuid); - if (account == null || (account != null && !account.LocalToGrid)) - return false; + lock (m_Scenes) + { + if (m_Scenes.Count == 0) + return true; + UserAccount account = m_Scenes[0].UserAccountService.GetUserAccount(m_Scenes[0].RegionInfo.ScopeID, uuid); + if (account == null || (account != null && !account.LocalToGrid)) + return false; + } return true; } #endregion IUserManagement - protected void Init() + protected virtual void Init() { AddUser(UUID.Zero, "Unknown", "User"); RegisterConsoleCmds(); } - protected void RegisterConsoleCmds() + protected virtual void RegisterConsoleCmds() { MainConsole.Instance.Commands.AddCommand("Users", true, "show name", @@ -735,7 +1002,7 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement HandleResetUserCache); } - private void HandleResetUserCache(string module, string[] cmd) + protected virtual void HandleResetUserCache(string module, string[] cmd) { lock(m_UserCache) { @@ -743,7 +1010,7 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement } } - private void HandleShowUser(string module, string[] cmd) + protected virtual void HandleShowUser(string module, string[] cmd) { if (cmd.Length < 3) { @@ -772,7 +1039,7 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement MainConsole.Instance.Output(cdt.ToString()); } - private void HandleShowUsers(string module, string[] cmd) + protected virtual void HandleShowUsers(string module, string[] cmd) { ConsoleDisplayTable cdt = new ConsoleDisplayTable(); cdt.AddColumn("UUID", 36); -- cgit v1.1