900 lines
28 KiB
C++
900 lines
28 KiB
C++
#include "entity.h"
|
|
// others
|
|
#include "../core/hooks.h"
|
|
#include "../utilities/draw.h"
|
|
|
|
// used: convars
|
|
#include "../core/convars.h"
|
|
#include "interfaces/cgameentitysystem.h"
|
|
#include "interfaces/ienginecvar.h"
|
|
#include "interfaces/iengineclient.h"
|
|
|
|
// used: game's definitions, enums
|
|
#include "const.h"
|
|
#include "../core/csig/sigscan.hpp"
|
|
#include "../core/pointer/pointer.hpp"
|
|
#include <array>
|
|
#include "../features.h"
|
|
#include "../cstrike/features/visuals/overlay.h"
|
|
#include "../cstrike/features/legit/legit.h"
|
|
#include "interfaces/iglobalvars.h"
|
|
#include "../cstrike/features/skins/ccsplayerinventory.hpp"
|
|
#include "../features/rage/rage.h"
|
|
|
|
Vector_t C_CSPlayerPawn::GetEyePosition() {
|
|
Vector_t EyePosition;
|
|
MEM::CallVFunc<void, 163>(this, &EyePosition);
|
|
return EyePosition;
|
|
}
|
|
|
|
static CachedEntity_t::Type GetEntityType(C_BaseEntity* pEntity);
|
|
|
|
static CachedEntity_t::Type GetEntityType(C_BaseEntity* pEntity) {
|
|
if (!pEntity)
|
|
return CachedEntity_t::UNKNOWN;
|
|
|
|
SchemaClassInfoData_t* pClassInfo = nullptr;
|
|
pEntity->GetSchemaClassInfo(&pClassInfo);
|
|
|
|
if (pClassInfo == nullptr)
|
|
return CachedEntity_t::UNKNOWN;
|
|
|
|
const FNV1A_t uHashedName = FNV1A::Hash(pClassInfo->szName);
|
|
|
|
if (uHashedName == FNV1A::HashConst(CS_XOR("CCSPlayerController"))) {
|
|
return CachedEntity_t::PLAYER_CONTROLLER;
|
|
}
|
|
|
|
return CachedEntity_t::UNKNOWN;
|
|
}
|
|
|
|
// Definition of the global vector and mutex
|
|
std::vector<CachedEntity_t> g_cachedEntities;
|
|
std::mutex g_cachedEntitiesMutex;
|
|
std::unordered_multimap<CachedEntity_t::Type, entity_callbacks> g_Callbacks;
|
|
|
|
namespace EntCache {
|
|
|
|
void CacheCurrentEntities() {
|
|
// This function runs ONCE on injection and caches all the entities if
|
|
// you happen to inject connected on a server.
|
|
|
|
if (!I::Engine->IsInGame() || !I::Engine->IsConnected()) return;
|
|
|
|
if (!I::GameResourceService->pGameEntitySystem) return;
|
|
|
|
|
|
int highestIndex = I::GameResourceService->pGameEntitySystem->GetHighestEntityIndex();
|
|
for (int i = 1; i <= highestIndex; ++i) {
|
|
C_BaseEntity* pEntity = I::GameResourceService->pGameEntitySystem->Get(i);
|
|
if (!pEntity) continue;
|
|
|
|
OnAddEntity(pEntity, pEntity->GetRefEHandle());
|
|
}
|
|
}
|
|
|
|
void OnAddEntity(CEntityInstance* inst, CBaseHandle handle) {
|
|
if (!I::GameResourceService->pGameEntitySystem) return;
|
|
|
|
C_BaseEntity* pEntity = (C_BaseEntity*)inst;
|
|
if (!pEntity) return;
|
|
|
|
// Cache only networked entities.
|
|
// https://developer.valvesoftware.com/wiki/Entity_limit#Source_2_limits
|
|
if (handle.GetEntryIndex() >= 16384) return;
|
|
// call callbacks
|
|
for (auto& [callback_type, callbacks] : g_Callbacks) {
|
|
if (!callbacks.add || callback_type != GetEntityType(pEntity))
|
|
continue;
|
|
callbacks.add(handle.GetEntryIndex(), handle);
|
|
}
|
|
std::lock_guard<std::mutex> lock(g_cachedEntitiesMutex);
|
|
|
|
auto it = std::find_if(g_cachedEntities.begin(), g_cachedEntities.end(),
|
|
[handle](const CachedEntity_t& i) {
|
|
return i.m_handle.GetEntryIndex() == handle.GetEntryIndex();
|
|
});
|
|
|
|
if (it == g_cachedEntities.end()) {
|
|
CachedEntity_t cachedEntity{};
|
|
cachedEntity.m_handle = handle;
|
|
cachedEntity.m_type = GetEntityType(pEntity);
|
|
cachedEntity.index = handle.GetEntryIndex();
|
|
cachedEntity.reset = false;
|
|
|
|
if (cachedEntity.m_type != CachedEntity_t::UNKNOWN) {
|
|
g_cachedEntities.emplace_back(cachedEntity);
|
|
}
|
|
}
|
|
else {
|
|
it->m_handle = handle;
|
|
it->m_type = GetEntityType(pEntity);
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
void OnRemoveEntity(CEntityInstance* inst, CBaseHandle handle) {
|
|
if (!I::GameResourceService->pGameEntitySystem) return;
|
|
|
|
C_BaseEntity* pEntity = (C_BaseEntity*)inst;
|
|
if (!pEntity) return;
|
|
|
|
// call callbacks
|
|
for (auto& [callback_type, callbacks] : g_Callbacks) {
|
|
if (!callbacks.remove)
|
|
continue;
|
|
|
|
if (callback_type != GetEntityType(pEntity))
|
|
continue;
|
|
|
|
callbacks.remove(handle.GetEntryIndex(), handle);
|
|
}
|
|
|
|
std::lock_guard<std::mutex> lock(g_cachedEntitiesMutex);
|
|
|
|
auto it = std::find_if(g_cachedEntities.begin(), g_cachedEntities.end(),
|
|
[handle](const CachedEntity_t& i) {
|
|
return i.m_handle == handle;
|
|
});
|
|
|
|
if (it == g_cachedEntities.end()) return;
|
|
|
|
it->m_draw = false;
|
|
it->m_type = CachedEntity_t::UNKNOWN;
|
|
|
|
}
|
|
void RegisterCallback(CachedEntity_t::Type type, entity_callback add, entity_callback remove) noexcept {
|
|
if (!add && !remove)
|
|
return;
|
|
|
|
std::unique_lock lock(g_cachedEntitiesMutex);
|
|
g_Callbacks.insert(std::make_pair(type, entity_callbacks{ add, remove }));
|
|
|
|
if (!add)
|
|
return;
|
|
|
|
// add existing entities
|
|
for (auto& cached_entity : g_cachedEntities) {
|
|
if (cached_entity.m_type == type)
|
|
add(cached_entity.m_handle.GetEntryIndex(), cached_entity.m_handle);
|
|
}
|
|
}
|
|
|
|
|
|
} // namespace EntCache
|
|
// global empty vector for when we can't get the origin
|
|
static Vector_t vecEmpty = Vector_t(0, 0, 0);
|
|
|
|
bool CCSPlayerController::IsThrowingGrenade(C_CSWeaponBase* pBaseWeapon)
|
|
{
|
|
if (!pBaseWeapon)
|
|
return false;
|
|
|
|
if (!SDK::LocalController->IsPawnAlive() || !SDK::LocalController)
|
|
return false;
|
|
|
|
const float flServerTime = TICKS_TO_TIME(this->m_nTickBase());
|
|
const short nDefinitionIndex = pBaseWeapon->m_AttributeManager().m_Item().m_iItemDefinitionIndex();
|
|
CCSWeaponBaseVData* pWeaponBaseVData = pBaseWeapon->datawep();
|
|
if (!pWeaponBaseVData)
|
|
return false;
|
|
|
|
if (pWeaponBaseVData->m_WeaponType() == WEAPONTYPE_GRENADE)
|
|
{
|
|
C_BaseCSGrenade* pGrenade = reinterpret_cast<C_BaseCSGrenade*>(pBaseWeapon);
|
|
if (pGrenade != nullptr)
|
|
{
|
|
return !pGrenade->IsPinPulled() && pGrenade->GetThrowTime() > 0.f && pGrenade->GetThrowTime() < flServerTime;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
CCSPlayerController* CCSPlayerController::GetLocalPlayerController()
|
|
{
|
|
|
|
const int nIndex = I::Engine->GetLocalPlayer();
|
|
return I::GameResourceService->pGameEntitySystem->Get<CCSPlayerController>(nIndex);
|
|
}
|
|
|
|
const Vector_t& CCSPlayerController::GetPawnOrigin()
|
|
{
|
|
|
|
CBaseHandle hPawn = this->GetPawnHandle();
|
|
if (!hPawn.IsValid())
|
|
return vecEmpty;
|
|
|
|
C_CSPlayerPawn* pPawn = I::GameResourceService->pGameEntitySystem->Get<C_CSPlayerPawn>(hPawn);
|
|
if (pPawn == nullptr)
|
|
return vecEmpty;
|
|
|
|
return pPawn->GetSceneOrigin();
|
|
}
|
|
|
|
C_BaseEntity* C_BaseEntity::GetLocalPlayer()
|
|
{
|
|
|
|
const int nIndex = I::Engine->GetLocalPlayer();
|
|
return I::GameResourceService->pGameEntitySystem->Get(nIndex);
|
|
}
|
|
|
|
const Vector_t& C_BaseEntity::GetSceneOrigin()
|
|
{
|
|
if (this->GetGameSceneNode())
|
|
return GetGameSceneNode()->GetAbsOrigin();
|
|
|
|
return vecEmpty;
|
|
}
|
|
bool C_CSPlayerPawn::CalculateBoundingBox(ImVec4& out, bool compute_surrounding_box) {
|
|
|
|
if (!this || this->GetHealth() <= 0)
|
|
return false;
|
|
|
|
CCollisionProperty* pCollision = this->GetCollision();
|
|
if (pCollision == nullptr) {
|
|
return false;
|
|
}
|
|
|
|
Vector_t min{}, max{};
|
|
|
|
CTransform nodeToWorldTransform = this->GetGameSceneNode()->GetNodeToWorld();
|
|
const Matrix3x4_t matTransform = nodeToWorldTransform.quatOrientation.ToMatrix(nodeToWorldTransform.vecPosition);
|
|
if (compute_surrounding_box) {
|
|
if (!ComputeHitboxSurroundingBox(min, max)) {
|
|
return false;
|
|
}
|
|
}
|
|
else {
|
|
min = pCollision->GetMins();
|
|
max = pCollision->GetMaxs();
|
|
}
|
|
|
|
out.x = out.y = std::numeric_limits<float>::max();
|
|
out.z = out.w = -std::numeric_limits<float>::max();
|
|
|
|
for (int i = 0; i < 8; ++i)
|
|
{
|
|
const Vector_t vecPoint{
|
|
i & 1 ? max.x : min.x,
|
|
i & 2 ? max.y : min.y,
|
|
i & 4 ? max.z : min.z
|
|
};
|
|
ImVec2 vecScreen;
|
|
if (!D::WorldToScreen(vecPoint.Transform(matTransform), vecScreen))
|
|
return false;
|
|
|
|
out.x = MATH::Min(out.x, vecScreen.x);
|
|
out.y = MATH::Min(out.y, vecScreen.y);
|
|
out.z = MATH::Max(out.z, vecScreen.x);
|
|
out.w = MATH::Max(out.w, vecScreen.y);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool C_CSPlayerPawn::hasArmour(const int hitgroup) {
|
|
if (!this->GetItemServices())
|
|
return false;
|
|
|
|
switch (hitgroup) {
|
|
case HITGROUP_HEAD:
|
|
return this->GetItemServices()->m_bHasHelmet();
|
|
case HITGROUP_GENERIC:
|
|
case HITGROUP_CHEST:
|
|
case HITGROUP_STOMACH:
|
|
case HITGROUP_LEFTARM:
|
|
case HITGROUP_RIGHTARM:
|
|
return true;
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
bool C_CSPlayerPawn::IsOtherEnemy(C_CSPlayerPawn* pOther)
|
|
{
|
|
// check are other player is invalid or we're comparing against ourselves
|
|
if (pOther == nullptr || this == pOther)
|
|
return false;
|
|
|
|
if (CONVAR::game_type->value.i32 == GAMETYPE_FREEFORALL && CONVAR::game_mode->value.i32 == GAMEMODE_FREEFORALL_SURVIVAL)
|
|
// check is not teammate
|
|
return (this->GetSurvivalTeam() != pOther->GetSurvivalTeam());
|
|
|
|
// @todo: check is deathmatch
|
|
if (CONVAR::mp_teammates_are_enemies->value.i1)
|
|
return true;
|
|
|
|
return this->GetAssociatedTeam() != pOther->GetAssociatedTeam();
|
|
}
|
|
/*
|
|
bool CEconItemDefinition::IsWeapon() {
|
|
// Every gun supports at least 4 stickers.
|
|
return GetStickersSupportedCount() >= 4;
|
|
}
|
|
|
|
bool CEconItemDefinition::IsKnife(bool excludeDefault) {
|
|
static constexpr auto CSGO_Type_Knife =
|
|
HASHCNSX::hash_32_fnv1a_const("#CSGO_Type_Knife");
|
|
|
|
if (HASHCNSX::hash_32_fnv1a_const(m_pszItemTypeName) != CSGO_Type_Knife)
|
|
return false;
|
|
|
|
return excludeDefault ? m_nDefIndex >= 500 : true;
|
|
}
|
|
|
|
bool CEconItemDefinition::IsGlove(bool excludeDefault) {
|
|
static constexpr auto Type_Hands = HASHCNSX::hash_32_fnv1a_const("#Type_Hands");
|
|
|
|
if (HASHCNSX::hash_32_fnv1a_const(m_pszItemTypeName) != Type_Hands) return false;
|
|
const bool defaultGlove = m_nDefIndex == 5028 || m_nDefIndex == 5029;
|
|
|
|
return excludeDefault ? !defaultGlove : true;
|
|
}
|
|
*/
|
|
int C_CSPlayerPawn::GetAssociatedTeam()
|
|
{
|
|
const int nTeam = this->GetTeam();
|
|
|
|
// @todo: check is coaching, currently cs2 doesnt have sv_coaching_enabled, so just let it be for now...
|
|
//if (CONVAR::sv_coaching_enabled->GetBool() && nTeam == TEAM_SPECTATOR)
|
|
// return this->GetCoachingTeam();
|
|
|
|
return nTeam;
|
|
}
|
|
#include "interfaces/itrace.h"
|
|
//48 89 5C 24 08 48 89 6C 24 10 48 89 74 24 18 57 48 83 EC 30 48 8B 59 08 41 8B F8 8B 69 10 8B 72 10 0F 29 74 24 20 0F 28 F3 48 8D 8B C0 00 00 00 81 39 00 02 00 00 7F 6D E8 ?? ?? ?? ?? 48 63 C8 48 C1 E1 06 48 03 8B D0 00 00 00 33 C0 48 C7 01 01"
|
|
/*bool C_CSPlayerPawn::SetupBones(matrix3x4* out, int maxBones, int boneMask, float currentTime) noexcept
|
|
{
|
|
if (localPlayer && this == localPlayer.get() && localPlayer->isAlive())
|
|
{
|
|
uint32_t* effects = this->getEffects();
|
|
uint32_t* shouldskipframe = (uint32_t*)((uintptr_t)this + 0xA68);
|
|
uint32_t backup_effects = *effects;
|
|
uint32_t backup_shouldskipframe = *shouldskipframe;
|
|
*shouldskipframe = 0;
|
|
*effects |= 8;
|
|
auto result = VirtualMethod::call<bool, 13>(this + 4, out, maxBones, boneMask, currentTime);
|
|
*effects = backup_effects;
|
|
*shouldskipframe = backup_shouldskipframe;
|
|
return result;
|
|
}
|
|
else
|
|
{
|
|
*reinterpret_cast<int*>(this + 0xA28) = 0;
|
|
*reinterpret_cast<int*>(this + 0xA30) = memory->globalVars->framecount;
|
|
int* render = reinterpret_cast<int*>(this + 0x274);
|
|
uint32_t* shouldskipframe = (uint32_t*)((uintptr_t)this + 0xA68);
|
|
uint32_t* effects = this->getEffects();
|
|
int backup = *render;
|
|
uint32_t backup_effects = *effects;
|
|
*shouldskipframe = 0;
|
|
*render = 0;
|
|
boneMask |= 0x200;
|
|
*effects |= 8;
|
|
auto result = VirtualMethod::call<bool, 13>(this + 4, out, maxBones, boneMask, currentTime);
|
|
*render = backup;
|
|
*effects = backup_effects;
|
|
return result;
|
|
}
|
|
return VirtualMethod::call<bool, 13>(this + 4, out, maxBones, boneMask, currentTime);
|
|
}*/
|
|
|
|
static Vector_t get_target_angle(C_CSPlayerPawn* localplayer, Vector_t position)
|
|
{
|
|
Vector_t eye_position = localplayer->GetEyePosition();
|
|
Vector_t angle = position;
|
|
|
|
angle.x = position.x - eye_position.x;
|
|
angle.y = position.y - eye_position.y;
|
|
angle.z = position.z - eye_position.z;
|
|
|
|
angle.Normalizes();
|
|
MATH::vec_angles(angle, &angle);
|
|
|
|
angle.clamp();
|
|
return angle;
|
|
}
|
|
template<class T, class U>
|
|
T fine(T in, U low, U high)
|
|
{
|
|
if (in <= low)
|
|
return low;
|
|
|
|
if (in >= high)
|
|
return high;
|
|
|
|
return in;
|
|
}
|
|
// basic extrap made in 3 mins gonna improve a lot later on its rly Important & needed
|
|
Vector_t extrapolate(C_CSPlayerPawn* ent, Vector_t pos) {
|
|
if (!ent)
|
|
return pos;
|
|
|
|
auto simtime = ent->m_flSimulationTime();
|
|
auto old_simtime = simtime + 4;
|
|
float simtime_delta = simtime - old_simtime;
|
|
int choked_ticks = fine(TIME_TO_TICKS(simtime_delta), 1, 15);
|
|
|
|
Vector_t lastOrig;
|
|
|
|
if (lastOrig.Length() != pos.Length())
|
|
lastOrig = pos;
|
|
|
|
float delta_distance = (pos - lastOrig).Length();
|
|
Vector_t velocity_per_tick = ent->m_vecVelocity() * I::GlobalVars->flIntervalPerTick;
|
|
Vector_t new_origin = pos + (velocity_per_tick * choked_ticks);
|
|
return new_origin;
|
|
}
|
|
void C_CSPlayerPawn::CalculateHitboxData(uint32_t idx, Vector_t& pos, Vector4D_t& rot, float& scale, bool predict) {
|
|
if (!this || this->GetHealth() <= 0)
|
|
return;
|
|
|
|
auto game_scene_node = this->GetGameSceneNode();
|
|
if (!game_scene_node)
|
|
return;
|
|
|
|
auto skeleton = game_scene_node->GetSkeletonInstance();
|
|
if (!skeleton)
|
|
return;
|
|
|
|
auto model_state = &skeleton->GetModel();
|
|
if (!model_state)
|
|
return;
|
|
|
|
CStrongHandle<CModel> model = model_state->m_hModel();
|
|
if (!model.is_valid())
|
|
return;
|
|
|
|
auto model_skelet = &model->m_modelSkeleton();
|
|
if (!model_skelet)
|
|
return;
|
|
|
|
skeleton->calc_world_space_bones(0, bone_flags::FLAG_HITBOX);
|
|
|
|
auto data = model_state->GetHitboxData();
|
|
if (!data)
|
|
return;
|
|
|
|
if (!(model->GetHitboxFlags(idx) & bone_flags::FLAG_HITBOX))
|
|
return;
|
|
|
|
auto parent_index = model->GetHitboxParent(idx);
|
|
if (parent_index == -1)
|
|
return;
|
|
|
|
rot = data[idx].rot;
|
|
scale = data[idx].scale;
|
|
|
|
|
|
if (predict) {
|
|
// Extrapolate position based on velocity and acceleration
|
|
pos = data[idx].pos + this->m_vecVelocity() * I::GlobalVars->flIntervalPerTick;
|
|
}
|
|
else {
|
|
pos = data[idx].pos;
|
|
}
|
|
|
|
}
|
|
uint32_t C_CSPlayerPawn::GetHitGroup(int idx) {
|
|
switch (idx) {
|
|
case HEAD:
|
|
case NECK:
|
|
return HITGROUP_HEAD;
|
|
case CHEST:
|
|
case LEFT_CHEST:
|
|
case RIGHT_CHEST:
|
|
case PELVIS:
|
|
return HITGROUP_CHEST;
|
|
case STOMACH:
|
|
return HITGROUP_STOMACH;
|
|
case L_LEG:
|
|
case R_LEG:
|
|
case L_FEET:
|
|
case R_FEET:
|
|
return HITGROUP_LEFTLEG;
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
C_CSWeaponBase* C_CSPlayerPawn::ActiveWeapon() {
|
|
CPlayer_WeaponServices* WeaponServices = this->GetWeaponServices();
|
|
if (!WeaponServices)
|
|
return nullptr;
|
|
|
|
auto ActiveWeapon = I::GameResourceService->pGameEntitySystem->Get<C_CSWeaponBase>(WeaponServices->m_hActiveWeapon());
|
|
if (!ActiveWeapon)
|
|
return nullptr;
|
|
|
|
return ActiveWeapon;
|
|
}
|
|
|
|
C_CSWeaponBase* CCSPlayerController::GetPlayerWeapon(C_CSPlayerPawn* pPlayer)
|
|
{
|
|
if (!pPlayer || !pPlayer->GetWeaponServices())
|
|
return nullptr;
|
|
|
|
CBaseHandle hActiveWeapon = pPlayer->GetWeaponServices()->m_hActiveWeapon();
|
|
|
|
if (!hActiveWeapon.IsValid())
|
|
return nullptr;
|
|
|
|
C_CSWeaponBase* pWeapon = I::GameResourceService->pGameEntitySystem->Get<C_CSWeaponBase>(hActiveWeapon);
|
|
|
|
return pWeapon;
|
|
}
|
|
|
|
bool C_CSPlayerPawn::CanNextAttack(float svtime) {
|
|
return false;
|
|
}
|
|
bool C_CSPlayerPawn::CanShoot(float svtime) {
|
|
CPlayer_WeaponServices* WeaponServices = this->GetWeaponServices();
|
|
if (!WeaponServices)
|
|
return false;
|
|
|
|
auto ActiveWeapon = I::GameResourceService->pGameEntitySystem->Get<C_CSWeaponBase>(WeaponServices->m_hActiveWeapon());
|
|
if (!ActiveWeapon)
|
|
return false;
|
|
|
|
auto data = ActiveWeapon->datawep();
|
|
if (!data)
|
|
return false;
|
|
|
|
if (ActiveWeapon->clip1() <= 0)
|
|
return false;
|
|
|
|
if (data->m_WeaponType() == WEAPONTYPE_KNIFE || data->m_WeaponType() == WEAPONTYPE_FISTS)
|
|
return true;
|
|
/*
|
|
auto next_attack = (WeaponServices->m_flNextAttack());
|
|
auto next_2 = WeaponServices->m_flNextAttack() * I::GlobalVars->flIntervalPerTick;
|
|
auto next_3 = static_cast<float>(WeaponServices->m_flNextAttack() * I::GlobalVars->flIntervalPerTick);
|
|
*/
|
|
|
|
auto primary_tick = ActiveWeapon->m_nNextPrimaryAttackTick();
|
|
|
|
if (primary_tick > svtime) {
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
bool C_CSPlayerPawn::Visible(C_CSPlayerPawn* local, int type, bool v)
|
|
{
|
|
if (!this || this->GetHealth() <= 0)
|
|
return false;
|
|
|
|
if (type == 0) {
|
|
trace_filter_t filter = {};
|
|
I::Trace->Init(filter, local, 0x1C3003, 4, 7);
|
|
|
|
game_trace_t trace = {};
|
|
ray_t ray = {};
|
|
|
|
Vector_t start_eye = local->GetEyePosition();
|
|
Vector_t end_eye = this->GetEyePosition();
|
|
|
|
I::Trace->TraceShape(ray, &start_eye, &end_eye, filter, trace);
|
|
|
|
return trace.HitEntity && trace.HitEntity->GetRefEHandle().GetEntryIndex() == this->GetRefEHandle().GetEntryIndex() || trace.Fraction > 0.97f;
|
|
}
|
|
else if (type == TRACE_TYPE::AIMBOT) {
|
|
if (v) {
|
|
trace_filter_t filter = {};
|
|
I::Trace->Init(filter, local, 0x1C3003, 4, 7);
|
|
|
|
game_trace_t trace = {};
|
|
ray_t ray = {};
|
|
|
|
Vector_t start_eye = local->GetEyePosition();
|
|
Vector_t end_eye = this->GetEyePosition();
|
|
|
|
I::Trace->TraceShape(ray, &start_eye, &end_eye, filter, trace);
|
|
|
|
return trace.HitEntity && trace.HitEntity->GetRefEHandle().GetEntryIndex() == this->GetRefEHandle().GetEntryIndex() || trace.Fraction > 0.97f;
|
|
}
|
|
else
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
float C_CSPlayerPawn::GetProperSpread() {
|
|
/* acc penalty */
|
|
auto weapon = this->ActiveWeapon();
|
|
if (!weapon)
|
|
return 0.f;
|
|
|
|
auto vdata = weapon->datawep();
|
|
if (!vdata)
|
|
return 0.f;
|
|
float flSpread = 0.f;
|
|
if (weapon->m_weaponMode() == CSWeaponMode::Primary_Mode)
|
|
{
|
|
return vdata->m_flSpread().flValue[0];
|
|
}
|
|
else if (weapon->m_weaponMode() == CSWeaponMode::Secondary_Mode)
|
|
{
|
|
return vdata->m_flSpread().flValue[1];
|
|
}
|
|
return flSpread;
|
|
};
|
|
float C_CSPlayerPawn::GetProperAccuracy() {
|
|
/* acc penalty */
|
|
auto weapon = this->ActiveWeapon();
|
|
if (!weapon)
|
|
return 0.f;
|
|
|
|
auto vdata = weapon->datawep();
|
|
if (!vdata)
|
|
return 0.f;
|
|
|
|
float flInnacuracy = weapon->m_fAccuracyPenalty();
|
|
|
|
if (this->m_vecVelocity().Length2D() != 0.0f) /* we are not standing */
|
|
{
|
|
float flInnacuracyMove = 0.0f;
|
|
|
|
if (weapon->m_weaponMode() == CSWeaponMode::Primary_Mode)
|
|
flInnacuracyMove = vdata->m_flInaccuracyMove().flValue[0];
|
|
else if (weapon->m_weaponMode() == CSWeaponMode::Secondary_Mode)
|
|
flInnacuracyMove = vdata->m_flInaccuracyMove().flValue[1];
|
|
|
|
if (this->m_bIsWalking())
|
|
flInnacuracyMove /= 3.f;
|
|
|
|
else if (this->GetFlags() & FL_DUCKING)
|
|
flInnacuracyMove /= 6.f;
|
|
|
|
flInnacuracy += flInnacuracyMove;
|
|
}
|
|
|
|
if (!(this->GetFlags() & FL_ONGROUND))
|
|
{
|
|
if (weapon->m_weaponMode() == CSWeaponMode::Primary_Mode)
|
|
flInnacuracy += vdata->m_flInaccuracyJump().flValue[0];
|
|
else if (weapon->m_weaponMode() == CSWeaponMode::Secondary_Mode)
|
|
flInnacuracy += vdata->m_flInaccuracyJump().flValue[1];
|
|
}
|
|
|
|
return flInnacuracy;
|
|
};
|
|
bool C_CSPlayerPawn::InsideCrosshair(C_CSPlayerPawn* target, QAngle_t ang, float range)
|
|
{
|
|
if (!this || this->GetHealth() <= 0)
|
|
return false;
|
|
|
|
|
|
trace_filter_t filter = {};
|
|
I::Trace->Init(filter, target, 0x1C3003, 4, 7);
|
|
|
|
game_trace_t trace = {};
|
|
ray_t ray = {};
|
|
Vector_t vecForward = { };
|
|
ang.ToDirections(&vecForward);
|
|
vecForward *= range;
|
|
Vector_t vecStart = target->GetEyePosition();
|
|
Vector_t vecEnd = vecStart + vecForward;
|
|
I::Trace->TraceShape(ray, &vecStart, &vecEnd, filter, trace);
|
|
|
|
return trace.HitEntity && trace.HitEntity->GetRefEHandle().GetEntryIndex() == this->GetRefEHandle().GetEntryIndex();
|
|
}
|
|
|
|
bool C_CSPlayerPawn::TracePoint(C_CSPlayerPawn* target, Vector_t end)
|
|
{
|
|
if (!this || this->GetHealth() <= 0)
|
|
return false;
|
|
|
|
trace_filter_t filter = {};
|
|
I::Trace->Init(filter, this, 0x1C3003, 4, 7);
|
|
|
|
game_trace_t trace = {};
|
|
ray_t ray = {};
|
|
|
|
Vector_t vecStart = this->GetEyePosition();
|
|
I::Trace->TraceShape(ray, &vecStart, &end, filter, trace);
|
|
|
|
if (trace.HitEntity && trace.HitEntity->GetRefEHandle().GetEntryIndex() == target->GetRefEHandle().GetEntryIndex())
|
|
{
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
|
|
// cHoca
|
|
|
|
bool C_BaseEntity::ComputeHitboxSurroundingBox(Vector_t& min, Vector_t& max) {
|
|
using fnComputeHitboxSurroundingBox = bool(CS_FASTCALL*)(void*, Vector_t&, Vector_t&);
|
|
static auto ComputeHitboxSurroundingBox = reinterpret_cast<fnComputeHitboxSurroundingBox>(MEM::GetAbsoluteAddress(MEM::FindPattern(CLIENT_DLL, CS_XOR("E9 ? ? ? ? F6 43 5B FD")), 1, 0));
|
|
if (!ComputeHitboxSurroundingBox) {
|
|
L_PRINT(LOG_ERROR) << CS_XOR("[C_BaseEntity::ComputeHitboxSurroundingBox] C_HOOK::ComputeHitboxSurroundingBox > null");
|
|
return false;
|
|
}
|
|
return ComputeHitboxSurroundingBox(this, min, max);
|
|
|
|
}
|
|
//?GetNumberOfBoundContexts@SchedulerBase@details@Concurrency@@IEBAKXZ_0 ; Concurrency::details::SchedulerBase::GetNumberOfBoundContexts(void)
|
|
// Em baixo no SUBROUTINE de baixo
|
|
|
|
#include "../core/spoofcall/invoker.h"
|
|
void CSkeletonInstance::get_bone_data(bone_data& data, int index)
|
|
{
|
|
// cHoca
|
|
|
|
using fnBoneData = void(CS_FASTCALL*)(void*, bone_data&, int index);
|
|
static auto BoneData = reinterpret_cast<fnBoneData>(MEM::FindPattern(CLIENT_DLL, CS_XOR("E8 ? ? ? ? EB 19 48 8B CF")));
|
|
|
|
return BoneData(this, data, index);
|
|
}
|
|
// #STR: "C:\\buildworker\\csgo_rel_win64\\build\\src\\game\\shared\, "Bone merge bones from parent were invalid: parent model '%, "CalcWorldSpaceBones"
|
|
void CS_FASTCALL CSkeletonInstance::calc_world_space_bones(uint32_t parent, uint32_t mask)
|
|
{ // cHoca
|
|
|
|
using fnNewCalcWSsBones = void(CS_FASTCALL)(void*, uint32_t);
|
|
static auto bone_new = reinterpret_cast<fnNewCalcWSsBones*>(MEM::FindPattern(CLIENT_DLL, CS_XOR("40 55 56 57 41 54 41 55 41 56 41 57 48 81 EC D0")));
|
|
return bone_new(this, mask);
|
|
}
|
|
|
|
uint32_t CModel::GetHitboxesNum() {
|
|
|
|
using fnHitboxNum = uint32_t(CS_FASTCALL*)(void*);
|
|
static auto HitboxNum = reinterpret_cast<fnHitboxNum>(MEM::GetAbsoluteAddress(MEM::FindPattern(CLIENT_DLL, CS_XOR("E8 ? ? ? ? 8B D8 48 C7 44 24 50 00 00 00 00")), 1, 0));
|
|
CS_ASSERT(HitboxNum != nullptr);
|
|
|
|
return HitboxNum(this);
|
|
|
|
}
|
|
|
|
CGCClientSharedObjectCache* CGCClient::FindSOCache(SOID_t ID,
|
|
bool bCreateIfMissing) {
|
|
|
|
using fnFindSOCache = CGCClientSharedObjectCache * (CS_FASTCALL*)(void*, SOID_t, bool);
|
|
static auto FindSOCache = reinterpret_cast<fnFindSOCache>(MEM::FindPattern(CLIENT_DLL, CS_XOR("48 89 5C 24 10 48 89 6C 24 18 48 89 7C 24 20 41 54 41 56 41 57 48 83 EC 40 48")));
|
|
CS_ASSERT(FindSOCache != nullptr);
|
|
|
|
return FindSOCache(this, ID, bCreateIfMissing);
|
|
|
|
}
|
|
|
|
|
|
|
|
void CGameSceneNode::SetMeshGroupMask(uint64_t meshGroupMask) {
|
|
if (!H::SetMeshGroupMask) {
|
|
L_PRINT(LOG_ERROR) << "error getting meshgroupmask";
|
|
}
|
|
|
|
return H::SetMeshGroupMask(this, meshGroupMask);
|
|
}
|
|
|
|
void C_BaseModelEntity::SetModel(const char* name) {
|
|
auto orig = H::hkSetModel.GetOriginal();
|
|
return orig(this, name);
|
|
}
|
|
|
|
|
|
void CEconItem::SetDynamicAttributeValue(int index, void* value) {
|
|
CEconItemSchema* pItemSchema =
|
|
I::Client->GetEconItemSystem()->GetEconItemSchema();
|
|
if (!pItemSchema) return;
|
|
|
|
void* pAttributeDefinitionInterface =
|
|
pItemSchema->GetAttributeDefinitionInterface(index);
|
|
if (!pAttributeDefinitionInterface) return;
|
|
|
|
if (!H::fnSetDynamicAttributeValueUint) return;
|
|
H::fnSetDynamicAttributeValueUint(this, pAttributeDefinitionInterface,
|
|
value);
|
|
}
|
|
|
|
void CEconItem::SetDynamicAttributeValueString(int index, const char* value) {
|
|
// CS2FIXME: Function got inlined and cannot be sigscanned.
|
|
}
|
|
|
|
CEconItem* CEconItem::CreateInstance() {
|
|
// ida: // #STR: "Update(CEconItem)", "CEconItem", "Create(CEconItem)", "BuildCacheSubscribed(CEconItem)", "Update(CEconEquipSlot)", "CEconEquipSlot", "Create(CEconEquipSlot)", "BuildCacheSubscribed(CEconEquipSlot)", "Update(CEconPersonaDataPublic)", "CEconPersonaDataPublic"
|
|
// ida: sub_E0F420(
|
|
// 1,
|
|
// (unsigned int)CEconItem::CreateInstance,
|
|
// 0,
|
|
// (unsigned int)"CEconItem",
|
|
// (__int64)"BuildCacheSubscribed(CEconItem)",
|
|
// (__int64)"Create(CEconItem)",
|
|
// (__int64)"Update(CEconItem)");
|
|
|
|
using fnCreateSharedObjectSubclassEconItem = CEconItem * (__cdecl*)();
|
|
static fnCreateSharedObjectSubclassEconItem oCreateSharedObjectSubclassEconItem = reinterpret_cast<fnCreateSharedObjectSubclassEconItem>(MEM::FindPattern(CLIENT_DLL, CS_XOR("48 83 EC 28 B9 48 00 00 00 E8 ? ? ? ? 48 85")));
|
|
|
|
#ifdef CS_PARANOID
|
|
CS_ASSERT(oCreateSharedObjectSubclassEconItem != nullptr);
|
|
#endif
|
|
|
|
return oCreateSharedObjectSubclassEconItem();
|
|
}
|
|
uint32_t CModel::GetHitboxFlags(uint32_t index)
|
|
{
|
|
|
|
using fnHitboxFlags = uint32_t(CS_FASTCALL*)(void*, uint32_t);
|
|
static auto HitboxFlags = reinterpret_cast<fnHitboxFlags>(MEM::FindPattern(CLIENT_DLL, CS_XOR("85 D2 78 16 3B 91")));
|
|
CS_ASSERT(HitboxFlags != nullptr);
|
|
|
|
return HitboxFlags(this, index);
|
|
}
|
|
|
|
const char* CModel::GetHitboxName(uint32_t index)
|
|
{
|
|
using fnHitboxName = const char* (CS_FASTCALL*)(void*, uint32_t);
|
|
static auto HitboxName = reinterpret_cast<fnHitboxName>(MEM::FindPattern(CLIENT_DLL, CS_XOR("85 D2 78 25 3B 91")));
|
|
CS_ASSERT(HitboxName != nullptr);
|
|
|
|
return HitboxName(this, index);
|
|
}
|
|
|
|
uint32_t CModel::GetHitboxParent(uint32_t index)
|
|
{
|
|
|
|
using fnHitboxParent = uint32_t(CS_FASTCALL*)(void*, uint32_t);
|
|
static auto HitboxParent = reinterpret_cast<fnHitboxParent>(MEM::FindPattern(CLIENT_DLL, CS_XOR("85 D2 78 17 3B 91 78")));
|
|
CS_ASSERT(HitboxParent != nullptr);
|
|
return HitboxParent(this, index);
|
|
}
|
|
|
|
CGCClientSharedObjectTypeCache* CGCClientSharedObjectCache::CreateBaseTypeCache(
|
|
int nClassID) {
|
|
using fnCGCClientSharedObjectTypeCache = CGCClientSharedObjectTypeCache * (CS_FASTCALL*)(void*, int);
|
|
static fnCGCClientSharedObjectTypeCache createbasetypecache = reinterpret_cast<fnCGCClientSharedObjectTypeCache>(MEM::GetAbsoluteAddress(MEM::FindPattern(CLIENT_DLL, CS_XOR("E8 ? ? ? ? 33 C9 8B D1")), 1, 0));
|
|
CS_ASSERT(createbasetypecache != nullptr);
|
|
return createbasetypecache(this, nClassID);
|
|
}
|
|
|
|
|
|
void C_CSWeaponBase::AddStattrakEntity()
|
|
{
|
|
using fnAddStattrakEntity = void(CS_FASTCALL*)(void*);
|
|
static auto hkAddStattrakEntity = reinterpret_cast<fnAddStattrakEntity>(MEM::FindPattern(CLIENT_DLL, CS_XOR("40 55 41 55 48 8D 6C 24 B8")));
|
|
CS_ASSERT(hkAddStattrakEntity != nullptr);
|
|
return hkAddStattrakEntity(this);
|
|
}
|
|
|
|
void C_CSWeaponBase::AddNametagEntity()
|
|
{
|
|
using fnAddNametagEntity = void(CS_FASTCALL*)(void*);
|
|
static auto hkAddNametagEntity = reinterpret_cast<fnAddNametagEntity>(MEM::GetAbsoluteAddress(MEM::FindPattern(CLIENT_DLL, CS_XOR("E8 ? ? ? ? 48 8B CF E8 ? ? ? ? 48 8B C8 E8 ? ? ? ?")), 1, 0));
|
|
CS_ASSERT(hkAddNametagEntity != nullptr);
|
|
return hkAddNametagEntity(this);
|
|
}
|
|
|
|
CEconItem* C_EconItemView::GetSOCData(CCSPlayerInventory* sdfsdf) {
|
|
CCSPlayerInventory* pInventory = CCSPlayerInventory::GetInstance();
|
|
if (!pInventory) return nullptr;
|
|
|
|
return pInventory->GetSOCDataForItem(m_iItemID());
|
|
}
|
|
|
|
|
|
bool CEconItemDefinition::IsWeapon() {
|
|
// Every gun supports at least 4 stickers.
|
|
return GetStickersSupportedCount() >= 4;
|
|
}
|
|
|
|
bool CEconItemDefinition::IsKnife(bool excludeDefault, const char* name) {
|
|
auto CSGO_Type_Knife = FNV1A::Hash("#CSGO_Type_Knife");
|
|
|
|
if (FNV1A::Hash(this->m_pszItemBaseName) != CSGO_Type_Knife)
|
|
return false;
|
|
|
|
return excludeDefault ? m_nDefIndex >= 500 : true;
|
|
}
|
|
|
|
bool CEconItemDefinition::IsGlove(bool excludeDefault, const char* name) {
|
|
auto Type_Hands = FNV1A::Hash("#Type_Hands");
|
|
|
|
bool valid = FNV1A::Hash(this->m_pszItemBaseName) == Type_Hands;
|
|
bool defaultGlove = valid && m_nDefIndex == 5028 || m_nDefIndex == 5029;
|
|
|
|
return excludeDefault ? !defaultGlove : valid;
|
|
}
|