diff options
author | Oren Hurvitz | 2014-07-10 16:02:38 +0300 |
---|---|---|
committer | Justin Clark-Casey | 2014-08-02 00:56:58 +0100 |
commit | 37fcc827e25d362fcd0e2cbb11f5efd0c307e519 (patch) | |
tree | b15dd3e656eec8d07054059cad0a5c0edf7f880a | |
parent | Added locking in AccessModule to prevent possible errors when shutting down a... (diff) | |
download | opensim-SC-37fcc827e25d362fcd0e2cbb11f5efd0c307e519.zip opensim-SC-37fcc827e25d362fcd0e2cbb11f5efd0c307e519.tar.gz opensim-SC-37fcc827e25d362fcd0e2cbb11f5efd0c307e519.tar.bz2 opensim-SC-37fcc827e25d362fcd0e2cbb11f5efd0c307e519.tar.xz |
Fixed problems if an avatar tries to cross regions when the previous cross hasn't completed yet
This caused the client to stop responding, and even the simulators to have problems. The solution is to disallow crossing before the previous cross has completed.
-rw-r--r-- | OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs | 2 | ||||
-rw-r--r-- | OpenSim/Region/Framework/Scenes/ScenePresence.cs | 268 |
2 files changed, 134 insertions, 136 deletions
diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs index 3b1c5d8..69491b7 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs | |||
@@ -568,7 +568,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
568 | } | 568 | } |
569 | else | 569 | else |
570 | { | 570 | { |
571 | m_log.DebugFormat("[SCENE OBJECT]: Crossing avatar alreasy in transit {0} to {1}", av.Name, val); | 571 | m_log.DebugFormat("[SCENE OBJECT]: Not crossing avatar {0} to {1} because it's already in transit", av.Name, val); |
572 | } | 572 | } |
573 | } | 573 | } |
574 | 574 | ||
diff --git a/OpenSim/Region/Framework/Scenes/ScenePresence.cs b/OpenSim/Region/Framework/Scenes/ScenePresence.cs index 17f6301..493090c 100644 --- a/OpenSim/Region/Framework/Scenes/ScenePresence.cs +++ b/OpenSim/Region/Framework/Scenes/ScenePresence.cs | |||
@@ -1691,109 +1691,122 @@ namespace OpenSim.Region.Framework.Scenes | |||
1691 | "[SCENE PRESENCE]: Completing movement of {0} into region {1} in position {2}", | 1691 | "[SCENE PRESENCE]: Completing movement of {0} into region {1} in position {2}", |
1692 | client.Name, Scene.Name, AbsolutePosition); | 1692 | client.Name, Scene.Name, AbsolutePosition); |
1693 | 1693 | ||
1694 | // Make sure it's not a login agent. We don't want to wait for updates during login | 1694 | bool flying = ((m_AgentControlFlags & AgentManager.ControlFlags.AGENT_CONTROL_FLY) != 0); // Get this ahead of time because IsInTransit modifies 'm_AgentControlFlags' |
1695 | if (PresenceType != PresenceType.Npc && (m_teleportFlags & TeleportFlags.ViaLogin) == 0) | 1695 | |
1696 | IsInTransit = true; | ||
1697 | try | ||
1696 | { | 1698 | { |
1697 | // Let's wait until UpdateAgent (called by departing region) is done | 1699 | // Make sure it's not a login agent. We don't want to wait for updates during login |
1698 | if (!WaitForUpdateAgent(client)) | 1700 | if (PresenceType != PresenceType.Npc && (m_teleportFlags & TeleportFlags.ViaLogin) == 0) |
1699 | // The sending region never sent the UpdateAgent data, we have to refuse | 1701 | { |
1700 | return; | 1702 | // Let's wait until UpdateAgent (called by departing region) is done |
1701 | } | 1703 | if (!WaitForUpdateAgent(client)) |
1704 | // The sending region never sent the UpdateAgent data, we have to refuse | ||
1705 | return; | ||
1706 | } | ||
1702 | 1707 | ||
1703 | Vector3 look = Velocity; | 1708 | Vector3 look = Velocity; |
1704 | 1709 | ||
1705 | // if ((look.X == 0) && (look.Y == 0) && (look.Z == 0)) | 1710 | // if ((look.X == 0) && (look.Y == 0) && (look.Z == 0)) |
1706 | if ((Math.Abs(look.X) < 0.1) && (Math.Abs(look.Y) < 0.1) && (Math.Abs(look.Z) < 0.1)) | 1711 | if ((Math.Abs(look.X) < 0.1) && (Math.Abs(look.Y) < 0.1) && (Math.Abs(look.Z) < 0.1)) |
1707 | { | 1712 | { |
1708 | look = new Vector3(0.99f, 0.042f, 0); | 1713 | look = new Vector3(0.99f, 0.042f, 0); |
1709 | } | 1714 | } |
1710 | 1715 | ||
1711 | // Prevent teleporting to an underground location | 1716 | // Prevent teleporting to an underground location |
1712 | // (may crash client otherwise) | 1717 | // (may crash client otherwise) |
1713 | // | 1718 | // |
1714 | Vector3 pos = AbsolutePosition; | 1719 | Vector3 pos = AbsolutePosition; |
1715 | float ground = m_scene.GetGroundHeight(pos.X, pos.Y); | 1720 | float ground = m_scene.GetGroundHeight(pos.X, pos.Y); |
1716 | if (pos.Z < ground + 1.5f) | 1721 | if (pos.Z < ground + 1.5f) |
1717 | { | 1722 | { |
1718 | pos.Z = ground + 1.5f; | 1723 | pos.Z = ground + 1.5f; |
1719 | AbsolutePosition = pos; | 1724 | AbsolutePosition = pos; |
1720 | } | 1725 | } |
1721 | 1726 | ||
1722 | bool flying = ((m_AgentControlFlags & AgentManager.ControlFlags.AGENT_CONTROL_FLY) != 0); | 1727 | if (!MakeRootAgent(AbsolutePosition, flying)) |
1723 | if (!MakeRootAgent(AbsolutePosition, flying)) | 1728 | { |
1724 | { | 1729 | m_log.DebugFormat( |
1725 | m_log.DebugFormat( | 1730 | "[SCENE PRESENCE]: Aborting CompleteMovement call for {0} in {1} as they are already root", |
1726 | "[SCENE PRESENCE]: Aborting CompleteMovement call for {0} in {1} as they are already root", | 1731 | Name, Scene.Name); |
1727 | Name, Scene.Name); | ||
1728 | 1732 | ||
1729 | return; | 1733 | return; |
1730 | } | 1734 | } |
1731 | 1735 | ||
1732 | // Tell the client that we're totally ready | 1736 | // Tell the client that we're totally ready |
1733 | ControllingClient.MoveAgentIntoRegion(m_scene.RegionInfo, AbsolutePosition, look); | 1737 | ControllingClient.MoveAgentIntoRegion(m_scene.RegionInfo, AbsolutePosition, look); |
1734 | 1738 | ||
1735 | // Remember in HandleUseCircuitCode, we delayed this to here | 1739 | // Remember in HandleUseCircuitCode, we delayed this to here |
1736 | if (m_teleportFlags > 0) | 1740 | if (m_teleportFlags > 0) |
1737 | SendInitialDataToMe(); | 1741 | SendInitialDataToMe(); |
1738 | 1742 | ||
1739 | // m_log.DebugFormat("[SCENE PRESENCE] Completed movement"); | 1743 | // m_log.DebugFormat("[SCENE PRESENCE] Completed movement"); |
1740 | 1744 | ||
1741 | if (!string.IsNullOrEmpty(m_callbackURI)) | 1745 | if (!string.IsNullOrEmpty(m_callbackURI)) |
1742 | { | 1746 | { |
1743 | // We cannot sleep here since this would hold up the inbound packet processing thread, as | 1747 | // We cannot sleep here since this would hold up the inbound packet processing thread, as |
1744 | // CompleteMovement() is executed synchronously. However, it might be better to delay the release | 1748 | // CompleteMovement() is executed synchronously. However, it might be better to delay the release |
1745 | // here until we know for sure that the agent is active in this region. Sending AgentMovementComplete | 1749 | // here until we know for sure that the agent is active in this region. Sending AgentMovementComplete |
1746 | // is not enough for Imprudence clients - there appears to be a small delay (<200ms, <500ms) until they regard this | 1750 | // is not enough for Imprudence clients - there appears to be a small delay (<200ms, <500ms) until they regard this |
1747 | // region as the current region, meaning that a close sent before then will fail the teleport. | 1751 | // region as the current region, meaning that a close sent before then will fail the teleport. |
1748 | // System.Threading.Thread.Sleep(2000); | 1752 | // System.Threading.Thread.Sleep(2000); |
1749 | 1753 | ||
1750 | m_log.DebugFormat( | 1754 | m_log.DebugFormat( |
1751 | "[SCENE PRESENCE]: Releasing {0} {1} with callback to {2}", | 1755 | "[SCENE PRESENCE]: Releasing {0} {1} with callback to {2}", |
1752 | client.Name, client.AgentId, m_callbackURI); | 1756 | client.Name, client.AgentId, m_callbackURI); |
1753 | 1757 | ||
1754 | UUID originID; | 1758 | UUID originID; |
1755 | 1759 | ||
1756 | lock (m_originRegionIDAccessLock) | 1760 | lock (m_originRegionIDAccessLock) |
1757 | originID = m_originRegionID; | 1761 | originID = m_originRegionID; |
1758 | 1762 | ||
1759 | Scene.SimulationService.ReleaseAgent(originID, UUID, m_callbackURI); | 1763 | Scene.SimulationService.ReleaseAgent(originID, UUID, m_callbackURI); |
1760 | m_callbackURI = null; | 1764 | m_callbackURI = null; |
1761 | } | 1765 | } |
1762 | // else | 1766 | // else |
1763 | // { | 1767 | // { |
1764 | // m_log.DebugFormat( | 1768 | // m_log.DebugFormat( |
1765 | // "[SCENE PRESENCE]: No callback provided on CompleteMovement of {0} {1} to {2}", | 1769 | // "[SCENE PRESENCE]: No callback provided on CompleteMovement of {0} {1} to {2}", |
1766 | // client.Name, client.AgentId, m_scene.RegionInfo.RegionName); | 1770 | // client.Name, client.AgentId, m_scene.RegionInfo.RegionName); |
1767 | // } | 1771 | // } |
1768 | 1772 | ||
1769 | ValidateAndSendAppearanceAndAgentData(); | 1773 | ValidateAndSendAppearanceAndAgentData(); |
1770 | 1774 | ||
1771 | // Create child agents in neighbouring regions | 1775 | // Create child agents in neighbouring regions |
1772 | if (openChildAgents && !IsChildAgent) | 1776 | if (openChildAgents && !IsChildAgent) |
1773 | { | 1777 | { |
1774 | IEntityTransferModule m_agentTransfer = m_scene.RequestModuleInterface<IEntityTransferModule>(); | 1778 | IEntityTransferModule m_agentTransfer = m_scene.RequestModuleInterface<IEntityTransferModule>(); |
1775 | if (m_agentTransfer != null) | 1779 | if (m_agentTransfer != null) |
1776 | m_agentTransfer.EnableChildAgents(this); | 1780 | { |
1781 | // Note: this call can take a while, because it notifies each of the simulator's neighbours. | ||
1782 | // It's important that we don't allow the avatar to cross regions meanwhile, as that will | ||
1783 | // cause serious errors. We've prevented that from happening by setting IsInTransit=true. | ||
1784 | m_agentTransfer.EnableChildAgents(this); | ||
1785 | } | ||
1777 | 1786 | ||
1778 | IFriendsModule friendsModule = m_scene.RequestModuleInterface<IFriendsModule>(); | 1787 | IFriendsModule friendsModule = m_scene.RequestModuleInterface<IFriendsModule>(); |
1779 | if (friendsModule != null) | 1788 | if (friendsModule != null) |
1780 | friendsModule.SendFriendsOnlineIfNeeded(ControllingClient); | 1789 | friendsModule.SendFriendsOnlineIfNeeded(ControllingClient); |
1781 | 1790 | ||
1782 | } | 1791 | } |
1783 | 1792 | ||
1784 | // XXX: If we force an update here, then multiple attachments do appear correctly on a destination region | 1793 | // XXX: If we force an update here, then multiple attachments do appear correctly on a destination region |
1785 | // If we do it a little bit earlier (e.g. when converting the child to a root agent) then this does not work. | 1794 | // If we do it a little bit earlier (e.g. when converting the child to a root agent) then this does not work. |
1786 | // This may be due to viewer code or it may be something we're not doing properly simulator side. | 1795 | // This may be due to viewer code or it may be something we're not doing properly simulator side. |
1787 | lock (m_attachments) | 1796 | lock (m_attachments) |
1797 | { | ||
1798 | foreach (SceneObjectGroup sog in m_attachments) | ||
1799 | sog.ScheduleGroupForFullUpdate(); | ||
1800 | } | ||
1801 | |||
1802 | // m_log.DebugFormat( | ||
1803 | // "[SCENE PRESENCE]: Completing movement of {0} into region {1} took {2}ms", | ||
1804 | // client.Name, Scene.RegionInfo.RegionName, (DateTime.Now - startTime).Milliseconds); | ||
1805 | } | ||
1806 | finally | ||
1788 | { | 1807 | { |
1789 | foreach (SceneObjectGroup sog in m_attachments) | 1808 | IsInTransit = false; |
1790 | sog.ScheduleGroupForFullUpdate(); | ||
1791 | } | 1809 | } |
1792 | |||
1793 | // m_log.DebugFormat( | ||
1794 | // "[SCENE PRESENCE]: Completing movement of {0} into region {1} took {2}ms", | ||
1795 | // client.Name, Scene.RegionInfo.RegionName, (DateTime.Now - startTime).Milliseconds); | ||
1796 | |||
1797 | } | 1810 | } |
1798 | 1811 | ||
1799 | /// <summary> | 1812 | /// <summary> |
@@ -3587,65 +3600,50 @@ namespace OpenSim.Region.Framework.Scenes | |||
3587 | if (ParentID != 0 || PhysicsActor == null || ParentUUID != UUID.Zero) | 3600 | if (ParentID != 0 || PhysicsActor == null || ParentUUID != UUID.Zero) |
3588 | return; | 3601 | return; |
3589 | 3602 | ||
3590 | if (!IsInTransit) | 3603 | if (IsInTransit) |
3591 | { | 3604 | return; |
3592 | Vector3 pos2 = AbsolutePosition; | ||
3593 | Vector3 origPosition = pos2; | ||
3594 | Vector3 vel = Velocity; | ||
3595 | 3605 | ||
3596 | // Compute the avatar position in the next physics tick. | 3606 | Vector3 pos2 = AbsolutePosition; |
3597 | // If the avatar will be crossing, we force the crossing to happen now | 3607 | Vector3 origPosition = pos2; |
3598 | // in the hope that this will make the avatar movement smoother when crossing. | 3608 | Vector3 vel = Velocity; |
3599 | float timeStep = 0.1f; | ||
3600 | pos2.X = pos2.X + (vel.X * timeStep); | ||
3601 | pos2.Y = pos2.Y + (vel.Y * timeStep); | ||
3602 | pos2.Z = pos2.Z + (vel.Z * timeStep); | ||
3603 | 3609 | ||
3604 | if (!IsInTransit) | 3610 | // Compute the avatar position in the next physics tick. |
3605 | { | 3611 | // If the avatar will be crossing, we force the crossing to happen now |
3606 | if (!m_scene.PositionIsInCurrentRegion(pos2)) | 3612 | // in the hope that this will make the avatar movement smoother when crossing. |
3607 | { | 3613 | float timeStep = 0.1f; |
3608 | m_log.DebugFormat("{0} CheckForBorderCrossing: position outside region. {1} in {2} at pos {3}", | 3614 | pos2.X = pos2.X + (vel.X * timeStep); |
3609 | LogHeader, Name, Scene.Name, pos2); | 3615 | pos2.Y = pos2.Y + (vel.Y * timeStep); |
3610 | 3616 | pos2.Z = pos2.Z + (vel.Z * timeStep); | |
3611 | // Disconnect from the current region | ||
3612 | bool isFlying = Flying; | ||
3613 | RemoveFromPhysicalScene(); | ||
3614 | // pos2 is the forcasted position so make that the 'current' position so the crossing | ||
3615 | // code will move us into the newly addressed region. | ||
3616 | m_pos = pos2; | ||
3617 | if (CrossToNewRegion()) | ||
3618 | { | ||
3619 | AddToPhysicalScene(isFlying); | ||
3620 | } | ||
3621 | else | ||
3622 | { | ||
3623 | // Tried to make crossing happen but it failed. | ||
3624 | if (m_requestedSitTargetUUID == UUID.Zero) | ||
3625 | { | ||
3626 | m_log.DebugFormat("{0} CheckForBorderCrossing: Crossing failed. Restoring old position.", LogHeader); | ||
3627 | 3617 | ||
3628 | Velocity = Vector3.Zero; | 3618 | if (m_scene.PositionIsInCurrentRegion(pos2)) |
3629 | AbsolutePosition = EnforceSanityOnPosition(origPosition); | 3619 | return; |
3630 | 3620 | ||
3631 | AddToPhysicalScene(isFlying); | 3621 | m_log.DebugFormat("{0} CheckForBorderCrossing: position outside region. {1} in {2} at pos {3}", |
3632 | } | 3622 | LogHeader, Name, Scene.Name, pos2); |
3633 | } | 3623 | |
3634 | } | 3624 | // Disconnect from the current region |
3635 | } | 3625 | bool isFlying = Flying; |
3636 | else | 3626 | RemoveFromPhysicalScene(); |
3627 | // pos2 is the forcasted position so make that the 'current' position so the crossing | ||
3628 | // code will move us into the newly addressed region. | ||
3629 | m_pos = pos2; | ||
3630 | if (CrossToNewRegion()) | ||
3631 | { | ||
3632 | AddToPhysicalScene(isFlying); | ||
3633 | } | ||
3634 | else | ||
3635 | { | ||
3636 | // Tried to make crossing happen but it failed. | ||
3637 | if (m_requestedSitTargetUUID == UUID.Zero) | ||
3637 | { | 3638 | { |
3638 | // This constant has been inferred from experimentation | 3639 | m_log.DebugFormat("{0} CheckForBorderCrossing: Crossing failed. Restoring old position.", LogHeader); |
3639 | // I'm not sure what this value should be, so I tried a few values. | 3640 | |
3640 | timeStep = 0.04f; | 3641 | Velocity = Vector3.Zero; |
3641 | pos2 = AbsolutePosition; | 3642 | AbsolutePosition = EnforceSanityOnPosition(origPosition); |
3642 | pos2.X = pos2.X + (vel.X * timeStep); | 3643 | |
3643 | pos2.Y = pos2.Y + (vel.Y * timeStep); | 3644 | AddToPhysicalScene(isFlying); |
3644 | // Don't touch the Z | ||
3645 | m_pos = pos2; | ||
3646 | m_log.DebugFormat("[SCENE PRESENCE]: In transit m_pos={0}", m_pos); | ||
3647 | } | 3645 | } |
3648 | } | 3646 | } |
3649 | } | 3647 | } |
3650 | 3648 | ||
3651 | // Given a position, make sure it is within the current region. | 3649 | // Given a position, make sure it is within the current region. |