Add bullet changes from iw4x

This commit is contained in:
FutureRave 2022-05-12 19:45:29 +01:00
parent 949d6ad9d5
commit f4f5960dcf
No known key found for this signature in database
GPG Key ID: E883E2BC9657D955
10 changed files with 316 additions and 20 deletions

3
.gitmodules vendored
View File

@ -34,3 +34,6 @@
path = deps/zstd path = deps/zstd
url = https://github.com/facebook/zstd.git url = https://github.com/facebook/zstd.git
branch = dev branch = dev
[submodule "deps/minhook"]
path = deps/minhook
url = https://github.com/TsudaKageyu/minhook.git

1
deps/minhook vendored Submodule

@ -0,0 +1 @@
Subproject commit 4a455528f61b5a375b1f9d44e7d296d47f18bb18

31
deps/premake/minhook.lua vendored Normal file
View File

@ -0,0 +1,31 @@
minhook = {
source = path.join(dependencies.basePath, "minhook"),
}
function minhook.import()
links { "minhook" }
minhook.includes()
end
function minhook.includes()
includedirs {
path.join(minhook.source, "include")
}
end
function minhook.project()
project "minhook"
language "C"
minhook.includes()
files {
path.join(minhook.source, "src/**.h"),
path.join(minhook.source, "src/**.c"),
}
warnings "Off"
kind "StaticLib"
end
table.insert(dependencies, minhook)

View File

@ -17,8 +17,6 @@ namespace game
Dvar_RegisterInt_t Dvar_RegisterInt; Dvar_RegisterInt_t Dvar_RegisterInt;
Dvar_RegisterFloat_t Dvar_RegisterFloat;
Dvar_SetIntByName_t Dvar_SetIntByName; Dvar_SetIntByName_t Dvar_SetIntByName;
Dvar_SetFromStringByName_t Dvar_SetFromStringByName; Dvar_SetFromStringByName_t Dvar_SetFromStringByName;
@ -246,11 +244,64 @@ namespace game
{ {
return dvar_find_malleable_var(dvarName); return dvar_find_malleable_var(dvarName);
} }
else
{
return reinterpret_cast<dvar_t*(*)(const char*)> return reinterpret_cast<dvar_t*(*)(const char*)>
(SELECT_VALUE(0x539550, 0x5BDCC0, 0x0))(dvarName); (SELECT_VALUE(0x539550, 0x5BDCC0, 0x0))(dvarName);
} }
constexpr auto Dvar_RegisterVariant_Addr = 0x531F70;
__declspec(naked) const dvar_t* Dvar_RegisterVariant(const char* dvarName, unsigned char type,
unsigned __int16 flags, DvarValue value, DvarLimits domain, const char* description)
{
__asm
{
push eax
pushad
mov edi, [esp + 0x24 + 0x28] // description
mov eax, [esp + 0x24 + 0x4] // dvarName
push [esp + 0x24 + 0x24] // domain
push [esp + 0x24 + 0x24] // domain
push [esp + 0x24 + 0x24] // value
push [esp + 0x24 + 0x24] // value
push [esp + 0x24 + 0x24] // value
push [esp + 0x24 + 0x24] // value
push [esp + 0x24 + 0x24] // flags
push [esp + 0x24 + 0x24] // type
call Dvar_RegisterVariant_Addr
add esp, 0x20
mov [esp + 0x20], eax // result
popad
pop eax
retn
}
}
const dvar_t* Dvar_RegisterFloat(const char* dvarName, float value,
float min, float max, unsigned __int16 flags, const char* description)
{
if (!is_dedi())
{
return reinterpret_cast<const dvar_t*(*)(const char*, float, float, float, unsigned __int16, const char*)>
(SELECT_VALUE(0x4F9CC0, 0x5BEA80, 0x0))(dvarName, value, min, max, flags, description);
}
DvarLimits domain;
DvarValue dvar_value;
domain.value.min = min;
domain.value.max = max;
dvar_value.value = value;
return Dvar_RegisterVariant(dvarName, dvar_type::DVAR_TYPE_FLOAT,
flags, dvar_value, domain, description);
} }
const float* Scr_AllocVector(const float* v) const float* Scr_AllocVector(const float* v)
@ -632,8 +683,6 @@ namespace game
native::Dvar_RegisterInt = native::Dvar_RegisterInt_t(SELECT_VALUE(0x48CD40, 0x5BEA40, 0x0)); native::Dvar_RegisterInt = native::Dvar_RegisterInt_t(SELECT_VALUE(0x48CD40, 0x5BEA40, 0x0));
native::Dvar_RegisterFloat = native::Dvar_RegisterFloat_t(SELECT_VALUE(0x4F9CC0, 0x5BEA80, 0x0));
native::Dvar_SetIntByName = native::Dvar_SetIntByName_t(SELECT_VALUE(0x5396B0, 0x5BF560, 0x0)); native::Dvar_SetIntByName = native::Dvar_SetIntByName_t(SELECT_VALUE(0x5396B0, 0x5BF560, 0x0));
native::Dvar_SetFromStringByName = native::Dvar_SetFromStringByName_t( native::Dvar_SetFromStringByName = native::Dvar_SetFromStringByName_t(

View File

@ -31,10 +31,6 @@ namespace game
int min, int max, unsigned __int16 flags, const char* description); int min, int max, unsigned __int16 flags, const char* description);
extern Dvar_RegisterInt_t Dvar_RegisterInt; extern Dvar_RegisterInt_t Dvar_RegisterInt;
typedef const dvar_t* (*Dvar_RegisterFloat_t)(const char* dvarName, float value,
float min, float max, unsigned __int16 flags, const char* description);
extern Dvar_RegisterFloat_t Dvar_RegisterFloat;
typedef void (*Dvar_SetIntByName_t)(const char* dvarName, int value); typedef void (*Dvar_SetIntByName_t)(const char* dvarName, int value);
extern Dvar_SetIntByName_t Dvar_SetIntByName; extern Dvar_SetIntByName_t Dvar_SetIntByName;
@ -104,8 +100,8 @@ namespace game
typedef void (*PM_WeaponUseAmmo_t)(playerState_s* ps, const Weapon weapon, bool isAlternate, int amount, PlayerHandIndex hand); typedef void (*PM_WeaponUseAmmo_t)(playerState_s* ps, const Weapon weapon, bool isAlternate, int amount, PlayerHandIndex hand);
extern PM_WeaponUseAmmo_t PM_WeaponUseAmmo; extern PM_WeaponUseAmmo_t PM_WeaponUseAmmo;
typedef void (*CM_TransformedCapsuleTrace_t)(game::native::trace_t* results, const float* start, const float* end, typedef void (*CM_TransformedCapsuleTrace_t)(trace_t* results, const float* start, const float* end,
const game::native::Bounds* bounds, const game::native::Bounds* capsule, int contents, const Bounds* bounds, const Bounds* capsule, int contents,
const float* origin, const float* angles); const float* origin, const float* angles);
extern CM_TransformedCapsuleTrace_t CM_TransformedCapsuleTrace; extern CM_TransformedCapsuleTrace_t CM_TransformedCapsuleTrace;
@ -197,6 +193,8 @@ namespace game
void* MT_Alloc(int numBytes, int type); void* MT_Alloc(int numBytes, int type);
dvar_t* Dvar_FindVar(const char* dvarName); dvar_t* Dvar_FindVar(const char* dvarName);
const dvar_t* Dvar_RegisterVariant(const char* dvarName, unsigned char type, unsigned __int16 flags, DvarValue value, DvarLimits domain, const char* description);
const dvar_t* Dvar_RegisterFloat(const char* dvarName, float value, float min, float max, unsigned __int16 flags, const char* description);
const float* Scr_AllocVector(const float* v); const float* Scr_AllocVector(const float* v);
void Scr_ClearOutParams(); void Scr_ClearOutParams();

