DayZ 1.30
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 строка 1651

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

Перекрестные ссылки Math::Acos(), vector::AnglesToVector(), ApproximateBaseObstructionLength(), ApproximateWeaponLiftTransform(), HumanInputController::CameraIsFreeLook(), Math::Clamp(), Math::DEG2RAD, vector::DistanceSq(), vector::Dot(), RaycastRVParams::flags, g_Game, HumanCommandWeapons::GetAimingHandsOffsetLR(), HumanCommandWeapons::GetAimingHandsOffsetUD(), HumanCommandWeapons::GetBaseAimingAngleLR(), HumanCommandWeapons::GetBaseAimingAngleUD(), GetEffectiveAttachmentLength(), GetVelocity(), HumanCommandWeapons::GetWeaponObstruction(), hitFraction, 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().