Fix crithack and nospread + clean up WeaponData usage

This commit is contained in:
BenCat07 2020-10-02 15:49:23 +02:00 committed by LightCat
parent f84279d4e2
commit 3d2858442f
5 changed files with 93 additions and 96 deletions

84
include/WeaponData.hpp Normal file
View File

@ -0,0 +1,84 @@
#include "common.hpp"
#pragma once
struct WeaponData_t
{
int m_nDamage;
int m_nBulletsPerShot;
float m_flRange;
float m_flSpread;
float m_flPunchAngle;
float m_flTimeFireDelay; // Time to delay between firing
float m_flTimeIdle; // Time to idle after firing
float m_flTimeIdleEmpty; // Time to idle after firing last bullet in clip
float m_flTimeReloadStart; // Time to start into a reload (ie. shotgun)
float m_flTimeReload; // Time to reload
bool m_bDrawCrosshair; // Should the weapon draw a crosshair
int m_iProjectile; // The type of projectile this mode fires
int m_iAmmoPerShot; // How much ammo each shot consumes
float m_flProjectileSpeed; // Start speed for projectiles (nail, etc.); NOTE: union with something non-projectile
float m_flSmackDelay; // how long after swing should damage happen for melee weapons
bool m_bUseRapidFireCrits;
};
class weapon_info
{
public:
float crit_bucket{};
unsigned int weapon_seed{};
unsigned unknown1{};
unsigned unknown2{};
bool unknown3{};
float unknown4{};
int crit_attempts{};
int crit_count{};
float observed_crit_chance{};
bool unknown7{};
int weapon_mode{};
int weapon_data{};
weapon_info()
{
}
void Load(IClientEntity *weapon)
{
crit_bucket = *(float *) ((uintptr_t) weapon + 0xa38);
weapon_seed = *(unsigned int *) ((uintptr_t) weapon + 0xb3c);
unknown1 = *(unsigned int *) ((uintptr_t) weapon + 0xb30);
unknown2 = *(unsigned int *) ((uintptr_t) weapon + 0xb34);
unknown3 = *(bool *) ((uintptr_t) weapon + 0xb17);
unknown4 = *(float *) ((uintptr_t) weapon + 0xb40);
crit_attempts = *(int *) ((uintptr_t) weapon + 0xa3c);
crit_count = *(int *) ((uintptr_t) weapon + 0xa40);
observed_crit_chance = *(float *) ((uintptr_t) weapon + 0xbfc);
unknown7 = *(bool *) ((uintptr_t) weapon + 0xb18);
// No need to restore
weapon_mode = *(int *) ((uintptr_t) weapon + 0xb04);
weapon_data = *(int *) ((uintptr_t) weapon + 0xb10);
}
weapon_info(IClientEntity *weapon)
{
Load(weapon);
}
void restore_data(IClientEntity *weapon)
{
*(float *) ((uintptr_t) weapon + 0xa38) = crit_bucket;
*(unsigned int *) ((uintptr_t) weapon + 0xb3c) = weapon_seed;
*(unsigned int *) ((uintptr_t) weapon + 0xb30) = unknown1;
*(unsigned int *) ((uintptr_t) weapon + 0xb34) = unknown2;
*(bool *) ((uintptr_t) weapon + 0xb17) = unknown3;
*(float *) ((uintptr_t) weapon + 0xb40) = unknown4;
*(int *) ((uintptr_t) weapon + 0xa3c) = crit_attempts;
*(int *) ((uintptr_t) weapon + 0xa40) = crit_count;
*(float *) ((uintptr_t) weapon + 0xbfc) = observed_crit_chance;
*(bool *) ((uintptr_t) weapon + 0xb18) = unknown7;
}
};
inline WeaponData_t *GetWeaponData(IClientEntity *weapon)
{
weapon_info info(weapon);
int WeaponData = info.weapon_data;
int WeaponMode = info.weapon_mode;
return (WeaponData_t *) (WeaponData + sizeof(WeaponData_t) * WeaponMode + 1784);
}

View File