View File

@ -547,13 +547,14 @@ namespace game
enum dvar_flags : std::uint16_t enum dvar_flags : std::uint16_t
{ {
DVAR_ARCHIVE = 0x1, DVAR_ARCHIVE = 1 << 0,
DVAR_CHEAT = 0x4, DVAR_CHEAT = 1 << 2,
DVAR_CODINFO = 0x8, DVAR_CODINFO = 1 << 3,
DVAR_SCRIPTINFO = 0x10, DVAR_SCRIPTINFO = 1 << 4,
DVAR_SERVERINFO = 0x400, DVAR_SERVERINFO = 1 << 10,
DVAR_WRITEPROTECTED = 0x800, DVAR_WRITEPROTECTED = 1 << 11,
DVAR_READONLY = 0x2000, DVAR_READONLY = 1 << 13,
DVAR_AUTOEXEC = 1 << 15,
}; // Incomplete }; // Incomplete
enum dvar_type : std::int8_t enum dvar_type : std::int8_t
@ -581,6 +582,8 @@ namespace game
char color[4]; char color[4];
}; };
static_assert(sizeof(DvarValue) == 0x10);
struct enum_limit struct enum_limit
{ {
int stringCount; int stringCount;

56
src/module/bullet.cpp Normal file
View File

@ -0,0 +1,56 @@
#include <std_include.hpp>
#include <loader/module_loader.hpp>
#include "game/game.hpp"
#include <utils/hook.hpp>
#include "bullet.hpp"
const game::native::dvar_t* bullet::bg_bulletRange;
const game::native::dvar_t* bullet::bg_surfacePenetration;
DWORD bullet::bullet_fire_addr;
utils::hook::detour bullet::bg_get_surface_penetration_depth_hook;
__declspec(naked) void bullet::bullet_fire_stub()
{
__asm
{
push eax
mov eax, bg_bulletRange
fld dword ptr [eax + 0xC] //dvar_t.current
pop eax
jmp bullet_fire_addr
}
}
float bullet::bg_get_surface_penetration_depth_stub(const game::native::Weapon weapon, bool is_alternate, int surface_type)
{
const auto value = bg_surfacePenetration->current.value;
if (value > 0.0f)
{
return value;
}
return bg_get_surface_penetration_depth_hook.invoke<float>(weapon, is_alternate, surface_type);
}
void bullet::post_load()
{
bg_bulletRange = game::native::Dvar_RegisterFloat("bg_bulletRange", 8192.0f, 0.0f,
std::numeric_limits<float>::max(), game::native::DVAR_CODINFO,
"Max range used when calculating the bullet end position");
bg_surfacePenetration = game::native::Dvar_RegisterFloat("bg_surfacePenetration", 0.0f,
0.0f, std::numeric_limits<float>::max(), game::native::DVAR_CODINFO,
"Set to a value greater than 0 to override the surface penetration depth");
bullet_fire_addr = SELECT_VALUE(0x5B6442, 0x4F6C5C, 0x46CFFA);
utils::hook(SELECT_VALUE(0x5B643C, 0x4F6C56, 0x46CFF4), &bullet_fire_stub, HOOK_JUMP).install()->quick();
bg_get_surface_penetration_depth_hook.create(SELECT_VALUE(0x43BDE0, 0x42F4D0, 0x421610), &bg_get_surface_penetration_depth_stub);
}
REGISTER_MODULE(bullet)

17
src/module/bullet.hpp Normal file
View File

@ -0,0 +1,17 @@
#pragma once
class bullet final : public module
{
public:
void post_load() override;
private:
static const game::native::dvar_t* bg_bulletRange;
static const game::native::dvar_t* bg_surfacePenetration;
static DWORD bullet_fire_addr;
static void bullet_fire_stub();
static utils::hook::detour bg_get_surface_penetration_depth_hook;
static float bg_get_surface_penetration_depth_stub(const game::native::Weapon weapon, bool isAlternate, int surfaceType);
};

View File

@ -1,8 +1,30 @@
#include <std_include.hpp> #include <std_include.hpp>
#include "hook.hpp" #include "hook.hpp"
#include <MinHook.h>
namespace utils namespace utils
{ {
namespace
{
[[maybe_unused]] class _
{
public:
_()
{
if (MH_Initialize() != MH_OK)
{
throw std::runtime_error("Failed to initialize MinHook");
}
}
~_()
{
MH_Uninitialize();
}
} __;
}
void hook::signature::process() void hook::signature::process()
{ {
if (this->signatures_.empty()) return; if (this->signatures_.empty()) return;
@ -42,6 +64,64 @@ namespace utils
signatures_.push_back(container); signatures_.push_back(container);
} }
hook::detour::detour(const size_t place, void* target) : detour(reinterpret_cast<void*>(place), target)
{
}
hook::detour::detour(void* place, void* target)
{
this->create(place, target);
}
hook::detour::~detour()
{
this->clear();
}
void hook::detour::enable() const
{
MH_EnableHook(this->place_);
}
void hook::detour::disable() const
{
MH_DisableHook(this->place_);
}
void hook::detour::create(void* place, void* target)
{
this->clear();
this->place_ = place;
if (MH_CreateHook(this->place_, target, &this->original_) != MH_OK)
{
throw std::runtime_error("Unable to create hook");
}
this->enable();
}
void hook::detour::create(const size_t place, void* target)
{
this->create(reinterpret_cast<void*>(place), target);
}
void hook::detour::clear()
{
if (this->place_)
{
MH_RemoveHook(this->place_);
}
this->place_ = nullptr;
this->original_ = nullptr;
}
void* hook::detour::get_original() const
{
return this->original_;
}
hook::~hook() hook::~hook()
{ {
if (this->initialized_) if (this->initialized_)

View File

@ -40,6 +40,64 @@ namespace utils
std::vector<container> signatures_; std::vector<container> signatures_;
}; };
class detour
{
public:
detour() = default;
detour(void* place, void* target);
detour(size_t place, void* target);
~detour();
detour(detour&& other) noexcept
{
this->operator=(std::move(other));
}
detour& operator=(detour&& other) noexcept
{
if (this != &other)
{
this->~detour();
this->place_ = other.place_;
this->original_ = other.original_;
other.place_ = nullptr;
other.original_ = nullptr;
}
return *this;
}
detour(const detour&) = delete;
detour& operator=(const detour&) = delete;
void enable() const;
void disable() const;
void create(void* place, void* target);
void create(size_t place, void* target);
void clear();
template <typename T>
T* get() const
{
return static_cast<T*>(this->get_original());
}
template <typename T = void, typename... Args>
T invoke(Args ... args)
{
return static_cast<T(*)(Args ...)>(this->get_original())(args...);
}
[[nodiscard]] void* get_original() const;
private:
void* place_{};
void* original_{};
};
hook() : initialized_(false), installed_(false), place_(nullptr), stub_(nullptr), original_(nullptr), hook() : initialized_(false), installed_(false), place_(nullptr), stub_(nullptr), original_(nullptr),
use_jump_(false), protection_(0) use_jump_(false), protection_(0)
{ {