diff options
author | Melanie | 2011-11-11 23:43:18 +0000 |
---|---|---|
committer | Melanie | 2011-11-11 23:43:18 +0000 |
commit | a4ec97cfddc6baeed2eb5ed08240a7f9fb300d1e (patch) | |
tree | f19e00c12dfe753ee218eccd98b5a21304018247 /OpenSim/Region/Framework/Scenes | |
parent | Merge branch 'master' into bigmerge (diff) | |
parent | Make log messages on authentication failure more explicit (diff) | |
download | opensim-SC-a4ec97cfddc6baeed2eb5ed08240a7f9fb300d1e.zip opensim-SC-a4ec97cfddc6baeed2eb5ed08240a7f9fb300d1e.tar.gz opensim-SC-a4ec97cfddc6baeed2eb5ed08240a7f9fb300d1e.tar.bz2 opensim-SC-a4ec97cfddc6baeed2eb5ed08240a7f9fb300d1e.tar.xz |
Merge branch 'master' into bigmerge
Conflicts:
OpenSim/Region/Framework/Scenes/ScenePresence.cs
OpenSim/Services/AuthenticationService/PasswordAuthenticationService.cs
Diffstat (limited to '')
-rw-r--r-- | OpenSim/Region/Framework/Scenes/ScenePresence.cs | 442 | ||||
-rw-r--r-- | OpenSim/Region/Framework/Scenes/Tests/ScenePresenceSitTests.cs | 176 |
2 files changed, 370 insertions, 248 deletions
diff --git a/OpenSim/Region/Framework/Scenes/ScenePresence.cs b/OpenSim/Region/Framework/Scenes/ScenePresence.cs index fe2dfef..087697f 100644 --- a/OpenSim/Region/Framework/Scenes/ScenePresence.cs +++ b/OpenSim/Region/Framework/Scenes/ScenePresence.cs | |||
@@ -164,7 +164,11 @@ namespace OpenSim.Region.Framework.Scenes | |||
164 | 164 | ||
165 | private uint m_requestedSitTargetID; | 165 | private uint m_requestedSitTargetID; |
166 | private UUID m_requestedSitTargetUUID; | 166 | private UUID m_requestedSitTargetUUID; |
167 | public bool SitGround = false; | 167 | |
168 | /// <summary> | ||
169 | /// Are we sitting on the ground? | ||
170 | /// </summary> | ||
171 | public bool SitGround { get; private set; } | ||
168 | 172 | ||
169 | private SendCourseLocationsMethod m_sendCourseLocationsMethod; | 173 | private SendCourseLocationsMethod m_sendCourseLocationsMethod; |
170 | 174 | ||
@@ -189,20 +193,12 @@ namespace OpenSim.Region.Framework.Scenes | |||
189 | 193 | ||
190 | private readonly Vector3[] Dir_Vectors = new Vector3[11]; | 194 | private readonly Vector3[] Dir_Vectors = new Vector3[11]; |
191 | 195 | ||
192 | |||
193 | protected Timer m_reprioritization_timer; | 196 | protected Timer m_reprioritization_timer; |
194 | protected bool m_reprioritizing; | 197 | protected bool m_reprioritizing; |
195 | protected bool m_reprioritization_called; | 198 | protected bool m_reprioritization_called; |
196 | 199 | ||
197 | private Quaternion m_headrotation = Quaternion.Identity; | 200 | private Quaternion m_headrotation = Quaternion.Identity; |
198 | 201 | ||
199 | //Reuse the Vector3 instead of creating a new one on the UpdateMovement method | ||
200 | // private Vector3 movementvector; | ||
201 | |||
202 | private bool m_autopilotMoving; | ||
203 | private Vector3 m_autoPilotTarget; | ||
204 | private bool m_sitAtAutoTarget; | ||
205 | |||
206 | private string m_nextSitAnimation = String.Empty; | 202 | private string m_nextSitAnimation = String.Empty; |
207 | 203 | ||
208 | //PauPaw:Proper PID Controler for autopilot************ | 204 | //PauPaw:Proper PID Controler for autopilot************ |
@@ -1422,20 +1418,8 @@ namespace OpenSim.Region.Framework.Scenes | |||
1422 | } | 1418 | } |
1423 | } | 1419 | } |
1424 | 1420 | ||
1425 | if (m_autopilotMoving) | ||
1426 | CheckAtSitTarget(); | ||
1427 | |||
1428 | if ((flags & AgentManager.ControlFlags.AGENT_CONTROL_SIT_ON_GROUND) != 0) | 1421 | if ((flags & AgentManager.ControlFlags.AGENT_CONTROL_SIT_ON_GROUND) != 0) |
1429 | { | 1422 | HandleAgentSitOnGround(); |
1430 | m_updateCount = 0; // Kill animation update burst so that the SIT_G.. will stick. | ||
1431 | Animator.TrySetMovementAnimation("SIT_GROUND_CONSTRAINED"); | ||
1432 | |||
1433 | // TODO: This doesn't prevent the user from walking yet. | ||
1434 | // Setting parent ID would fix this, if we knew what value | ||
1435 | // to use. Or we could add a m_isSitting variable. | ||
1436 | //Animator.TrySetMovementAnimation("SIT_GROUND_CONSTRAINED"); | ||
1437 | SitGround = true; | ||
1438 | } | ||
1439 | 1423 | ||
1440 | // In the future, these values might need to go global. | 1424 | // In the future, these values might need to go global. |
1441 | // Here's where you get them. | 1425 | // Here's where you get them. |
@@ -1641,111 +1625,109 @@ namespace OpenSim.Region.Framework.Scenes | |||
1641 | // "[SCENE PRESENCE]: bAllowUpdateMoveToPosition {0}, m_moveToPositionInProgress {1}, m_autopilotMoving {2}", | 1625 | // "[SCENE PRESENCE]: bAllowUpdateMoveToPosition {0}, m_moveToPositionInProgress {1}, m_autopilotMoving {2}", |
1642 | // allowUpdate, m_moveToPositionInProgress, m_autopilotMoving); | 1626 | // allowUpdate, m_moveToPositionInProgress, m_autopilotMoving); |
1643 | 1627 | ||
1644 | if (!m_autopilotMoving) | 1628 | double distanceToTarget = Util.GetDistanceTo(AbsolutePosition, MoveToPositionTarget); |
1645 | { | 1629 | |
1646 | double distanceToTarget = Util.GetDistanceTo(AbsolutePosition, MoveToPositionTarget); | ||
1647 | // m_log.DebugFormat( | 1630 | // m_log.DebugFormat( |
1648 | // "[SCENE PRESENCE]: Abs pos of {0} is {1}, target {2}, distance {3}", | 1631 | // "[SCENE PRESENCE]: Abs pos of {0} is {1}, target {2}, distance {3}", |
1649 | // Name, AbsolutePosition, MoveToPositionTarget, distanceToTarget); | 1632 | // Name, AbsolutePosition, MoveToPositionTarget, distanceToTarget); |
1650 | 1633 | ||
1651 | // Check the error term of the current position in relation to the target position | 1634 | // Check the error term of the current position in relation to the target position |
1652 | if (distanceToTarget <= 1) | 1635 | if (distanceToTarget <= 1) |
1653 | { | 1636 | { |
1654 | // We are close enough to the target | 1637 | // We are close enough to the target |
1655 | AbsolutePosition = MoveToPositionTarget; | 1638 | AbsolutePosition = MoveToPositionTarget; |
1656 | ResetMoveToTarget(); | 1639 | ResetMoveToTarget(); |
1657 | updated = true; | 1640 | updated = true; |
1658 | } | 1641 | } |
1659 | else | 1642 | else |
1643 | { | ||
1644 | try | ||
1660 | { | 1645 | { |
1661 | try | 1646 | // move avatar in 3D at one meter/second towards target, in avatar coordinate frame. |
1662 | { | 1647 | // This movement vector gets added to the velocity through AddNewMovement(). |
1663 | // move avatar in 3D at one meter/second towards target, in avatar coordinate frame. | 1648 | // Theoretically we might need a more complex PID approach here if other |
1664 | // This movement vector gets added to the velocity through AddNewMovement(). | 1649 | // unknown forces are acting on the avatar and we need to adaptively respond |
1665 | // Theoretically we might need a more complex PID approach here if other | 1650 | // to such forces, but the following simple approach seems to works fine. |
1666 | // unknown forces are acting on the avatar and we need to adaptively respond | 1651 | Vector3 LocalVectorToTarget3D = |
1667 | // to such forces, but the following simple approach seems to works fine. | 1652 | (MoveToPositionTarget - AbsolutePosition) // vector from cur. pos to target in global coords |
1668 | Vector3 LocalVectorToTarget3D = | 1653 | * Matrix4.CreateFromQuaternion(Quaternion.Inverse(Rotation)); // change to avatar coords |
1669 | (MoveToPositionTarget - AbsolutePosition) // vector from cur. pos to target in global coords | 1654 | // Ignore z component of vector |
1670 | * Matrix4.CreateFromQuaternion(Quaternion.Inverse(Rotation)); // change to avatar coords | ||
1671 | // Ignore z component of vector | ||
1672 | // Vector3 LocalVectorToTarget2D = new Vector3((float)(LocalVectorToTarget3D.X), (float)(LocalVectorToTarget3D.Y), 0f); | 1655 | // Vector3 LocalVectorToTarget2D = new Vector3((float)(LocalVectorToTarget3D.X), (float)(LocalVectorToTarget3D.Y), 0f); |
1673 | LocalVectorToTarget3D.Normalize(); | 1656 | LocalVectorToTarget3D.Normalize(); |
1674 | 1657 | ||
1675 | // update avatar movement flags. the avatar coordinate system is as follows: | 1658 | // update avatar movement flags. the avatar coordinate system is as follows: |
1676 | // | 1659 | // |
1677 | // +X (forward) | 1660 | // +X (forward) |
1678 | // | 1661 | // |
1679 | // ^ | 1662 | // ^ |
1680 | // | | 1663 | // | |
1681 | // | | 1664 | // | |
1682 | // | | 1665 | // | |
1683 | // | | 1666 | // | |
1684 | // (left) +Y <--------o--------> -Y | 1667 | // (left) +Y <--------o--------> -Y |
1685 | // avatar | 1668 | // avatar |
1686 | // | | 1669 | // | |
1687 | // | | 1670 | // | |
1688 | // | | 1671 | // | |
1689 | // | | 1672 | // | |
1690 | // v | 1673 | // v |
1691 | // -X | 1674 | // -X |
1692 | // | 1675 | // |
1693 | 1676 | ||
1694 | // based on the above avatar coordinate system, classify the movement into | 1677 | // based on the above avatar coordinate system, classify the movement into |
1695 | // one of left/right/back/forward. | 1678 | // one of left/right/back/forward. |
1696 | if (LocalVectorToTarget3D.X < 0) //MoveBack | 1679 | if (LocalVectorToTarget3D.X < 0) //MoveBack |
1697 | { | 1680 | { |
1698 | MovementFlag += (byte)(uint)Dir_ControlFlags.DIR_CONTROL_FLAG_BACK; | 1681 | MovementFlag += (byte)(uint)Dir_ControlFlags.DIR_CONTROL_FLAG_BACK; |
1699 | AgentControlFlags |= (uint)Dir_ControlFlags.DIR_CONTROL_FLAG_BACK; | 1682 | AgentControlFlags |= (uint)Dir_ControlFlags.DIR_CONTROL_FLAG_BACK; |
1700 | updated = true; | 1683 | updated = true; |
1701 | } | 1684 | } |
1702 | else if (LocalVectorToTarget3D.X > 0) //Move Forward | 1685 | else if (LocalVectorToTarget3D.X > 0) //Move Forward |
1703 | { | 1686 | { |
1704 | MovementFlag += (byte)(uint)Dir_ControlFlags.DIR_CONTROL_FLAG_FORWARD; | 1687 | MovementFlag += (byte)(uint)Dir_ControlFlags.DIR_CONTROL_FLAG_FORWARD; |
1705 | AgentControlFlags |= (uint)Dir_ControlFlags.DIR_CONTROL_FLAG_FORWARD; | 1688 | AgentControlFlags |= (uint)Dir_ControlFlags.DIR_CONTROL_FLAG_FORWARD; |
1706 | updated = true; | 1689 | updated = true; |
1707 | } | 1690 | } |
1708 | 1691 | ||
1709 | if (LocalVectorToTarget3D.Y > 0) //MoveLeft | 1692 | if (LocalVectorToTarget3D.Y > 0) //MoveLeft |
1710 | { | 1693 | { |
1711 | MovementFlag += (byte)(uint)Dir_ControlFlags.DIR_CONTROL_FLAG_LEFT; | 1694 | MovementFlag += (byte)(uint)Dir_ControlFlags.DIR_CONTROL_FLAG_LEFT; |
1712 | AgentControlFlags |= (uint)Dir_ControlFlags.DIR_CONTROL_FLAG_LEFT; | 1695 | AgentControlFlags |= (uint)Dir_ControlFlags.DIR_CONTROL_FLAG_LEFT; |
1713 | updated = true; | 1696 | updated = true; |
1714 | } | 1697 | } |
1715 | else if (LocalVectorToTarget3D.Y < 0) //MoveRight | 1698 | else if (LocalVectorToTarget3D.Y < 0) //MoveRight |
1716 | { | 1699 | { |
1717 | MovementFlag += (byte)(uint)Dir_ControlFlags.DIR_CONTROL_FLAG_RIGHT; | 1700 | MovementFlag += (byte)(uint)Dir_ControlFlags.DIR_CONTROL_FLAG_RIGHT; |
1718 | AgentControlFlags |= (uint)Dir_ControlFlags.DIR_CONTROL_FLAG_RIGHT; | 1701 | AgentControlFlags |= (uint)Dir_ControlFlags.DIR_CONTROL_FLAG_RIGHT; |
1719 | updated = true; | 1702 | updated = true; |
1720 | } | 1703 | } |
1721 | 1704 | ||
1722 | if (LocalVectorToTarget3D.Z > 0) //Up | 1705 | if (LocalVectorToTarget3D.Z > 0) //Up |
1723 | { | 1706 | { |
1724 | // Don't set these flags for up or down - doing so will make the avatar crouch or | 1707 | // Don't set these flags for up or down - doing so will make the avatar crouch or |
1725 | // keep trying to jump even if walking along level ground | 1708 | // keep trying to jump even if walking along level ground |
1726 | //MovementFlag += (byte)(uint)Dir_ControlFlags.DIR_CONTROL_FLAG_UP; | 1709 | //MovementFlag += (byte)(uint)Dir_ControlFlags.DIR_CONTROL_FLAG_UP; |
1727 | //AgentControlFlags | 1710 | //AgentControlFlags |
1728 | //AgentControlFlags |= (uint)Dir_ControlFlags.DIR_CONTROL_FLAG_UP; | 1711 | //AgentControlFlags |= (uint)Dir_ControlFlags.DIR_CONTROL_FLAG_UP; |
1729 | updated = true; | 1712 | updated = true; |
1730 | } | 1713 | } |
1731 | else if (LocalVectorToTarget3D.Z < 0) //Down | 1714 | else if (LocalVectorToTarget3D.Z < 0) //Down |
1732 | { | 1715 | { |
1733 | //MovementFlag += (byte)(uint)Dir_ControlFlags.DIR_CONTROL_FLAG_DOWN; | 1716 | //MovementFlag += (byte)(uint)Dir_ControlFlags.DIR_CONTROL_FLAG_DOWN; |
1734 | //AgentControlFlags |= (uint)Dir_ControlFlags.DIR_CONTROL_FLAG_DOWN; | 1717 | //AgentControlFlags |= (uint)Dir_ControlFlags.DIR_CONTROL_FLAG_DOWN; |
1735 | updated = true; | 1718 | updated = true; |
1736 | } | 1719 | } |
1737 | 1720 | ||
1738 | // m_log.DebugFormat( | 1721 | // m_log.DebugFormat( |
1739 | // "[SCENE PRESENCE]: HandleMoveToTargetUpdate adding {0} to move vector {1} for {2}", | 1722 | // "[SCENE PRESENCE]: HandleMoveToTargetUpdate adding {0} to move vector {1} for {2}", |
1740 | // LocalVectorToTarget3D, agent_control_v3, Name); | 1723 | // LocalVectorToTarget3D, agent_control_v3, Name); |
1741 | 1724 | ||
1742 | agent_control_v3 += LocalVectorToTarget3D; | 1725 | agent_control_v3 += LocalVectorToTarget3D; |
1743 | } | 1726 | } |
1744 | catch (Exception e) | 1727 | catch (Exception e) |
1745 | { | 1728 | { |
1746 | //Avoid system crash, can be slower but... | 1729 | //Avoid system crash, can be slower but... |
1747 | m_log.DebugFormat("Crash! {0}", e.ToString()); | 1730 | m_log.DebugFormat("Crash! {0}", e.ToString()); |
1748 | } | ||
1749 | } | 1731 | } |
1750 | } | 1732 | } |
1751 | 1733 | ||
@@ -1847,58 +1829,20 @@ namespace OpenSim.Region.Framework.Scenes | |||
1847 | AgentControlFlags = (uint)AgentManager.ControlFlags.NONE; | 1829 | AgentControlFlags = (uint)AgentManager.ControlFlags.NONE; |
1848 | } | 1830 | } |
1849 | 1831 | ||
1850 | private void CheckAtSitTarget() | ||
1851 | { | ||
1852 | //m_log.Debug("[AUTOPILOT]: " + Util.GetDistanceTo(AbsolutePosition, m_autoPilotTarget).ToString()); | ||
1853 | if (Util.GetDistanceTo(AbsolutePosition, m_autoPilotTarget) <= 1.5) | ||
1854 | { | ||
1855 | if (m_sitAtAutoTarget) | ||
1856 | { | ||
1857 | SceneObjectPart part = m_scene.GetSceneObjectPart(m_requestedSitTargetUUID); | ||
1858 | if (part != null) | ||
1859 | { | ||
1860 | AbsolutePosition = part.AbsolutePosition; | ||
1861 | Velocity = Vector3.Zero; | ||
1862 | SendAvatarDataToAllAgents(); | ||
1863 | |||
1864 | //HandleAgentSit(ControllingClient, m_requestedSitTargetUUID); | ||
1865 | } | ||
1866 | //ControllingClient.SendSitResponse(m_requestedSitTargetID, m_requestedSitOffset, Quaternion.Identity, false, Vector3.Zero, Vector3.Zero, false); | ||
1867 | m_requestedSitTargetUUID = UUID.Zero; | ||
1868 | } | ||
1869 | /* | ||
1870 | else | ||
1871 | { | ||
1872 | //ControllingClient.SendAlertMessage("Autopilot cancelled"); | ||
1873 | //SendTerseUpdateToAllClients(); | ||
1874 | //PrimitiveBaseShape proxy = PrimitiveBaseShape.Default; | ||
1875 | //proxy.PCode = (byte)PCode.ParticleSystem; | ||
1876 | ////uint nextUUID = m_scene.NextLocalId; | ||
1877 | |||
1878 | //proxyObjectGroup = new SceneObjectGroup(m_scene, m_scene.RegionInfo.RegionHandle, UUID, nextUUID, m_autoPilotTarget, Quaternion.Identity, proxy); | ||
1879 | //if (proxyObjectGroup != null) | ||
1880 | //{ | ||
1881 | //proxyObjectGroup.SendGroupFullUpdate(); | ||
1882 | //ControllingClient.SendSitResponse(UUID.Zero, m_autoPilotTarget, Quaternion.Identity, true, Vector3.Zero, Vector3.Zero, false); | ||
1883 | //m_scene.DeleteSceneObject(proxyObjectGroup); | ||
1884 | //} | ||
1885 | } | ||
1886 | */ | ||
1887 | m_autoPilotTarget = Vector3.Zero; | ||
1888 | m_autopilotMoving = false; | ||
1889 | } | ||
1890 | } | ||
1891 | /// <summary> | 1832 | /// <summary> |
1892 | /// Perform the logic necessary to stand the avatar up. This method also executes | 1833 | /// Perform the logic necessary to stand the avatar up. This method also executes |
1893 | /// the stand animation. | 1834 | /// the stand animation. |
1894 | /// </summary> | 1835 | /// </summary> |
1895 | public void StandUp() | 1836 | public void StandUp() |
1896 | { | 1837 | { |
1838 | // m_log.DebugFormat("[SCENE PRESENCE]: StandUp() for {0}", Name); | ||
1839 | |||
1897 | SitGround = false; | 1840 | SitGround = false; |
1841 | if (PhysicsActor == null) | ||
1842 | AddToPhysicalScene(false); | ||
1898 | 1843 | ||
1899 | if (ParentID != 0) | 1844 | if (ParentID != 0) |
1900 | { | 1845 | { |
1901 | m_log.Debug("StandupCode Executed"); | ||
1902 | SceneObjectPart part = m_scene.GetSceneObjectPart(ParentID); | 1846 | SceneObjectPart part = m_scene.GetSceneObjectPart(ParentID); |
1903 | if (part != null) | 1847 | if (part != null) |
1904 | { | 1848 | { |
@@ -1926,11 +1870,6 @@ namespace OpenSim.Region.Framework.Scenes | |||
1926 | ControllingClient.SendClearFollowCamProperties(part.ParentUUID); | 1870 | ControllingClient.SendClearFollowCamProperties(part.ParentUUID); |
1927 | } | 1871 | } |
1928 | 1872 | ||
1929 | if (PhysicsActor == null) | ||
1930 | { | ||
1931 | AddToPhysicalScene(false); | ||
1932 | } | ||
1933 | |||
1934 | m_pos += ParentPosition + new Vector3(0.0f, 0.0f, 2.0f * m_sitAvatarHeight); | 1873 | m_pos += ParentPosition + new Vector3(0.0f, 0.0f, 2.0f * m_sitAvatarHeight); |
1935 | ParentPosition = Vector3.Zero; | 1874 | ParentPosition = Vector3.Zero; |
1936 | 1875 | ||
@@ -1987,9 +1926,8 @@ namespace OpenSim.Region.Framework.Scenes | |||
1987 | return targetPart; | 1926 | return targetPart; |
1988 | } | 1927 | } |
1989 | 1928 | ||
1990 | private void SendSitResponse(IClientAPI remoteClient, UUID targetID, Vector3 offset, Quaternion pSitOrientation) | 1929 | private void SendSitResponse(UUID targetID, Vector3 offset, Quaternion pSitOrientation) |
1991 | { | 1930 | { |
1992 | bool autopilot = true; | ||
1993 | Vector3 pos = new Vector3(); | 1931 | Vector3 pos = new Vector3(); |
1994 | Quaternion sitOrientation = pSitOrientation; | 1932 | Quaternion sitOrientation = pSitOrientation; |
1995 | Vector3 cameraEyeOffset = Vector3.Zero; | 1933 | Vector3 cameraEyeOffset = Vector3.Zero; |
@@ -1997,89 +1935,87 @@ namespace OpenSim.Region.Framework.Scenes | |||
1997 | bool forceMouselook = false; | 1935 | bool forceMouselook = false; |
1998 | 1936 | ||
1999 | SceneObjectPart part = FindNextAvailableSitTarget(targetID); | 1937 | SceneObjectPart part = FindNextAvailableSitTarget(targetID); |
2000 | if (part != null) | 1938 | if (part == null) |
2001 | { | 1939 | return; |
2002 | // TODO: determine position to sit at based on scene geometry; don't trust offset from client | ||
2003 | // see http://wiki.secondlife.com/wiki/User:Andrew_Linden/Office_Hours/2007_11_06 for details on how LL does it | ||
2004 | 1940 | ||
2005 | // Is a sit target available? | 1941 | // TODO: determine position to sit at based on scene geometry; don't trust offset from client |
2006 | Vector3 avSitOffSet = part.SitTargetPosition; | 1942 | // see http://wiki.secondlife.com/wiki/User:Andrew_Linden/Office_Hours/2007_11_06 for details on how LL does it |
2007 | Quaternion avSitOrientation = part.SitTargetOrientation; | ||
2008 | UUID avOnTargetAlready = part.SitTargetAvatar; | ||
2009 | 1943 | ||
2010 | bool SitTargetUnOccupied = (!(avOnTargetAlready != UUID.Zero)); | 1944 | // Is a sit target available? |
2011 | bool SitTargetisSet = | 1945 | Vector3 avSitOffSet = part.SitTargetPosition; |
2012 | (!(avSitOffSet == Vector3.Zero && | 1946 | Quaternion avSitOrientation = part.SitTargetOrientation; |
2013 | ( | 1947 | UUID avOnTargetAlready = part.SitTargetAvatar; |
2014 | avSitOrientation == Quaternion.Identity // Valid Zero Rotation quaternion | 1948 | |
2015 | || avSitOrientation.X == 0f && avSitOrientation.Y == 0f && avSitOrientation.Z == 1f && avSitOrientation.W == 0f // W-Z Mapping was invalid at one point | 1949 | bool SitTargetUnOccupied = (!(avOnTargetAlready != UUID.Zero)); |
2016 | || avSitOrientation.X == 0f && avSitOrientation.Y == 0f && avSitOrientation.Z == 0f && avSitOrientation.W == 0f // Invalid Quaternion | 1950 | bool SitTargetisSet = |
2017 | ) | 1951 | (!(avSitOffSet == Vector3.Zero && |
2018 | )); | 1952 | ( |
1953 | avSitOrientation == Quaternion.Identity // Valid Zero Rotation quaternion | ||
1954 | || avSitOrientation.X == 0f && avSitOrientation.Y == 0f && avSitOrientation.Z == 1f && avSitOrientation.W == 0f // W-Z Mapping was invalid at one point | ||
1955 | || avSitOrientation.X == 0f && avSitOrientation.Y == 0f && avSitOrientation.Z == 0f && avSitOrientation.W == 0f // Invalid Quaternion | ||
1956 | ) | ||
1957 | )); | ||
2019 | 1958 | ||
2020 | // m_log.DebugFormat("[SCENE PRESENCE]: {0} {1}", SitTargetisSet, SitTargetUnOccupied); | 1959 | // m_log.DebugFormat("[SCENE PRESENCE]: {0} {1}", SitTargetisSet, SitTargetUnOccupied); |
2021 | 1960 | ||
2022 | if (SitTargetisSet && SitTargetUnOccupied) | 1961 | if (PhysicsActor != null) |
1962 | m_sitAvatarHeight = m_physicsActor.Size.Z; | ||
1963 | |||
1964 | bool canSit = false; | ||
1965 | pos = part.AbsolutePosition + offset; | ||
1966 | |||
1967 | if (SitTargetisSet) | ||
1968 | { | ||
1969 | if (SitTargetUnOccupied) | ||
2023 | { | 1970 | { |
1971 | m_log.DebugFormat( | ||
1972 | "[SCENE PRESENCE]: Sitting {0} on {1} {2} because sit target is set and unoccupied", | ||
1973 | Name, part.Name, part.LocalId); | ||
1974 | |||
2024 | part.SitTargetAvatar = UUID; | 1975 | part.SitTargetAvatar = UUID; |
2025 | offset = new Vector3(avSitOffSet.X, avSitOffSet.Y, avSitOffSet.Z); | 1976 | offset = new Vector3(avSitOffSet.X, avSitOffSet.Y, avSitOffSet.Z); |
2026 | sitOrientation = avSitOrientation; | 1977 | sitOrientation = avSitOrientation; |
2027 | autopilot = false; | 1978 | canSit = true; |
2028 | } | 1979 | } |
2029 | pos = part.AbsolutePosition + offset; | 1980 | } |
2030 | //if (Math.Abs(part.AbsolutePosition.Z - AbsolutePosition.Z) > 1) | 1981 | else |
2031 | //{ | 1982 | { |
2032 | // offset = pos; | 1983 | if (Util.GetDistanceTo(AbsolutePosition, pos) <= 10) |
2033 | //autopilot = false; | ||
2034 | //} | ||
2035 | if (PhysicsActor != null) | ||
2036 | { | 1984 | { |
2037 | // If we're not using the client autopilot, we're immediately warping the avatar to the location | 1985 | m_log.DebugFormat( |
2038 | // We can remove the physicsActor until they stand up. | 1986 | "[SCENE PRESENCE]: Sitting {0} on {1} {2} because sit target is unset and within 10m", |
2039 | m_sitAvatarHeight = PhysicsActor.Size.Z; | 1987 | Name, part.Name, part.LocalId); |
2040 | 1988 | ||
2041 | if (autopilot) | 1989 | AbsolutePosition = pos + new Vector3(0.0f, 0.0f, m_sitAvatarHeight); |
2042 | { | 1990 | canSit = true; |
2043 | if (Util.GetDistanceTo(AbsolutePosition, pos) < 4.5) | 1991 | } |
2044 | { | 1992 | } |
2045 | autopilot = false; | ||
2046 | 1993 | ||
2047 | RemoveFromPhysicalScene(); | 1994 | if (canSit) |
2048 | AbsolutePosition = pos + new Vector3(0.0f, 0.0f, m_sitAvatarHeight); | 1995 | { |
2049 | } | 1996 | if (PhysicsActor != null) |
2050 | } | 1997 | { |
2051 | else | 1998 | // We can remove the physicsActor until they stand up. |
2052 | { | 1999 | RemoveFromPhysicalScene(); |
2053 | RemoveFromPhysicalScene(); | ||
2054 | } | ||
2055 | } | 2000 | } |
2056 | 2001 | ||
2057 | cameraAtOffset = part.GetCameraAtOffset(); | 2002 | cameraAtOffset = part.GetCameraAtOffset(); |
2058 | cameraEyeOffset = part.GetCameraEyeOffset(); | 2003 | cameraEyeOffset = part.GetCameraEyeOffset(); |
2059 | forceMouselook = part.GetForceMouselook(); | 2004 | forceMouselook = part.GetForceMouselook(); |
2060 | } | ||
2061 | 2005 | ||
2062 | ControllingClient.SendSitResponse(targetID, offset, sitOrientation, autopilot, cameraAtOffset, cameraEyeOffset, forceMouselook); | 2006 | ControllingClient.SendSitResponse( |
2063 | m_requestedSitTargetUUID = targetID; | 2007 | targetID, offset, sitOrientation, false, cameraAtOffset, cameraEyeOffset, forceMouselook); |
2064 | 2008 | ||
2065 | // This calls HandleAgentSit twice, once from here, and the client calls | 2009 | m_requestedSitTargetUUID = targetID; |
2066 | // HandleAgentSit itself after it gets to the location | ||
2067 | // It doesn't get to the location until we've moved them there though | ||
2068 | // which happens in HandleAgentSit :P | ||
2069 | m_autopilotMoving = autopilot; | ||
2070 | m_autoPilotTarget = pos; | ||
2071 | m_sitAtAutoTarget = autopilot; | ||
2072 | if (!autopilot) | ||
2073 | HandleAgentSit(remoteClient, UUID); | ||
2074 | 2010 | ||
2075 | // Moved here to avoid a race with default sit anim | 2011 | HandleAgentSit(ControllingClient, UUID); |
2076 | // The script event needs to be raised after the default sit anim is set. | ||
2077 | if (part != null) | ||
2078 | part.ParentGroup.TriggerScriptChangedEvent(Changed.LINK); | ||
2079 | 2012 | ||
2013 | // Moved here to avoid a race with default sit anim | ||
2014 | // The script event needs to be raised after the default sit anim is set. | ||
2015 | part.ParentGroup.TriggerScriptChangedEvent(Changed.LINK); | ||
2016 | } | ||
2080 | } | 2017 | } |
2081 | 2018 | ||
2082 | // public void HandleAgentRequestSit(IClientAPI remoteClient, UUID agentID, UUID targetID, Vector3 offset, string sitAnimation) | ||
2083 | public void HandleAgentRequestSit(IClientAPI remoteClient, UUID agentID, UUID targetID, Vector3 offset) | 2019 | public void HandleAgentRequestSit(IClientAPI remoteClient, UUID agentID, UUID targetID, Vector3 offset) |
2084 | { | 2020 | { |
2085 | if (ParentID != 0) | 2021 | if (ParentID != 0) |
@@ -2105,11 +2041,11 @@ namespace OpenSim.Region.Framework.Scenes | |||
2105 | { | 2041 | { |
2106 | m_nextSitAnimation = part.SitAnimation; | 2042 | m_nextSitAnimation = part.SitAnimation; |
2107 | } | 2043 | } |
2044 | |||
2108 | m_requestedSitTargetID = part.LocalId; | 2045 | m_requestedSitTargetID = part.LocalId; |
2109 | //m_requestedSitOffset = offset; | ||
2110 | m_requestedSitTargetUUID = targetID; | 2046 | m_requestedSitTargetUUID = targetID; |
2111 | 2047 | ||
2112 | m_log.DebugFormat("[SIT]: Client requested Sit Position: {0}", offset); | 2048 | // m_log.DebugFormat("[SIT]: Client requested Sit Position: {0}", offset); |
2113 | 2049 | ||
2114 | if (m_scene.PhysicsScene.SupportsRayCast()) | 2050 | if (m_scene.PhysicsScene.SupportsRayCast()) |
2115 | { | 2051 | { |
@@ -2123,7 +2059,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
2123 | m_log.Warn("Sit requested on unknown object: " + targetID.ToString()); | 2059 | m_log.Warn("Sit requested on unknown object: " + targetID.ToString()); |
2124 | } | 2060 | } |
2125 | 2061 | ||
2126 | SendSitResponse(remoteClient, targetID, offset, Quaternion.Identity); | 2062 | SendSitResponse(targetID, offset, Quaternion.Identity); |
2127 | } | 2063 | } |
2128 | 2064 | ||
2129 | /* | 2065 | /* |
@@ -2334,45 +2270,42 @@ namespace OpenSim.Region.Framework.Scenes | |||
2334 | { | 2270 | { |
2335 | SceneObjectPart part = m_scene.GetSceneObjectPart(m_requestedSitTargetID); | 2271 | SceneObjectPart part = m_scene.GetSceneObjectPart(m_requestedSitTargetID); |
2336 | 2272 | ||
2337 | if (m_sitAtAutoTarget || !m_autopilotMoving) | 2273 | if (part != null) |
2338 | { | 2274 | { |
2339 | if (part != null) | 2275 | if (part.SitTargetAvatar == UUID) |
2340 | { | 2276 | { |
2341 | if (part.SitTargetAvatar == UUID) | 2277 | Vector3 sitTargetPos = part.SitTargetPosition; |
2342 | { | 2278 | Quaternion sitTargetOrient = part.SitTargetOrientation; |
2343 | Vector3 sitTargetPos = part.SitTargetPosition; | ||
2344 | Quaternion sitTargetOrient = part.SitTargetOrientation; | ||
2345 | 2279 | ||
2346 | // m_log.DebugFormat( | 2280 | // m_log.DebugFormat( |
2347 | // "[SCENE PRESENCE]: Sitting {0} at sit target {1}, {2} on {3} {4}", | 2281 | // "[SCENE PRESENCE]: Sitting {0} at sit target {1}, {2} on {3} {4}", |
2348 | // Name, sitTargetPos, sitTargetOrient, part.Name, part.LocalId); | 2282 | // Name, sitTargetPos, sitTargetOrient, part.Name, part.LocalId); |
2349 | 2283 | ||
2350 | //Quaternion vq = new Quaternion(sitTargetPos.X, sitTargetPos.Y+0.2f, sitTargetPos.Z+0.2f, 0); | 2284 | //Quaternion vq = new Quaternion(sitTargetPos.X, sitTargetPos.Y+0.2f, sitTargetPos.Z+0.2f, 0); |
2351 | //Quaternion nq = new Quaternion(-sitTargetOrient.X, -sitTargetOrient.Y, -sitTargetOrient.Z, sitTargetOrient.w); | 2285 | //Quaternion nq = new Quaternion(-sitTargetOrient.X, -sitTargetOrient.Y, -sitTargetOrient.Z, sitTargetOrient.w); |
2352 | 2286 | ||
2353 | //Quaternion result = (sitTargetOrient * vq) * nq; | 2287 | //Quaternion result = (sitTargetOrient * vq) * nq; |
2354 | 2288 | ||
2355 | m_pos = sitTargetPos + SIT_TARGET_ADJUSTMENT; | 2289 | m_pos = sitTargetPos + SIT_TARGET_ADJUSTMENT; |
2356 | Rotation = sitTargetOrient; | 2290 | Rotation = sitTargetOrient; |
2357 | ParentPosition = part.AbsolutePosition; | 2291 | ParentPosition = part.AbsolutePosition; |
2358 | part.ParentGroup.AddAvatar(UUID); | 2292 | part.ParentGroup.AddAvatar(UUID); |
2359 | } | 2293 | } |
2360 | else | 2294 | else |
2361 | { | 2295 | { |
2362 | m_pos -= part.AbsolutePosition; | 2296 | m_pos -= part.AbsolutePosition; |
2363 | ParentPosition = part.AbsolutePosition; | 2297 | ParentPosition = part.AbsolutePosition; |
2364 | part.ParentGroup.AddAvatar(UUID); | 2298 | part.ParentGroup.AddAvatar(UUID); |
2365 | 2299 | ||
2366 | // m_log.DebugFormat( | 2300 | // m_log.DebugFormat( |
2367 | // "[SCENE PRESENCE]: Sitting {0} at position {1} ({2} + {3}) on part {4} {5} without sit target", | 2301 | // "[SCENE PRESENCE]: Sitting {0} at position {1} ({2} + {3}) on part {4} {5} without sit target", |
2368 | // Name, part.AbsolutePosition, m_pos, ParentPosition, part.Name, part.LocalId); | 2302 | // Name, part.AbsolutePosition, m_pos, ParentPosition, part.Name, part.LocalId); |
2369 | } | ||
2370 | } | ||
2371 | else | ||
2372 | { | ||
2373 | return; | ||
2374 | } | 2303 | } |
2375 | } | 2304 | } |
2305 | else | ||
2306 | { | ||
2307 | return; | ||
2308 | } | ||
2376 | 2309 | ||
2377 | ParentID = m_requestedSitTargetID; | 2310 | ParentID = m_requestedSitTargetID; |
2378 | 2311 | ||
@@ -2383,6 +2316,19 @@ namespace OpenSim.Region.Framework.Scenes | |||
2383 | SendAvatarDataToAllAgents(); | 2316 | SendAvatarDataToAllAgents(); |
2384 | } | 2317 | } |
2385 | 2318 | ||
2319 | public void HandleAgentSitOnGround() | ||
2320 | { | ||
2321 | m_updateCount = 0; // Kill animation update burst so that the SIT_G.. will stick. | ||
2322 | Animator.TrySetMovementAnimation("SIT_GROUND_CONSTRAINED"); | ||
2323 | |||
2324 | // TODO: This doesn't prevent the user from walking yet. | ||
2325 | // Setting parent ID would fix this, if we knew what value | ||
2326 | // to use. Or we could add a m_isSitting variable. | ||
2327 | //Animator.TrySetMovementAnimation("SIT_GROUND_CONSTRAINED"); | ||
2328 | SitGround = true; | ||
2329 | RemoveFromPhysicalScene(); | ||
2330 | } | ||
2331 | |||
2386 | /// <summary> | 2332 | /// <summary> |
2387 | /// Event handler for the 'Always run' setting on the client | 2333 | /// Event handler for the 'Always run' setting on the client |
2388 | /// Tells the physics plugin to increase speed of movement. | 2334 | /// Tells the physics plugin to increase speed of movement. |
diff --git a/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceSitTests.cs b/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceSitTests.cs new file mode 100644 index 0000000..b7b8db4 --- /dev/null +++ b/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceSitTests.cs | |||
@@ -0,0 +1,176 @@ | |||
1 | /* | ||
2 | * Copyright (c) Contributors, http://opensimulator.org/ | ||
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||
4 | * | ||
5 | * Redistribution and use in source and binary forms, with or without | ||
6 | * modification, are permitted provided that the following conditions are met: | ||
7 | * * Redistributions of source code must retain the above copyright | ||
8 | * notice, this list of conditions and the following disclaimer. | ||
9 | * * Redistributions in binary form must reproduce the above copyright | ||
10 | * notice, this list of conditions and the following disclaimer in the | ||
11 | * documentation and/or other materials provided with the distribution. | ||
12 | * * Neither the name of the OpenSimulator Project nor the | ||
13 | * names of its contributors may be used to endorse or promote products | ||
14 | * derived from this software without specific prior written permission. | ||
15 | * | ||
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
26 | */ | ||
27 | |||
28 | using System; | ||
29 | using System.Reflection; | ||
30 | using Nini.Config; | ||
31 | using NUnit.Framework; | ||
32 | using OpenMetaverse; | ||
33 | using OpenSim.Framework; | ||
34 | using OpenSim.Framework.Communications; | ||
35 | using OpenSim.Framework.Servers; | ||
36 | using OpenSim.Region.Framework.Interfaces; | ||
37 | using OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation; | ||
38 | using OpenSim.Tests.Common; | ||
39 | using OpenSim.Tests.Common.Mock; | ||
40 | using System.Threading; | ||
41 | |||
42 | namespace OpenSim.Region.Framework.Scenes.Tests | ||
43 | { | ||
44 | [TestFixture] | ||
45 | public class ScenePresenceSitTests | ||
46 | { | ||
47 | private TestScene m_scene; | ||
48 | private ScenePresence m_sp; | ||
49 | |||
50 | [SetUp] | ||
51 | public void Init() | ||
52 | { | ||
53 | m_scene = SceneHelpers.SetupScene(); | ||
54 | m_sp = SceneHelpers.AddScenePresence(m_scene, TestHelpers.ParseTail(0x1)); | ||
55 | } | ||
56 | |||
57 | [Test] | ||
58 | public void TestSitOutsideRangeNoTarget() | ||
59 | { | ||
60 | TestHelpers.InMethod(); | ||
61 | // log4net.Config.XmlConfigurator.Configure(); | ||
62 | |||
63 | // More than 10 meters away from 0, 0, 0 (default part position) | ||
64 | Vector3 startPos = new Vector3(10.1f, 0, 0); | ||
65 | m_sp.AbsolutePosition = startPos; | ||
66 | |||
67 | SceneObjectPart part = SceneHelpers.AddSceneObject(m_scene); | ||
68 | |||
69 | m_sp.HandleAgentRequestSit(m_sp.ControllingClient, m_sp.UUID, part.UUID, Vector3.Zero); | ||
70 | |||
71 | Assert.That(part.SitTargetAvatar, Is.EqualTo(UUID.Zero)); | ||
72 | Assert.That(m_sp.ParentID, Is.EqualTo(0)); | ||
73 | } | ||
74 | |||
75 | [Test] | ||
76 | public void TestSitWithinRangeNoTarget() | ||
77 | { | ||
78 | TestHelpers.InMethod(); | ||
79 | // log4net.Config.XmlConfigurator.Configure(); | ||
80 | |||
81 | // Less than 10 meters away from 0, 0, 0 (default part position) | ||
82 | Vector3 startPos = new Vector3(9.9f, 0, 0); | ||
83 | m_sp.AbsolutePosition = startPos; | ||
84 | |||
85 | SceneObjectPart part = SceneHelpers.AddSceneObject(m_scene); | ||
86 | |||
87 | m_sp.HandleAgentRequestSit(m_sp.ControllingClient, m_sp.UUID, part.UUID, Vector3.Zero); | ||
88 | |||
89 | Assert.That(part.SitTargetAvatar, Is.EqualTo(UUID.Zero)); | ||
90 | Assert.That(m_sp.ParentID, Is.EqualTo(part.LocalId)); | ||
91 | } | ||
92 | |||
93 | [Test] | ||
94 | public void TestSitAndStandWithNoSitTarget() | ||
95 | { | ||
96 | TestHelpers.InMethod(); | ||
97 | // log4net.Config.XmlConfigurator.Configure(); | ||
98 | |||
99 | // Make sure we're within range to sit | ||
100 | Vector3 startPos = new Vector3(1, 1, 1); | ||
101 | m_sp.AbsolutePosition = startPos; | ||
102 | |||
103 | SceneObjectPart part = SceneHelpers.AddSceneObject(m_scene); | ||
104 | |||
105 | m_sp.HandleAgentRequestSit(m_sp.ControllingClient, m_sp.UUID, part.UUID, Vector3.Zero); | ||
106 | |||
107 | Assert.That(part.SitTargetAvatar, Is.EqualTo(UUID.Zero)); | ||
108 | Assert.That(m_sp.ParentID, Is.EqualTo(part.LocalId)); | ||
109 | Assert.That(m_sp.PhysicsActor, Is.Null); | ||
110 | |||
111 | // FIXME: This is different for live avatars - z position is adjusted. This is half the height of the | ||
112 | // default avatar. | ||
113 | // Curiously, Vector3.ToString() will not display the last two places of the float. For example, | ||
114 | // printing out npc.AbsolutePosition will give <0, 0, 0.8454993> not <0, 0, 0.845499337> | ||
115 | Assert.That( | ||
116 | m_sp.AbsolutePosition, | ||
117 | Is.EqualTo(part.AbsolutePosition + new Vector3(0, 0, 0.845499337f))); | ||
118 | |||
119 | m_sp.StandUp(); | ||
120 | |||
121 | Assert.That(part.SitTargetAvatar, Is.EqualTo(UUID.Zero)); | ||
122 | Assert.That(m_sp.ParentID, Is.EqualTo(0)); | ||
123 | Assert.That(m_sp.PhysicsActor, Is.Not.Null); | ||
124 | } | ||
125 | |||
126 | [Test] | ||
127 | public void TestSitAndStandWithSitTarget() | ||
128 | { | ||
129 | TestHelpers.InMethod(); | ||
130 | // log4net.Config.XmlConfigurator.Configure(); | ||
131 | |||
132 | // If a prim has a sit target then we can sit from any distance away | ||
133 | Vector3 startPos = new Vector3(128, 128, 30); | ||
134 | m_sp.AbsolutePosition = startPos; | ||
135 | |||
136 | SceneObjectPart part = SceneHelpers.AddSceneObject(m_scene); | ||
137 | part.SitTargetPosition = new Vector3(0, 0, 1); | ||
138 | |||
139 | m_sp.HandleAgentRequestSit(m_sp.ControllingClient, m_sp.UUID, part.UUID, Vector3.Zero); | ||
140 | |||
141 | Assert.That(part.SitTargetAvatar, Is.EqualTo(m_sp.UUID)); | ||
142 | Assert.That(m_sp.ParentID, Is.EqualTo(part.LocalId)); | ||
143 | Assert.That( | ||
144 | m_sp.AbsolutePosition, | ||
145 | Is.EqualTo(part.AbsolutePosition + part.SitTargetPosition + ScenePresence.SIT_TARGET_ADJUSTMENT)); | ||
146 | Assert.That(m_sp.PhysicsActor, Is.Null); | ||
147 | |||
148 | m_sp.StandUp(); | ||
149 | |||
150 | Assert.That(part.SitTargetAvatar, Is.EqualTo(UUID.Zero)); | ||
151 | Assert.That(m_sp.ParentID, Is.EqualTo(0)); | ||
152 | Assert.That(m_sp.PhysicsActor, Is.Not.Null); | ||
153 | } | ||
154 | |||
155 | [Test] | ||
156 | public void TestSitAndStandOnGround() | ||
157 | { | ||
158 | TestHelpers.InMethod(); | ||
159 | // log4net.Config.XmlConfigurator.Configure(); | ||
160 | |||
161 | // If a prim has a sit target then we can sit from any distance away | ||
162 | // Vector3 startPos = new Vector3(128, 128, 30); | ||
163 | // sp.AbsolutePosition = startPos; | ||
164 | |||
165 | m_sp.HandleAgentSitOnGround(); | ||
166 | |||
167 | Assert.That(m_sp.SitGround, Is.True); | ||
168 | Assert.That(m_sp.PhysicsActor, Is.Null); | ||
169 | |||
170 | m_sp.StandUp(); | ||
171 | |||
172 | Assert.That(m_sp.SitGround, Is.False); | ||
173 | Assert.That(m_sp.PhysicsActor, Is.Not.Null); | ||
174 | } | ||
175 | } | ||
176 | } \ No newline at end of file | ||