@ -11,57 +11,4 @@ extern int current_index;
extern bool isEnabled();
extern bool force_crit_this_tick;
void fixBucket(IClientEntity *weapon, CUserCmd *cmd);
class weapon_info
{
public:
float crit_bucket{};
unsigned int weapon_seed{};
unsigned unknown1{};
unsigned unknown2{};
bool unknown3{};
float unknown4{};
int crit_attempts{};
int crit_count{};
float observed_crit_chance{};
bool unknown7{};
int weapon_mode{};
int weapon_data{};
weapon_info()
{
}
void Load(IClientEntity *weapon)
{
crit_bucket = *(float *) ((uintptr_t) weapon + 0xa38);
weapon_seed = *(unsigned int *) ((uintptr_t) weapon + 0xb3c);
unknown1 = *(unsigned int *) ((uintptr_t) weapon + 0xb30);
unknown2 = *(unsigned int *) ((uintptr_t) weapon + 0xb34);
unknown3 = *(bool *) ((uintptr_t) weapon + 0xb17);
unknown4 = *(float *) ((uintptr_t) weapon + 0xb40);
crit_attempts = *(int *) ((uintptr_t) weapon + 0xa3c);
crit_count = *(int *) ((uintptr_t) weapon + 0xa40);
observed_crit_chance = *(float *) ((uintptr_t) weapon + 0xbfc);
unknown7 = *(bool *) ((uintptr_t) weapon + 0xb18);
// No need to restore
weapon_mode = *(int *) ((uintptr_t) weapon + 0xb04);
weapon_data = *(int *) ((uintptr_t) weapon + 0xb10);
}
weapon_info(IClientEntity *weapon)
{
Load(weapon);
}
void restore_data(IClientEntity *weapon)
{
*(float *) ((uintptr_t) weapon + 0xa38) = crit_bucket;
*(unsigned int *) ((uintptr_t) weapon + 0xb3c) = weapon_seed;
*(unsigned int *) ((uintptr_t) weapon + 0xb30) = unknown1;
*(unsigned int *) ((uintptr_t) weapon + 0xb34) = unknown2;
*(bool *) ((uintptr_t) weapon + 0xb17) = unknown3;
*(float *) ((uintptr_t) weapon + 0xb40) = unknown4;
*(int *) ((uintptr_t) weapon + 0xa3c) = crit_attempts;
*(int *) ((uintptr_t) weapon + 0xa40) = crit_count;
*(float *) ((uintptr_t) weapon + 0xbfc) = observed_crit_chance;
*(bool *) ((uintptr_t) weapon + 0xb18) = unknown7;
}
};
} // namespace criticals

View File

