DayZ 1.28
DayZ Explorer by KGB
 
Загрузка...
Поиск...
Не найдено

◆ LiftWeaponCheckEx()

bool Weapon::LiftWeaponCheckEx ( PlayerBase player,
out float outObstruction,
out Object outHitObject )
inlineprivate

Perform weapon obstruction check by the provided player.

Аргументы
playerThe player to perform the check.
outObstructionResult obstruction value [0 .. 1] or > 1 when out of range and needs lift instead
outHitObjectObject that was hit (if any)
Возвращает
True whenever weapon should be lifted or obstruted. (See also Weapon_Base.UseWeaponObstruction)

См. определение в файле Weapon_Base.c строка 1657

1658 {
1659 bool wasLift = m_LiftWeapon;
1660 vector lastLiftPosition = m_LastLiftPosition;
1661
1662 m_LiftWeapon = false;
1663
1664 // [14.2.2025]
1665 // The following selection check should be *unused* for some time now.
1666 // Leaving commented out for future reference, should the removal have unforseen consequences.
1667 // if ( HasSelection("Usti hlavne") )
1668 // return false;
1669
1670 if (!player)
1671 {
1672 #ifndef SERVER
1673 #ifdef DIAG_DEVELOPER
1674 PluginDiagMenuClient.GetWeaponLiftDiag().Reset();
1675 #endif
1676 #endif
1677 Print("Error: No weapon owner for LiftWeaponCheckEx, returning.");
1678 return false;
1679 }
1680
1681 // Obstruction can only occur if the weapon is rasied
1682 HumanMovementState movementState = new HumanMovementState();
1683 player.GetMovementState(movementState);
1684 if (!movementState.IsRaised())
1685 return false;
1686
1687 // Suppress weapon obstruction during melee attack preventing state inconsistency
1688 if (movementState.m_CommandTypeId == DayZPlayerConstants.COMMANDID_MELEE || movementState.m_CommandTypeId == DayZPlayerConstants.COMMANDID_MELEE2)
1689 {
1690 #ifndef SERVER
1691 #ifdef DIAG_DEVELOPER
1692 PluginDiagMenuClient.GetWeaponLiftDiag().Reset();
1693 #endif
1694 #endif
1695 return false;
1696 }
1697
1698
1699 // If possible use aiming angles instead as these will work consistently
1700 // and independently of any cameras, etc.
1701 vector direction;
1702 HumanInputController hic = player.GetInputController();
1703 HumanCommandWeapons hcw = player.GetCommandModifier_Weapons();
1704 HumanCommandMove hcm = player.GetCommand_Move();
1705 if (hcw)
1706 {
1707 vector yawPitchRoll = Vector(
1708 hcw.GetBaseAimingAngleLR() + player.GetOrientation()[0],
1710 0.0);
1711
1712 float xAimHandsOffset = hcw.GetAimingHandsOffsetLR();
1713 float yAimHandsOffset = hcw.GetAimingHandsOffsetUD();
1714
1715 yawPitchRoll[0] = yawPitchRoll[0] + xAimHandsOffset;
1716 yawPitchRoll[1] = Math.Clamp( yawPitchRoll[1] + yAimHandsOffset, DayZPlayerCamera1stPerson.CONST_UD_MIN, DayZPlayerCamera1stPerson.CONST_UD_MAX );
1717
1718 direction = yawPitchRoll.AnglesToVector();
1719 }
1720 else // Fallback to previously implemented logic
1721 {
1722 // freelook raycast
1723 if (hic.CameraIsFreeLook())
1724 {
1725 if (player.m_DirectionToCursor != vector.Zero)
1726 {
1727 direction = player.m_DirectionToCursor;
1728 }
1729 // if player raises weapon in freelook
1730 else
1731 {
1732 direction = MiscGameplayFunctions.GetHeadingVector(player);
1733 }
1734 }
1735 else
1736 {
1737 direction = GetGame().GetCurrentCameraDirection(); // exception for freelook. Much better this way!
1738 }
1739 }
1740
1741 // Reference bone to perform checks from
1742 vector start;
1743 int boneIdx = player.GetBoneIndexByName("Neck");
1744 if (boneIdx == -1)
1745 {
1746 start = player.GetPosition()[1] + 1.5;
1747 }
1748 else
1749 {
1750 start = player.GetBonePositionWS(boneIdx);
1751 }
1752
1753 // Update the ray origin and direction with approximations of character state
1754 vector velocity = GetVelocity(player);
1755 velocity = player.VectorToLocal(velocity);
1756 ApproximateWeaponLiftTransform(start, direction, movementState, hic, hcw, hcm, velocity);
1757
1758 float effectiveAttachmentLength = GetEffectiveAttachmentLength();
1759
1760 // weapon length including effective attachments
1761 float weaponLength = m_WeaponLength + effectiveAttachmentLength;
1762 // distance of point from 'shoulder' (start) from which the weapon length should be computed,
1763 // pistols have the start point further, near the character wrist whereas longer rifles, typically
1764 // the ones with buttstocks have the start point at 0 distance, ie. directly at shoulder
1765 float weaponStartDist = m_ShoulderDistance;
1766 float weaponEndDist = weaponStartDist + weaponLength;
1767
1768 // Weapon start and end positions as an offset from the character shoulder
1769 vector weaponStart = start + (weaponStartDist * direction);
1770 vector weaponEnd = start + (weaponEndDist * direction);
1771
1772 // distance of point from 'shoulder' (start) at which the weapon is "fully obstructed", i.e.
1773 // needs to be lifted to be able to be physically fit wherever it is. Shifted by effective
1774 // attachment length to account for e.g. suppressors that make the weapon "longer".
1775 // Defaults to FLT_MAX if no value is configured, effectivelly always lifting weapon instead of obstructing.
1776 float baseObstructionLength = m_ObstructionDistance;
1777 if (baseObstructionLength==0)
1778 {
1779 baseObstructionLength = ApproximateBaseObstructionLength();
1780 }
1781
1782 float weaponObstructionDist = baseObstructionLength + effectiveAttachmentLength;
1783 float rayRadius = 0.02;
1784
1785 #ifndef SERVER
1786 #ifdef DIAG_DEVELOPER // Retrieve possible override
1787 float overrideObstDist = PluginDiagMenuClient.GetWeaponLiftDiag().Data().m_ObstructionDistance;
1788 PluginDiagMenuClient.GetWeaponLiftDiag().Data().SetWeaponRayParams(start, direction, weaponStartDist, weaponEndDist, effectiveAttachmentLength, m_ObstructionDistance, weaponObstructionDist, rayRadius);
1789 weaponObstructionDist = overrideObstDist;
1790 rayRadius = PluginDiagMenuClient.GetWeaponLiftDiag().Data().m_RayRadiusOverride;
1791 #endif
1792 #endif
1793
1794 // Extend the raycast range by 30 cm to allow checking for intersections even
1795 // under shallow angles and other odd cases
1796 float rayEndDist = weaponEndDist + 0.30;
1797 vector rayEnd = start + rayEndDist * direction;
1798
1799 // Prepare raycast params and perform the cast in fire geo
1800 RaycastRVParams rayParm = new RaycastRVParams(start, rayEnd, player, rayRadius);
1801 rayParm.flags = CollisionFlags.ALLOBJECTS;
1802 rayParm.type = ObjIntersect.Fire;
1803
1804 RaycastRVResult hitResult;
1805 float hitFraction;
1806 float hitDist;
1807
1808 array<ref RaycastRVResult> results = {};
1809 if (!DayZPhysics.RaycastRVProxy(rayParm, results) || results.Count() == 0)
1810 {
1811 hitFraction = 0;
1812 }
1813 else
1814 {
1815 // In case of multiple results, find the best (nearest) match, RaycastRVProxy doesn't guarantee any sensible order
1816 int numRes = results.Count();
1817 if (numRes == 1)
1818 {
1819 hitResult = results[0];
1820 }
1821 else
1822 {
1823 int bi = -1;
1824 float maxDist = float.MAX;
1825 for (int i = 0, nr = results.Count(); i < nr; ++i)
1826 {
1827 float sqDist = vector.DistanceSq(results[i].pos, weaponStart);
1828 if (sqDist < maxDist)
1829 {
1830 maxDist = sqDist;
1831 bi = i;
1832 }
1833 }
1834 hitResult = results[bi];
1835 }
1836
1837 if (LiftWeaponRaycastResultCheck(hitResult))
1838 {
1839 float len0 = (hitResult.pos - start).Length();
1840 float len1 = (weaponEnd - start).Length(); // Do not include 'rayEnd' - pretend as if the computation happened in <start, weaponEnd>
1841
1842 if (len0 <= 0 || len1 <= 0)
1843 {
1844 hitFraction = 1;
1845 }
1846 else
1847 {
1848 hitFraction = len0 / len1;
1849 }
1850 hitDist = hitFraction * weaponEndDist;
1851 }
1852 else
1853 {
1854 hitFraction = 0;
1855 hitDist = 0;
1856 }
1857 }
1858
1859 #ifndef SERVER
1860 #ifdef DIAG_DEVELOPER // isect diag
1861 PluginDiagMenuClient.GetWeaponLiftDiag().Data().SetIntersectionParams(hitResult, hitFraction, hitDist);
1862 PluginDiagMenuClient.GetWeaponLiftDiag().Data().SetLastPosition(lastLiftPosition);
1863 #endif // !isect diag
1864 #endif
1865
1866 // Start by assuming that we want to retain state
1867 bool wantsLift = wasLift;
1868
1869 // Sq. distance of weapon movement required to trigger lift (in)
1870 const float inThreshold = 0.002;
1871 // Sq. distance of weapon movement required to trigger lift (out)
1872 const float outThreshold = 0.003;
1873 const float noIsctOutThreshold = 0.01;
1874 // Max num of ticks with no hit for which hysteresis will persist
1875 // value chosen by iteration, should be approx 0.333s
1876 const int maxNumMissedTicks = 10;
1877
1878 // Min angle in degrees change from last lift to stop lifting
1879 // Base threshold of 0.75 degrees + 0.6 degrees per meter of weapon length
1880 float angleThreshold = 0.75 + Math.Clamp( m_WeaponLength * 0.6, 0, 1.5 );
1881
1882 // Update state when a hit is registered
1883 if (hitFraction != 0)
1884 {
1885 vector v1 = hitResult.pos - weaponEnd;
1886 vector v2 = hitResult.pos - rayEnd;
1887 float d = vector.Dot(v1, v2);
1888 // But leave some threshold where previous state is kept
1889 // to prevent excessive switches from occuring
1890 if (!wasLift && d > inThreshold)
1891 {
1892 wantsLift = true;
1893 }
1894 else if (wasLift && d < -outThreshold)
1895 {
1896 wantsLift = false;
1897 }
1898
1899 m_LastLiftPosition = hitResult.pos;
1900 m_LastLiftHit = player.GetSimulationTimeStamp();
1901 }
1902 else
1903 {
1904 // With no hit and no previous lift
1905 if (lastLiftPosition == vector.Zero)
1906 {
1907 wantsLift = false;
1908 m_LastLiftPosition = vector.Zero;
1909 }
1910 // See if previous hit wasn't very close to our current position,
1911 // in which case simply don't lift the weapon
1912 else
1913 {
1914 vector v3 = (lastLiftPosition - start).Normalized();
1915 vector v4 = (weaponEnd-start).Normalized();
1916 float d2 = vector.Dot(v3, v4);
1917 // no isect, angle delta check
1918 if (Math.Acos(d2) > (angleThreshold * Math.DEG2RAD)) // if relative angle is > x degree, stop lifting
1919 {
1920 wantsLift = false;
1921 m_LastLiftPosition = vector.Zero;
1922 }
1923 // no isect, distance check
1924 else
1925 {
1926 float d3 = vector.Dot( lastLiftPosition - weaponEnd, (start-weaponEnd).Normalized() );
1927 if (d3 < -noIsctOutThreshold)
1928 {
1929 wantsLift = false;
1930 m_LastLiftPosition = vector.Zero;
1931 }
1932 float lastObstruction = hcw.GetWeaponObstruction();
1933 // fallback in case offending object disappears or moves
1934 int timeSinceHit = player.GetSimulationTimeStamp() - m_LastLiftHit;
1935 if (timeSinceHit > maxNumMissedTicks)
1936 {
1937 wantsLift = false;
1938 m_LastLiftPosition = vector.Zero;
1939 }
1940 else if (wantsLift && m_LastLiftPosition != vector.Zero) // pretended hit to retain obstruction in this very tight edge case
1941 {
1942 float l0 = (m_LastLiftPosition - start).Length();
1943 float l1 = (weaponEnd - start).Length();
1944 if (l0 <= 0 || l1 <= 0)
1945 {
1946 hitFraction = 1;
1947 }
1948 else
1949 {
1950 hitFraction = l0 / l1;
1951 }
1952 hitDist = hitFraction * weaponEndDist;
1953 }
1954 }
1955 }
1956 }
1957
1958 // lift is desired
1959 if (wantsLift)
1960 {
1961 // Remap the hit distance into the <obstruction, weaponWithAttachmentLength> range as 0..1 (and beyond)
1962 float begDist = weaponObstructionDist;
1963 float endDist = weaponStartDist + weaponLength;
1964
1965 float obstFraction;
1966 if (begDist < endDist)
1967 obstFraction = Math.InverseLerp( begDist, endDist, hitDist );
1968
1969 if (hitResult)
1970 outHitObject = hitResult.obj;
1971
1972 outObstruction = 1.0 - obstFraction;
1973 m_LiftWeapon = true;
1974 return true;
1975 }
1976
1977 return false;
1978 }
void DayZPlayerCamera1stPerson(DayZPlayer pPlayer, HumanInputController pInput)
Определения DayZPlayerCamera1stPerson.c:112
proto native vector GetCurrentCameraDirection()
proto native float GetAimingHandsOffsetUD()
returns aiming hands up/down (y) offset angle
proto native float GetWeaponObstruction()
return obstruction value
proto native float GetBaseAimingAngleLR()
returns base aiming angle LR - without sway/offsets/...
proto native float GetAimingHandsOffsetLR()
returns aiming hands left/right (x) offset angle
proto native float GetBaseAimingAngleUD()
returns base aiming angle UD - without sway/offsets/...
proto native bool CameraIsFreeLook()
returns true if freelook is active
int m_CommandTypeId
Определения human.c:1153
bool IsRaised()
Определения human.c:1161
int type
Определения DayZPhysics.c:73
CollisionFlags flags
Определения DayZPhysics.c:63
Object obj
object,that we collide with (NULL if none), If hierLevel > 0 object is the proxy object
Определения DayZPhysics.c:100
vector pos
position of collision (in world coord)
Определения DayZPhysics.c:103
float m_ObstructionDistance
Определения Weapon_Base.c:67
int m_LastLiftHit
Определения Weapon_Base.c:69
float GetEffectiveAttachmentLength()
Returns effective length of attachments that influence total weapon length.
Определения Weapon_Base.c:2006
float m_ShoulderDistance
Определения Weapon_Base.c:66
void ApproximateWeaponLiftTransform(inout vector start, inout vector direction, HumanMovementState hms, HumanInputController hic, HumanCommandWeapons hcw, HumanCommandMove hcm, vector localVelocity="0 0 0")
Определения Weapon_Base.c:1570
vector m_LastLiftPosition
Определения Weapon_Base.c:68
bool LiftWeaponRaycastResultCheck(notnull RaycastRVResult res)
Return whether provided material triggers weapon lift (true) or not (false).
Определения Weapon_Base.c:2000
bool m_LiftWeapon
Определения Weapon_Base.c:51
float m_WeaponLength
Определения Weapon_Base.c:64
float ApproximateBaseObstructionLength()
Approximate ObstructionDistance for weapons with no configuration. Returned length doesn't account fo...
Определения Weapon_Base.c:1643
static float Dot(vector v1, vector v2)
Returns Dot product of vector v1 and vector v2.
Определения EnConvert.c:271
proto vector AnglesToVector()
Converts spherical coordinates (yaw, pitch, roll in degrees) to unit length vector.
DayZPlayerConstants
defined in C++
Определения dayzplayer.c:602
proto native CGame GetGame()
proto void Print(void var)
Prints content of variable to console/log.
CollisionFlags
Определения EnDebug.c:141
proto native vector Vector(float x, float y, float z)
Vector constructor from components.
proto native vector GetVelocity(notnull IEntity ent)
Returns linear velocity.
void HumanCommandMove()
Определения human.c:514
void HumanCommandWeapons()
Определения human.c:1126

