mirror of
https://github.com/rei-2/Amalgam
synced 2026-10-10 04:43:09 +08:00
improve face splash
do projectile sim for nondrag projectiles directly without vphysics fixes
This commit is contained in:
@@ -1260,6 +1260,7 @@
|
||||
<ClInclude Include="src\Features\World\World.h" />
|
||||
<ClInclude Include="src\Hooks\Direct3DDevice9.h" />
|
||||
<ClInclude Include="src\SDK\Definitions\Interfaces\CCollisionBSPData.h" />
|
||||
<ClInclude Include="src\SDK\Definitions\Interfaces\CMDLCache.h" />
|
||||
<ClInclude Include="src\SDK\Definitions\Interfaces\CStaticPropMgr.h" />
|
||||
<ClInclude Include="src\SDK\Definitions\Interfaces\CTFGameRules.h" />
|
||||
<ClInclude Include="src\SDK\Definitions\Interfaces\CTFGCClientSystem.h" />
|
||||
@@ -1293,6 +1294,7 @@
|
||||
<ClInclude Include="src\SDK\Definitions\Main\ICollideable.h" />
|
||||
<ClInclude Include="src\SDK\Definitions\Main\Ray.h" />
|
||||
<ClInclude Include="src\SDK\Definitions\Misc\CByteSwap.h" />
|
||||
<ClInclude Include="src\SDK\Definitions\Misc\CDefaultDataCacheClient.h" />
|
||||
<ClInclude Include="src\SDK\Definitions\Misc\CDiscardableArray.h" />
|
||||
<ClInclude Include="src\SDK\Definitions\Misc\CInterpolatedVar.h" />
|
||||
<ClInclude Include="src\SDK\Definitions\Main\CModel.h" />
|
||||
@@ -1308,11 +1310,18 @@
|
||||
<ClInclude Include="src\SDK\Definitions\Misc\BSPFlags.h" />
|
||||
<ClInclude Include="src\SDK\Definitions\Interfaces\IMoveHelper.h" />
|
||||
<ClInclude Include="src\SDK\Definitions\Misc\CRangeValidatedArray.h" />
|
||||
<ClInclude Include="src\SDK\Definitions\Misc\CUtlBlockMemory.h" />
|
||||
<ClInclude Include="src\SDK\Definitions\Misc\CUtlBuffer.h" />
|
||||
<ClInclude Include="src\SDK\Definitions\Misc\CUtlCharConversion.h" />
|
||||
<ClInclude Include="src\SDK\Definitions\Misc\CUtlDict.h" />
|
||||
<ClInclude Include="src\SDK\Definitions\Misc\CUtlFixedMemory.h" />
|
||||
<ClInclude Include="src\SDK\Definitions\Misc\CUtlIntrusiveList.h" />
|
||||
<ClInclude Include="src\SDK\Definitions\Misc\CUtlLinkedList.h" />
|
||||
<ClInclude Include="src\SDK\Definitions\Misc\CUtlMap.h" />
|
||||
<ClInclude Include="src\SDK\Definitions\Misc\CUtlMemory.h" />
|
||||
<ClInclude Include="src\SDK\Definitions\Misc\CUtlObjectReference.h" />
|
||||
<ClInclude Include="src\SDK\Definitions\Misc\CUtlRBTree.h" />
|
||||
<ClInclude Include="src\SDK\Definitions\Misc\CUtlShared.h" />
|
||||
<ClInclude Include="src\SDK\Definitions\Misc\CUtlString.h" />
|
||||
<ClInclude Include="src\SDK\Definitions\Misc\dt_send.h" />
|
||||
<ClInclude Include="src\SDK\Definitions\Main\IDispInfo.h" />
|
||||
@@ -1320,6 +1329,7 @@
|
||||
<ClInclude Include="src\SDK\Definitions\Misc\IMDLCache.h" />
|
||||
<ClInclude Include="src\SDK\Definitions\Misc\IPrediction.h" />
|
||||
<ClInclude Include="src\SDK\Definitions\Interfaces\ISpatialPartition.h" />
|
||||
<ClInclude Include="src\SDK\Definitions\Misc\IStudioDataCache.h" />
|
||||
<ClInclude Include="src\SDK\Definitions\Misc\ServerClass.h" />
|
||||
<ClInclude Include="src\SDK\Definitions\Misc\CSmartPtr.h" />
|
||||
<ClInclude Include="src\SDK\Definitions\Misc\TraceInfo.h" />
|
||||
|
||||
@@ -611,6 +611,16 @@
|
||||
<ClInclude Include="src\SDK\Definitions\Interfaces\CDispCollTree.h" />
|
||||
<ClInclude Include="src\SDK\Definitions\Misc\TraceInfo.h" />
|
||||
<ClInclude Include="src\Utils\Math\BaseMath.h" />
|
||||
<ClInclude Include="src\SDK\Definitions\Misc\IStudioDataCache.h" />
|
||||
<ClInclude Include="src\SDK\Definitions\Interfaces\CMDLCache.h" />
|
||||
<ClInclude Include="src\SDK\Definitions\Misc\CDefaultDataCacheClient.h" />
|
||||
<ClInclude Include="src\SDK\Definitions\Misc\CUtlDict.h" />
|
||||
<ClInclude Include="src\SDK\Definitions\Misc\CUtlMap.h" />
|
||||
<ClInclude Include="src\SDK\Definitions\Misc\CUtlRBTree.h" />
|
||||
<ClInclude Include="src\SDK\Definitions\Misc\CUtlFixedMemory.h" />
|
||||
<ClInclude Include="src\SDK\Definitions\Misc\CUtlBlockMemory.h" />
|
||||
<ClInclude Include="src\SDK\Definitions\Misc\CUtlLinkedList.h" />
|
||||
<ClInclude Include="src\SDK\Definitions\Misc\CUtlShared.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="cpp.hint" />
|
||||
|
||||
@@ -379,11 +379,11 @@ int CAimbotMelee::CanHit(Target_t& tTarget, CTFPlayer* pLocal, CTFWeaponBase* pW
|
||||
Vec3 vTraceEnd = m_vEyePos + vForward * flRange;
|
||||
|
||||
SDK::TraceHull(m_vEyePos, vTraceEnd, {}, {}, MASK_SOLID, &filter, &trace);
|
||||
bool bReturn = trace.m_pEnt && trace.m_pEnt == tTarget.m_pEntity;
|
||||
bool bReturn = trace.m_pEnt == tTarget.m_pEntity;
|
||||
if (!bReturn)
|
||||
{
|
||||
SDK::TraceHull(m_vEyePos, vTraceEnd, vSwingMins, vSwingMaxs, MASK_SOLID, &filter, &trace);
|
||||
bReturn = trace.m_pEnt && trace.m_pEnt == tTarget.m_pEntity;
|
||||
bReturn = trace.m_pEnt == tTarget.m_pEntity;
|
||||
}
|
||||
|
||||
if (bReturn && Vars::Aimbot::Melee::AutoBackstab.Value && pWeapon->GetWeaponID() == TF_WEAPON_KNIFE)
|
||||
@@ -411,7 +411,7 @@ int CAimbotMelee::CanHit(Target_t& tTarget, CTFPlayer* pLocal, CTFWeaponBase* pW
|
||||
vTraceEnd = m_vEyePos + vForward * flRange;
|
||||
|
||||
SDK::TraceHull(m_vEyePos, vTraceEnd, vSwingMins, vSwingMaxs, MASK_SOLID, &filter, &trace);
|
||||
if (trace.m_pEnt && trace.m_pEnt == tTarget.m_pEntity)
|
||||
if (trace.m_pEnt == tTarget.m_pEntity)
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,6 +16,9 @@
|
||||
#ifdef SPLASH_DEBUG5
|
||||
static std::map<std::string, int> s_mTraceCount = {};
|
||||
#endif
|
||||
#ifdef SPLASH_DEBUG2
|
||||
//#include "../../Visuals/Visuals.h"
|
||||
#endif
|
||||
|
||||
static inline std::vector<Target_t> GetTargets(CTFPlayer* pLocal, CTFWeaponBase* pWeapon)
|
||||
{
|
||||
@@ -270,6 +273,16 @@ static inline float ArmTime(CTFWeaponBase* pWeapon)
|
||||
return 0.f;
|
||||
}
|
||||
|
||||
static inline bool ShouldLob(Info_t& tInfo)
|
||||
{
|
||||
return tInfo.m_flGravity && Vars::Aimbot::Projectile::Modifiers.Value & Vars::Aimbot::Projectile::ModifiersEnum::LobAngles;
|
||||
}
|
||||
|
||||
static inline bool ShouldLob(MoveStorage& tMoveStorage, Info_t& tInfo)
|
||||
{
|
||||
return tInfo.m_bIgnoreTiming && (tMoveStorage.m_bFailed || tMoveStorage.m_pPlayer->IsOnGround());
|
||||
}
|
||||
|
||||
static inline bool AirSplash(CTFWeaponBase* pWeapon)
|
||||
{
|
||||
if (!(Vars::Aimbot::Projectile::Modifiers.Value & Vars::Aimbot::Projectile::ModifiersEnum::AirSplash))
|
||||
@@ -349,7 +362,7 @@ Directs_t CAimbotProjectile::GetDirects()
|
||||
|
||||
auto& tTarget = *m_tInfo.m_pTarget;
|
||||
uint8_t iFlags = PointFlagsEnum::Regular;
|
||||
if (m_tInfo.m_flGravity && Vars::Aimbot::Projectile::Modifiers.Value & Vars::Aimbot::Projectile::ModifiersEnum::LobAngles)
|
||||
if (ShouldLob(m_tInfo))
|
||||
iFlags |= PointFlagsEnum::Lob;
|
||||
|
||||
const Vec3 vMins = tTarget.m_pEntity->m_vecMins(), vMaxs = tTarget.m_pEntity->m_vecMaxs();
|
||||
@@ -418,37 +431,36 @@ Splashes_t CAimbotProjectile::GetSplashes()
|
||||
return vSplashes;
|
||||
|
||||
vSplashes.push_back(PointFlagsEnum::Regular);
|
||||
if (m_tInfo.m_flGravity && Vars::Aimbot::Projectile::Modifiers.Value & Vars::Aimbot::Projectile::ModifiersEnum::LobAngles)
|
||||
if (ShouldLob(m_tInfo))
|
||||
vSplashes.push_back(PointFlagsEnum::Lob);
|
||||
|
||||
return vSplashes;
|
||||
}
|
||||
|
||||
static inline std::vector<Vec3> ComputePoints(float flRadius, int iSamples, bool bSphere)
|
||||
static inline std::vector<Vec3> ComputePoints(float flRadius, int iSamples)
|
||||
{
|
||||
std::vector<Vec3> vPoints = { { Vec3(0.f, 0.f, -1.f) * flRadius } };
|
||||
if (!iSamples)
|
||||
return vPoints;
|
||||
|
||||
if (bSphere)
|
||||
vPoints.reserve(iSamples + 1);
|
||||
|
||||
float flRotateX = Vars::Aimbot::Projectile::SplashRotateX.Value < 0.f ? SDK::StdRandomFloat(0.f, 360.f) : Vars::Aimbot::Projectile::SplashRotateX.Value;
|
||||
float flRotateY = Vars::Aimbot::Projectile::SplashRotateY.Value < 0.f ? SDK::StdRandomFloat(0.f, 360.f) : Vars::Aimbot::Projectile::SplashRotateY.Value;
|
||||
|
||||
float a = Math::PI * (3.f - sqrtf(5.f));
|
||||
for (int n = 0; n < iSamples; n++)
|
||||
{
|
||||
vPoints.reserve(iSamples + 1);
|
||||
float t = a * n;
|
||||
float y = 1 - (n / (iSamples - 1.f)) * 2;
|
||||
float r = sqrtf(1 - powf(y, 2));
|
||||
float x = cosf(t) * r;
|
||||
float z = sinf(t) * r;
|
||||
|
||||
float flRotateX = Vars::Aimbot::Projectile::SplashRotateX.Value < 0.f ? SDK::StdRandomFloat(0.f, 360.f) : Vars::Aimbot::Projectile::SplashRotateX.Value;
|
||||
float flRotateY = Vars::Aimbot::Projectile::SplashRotateY.Value < 0.f ? SDK::StdRandomFloat(0.f, 360.f) : Vars::Aimbot::Projectile::SplashRotateY.Value;
|
||||
Vec3 vPoint = Vec3(x, y, z) * flRadius;
|
||||
vPoint = Math::RotatePoint(vPoint, {}, { flRotateX, flRotateY });
|
||||
|
||||
float a = Math::PI * (3.f - sqrtf(5.f));
|
||||
for (int n = 0; n < iSamples; n++)
|
||||
{
|
||||
float t = a * n;
|
||||
float y = 1 - (n / (iSamples - 1.f)) * 2;
|
||||
float r = sqrtf(1 - powf(y, 2));
|
||||
float x = cosf(t) * r;
|
||||
float z = sinf(t) * r;
|
||||
|
||||
Vec3 vPoint = Vec3(x, y, z) * flRadius;
|
||||
vPoint = Math::RotatePoint(vPoint, {}, { flRotateX, flRotateY });
|
||||
|
||||
vPoints.push_back(vPoint);
|
||||
}
|
||||
vPoints.push_back(vPoint);
|
||||
}
|
||||
|
||||
return vPoints;
|
||||
@@ -520,53 +532,111 @@ static inline void HandleTrace(const Vec3& vPoint, std::vector<Setup_t>& vPoints
|
||||
}
|
||||
|
||||
static float s_flTotal = 0.f;
|
||||
static inline void HandleFace(const Face_t& tFace, std::vector<Setup_t>& vPoints, float flDensity, float flRadius, float flCutoff, const Vec3& vTargetEye, const Vec3& vTargetCenter, Info_t& tInfo, CGameTrace& trace, ITraceFilter& filter)
|
||||
static inline void HandleFace(Face_t& tFace, std::vector<Setup_t>& vPoints, float flDensity, float flRadius, float flCutoff, const Vec3& vTargetEye, const Vec3& vTargetCenter, const Vec3& vTargetOrigin, Info_t& tInfo, CGameTrace& trace, ITraceFilter& filter)
|
||||
{
|
||||
float flRadiusSqr = powf(flRadius, 2);
|
||||
float flRadius2Sqr = flRadiusSqr * 4;
|
||||
int nMask = MASK_SHOT;
|
||||
if (F::ProjSim.m_pObj->m_dragCoefficient && F::ProjSim.m_pObj->m_angDragBasis)
|
||||
nMask |= CONTENTS_DISPSOLID;
|
||||
int nMask = F::ProjSim.m_bPhysics ? MASK_SHOT | CONTENTS_DISPSOLID : MASK_SHOT;
|
||||
|
||||
for (int i = 0; ++i < tFace.m_vVertices.size() - 1;)
|
||||
std::vector<Vec3> vVertices, vEpsilon;
|
||||
if (tFace.m_iType != FaceTypeEnum::Prop)
|
||||
vVertices = tFace.m_vVertices;
|
||||
else
|
||||
Math::ExpandPolygon(vVertices, tFace.m_vVertices, tFace.m_vNormal, SDK::StdRandomFloat(0.f, DIST_EPSILON), &vTargetEye);
|
||||
|
||||
for (int i = 0, n = int(tFace.m_vVertices.size()), o = SDK::StdRandomInt(0, n - 1); ++i < n - 1;)
|
||||
{
|
||||
const Vec3& vVertex1 = tFace.m_vVertices[0], &vVertex2 = tFace.m_vVertices[i], &vVertex3 = tFace.m_vVertices[i + 1];
|
||||
Vec3& vVertex1 = tFace.m_vVertices[o], &vVertex2 = tFace.m_vVertices[(o + i) % n], &vVertex3 = tFace.m_vVertices[(o + i + 1) % n];
|
||||
|
||||
Vec3 vDir21 = vVertex2 - vVertex1, vDir31 = vVertex3 - vVertex1;
|
||||
float flArea = vDir21.Cross(vDir31).Length() / 2;
|
||||
float flSamples = flDensity * flArea / flRadius2Sqr;
|
||||
int iSamples = flSamples < flCutoff ? fmodf(s_flTotal += flSamples, flCutoff) < flSamples : ceilf(flSamples);
|
||||
int iSamples = flSamples > flCutoff ? ceilf(flSamples) : fmodf(s_flTotal += flSamples, flCutoff) < flSamples;
|
||||
if (!iSamples)
|
||||
continue;
|
||||
|
||||
#if defined(SPLASH_DEBUG2) && defined(WORLD_DEBUG)
|
||||
if (iSamples)
|
||||
F::World.DrawFace({ { vVertex1, vVertex2, vVertex3 }, tFace.m_vNormal }, DrawTypeEnum::Edges | DrawTypeEnum::Faces);
|
||||
// don't particularly like the hacky random epsilons
|
||||
int iFaceClosest = SDK::StdRandomInt(iSamples < 2 ? 0 : iSamples < 4 ? 1 : 2, iSamples < 2 ? 1 : 2);
|
||||
//int iEdgeClosest = SDK::StdRandomInt(iSamples < 8 ? 0 : iSamples < 16 ? 1 : 2, iSamples < 8 ? 1 : 2); // eats up a bit too much performance for my liking
|
||||
int iEdgeRandom = SDK::StdRandomInt(iSamples < 8 ? 0 : iSamples < 16 ? 1 : 2, iSamples < 3 ? 0 : iSamples < 12 ? 1 : 2);
|
||||
iEdgeRandom += iFaceClosest; //iEdgeClosest += iFaceClosest, iEdgeRandom += iEdgeClosest; //, iSamples += iEdgeRandom;
|
||||
#ifdef SPLASH_DEBUG2
|
||||
Color_t tColor = { byte(SDK::StdRandomInt(0, 255)), byte(SDK::StdRandomInt(0, 255)), byte(SDK::StdRandomInt(0, 255)) };
|
||||
#ifdef WORLD_DEBUG
|
||||
F::World.DrawFace({ { vVertex1, vVertex2, vVertex3 }, tFace.m_vNormal, tFace.m_iType }, DrawTypeEnum::Edges | DrawTypeEnum::Faces, tColor);
|
||||
#endif
|
||||
|
||||
for (int i = 0; i < iSamples; i++)
|
||||
#ifdef DEBUG_TEXT
|
||||
F::Visuals.AddDebugText(std::format("{}:{}:{}"/*:{}"*/, iFaceClosest, /*iEdgeClosest,*/ iEdgeRandom, iSamples), (vVertex1 + vVertex2 + vVertex3) / 3, tColor);
|
||||
#endif
|
||||
#endif
|
||||
for (int s = 0; s < iSamples; s++)
|
||||
{
|
||||
float flRandom1 = SDK::StdRandomFloat(), flRandom2 = SDK::StdRandomFloat();
|
||||
if (flRandom1 + flRandom2 > 1)
|
||||
flRandom1 = 1 - flRandom1, flRandom2 = 1 - flRandom2;
|
||||
|
||||
Vec3 vPoint = vVertex1 + vDir21 * flRandom1 + vDir31 * flRandom2 + tFace.m_vNormal * (tInfo.m_vHull + CALC_EPSILON);
|
||||
Vec3 vPoint, vNormal = tFace.m_vNormal; bool bInside = true;
|
||||
if (s < iFaceClosest) // closest point
|
||||
{
|
||||
float flEpsilon = s == 0 && (tFace.m_iType == FaceTypeEnum::BoxBrush || iFaceClosest != 1 || SDK::StdRandomBool()) ? CALC_EPSILON : DIST_EPSILON;
|
||||
vPoint = Math::ClosestPointOnTriangle(vTargetOrigin, vVertex1, vVertex2, vVertex3, &bInside);
|
||||
vPoint += { SDK::StdRandomFloat(-flEpsilon, flEpsilon), SDK::StdRandomFloat(-flEpsilon, flEpsilon), SDK::StdRandomFloat(-flEpsilon, flEpsilon) };
|
||||
}
|
||||
//else if (s < iEdgeClosest) // closest point on edge
|
||||
//{
|
||||
// float flEpsilon = SDK::StdRandomBool() ? CALC_EPSILON : DIST_EPSILON; bInside = false;
|
||||
// switch (SDK::StdRandomInt(0, 2))
|
||||
// {
|
||||
// case 0: vPoint = Math::ClosestPointOnLine(vTargetOrigin, vVertex1, vVertex2); break;
|
||||
// case 1: vPoint = Math::ClosestPointOnLine(vTargetOrigin, vVertex2, vVertex3); break;
|
||||
// case 2: vPoint = Math::ClosestPointOnLine(vTargetOrigin, vVertex3, vVertex1); break;
|
||||
// }
|
||||
// vPoint += { SDK::StdRandomFloat(-flEpsilon, flEpsilon), SDK::StdRandomFloat(-flEpsilon, flEpsilon), SDK::StdRandomFloat(-flEpsilon, flEpsilon) };
|
||||
//}
|
||||
else if (s < iEdgeRandom) // random point on edge
|
||||
{
|
||||
float flEpsilon = SDK::StdRandomBool() ? CALC_EPSILON : DIST_EPSILON; bInside = false;
|
||||
switch (SDK::StdRandomInt(0, 2))
|
||||
{
|
||||
case 0: vPoint = vVertex1.Lerp(vVertex2, SDK::StdRandomFloat()); break;
|
||||
case 1: vPoint = vVertex2.Lerp(vVertex3, SDK::StdRandomFloat()); break;
|
||||
case 2: vPoint = vVertex3.Lerp(vVertex1, SDK::StdRandomFloat()); break;
|
||||
}
|
||||
vPoint += { SDK::StdRandomFloat(-flEpsilon, flEpsilon), SDK::StdRandomFloat(-flEpsilon, flEpsilon), SDK::StdRandomFloat(-flEpsilon, flEpsilon) };
|
||||
}
|
||||
else // random point on face
|
||||
{
|
||||
float flRandom1 = SDK::StdRandomFloat(), flRandom2 = SDK::StdRandomFloat();
|
||||
if (flRandom1 + flRandom2 > 1)
|
||||
flRandom1 = 1 - flRandom1, flRandom2 = 1 - flRandom2;
|
||||
vPoint = vVertex1 + vDir21 * flRandom1 + vDir31 * flRandom2;
|
||||
}
|
||||
vPoint += vNormal * (tInfo.m_vHull + CALC_EPSILON);
|
||||
if (vPoint.DistToSqr(vTargetCenter) > flRadiusSqr)
|
||||
continue;
|
||||
|
||||
if (!bInside)
|
||||
{
|
||||
if (vEpsilon.empty())
|
||||
Math::ExpandPolygon(vEpsilon = vVertices, tFace.m_vNormal, -DIST_EPSILON);
|
||||
Math::ClosestPointOnPolygon(vPoint, vEpsilon, vNormal, &bInside);
|
||||
|
||||
if (tFace.m_iType == FaceTypeEnum::Prop && !bInside)
|
||||
vPoint += tFace.m_vNormal * SDK::StdRandomFloat(0.f, DIST_EPSILON);
|
||||
}
|
||||
|
||||
#ifdef SPLASH_DEBUG5
|
||||
s_mTraceCount[__FUNCTION__": point contents"]++;
|
||||
if (bInside) s_mTraceCount[__FUNCTION__": point contents"]++;
|
||||
#endif
|
||||
if (I::EngineTrace->GetPointContents(vPoint) & MASK_SOLID)
|
||||
if (bInside && I::EngineTrace->GetPointContents(vPoint) & MASK_SOLID)
|
||||
continue;
|
||||
|
||||
if (tFace.m_iType == FaceTypeEnum::Prop)
|
||||
vPoint += tFace.m_vNormal * DIST_EPSILON;
|
||||
int nSubMask = nMask;
|
||||
if (!bInside)
|
||||
vNormal = (vTargetEye - vPoint).Normalized(), nSubMask &= ~CONTENTS_MOVEABLE;
|
||||
|
||||
SDK::Trace(vPoint + tFace.m_vNormal * tInfo.m_flNormalOffset, vTargetEye, nMask, &filter, &trace);
|
||||
SDK::Trace(vPoint + vNormal * tInfo.m_flNormalOffset, vTargetEye, nSubMask, &filter, &trace);
|
||||
#ifdef SPLASH_DEBUG5
|
||||
s_mTraceCount[__FUNCTION__": vispos"]++;
|
||||
#endif
|
||||
#ifdef SPLASH_DEBUG2
|
||||
DrawTrace(!trace.DidHit(), Vars::Colors::IndicatorMisc.Value, trace);
|
||||
DrawTrace(trace.fraction == 1.f, Vars::Colors::IndicatorMisc.Value, trace);
|
||||
#endif
|
||||
if (trace.fraction != 1.f)
|
||||
continue;
|
||||
@@ -594,7 +664,7 @@ void CAimbotProjectile::SetupSplashPoints(Vec3& vOrigin, std::vector<Setup_t>& v
|
||||
if (pAngle)
|
||||
{
|
||||
Vec3 vForward, vRight, vUp; Math::AngleVectors(*pAngle, &vForward, &vRight, &vUp);
|
||||
Vec3 vShootPos = m_tInfo.m_vLocalEye + (vForward * m_tInfo.m_vOffset.x) + (vRight * m_tInfo.m_vOffset.y) + (vUp * m_tInfo.m_vOffset.z);
|
||||
Vec3 vShootPos = m_tInfo.m_vLocalEye + vForward * m_tInfo.m_vOffset.x + vRight * m_tInfo.m_vOffset.y + vUp * m_tInfo.m_vOffset.z;
|
||||
vForward = (vShootPos - vPoint).Normalized();
|
||||
return vForward.Dot(vNormal) > 0;
|
||||
}
|
||||
@@ -606,9 +676,10 @@ void CAimbotProjectile::SetupSplashPoints(Vec3& vOrigin, std::vector<Setup_t>& v
|
||||
};
|
||||
|
||||
// Trace
|
||||
int iPoints = !m_tInfo.m_flGravity ? Vars::Aimbot::Projectile::SplashPointsDirect.Value : Vars::Aimbot::Projectile::SplashPointsArc.Value;
|
||||
int iPoints = Vars::Aimbot::Projectile::SplashMode.Value == Vars::Aimbot::Projectile::SplashModeEnum::Face && !bAirSplash ? 0
|
||||
: !m_tInfo.m_flGravity ? Vars::Aimbot::Projectile::SplashPointsDirect.Value : Vars::Aimbot::Projectile::SplashPointsArc.Value;
|
||||
{
|
||||
auto vPoints = ComputePoints(flRadius, iPoints, Vars::Aimbot::Projectile::SplashMode.Value == Vars::Aimbot::Projectile::SplashModeEnum::Trace || bAirSplash);
|
||||
auto vPoints = ComputePoints(flRadius, iPoints);
|
||||
|
||||
for (int i = 0; i < vPoints.size(); i++)
|
||||
{
|
||||
@@ -626,7 +697,7 @@ void CAimbotProjectile::SetupSplashPoints(Vec3& vOrigin, std::vector<Setup_t>& v
|
||||
CalculateAngle(m_tInfo.m_vLocalEye, tPoint.m_vPoint, 0, tPoint.m_tSolution, iFlags);
|
||||
if (tPoint.m_tSolution.m_iCalculated == CalculateResultEnum::Bad)
|
||||
return false;
|
||||
vPoint -= Vec3(0, 0, (m_tInfo.m_flGravity * 800.f * powf(tPoint.m_tSolution.m_flTime, 2)) / 2);
|
||||
vPoint -= Vec3(0, 0, m_tInfo.m_flGravity * powf(tPoint.m_tSolution.m_flTime, 2) / 2);
|
||||
vAngle = Vec3(tPoint.m_tSolution.m_flPitch, tPoint.m_tSolution.m_flYaw);
|
||||
}
|
||||
return fCheckNormal(trace.plane.normal, vPoint, &vAngle);
|
||||
@@ -655,8 +726,8 @@ void CAimbotProjectile::SetupSplashPoints(Vec3& vOrigin, std::vector<Setup_t>& v
|
||||
}
|
||||
|
||||
// Face
|
||||
float flDensity = !m_tInfo.m_flGravity ? Vars::Aimbot::Projectile::SplashDensityDirect.Value : Vars::Aimbot::Projectile::SplashDensityArc.Value;
|
||||
if (Vars::Aimbot::Projectile::SplashMode.Value == Vars::Aimbot::Projectile::SplashModeEnum::Face && flDensity)
|
||||
if (float flDensity = !m_tInfo.m_flGravity ? Vars::Aimbot::Projectile::SplashDensityDirect.Value : Vars::Aimbot::Projectile::SplashDensityArc.Value;
|
||||
Vars::Aimbot::Projectile::SplashMode.Value == Vars::Aimbot::Projectile::SplashModeEnum::Face && flDensity)
|
||||
{
|
||||
Vec3 vMins = vTargetCenter - flRadius, vMaxs = vTargetCenter + flRadius;
|
||||
|
||||
@@ -664,14 +735,14 @@ void CAimbotProjectile::SetupSplashPoints(Vec3& vOrigin, std::vector<Setup_t>& v
|
||||
{
|
||||
Vec3 vPoint = std::reduce(vVertices.begin(), vVertices.end()) / vVertices.size(), vAngle;
|
||||
if (!m_tInfo.m_flGravity)
|
||||
vAngle = Math::CalcAngle(m_tInfo.m_vLocalEye, trace.endpos);
|
||||
vAngle = Math::CalcAngle(m_tInfo.m_vLocalEye, vPoint);
|
||||
else
|
||||
{
|
||||
Point_t tPoint = { vPoint, {} };
|
||||
CalculateAngle(m_tInfo.m_vLocalEye, tPoint.m_vPoint, 0, tPoint.m_tSolution, iFlags);
|
||||
if (tPoint.m_tSolution.m_iCalculated == CalculateResultEnum::Bad)
|
||||
return false;
|
||||
vPoint -= Vec3(0, 0, (m_tInfo.m_flGravity * 800.f * powf(tPoint.m_tSolution.m_flTime, 2)) / 2);
|
||||
vPoint -= Vec3(0, 0, m_tInfo.m_flGravity * powf(tPoint.m_tSolution.m_flTime, 2) / 2);
|
||||
vAngle = Vec3(tPoint.m_tSolution.m_flPitch, tPoint.m_tSolution.m_flYaw);
|
||||
}
|
||||
return fCheckNormal(vNormal, vPoint, &vAngle);
|
||||
@@ -686,7 +757,7 @@ void CAimbotProjectile::SetupSplashPoints(Vec3& vOrigin, std::vector<Setup_t>& v
|
||||
float flCutoff = Vars::Aimbot::Projectile::SplashSamplesCutoff.Value * powf(vFaces.size(), 2); s_flTotal = SDK::StdRandomFloat();
|
||||
for (auto& tFace : vFaces)
|
||||
{
|
||||
HandleFace(tFace, vSplashPoints, flDensity, flRadius, flCutoff, vTargetEye, vTargetCenter, m_tInfo, trace, filter);
|
||||
HandleFace(tFace, vSplashPoints, flDensity, flRadius, flCutoff, vTargetEye, vTargetCenter, vOrigin, m_tInfo, trace, filter);
|
||||
//#if defined(SPLASH_DEBUG2) && defined(WORLD_DEBUG)
|
||||
// F::World.DrawFace(tFace, DrawTypeEnum::Edges | DrawTypeEnum::Faces);
|
||||
//#endif
|
||||
@@ -720,7 +791,7 @@ std::vector<Point_t> CAimbotProjectile::GetSplashPoints(Vec3 vOrigin, std::vecto
|
||||
flRadiusAirSqr = powf(m_tInfo.m_flRadius * Math::RemapVal(TICKS_TO_TIME(iSimTime), flLiveTime, flLiveTime + flRampTime, flAirdetRadius, 1.f), 2);
|
||||
}
|
||||
bool bLob = iFlags & CalculateFlagsEnum::LobAngle;
|
||||
int iTolerance = m_tInfo.m_bIgnoreTiming && bLob ? std::numeric_limits<int>::max() : !m_tInfo.m_iArmTime ? 0 : -1;
|
||||
int iTolerance = m_tInfo.m_bIgnoreTiming && bLob ? std::numeric_limits<int>::max() : m_tInfo.m_iArmTime ? -1 : 0;
|
||||
int iLimit = !bFirst ? m_tInfo.m_iSplashRestrict : std::max(m_tInfo.m_iSplashRestrict, Vars::Aimbot::Projectile::SplashRestrictFirst.Value);
|
||||
bool bSort = !bLob || !m_tInfo.m_bIgnoreTiming;
|
||||
|
||||
@@ -787,20 +858,20 @@ static inline Vec3 PullPoint(const Vec3& vPoint, Vec3 vLocalPos, Info_t& tInfo,
|
||||
{
|
||||
auto fHeightenLocalPos = [&]()
|
||||
{ // basic trajectory pass
|
||||
const float flGrav = tInfo.m_flGravity * 800.f;
|
||||
float flGrav = tInfo.m_flGravity;
|
||||
if (!flGrav)
|
||||
return vPoint;
|
||||
|
||||
const Vec3 vDelta = vTargetPos - vLocalPos;
|
||||
const float flDist = vDelta.Length2D();
|
||||
Vec3 vDelta = vTargetPos - vLocalPos;
|
||||
float flDist = vDelta.Length2D();
|
||||
|
||||
const float flRoot = powf(tInfo.m_flVelocity, 4) - flGrav * (flGrav * powf(flDist, 2) + 2.f * vDelta.z * powf(tInfo.m_flVelocity, 2));
|
||||
float flRoot = powf(tInfo.m_flVelocity, 4) - flGrav * (flGrav * powf(flDist, 2) + 2.f * vDelta.z * powf(tInfo.m_flVelocity, 2));
|
||||
if (flRoot < 0.f)
|
||||
return vPoint;
|
||||
float flPitch = atan((powf(tInfo.m_flVelocity, 2) - sqrt(flRoot)) / (flGrav * flDist));
|
||||
|
||||
float flTime = flDist / (cos(flPitch) * tInfo.m_flVelocity) - tInfo.m_flOffsetTime;
|
||||
return vLocalPos + Vec3(0, 0, (flGrav * powf(flTime, 2)) / 2);
|
||||
return vLocalPos + Vec3(0, 0, flGrav * powf(flTime, 2) / 2);
|
||||
};
|
||||
|
||||
vLocalPos = fHeightenLocalPos();
|
||||
@@ -821,7 +892,7 @@ static inline float GetDrag(float flVelocity, ProjectileInfo* pInfo, int iFlags)
|
||||
{
|
||||
auto fGetDrag = [&](std::function<float()> fGetTypeDrag)
|
||||
{
|
||||
if (!F::ProjSim.m_pObj->m_dragCoefficient || !F::ProjSim.m_pObj->m_dragBasis)
|
||||
if (!F::ProjSim.m_bPhysics)
|
||||
return 0.f;
|
||||
|
||||
if (Vars::Aimbot::Projectile::DragOverride.Value)
|
||||
@@ -902,7 +973,7 @@ static inline float GetDrag(float flVelocity, ProjectileInfo* pInfo, int iFlags)
|
||||
static inline bool GetAngle(const Vec3& vLocalPos, const Vec3& vTargetPos, int iFlags, Info_t& tInfo, float& flPitch, float& flYaw, float& flTime)
|
||||
{
|
||||
float flVelocity = tInfo.m_flVelocity;
|
||||
float flGrav = tInfo.m_flGravity * 800.f;
|
||||
float flGrav = tInfo.m_flGravity;
|
||||
Vec3 vDelta = vTargetPos - vLocalPos;
|
||||
float flDist = vDelta.Length2D();
|
||||
float flDrag = GetDrag(flVelocity, F::ProjSim.m_pCurrent, iFlags);
|
||||
@@ -960,7 +1031,7 @@ void CAimbotProjectile::CalculateAngle(const Vec3& vLocalPos, const Vec3& vTarge
|
||||
float flPitch, flYaw;
|
||||
{ // basic trajectory pass
|
||||
//Vec3 vForward, vRight, vUp; Math::AngleVectors(Math::CalcAngle(vLocalPos, vTargetPos), &vForward, &vRight, &vUp);
|
||||
//Vec3 vShootPos = vLocalPos + (vForward * m_tInfo.m_vOffset.x) + (vRight * m_tInfo.m_vOffset.y) + (vUp * m_tInfo.m_vOffset.z);
|
||||
//Vec3 vShootPos = vLocalPos + vForward * m_tInfo.m_vOffset.x + vRight * m_tInfo.m_vOffset.y + vUp * m_tInfo.m_vOffset.z;
|
||||
if (!GetAngle(vLocalPos, vTargetPos, iFlags, m_tInfo, flPitch, flYaw, tOut.m_flTime))
|
||||
{
|
||||
tOut.m_iCalculated = CalculateResultEnum::Bad;
|
||||
@@ -1134,7 +1205,7 @@ bool CAimbotProjectile::TestAngle(const Vec3& vPoint, const Vec3& vAngles, int i
|
||||
|
||||
#ifdef SPLASH_DEBUG4
|
||||
Vec3 vHull = m_tProjInfo.m_vHull.Max(1);
|
||||
G::BoxStorage.emplace_back(vPoint, -vHull, vHull, Vec3(), I::GlobalVars->curtime + 5.f, Color_t(255, 0, 0), Color_t(0, 0, 0, 0));
|
||||
G::BoxStorage.emplace_back(vPoint, -vHull, vHull, Vec3(), I::GlobalVars->curtime + 5.f, Color_t(0, 0, 0), Color_t(0, 0, 0, 0));
|
||||
#endif
|
||||
|
||||
if (!m_tProjInfo.m_flGravity)
|
||||
@@ -1146,7 +1217,7 @@ bool CAimbotProjectile::TestAngle(const Vec3& vPoint, const Vec3& vAngles, int i
|
||||
#ifdef SPLASH_DEBUG4
|
||||
G::LineStorage.emplace_back(std::pair<Vec3, Vec3>(m_tProjInfo.m_vPos, trace.endpos), I::GlobalVars->curtime + 5.f, Color_t(0, 0, 0));
|
||||
#endif
|
||||
if (trace.fraction < 0.999f && trace.m_pEnt != tTarget.m_pEntity)
|
||||
if (Math::FullFraction(m_tProjInfo.m_vPos, vPoint, trace) < 0.999f && trace.m_pEnt != tTarget.m_pEntity)
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1157,7 +1228,7 @@ bool CAimbotProjectile::TestAngle(const Vec3& vPoint, const Vec3& vAngles, int i
|
||||
bool bDidHit = false;
|
||||
Vec3 vNew = F::ProjSim.GetOrigin();
|
||||
int iTimingTolerance = TIME_TO_TICKS(m_tInfo.m_flBoundsTime);
|
||||
float flRadiusSqr = powf(m_tProjInfo.m_flVelocity * TICK_INTERVAL + m_tProjInfo.m_vHull.z, 2);
|
||||
float flRadiusSqr = iType != PointTypeEnum::Direct ? powf(m_tProjInfo.m_flVelocity * TICK_INTERVAL + m_tProjInfo.m_vHull.z, 2) : std::numeric_limits<float>::max();
|
||||
uint8_t iTraceInterval = iFlags == PointFlagsEnum::Lob ? Vars::Aimbot::Projectile::LobTraceInterval.Value
|
||||
: iType != PointTypeEnum::Direct ? Vars::Aimbot::Projectile::SplashTraceInterval.Value
|
||||
: Vars::Aimbot::Projectile::DirectTraceInterval.Value;
|
||||
@@ -1192,10 +1263,9 @@ bool CAimbotProjectile::TestAngle(const Vec3& vPoint, const Vec3& vAngles, int i
|
||||
{
|
||||
case PointTypeEnum::Direct:
|
||||
case PointTypeEnum::Geometry:
|
||||
bHit = trace.DidHit();
|
||||
break;
|
||||
bHit = trace.DidHit(); break;
|
||||
case PointTypeEnum::Air:
|
||||
bHit = trace.endpos.DistToSqr(vPoint) < flRadiusSqr || trace.DidHit();
|
||||
bHit = trace.endpos.DistToSqr(vPoint) < flRadiusSqr || trace.DidHit(); break;
|
||||
}
|
||||
|
||||
if (bHit)
|
||||
@@ -1204,24 +1274,22 @@ bool CAimbotProjectile::TestAngle(const Vec3& vPoint, const Vec3& vAngles, int i
|
||||
switch (iType)
|
||||
{
|
||||
case PointTypeEnum::Direct:
|
||||
bTarget = trace.m_pEnt == tTarget.m_pEntity, bValid = bTarget && iSimTime - n < iTimingTolerance;
|
||||
break;
|
||||
bTarget = trace.m_pEnt == tTarget.m_pEntity, bValid = bTarget && iSimTime - n < iTimingTolerance; break;
|
||||
case PointTypeEnum::Geometry:
|
||||
bValid = trace.endpos.DistToSqr(vPoint) < flRadiusSqr;
|
||||
break;
|
||||
bValid = trace.endpos.DistToSqr(vPoint) < flRadiusSqr; break;
|
||||
case PointTypeEnum::Air:
|
||||
bValid = !trace.DidHit();
|
||||
break;
|
||||
bValid = !trace.DidHit(); break;
|
||||
}
|
||||
if (bValid && iType != PointTypeEnum::Direct)
|
||||
{
|
||||
CGameTrace eyeTrace = {};
|
||||
SDK::Trace(trace.endpos + m_tInfo.m_flNormalOffset * trace.plane.normal, tTarget.m_vPos + m_tInfo.m_vTargetEye, MASK_SHOT, &filter, &eyeTrace);
|
||||
SDK::Trace(trace.endpos + trace.plane.normal * m_tInfo.m_flNormalOffset, tTarget.m_vPos + m_tInfo.m_vTargetEye, MASK_SHOT, &filter, &eyeTrace);
|
||||
bValid = eyeTrace.fraction == 1.f;
|
||||
#ifdef SPLASH_DEBUG5
|
||||
s_mTraceCount[__FUNCTION__": splash eye trace"]++;
|
||||
#endif
|
||||
#ifdef SPLASH_DEBUG4
|
||||
//G::LineStorage.emplace_back(std::pair<Vec3, Vec3>(trace.endpos, trace.endpos + trace.plane.normal * m_tInfo.m_flNormalOffset), I::GlobalVars->curtime + 5.f, Color_t(255, 0, 255));
|
||||
G::LineStorage.emplace_back(std::pair<Vec3, Vec3>(eyeTrace.startpos, eyeTrace.endpos), I::GlobalVars->curtime + 5.f, Color_t(255, 0, 255));
|
||||
G::BoxStorage.emplace_back(trace.endpos + m_tInfo.m_flNormalOffset * trace.plane.normal, -vHull, vHull, Vec3(), I::GlobalVars->curtime + 5.f, Color_t(255, 0, 255), Color_t(0, 0, 0, 0));
|
||||
#endif
|
||||
@@ -1230,17 +1298,8 @@ bool CAimbotProjectile::TestAngle(const Vec3& vPoint, const Vec3& vAngles, int i
|
||||
#ifdef SPLASH_DEBUG4
|
||||
if (bValid)
|
||||
G::BoxStorage.emplace_back(vPoint, -vHull, vHull, Vec3(), I::GlobalVars->curtime + 5.f, Color_t(0, 255, 0), Color_t(0, 0, 0, 0));
|
||||
else if (bTarget)
|
||||
G::BoxStorage.emplace_back(vPoint, -vHull, vHull, Vec3(), I::GlobalVars->curtime + 5.f, Color_t(0, 0, 255), Color_t(0, 0, 0, 0));
|
||||
else
|
||||
{
|
||||
G::BoxStorage.emplace_back(vPoint, -vHull, vHull, Vec3(), I::GlobalVars->curtime + 5.f, Color_t(127, 0, 255), Color_t(0, 0, 0, 0));
|
||||
if (iType != PointTypeEnum::Direct)
|
||||
{
|
||||
G::BoxStorage.emplace_back(trace.endpos, Vec3::Get(-1), Vec3::Get(1), Vec3(), I::GlobalVars->curtime + 5.f, Color_t(0, 0, 0), Color_t(0, 0, 0, 0));
|
||||
G::BoxStorage.emplace_back(vPoint, Vec3::Get(-1), Vec3::Get(1), Vec3(), I::GlobalVars->curtime + 5.f, Color_t(255, 255, 255), Color_t(0, 0, 0, 0));
|
||||
}
|
||||
}
|
||||
G::BoxStorage.emplace_back(vPoint, -vHull, vHull, Vec3(), I::GlobalVars->curtime + 5.f, Color_t(255, 0, 0), Color_t(0, 0, 0, 0));
|
||||
#endif
|
||||
|
||||
if (bValid)
|
||||
@@ -1272,7 +1331,7 @@ bool CAimbotProjectile::TestAngle(const Vec3& vPoint, const Vec3& vAngles, int i
|
||||
Vec3 vOffset = tOriginal.m_vOrigin - tTarget.m_vPos;
|
||||
Vec3 vPos = trace.endpos + F::ProjSim.GetVelocity().Normalized() * 16 + vOffset;
|
||||
|
||||
float flClosest = std::numeric_limits<float>::max(); int iClosest = -1;
|
||||
float flLowestDistance = std::numeric_limits<float>::max(); int iClosest = -1;
|
||||
for (int nHitbox = 0; nHitbox < pSet->numhitboxes; ++nHitbox)
|
||||
{
|
||||
auto pBox = pSet->pHitbox(nHitbox);
|
||||
@@ -1280,12 +1339,9 @@ bool CAimbotProjectile::TestAngle(const Vec3& vPoint, const Vec3& vAngles, int i
|
||||
|
||||
Vec3 vCenter; Math::VectorTransform({}, aBones[pBox->bone], vCenter);
|
||||
|
||||
const float flDist = vPos.DistToSqr(vCenter);
|
||||
if (flDist < flClosest)
|
||||
{
|
||||
flClosest = flDist;
|
||||
iClosest = nHitbox;
|
||||
}
|
||||
const float flDistance = vPos.DistToSqr(vCenter);
|
||||
if (flDistance < flLowestDistance)
|
||||
iClosest = nHitbox, flLowestDistance = flDistance;
|
||||
}
|
||||
if (iClosest != HITBOX_HEAD)
|
||||
break;
|
||||
@@ -1300,7 +1356,6 @@ bool CAimbotProjectile::TestAngle(const Vec3& vPoint, const Vec3& vAngles, int i
|
||||
filter.pSkip = tTarget.m_pEntity;
|
||||
filter.iPlayer = PLAYER_NONE;
|
||||
filter.bMisc = false;
|
||||
flRadiusSqr = std::numeric_limits<float>::max();
|
||||
continue;
|
||||
}
|
||||
else
|
||||
@@ -1329,7 +1384,7 @@ bool CAimbotProjectile::HandlePoint(const Vec3& vOrigin, int iSimTime, float flP
|
||||
m_tInfo.m_pTarget->m_vPos = vOrigin;
|
||||
|
||||
int iOriginalSimTime = iSimTime;
|
||||
if (m_tInfo.m_iArmTime || m_tInfo.m_bIgnoreTiming && iFlags == PointFlagsEnum::Lob)
|
||||
if (m_tInfo.m_iArmTime && iType == PointTypeEnum::Geometry || m_tInfo.m_bIgnoreTiming && iFlags == PointFlagsEnum::Lob)
|
||||
{
|
||||
if (flTime > m_tProjInfo.m_flLifetime)
|
||||
return false;
|
||||
@@ -1344,7 +1399,7 @@ bool CAimbotProjectile::HandlePoint(const Vec3& vOrigin, int iSimTime, float flP
|
||||
bReturn = m_iResult = true;
|
||||
m_flTimeTo = flTime + m_tInfo.m_flLatency;
|
||||
}
|
||||
else if (m_iResult != 1 && !m_tInfo.m_pProjectile)
|
||||
else if (!m_iResult && !m_tInfo.m_pProjectile)
|
||||
{
|
||||
switch (Vars::Aimbot::General::AimType.Value)
|
||||
{
|
||||
@@ -1381,7 +1436,7 @@ bool CAimbotProjectile::HandlePoint(const Vec3& vOrigin, int iSimTime, float flP
|
||||
}
|
||||
}
|
||||
|
||||
return bReturn;
|
||||
return bReturn && m_iResult == 1;
|
||||
}
|
||||
|
||||
bool CAimbotProjectile::HandleDirect(DirectHistory_t& mDirectHistory)
|
||||
@@ -1487,7 +1542,7 @@ int CAimbotProjectile::CanHit(Target_t& tTarget, CTFPlayer* pLocal, CTFWeaponBas
|
||||
|
||||
m_tInfo.m_vHull = m_tProjInfo.m_vHull.Min(3);
|
||||
m_tInfo.m_vOffset = m_tProjInfo.m_vPos - m_tInfo.m_vLocalEye; m_tInfo.m_vOffset.y *= -1;
|
||||
m_tInfo.m_flOffsetTime = m_tInfo.m_vOffset.Length() / m_tInfo.m_flVelocity; // silly
|
||||
m_tInfo.m_flOffsetTime = m_tInfo.m_vOffset.Length() / m_tInfo.m_flVelocity;
|
||||
|
||||
m_tInfo.m_flGravity = m_tProjInfo.m_flGravity;
|
||||
m_tInfo.m_iSplashRestrict = !m_tInfo.m_flGravity ? Vars::Aimbot::Projectile::SplashRestrictDirect.Value : Vars::Aimbot::Projectile::SplashRestrictArc.Value;
|
||||
@@ -1544,7 +1599,16 @@ int CAimbotProjectile::CanHit(Target_t& tTarget, CTFPlayer* pLocal, CTFWeaponBas
|
||||
iFlags |= CalculateFlagsEnum::LobAngle;
|
||||
int iTolerance = m_tInfo.m_bIgnoreTiming && iType == PointFlagsEnum::Lob ? std::numeric_limits<int>::max() : -1;
|
||||
|
||||
Solution_t tSolution; CalculateAngle(m_tInfo.m_vLocalEye, vPoint, i, tSolution, iFlags, iTolerance);
|
||||
Solution_t tSolution;
|
||||
switch (iType)
|
||||
{
|
||||
case PointFlagsEnum::Lob:
|
||||
if (ShouldLob(m_tMoveStorage, m_tInfo))
|
||||
goto end;
|
||||
tSolution.m_iCalculated = CalculateResultEnum::Bad; break;
|
||||
default: end:
|
||||
CalculateAngle(m_tInfo.m_vLocalEye, vPoint, i, tSolution, iFlags, iTolerance);
|
||||
}
|
||||
switch (tSolution.m_iCalculated)
|
||||
{
|
||||
case CalculateResultEnum::Good:
|
||||
@@ -1560,7 +1624,7 @@ int CAimbotProjectile::CanHit(Target_t& tTarget, CTFPlayer* pLocal, CTFWeaponBas
|
||||
for (auto it = vSplashes.begin(); it != vSplashes.end();)
|
||||
{
|
||||
uint8_t iFlags = CalculateFlagsEnum::AccountDrag;
|
||||
if (!m_tInfo.m_bIgnoreTiming && *it == PointFlagsEnum::Lob)
|
||||
if (*it == PointFlagsEnum::Lob && !m_tInfo.m_bIgnoreTiming)
|
||||
iFlags |= CalculateFlagsEnum::LobAngle;
|
||||
|
||||
Solution_t tSolution; CalculateAngle(m_tInfo.m_vLocalEye, tTarget.m_vPos, i, tSolution, iFlags);
|
||||
@@ -1581,6 +1645,11 @@ int CAimbotProjectile::CanHit(Target_t& tTarget, CTFPlayer* pLocal, CTFWeaponBas
|
||||
it = vSplashes.erase(it);
|
||||
continue;
|
||||
}
|
||||
if (*it == PointFlagsEnum::Lob && !ShouldLob(m_tMoveStorage, m_tInfo))
|
||||
{
|
||||
++it;
|
||||
continue;
|
||||
}
|
||||
|
||||
mSplashHistory[*it].emplace_back(History_t(tTarget.m_vPos, i), fabsf(flTimeTo));
|
||||
++it;
|
||||
@@ -1841,6 +1910,9 @@ bool CAimbotProjectile::RunMain(CTFPlayer* pLocal, CTFWeaponBase* pWeapon, CUser
|
||||
#endif
|
||||
#if defined(SPLASH_DEBUG2) && defined(WORLD_DEBUG)
|
||||
G::TriangleStorage.clear();
|
||||
#endif
|
||||
#if defined(SPLASH_DEBUG2) && defined(DEBUG_TEXT)
|
||||
F::Visuals.ClearDebugText();
|
||||
#endif
|
||||
for (auto& tTarget : vTargets)
|
||||
{
|
||||
@@ -2026,7 +2098,7 @@ bool CAimbotProjectile::TestAngle(CBaseEntity* pProjectile, const Vec3& vPoint,
|
||||
|
||||
Vec3 vPos = vPoint;
|
||||
if (m_tInfo.m_flGravity)
|
||||
vPos += Vec3(0, 0, (m_tInfo.m_flGravity * 800.f * pow(TICKS_TO_TIME(iSimTime), 2)) / 2);
|
||||
vPos += Vec3(0, 0, m_tInfo.m_flGravity * pow(TICKS_TO_TIME(iSimTime), 2) / 2);
|
||||
Vec3 vForward = (vPos - m_tProjInfo.m_vPos).Normalized();
|
||||
m_tProjInfo.m_vAng = Math::VectorAngles(vForward);
|
||||
|
||||
@@ -2037,7 +2109,7 @@ bool CAimbotProjectile::TestAngle(CBaseEntity* pProjectile, const Vec3& vPoint,
|
||||
return false;
|
||||
|
||||
SDK::Trace(vEyePos, trace.endpos, MASK_SOLID, &filter, &trace);
|
||||
if (trace.fraction < 0.999f)
|
||||
if (Math::FullFraction(vEyePos, trace.endpos, trace) < 0.999f)
|
||||
return false;
|
||||
|
||||
if (!F::AutoAirblast.CanAirblastEntity(pLocal, pWeapon, pProjectile, vAngles))
|
||||
@@ -2055,7 +2127,7 @@ bool CAimbotProjectile::TestAngle(CBaseEntity* pProjectile, const Vec3& vPoint,
|
||||
if (!m_tProjInfo.m_flGravity)
|
||||
{
|
||||
SDK::TraceHull(m_tProjInfo.m_vPos, vPoint, -m_tProjInfo.m_vHull, m_tProjInfo.m_vHull, nMask, &filter, &trace);
|
||||
if (trace.fraction < 0.999f && trace.m_pEnt != tTarget.m_pEntity)
|
||||
if (Math::FullFraction(m_tProjInfo.m_vPos, vPoint, trace) < 0.999f && trace.m_pEnt != tTarget.m_pEntity)
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -2091,10 +2163,9 @@ bool CAimbotProjectile::TestAngle(CBaseEntity* pProjectile, const Vec3& vPoint,
|
||||
{
|
||||
case PointTypeEnum::Direct:
|
||||
case PointTypeEnum::Geometry:
|
||||
bHit = trace.DidHit();
|
||||
break;
|
||||
bHit = trace.DidHit(); break;
|
||||
case PointTypeEnum::Air:
|
||||
bHit = trace.endpos.DistToSqr(vPoint) < flRadiusSqr || trace.DidHit();
|
||||
bHit = trace.endpos.DistToSqr(vPoint) < flRadiusSqr || trace.DidHit(); break;
|
||||
}
|
||||
|
||||
if (bHit)
|
||||
@@ -2103,33 +2174,17 @@ bool CAimbotProjectile::TestAngle(CBaseEntity* pProjectile, const Vec3& vPoint,
|
||||
switch (iType)
|
||||
{
|
||||
case PointTypeEnum::Direct:
|
||||
bTarget = trace.m_pEnt == tTarget.m_pEntity, bValid = bTarget && iSimTime - n < iTimingTolerance;
|
||||
break;
|
||||
bTarget = trace.m_pEnt == tTarget.m_pEntity, bValid = bTarget && iSimTime - n < iTimingTolerance; break;
|
||||
case PointTypeEnum::Geometry:
|
||||
bValid = trace.endpos.DistToSqr(vPoint) < flRadiusSqr;
|
||||
break;
|
||||
bValid = trace.endpos.DistToSqr(vPoint) < flRadiusSqr; break;
|
||||
case PointTypeEnum::Air:
|
||||
bValid = !trace.DidHit();
|
||||
break;
|
||||
bValid = !trace.DidHit(); break;
|
||||
}
|
||||
if (bValid && iType != PointTypeEnum::Direct)
|
||||
{
|
||||
bValid = SDK::VisPosWorld(nullptr, tTarget.m_pEntity, trace.endpos, vPoint, nMask);
|
||||
if (bValid)
|
||||
{
|
||||
Vec3 vFrom = trace.endpos;
|
||||
switch (pProjectile->GetClassID())
|
||||
{
|
||||
case ETFClassID::CTFProjectile_Rocket:
|
||||
case ETFClassID::CTFProjectile_SentryRocket:
|
||||
case ETFClassID::CTFProjectile_EnergyBall:
|
||||
vFrom += trace.plane.normal;
|
||||
}
|
||||
|
||||
CGameTrace eyeTrace = {};
|
||||
SDK::Trace(vFrom, tTarget.m_vPos + tTarget.m_pEntity->As<CTFPlayer>()->GetViewOffset(), MASK_SHOT, &filter, &eyeTrace);
|
||||
bValid = eyeTrace.fraction == 1.f;
|
||||
}
|
||||
CGameTrace eyeTrace = {};
|
||||
SDK::Trace(trace.endpos + trace.plane.normal * m_tInfo.m_flNormalOffset, tTarget.m_vPos + m_tInfo.m_vTargetEye, MASK_SHOT, &filter, &eyeTrace);
|
||||
bValid = eyeTrace.fraction == 1.f;
|
||||
}
|
||||
|
||||
if (bValid)
|
||||
@@ -2244,7 +2299,16 @@ bool CAimbotProjectile::CanHit(Target_t& tTarget, CTFPlayer* pLocal, CTFWeaponBa
|
||||
iFlags |= CalculateFlagsEnum::LobAngle;
|
||||
int iTolerance = m_tInfo.m_bIgnoreTiming && iType == PointFlagsEnum::Lob ? std::numeric_limits<int>::max() : -1;
|
||||
|
||||
Solution_t tSolution; CalculateAngle(m_tInfo.m_vLocalEye, vPoint, i, tSolution, iFlags, iTolerance);
|
||||
Solution_t tSolution;
|
||||
switch (iType)
|
||||
{
|
||||
case PointFlagsEnum::Lob:
|
||||
if (ShouldLob(m_tMoveStorage, m_tInfo))
|
||||
goto end;
|
||||
tSolution.m_iCalculated = CalculateResultEnum::Bad; break;
|
||||
default: end:
|
||||
CalculateAngle(m_tInfo.m_vLocalEye, vPoint, i, tSolution, iFlags, iTolerance);
|
||||
}
|
||||
switch (tSolution.m_iCalculated)
|
||||
{
|
||||
case CalculateResultEnum::Good:
|
||||
@@ -2260,7 +2324,7 @@ bool CAimbotProjectile::CanHit(Target_t& tTarget, CTFPlayer* pLocal, CTFWeaponBa
|
||||
for (auto it = vSplashes.begin(); it != vSplashes.end();)
|
||||
{
|
||||
uint8_t iFlags = CalculateFlagsEnum::AccountDrag;
|
||||
if (!m_tInfo.m_bIgnoreTiming && *it == PointFlagsEnum::Lob)
|
||||
if (*it == PointFlagsEnum::Lob && !m_tInfo.m_bIgnoreTiming)
|
||||
iFlags |= CalculateFlagsEnum::LobAngle;
|
||||
|
||||
Solution_t tSolution; CalculateAngle(m_tInfo.m_vLocalEye, tTarget.m_vPos, i, tSolution, iFlags);
|
||||
@@ -2281,6 +2345,11 @@ bool CAimbotProjectile::CanHit(Target_t& tTarget, CTFPlayer* pLocal, CTFWeaponBa
|
||||
it = vSplashes.erase(it);
|
||||
continue;
|
||||
}
|
||||
if (*it == PointFlagsEnum::Lob && !ShouldLob(m_tMoveStorage, m_tInfo))
|
||||
{
|
||||
++it;
|
||||
continue;
|
||||
}
|
||||
|
||||
mSplashHistory[*it].emplace_back(History_t(tTarget.m_vPos, i), fabsf(flTimeTo));
|
||||
++it;
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
#include "../../../SDK/SDK.h"
|
||||
|
||||
#include "../AimbotGlobal/AimbotGlobal.h"
|
||||
#include <optional>
|
||||
|
||||
class CAutoDetonate
|
||||
{
|
||||
|
||||
@@ -3362,6 +3362,13 @@ void CMenu::MenuSettings(int iTab)
|
||||
{
|
||||
FDropdown(Vars::World::Faces, FDropdownEnum::Left);
|
||||
FDropdown(Vars::World::Draw, FDropdownEnum::Right);
|
||||
FSlider(Vars::World::Offset, FSliderEnum::Left);
|
||||
FSlider(Vars::World::Resize, FSliderEnum::Right);
|
||||
FColorPicker(Vars::World::BoxBrush, FColorPickerEnum::Left);
|
||||
FColorPicker(Vars::World::PlaneBrush, FColorPickerEnum::Right);
|
||||
FColorPicker(Vars::World::Displacement, FColorPickerEnum::Left);
|
||||
FColorPicker(Vars::World::Prop, FColorPickerEnum::Right);
|
||||
FColorPicker(Vars::World::Entity, FColorPickerEnum::Left);
|
||||
} EndSection();
|
||||
#endif
|
||||
#ifdef DEBUG_HOOKS
|
||||
|
||||
@@ -39,7 +39,8 @@ void CNoSpreadProjectile::Run(CTFPlayer* pLocal, CTFWeaponBase* pWeapon, CUserCm
|
||||
switch (pWeapon->GetWeaponID())
|
||||
{
|
||||
case TF_WEAPON_COMPOUND_BOW:
|
||||
if (I::GlobalVars->curtime - pWeapon->As<CTFPipebombLauncher>()->m_flChargeBeginTime() > TF_ARROW_MAX_CHARGE_TIME)
|
||||
if (pWeapon->As<CTFPipebombLauncher>()->m_flChargeBeginTime() > 0.f
|
||||
&& I::GlobalVars->curtime - pWeapon->As<CTFPipebombLauncher>()->m_flChargeBeginTime() > TF_ARROW_MAX_CHARGE_TIME)
|
||||
{
|
||||
vAngAdd.x -= float(SDK::RandomInt()) / VALVE_RAND_MAX * 12.f - 6.f;
|
||||
vAngAdd.y -= float(SDK::RandomInt()) / VALVE_RAND_MAX * 12.f - 6.f;
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
#pragma once
|
||||
#include "../../SDK/SDK.h"
|
||||
#include <optional>
|
||||
|
||||
struct ResolveData
|
||||
{
|
||||
|
||||
@@ -228,54 +228,13 @@ bool CMovementSimulation::Initialize(CBaseEntity* pEntity, MoveStorage& tMoveSto
|
||||
tMoveStorage.m_bBunnyHop = true;
|
||||
|
||||
// setup move data
|
||||
if (!SetupMoveData(tMoveStorage))
|
||||
{
|
||||
tMoveStorage.m_bFailed = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
const int iStrafeSamples = tMoveStorage.m_bDirectMove
|
||||
? Vars::Aimbot::Projectile::GroundSamples.Value
|
||||
: Vars::Aimbot::Projectile::AirSamples.Value;
|
||||
SetupMoveData(tMoveStorage);
|
||||
|
||||
// calculate strafe if desired
|
||||
bool bCalculated = bStrafe ? StrafePrediction(tMoveStorage, iStrafeSamples) : false;
|
||||
|
||||
// really hope this doesn't work like shit
|
||||
if (bHitchance && bCalculated && !pPlayer->m_vecVelocity().IsZero() && Vars::Aimbot::Projectile::HitChance.Value)
|
||||
if (bStrafe)
|
||||
{
|
||||
const auto& vRecords = m_mRecords[pPlayer->entindex()];
|
||||
const auto iSamples = vRecords.size();
|
||||
|
||||
float flCurrentChance = 1.f, flAverageYaw = 0.f;
|
||||
for (size_t i = 0; i < iSamples; i++)
|
||||
if (!StrafePrediction(tMoveStorage, bHitchance))
|
||||
{
|
||||
if (vRecords.size() <= i + 2)
|
||||
break;
|
||||
|
||||
const auto& pRecord1 = vRecords[i], &pRecord2 = vRecords[i + 1];
|
||||
const float flYaw1 = Math::VectorAngles(pRecord1.m_vDirection).y, flYaw2 = Math::VectorAngles(pRecord2.m_vDirection).y;
|
||||
const float flTime1 = pRecord1.m_flSimTime, flTime2 = pRecord2.m_flSimTime;
|
||||
const int iTicks = std::max(TIME_TO_TICKS(flTime1 - flTime2), 1);
|
||||
|
||||
float flYaw = Math::NormalizeAngle(flYaw1 - flYaw2) / iTicks;
|
||||
flAverageYaw += flYaw;
|
||||
if (tMoveStorage.m_MoveData.m_flMaxSpeed)
|
||||
flYaw *= std::clamp(pRecord1.m_vVelocity.Length2D() / tMoveStorage.m_MoveData.m_flMaxSpeed, 0.f, 1.f);
|
||||
|
||||
if ((i + 1) % iStrafeSamples == 0 || i == iSamples - 1)
|
||||
{
|
||||
flAverageYaw /= i % iStrafeSamples + 1;
|
||||
if (fabsf(tMoveStorage.m_flAverageYaw - flAverageYaw) > 0.5f)
|
||||
flCurrentChance -= 1.f / ((iSamples - 1) / float(iStrafeSamples) + 1);
|
||||
flAverageYaw = 0.f;
|
||||
}
|
||||
}
|
||||
|
||||
if (flCurrentChance < Vars::Aimbot::Projectile::HitChance.Value / 100)
|
||||
{
|
||||
SDK::Output("MovementSimulation", std::format("Hitchance ({}% < {}%)", flCurrentChance * 100, Vars::Aimbot::Projectile::HitChance.Value).c_str(), { 80, 200, 120 }, Vars::Debug::Logging.Value);
|
||||
|
||||
tMoveStorage.m_bFailed = true;
|
||||
return false;
|
||||
}
|
||||
@@ -288,11 +247,8 @@ bool CMovementSimulation::Initialize(CBaseEntity* pEntity, MoveStorage& tMoveSto
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CMovementSimulation::SetupMoveData(MoveStorage& tMoveStorage)
|
||||
void CMovementSimulation::SetupMoveData(MoveStorage& tMoveStorage)
|
||||
{
|
||||
if (!tMoveStorage.m_pPlayer)
|
||||
return false;
|
||||
|
||||
tMoveStorage.m_MoveData.m_bFirstRunOfFunctions = false;
|
||||
tMoveStorage.m_MoveData.m_bGameCodeMovedPlayer = false;
|
||||
tMoveStorage.m_MoveData.m_nPlayerHandle = reinterpret_cast<IHandleEntity*>(tMoveStorage.m_pPlayer)->GetRefEHandle();
|
||||
@@ -346,8 +302,6 @@ bool CMovementSimulation::SetupMoveData(MoveStorage& tMoveStorage)
|
||||
tMoveStorage.m_flPredictedSimTime = tMoveStorage.m_flSimTime + tMoveStorage.m_flPredictedDelta;
|
||||
tMoveStorage.m_vPredictedOrigin = tMoveStorage.m_MoveData.m_vecAbsOrigin;
|
||||
tMoveStorage.m_bDirectMove = tMoveStorage.m_pPlayer->IsOnGround() || tMoveStorage.m_pPlayer->IsSwimming();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline float GetGravity()
|
||||
@@ -527,14 +481,57 @@ void CMovementSimulation::GetAverageYaw(MoveStorage& tMoveStorage, int iSamples)
|
||||
SDK::Output("MovementSimulation", std::format("flAverageYaw calculated to {} from {} ({}){}", flAverageYaw, iTicks, iMinimum, bLocal ? " (local)" : "").c_str(), { 100, 255, 150 }, Vars::Debug::Logging.Value);
|
||||
}
|
||||
|
||||
bool CMovementSimulation::StrafePrediction(MoveStorage& tMoveStorage, int iSamples)
|
||||
bool CMovementSimulation::StrafePrediction(MoveStorage& tMoveStorage, bool bHitchance)
|
||||
{
|
||||
if (tMoveStorage.m_bDirectMove
|
||||
? !(Vars::Aimbot::Projectile::StrafePrediction.Value & Vars::Aimbot::Projectile::StrafePredictionEnum::Ground)
|
||||
: !(Vars::Aimbot::Projectile::StrafePrediction.Value & Vars::Aimbot::Projectile::StrafePredictionEnum::Air))
|
||||
return false;
|
||||
return true;
|
||||
|
||||
const int iStrafeSamples = tMoveStorage.m_bDirectMove
|
||||
? Vars::Aimbot::Projectile::GroundSamples.Value
|
||||
: Vars::Aimbot::Projectile::AirSamples.Value;
|
||||
|
||||
GetAverageYaw(tMoveStorage, iStrafeSamples);
|
||||
|
||||
// really hope this doesn't work like shit
|
||||
if (bHitchance && !tMoveStorage.m_pPlayer->m_vecVelocity().IsZero() && Vars::Aimbot::Projectile::HitChance.Value)
|
||||
{
|
||||
const auto& vRecords = m_mRecords[tMoveStorage.m_pPlayer->entindex()];
|
||||
const auto iSamples = vRecords.size();
|
||||
|
||||
float flCurrentChance = 1.f, flAverageYaw = 0.f;
|
||||
for (size_t i = 0; i < iSamples; i++)
|
||||
{
|
||||
if (vRecords.size() <= i + 2)
|
||||
break;
|
||||
|
||||
const auto& pRecord1 = vRecords[i], & pRecord2 = vRecords[i + 1];
|
||||
const float flYaw1 = Math::VectorAngles(pRecord1.m_vDirection).y, flYaw2 = Math::VectorAngles(pRecord2.m_vDirection).y;
|
||||
const float flTime1 = pRecord1.m_flSimTime, flTime2 = pRecord2.m_flSimTime;
|
||||
const int iTicks = std::max(TIME_TO_TICKS(flTime1 - flTime2), 1);
|
||||
|
||||
float flYaw = Math::NormalizeAngle(flYaw1 - flYaw2) / iTicks;
|
||||
flAverageYaw += flYaw;
|
||||
if (tMoveStorage.m_MoveData.m_flMaxSpeed)
|
||||
flYaw *= std::clamp(pRecord1.m_vVelocity.Length2D() / tMoveStorage.m_MoveData.m_flMaxSpeed, 0.f, 1.f);
|
||||
|
||||
if ((i + 1) % iStrafeSamples == 0 || i == iSamples - 1)
|
||||
{
|
||||
flAverageYaw /= i % iStrafeSamples + 1;
|
||||
if (fabsf(tMoveStorage.m_flAverageYaw - flAverageYaw) > 0.5f)
|
||||
flCurrentChance -= 1.f / ((iSamples - 1) / float(iStrafeSamples) + 1);
|
||||
flAverageYaw = 0.f;
|
||||
}
|
||||
}
|
||||
|
||||
if (flCurrentChance < Vars::Aimbot::Projectile::HitChance.Value / 100)
|
||||
{
|
||||
SDK::Output("MovementSimulation", std::format("Hitchance ({}% < {}%)", flCurrentChance * 100, Vars::Aimbot::Projectile::HitChance.Value).c_str(), { 80, 200, 120 }, Vars::Debug::Logging.Value);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
GetAverageYaw(tMoveStorage, iSamples);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -44,9 +44,9 @@ private:
|
||||
void Store(MoveStorage& tMoveStorage);
|
||||
void Reset(MoveStorage& tMoveStorage);
|
||||
|
||||
bool SetupMoveData(MoveStorage& tMoveStorage);
|
||||
void SetupMoveData(MoveStorage& tMoveStorage);
|
||||
void GetAverageYaw(MoveStorage& tMoveStorage, int iSamples);
|
||||
bool StrafePrediction(MoveStorage& tMoveStorage, int iSamples);
|
||||
bool StrafePrediction(MoveStorage& tMoveStorage, bool bHitchance = false);
|
||||
|
||||
void SetBounds(CTFPlayer* pPlayer);
|
||||
void RestoreBounds(CTFPlayer* pPlayer);
|
||||
|
||||
@@ -11,7 +11,7 @@ bool CProjectileSimulation::GetInfoMain(CTFPlayer* pPlayer, CTFWeaponBase* pWeap
|
||||
return false;
|
||||
|
||||
static auto sv_gravity = H::ConVars.FindVar("sv_gravity");
|
||||
float flGravity = sv_gravity->GetFloat() / 800.f;
|
||||
float flGravity = sv_gravity->GetFloat(); // vphysics projectiles affected by server start gravity
|
||||
bool bDucking = pPlayer->m_fFlags() & FL_DUCKING;
|
||||
|
||||
bool bRedirect = iFlags & ProjSimEnum::Redirect;
|
||||
@@ -118,7 +118,7 @@ bool CProjectileSimulation::GetInfoMain(CTFPlayer* pPlayer, CTFWeaponBase* pWeap
|
||||
tProjInfo = { pPlayer, pWeapon, uType, vPos, vAngle, vHull, flSpeed, 0.f };
|
||||
return true;
|
||||
}
|
||||
case TF_WEAPON_GRENADELAUNCHER: // vphysics projectiles affected by server start gravity
|
||||
case TF_WEAPON_GRENADELAUNCHER:
|
||||
case TF_WEAPON_CANNON:
|
||||
{
|
||||
bool bCannon = pWeapon->GetWeaponID() == TF_WEAPON_CANNON;
|
||||
@@ -133,7 +133,7 @@ bool CProjectileSimulation::GetInfoMain(CTFPlayer* pPlayer, CTFWeaponBase* pWeap
|
||||
? pWeapon->As<CTFGrenadeLauncher>()->m_flDetonateTime() > 0.f ? pWeapon->As<CTFGrenadeLauncher>()->m_flDetonateTime() - I::GlobalVars->curtime : flMortar
|
||||
: SDK::AttribHookValue(2.f, "fuse_mult", pWeapon);
|
||||
flLifeTime = ceilf(flLifeTime / GRENADE_CHECK_INTERVAL) * GRENADE_CHECK_INTERVAL + GetDesync();
|
||||
tProjInfo = { pPlayer, pWeapon, uType, vPos, vAngle, vHull, flSpeed, 1.f, flLifeTime };
|
||||
tProjInfo = { pPlayer, pWeapon, uType, vPos, vAngle, vHull, flSpeed, DEFAULT_GRAVITY, flLifeTime };
|
||||
return true;
|
||||
}
|
||||
case TF_WEAPON_PIPEBOMBLAUNCHER:
|
||||
@@ -145,7 +145,7 @@ bool CProjectileSimulation::GetInfoMain(CTFPlayer* pPlayer, CTFWeaponBase* pWeap
|
||||
? SDK::AttribHookValue(4.f, "stickybomb_charge_rate", pWeapon) * flAutoCharge
|
||||
: (pWeapon->As<CTFPipebombLauncher>()->m_flChargeBeginTime() > 0.f ? I::GlobalVars->curtime - pWeapon->As<CTFPipebombLauncher>()->m_flChargeBeginTime() : 0.f);
|
||||
float flSpeed = SDK::AttribHookValue(bMaxSpeed ? 2400.f : Math::RemapVal(flCharge, 0.f, SDK::AttribHookValue(4.f, "stickybomb_charge_rate", pWeapon), 900.f, 2400.f), "mult_projectile_range", pWeapon);
|
||||
tProjInfo = { pPlayer, pWeapon, uType, vPos, vAngle, { 4.f, 4.f, 4.f }, flSpeed, 1.f };
|
||||
tProjInfo = { pPlayer, pWeapon, uType, vPos, vAngle, { 5.f, 5.f, 5.f }, flSpeed, DEFAULT_GRAVITY };
|
||||
return true;
|
||||
}
|
||||
case TF_WEAPON_FLAREGUN:
|
||||
@@ -238,7 +238,7 @@ bool CProjectileSimulation::GetInfoMain(CTFPlayer* pPlayer, CTFWeaponBase* pWeap
|
||||
SDK::GetProjectileFireSetup(pPlayer, vAngles, { 16.f, 8.f, -6.f }, vPos, vAngle, 0.f, 0.f, bInterp);
|
||||
|
||||
auto uType = FNV1A::Hash32Const("models/workshop_partner/weapons/c_models/c_sd_cleaver/c_sd_cleaver.mdl");
|
||||
tProjInfo = { pPlayer, pWeapon, uType, vPos, vAngle, { 1.f, 1.f, 10.f } /*weird, probably still inaccurate*/, 3000.f, 1.f, 2.2f };
|
||||
tProjInfo = { pPlayer, pWeapon, uType, vPos, vAngle, { 1.f, 1.f, 10.f } /*weird, probably still inaccurate*/, 3000.f, DEFAULT_GRAVITY, 2.2f };
|
||||
return true;
|
||||
}
|
||||
case TF_WEAPON_BAT_WOOD:
|
||||
@@ -252,7 +252,7 @@ bool CProjectileSimulation::GetInfoMain(CTFPlayer* pPlayer, CTFWeaponBase* pWeap
|
||||
auto uType = bWrapAssassin ? FNV1A::Hash32Const("models/weapons/c_models/c_xms_festive_ornament.mdl") : FNV1A::Hash32Const("models/weapons/w_models/w_baseball.mdl");
|
||||
Vec3 vForward; Math::AngleVectors(vAngle, &vForward);
|
||||
vPos = (bInterp ? pPlayer->GetAbsOrigin() : pPlayer->m_vecOrigin()) + (Vec3(0, 0, 50) + vForward * 32.f) * pPlayer->m_flModelScale(); // why?
|
||||
tProjInfo = { pPlayer, pWeapon, uType, vPos, vAngle, { 3.f, 3.f, 3.f }, tf_scout_stunball_base_speed->GetFloat(), 1.f, bWrapAssassin ? 2.3f : 100.f };
|
||||
tProjInfo = { pPlayer, pWeapon, uType, vPos, vAngle, { 3.f, 3.f, 3.f }, tf_scout_stunball_base_speed->GetFloat(), DEFAULT_GRAVITY, bWrapAssassin ? 2.3f : 100.f };
|
||||
return true;
|
||||
}
|
||||
case TF_WEAPON_JAR:
|
||||
@@ -267,7 +267,7 @@ bool CProjectileSimulation::GetInfoMain(CTFPlayer* pPlayer, CTFWeaponBase* pWeap
|
||||
case Sniper_s_TheSelfAwareBeautyMark: uType = FNV1A::Hash32Const("models/weapons/c_models/c_breadmonster/c_breadmonster.mdl"); break;
|
||||
case Scout_s_MutatedMilk: uType = FNV1A::Hash32Const("models/weapons/c_models/c_breadmonster/c_breadmonster_milk.mdl"); break;
|
||||
}
|
||||
tProjInfo = { pPlayer, pWeapon, uType, vPos, vAngle, { 3.f, 3.f, 3.f }, 1000.f, 1.f, 2.2f };
|
||||
tProjInfo = { pPlayer, pWeapon, uType, vPos, vAngle, { 3.f, 3.f, 3.f }, 1000.f, DEFAULT_GRAVITY, 2.2f };
|
||||
return true;
|
||||
}
|
||||
case TF_WEAPON_JAR_GAS:
|
||||
@@ -275,7 +275,7 @@ bool CProjectileSimulation::GetInfoMain(CTFPlayer* pPlayer, CTFWeaponBase* pWeap
|
||||
SDK::GetProjectileFireSetup(pPlayer, vAngles, { 16.f, 8.f, -6.f }, vPos, vAngle, 0.f, 0.f, bInterp);
|
||||
|
||||
auto uType = FNV1A::Hash32Const("models/weapons/c_models/c_gascan/c_gascan.mdl");
|
||||
tProjInfo = { pPlayer, pWeapon, uType, vPos, vAngle, { 3.f, 3.f, 3.f }, 2000.f, 1.f, 2.2f };
|
||||
tProjInfo = { pPlayer, pWeapon, uType, vPos, vAngle, { 3.f, 3.f, 3.f }, 2000.f, DEFAULT_GRAVITY, 2.2f };
|
||||
return true;
|
||||
}
|
||||
case TF_WEAPON_GRAPPLINGHOOK:
|
||||
@@ -325,7 +325,7 @@ bool CProjectileSimulation::GetInfoMain(CTFPlayer* pPlayer, CTFWeaponBase* pWeap
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CProjectileSimulation::GetInfo(CTFPlayer* pPlayer, CTFWeaponBase* pWeapon, Vec3 vAngles, ProjectileInfo& tProjInfo, int iFlags, float flAutoCharge)
|
||||
bool CProjectileSimulation::GetInfo(CTFPlayer* pPlayer, CTFWeaponBase* pWeapon, const Vec3& vAngles, ProjectileInfo& tProjInfo, int iFlags, float flAutoCharge)
|
||||
{
|
||||
bool bInitCheck = iFlags & ProjSimEnum::InitCheck;
|
||||
bool bInterp = iFlags & ProjSimEnum::Interp;
|
||||
@@ -479,6 +479,7 @@ bool CProjectileSimulation::Initialize(ProjectileInfo& tProjInfo, bool bSimulate
|
||||
|
||||
m_pObj->m_dragBasis = vDragBasis;
|
||||
m_pObj->m_angDragBasis = vAngDragBasis;
|
||||
m_bPhysics = m_pObj->m_dragCoefficient && m_pObj->m_dragBasis;
|
||||
}
|
||||
|
||||
// set position and velocity
|
||||
@@ -586,11 +587,19 @@ bool CProjectileSimulation::Initialize(ProjectileInfo& tProjInfo, bool bSimulate
|
||||
}
|
||||
}
|
||||
|
||||
if (bSimulate && !F::ProjSim.m_pObj->IsDragEnabled() && m_pObj->m_dragBasis.IsZero()) // don't include vphysics projectiles
|
||||
vVelocity.z += 400.f * tProjInfo.m_flGravity * TICK_INTERVAL; // i don't know why this makes it more accurate but it does
|
||||
if (bSimulate && !m_bPhysics)
|
||||
vVelocity.z += tProjInfo.m_flGravity * TICK_INTERVAL / 2;
|
||||
|
||||
m_pObj->SetPosition(tProjInfo.m_vPos, tProjInfo.m_vAng, true);
|
||||
m_pObj->SetVelocity(&vVelocity, &vAngularVelocity);
|
||||
if (m_bPhysics)
|
||||
{
|
||||
m_pObj->SetPosition(tProjInfo.m_vPos, tProjInfo.m_vAng, true);
|
||||
m_pObj->SetVelocity(&vVelocity, &vAngularVelocity);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_tObj.m_vOrigin = tProjInfo.m_vPos;
|
||||
m_tObj.m_vVelocity = vVelocity;
|
||||
}
|
||||
}
|
||||
|
||||
// set m_pEnv params
|
||||
@@ -624,7 +633,7 @@ bool CProjectileSimulation::Initialize(ProjectileInfo& tProjInfo, bool bSimulate
|
||||
|
||||
m_pEnv->SetPerformanceSettings(¶ms);
|
||||
m_pEnv->SetAirDensity(AIR_DENSITY);
|
||||
m_pEnv->SetGravity({ 0.f, 0.f, -(800.f * tProjInfo.m_flGravity) });
|
||||
m_pEnv->SetGravity({ 0.f, 0.f, -tProjInfo.m_flGravity });
|
||||
|
||||
m_pEnv->ResetSimulationClock();
|
||||
}
|
||||
@@ -632,7 +641,8 @@ bool CProjectileSimulation::Initialize(ProjectileInfo& tProjInfo, bool bSimulate
|
||||
if (tProjInfo.m_uType == FNV1A::Hash32Const("custom"))
|
||||
tProjInfo.m_uType = FNV1A::Hash32(Vars::Visuals::Trajectory::Type.Value.c_str());
|
||||
|
||||
RunTick(tProjInfo, false); // simulate an initial time because dumb
|
||||
if (m_bPhysics)
|
||||
RunTick(tProjInfo, false); // simulate an initial time because dumb
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -642,15 +652,27 @@ void CProjectileSimulation::RunTick(ProjectileInfo& tProjInfo, bool bPath) // bu
|
||||
if (bPath)
|
||||
tProjInfo.m_vPath.push_back(GetOrigin());
|
||||
|
||||
m_pEnv->Simulate(TICK_INTERVAL);
|
||||
if (m_bPhysics)
|
||||
m_pEnv->Simulate(TICK_INTERVAL);
|
||||
else
|
||||
{
|
||||
Vec3& vOrigin = m_tObj.m_vOrigin;
|
||||
Vec3& vVelocity = m_tObj.m_vVelocity;
|
||||
|
||||
if (tProjInfo.m_flGravity)
|
||||
vVelocity.z -= tProjInfo.m_flGravity * TICK_INTERVAL;
|
||||
|
||||
vOrigin += vVelocity * TICK_INTERVAL;
|
||||
}
|
||||
|
||||
/* // params.maxVelocity limits velocity uniformly
|
||||
Vec3 vVelocity, vAngular;
|
||||
m_pObj->GetVelocity(&vVelocity, &vAngular);
|
||||
static auto sv_maxvelocity = H::ConVars.FindVar("sv_maxvelocity");
|
||||
const float flMaxVel = sv_maxvelocity->GetFloat();
|
||||
vVelocity = { std::clamp(vVelocity.x, -flMaxVel, flMaxVel), std::clamp(vVelocity.y, -flMaxVel, flMaxVel), std::clamp(vVelocity.z, -flMaxVel, flMaxVel) };
|
||||
m_pObj->SetVelocity(&vVelocity, &vAngular);
|
||||
|
||||
Vec3 vVelocity;
|
||||
m_pObj->GetVelocity(&vVelocity, nullptr);
|
||||
float flMaxVel = sv_maxvelocity->GetFloat();
|
||||
vVelocity = vVelocity.Clamp(-flMaxVel, flMaxVel);
|
||||
m_pObj->SetVelocity(&vVelocity, nullptr);
|
||||
*/
|
||||
}
|
||||
|
||||
@@ -659,8 +681,10 @@ Vec3 CProjectileSimulation::GetOrigin()
|
||||
if (!m_pObj)
|
||||
return {};
|
||||
|
||||
Vec3 vOut;
|
||||
m_pObj->GetPosition(&vOut, nullptr);
|
||||
if (!m_bPhysics)
|
||||
return m_tObj.m_vOrigin;
|
||||
|
||||
Vec3 vOut; m_pObj->GetPosition(&vOut, nullptr);
|
||||
return vOut;
|
||||
}
|
||||
|
||||
@@ -669,8 +693,10 @@ Vec3 CProjectileSimulation::GetVelocity()
|
||||
if (!m_pObj)
|
||||
return {};
|
||||
|
||||
Vec3 vOut;
|
||||
m_pObj->GetVelocity(&vOut, nullptr);
|
||||
if (!m_bPhysics)
|
||||
return m_tObj.m_vVelocity;
|
||||
|
||||
Vec3 vOut; m_pObj->GetVelocity(&vOut, nullptr);
|
||||
return vOut;
|
||||
}
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@ Enum(ProjSim,
|
||||
CorrectRandomAngles = 1 << 6 // or do, position matters
|
||||
)
|
||||
|
||||
#define DEFAULT_GRAVITY 800.f
|
||||
#define GRENADE_CHECK_INTERVAL 0.195f
|
||||
|
||||
struct ProjectileInfo
|
||||
@@ -30,7 +31,13 @@ struct ProjectileInfo
|
||||
|
||||
std::vector<Vec3> m_vPath = {};
|
||||
|
||||
int m_iFlags = 0;
|
||||
uint8_t m_iFlags = 0;
|
||||
};
|
||||
|
||||
struct PhysicsObject_t
|
||||
{
|
||||
Vec3 m_vOrigin = {};
|
||||
Vec3 m_vVelocity = {};
|
||||
};
|
||||
|
||||
class CProjectileSimulation
|
||||
@@ -53,7 +60,7 @@ private:
|
||||
};
|
||||
|
||||
public:
|
||||
bool GetInfo(CTFPlayer* pPlayer, CTFWeaponBase* pWeapon, Vec3 vAngles, ProjectileInfo& tProjInfo, int iFlags = ProjSimEnum::Redirect | ProjSimEnum::InitCheck, float flAutoCharge = -1.f);
|
||||
bool GetInfo(CTFPlayer* pPlayer, CTFWeaponBase* pWeapon, const Vec3& vAngles, ProjectileInfo& tProjInfo, int iFlags = ProjSimEnum::Redirect | ProjSimEnum::InitCheck, float flAutoCharge = -1.f);
|
||||
void SetupTrace(CTraceFilterCollideable& filter, int& nMask, CTFWeaponBase* pWeapon, int nTick = 0, bool bInterp = false);
|
||||
|
||||
void GetInfo(CBaseEntity* pProjectile, ProjectileInfo& tProjInfo);
|
||||
@@ -165,7 +172,7 @@ public:
|
||||
float flReturn = 0.f;
|
||||
|
||||
static auto sv_gravity = H::ConVars.FindVar("sv_gravity");
|
||||
float flGravity = sv_gravity->GetFloat() / 800.f;
|
||||
float flGravity = sv_gravity->GetFloat();
|
||||
switch (pProjectile->GetClassID())
|
||||
{
|
||||
case ETFClassID::CBaseGrenade:
|
||||
@@ -191,7 +198,7 @@ public:
|
||||
case ETFClassID::CTFProjectile_ThrowableBreadMonster:
|
||||
case ETFClassID::CTFProjectile_ThrowableBrick:
|
||||
case ETFClassID::CTFProjectile_ThrowableRepel:
|
||||
flReturn = 1.f;
|
||||
flReturn = DEFAULT_GRAVITY;
|
||||
break;
|
||||
case ETFClassID::CTFProjectile_HealingBolt:
|
||||
flReturn = 0.2f * flGravity;
|
||||
@@ -209,7 +216,11 @@ public:
|
||||
}
|
||||
|
||||
IPhysicsEnvironment* m_pEnv = nullptr;
|
||||
|
||||
IPhysicsObject* m_pObj = nullptr;
|
||||
PhysicsObject_t m_tObj = {};
|
||||
bool m_bPhysics = false;
|
||||
|
||||
ProjectileInfo* m_pCurrent = nullptr;
|
||||
};
|
||||
|
||||
|
||||
@@ -374,7 +374,7 @@ void CVisuals::DrawDebugInfo(CTFPlayer* pLocal)
|
||||
Vec3 vOrigin = pLocal->m_vecOrigin();
|
||||
H::Draw.StringOutlined(fFont, x, y += nTall * 2, Vars::Menu::Theme::Active.Value, Vars::Menu::Theme::Background.Value, ALIGN_TOPLEFT, std::format("Origin: ({:.3f}, {:.3f}, {:.3f})", vOrigin.x, vOrigin.y, vOrigin.z).c_str());
|
||||
Vec3 vVelocity = pLocal->m_vecVelocity();
|
||||
H::Draw.StringOutlined(fFont, x, y += nTall, Vars::Menu::Theme::Active.Value, Vars::Menu::Theme::Background.Value, ALIGN_TOPLEFT, std::format("Velocity: {:.3f} ({:.3f}, {:.3f}, {:.3f})", vVelocity.Length(), vVelocity.x, vVelocity.y, vVelocity.z).c_str());
|
||||
H::Draw.StringOutlined(fFont, x, y += nTall, Vars::Menu::Theme::Active.Value, Vars::Menu::Theme::Background.Value, ALIGN_TOPLEFT, std::format("Velocity: {:.3f}, {:.3f} ({:.3f}, {:.3f}, {:.3f})", vVelocity.Length(), vVelocity.Length2D(), vVelocity.x, vVelocity.y, vVelocity.z).c_str());
|
||||
H::Draw.StringOutlined(fFont, x, y += nTall, Vars::Menu::Theme::Active.Value, Vars::Menu::Theme::Background.Value, ALIGN_TOPLEFT, std::format("Tickbase: {}", pLocal->m_nTickBase()).c_str());
|
||||
//H::Draw.StringOutlined(fFont, x, y += nTall, Vars::Menu::Theme::Active.Value, Vars::Menu::Theme::Background.Value, ALIGN_TOPLEFT, std::format("Choke: {}, {}", G::Choking, I::ClientState->chokedcommands).c_str());
|
||||
//H::Draw.StringOutlined(fFont, x, y += nTall, Vars::Menu::Theme::Active.Value, Vars::Menu::Theme::Background.Value, ALIGN_TOPLEFT, std::format("Ticks: {}, {}", F::Ticks.m_iShiftedTicks, F::Ticks.m_iShiftedGoal).c_str());
|
||||
@@ -406,16 +406,41 @@ void CVisuals::DrawDebugInfo(CTFPlayer* pLocal)
|
||||
{
|
||||
if (Vars::Debug::Info.Value)
|
||||
y += nTall;
|
||||
for (auto& [sString, tColor] : m_vDebugText)
|
||||
for (auto& [sString, tColor, vPosition2D, vPosition3D] : m_vDebugText)
|
||||
{
|
||||
if (vPosition3D)
|
||||
{
|
||||
if (Vec3 vScreen; SDK::W2S(*vPosition3D, vScreen))
|
||||
H::Draw.StringOutlined(fFont, vScreen.x, vScreen.y, tColor, Vars::Menu::Theme::Background.Value, ALIGN_TOPLEFT, sString.c_str());
|
||||
}
|
||||
else if (vPosition2D)
|
||||
H::Draw.StringOutlined(fFont, vPosition2D->x, vPosition2D->y, tColor, Vars::Menu::Theme::Background.Value, ALIGN_TOPLEFT, sString.c_str());
|
||||
else
|
||||
H::Draw.StringOutlined(fFont, x, y += nTall, tColor, Vars::Menu::Theme::Background.Value, ALIGN_TOPLEFT, sString.c_str());
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef DEBUG_TEXT
|
||||
void CVisuals::AddDebugText(const DebugText_t& sText)
|
||||
{
|
||||
m_vDebugText.push_back(sText);
|
||||
}
|
||||
|
||||
void CVisuals::AddDebugText(const std::string& sString, Color_t tColor)
|
||||
{
|
||||
m_vDebugText.emplace_back(sString, tColor);
|
||||
m_vDebugText.emplace_back(sString, tColor, std::nullopt, std::nullopt);
|
||||
}
|
||||
|
||||
void CVisuals::AddDebugText(const std::string& sString, const Vec2& vPosition, Color_t tColor)
|
||||
{
|
||||
m_vDebugText.emplace_back(sString, tColor, vPosition, std::nullopt);
|
||||
}
|
||||
|
||||
void CVisuals::AddDebugText(const std::string& sString, const Vec3& vPosition, Color_t tColor)
|
||||
{
|
||||
m_vDebugText.emplace_back(sString, tColor, std::nullopt, vPosition);
|
||||
}
|
||||
|
||||
void CVisuals::ClearDebugText()
|
||||
@@ -863,7 +888,6 @@ void CVisuals::Store()
|
||||
if (!F::Groups.GetGroup(pEntity, pGroup, false) || !(pGroup->m_iTrajectory & TrajectoryEnum::Enabled))
|
||||
continue;
|
||||
|
||||
bool bContains = m_mProjectiles.contains(pEntity);
|
||||
Projectile_t& tProjectile = m_mProjectiles[pEntity];
|
||||
mProjectiles[pEntity];
|
||||
|
||||
@@ -947,7 +971,7 @@ void CVisuals::Store()
|
||||
}
|
||||
}
|
||||
|
||||
for (auto& [pEntity, tProjectile] : m_mProjectiles)
|
||||
for (auto& pEntity : m_mProjectiles | std::views::keys)
|
||||
{
|
||||
if (!mProjectiles.contains(pEntity))
|
||||
m_mProjectiles.erase(pEntity);
|
||||
@@ -1212,11 +1236,17 @@ void CVisuals::CreateMove(CTFPlayer* pLocal, CTFWeaponBase* pWeapon)
|
||||
{
|
||||
for (auto& tFace : vFaces)
|
||||
{
|
||||
if (Vars::World::Offset.Value)
|
||||
Math::OffsetPolygon(tFace.m_vVertices, tFace.m_vNormal, Vars::World::Offset.Value);
|
||||
if (Vars::World::Resize.Value)
|
||||
Math::ExpandPolygon(tFace.m_vVertices, tFace.m_vNormal, Vars::World::Resize.Value);
|
||||
|
||||
F::World.DrawFace(tFace, Vars::World::Draw.Value);
|
||||
|
||||
/*
|
||||
for (int i = 0; ++i < tFace.m_vVertices.size() - 1;)
|
||||
{
|
||||
const Vec3& vVertex1 = tFace.m_vVertices[0], & vVertex2 = tFace.m_vVertices[i], & vVertex3 = tFace.m_vVertices[i + 1];
|
||||
const Vec3& vVertex1 = tFace.m_vVertices[0], &vVertex2 = tFace.m_vVertices[i], &vVertex3 = tFace.m_vVertices[i + 1];
|
||||
|
||||
Vec3 vDir21 = vVertex2 - vVertex1, vDir31 = vVertex3 - vVertex1;
|
||||
float flArea = vDir21.Cross(vDir31).Length() / 2;
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
#pragma once
|
||||
#include "../../SDK/SDK.h"
|
||||
|
||||
#include <map>
|
||||
|
||||
//#define DEBUG_TEXT
|
||||
|
||||
struct Projectile_t
|
||||
@@ -30,6 +28,16 @@ struct PickupData_t
|
||||
Vec3 m_vLocation;
|
||||
};
|
||||
|
||||
#ifdef DEBUG_TEXT
|
||||
struct DebugText_t
|
||||
{
|
||||
std::string m_sText = "";
|
||||
Color_t m_tColor = {};
|
||||
std::optional<Vec2> vPosition2D = std::nullopt;
|
||||
std::optional<Vec3> vPosition3D = std::nullopt;
|
||||
};
|
||||
#endif
|
||||
|
||||
class CVisuals
|
||||
{
|
||||
private:
|
||||
@@ -38,7 +46,7 @@ private:
|
||||
std::vector<PickupData_t> m_vPickups = {};
|
||||
|
||||
#ifdef DEBUG_TEXT
|
||||
std::vector<std::pair<std::string, Color_t>> m_vDebugText = {};
|
||||
std::vector<DebugText_t> m_vDebugText = {};
|
||||
#endif
|
||||
|
||||
public:
|
||||
@@ -52,7 +60,10 @@ public:
|
||||
void DrawDebugInfo(CTFPlayer* pLocal);
|
||||
|
||||
#ifdef DEBUG_TEXT
|
||||
void AddDebugText(const DebugText_t& sText);
|
||||
void AddDebugText(const std::string& sString, Color_t tColor = Vars::Menu::Theme::Active.Value);
|
||||
void AddDebugText(const std::string& sString, const Vec2& vPosition, Color_t tColor = Vars::Menu::Theme::Active.Value);
|
||||
void AddDebugText(const std::string& sString, const Vec3& vPosition, Color_t tColor = Vars::Menu::Theme::Active.Value);
|
||||
void ClearDebugText();
|
||||
#endif
|
||||
|
||||
|
||||
@@ -125,7 +125,7 @@ static inline void GetFacesForConvex(CPhysConvex* pConvex, std::vector<Face_t>&
|
||||
|
||||
if (CPhysConvex* pConvex2 = I::PhysicsCollision->ConvexFromPlanes(reinterpret_cast<float*>(vPlanes.data()), int(vPlanes.size()), 0.f))
|
||||
{
|
||||
GetFacesForConvex(pConvex2, vFaces);
|
||||
GetFacesForConvex(pConvex2, vFaces, 0.f, iType);
|
||||
I::PhysicsCollision->ConvexFree(pConvex2);
|
||||
}
|
||||
}
|
||||
@@ -265,11 +265,14 @@ void CWorld::CacheProps()
|
||||
|
||||
m_iNeedsCache &= ~FaceTypeEnum::Prop;
|
||||
|
||||
CUtlVector<ICollideable*> vProps; I::StaticPropMgr->GetAllStaticProps(&vProps);
|
||||
for (int i = 0; i < vProps.Count(); i++)
|
||||
for (int i = I::MDLCache->m_MDLDict.First(); i != I::MDLCache->m_MDLDict.InvalidIndex(); i = I::MDLCache->m_MDLDict.Next(i))
|
||||
{
|
||||
vcollide_t* pCollide = I::ModelInfoClient->GetVCollide(vProps[i]->GetCollisionModel());
|
||||
if (!pCollide || m_mFaceCache.contains(pCollide))
|
||||
studiodata_t* pStudioData = I::MDLCache->m_MDLDict[i];
|
||||
if (!pStudioData)
|
||||
continue;
|
||||
|
||||
vcollide_t* pCollide = &pStudioData->m_VCollisionData;
|
||||
if (m_mFaceCache.contains(pCollide))
|
||||
continue;
|
||||
|
||||
for (int iSolid = 0; iSolid < pCollide->solidCount; iSolid++)
|
||||
@@ -474,7 +477,7 @@ std::vector<Face_t> CWorld::GetFacesInAABB(const Vec3& vMins, const Vec3& vMaxs,
|
||||
|
||||
vcollide_t* pCollide = I::ModelInfoClient->GetVCollide(pCollideable->GetCollisionModel());
|
||||
if (!m_mFaceCache.contains(pCollide))
|
||||
continue;
|
||||
continue; // cache as well?
|
||||
|
||||
auto& vCache = m_mFaceCache[pCollide];
|
||||
for (auto& tFace : vCache)
|
||||
@@ -503,8 +506,21 @@ std::vector<Face_t> CWorld::GetFacesInAABB(const Vec3& vMins, const Vec3& vMaxs,
|
||||
}
|
||||
|
||||
#ifdef WORLD_DEBUG
|
||||
void CWorld::DrawFace(const Face_t& tFace, int iFlags)
|
||||
void CWorld::DrawFace(const Face_t& tFace, int iFlags, std::optional<Color_t> tColor)
|
||||
{
|
||||
if (!tColor)
|
||||
{
|
||||
switch (tFace.m_iType)
|
||||
{
|
||||
case FaceTypeEnum::BoxBrush: tColor = Vars::World::BoxBrush.Value; break;
|
||||
case FaceTypeEnum::PlaneBrush: tColor = Vars::World::PlaneBrush.Value; break;
|
||||
case FaceTypeEnum::Displacement: tColor = Vars::World::Displacement.Value; break;
|
||||
case FaceTypeEnum::Prop: tColor = Vars::World::Prop.Value; break;
|
||||
case FaceTypeEnum::Entity: tColor = Vars::World::Entity.Value; break;
|
||||
default: tColor = { 255, 255, 255 }; break;
|
||||
}
|
||||
}
|
||||
|
||||
if (iFlags & (DrawTypeEnum::Points | DrawTypeEnum::Edges))
|
||||
{
|
||||
for (int i = 0; i < tFace.m_vVertices.size(); i++)
|
||||
@@ -512,9 +528,9 @@ void CWorld::DrawFace(const Face_t& tFace, int iFlags)
|
||||
const Vec3& vVertex1 = tFace.m_vVertices[i], &vVertex2 = tFace.m_vVertices[(i + 1) % tFace.m_vVertices.size()];
|
||||
|
||||
if (iFlags & DrawTypeEnum::Points)
|
||||
G::BoxStorage.emplace_back(vVertex1, Vec3::Get(-1), Vec3::Get(1), Vec3(0, 0, 0), I::GlobalVars->curtime + 60.f, Color_t(255, 0, 0), Color_t(0, 0, 0, 0), true);
|
||||
G::BoxStorage.emplace_back(vVertex1, Vec3::Get(-1), Vec3::Get(1), Vec3(0, 0, 0), I::GlobalVars->curtime + 60.f, *tColor, Color_t(0, 0, 0, 0), true);
|
||||
if (iFlags & DrawTypeEnum::Edges)
|
||||
G::LineStorage.emplace_back(std::pair<Vec3, Vec3>(vVertex1, vVertex2), I::GlobalVars->curtime + 60.f, Color_t(255, 0, 0), true);
|
||||
G::LineStorage.emplace_back(std::pair<Vec3, Vec3>(vVertex1, vVertex2), I::GlobalVars->curtime + 60.f, *tColor, true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -523,14 +539,14 @@ void CWorld::DrawFace(const Face_t& tFace, int iFlags)
|
||||
for (int i = 0; ++i < tFace.m_vVertices.size() - 1;)
|
||||
{
|
||||
const Vec3& vVertex1 = tFace.m_vVertices[0], &vVertex2 = tFace.m_vVertices[i], &vVertex3 = tFace.m_vVertices[i + 1];
|
||||
G::TriangleStorage.emplace_back(std::array<Vec3, 3>({ vVertex1, vVertex2, vVertex3 }), I::GlobalVars->curtime + 60.f, Color_t(255, 0, 0, 50), true);
|
||||
G::TriangleStorage.emplace_back(std::array<Vec3, 3>({ vVertex1, vVertex2, vVertex3 }), I::GlobalVars->curtime + 60.f, tColor->Alpha(50), true);
|
||||
}
|
||||
}
|
||||
|
||||
if (iFlags & DrawTypeEnum::Normals)
|
||||
{
|
||||
G::LineStorage.emplace_back(std::pair<Vec3, Vec3>(tFace.m_vVertices[0], tFace.m_vVertices[0] + tFace.m_vNormal * 10), I::GlobalVars->curtime + 60.f, Color_t(255, 255, 0), true);
|
||||
G::BoxStorage.emplace_back(tFace.m_vVertices[0] + tFace.m_vNormal * 10, Vec3::Get(-1), Vec3::Get(1), Vec3(), I::GlobalVars->curtime + 60.f, Color_t(255, 255, 0), Color_t(0, 0, 0, 0), true);
|
||||
G::LineStorage.emplace_back(std::pair<Vec3, Vec3>(tFace.m_vVertices[0], tFace.m_vVertices[0] + tFace.m_vNormal * 10), I::GlobalVars->curtime + 60.f, tColor->Inverse(), true);
|
||||
G::BoxStorage.emplace_back(tFace.m_vVertices[0] + tFace.m_vNormal * 10, Vec3::Get(-1), Vec3::Get(1), Vec3(), I::GlobalVars->curtime + 60.f, tColor->Inverse(), Color_t(0, 0, 0, 0), true);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -2,9 +2,6 @@
|
||||
#include "../../SDK/SDK.h"
|
||||
#include <functional>
|
||||
|
||||
#define DIST_EPSILON 0.03125f
|
||||
#define CALC_EPSILON 0.001f
|
||||
|
||||
//#define WORLD_DEBUG
|
||||
|
||||
Enum(FaceType, None = 0, BoxBrush = 1 << 0, PlaneBrush = 1 << 1, Displacement = 1 << 2, Prop = 1 << 3, Entity = 1 << 4, All = BoxBrush | PlaneBrush | Displacement | Prop | Entity, Cache = BoxBrush | PlaneBrush | Prop | Entity)
|
||||
@@ -17,6 +14,15 @@ namespace Vars {
|
||||
"BoxBrush", "PlaneBrush", "Displacement", "Prop", "Entity");
|
||||
CVarValues(Draw, "Draw", 0b0110, NOSAVE | DEBUGVAR | DROPDOWN_MULTI, nullptr,
|
||||
"Points", "Edges", "Faces", "Normals");
|
||||
|
||||
CVar(Offset, "Offset", 0.f, NOSAVE | DEBUGVAR | SLIDER_MIN | SLIDER_PRECISION, 0.f, 1.f, DIST_EPSILON);
|
||||
CVar(Resize, "Resize", 0.f, NOSAVE | DEBUGVAR | SLIDER_MIN | SLIDER_PRECISION, 0.f, 1.f, DIST_EPSILON);
|
||||
|
||||
CVar(BoxBrush, "BoxBrush", Color_t(255, 0, 0, 255), NOSAVE | DEBUGVAR);
|
||||
CVar(PlaneBrush, "PlaneBrush", Color_t(0, 255, 0, 255), NOSAVE | DEBUGVAR);
|
||||
CVar(Displacement, "Displacement", Color_t(0, 0, 255, 255), NOSAVE | DEBUGVAR);
|
||||
CVar(Prop, "Prop", Color_t(255, 0, 255, 255), NOSAVE | DEBUGVAR);
|
||||
CVar(Entity, "Entity", Color_t(255, 255, 0, 255), NOSAVE | DEBUGVAR);
|
||||
NAMESPACE_END(World)
|
||||
}
|
||||
#endif
|
||||
@@ -93,7 +99,7 @@ public:
|
||||
void SetNormalValidCallback(NormalValidCallback* pCallback = nullptr);
|
||||
|
||||
#ifdef WORLD_DEBUG
|
||||
void DrawFace(const Face_t& tFace, int iFlags = DrawTypeEnum::Points | DrawTypeEnum::Edges | DrawTypeEnum::Faces | DrawTypeEnum::Normals);
|
||||
void DrawFace(const Face_t& tFace, int iFlags = DrawTypeEnum::Points | DrawTypeEnum::Edges | DrawTypeEnum::Faces | DrawTypeEnum::Normals, std::optional<Color_t> tColor = std::nullopt);
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ MAKE_HOOK(CClientModeShared_DoPostScreenSpaceEffects, U::Memory.GetVirtual(I::Cl
|
||||
{
|
||||
DEBUG_RETURN(CClientModeShared_DoPostScreenSpaceEffects, rcx, pSetup);
|
||||
|
||||
if (SDK::CleanScreenshot())
|
||||
if (SDK::CleanScreenshot() || G::Unload)
|
||||
return CALL_ORIGINAL(rcx, pSetup);
|
||||
|
||||
F::Visuals.ProjectileTrace(H::Entities.GetLocal(), H::Entities.GetWeapon());
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
#include "../SDK/SDK.h"
|
||||
|
||||
#include "../SDK/Definitions/Misc/TraceInfo.h"
|
||||
#include <optional>
|
||||
|
||||
MAKE_SIGNATURE(CM_TraceToDispTree_True, "engine.dll", "48 8B C4 48 89 58 ? 48 89 70 ? 57 48 81 EC ? ? ? ? F3 0F 10 01", 0x0);
|
||||
MAKE_SIGNATURE(CM_TraceToDispTree_False, "engine.dll", "48 8B C4 48 89 58 ? 48 89 70 ? 57 48 83 EC ? F3 0F 10 01", 0x0);
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
#include "../Features/World/World.h"
|
||||
|
||||
MAKE_SIGNATURE(CModelLoader_Map_LoadModel, "engine.dll", "48 8B C4 48 89 58 ? 48 89 50 ? 48 89 48 ? 55 56 57 41 54 41 55 41 56 41 57 48 8D A8 ? ? ? ? 48 81 EC ? ? ? ? FF 05", 0x0);
|
||||
MAKE_SIGNATURE(CStaticPropMgr_LevelInit, "engine.dll", "40 57 48 81 EC ? ? ? ? 80 B9", 0x0);
|
||||
MAKE_SIGNATURE(R_LevelInit, "engine.dll", "48 83 EC ? 48 8D 0D ? ? ? ? FF 15 ? ? ? ? 48 8D 0D ? ? ? ? FF 15", 0x0);
|
||||
MAKE_SIGNATURE(CM_FreeMap, "engine.dll", "48 8D 0D ? ? ? ? E9 ? ? ? ? CC CC CC CC 48 89 5C 24 ? 57 48 83 EC ? 45 33 C9", 0x0);
|
||||
|
||||
MAKE_HOOK(CModelLoader_Map_LoadModel, S::CModelLoader_Map_LoadModel(), void,
|
||||
@@ -18,12 +18,12 @@ MAKE_HOOK(CModelLoader_Map_LoadModel, S::CModelLoader_Map_LoadModel(), void,
|
||||
F::World.CacheEntities();
|
||||
}
|
||||
|
||||
MAKE_HOOK(CStaticPropMgr_LevelInit, S::CStaticPropMgr_LevelInit(), void,
|
||||
void* rcx)
|
||||
MAKE_HOOK(R_LevelInit, S::R_LevelInit(), void,
|
||||
)
|
||||
{
|
||||
DEBUG_RETURN(CStaticPropMgr_LevelInit, rcx);
|
||||
DEBUG_RETURN(R_LevelInit);
|
||||
|
||||
CALL_ORIGINAL(rcx);
|
||||
CALL_ORIGINAL();
|
||||
|
||||
F::World.CacheProps();
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include "Interfaces/CGlobalVarsBase.h"
|
||||
#include "Interfaces/CHLClient.h"
|
||||
#include "Interfaces/CHLTVCamera.h"
|
||||
#include "Interfaces/CMDLCache.h"
|
||||
#include "Interfaces/CStaticPropMgr.h"
|
||||
#include "Interfaces/CTFGameRules.h"
|
||||
#include "Interfaces/CTFGCClientSystem.h"
|
||||
|
||||
@@ -0,0 +1,118 @@
|
||||
#pragma once
|
||||
#include "../Misc/IMDLCache.h"
|
||||
#include "../Misc/IStudioDataCache.h"
|
||||
#include "../Misc/CDefaultDataCacheClient.h"
|
||||
#include "../Misc/VCollide.h"
|
||||
#include "../Misc/Studio.h"
|
||||
#include "../Misc/CUtlDict.h"
|
||||
#include "../Misc/CUtlLinkedList.h"
|
||||
|
||||
class IDataCacheSection;
|
||||
typedef void* DataCacheHandle_t;
|
||||
|
||||
struct studiodata_t
|
||||
{
|
||||
DataCacheHandle_t m_MDLCache;
|
||||
vcollide_t m_VCollisionData;
|
||||
studiohwdata_t m_HardwareData;
|
||||
#if defined( USE_HARDWARE_CACHE )
|
||||
DataCacheHandle_t m_HardwareDataCache;
|
||||
#endif
|
||||
unsigned short m_nFlags;
|
||||
short m_nRefCount;
|
||||
virtualmodel_t* m_pVirtualModel;
|
||||
int m_nAnimBlockCount;
|
||||
DataCacheHandle_t* m_pAnimBlock;
|
||||
unsigned long* m_iFakeAnimBlockStall;
|
||||
DataCacheHandle_t m_VertexCache;
|
||||
bool m_VertexDataIsCompressed;
|
||||
int m_nAutoplaySequenceCount;
|
||||
unsigned short* m_pAutoplaySequenceList;
|
||||
void* m_pUserData;
|
||||
};
|
||||
|
||||
struct AsyncInfo_t
|
||||
{
|
||||
FSAsyncControl_t hControl;
|
||||
MDLHandle_t hModel;
|
||||
MDLCacheDataType_t type;
|
||||
int iAnimBlock;
|
||||
};
|
||||
|
||||
class CThreadFastMutex
|
||||
{
|
||||
public:
|
||||
volatile uint32 m_ownerID;
|
||||
int m_depth;
|
||||
};
|
||||
|
||||
class CMDLCache : public CTier3AppSystem<IMDLCache>, public IStudioDataCache, public CDefaultDataCacheClient
|
||||
{
|
||||
typedef CTier3AppSystem<IMDLCache> BaseClass;
|
||||
|
||||
public:
|
||||
virtual bool Connect(CreateInterfaceFn factory) = 0;
|
||||
virtual void Disconnect() = 0;
|
||||
virtual void* QueryInterface(const char* pInterfaceName) = 0;
|
||||
virtual InitReturnVal_t Init() = 0;
|
||||
virtual void Shutdown() = 0;
|
||||
virtual MDLHandle_t FindMDL(const char* pMDLRelativePath) = 0;
|
||||
virtual int AddRef(MDLHandle_t handle) = 0;
|
||||
virtual int Release(MDLHandle_t handle) = 0;
|
||||
virtual int GetRef(MDLHandle_t handle) = 0;
|
||||
virtual void MarkAsLoaded(MDLHandle_t handle) = 0;
|
||||
virtual studiohdr_t* GetStudioHdr(MDLHandle_t handle) = 0;
|
||||
virtual studiohwdata_t* GetHardwareData(MDLHandle_t handle) = 0;
|
||||
virtual vcollide_t* GetVCollide(MDLHandle_t handle) = 0;
|
||||
virtual vcollide_t* GetVCollideEx(MDLHandle_t handle, bool synchronousLoad = true) = 0;
|
||||
virtual unsigned char* GetAnimBlock(MDLHandle_t handle, int nBlock) = 0;
|
||||
virtual virtualmodel_t* GetVirtualModel(MDLHandle_t handle) = 0;
|
||||
virtual virtualmodel_t* GetVirtualModelFast(const studiohdr_t* pStudioHdr, MDLHandle_t handle) = 0;
|
||||
virtual int GetAutoplayList(MDLHandle_t handle, unsigned short** pOut) = 0;
|
||||
virtual void TouchAllData(MDLHandle_t handle) = 0;
|
||||
virtual void SetUserData(MDLHandle_t handle, void* pData) = 0;
|
||||
virtual void* GetUserData(MDLHandle_t handle) = 0;
|
||||
virtual bool IsErrorModel(MDLHandle_t handle) = 0;
|
||||
virtual void SetCacheNotify(IMDLCacheNotify* pNotify) = 0;
|
||||
virtual vertexFileHeader_t* GetVertexData(MDLHandle_t handle) = 0;
|
||||
virtual void Flush(MDLCacheFlush_t nFlushFlags = MDLCACHE_FLUSH_ALL) = 0;
|
||||
virtual void Flush(MDLHandle_t handle, int nFlushFlags = MDLCACHE_FLUSH_ALL) = 0;
|
||||
virtual const char* GetModelName(MDLHandle_t handle) = 0;
|
||||
virtual void BeginLock() = 0;
|
||||
virtual void EndLock() = 0;
|
||||
virtual int* GetFrameUnlockCounterPtrOLD() = 0;
|
||||
virtual int* GetFrameUnlockCounterPtr(MDLCacheDataType_t type) = 0;
|
||||
virtual void FinishPendingLoads() = 0;
|
||||
virtual bool GetVCollideSize(MDLHandle_t handle, int* pVCollideSize) = 0;
|
||||
virtual void BeginMapLoad() = 0;
|
||||
virtual void EndMapLoad() = 0;
|
||||
virtual void InitPreloadData(bool rebuild) = 0;
|
||||
virtual void ShutdownPreloadData() = 0;
|
||||
virtual bool IsDataLoaded(MDLHandle_t handle, MDLCacheDataType_t type) = 0;
|
||||
virtual studiohdr_t* LockStudioHdr(MDLHandle_t handle) = 0;
|
||||
virtual void UnlockStudioHdr(MDLHandle_t handle) = 0;
|
||||
virtual bool PreloadModel(MDLHandle_t handle) = 0;
|
||||
virtual void ResetErrorModelStatus(MDLHandle_t handle) = 0;
|
||||
virtual void MarkFrame() = 0;
|
||||
virtual bool HandleCacheNotification(const DataCacheNotification_t& notification) = 0;
|
||||
virtual bool GetItemName(DataCacheClientID_t clientId, const void* pItem, char* pDest, unsigned nMaxLen) = 0;
|
||||
virtual bool GetAsyncLoad(MDLCacheDataType_t type) = 0;
|
||||
virtual bool SetAsyncLoad(MDLCacheDataType_t type, bool bAsync) = 0;
|
||||
|
||||
public:
|
||||
IDataCacheSection* m_pModelCacheSection;
|
||||
IDataCacheSection* m_pMeshCacheSection;
|
||||
IDataCacheSection* m_pAnimBlockCacheSection;
|
||||
int m_nModelCacheFrameLocks;
|
||||
int m_nMeshCacheFrameLocks;
|
||||
CUtlDict<studiodata_t*, MDLHandle_t> m_MDLDict;
|
||||
IMDLCacheNotify* m_pCacheNotify;
|
||||
CUtlFixedLinkedList<AsyncInfo_t> m_PendingAsyncs;
|
||||
CThreadFastMutex m_QueuedLoadingMutex;
|
||||
CThreadFastMutex m_AsyncMutex;
|
||||
bool m_bLostVideoMemory : 1;
|
||||
bool m_bConnected : 1;
|
||||
bool m_bInitialized : 1;
|
||||
};
|
||||
|
||||
MAKE_INTERFACE_VERSION(CMDLCache, MDLCache, "datacache.dll", "MDLCache004");
|
||||
@@ -16,7 +16,6 @@ struct studiomeshdata_t;
|
||||
struct LightDesc_t;
|
||||
struct studiohwdata_t;
|
||||
struct Ray_t;
|
||||
struct vertexFileHeader_t;
|
||||
struct FlashlightState_t;
|
||||
struct FileHeader_t;
|
||||
typedef unsigned short MDLHandle_t;
|
||||
@@ -175,13 +174,6 @@ struct model_array_instance_t
|
||||
matrix3x4 modelToWorld;
|
||||
};
|
||||
|
||||
class IStudioDataCache : public IAppSystem
|
||||
{
|
||||
public:
|
||||
virtual bool VerifyHeaders(studiohdr_t* pStudioHdr) = 0;
|
||||
virtual vertexFileHeader_t* CacheVertexData(studiohdr_t* pStudioHdr) = 0;
|
||||
};
|
||||
|
||||
class IStudioRender : public IAppSystem
|
||||
{
|
||||
public:
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
#pragma once
|
||||
#include "BaseTypes.h"
|
||||
|
||||
typedef uint32 DataCacheClientID_t;
|
||||
|
||||
enum DataCacheNotificationType_t
|
||||
{
|
||||
DC_NONE,
|
||||
DC_AGE_DISCARD,
|
||||
DC_FLUSH_DISCARD,
|
||||
DC_REMOVED,
|
||||
DC_RELOCATE,
|
||||
DC_PRINT_INF0,
|
||||
};
|
||||
|
||||
struct DataCacheNotification_t
|
||||
{
|
||||
DataCacheNotificationType_t type;
|
||||
const char* pszSectionName;
|
||||
DataCacheClientID_t clientId;
|
||||
const void* pItemData;
|
||||
unsigned nItemSize;
|
||||
};
|
||||
|
||||
class IDataCacheClient
|
||||
{
|
||||
public:
|
||||
virtual bool HandleCacheNotification(const DataCacheNotification_t& notification) = 0;
|
||||
virtual bool GetItemName(DataCacheClientID_t clientId, const void* pItem, char* pDest, unsigned nMaxLen) = 0;
|
||||
};
|
||||
|
||||
//-------------------------------------
|
||||
|
||||
class CDefaultDataCacheClient : public IDataCacheClient
|
||||
{
|
||||
public:
|
||||
virtual bool HandleCacheNotification(const DataCacheNotification_t& notification)
|
||||
{
|
||||
switch (notification.type)
|
||||
{
|
||||
case DC_AGE_DISCARD:
|
||||
case DC_FLUSH_DISCARD:
|
||||
case DC_REMOVED:
|
||||
default:
|
||||
//Assert(0);
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual bool GetItemName(DataCacheClientID_t clientId, const void* pItem, char* pDest, unsigned nMaxLen)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,332 @@
|
||||
#pragma once
|
||||
|
||||
#pragma warning (push)
|
||||
#pragma warning (disable:4100)
|
||||
#pragma warning (disable:4514)
|
||||
|
||||
#ifdef UTBLOCKLMEMORY_TRACK
|
||||
#define UTLBLOCKMEMORY_TRACK_ALLOC() MemAlloc_RegisterAllocation( "Sum of all UtlBlockMemory", 0, NumAllocated() * sizeof(T), NumAllocated() * sizeof(T), 0 )
|
||||
#define UTLBLOCKMEMORY_TRACK_FREE() if ( !m_pMemory ) ; else MemAlloc_RegisterDeallocation( "Sum of all UtlBlockMemory", 0, NumAllocated() * sizeof(T), NumAllocated() * sizeof(T), 0 )
|
||||
#else
|
||||
#define UTLBLOCKMEMORY_TRACK_ALLOC() ((void)0)
|
||||
#define UTLBLOCKMEMORY_TRACK_FREE() ((void)0)
|
||||
#endif
|
||||
|
||||
__forceinline uint SmallestPowerOfTwoGreaterOrEqual(uint x)
|
||||
{
|
||||
x -= 1;
|
||||
x |= x >> 1;
|
||||
x |= x >> 2;
|
||||
x |= x >> 4;
|
||||
x |= x >> 8;
|
||||
x |= x >> 16;
|
||||
return x + 1;
|
||||
}
|
||||
|
||||
template< class T, class I >
|
||||
class CUtlBlockMemory
|
||||
{
|
||||
public:
|
||||
// constructor, destructor
|
||||
CUtlBlockMemory(int nGrowSize = 0, int nInitSize = 0);
|
||||
~CUtlBlockMemory();
|
||||
|
||||
// Set the size by which the memory grows - round up to the next power of 2
|
||||
void Init(int nGrowSize = 0, int nInitSize = 0);
|
||||
|
||||
// here to match CUtlMemory, but only used by ResetDbgInfo, so it can just return NULL
|
||||
T* Base() { return NULL; }
|
||||
const T* Base() const { return NULL; }
|
||||
|
||||
class Iterator_t
|
||||
{
|
||||
public:
|
||||
Iterator_t(I i) : index(i) {}
|
||||
I index;
|
||||
|
||||
bool operator==(const Iterator_t it) const { return index == it.index; }
|
||||
bool operator!=(const Iterator_t it) const { return index != it.index; }
|
||||
};
|
||||
Iterator_t First() const { return Iterator_t(IsIdxValid(0) ? 0 : InvalidIndex()); }
|
||||
Iterator_t Next(const Iterator_t& it) const { return Iterator_t(IsIdxValid(it.index + 1) ? it.index + 1 : InvalidIndex()); }
|
||||
I GetIndex(const Iterator_t& it) const { return it.index; }
|
||||
bool IsIdxAfter(I i, const Iterator_t& it) const { return i > it.index; }
|
||||
bool IsValidIterator(const Iterator_t& it) const { return IsIdxValid(it.index); }
|
||||
Iterator_t InvalidIterator() const { return Iterator_t(InvalidIndex()); }
|
||||
|
||||
// element access
|
||||
T& operator[](I i);
|
||||
const T& operator[](I i) const;
|
||||
T& Element(I i);
|
||||
const T& Element(I i) const;
|
||||
|
||||
// Can we use this index?
|
||||
bool IsIdxValid(I i) const;
|
||||
static I InvalidIndex() { return (I)-1; }
|
||||
|
||||
void Swap(CUtlBlockMemory< T, I >& mem);
|
||||
|
||||
// Size
|
||||
int NumAllocated() const;
|
||||
int Count() const { return NumAllocated(); }
|
||||
|
||||
// Grows memory by max(num,growsize) rounded up to the next power of 2, and returns the allocation index/ptr
|
||||
void Grow(int num = 1);
|
||||
|
||||
// Makes sure we've got at least this much memory
|
||||
void EnsureCapacity(int num);
|
||||
|
||||
// Memory deallocation
|
||||
void Purge();
|
||||
|
||||
// Purge all but the given number of elements
|
||||
void Purge(int numElements);
|
||||
|
||||
protected:
|
||||
int Index(int major, int minor) const { return (major << m_nIndexShift) | minor; }
|
||||
int MajorIndex(int i) const { return i >> m_nIndexShift; }
|
||||
int MinorIndex(int i) const { return i & m_nIndexMask; }
|
||||
void ChangeSize(int nBlocks);
|
||||
int NumElementsInBlock() const { return m_nIndexMask + 1; }
|
||||
|
||||
T** m_pMemory;
|
||||
int m_nBlocks;
|
||||
int m_nIndexMask : 27;
|
||||
int m_nIndexShift : 5;
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// constructor, destructor
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
template< class T, class I >
|
||||
CUtlBlockMemory<T, I>::CUtlBlockMemory(int nGrowSize, int nInitAllocationCount)
|
||||
: m_pMemory(0), m_nBlocks(0), m_nIndexMask(0), m_nIndexShift(0)
|
||||
{
|
||||
Init(nGrowSize, nInitAllocationCount);
|
||||
}
|
||||
|
||||
template< class T, class I >
|
||||
CUtlBlockMemory<T, I>::~CUtlBlockMemory()
|
||||
{
|
||||
Purge();
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Fast swap
|
||||
//-----------------------------------------------------------------------------
|
||||
template< class T, class I >
|
||||
void CUtlBlockMemory<T, I>::Swap(CUtlBlockMemory< T, I >& mem)
|
||||
{
|
||||
std::swap(m_pMemory, mem.m_pMemory);
|
||||
std::swap(m_nBlocks, mem.m_nBlocks);
|
||||
std::swap(m_nIndexMask, mem.m_nIndexMask);
|
||||
std::swap(m_nIndexShift, mem.m_nIndexShift);
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Set the size by which the memory grows - round up to the next power of 2
|
||||
//-----------------------------------------------------------------------------
|
||||
template< class T, class I >
|
||||
void CUtlBlockMemory<T, I>::Init(int nGrowSize /* = 0 */, int nInitSize /* = 0 */)
|
||||
{
|
||||
Purge();
|
||||
|
||||
if (nGrowSize == 0)
|
||||
{
|
||||
// default grow size is smallest size s.t. c++ allocation overhead is ~6% of block size
|
||||
nGrowSize = (127 + sizeof(T)) / sizeof(T);
|
||||
}
|
||||
nGrowSize = SmallestPowerOfTwoGreaterOrEqual(nGrowSize);
|
||||
m_nIndexMask = nGrowSize - 1;
|
||||
|
||||
m_nIndexShift = 0;
|
||||
while (nGrowSize > 1)
|
||||
{
|
||||
nGrowSize >>= 1;
|
||||
++m_nIndexShift;
|
||||
}
|
||||
//Assert(m_nIndexMask + 1 == (1 << m_nIndexShift));
|
||||
|
||||
Grow(nInitSize);
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// element access
|
||||
//-----------------------------------------------------------------------------
|
||||
template< class T, class I >
|
||||
inline T& CUtlBlockMemory<T, I>::operator[](I i)
|
||||
{
|
||||
//Assert(IsIdxValid(i));
|
||||
T* pBlock = m_pMemory[MajorIndex(i)];
|
||||
return pBlock[MinorIndex(i)];
|
||||
}
|
||||
|
||||
template< class T, class I >
|
||||
inline const T& CUtlBlockMemory<T, I>::operator[](I i) const
|
||||
{
|
||||
//Assert(IsIdxValid(i));
|
||||
const T* pBlock = m_pMemory[MajorIndex(i)];
|
||||
return pBlock[MinorIndex(i)];
|
||||
}
|
||||
|
||||
template< class T, class I >
|
||||
inline T& CUtlBlockMemory<T, I>::Element(I i)
|
||||
{
|
||||
//Assert(IsIdxValid(i));
|
||||
T* pBlock = m_pMemory[MajorIndex(i)];
|
||||
return pBlock[MinorIndex(i)];
|
||||
}
|
||||
|
||||
template< class T, class I >
|
||||
inline const T& CUtlBlockMemory<T, I>::Element(I i) const
|
||||
{
|
||||
//Assert(IsIdxValid(i));
|
||||
const T* pBlock = m_pMemory[MajorIndex(i)];
|
||||
return pBlock[MinorIndex(i)];
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Size
|
||||
//-----------------------------------------------------------------------------
|
||||
template< class T, class I >
|
||||
inline int CUtlBlockMemory<T, I>::NumAllocated() const
|
||||
{
|
||||
return m_nBlocks * NumElementsInBlock();
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Is element index valid?
|
||||
//-----------------------------------------------------------------------------
|
||||
template< class T, class I >
|
||||
inline bool CUtlBlockMemory<T, I>::IsIdxValid(I i) const
|
||||
{
|
||||
return (i >= 0) && (MajorIndex(i) < m_nBlocks);
|
||||
}
|
||||
|
||||
template< class T, class I >
|
||||
void CUtlBlockMemory<T, I>::Grow(int num)
|
||||
{
|
||||
if (num <= 0)
|
||||
return;
|
||||
|
||||
int nBlockSize = NumElementsInBlock();
|
||||
int nBlocks = (num + nBlockSize - 1) / nBlockSize;
|
||||
|
||||
ChangeSize(m_nBlocks + nBlocks);
|
||||
}
|
||||
|
||||
template< class T, class I >
|
||||
void CUtlBlockMemory<T, I>::ChangeSize(int nBlocks)
|
||||
{
|
||||
UTLBLOCKMEMORY_TRACK_FREE(); // this must stay before the recalculation of m_nBlocks, since it implicitly uses the old value
|
||||
|
||||
int nBlocksOld = m_nBlocks;
|
||||
m_nBlocks = nBlocks;
|
||||
|
||||
UTLBLOCKMEMORY_TRACK_ALLOC(); // this must stay after the recalculation of m_nBlocks, since it implicitly uses the new value
|
||||
|
||||
if (m_pMemory)
|
||||
{
|
||||
// free old blocks if shrinking
|
||||
// Only possible if m_pMemory is non-NULL (and avoids PVS-Studio warning)
|
||||
for (int i = m_nBlocks; i < nBlocksOld; ++i)
|
||||
{
|
||||
UTLBLOCKMEMORY_TRACK_FREE();
|
||||
free((void*)m_pMemory[i]);
|
||||
}
|
||||
|
||||
MEM_ALLOC_CREDIT_CLASS();
|
||||
m_pMemory = (T**)realloc(m_pMemory, m_nBlocks * sizeof(T*));
|
||||
//Assert(m_pMemory);
|
||||
}
|
||||
else
|
||||
{
|
||||
MEM_ALLOC_CREDIT_CLASS();
|
||||
m_pMemory = (T**)malloc(m_nBlocks * sizeof(T*));
|
||||
//Assert(m_pMemory);
|
||||
}
|
||||
|
||||
if (!m_pMemory)
|
||||
{
|
||||
//Error("CUtlBlockMemory overflow!\n");
|
||||
}
|
||||
|
||||
// allocate new blocks if growing
|
||||
int nBlockSize = NumElementsInBlock();
|
||||
for (int i = nBlocksOld; i < m_nBlocks; ++i)
|
||||
{
|
||||
MEM_ALLOC_CREDIT_CLASS();
|
||||
m_pMemory[i] = (T*)malloc(nBlockSize * sizeof(T));
|
||||
//Assert(m_pMemory[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Makes sure we've got at least this much memory
|
||||
//-----------------------------------------------------------------------------
|
||||
template< class T, class I >
|
||||
inline void CUtlBlockMemory<T, I>::EnsureCapacity(int num)
|
||||
{
|
||||
Grow(num - NumAllocated());
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Memory deallocation
|
||||
//-----------------------------------------------------------------------------
|
||||
template< class T, class I >
|
||||
void CUtlBlockMemory<T, I>::Purge()
|
||||
{
|
||||
if (!m_pMemory)
|
||||
return;
|
||||
|
||||
for (int i = 0; i < m_nBlocks; ++i)
|
||||
{
|
||||
UTLBLOCKMEMORY_TRACK_FREE();
|
||||
free((void*)m_pMemory[i]);
|
||||
}
|
||||
m_nBlocks = 0;
|
||||
|
||||
UTLBLOCKMEMORY_TRACK_FREE();
|
||||
free((void*)m_pMemory);
|
||||
m_pMemory = 0;
|
||||
}
|
||||
|
||||
template< class T, class I >
|
||||
void CUtlBlockMemory<T, I>::Purge(int numElements)
|
||||
{
|
||||
//Assert(numElements >= 0);
|
||||
|
||||
int nAllocated = NumAllocated();
|
||||
if (numElements > nAllocated)
|
||||
{
|
||||
// Ensure this isn't a grow request in disguise.
|
||||
//Assert(numElements <= nAllocated);
|
||||
return;
|
||||
}
|
||||
|
||||
if (numElements <= 0)
|
||||
{
|
||||
Purge();
|
||||
return;
|
||||
}
|
||||
|
||||
int nBlockSize = NumElementsInBlock();
|
||||
int nBlocksOld = m_nBlocks;
|
||||
int nBlocks = (numElements + nBlockSize - 1) / nBlockSize;
|
||||
|
||||
// If the number of blocks is the same as the allocated number of blocks, we are done.
|
||||
if (nBlocks == m_nBlocks)
|
||||
return;
|
||||
|
||||
ChangeSize(nBlocks);
|
||||
}
|
||||
|
||||
#pragma warning (pop)
|
||||
@@ -0,0 +1,327 @@
|
||||
#pragma once
|
||||
#include "CUtlMap.h"
|
||||
|
||||
enum EDictCompareType
|
||||
{
|
||||
k_eDictCompareTypeCaseSensitive = 0,
|
||||
k_eDictCompareTypeCaseInsensitive = 1,
|
||||
k_eDictCompareTypeFilenames
|
||||
};
|
||||
|
||||
#define FOR_EACH_DICT( dictName, iteratorName ) \
|
||||
for( int iteratorName=dictName.First(); iteratorName != dictName.InvalidIndex(); iteratorName = dictName.Next( iteratorName ) )
|
||||
|
||||
#define FOR_EACH_DICT_FAST( dictName, iteratorName ) \
|
||||
for ( int iteratorName = 0; iteratorName < dictName.MaxElement(); ++iteratorName ) if ( !dictName.IsValidIndex( iteratorName ) ) continue; else
|
||||
|
||||
template <class T, class I = int >
|
||||
class CUtlDict
|
||||
{
|
||||
public:
|
||||
// constructor, destructor
|
||||
// Left at growSize = 0, the memory will first allocate 1 element and double in size
|
||||
// at each increment.
|
||||
CUtlDict(int compareType = k_eDictCompareTypeCaseInsensitive, int growSize = 0, int initSize = 0);
|
||||
~CUtlDict();
|
||||
|
||||
void EnsureCapacity(int);
|
||||
|
||||
// gets particular elements
|
||||
T& Element(I i);
|
||||
const T& Element(I i) const;
|
||||
T& operator[](I i);
|
||||
const T& operator[](I i) const;
|
||||
|
||||
// gets element names
|
||||
char* GetElementName(I i);
|
||||
char const* GetElementName(I i) const;
|
||||
|
||||
void SetElementName(I i, char const* pName);
|
||||
|
||||
// Number of elements
|
||||
unsigned int Count() const;
|
||||
|
||||
// Number of allocated slots
|
||||
I MaxElement() const;
|
||||
|
||||
// Checks if a node is valid and in the tree
|
||||
bool IsValidIndex(I i) const;
|
||||
|
||||
// Invalid index
|
||||
static I InvalidIndex();
|
||||
|
||||
// Insert method (inserts in order)
|
||||
I Insert(const char* pName, const T& element);
|
||||
I Insert(const char* pName);
|
||||
|
||||
// Find method
|
||||
I Find(const char* pName) const;
|
||||
bool HasElement(const char* pName) const;
|
||||
|
||||
// Remove methods
|
||||
void RemoveAt(I i);
|
||||
void Remove(const char* pName);
|
||||
void RemoveAll();
|
||||
|
||||
// Purge memory
|
||||
void Purge();
|
||||
void PurgeAndDeleteElements(); // Call delete on each element.
|
||||
|
||||
// Iteration methods
|
||||
I First() const;
|
||||
I Next(I i) const;
|
||||
|
||||
// Nested typedefs, for code that might need
|
||||
// to fish out the index type from a given dict
|
||||
typedef I IndexType_t;
|
||||
|
||||
protected:
|
||||
typedef CUtlMap<const char*, T, I> DictElementMap_t;
|
||||
DictElementMap_t m_Elements;
|
||||
};
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// constructor, destructor
|
||||
//-----------------------------------------------------------------------------
|
||||
template <class T, class I>
|
||||
CUtlDict<T, I>::CUtlDict(int compareType, int growSize, int initSize) : m_Elements(growSize, initSize)
|
||||
{
|
||||
if (compareType == k_eDictCompareTypeFilenames)
|
||||
{
|
||||
m_Elements.SetLessFunc(CaselessStringLessThanIgnoreSlashes);
|
||||
}
|
||||
else if (compareType == k_eDictCompareTypeCaseInsensitive)
|
||||
{
|
||||
m_Elements.SetLessFunc(CaselessStringLessThan);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_Elements.SetLessFunc(StringLessThan);
|
||||
}
|
||||
}
|
||||
|
||||
template <class T, class I>
|
||||
CUtlDict<T, I>::~CUtlDict()
|
||||
{
|
||||
Purge();
|
||||
}
|
||||
|
||||
template <class T, class I>
|
||||
inline void CUtlDict<T, I>::EnsureCapacity(int num)
|
||||
{
|
||||
return m_Elements.EnsureCapacity(num);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// gets particular elements
|
||||
//-----------------------------------------------------------------------------
|
||||
template <class T, class I>
|
||||
inline T& CUtlDict<T, I>::Element(I i)
|
||||
{
|
||||
return m_Elements[i];
|
||||
}
|
||||
|
||||
template <class T, class I>
|
||||
inline const T& CUtlDict<T, I>::Element(I i) const
|
||||
{
|
||||
return m_Elements[i];
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// gets element names
|
||||
//-----------------------------------------------------------------------------
|
||||
template <class T, class I>
|
||||
inline char* CUtlDict<T, I>::GetElementName(I i)
|
||||
{
|
||||
return (char*)m_Elements.Key(i);
|
||||
}
|
||||
|
||||
template <class T, class I>
|
||||
inline char const* CUtlDict<T, I>::GetElementName(I i) const
|
||||
{
|
||||
return m_Elements.Key(i);
|
||||
}
|
||||
|
||||
template <class T, class I>
|
||||
inline T& CUtlDict<T, I>::operator[](I i)
|
||||
{
|
||||
return Element(i);
|
||||
}
|
||||
|
||||
template <class T, class I>
|
||||
inline const T& CUtlDict<T, I>::operator[](I i) const
|
||||
{
|
||||
return Element(i);
|
||||
}
|
||||
|
||||
template <class T, class I>
|
||||
inline void CUtlDict<T, I>::SetElementName(I i, char const* pName)
|
||||
{
|
||||
MEM_ALLOC_CREDIT_CLASS();
|
||||
// TODO: This makes a copy of the old element
|
||||
// TODO: This relies on the rb tree putting the most recently
|
||||
// removed element at the head of the insert list
|
||||
free((void*)m_Elements.Key(i));
|
||||
m_Elements.Reinsert(strdup(pName), i);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Num elements
|
||||
//-----------------------------------------------------------------------------
|
||||
template <class T, class I>
|
||||
inline unsigned int CUtlDict<T, I>::Count() const
|
||||
{
|
||||
return m_Elements.Count();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Number of allocated slots
|
||||
//-----------------------------------------------------------------------------
|
||||
template <class T, class I>
|
||||
inline I CUtlDict<T, I>::MaxElement() const
|
||||
{
|
||||
return m_Elements.MaxElement();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Checks if a node is valid and in the tree
|
||||
//-----------------------------------------------------------------------------
|
||||
template <class T, class I>
|
||||
inline bool CUtlDict<T, I>::IsValidIndex(I i) const
|
||||
{
|
||||
return m_Elements.IsValidIndex(i);
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Invalid index
|
||||
//-----------------------------------------------------------------------------
|
||||
template <class T, class I>
|
||||
inline I CUtlDict<T, I>::InvalidIndex()
|
||||
{
|
||||
return DictElementMap_t::InvalidIndex();
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Delete a node from the tree
|
||||
//-----------------------------------------------------------------------------
|
||||
template <class T, class I>
|
||||
void CUtlDict<T, I>::RemoveAt(I elem)
|
||||
{
|
||||
free((void*)m_Elements.Key(elem));
|
||||
m_Elements.RemoveAt(elem);
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// remove a node in the tree
|
||||
//-----------------------------------------------------------------------------
|
||||
template <class T, class I> void CUtlDict<T, I>::Remove(const char* search)
|
||||
{
|
||||
I node = Find(search);
|
||||
if (node != InvalidIndex())
|
||||
{
|
||||
RemoveAt(node);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Removes all nodes from the tree
|
||||
//-----------------------------------------------------------------------------
|
||||
template <class T, class I>
|
||||
void CUtlDict<T, I>::RemoveAll()
|
||||
{
|
||||
typename DictElementMap_t::IndexType_t index = m_Elements.FirstInorder();
|
||||
while (index != m_Elements.InvalidIndex())
|
||||
{
|
||||
free((void*)m_Elements.Key(index));
|
||||
index = m_Elements.NextInorder(index);
|
||||
}
|
||||
|
||||
m_Elements.RemoveAll();
|
||||
}
|
||||
|
||||
template <class T, class I>
|
||||
void CUtlDict<T, I>::Purge()
|
||||
{
|
||||
RemoveAll();
|
||||
}
|
||||
|
||||
|
||||
template <class T, class I>
|
||||
void CUtlDict<T, I>::PurgeAndDeleteElements()
|
||||
{
|
||||
// Delete all the elements.
|
||||
I index = m_Elements.FirstInorder();
|
||||
while (index != m_Elements.InvalidIndex())
|
||||
{
|
||||
free((void*)m_Elements.Key(index));
|
||||
delete m_Elements[index];
|
||||
index = m_Elements.NextInorder(index);
|
||||
}
|
||||
|
||||
m_Elements.RemoveAll();
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// inserts a node into the tree
|
||||
//-----------------------------------------------------------------------------
|
||||
template <class T, class I>
|
||||
I CUtlDict<T, I>::Insert(const char* pName, const T& element)
|
||||
{
|
||||
MEM_ALLOC_CREDIT_CLASS();
|
||||
return m_Elements.Insert(strdup(pName), element);
|
||||
}
|
||||
|
||||
template <class T, class I>
|
||||
I CUtlDict<T, I>::Insert(const char* pName)
|
||||
{
|
||||
MEM_ALLOC_CREDIT_CLASS();
|
||||
return m_Elements.Insert(strdup(pName));
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// finds a node in the tree
|
||||
//-----------------------------------------------------------------------------
|
||||
template <class T, class I>
|
||||
I CUtlDict<T, I>::Find(const char* pName) const
|
||||
{
|
||||
MEM_ALLOC_CREDIT_CLASS();
|
||||
if (pName)
|
||||
return m_Elements.Find(pName);
|
||||
else
|
||||
return InvalidIndex();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// returns true if we already have this node
|
||||
//-----------------------------------------------------------------------------
|
||||
template <class T, class I>
|
||||
bool CUtlDict<T, I>::HasElement(const char* pName) const
|
||||
{
|
||||
if (pName)
|
||||
return m_Elements.IsValidIndex(m_Elements.Find(pName));
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Iteration methods
|
||||
//-----------------------------------------------------------------------------
|
||||
template <class T, class I>
|
||||
I CUtlDict<T, I>::First() const
|
||||
{
|
||||
return m_Elements.FirstInorder();
|
||||
}
|
||||
|
||||
template <class T, class I>
|
||||
I CUtlDict<T, I>::Next(I i) const
|
||||
{
|
||||
return m_Elements.NextInorder(i);
|
||||
}
|
||||
@@ -0,0 +1,327 @@
|
||||
#pragma once
|
||||
#include "../Steam/SteamTypes.h"
|
||||
|
||||
#pragma warning (push)
|
||||
#pragma warning (disable:4100)
|
||||
#pragma warning (disable:4514)
|
||||
|
||||
#ifdef UTLFIXEDMEMORY_TRACK
|
||||
#define UTLFIXEDMEMORY_TRACK_ALLOC() MemAlloc_RegisterAllocation( "Sum of all UtlFixedMemory", 0, NumAllocated() * sizeof(T), NumAllocated() * sizeof(T), 0 )
|
||||
#define UTLFIXEDMEMORY_TRACK_FREE() if ( !m_pMemory ) ; else MemAlloc_RegisterDeallocation( "Sum of all UtlFixedMemory", 0, NumAllocated() * sizeof(T), NumAllocated() * sizeof(T), 0 )
|
||||
#else
|
||||
#define UTLFIXEDMEMORY_TRACK_ALLOC() ((void)0)
|
||||
#define UTLFIXEDMEMORY_TRACK_FREE() ((void)0)
|
||||
#endif
|
||||
|
||||
template< class T >
|
||||
class CUtlFixedMemory
|
||||
{
|
||||
public:
|
||||
// constructor, destructor
|
||||
CUtlFixedMemory(int nGrowSize = 0, int nInitSize = 0);
|
||||
~CUtlFixedMemory();
|
||||
|
||||
// Set the size by which the memory grows
|
||||
void Init(int nGrowSize = 0, int nInitSize = 0);
|
||||
|
||||
// here to match CUtlMemory, but only used by ResetDbgInfo, so it can just return NULL
|
||||
T* Base() { return NULL; }
|
||||
const T* Base() const { return NULL; }
|
||||
|
||||
protected:
|
||||
struct BlockHeader_t;
|
||||
|
||||
public:
|
||||
class Iterator_t
|
||||
{
|
||||
public:
|
||||
Iterator_t(BlockHeader_t* p, int i) : m_pBlockHeader(p), m_nIndex(i) {}
|
||||
BlockHeader_t* m_pBlockHeader;
|
||||
intp m_nIndex;
|
||||
|
||||
bool operator==(const Iterator_t it) const { return m_pBlockHeader == it.m_pBlockHeader && m_nIndex == it.m_nIndex; }
|
||||
bool operator!=(const Iterator_t it) const { return m_pBlockHeader != it.m_pBlockHeader || m_nIndex != it.m_nIndex; }
|
||||
};
|
||||
Iterator_t First() const { return m_pBlocks ? Iterator_t(m_pBlocks, 0) : InvalidIterator(); }
|
||||
Iterator_t Next(const Iterator_t& it) const
|
||||
{
|
||||
//Assert(IsValidIterator(it));
|
||||
if (!IsValidIterator(it))
|
||||
return InvalidIterator();
|
||||
|
||||
BlockHeader_t* RESTRICT pHeader = it.m_pBlockHeader;
|
||||
if (it.m_nIndex + 1 < pHeader->m_nBlockSize)
|
||||
return Iterator_t(pHeader, it.m_nIndex + 1);
|
||||
|
||||
return pHeader->m_pNext ? Iterator_t(pHeader->m_pNext, 0) : InvalidIterator();
|
||||
}
|
||||
intp GetIndex(const Iterator_t& it) const
|
||||
{
|
||||
//Assert(IsValidIterator(it));
|
||||
if (!IsValidIterator(it))
|
||||
return InvalidIndex();
|
||||
|
||||
return (intp)(HeaderToBlock(it.m_pBlockHeader) + it.m_nIndex);
|
||||
}
|
||||
bool IsIdxAfter(intp i, const Iterator_t& it) const
|
||||
{
|
||||
//Assert(IsValidIterator(it));
|
||||
if (!IsValidIterator(it))
|
||||
return false;
|
||||
|
||||
if (IsInBlock(i, it.m_pBlockHeader))
|
||||
return i > GetIndex(it);
|
||||
|
||||
for (BlockHeader_t* RESTRICT pbh = it.m_pBlockHeader->m_pNext; pbh; pbh = pbh->m_pNext)
|
||||
{
|
||||
if (IsInBlock(i, pbh))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
bool IsValidIterator(const Iterator_t& it) const { return it.m_pBlockHeader && it.m_nIndex >= 0 && it.m_nIndex < it.m_pBlockHeader->m_nBlockSize; }
|
||||
Iterator_t InvalidIterator() const { return Iterator_t(NULL, INVALID_INDEX); }
|
||||
|
||||
// element access
|
||||
T& operator[](intp i);
|
||||
const T& operator[](intp i) const;
|
||||
T& Element(intp i);
|
||||
const T& Element(intp i) const;
|
||||
|
||||
// Can we use this index?
|
||||
bool IsIdxValid(intp i) const;
|
||||
|
||||
// Specify the invalid ('null') index that we'll only return on failure
|
||||
static const intp INVALID_INDEX = 0; // For use with COMPILE_TIME_ASSERT
|
||||
static intp InvalidIndex() { return INVALID_INDEX; }
|
||||
|
||||
// Size
|
||||
int NumAllocated() const;
|
||||
int Count() const { return NumAllocated(); }
|
||||
|
||||
// Grows memory by max(num,growsize), and returns the allocation index/ptr
|
||||
void Grow(int num = 1);
|
||||
|
||||
// Makes sure we've got at least this much memory
|
||||
void EnsureCapacity(int num);
|
||||
|
||||
// Memory deallocation
|
||||
void Purge();
|
||||
|
||||
protected:
|
||||
// Fast swap - WARNING: Swap invalidates all ptr-based indices!!!
|
||||
void Swap(CUtlFixedMemory< T >& mem);
|
||||
|
||||
bool IsInBlock(intp i, BlockHeader_t* pBlockHeader) const
|
||||
{
|
||||
T* p = (T*)i;
|
||||
const T* p0 = HeaderToBlock(pBlockHeader);
|
||||
return p >= p0 && p < p0 + pBlockHeader->m_nBlockSize;
|
||||
}
|
||||
|
||||
struct BlockHeader_t
|
||||
{
|
||||
BlockHeader_t* m_pNext;
|
||||
intp m_nBlockSize;
|
||||
};
|
||||
|
||||
const T* HeaderToBlock(const BlockHeader_t* pHeader) const { return (T*)(pHeader + 1); }
|
||||
const BlockHeader_t* BlockToHeader(const T* pBlock) const { return (BlockHeader_t*)(pBlock)-1; }
|
||||
|
||||
BlockHeader_t* m_pBlocks;
|
||||
int m_nAllocationCount;
|
||||
int m_nGrowSize;
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// constructor, destructor
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
template< class T >
|
||||
CUtlFixedMemory<T>::CUtlFixedMemory(int nGrowSize, int nInitAllocationCount)
|
||||
: m_pBlocks(0), m_nAllocationCount(0), m_nGrowSize(0)
|
||||
{
|
||||
Init(nGrowSize, nInitAllocationCount);
|
||||
}
|
||||
|
||||
template< class T >
|
||||
CUtlFixedMemory<T>::~CUtlFixedMemory()
|
||||
{
|
||||
Purge();
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Fast swap - WARNING: Swap invalidates all ptr-based indices!!!
|
||||
//-----------------------------------------------------------------------------
|
||||
template< class T >
|
||||
void CUtlFixedMemory<T>::Swap(CUtlFixedMemory< T >& mem)
|
||||
{
|
||||
V_swap(m_pBlocks, mem.m_pBlocks);
|
||||
V_swap(m_nAllocationCount, mem.m_nAllocationCount);
|
||||
V_swap(m_nGrowSize, mem.m_nGrowSize);
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Set the size by which the memory grows - round up to the next power of 2
|
||||
//-----------------------------------------------------------------------------
|
||||
template< class T >
|
||||
void CUtlFixedMemory<T>::Init(int nGrowSize /* = 0 */, int nInitSize /* = 0 */)
|
||||
{
|
||||
Purge();
|
||||
|
||||
m_nGrowSize = nGrowSize;
|
||||
|
||||
Grow(nInitSize);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// element access
|
||||
//-----------------------------------------------------------------------------
|
||||
template< class T >
|
||||
inline T& CUtlFixedMemory<T>::operator[](intp i)
|
||||
{
|
||||
//Assert(IsIdxValid(i));
|
||||
return *(T*)i;
|
||||
}
|
||||
|
||||
template< class T >
|
||||
inline const T& CUtlFixedMemory<T>::operator[](intp i) const
|
||||
{
|
||||
//Assert(IsIdxValid(i));
|
||||
return *(T*)i;
|
||||
}
|
||||
|
||||
template< class T >
|
||||
inline T& CUtlFixedMemory<T>::Element(intp i)
|
||||
{
|
||||
//Assert(IsIdxValid(i));
|
||||
return *(T*)i;
|
||||
}
|
||||
|
||||
template< class T >
|
||||
inline const T& CUtlFixedMemory<T>::Element(intp i) const
|
||||
{
|
||||
//Assert(IsIdxValid(i));
|
||||
return *(T*)i;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Size
|
||||
//-----------------------------------------------------------------------------
|
||||
template< class T >
|
||||
inline int CUtlFixedMemory<T>::NumAllocated() const
|
||||
{
|
||||
return m_nAllocationCount;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Is element index valid?
|
||||
//-----------------------------------------------------------------------------
|
||||
template< class T >
|
||||
inline bool CUtlFixedMemory<T>::IsIdxValid(intp i) const
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
for (BlockHeader_t* pbh = m_pBlocks; pbh; pbh = pbh->m_pNext)
|
||||
{
|
||||
if (IsInBlock(i, pbh))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
#else
|
||||
return i != InvalidIndex();
|
||||
#endif
|
||||
}
|
||||
|
||||
template< class T >
|
||||
void CUtlFixedMemory<T>::Grow(int num)
|
||||
{
|
||||
if (num <= 0)
|
||||
return;
|
||||
|
||||
int nBlockSize = m_nGrowSize;
|
||||
if (nBlockSize == 0)
|
||||
{
|
||||
if (m_nAllocationCount)
|
||||
{
|
||||
nBlockSize = m_nAllocationCount;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Compute an allocation which is at least as big as a cache line...
|
||||
nBlockSize = (31 + sizeof(T)) / sizeof(T);
|
||||
//Assert(nBlockSize);
|
||||
}
|
||||
}
|
||||
if (nBlockSize < num)
|
||||
{
|
||||
int n = (num + nBlockSize - 1) / nBlockSize;
|
||||
//Assert(n * nBlockSize >= num);
|
||||
//Assert((n - 1) * nBlockSize < num);
|
||||
nBlockSize *= n;
|
||||
}
|
||||
m_nAllocationCount += nBlockSize;
|
||||
|
||||
MEM_ALLOC_CREDIT_CLASS();
|
||||
BlockHeader_t* RESTRICT pBlockHeader = (BlockHeader_t*)malloc(sizeof(BlockHeader_t) + nBlockSize * sizeof(T));
|
||||
if (!pBlockHeader)
|
||||
{
|
||||
//Error("CUtlFixedMemory overflow!\n");
|
||||
}
|
||||
pBlockHeader->m_pNext = NULL;
|
||||
pBlockHeader->m_nBlockSize = nBlockSize;
|
||||
|
||||
if (!m_pBlocks)
|
||||
{
|
||||
m_pBlocks = pBlockHeader;
|
||||
}
|
||||
else
|
||||
{
|
||||
#if 1 // IsIdxAfter assumes that newly allocated blocks are at the end
|
||||
BlockHeader_t* RESTRICT pbh = m_pBlocks;
|
||||
while (pbh->m_pNext)
|
||||
{
|
||||
pbh = pbh->m_pNext;
|
||||
}
|
||||
pbh->m_pNext = pBlockHeader;
|
||||
#else
|
||||
pBlockHeader = m_pBlocks;
|
||||
pBlockHeader->m_pNext = m_pBlocks;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Makes sure we've got at least this much memory
|
||||
//-----------------------------------------------------------------------------
|
||||
template< class T >
|
||||
inline void CUtlFixedMemory<T>::EnsureCapacity(int num)
|
||||
{
|
||||
Grow(num - NumAllocated());
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Memory deallocation
|
||||
//-----------------------------------------------------------------------------
|
||||
template< class T >
|
||||
void CUtlFixedMemory<T>::Purge()
|
||||
{
|
||||
if (!m_pBlocks)
|
||||
return;
|
||||
|
||||
for (BlockHeader_t* pbh = m_pBlocks; pbh; )
|
||||
{
|
||||
BlockHeader_t* pFree = pbh;
|
||||
pbh = pbh->m_pNext;
|
||||
free(pFree);
|
||||
}
|
||||
m_pBlocks = NULL;
|
||||
m_nAllocationCount = 0;
|
||||
}
|
||||
|
||||
#pragma warning (pop)
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,227 @@
|
||||
#pragma once
|
||||
#include "CUtlRBTree.h"
|
||||
|
||||
#define FOR_EACH_MAP( mapName, iteratorName ) \
|
||||
for ( int iteratorName = (mapName).FirstInorder(); (mapName).IsUtlMap && iteratorName != (mapName).InvalidIndex(); iteratorName = (mapName).NextInorder( iteratorName ) )
|
||||
|
||||
#define FOR_EACH_MAP_FAST( mapName, iteratorName ) \
|
||||
for ( int iteratorName = 0; (mapName).IsUtlMap && iteratorName < (mapName).MaxElement(); ++iteratorName ) if ( !(mapName).IsValidIndex( iteratorName ) ) continue; else
|
||||
|
||||
struct base_utlmap_t
|
||||
{
|
||||
public:
|
||||
// This enum exists so that FOR_EACH_MAP and FOR_EACH_MAP_FAST cannot accidentally
|
||||
// be used on a type that is not a CUtlMap. If the code compiles then all is well.
|
||||
// The check for IsUtlMap being true should be free.
|
||||
// Using an enum rather than a static const bool ensures that this trick works even
|
||||
// with optimizations disabled on gcc.
|
||||
enum CompileTimeCheck
|
||||
{
|
||||
IsUtlMap = 1
|
||||
};
|
||||
};
|
||||
|
||||
template <typename K, typename T, typename I = unsigned short>
|
||||
class CUtlMap : public base_utlmap_t
|
||||
{
|
||||
public:
|
||||
typedef K KeyType_t;
|
||||
typedef T ElemType_t;
|
||||
typedef I IndexType_t;
|
||||
|
||||
// Less func typedef
|
||||
// Returns true if the first parameter is "less" than the second
|
||||
typedef bool (*LessFunc_t)(const KeyType_t&, const KeyType_t&);
|
||||
|
||||
// constructor, destructor
|
||||
// Left at growSize = 0, the memory will first allocate 1 element and double in size
|
||||
// at each increment.
|
||||
// LessFunc_t is required, but may be set after the constructor using SetLessFunc() below
|
||||
CUtlMap(int growSize = 0, int initSize = 0, LessFunc_t lessfunc = 0)
|
||||
: m_Tree(growSize, initSize, CKeyLess(lessfunc))
|
||||
{
|
||||
}
|
||||
|
||||
CUtlMap(LessFunc_t lessfunc)
|
||||
: m_Tree(CKeyLess(lessfunc))
|
||||
{
|
||||
}
|
||||
|
||||
void EnsureCapacity(int num) { m_Tree.EnsureCapacity(num); }
|
||||
|
||||
// gets particular elements
|
||||
ElemType_t& Element(IndexType_t i) { return m_Tree.Element(i).elem; }
|
||||
const ElemType_t& Element(IndexType_t i) const { return m_Tree.Element(i).elem; }
|
||||
ElemType_t& operator[](IndexType_t i) { return m_Tree.Element(i).elem; }
|
||||
const ElemType_t& operator[](IndexType_t i) const { return m_Tree.Element(i).elem; }
|
||||
KeyType_t& Key(IndexType_t i) { return m_Tree.Element(i).key; }
|
||||
const KeyType_t& Key(IndexType_t i) const { return m_Tree.Element(i).key; }
|
||||
|
||||
|
||||
// Num elements
|
||||
unsigned int Count() const { return m_Tree.Count(); }
|
||||
|
||||
// Max "size" of the vector
|
||||
IndexType_t MaxElement() const { return m_Tree.MaxElement(); }
|
||||
|
||||
// Checks if a node is valid and in the map
|
||||
bool IsValidIndex(IndexType_t i) const { return m_Tree.IsValidIndex(i); }
|
||||
|
||||
// Checks if the map as a whole is valid
|
||||
bool IsValid() const { return m_Tree.IsValid(); }
|
||||
|
||||
// Invalid index
|
||||
static IndexType_t InvalidIndex() { return CTree::InvalidIndex(); }
|
||||
|
||||
// Sets the less func
|
||||
void SetLessFunc(LessFunc_t func)
|
||||
{
|
||||
m_Tree.SetLessFunc(CKeyLess(func));
|
||||
}
|
||||
|
||||
// Insert method (inserts in order)
|
||||
IndexType_t Insert(const KeyType_t& key, const ElemType_t& insert)
|
||||
{
|
||||
Node_t node;
|
||||
node.key = key;
|
||||
node.elem = insert;
|
||||
return m_Tree.Insert(node);
|
||||
}
|
||||
|
||||
IndexType_t Insert(const KeyType_t& key)
|
||||
{
|
||||
Node_t node;
|
||||
node.key = key;
|
||||
return m_Tree.Insert(node);
|
||||
}
|
||||
|
||||
// Find method
|
||||
IndexType_t Find(const KeyType_t& key) const
|
||||
{
|
||||
Node_t dummyNode;
|
||||
dummyNode.key = key;
|
||||
return m_Tree.Find(dummyNode);
|
||||
}
|
||||
|
||||
// Remove methods
|
||||
void RemoveAt(IndexType_t i) { m_Tree.RemoveAt(i); }
|
||||
bool Remove(const KeyType_t& key)
|
||||
{
|
||||
Node_t dummyNode;
|
||||
dummyNode.key = key;
|
||||
return m_Tree.Remove(dummyNode);
|
||||
}
|
||||
|
||||
void RemoveAll() { m_Tree.RemoveAll(); }
|
||||
void Purge() { m_Tree.Purge(); }
|
||||
|
||||
// Purges the list and calls delete on each element in it.
|
||||
void PurgeAndDeleteElements();
|
||||
|
||||
// Iteration
|
||||
IndexType_t FirstInorder() const { return m_Tree.FirstInorder(); }
|
||||
IndexType_t NextInorder(IndexType_t i) const { return m_Tree.NextInorder(i); }
|
||||
IndexType_t PrevInorder(IndexType_t i) const { return m_Tree.PrevInorder(i); }
|
||||
IndexType_t LastInorder() const { return m_Tree.LastInorder(); }
|
||||
|
||||
// If you change the search key, this can be used to reinsert the
|
||||
// element into the map.
|
||||
void Reinsert(const KeyType_t& key, IndexType_t i)
|
||||
{
|
||||
m_Tree[i].key = key;
|
||||
m_Tree.Reinsert(i);
|
||||
}
|
||||
|
||||
IndexType_t InsertOrReplace(const KeyType_t& key, const ElemType_t& insert)
|
||||
{
|
||||
IndexType_t i = Find(key);
|
||||
if (i != InvalidIndex())
|
||||
{
|
||||
Element(i) = insert;
|
||||
return i;
|
||||
}
|
||||
|
||||
return Insert(key, insert);
|
||||
}
|
||||
|
||||
void Swap(CUtlMap< K, T, I >& that)
|
||||
{
|
||||
m_Tree.Swap(that.m_Tree);
|
||||
}
|
||||
|
||||
|
||||
struct Node_t
|
||||
{
|
||||
Node_t()
|
||||
{
|
||||
}
|
||||
|
||||
Node_t(const Node_t& from)
|
||||
: key(from.key),
|
||||
elem(from.elem)
|
||||
{
|
||||
}
|
||||
|
||||
KeyType_t key;
|
||||
ElemType_t elem;
|
||||
};
|
||||
|
||||
class CKeyLess
|
||||
{
|
||||
public:
|
||||
CKeyLess(LessFunc_t lessFunc) : m_LessFunc(lessFunc) {}
|
||||
|
||||
bool operator!() const
|
||||
{
|
||||
return !m_LessFunc;
|
||||
}
|
||||
|
||||
bool operator()(const Node_t& left, const Node_t& right) const
|
||||
{
|
||||
return m_LessFunc(left.key, right.key);
|
||||
}
|
||||
|
||||
LessFunc_t m_LessFunc;
|
||||
};
|
||||
|
||||
typedef CUtlRBTree<Node_t, I, CKeyLess> CTree;
|
||||
|
||||
CTree* AccessTree() { return &m_Tree; }
|
||||
|
||||
protected:
|
||||
CTree m_Tree;
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
// Purges the list and calls delete on each element in it.
|
||||
template< typename K, typename T, typename I >
|
||||
inline void CUtlMap<K, T, I>::PurgeAndDeleteElements()
|
||||
{
|
||||
for (I i = 0; i < MaxElement(); ++i)
|
||||
{
|
||||
if (!IsValidIndex(i))
|
||||
continue;
|
||||
|
||||
delete Element(i);
|
||||
}
|
||||
|
||||
Purge();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
// This is horrible and slow and meant to be used only when you're dealing with really
|
||||
// non-time/memory-critical code and desperately want to copy a whole map element-by-element
|
||||
// for whatever reason.
|
||||
template < typename K, typename T, typename I >
|
||||
void DeepCopyMap(const CUtlMap<K, T, I>& pmapIn, CUtlMap<K, T, I>* out_pmapOut)
|
||||
{
|
||||
Assert(out_pmapOut);
|
||||
|
||||
out_pmapOut->Purge();
|
||||
FOR_EACH_MAP_FAST(pmapIn, i)
|
||||
{
|
||||
out_pmapOut->Insert(pmapIn.Key(i), pmapIn.Element(i));
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
#pragma once
|
||||
#include "CUtlShared.h"
|
||||
#include "../Interfaces/IMemAlloc.h"
|
||||
|
||||
#pragma warning (push)
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,21 @@
|
||||
#pragma once
|
||||
|
||||
#define COMPILE_TIME_ASSERT( pred ) static_assert( pred, "Compile time assert constraint is not true: " #pred )
|
||||
|
||||
template <class T>
|
||||
inline void Construct(T* pMemory)
|
||||
{
|
||||
::new(pMemory) T;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline void CopyConstruct(T* pMemory, T const& src)
|
||||
{
|
||||
::new(pMemory) T(src);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline void Destruct(T* pMemory)
|
||||
{
|
||||
pMemory->~T();
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
#pragma once
|
||||
#include "CUtlMemory.h"
|
||||
#include "CUtlShared.h"
|
||||
#include <stdlib.h>
|
||||
#include <cassert>
|
||||
|
||||
@@ -8,23 +9,11 @@
|
||||
#pragma warning (disable : 4514)
|
||||
#pragma warning (disable : 26495)
|
||||
|
||||
template <class T>
|
||||
inline void Construct(T* pMemory)
|
||||
{
|
||||
::new(pMemory) T;
|
||||
}
|
||||
#define FOR_EACH_VEC( vecName, iteratorName ) \
|
||||
for ( int iteratorName = 0; (vecName).IsUtlVector && iteratorName < (vecName).Count(); iteratorName++ )
|
||||
|
||||
template <class T>
|
||||
inline void CopyConstruct(T* pMemory, T const& src)
|
||||
{
|
||||
::new(pMemory) T(src);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline void Destruct(T* pMemory)
|
||||
{
|
||||
pMemory->~T();
|
||||
}
|
||||
#define FOR_EACH_VEC_BACK( vecName, iteratorName ) \
|
||||
for ( int iteratorName = (vecName).Count()-1; (vecName).IsUtlVector && iteratorName >= 0; iteratorName-- )
|
||||
|
||||
template<class T, class A = CUtlMemory<T>>
|
||||
class CUtlVector
|
||||
|
||||
@@ -16,4 +16,40 @@ public:
|
||||
virtual void* QueryInterface(const char* pInterfaceName) = 0;
|
||||
virtual InitReturnVal_t Init() = 0;
|
||||
virtual void Shutdown() = 0;
|
||||
};
|
||||
|
||||
template <class IInterface>
|
||||
class CBaseAppSystem : public IInterface
|
||||
{
|
||||
public:
|
||||
virtual bool Connect(CreateInterfaceFn factory) = 0;
|
||||
virtual void Disconnect() = 0;
|
||||
virtual void* QueryInterface(const char* pInterfaceName) = 0;
|
||||
virtual InitReturnVal_t Init() = 0;
|
||||
virtual void Shutdown() = 0;
|
||||
};
|
||||
|
||||
template <class IInterface>
|
||||
class CTier0AppSystem : public CBaseAppSystem<IInterface>
|
||||
{
|
||||
public:
|
||||
bool m_bIsPrimaryAppSystem;
|
||||
};
|
||||
|
||||
template <class IInterface, int ConVarFlag = 0>
|
||||
class CTier1AppSystem : public CTier0AppSystem<IInterface>
|
||||
{
|
||||
typedef CTier0AppSystem<IInterface> BaseClass;
|
||||
};
|
||||
|
||||
template <class IInterface, int ConVarFlag = 0>
|
||||
class CTier2AppSystem : public CTier1AppSystem<IInterface, ConVarFlag>
|
||||
{
|
||||
typedef CTier1AppSystem<IInterface, ConVarFlag> BaseClass;
|
||||
};
|
||||
|
||||
template<class IInterface, int ConVarFlag = 0>
|
||||
class CTier3AppSystem : public CTier2AppSystem<IInterface, ConVarFlag>
|
||||
{
|
||||
typedef CTier2AppSystem<IInterface, ConVarFlag> BaseClass;
|
||||
};
|
||||
@@ -0,0 +1,12 @@
|
||||
#pragma once
|
||||
#include "IAppSystem.h"
|
||||
|
||||
struct studiohdr_t;
|
||||
struct vertexFileHeader_t;
|
||||
|
||||
class IStudioDataCache : public IAppSystem
|
||||
{
|
||||
public:
|
||||
virtual bool VerifyHeaders(studiohdr_t* pStudioHdr) = 0;
|
||||
virtual vertexFileHeader_t* CacheVertexData(studiohdr_t* pStudioHdr) = 0;
|
||||
};
|
||||
@@ -2,13 +2,10 @@
|
||||
#include "BaseTypes.h"
|
||||
#include <cstring>
|
||||
|
||||
#ifndef BITVEC_H
|
||||
#define BITVEC_H
|
||||
#define FORCEINLINE_TEMPLATE __forceinline
|
||||
#define COMPILE_TIME_ASSERT( pred ) static_assert( pred, "Compile time assert constraint is not true: " #pred )
|
||||
#define Plat_FastMemset memset
|
||||
#define PAD_NUMBER(number, boundary) \
|
||||
( ((number) + ((boundary)-1)) / (boundary) ) * (boundary)
|
||||
#define PAD_NUMBER(number, boundary) ( ((number) + ((boundary)-1)) / (boundary) ) * (boundary)
|
||||
|
||||
class CBitVecAccessor
|
||||
{
|
||||
@@ -1422,9 +1419,4 @@ inline void CBitVecAccessor::operator=(int val)
|
||||
inline CBitVecAccessor::operator uint32()
|
||||
{
|
||||
return m_pDWords[m_iBit >> 5] & (1 << (m_iBit & 31));
|
||||
}
|
||||
|
||||
|
||||
//=============================================================================
|
||||
|
||||
#endif // BITVEC_H
|
||||
}
|
||||
@@ -9,6 +9,7 @@
|
||||
#include <unordered_map>
|
||||
#include <map>
|
||||
#include <ranges>
|
||||
#include <optional>
|
||||
|
||||
class Vec2
|
||||
{
|
||||
@@ -1035,6 +1036,11 @@ struct Color_t
|
||||
return { r, g, b, to };
|
||||
}
|
||||
|
||||
inline Color_t Inverse() const
|
||||
{
|
||||
return Color_t(255 - r, 255 - g, 255 - b, a);
|
||||
}
|
||||
|
||||
inline float Brightness(float flRed = 0.299f, float flGreen = 0.587f, float flBlue = 0.114f) const
|
||||
{
|
||||
return r * flRed + g * flGreen + b * flBlue;
|
||||
|
||||
@@ -25,18 +25,18 @@ bool CTraceFilterHitscan::ShouldHitEntity(IHandleEntity* pHandleEntity, int nCon
|
||||
case ETFClassID::CFuncAreaPortalWindow:
|
||||
case ETFClassID::CFuncRespawnRoomVisualizer:
|
||||
case ETFClassID::CTFReviveMarker: return false;
|
||||
case ETFClassID::CTFMedigunShield: return pEntity->m_iTeamNum() != iTeam;
|
||||
case ETFClassID::CTFMedigunShield: return !(nContentsMask & CONTENTS_PLAYERCLIP) && pEntity->m_iTeamNum() != iTeam;
|
||||
case ETFClassID::CTFPlayer:
|
||||
case ETFClassID::CBaseObject:
|
||||
case ETFClassID::CObjectSentrygun:
|
||||
case ETFClassID::CObjectDispenser:
|
||||
case ETFClassID::CObjectTeleporter:
|
||||
if (iType != SKIP_CHECK && (iWeapon == WEAPON_INCLUDE ? bWeapon : !bWeapon))
|
||||
return iType == FORCE_HIT ? true : false;
|
||||
case ETFClassID::CObjectTeleporter:
|
||||
if (!(nContentsMask & CONTENTS_MOVEABLE)) return false;
|
||||
if (iType != SKIP_CHECK && (iWeapon == WEAPON_INCLUDE ? bWeapon : !bWeapon)) return iType == FORCE_HIT ? true : false;
|
||||
return pEntity->m_iTeamNum() != iTeam;
|
||||
}
|
||||
|
||||
return true;
|
||||
return nContentsMask & CONTENTS_SOLID;
|
||||
}
|
||||
TraceType_t CTraceFilterHitscan::GetTraceType() const
|
||||
{
|
||||
@@ -62,44 +62,36 @@ bool CTraceFilterCollideable::ShouldHitEntity(IHandleEntity* pHandleEntity, int
|
||||
|
||||
switch (pEntity->GetClassID())
|
||||
{
|
||||
case ETFClassID::CBaseEntity:
|
||||
case ETFClassID::CBaseEntity: return nContentsMask & CONTENTS_SOLID;
|
||||
case ETFClassID::CFunc_LOD:
|
||||
case ETFClassID::CBaseDoor:
|
||||
case ETFClassID::CDynamicProp:
|
||||
case ETFClassID::CPhysicsProp:
|
||||
case ETFClassID::CPhysicsPropMultiplayer:
|
||||
case ETFClassID::CFunc_LOD:
|
||||
case ETFClassID::CObjectCartDispenser:
|
||||
case ETFClassID::CFuncTrackTrain:
|
||||
case ETFClassID::CFuncConveyor:
|
||||
case ETFClassID::CTFGenericBomb:
|
||||
case ETFClassID::CTFPumpkinBomb: return true;
|
||||
case ETFClassID::CFuncRespawnRoomVisualizer:
|
||||
if (nContentsMask & CONTENTS_PLAYERCLIP)
|
||||
return pEntity->m_iTeamNum() != iTeam;
|
||||
break;
|
||||
case ETFClassID::CTFMedigunShield:
|
||||
if (!(nContentsMask & CONTENTS_PLAYERCLIP))
|
||||
return pEntity->m_iTeamNum() != iTeam;
|
||||
break;
|
||||
case ETFClassID::CTFPumpkinBomb: return nContentsMask & CONTENTS_MOVEABLE;
|
||||
case ETFClassID::CFuncRespawnRoomVisualizer: return nContentsMask & CONTENTS_PLAYERCLIP && pEntity->m_iTeamNum() != iTeam;
|
||||
case ETFClassID::CTFMedigunShield: return !(nContentsMask & CONTENTS_PLAYERCLIP) && pEntity->m_iTeamNum() != iTeam;
|
||||
case ETFClassID::CTFPlayer:
|
||||
if (iPlayer == PLAYER_ALL)
|
||||
return true;
|
||||
if (iPlayer == PLAYER_NONE)
|
||||
return false;
|
||||
if (iType != SKIP_CHECK && (iWeapon == WEAPON_INCLUDE ? bWeapon : !bWeapon))
|
||||
return iType == FORCE_HIT ? true : false;
|
||||
if (!(nContentsMask & CONTENTS_MONSTER)) return false;
|
||||
if (iPlayer == PLAYER_ALL) return true;
|
||||
if (iPlayer == PLAYER_NONE) return false;
|
||||
if (iType != SKIP_CHECK && (iWeapon == WEAPON_INCLUDE ? bWeapon : !bWeapon)) return iType == FORCE_HIT ? true : false;
|
||||
return pEntity->m_iTeamNum() != iTeam;
|
||||
case ETFClassID::CBaseObject:
|
||||
case ETFClassID::CObjectSentrygun:
|
||||
case ETFClassID::CObjectDispenser: return iObject == OBJECT_ALL ? true : iObject == OBJECT_NONE ? false : pEntity->m_iTeamNum() != iTeam;
|
||||
case ETFClassID::CObjectTeleporter: return true;
|
||||
case ETFClassID::CObjectDispenser: return nContentsMask & CONTENTS_MOVEABLE && (iObject == OBJECT_ALL ? true : iObject == OBJECT_NONE ? false : pEntity->m_iTeamNum() != iTeam);
|
||||
case ETFClassID::CObjectTeleporter: return nContentsMask & CONTENTS_MOVEABLE;
|
||||
//case ETFClassID::CTFBaseBoss:
|
||||
//case ETFClassID::CTFTankBoss:
|
||||
//case ETFClassID::CMerasmus:
|
||||
//case ETFClassID::CEyeballBoss:
|
||||
//case ETFClassID::CHeadlessHatman:
|
||||
//case ETFClassID::CZombie: return bMisc;
|
||||
case ETFClassID::CTFGrenadePipebombProjectile: return bMisc && pEntity->As<CTFGrenadePipebombProjectile>()->m_iType() == TF_GL_MODE_REMOTE_DETONATE;
|
||||
//case ETFClassID::CZombie: return nContentsMask & CONTENTS_MONSTER && bMisc;
|
||||
case ETFClassID::CTFGrenadePipebombProjectile: return nContentsMask & CONTENTS_MOVEABLE && bMisc && pEntity->As<CTFGrenadePipebombProjectile>()->m_iType() == TF_GL_MODE_REMOTE_DETONATE;
|
||||
}
|
||||
|
||||
return false;
|
||||
@@ -114,22 +106,22 @@ bool CTraceFilterWorldAndPropsOnly::ShouldHitEntity(IHandleEntity* pHandleEntity
|
||||
if (!pHandleEntity || pHandleEntity == pSkip)
|
||||
return false;
|
||||
if (pHandleEntity->GetRefEHandle().GetSerialNumber() == (1 << 15))
|
||||
return pHandleEntity->GetRefEHandle().GetEntryIndex() != iTeam; // just use team variable since cliententitylist can give us nullptrs for some props for whatever reason
|
||||
return nContentsMask & CONTENTS_SOLID && pHandleEntity->GetRefEHandle().GetEntryIndex() != iTeam; // team variable since cliententitylist can give nullptrs
|
||||
|
||||
auto pEntity = reinterpret_cast<CBaseEntity*>(pHandleEntity);
|
||||
if (iTeam == -1) iTeam = pSkip ? pSkip->m_iTeamNum() : 0;
|
||||
|
||||
switch (pEntity->GetClassID())
|
||||
{
|
||||
case ETFClassID::CBaseEntity:
|
||||
case ETFClassID::CBaseEntity: return nContentsMask & CONTENTS_SOLID;
|
||||
case ETFClassID::CFunc_LOD:
|
||||
case ETFClassID::CBaseDoor:
|
||||
case ETFClassID::CDynamicProp:
|
||||
case ETFClassID::CPhysicsProp:
|
||||
case ETFClassID::CPhysicsPropMultiplayer:
|
||||
case ETFClassID::CFunc_LOD:
|
||||
case ETFClassID::CObjectCartDispenser:
|
||||
case ETFClassID::CFuncTrackTrain:
|
||||
case ETFClassID::CFuncConveyor: return true;
|
||||
case ETFClassID::CFuncConveyor: return nContentsMask & CONTENTS_MOVEABLE;
|
||||
case ETFClassID::CFuncRespawnRoomVisualizer: return nContentsMask & CONTENTS_PLAYERCLIP && pEntity->m_iTeamNum() != iTeam;
|
||||
}
|
||||
|
||||
|
||||
@@ -155,6 +155,10 @@ bool SDK::IsGameWindowInFocus()
|
||||
return hWindow == GetForegroundWindow() || !hWindow;
|
||||
}
|
||||
|
||||
bool SDK::StdRandomBool()
|
||||
{
|
||||
return StdRandomInt(0, 1);
|
||||
}
|
||||
int SDK::StdRandomInt(int iMin, int iMax)
|
||||
{
|
||||
std::uniform_int_distribution<int> iDistribution(iMin, iMax);
|
||||
|
||||
@@ -88,6 +88,7 @@ namespace SDK
|
||||
bool IsGameWindowInFocus();
|
||||
|
||||
inline std::default_random_engine Random = {};
|
||||
bool StdRandomBool();
|
||||
int StdRandomInt(int iMin = 0, int iMax = VALVE_RAND_MAX);
|
||||
float StdRandomFloat(float flMin = 0.f, float flMax = 1.f);
|
||||
|
||||
|
||||
@@ -1,12 +1,16 @@
|
||||
#pragma once
|
||||
#include "BaseMath.h"
|
||||
#include "../../SDK/Definitions/Types.h"
|
||||
#include "../Hash/FNV1A.h"
|
||||
|
||||
#undef min
|
||||
#undef max
|
||||
|
||||
#define FLT_COMPARE(x, y) (fabsf(x - y) <= FLT_EPSILON * fmaxf(1.f, fmaxf(fabsf(x), fabsf(y))))
|
||||
|
||||
#define DIST_EPSILON 0.03125f
|
||||
#define CALC_EPSILON 0.001f
|
||||
|
||||
namespace Math
|
||||
{
|
||||
inline void ClampAngles(Vec3& v)
|
||||
@@ -387,4 +391,160 @@ namespace Math
|
||||
mOut[2][2] = mIn1[2][0] * mIn2[0][2] + mIn1[2][1] * mIn2[1][2] + mIn1[2][2] * mIn2[2][2];
|
||||
mOut[2][3] = mIn1[2][0] * mIn2[0][3] + mIn1[2][1] * mIn2[1][3] + mIn1[2][2] * mIn2[2][3] + mIn1[2][3];
|
||||
}
|
||||
|
||||
inline void OffsetPolygon(std::vector<Vec3>& vVertices, const Vec3& vNormal, float flOffset)
|
||||
{
|
||||
for (auto& vVertex : vVertices)
|
||||
vVertex += vNormal * flOffset;
|
||||
}
|
||||
|
||||
inline void ExpandPolygon(std::vector<Vec3>& vOldVertices, std::vector<Vec3>& vNewVertices, const Vec3& vNormal, float flOffset, const Vec3* pTarget = nullptr)
|
||||
{
|
||||
Vec3 vForward = (vNewVertices.front() - vNewVertices.back()).Normalized();
|
||||
Vec3 vRight = vForward.Cross(vNormal).Normalized();
|
||||
|
||||
vOldVertices = vNewVertices;
|
||||
for (int i = 0, n = int(vNewVertices.size()); i < n; i++)
|
||||
{
|
||||
Vec3& vVertex1 = vOldVertices[i], &vVertex2 = vOldVertices[(i + 1) % n], &vVertex3 = vOldVertices[(i + 2) % n];
|
||||
|
||||
Vec2 vPoint1 = { vVertex1.Dot(vForward), vVertex1.Dot(vRight) };
|
||||
Vec2 vPoint2 = { vVertex2.Dot(vForward), vVertex2.Dot(vRight) };
|
||||
Vec2 vPoint3 = { vVertex3.Dot(vForward), vVertex3.Dot(vRight) };
|
||||
|
||||
Vec2 vDelta21 = vPoint2 - vPoint1;
|
||||
Vec2 vDelta32 = vPoint3 - vPoint2;
|
||||
|
||||
Vec2 vNormal1 = Vec2(vDelta21.y, -vDelta21.x).Normalized();
|
||||
Vec2 vNormal2 = Vec2(vDelta32.y, -vDelta32.x).Normalized();
|
||||
|
||||
Vec2 vBisect = Vec2(vNormal1.x + vNormal2.x, vNormal1.y + vNormal2.y).Normalized();
|
||||
float flDistance = flOffset / vNormal1.Dot(vBisect);
|
||||
vBisect *= flDistance;
|
||||
|
||||
if (!pTarget)
|
||||
vNewVertices[(i + 1) % n] += vForward * vBisect.x + vRight * vBisect.y;
|
||||
else
|
||||
{
|
||||
Vec3 vToTarget = *pTarget - vVertex2;
|
||||
if (Vec3 vDisplacementX = vForward * vBisect.x; vDisplacementX.Dot(vToTarget) > 0.f)
|
||||
vNewVertices[(i + 1) % n] += vDisplacementX;
|
||||
if (Vec3 vDisplacementY = vRight * vBisect.y; vDisplacementY.Dot(vToTarget) > 0.f)
|
||||
vNewVertices[(i + 1) % n] += vDisplacementY;
|
||||
}
|
||||
}
|
||||
}
|
||||
inline void ExpandPolygon(std::vector<Vec3>& vVertices, const Vec3& vNormal, float flOffset, const Vec3* pTarget = nullptr)
|
||||
{
|
||||
std::vector<Vec3> vTemporary;
|
||||
ExpandPolygon(vTemporary, vVertices, vNormal, flOffset, pTarget);
|
||||
}
|
||||
|
||||
inline Vec3 ClosestPointOnLine(const Vec3& vPoint, const Vec3& vPoint1, const Vec3& vPoint2)
|
||||
{
|
||||
Vec3 vDelta = vPoint2 - vPoint1;
|
||||
|
||||
float flRatio = std::clamp((vPoint - vPoint1).Dot(vDelta) / vDelta.Dot(vDelta), 0.f, 1.f);
|
||||
|
||||
return vPoint1 + vDelta * flRatio;
|
||||
}
|
||||
|
||||
inline Vec3 ClosestPointOnTriangle(const Vec3& vPoint, const Vec3& vPoint1, const Vec3& vPoint2, const Vec3& vPoint3, bool* pInside = nullptr)
|
||||
{
|
||||
Vec3 vDelta21 = vPoint2 - vPoint1;
|
||||
Vec3 vDelta31 = vPoint3 - vPoint1;
|
||||
if (pInside) *pInside = false;
|
||||
|
||||
Vec3 vDeltaPT = vPoint - vPoint1;
|
||||
float flDot1 = vDelta21.Dot(vDeltaPT);
|
||||
float flDot2 = vDelta31.Dot(vDeltaPT);
|
||||
if (flDot1 <= 0 && flDot2 <= 0)
|
||||
return vPoint1;
|
||||
|
||||
vDeltaPT = vPoint - vPoint2;
|
||||
float flDot3 = vDelta21.Dot(vDeltaPT);
|
||||
float flDot4 = vDelta31.Dot(vDeltaPT);
|
||||
if (flDot3 >= 0 && flDot4 <= flDot3)
|
||||
return vPoint2;
|
||||
|
||||
vDeltaPT = vPoint - vPoint3;
|
||||
float flDot5 = vDelta21.Dot(vDeltaPT);
|
||||
float flDot6 = vDelta31.Dot(vDeltaPT);
|
||||
if (flDot6 >= 0 && flDot5 <= flDot6)
|
||||
return vPoint3;
|
||||
|
||||
float flSideC = flDot1 * flDot4 - flDot3 * flDot2;
|
||||
if (flSideC <= 0 && flDot1 >= 0 && flDot3 <= 0)
|
||||
{
|
||||
float flRatio = flDot1 / (flDot1 - flDot3);
|
||||
return vPoint1 + vDelta21 * flRatio;
|
||||
}
|
||||
|
||||
float flSideB = flDot5 * flDot2 - flDot1 * flDot6;
|
||||
if (flSideB <= 0 && flDot2 >= 0 && flDot6 <= 0)
|
||||
{
|
||||
float flRatio = flDot2 / (flDot2 - flDot6);
|
||||
return vPoint1 + vDelta31 * flRatio;
|
||||
}
|
||||
|
||||
float flSideA = flDot3 * flDot6 - flDot5 * flDot4;
|
||||
if (flSideA <= 0 && (flDot4 - flDot3) >= 0 && (flDot5 - flDot6) >= 0)
|
||||
{
|
||||
float flRatio = (flDot4 - flDot3) / (flDot4 - flDot3 + flDot5 - flDot6);
|
||||
return vPoint2 + (vPoint3 - vPoint2) * flRatio;
|
||||
}
|
||||
|
||||
float flDenominator = 1 / (flSideA + flSideB + flSideC);
|
||||
float flV = flSideB * flDenominator;
|
||||
float flW = flSideC * flDenominator;
|
||||
if (pInside) *pInside = true;
|
||||
return vPoint1 + vDelta21 * flV + vDelta31 * flW;
|
||||
}
|
||||
|
||||
inline Vec3 ClosestPointOnPolygon(const Vec3& vPoint, const std::vector<Vec3>& vVertices, const Vec3& vNormal, bool* pInside = nullptr)
|
||||
{
|
||||
float flDot = vNormal.Dot(vPoint - vVertices.front());
|
||||
Vec3 vProjection = vPoint - flDot * vNormal;
|
||||
|
||||
for (int i = 0, n = int(vVertices.size()); i < n; i++)
|
||||
{
|
||||
const Vec3& vVertex1 = vVertices[i], &vVertex2 = vVertices[(i + 1) % n];
|
||||
|
||||
Vec3 vEdge = vVertex2 - vVertex1;
|
||||
Vec3 vToProjection = vProjection - vVertex1;
|
||||
|
||||
if (vToProjection.Cross(vEdge).Dot(vNormal) < 0)
|
||||
goto outside;
|
||||
}
|
||||
if (pInside) *pInside = true;
|
||||
return vProjection;
|
||||
|
||||
outside:
|
||||
float flLowestDistance = std::numeric_limits<float>::max();
|
||||
for (int i = 0, n = int(vVertices.size()); i < n; i++)
|
||||
{
|
||||
const Vec3& vVertex1 = vVertices[i], &vVertex2 = vVertices[(i + 1) % n];
|
||||
|
||||
Vec3 vLine = ClosestPointOnLine(vPoint, vVertex1, vVertex2);
|
||||
float flDistance = vLine.DistToSqr(vPoint);
|
||||
if (flDistance < flLowestDistance)
|
||||
vProjection = vLine, flLowestDistance = flDistance;
|
||||
}
|
||||
if (pInside) *pInside = false;
|
||||
return vProjection;
|
||||
}
|
||||
|
||||
// note: not clamped
|
||||
inline float FullFraction(const Vec3& vDir, const CGameTrace& trace)
|
||||
{
|
||||
if (!trace.DidHit() || FNV1A::Hash32(trace.surface.name) == FNV1A::Hash32Const("**displacement**"))
|
||||
return trace.fraction;
|
||||
|
||||
float flFractionEpsilon = DIST_EPSILON / vDir.Dot(trace.plane.normal);
|
||||
return trace.fraction - flFractionEpsilon;
|
||||
}
|
||||
inline float FullFraction(const Vec3& vStart, const Vec3& vEnd, const CGameTrace& trace)
|
||||
{
|
||||
return FullFraction(vEnd - vStart, trace);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user