@ -1,6 +1,7 @@
#include "common.hpp"
#include "crits.hpp"
#include "Backtrack.hpp"
#include "WeaponData.hpp"
#include "netadr.h"
std::unordered_map<int, int> command_number_mod{};
@ -493,20 +494,13 @@ static void updateCmds()
if (added_per_shot == 0.0f || previous_weapon != weapon->entindex())
{
weapon_info info(weapon);
// m_pWeaponInfo->GetWeaponData(m_iWeaponMode).m_nBulletsPerShot;
int WeaponData = info.weapon_data;
int WeaponMode = info.weapon_mode;
// Size of one WeaponMode_t is 0x40, 0x6fc is the offset to projectiles per shot
int nProjectilesPerShot = *(int *) (WeaponData + 0x6fc + WeaponMode * 0x40);
int nProjectilesPerShot = GetWeaponData(weapon)->m_nBulletsPerShot;
if (nProjectilesPerShot >= 1)
nProjectilesPerShot = ATTRIB_HOOK_FLOAT(nProjectilesPerShot, "mult_bullets_per_shot", weapon, 0x0, true);
else
nProjectilesPerShot = 1;
// Size of one WeaponMode_t is 0x40, 0x6f8 is the offset to damage
added_per_shot = *(int *) (WeaponData + 0x6f8 + WeaponMode * 0x40);
added_per_shot = GetWeaponData(weapon)->m_nDamage;
added_per_shot = ATTRIB_HOOK_FLOAT(added_per_shot, "mult_dmg", weapon, 0x0, true);
added_per_shot *= nProjectilesPerShot;
shots_to_fill_bucket = getBucketCap() / added_per_shot;
@ -514,8 +508,7 @@ static void updateCmds()
if (isRapidFire(weapon))
{
taken_per_crit = added_per_shot;
// Size of one WeaponMode_t is 0x40, 0x70c is the offset to Fire delay
taken_per_crit *= 2.0f / *(float *) (WeaponData + 0x70c + WeaponMode * 0x40);
taken_per_crit *= 2.0f / GetWeaponData(weapon)->m_flTimeFireDelay;
// Yes this looks dumb but i want to ensure that it matches with valve code
int bucket_cap_recasted = (int) getBucketCap();

View File

@ -12,6 +12,7 @@
#include "MiscTemporary.hpp"
#include "PlayerTools.hpp"
#include "Ragdolls.hpp"
#include "WeaponData.hpp"
static settings::Boolean tcm{ "debug.tcm", "true" };
static settings::Boolean should_correct_punch{ "debug.correct-punch", "true" };
@ -838,9 +839,8 @@ void AngleVectors3(const QAngle &angles, Vector *forward, Vector *right, Vector
bool isRapidFire(IClientEntity *wep)
{
criticals::weapon_info info(wep);
// Taken from game, m_pWeaponInfo->GetWeaponData( m_iWeaponMode ).m_bUseRapidFireCrits;
bool ret = *(bool *) (info.weapon_data + 0x734 + info.weapon_mode * 0x40);
weapon_info info(wep);
bool ret = GetWeaponData(wep)->m_bUseRapidFireCrits;
// Minigun changes mode once revved, so fix that
return ret || wep->GetClientClass()->m_ClassID == CL_CLASS(CTFMinigun);
}
@ -1606,7 +1606,7 @@ float ATTRIB_HOOK_FLOAT(float base_value, const char *search_string, IClientEnti
{
typedef float (*AttribHookFloat_t)(float, const char *, IClientEntity *, void *, bool);
static uintptr_t AttribHookFloat = gSignatures.GetClientSignature("55 89 E5 57 56 53 83 EC 6C C7 45 ? 00 00 00 00 A1 ? ? ? ? C7 45 ? 00 00 00 00 8B 75 ? 85 C0 0F 84 ? ? ? ? 8D 55 ? 89 04 24 31 DB 89 54 24");
static uintptr_t AttribHookFloat = e8call_direct(gSignatures.GetClientSignature("E8 ? ? ? ? 8B 96 ? ? ? ? D9 5D"));
static auto AttribHookFloat_fn = AttribHookFloat_t(AttribHookFloat);
return AttribHookFloat_fn(base_value, search_string, ent, buffer, is_global_const_string);

View File

@ -28,34 +28,7 @@
#include "usercmd.hpp"
#include "MiscTemporary.hpp"
#include "AntiAim.hpp"
struct WeaponData_t
{
int m_nDamage;
int m_nBulletsPerShot;
float m_flRange;
float m_flSpread;
float m_flPunchAngle;
float m_flTimeFireDelay; // Time to delay between firing
float m_flTimeIdle; // Time to idle after firing
float m_flTimeIdleEmpty; // Time to idle after firing last bullet in clip
float m_flTimeReloadStart; // Time to start into a reload (ie. shotgun)
float m_flTimeReload; // Time to reload
bool m_bDrawCrosshair; // Should the weapon draw a crosshair
int m_iProjectile; // The type of projectile this mode fires
int m_iAmmoPerShot; // How much ammo each shot consumes
float m_flProjectileSpeed; // Start speed for projectiles (nail, etc.); NOTE: union with something non-projectile
float m_flSmackDelay; // how long after swing should damage happen for melee weapons
bool m_bUseRapidFireCrits;
};
WeaponData_t *GetWeaponData(IClientEntity *weapon)
{
criticals::weapon_info info(weapon);
int WeaponData = info.weapon_data;
int WeaponMode = info.weapon_mode;
return (WeaponData_t *) (WeaponData + sizeof(WeaponData_t) * WeaponMode + 1784);
}
#include "WeaponData.hpp"
namespace hacks::tf2::nospread
{