Перекрестные ссылки Math::Acos(), vector::AnglesToVector(), ApproximateBaseObstructionLength(), ApproximateWeaponLiftTransform(), HumanInputController::CameraIsFreeLook(), Math::Clamp(), Math::DEG2RAD, vector::DistanceSq(), vector::Dot(), RaycastRVParams::flags, HumanCommandWeapons::GetAimingHandsOffsetLR(), HumanCommandWeapons::GetAimingHandsOffsetUD(), HumanCommandWeapons::GetBaseAimingAngleLR(), HumanCommandWeapons::GetBaseAimingAngleUD(), CGame::GetCurrentCameraDirection(), GetEffectiveAttachmentLength(), GetGame(), GetVelocity(), HumanCommandWeapons::GetWeaponObstruction(), Math::InverseLerp(), HumanMovementState::IsRaised(), LiftWeaponRaycastResultCheck(), HumanMovementState::m_CommandTypeId, m_LastLiftHit, m_LastLiftPosition, m_LiftWeapon, m_ObstructionDistance, m_ShoulderDistance, m_WeaponLength, RaycastRVResult::obj, RaycastRVResult::pos, Print(), DayZPhysics::RaycastRVProxy(), RaycastRVParams::type, Vector() и vector::Zero.

Используется в LiftWeaponCheck().