fix: it's time to edge those bounces
This commit is contained in:
parent
e530495ecb
commit
87ce6fcf61
@ -3,7 +3,9 @@
|
||||
|
||||
#include <utils/cryptography.hpp>
|
||||
#include <utils/hook.hpp>
|
||||
#include <utils/io.hpp>
|
||||
#include <utils/nt.hpp>
|
||||
#include <utils/properties.hpp>
|
||||
#include <utils/smbios.hpp>
|
||||
#include <utils/string.hpp>
|
||||
|
||||
@ -63,9 +65,68 @@ std::string get_key_entropy() {
|
||||
return entropy;
|
||||
}
|
||||
|
||||
utils::cryptography::ecc::key& get_key() {
|
||||
static auto key =
|
||||
utils::cryptography::ecc::generate_key(512, get_key_entropy());
|
||||
bool load_key(utils::cryptography::ecc::key& key) {
|
||||
std::string data{};
|
||||
|
||||
auto key_path = (utils::properties::get_appdata_path() / "iw4xsp-private.key")
|
||||
.generic_string();
|
||||
if (!utils::io::read_file(key_path, &data)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
key.deserialize(data);
|
||||
if (!key.is_valid()) {
|
||||
game::Com_PrintError(game::CON_CHANNEL_ERROR, "Loaded key is invalid!\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
utils::cryptography::ecc::key generate_key() {
|
||||
auto key = utils::cryptography::ecc::generate_key(512, get_key_entropy());
|
||||
if (!key.is_valid()) {
|
||||
throw std::runtime_error("Failed to generate cryptographic key!");
|
||||
}
|
||||
|
||||
auto key_path = (utils::properties::get_appdata_path() / "iw4xsp-private.key")
|
||||
.generic_string();
|
||||
if (!utils::io::write_file(key_path, key.serialize())) {
|
||||
game::Com_PrintError(game::CON_CHANNEL_ERROR,
|
||||
"Failed to write cryptographic key!\n");
|
||||
}
|
||||
|
||||
game::Com_PrintError(game::CON_CHANNEL_ERROR,
|
||||
"Generated cryptographic key: %llX\n", key.get_hash());
|
||||
return key;
|
||||
}
|
||||
|
||||
utils::cryptography::ecc::key load_or_generate_key() {
|
||||
utils::cryptography::ecc::key key{};
|
||||
if (load_key(key)) {
|
||||
game::Com_PrintError(game::CON_CHANNEL_ERROR,
|
||||
"Loaded cryptographic key: %llX\n", key.get_hash());
|
||||
return key;
|
||||
}
|
||||
|
||||
return generate_key();
|
||||
}
|
||||
|
||||
utils::cryptography::ecc::key get_key_internal() {
|
||||
auto key = load_or_generate_key();
|
||||
|
||||
auto key_path = (utils::properties::get_appdata_path() / "iw4xsp-public.key")
|
||||
.generic_string();
|
||||
if (!utils::io::write_file(key_path, key.get_public_key())) {
|
||||
game::Com_PrintError(game::CON_CHANNEL_ERROR,
|
||||
"Failed to write public key!\n");
|
||||
}
|
||||
|
||||
return key;
|
||||
}
|
||||
|
||||
const utils::cryptography::ecc::key& get_key() {
|
||||
static auto key = get_key_internal();
|
||||
return key;
|
||||
}
|
||||
|
||||
|
@ -2,6 +2,7 @@
|
||||
#include "loader/component_loader.hpp"
|
||||
#include "game/dvars.hpp"
|
||||
|
||||
#include "branding.hpp"
|
||||
#include "scheduler.hpp"
|
||||
|
||||
#include <utils/hook.hpp>
|
||||
@ -17,10 +18,6 @@ constexpr auto* BUILD_TYPE = "IW4x_DEV SP";
|
||||
constexpr auto* BUILD_TYPE = "IW4x SP";
|
||||
#endif
|
||||
|
||||
constexpr const char* get_build_number() {
|
||||
return SHORTVERSION " latest " __DATE__ " " __TIME__;
|
||||
}
|
||||
|
||||
const char* get_version_string() {
|
||||
const auto* result = utils::string::va(
|
||||
"{0} {1} build {2} {3}", BUILD_TYPE, "(Alpha)", get_build_number(),
|
||||
@ -101,6 +98,10 @@ void branding_loop() {
|
||||
}
|
||||
} // namespace
|
||||
|
||||
const char* get_build_number() {
|
||||
return SHORTVERSION " latest " __DATE__ " " __TIME__;
|
||||
}
|
||||
|
||||
class component final : public component_interface {
|
||||
public:
|
||||
void post_load() override {
|
||||
|
5
src/client/component/branding.hpp
Normal file
5
src/client/component/branding.hpp
Normal file
@ -0,0 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
namespace branding {
|
||||
const char* get_build_number();
|
||||
}
|
@ -2,7 +2,6 @@
|
||||
#include "loader/component_loader.hpp"
|
||||
#include "game/dvars.hpp"
|
||||
#include "game/engine/scoped_critical_section.hpp"
|
||||
#include "game/engine/large_local.hpp"
|
||||
|
||||
#include <utils/hook.hpp>
|
||||
|
||||
@ -33,7 +32,7 @@ void com_bug_f(const command::params& params) {
|
||||
}
|
||||
|
||||
sprintf_s(new_file_name, "%s_%s.log", bug,
|
||||
game::Live_GetLocalClientName(game::LOCAL_CLIENT_0));
|
||||
game::Live_GetLocalClientName(game::CONTROLLER_INDEX_0));
|
||||
|
||||
game::engine::scoped_critical_section lock(game::CRITSECT_CONSOLE,
|
||||
game::SCOPED_CRITSECT_NORMAL);
|
||||
@ -79,8 +78,8 @@ void com_bug_name_inc_f() {
|
||||
void g_print_fast_file_errors(const char* fastfile) {
|
||||
assert(fastfile);
|
||||
|
||||
game::engine::large_local rawfile_buf_large_local(0x18000);
|
||||
auto* rawfile_buf = static_cast<char*>(rawfile_buf_large_local.get_buf());
|
||||
const auto rawfile_buf_large = std::make_unique<char[]>(0x18000);
|
||||
auto* rawfile_buf = rawfile_buf_large.get();
|
||||
|
||||
auto* text = game::DB_ReadRawFile(fastfile, rawfile_buf, 0x18000);
|
||||
|
||||
@ -91,6 +90,10 @@ void g_print_fast_file_errors(const char* fastfile) {
|
||||
"There were errors when building fast file '%s'\n",
|
||||
fastfile);
|
||||
game::Com_PrintError(game::CON_CHANNEL_ERROR, "%s", text);
|
||||
} else {
|
||||
game::Com_Printf(game::CON_CHANNEL_DONT_FILTER,
|
||||
"There were no errors when building fast file '%s'\n",
|
||||
fastfile);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -25,6 +25,8 @@ public:
|
||||
dvar::override::register_float("cg_fovScale", 1.0f, 0.2f, 2.0f,
|
||||
game::DVAR_ARCHIVE | game::DVAR_SAVED);
|
||||
dvar::override::register_string("fs_basegame", BASEGAME, game::DVAR_INIT);
|
||||
dvar::override::register_bool("com_filter_output", true,
|
||||
game::DVAR_ARCHIVE);
|
||||
|
||||
#ifdef _DEBUG
|
||||
dvar::override::register_bool("sv_cheats", true, game::DVAR_NONE);
|
||||
|
@ -1,11 +1,13 @@
|
||||
#include <std_include.hpp>
|
||||
#include "loader/component_loader.hpp"
|
||||
#include "game/game.hpp"
|
||||
#include "game/dvars.hpp"
|
||||
|
||||
#include <utils/hook.hpp>
|
||||
#include <utils/string.hpp>
|
||||
|
||||
#include "game_module.hpp"
|
||||
#include "filesystem.hpp"
|
||||
#include "game_module.hpp"
|
||||
|
||||
namespace filesystem {
|
||||
namespace {
|
||||
@ -15,6 +17,54 @@ const char* sys_default_install_path_stub() {
|
||||
}
|
||||
} // namespace
|
||||
|
||||
bool file_wrapper_rotate(const char* ospath) {
|
||||
constexpr auto MAX_BACKUPS = 20;
|
||||
|
||||
char renamed_path[game::MAX_OSPATH]{};
|
||||
struct _stat64i32 stat_buf;
|
||||
|
||||
auto oldest_index = -1;
|
||||
auto current_index = 0;
|
||||
time_t oldest_time = 0;
|
||||
|
||||
// Check if the original file exists
|
||||
if (_stat64i32(ospath, &stat_buf)) {
|
||||
return true; // Return true if the file does not exist (no file to rotate)
|
||||
}
|
||||
|
||||
for (; current_index < MAX_BACKUPS; ++current_index) {
|
||||
(void)sprintf_s(renamed_path, "%s.%03i", ospath, current_index);
|
||||
|
||||
if (_stat64i32(renamed_path, &stat_buf)) {
|
||||
break; // Stop if an available slot is found
|
||||
}
|
||||
|
||||
if (oldest_index == -1 || stat_buf.st_mtime < oldest_time) {
|
||||
oldest_time = stat_buf.st_mtime;
|
||||
oldest_index = current_index;
|
||||
}
|
||||
}
|
||||
|
||||
if (current_index == MAX_BACKUPS) {
|
||||
(void)sprintf_s(renamed_path, "%s.%03i", ospath, oldest_index);
|
||||
(void)std::remove(renamed_path); // Remove the oldest backup file
|
||||
} else {
|
||||
(void)sprintf_s(renamed_path, "%s.%03i", ospath, current_index);
|
||||
}
|
||||
|
||||
// Rename the original file to the selected backup slot
|
||||
return std::rename(ospath, renamed_path) == 0;
|
||||
}
|
||||
|
||||
bool file_rotate(const char* filename) {
|
||||
char ospath[game::MAX_OSPATH]{};
|
||||
|
||||
const auto* basepath = (*dvars::fs_homepath)->current.string;
|
||||
game::FS_BuildOSPath(basepath, reinterpret_cast<char*>(0x1956038), filename,
|
||||
ospath);
|
||||
return file_wrapper_rotate(ospath);
|
||||
}
|
||||
|
||||
std::vector<std::string> vectored_file_list(const std::string& path,
|
||||
const std::string& extension) {
|
||||
std::vector<std::string> file_list;
|
||||
|
@ -1,6 +1,9 @@
|
||||
#pragma once
|
||||
|
||||
namespace filesystem {
|
||||
bool file_wrapper_rotate(const char* ospath);
|
||||
bool file_rotate(const char* filename);
|
||||
|
||||
std::vector<std::string> vectored_file_list(const std::string& path,
|
||||
const std::string& extension);
|
||||
std::string get_binary_directory();
|
||||
|
@ -59,6 +59,11 @@ game::BuiltinMethod built_in_get_method_stub(const char** p_name, int* type) {
|
||||
// If no method was found let's call BuiltIn_GetMethod
|
||||
return utils::hook::invoke<game::BuiltinMethod>(0x5DB850, p_name, type);
|
||||
}
|
||||
|
||||
int hud_elem_set_enum_string_stub(char* string, const char* format,
|
||||
const char* string_value, const char* name) {
|
||||
return snprintf(string, 0x800, format, string_value, name);
|
||||
}
|
||||
} // namespace
|
||||
|
||||
void add_function(const char* name, game::BuiltinFunction func, bool type) {
|
||||
@ -89,6 +94,11 @@ public:
|
||||
.install()
|
||||
->quick(); // Scr_GetMethod
|
||||
|
||||
// Patch buffer overflows
|
||||
utils::hook(0x5BD3B9, hud_elem_set_enum_string_stub, HOOK_CALL)
|
||||
.install()
|
||||
->quick();
|
||||
|
||||
add_functions();
|
||||
#ifdef GSC_DEBUG_FUNCTIONS
|
||||
add_debug_functions();
|
||||
|
64
src/client/component/log_file.cpp
Normal file
64
src/client/component/log_file.cpp
Normal file
@ -0,0 +1,64 @@
|
||||
#include <std_include.hpp>
|
||||
#include "loader/component_loader.hpp"
|
||||
|
||||
#include "branding.hpp"
|
||||
#include "filesystem.hpp"
|
||||
|
||||
#include <utils/hook.hpp>
|
||||
#include <utils/string.hpp>
|
||||
|
||||
namespace log_file {
|
||||
namespace {
|
||||
void com_open_log_file_stub() {
|
||||
time_t aclock;
|
||||
char time[32]{};
|
||||
char log_file[game::MAX_OSPATH];
|
||||
|
||||
if (!game::Sys_IsMainThread() || *game::opening_qconsole) {
|
||||
return;
|
||||
}
|
||||
|
||||
*game::opening_qconsole = true;
|
||||
|
||||
tm new_time{};
|
||||
_time64(&aclock);
|
||||
_localtime64_s(&new_time, &aclock);
|
||||
|
||||
for (auto i = 0; i < 16; ++i) {
|
||||
const auto* file_name =
|
||||
(i == 0) ? "console.log"
|
||||
: utils::string::va("{0}.{1:03}", "console.log", i);
|
||||
game::I_strncpyz(log_file, file_name, sizeof(log_file));
|
||||
|
||||
if (!filesystem::file_rotate(log_file)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
*game::logfile = game::FS_FOpenTextFileWrite(log_file);
|
||||
if (*game::logfile) {
|
||||
game::Com_Printf(game::CON_CHANNEL_SYSTEM, "\'%s\'\n",
|
||||
game::Com_GetCommandLine());
|
||||
(void)asctime_s(time, sizeof(time), &new_time);
|
||||
game::Com_Printf(game::CON_CHANNEL_SYSTEM,
|
||||
"Build %s. Logfile opened on %s\n",
|
||||
branding::get_build_number(), time);
|
||||
break; // Stop attempting further backups
|
||||
}
|
||||
}
|
||||
|
||||
*game::opening_qconsole = false;
|
||||
*game::com_consoleLogOpenFailed = *game::logfile == 0;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
class component final : public component_interface {
|
||||
public:
|
||||
void post_load() override {
|
||||
utils::hook(0x603103, com_open_log_file_stub, HOOK_CALL)
|
||||
.install() // hook*
|
||||
->quick();
|
||||
}
|
||||
};
|
||||
} // namespace log_file
|
||||
|
||||
REGISTER_COMPONENT(log_file::component)
|
@ -55,6 +55,51 @@ void ui_replace_directive_stub(const int local_client_num,
|
||||
game::UI_ReplaceDirective(local_client_num, src_string, dst_string,
|
||||
dst_buffer_size);
|
||||
}
|
||||
|
||||
int g_parse_weapon_accuracy_graph_internal(char* string, const char* format,
|
||||
const char* dir_name,
|
||||
const char* graph_name) {
|
||||
return snprintf(string, 0x64, format, dir_name, graph_name);
|
||||
}
|
||||
|
||||
int scr_load_anim_tree_internal(char* string, const char* format,
|
||||
const char* file_name) {
|
||||
return snprintf(string, 0x64, format, file_name);
|
||||
}
|
||||
|
||||
// clang-format off
|
||||
void __declspec(naked) string_table_get_column_value_for_row() {
|
||||
static const char* fmt =
|
||||
"Looking up row %i, column %i of table \'%s\' results in an empty string "
|
||||
"(first column is %s, second column is %s for that row)\n";
|
||||
static const DWORD Com_PrintError = 0x4C6980;
|
||||
|
||||
// EAX is safe to reuse because it's nuked by the game's code after this stub exits
|
||||
__asm {
|
||||
// game's code
|
||||
mov eax, dword ptr [ecx + eax * 0x8]
|
||||
push edx
|
||||
push eax
|
||||
|
||||
mov eax, [esp + 0xC] // get table pointer
|
||||
mov eax, [eax] // get table->name
|
||||
push eax
|
||||
|
||||
// game's code
|
||||
push edi // column
|
||||
push ebx // row
|
||||
|
||||
push fmt
|
||||
|
||||
push 0xD // channel
|
||||
call Com_PrintError
|
||||
add esp, 0x1C
|
||||
|
||||
push 0x4BC84E
|
||||
ret
|
||||
}
|
||||
}
|
||||
// clang-format on
|
||||
} // namespace
|
||||
|
||||
class component final : public component_interface {
|
||||
@ -95,6 +140,19 @@ public:
|
||||
.install() // hook*
|
||||
->quick();
|
||||
|
||||
utils::hook(0x5DF16F, g_parse_weapon_accuracy_graph_internal, HOOK_CALL)
|
||||
.install() // hook*
|
||||
->quick();
|
||||
|
||||
utils::hook(0x609EAF, scr_load_anim_tree_internal, HOOK_CALL)
|
||||
.install() // hook*
|
||||
->quick();
|
||||
|
||||
// Fix crash in StringTable_GetColumnValueForRow
|
||||
utils::hook(0x4BC838, string_table_get_column_value_for_row, HOOK_JUMP)
|
||||
.install() // hook*
|
||||
->quick();
|
||||
|
||||
patch_sp();
|
||||
}
|
||||
|
||||
|
@ -30,29 +30,67 @@ void __declspec(naked) pm_step_slide_move_stub() {
|
||||
}
|
||||
}
|
||||
|
||||
void pm_project_velocity_stub(const float* vel_in, const float* normal,
|
||||
float* vel_out) {
|
||||
const auto length_squared_2d = vel_in[0] * vel_in[0] + vel_in[1] * vel_in[1];
|
||||
void __declspec(naked) pm_project_velocity_stub() {
|
||||
__asm {
|
||||
push eax;
|
||||
mov eax, dvars::pm_bouncesAllAngles;
|
||||
cmp byte ptr [eax + 0x10], 1;
|
||||
pop eax;
|
||||
|
||||
if (std::fabsf(normal[2]) < 0.001f || length_squared_2d == 0.0f) {
|
||||
vel_out[0] = vel_in[0];
|
||||
vel_out[1] = vel_in[1];
|
||||
vel_out[2] = vel_in[2];
|
||||
return;
|
||||
je force_bounce;
|
||||
|
||||
test ah, 0x5;
|
||||
jnp force_bounce;
|
||||
push 0x4761AF;
|
||||
ret;
|
||||
|
||||
force_bounce:
|
||||
push 0x4761CF;
|
||||
ret;
|
||||
}
|
||||
}
|
||||
|
||||
auto new_z = vel_in[0] * normal[0] + vel_in[1] * normal[1];
|
||||
new_z = -new_z / normal[2];
|
||||
void __declspec(naked) pm_project_velocity2_stub() {
|
||||
__asm {
|
||||
push eax;
|
||||
mov eax, dvars::pm_bouncesAllAngles;
|
||||
cmp byte ptr [eax + 0x10], 1;
|
||||
pop eax;
|
||||
|
||||
const auto length_scale =
|
||||
std::sqrtf((vel_in[2] * vel_in[2] + length_squared_2d) /
|
||||
(new_z * new_z + length_squared_2d));
|
||||
je force_bounce;
|
||||
|
||||
if (dvars::pm_bouncesAllAngles->current.enabled ||
|
||||
(length_scale < 1.f || new_z < 0.f || vel_in[2] > 0.f)) {
|
||||
vel_out[0] = vel_in[0] * length_scale;
|
||||
vel_out[1] = vel_in[1] * length_scale;
|
||||
vel_out[2] = new_z * length_scale;
|
||||
fld1;
|
||||
jmp go_back;
|
||||
|
||||
force_bounce:
|
||||
fldpi;
|
||||
|
||||
go_back:
|
||||
fld [esp + 0x14 + 0x8];
|
||||
push 0x4761A4;
|
||||
ret;
|
||||
}
|
||||
}
|
||||
|
||||
void __declspec(naked) pm_step_slide_move2_stub() {
|
||||
static float flt = 0.005f;
|
||||
__asm {
|
||||
push eax;
|
||||
mov eax, dvars::pm_bouncesAllAngles;
|
||||
cmp byte ptr [eax + 0x10], 1;
|
||||
pop eax;
|
||||
|
||||
je force_bounce;
|
||||
|
||||
fld ds:0x6D3AE4;
|
||||
jmp go_back;
|
||||
|
||||
force_bounce:
|
||||
fld flt;
|
||||
|
||||
go_back:
|
||||
push 0x4E9061;
|
||||
ret;
|
||||
}
|
||||
}
|
||||
|
||||
@ -116,6 +154,129 @@ void pm_crash_land_stub(const float* v, float scale, const float* result) {
|
||||
}
|
||||
}
|
||||
|
||||
void __declspec(naked) pm_accelerate_stub() {
|
||||
__asm {
|
||||
// Game's code
|
||||
sub esp, 0x20;
|
||||
|
||||
push eax;
|
||||
mov eax, dvars::pm_csStrafe;
|
||||
cmp byte ptr [eax + 0x10], 1;
|
||||
pop eax;
|
||||
|
||||
je attempt_to_force_movement;
|
||||
|
||||
// Game's code
|
||||
test byte ptr [esi + 0xC], 8;
|
||||
jnz movement;
|
||||
|
||||
go_back:
|
||||
push 0x64D87D;
|
||||
ret;
|
||||
|
||||
attempt_to_force_movement:
|
||||
test byte ptr [esi + 0xC], 8;
|
||||
je movement;
|
||||
jmp go_back;
|
||||
|
||||
movement:
|
||||
push 0x64D91A;
|
||||
ret;
|
||||
}
|
||||
}
|
||||
|
||||
void __declspec(naked) cm_is_edge_walkable_stub() {
|
||||
__asm {
|
||||
push eax;
|
||||
mov eax, dvars::pm_terrainEdgeBounces;
|
||||
cmp byte ptr [eax + 0x10], 1;
|
||||
pop eax;
|
||||
|
||||
je bounce;
|
||||
|
||||
// Game's code
|
||||
lea eax, [eax + ecx * 2];
|
||||
add eax, ecx;
|
||||
push 0x5FAED5;
|
||||
ret;
|
||||
|
||||
bounce:
|
||||
xor eax, eax;
|
||||
ret;
|
||||
}
|
||||
}
|
||||
|
||||
void __declspec(naked) cm_is_edge_walkable2_stub() {
|
||||
__asm {
|
||||
push eax;
|
||||
mov eax, dvars::pm_terrainEdgeBounces;
|
||||
cmp byte ptr [eax + 0x10], 1;
|
||||
pop eax;
|
||||
|
||||
je bounce;
|
||||
jmp go_back;
|
||||
|
||||
bounce:
|
||||
mov cl, 0;
|
||||
|
||||
go_back:
|
||||
pop ebp;
|
||||
mov byte ptr [edx + 0x2A], cl;
|
||||
pop ebx;
|
||||
add esp, 0x78;
|
||||
ret;
|
||||
}
|
||||
}
|
||||
|
||||
void __declspec(naked) pm_step_slide_move3_stub() {
|
||||
__asm {
|
||||
push eax;
|
||||
mov eax, dvars::pm_doubleBounces;
|
||||
cmp byte ptr [eax + 0x10], 1;
|
||||
pop eax;
|
||||
|
||||
je force_double_bounce;
|
||||
|
||||
test ah, 0x5;
|
||||
jp go_back;
|
||||
|
||||
force_double_bounce:
|
||||
push 0x4E904A;
|
||||
ret;
|
||||
|
||||
go_back:
|
||||
push 0x4E90C8;
|
||||
ret;
|
||||
}
|
||||
}
|
||||
|
||||
void __declspec(naked) pm_step_slide_move4_stub() {
|
||||
__asm {
|
||||
push eax;
|
||||
mov eax, dvars::pm_doubleBounces;
|
||||
cmp byte ptr [eax + 0x10], 1;
|
||||
pop eax;
|
||||
|
||||
// Code hook skipped
|
||||
add esp, 0xC;
|
||||
|
||||
je force_double_bounce;
|
||||
|
||||
push 0x4E8FB7;
|
||||
ret;
|
||||
|
||||
force_double_bounce:
|
||||
push 0x4E8FD0;
|
||||
ret;
|
||||
}
|
||||
}
|
||||
|
||||
void jump_clear_state_stub(game::playerState_s* ps) {
|
||||
if (!dvars::pm_doubleBounces->current.enabled) {
|
||||
game::Jump_ClearState(ps);
|
||||
}
|
||||
}
|
||||
|
||||
void __declspec(naked) jump_check_stub() {
|
||||
__asm {
|
||||
push eax;
|
||||
@ -184,9 +345,16 @@ public:
|
||||
utils::hook(0x4E9054, pm_step_slide_move_stub, HOOK_JUMP)
|
||||
.install()
|
||||
->quick(); // PM_StepSlideMove
|
||||
utils::hook(0x4E90BE, pm_project_velocity_stub, HOOK_CALL)
|
||||
|
||||
utils::hook(0x4761AA, pm_project_velocity_stub, HOOK_JUMP)
|
||||
.install()
|
||||
->quick(); // PM_StepSlideMove
|
||||
utils::hook(0x47619E, pm_project_velocity2_stub, HOOK_JUMP)
|
||||
.install()
|
||||
->quick(); // PM_StepSlideMove
|
||||
utils::hook(0x4E905B, pm_step_slide_move2_stub, HOOK_JUMP)
|
||||
.install()
|
||||
->quick();
|
||||
|
||||
utils::hook(0x4FA809, weapon_rocket_launcher_fire_stub, HOOK_CALL)
|
||||
.install()
|
||||
@ -209,10 +377,33 @@ public:
|
||||
.install()
|
||||
->quick(); // PM_CorrectAllSolid
|
||||
|
||||
// Double bounces
|
||||
utils::hook(0x4E9045, pm_step_slide_move3_stub, HOOK_JUMP)
|
||||
.install()
|
||||
->quick();
|
||||
utils::hook(0x4E8FAE, pm_step_slide_move4_stub, HOOK_JUMP)
|
||||
.install()
|
||||
->quick();
|
||||
utils::hook(0x651D80, jump_clear_state_stub, HOOK_CALL)
|
||||
.install()
|
||||
->quick(); // PM_GroundTrace
|
||||
|
||||
// Bunnny hop
|
||||
utils::hook(0x4D25E8, jump_check_stub, HOOK_JUMP).install()->quick();
|
||||
// Enable / Disable jump landing punishment within PM_CrashLand
|
||||
utils::hook(0x64E571, pm_crash_land_stub, HOOK_CALL)
|
||||
.install()
|
||||
->quick(); // Vec3Scale
|
||||
utils::hook(0x4D25E8, jump_check_stub, HOOK_JUMP).install()->quick();
|
||||
|
||||
utils::hook(0x64D870, pm_accelerate_stub, HOOK_JUMP).install()->quick();
|
||||
|
||||
// Implement terrain edge bounces
|
||||
utils::hook(0x5FAED0, cm_is_edge_walkable_stub, HOOK_JUMP)
|
||||
.install()
|
||||
->quick();
|
||||
utils::hook(0x5FBB14, cm_is_edge_walkable2_stub, HOOK_JUMP)
|
||||
.install()
|
||||
->quick();
|
||||
|
||||
utils::hook(0x6530C3, pm_move_single_stub, HOOK_JUMP).install()->quick();
|
||||
|
||||
@ -224,10 +415,14 @@ public:
|
||||
// clang-format off
|
||||
dvars::pm_bounces = game::Dvar_RegisterBool(
|
||||
"pm_bounces", false, game::DVAR_NONE, "CoD4 Bounces");
|
||||
dvars::pm_doubleBounces = game::Dvar_RegisterBool(
|
||||
"pm_doubleBounces", false, game::DVAR_NONE, "CoD4 Double Bounces");
|
||||
dvars::pm_bouncesAllAngles = game::Dvar_RegisterBool(
|
||||
"pm_bouncesAllAngles", false, game::DVAR_NONE, "Enable bouncing from all angles");
|
||||
dvars::pm_rocketJump = game::Dvar_RegisterBool(
|
||||
"pm_rocketJump", true, game::DVAR_NONE, "CoD4 rocket jumps");
|
||||
dvars::pm_csStrafe = game::Dvar_RegisterBool(
|
||||
"pm_csStrafe", false, game::DVAR_NONE, "Imitate CS Strafe movement");
|
||||
dvars::pm_rocketJumpScale = game::Dvar_RegisterFloat(
|
||||
"pm_rocketJumpScale", 64.0f, 0.0f, 1024.0f, game::DVAR_NONE, "");
|
||||
dvars::pm_playerCollision = game::Dvar_RegisterBool(
|
||||
@ -239,6 +434,8 @@ public:
|
||||
dvars::pm_bunnyHop = game::Dvar_RegisterBool("pm_bunnyHop",
|
||||
false, game::DVAR_NONE, "Constantly jump when holding space");
|
||||
dvars::pm_snapVector = game::Dvar_RegisterBool("pm_snapVector", false, game::DVAR_NONE, "Snap velocity");
|
||||
dvars::pm_terrainEdgeBounces = game::Dvar_RegisterBool(
|
||||
"pm_terrainEdgeBounces", false, game::DVAR_NONE, "Bounces on terrain edges");
|
||||
// clang-format on
|
||||
}
|
||||
};
|
||||
|
@ -4,14 +4,17 @@ namespace dvars {
|
||||
const game::dvar_t* r_noBorder = nullptr;
|
||||
|
||||
const game::dvar_t* pm_bounces = nullptr;
|
||||
const game::dvar_t* pm_doubleBounces = nullptr;
|
||||
const game::dvar_t* pm_bouncesAllAngles = nullptr;
|
||||
const game::dvar_t* pm_rocketJump = nullptr;
|
||||
const game::dvar_t* pm_csStrafe = nullptr;
|
||||
const game::dvar_t* pm_rocketJumpScale = nullptr;
|
||||
const game::dvar_t* pm_playerCollision = nullptr;
|
||||
const game::dvar_t* pm_elevators = nullptr;
|
||||
const game::dvar_t* pm_disableLandingSlowdown = nullptr;
|
||||
const game::dvar_t* pm_bunnyHop = nullptr;
|
||||
const game::dvar_t* pm_snapVector = nullptr;
|
||||
const game::dvar_t* pm_terrainEdgeBounces = nullptr;
|
||||
|
||||
const game::dvar_t* cg_drawVersion = nullptr;
|
||||
const game::dvar_t* cg_drawVersionX = nullptr;
|
||||
@ -36,6 +39,8 @@ const game::dvar_t** com_developer =
|
||||
const game::dvar_t** com_developer_script =
|
||||
reinterpret_cast<const game::dvar_t**>(0x145EC58);
|
||||
|
||||
const game::dvar_t** fs_homepath =
|
||||
reinterpret_cast<const game::dvar_t**>(0x195624C);
|
||||
const game::dvar_t** fs_gameDirVar =
|
||||
reinterpret_cast<const game::dvar_t**>(0x1956138);
|
||||
} // namespace dvars
|
||||
|
@ -4,14 +4,17 @@ namespace dvars {
|
||||
extern const game::dvar_t* r_noBorder;
|
||||
|
||||
extern const game::dvar_t* pm_bounces;
|
||||
extern const game::dvar_t* pm_doubleBounces;
|
||||
extern const game::dvar_t* pm_bouncesAllAngles;
|
||||
extern const game::dvar_t* pm_rocketJump;
|
||||
extern const game::dvar_t* pm_csStrafe;
|
||||
extern const game::dvar_t* pm_rocketJumpScale;
|
||||
extern const game::dvar_t* pm_playerCollision;
|
||||
extern const game::dvar_t* pm_elevators;
|
||||
extern const game::dvar_t* pm_disableLandingSlowdown;
|
||||
extern const game::dvar_t* pm_bunnyHop;
|
||||
extern const game::dvar_t* pm_snapVector;
|
||||
extern const game::dvar_t* pm_terrainEdgeBounces;
|
||||
|
||||
extern const game::dvar_t* cg_drawVersion;
|
||||
extern const game::dvar_t* cg_drawVersionX;
|
||||
@ -31,5 +34,6 @@ extern const game::dvar_t** version;
|
||||
extern const game::dvar_t** com_developer;
|
||||
extern const game::dvar_t** com_developer_script;
|
||||
|
||||
extern const game::dvar_t** fs_homepath;
|
||||
extern const game::dvar_t** fs_gameDirVar;
|
||||
} // namespace dvars
|
||||
|
@ -1,87 +0,0 @@
|
||||
#include <std_include.hpp>
|
||||
|
||||
#include "large_local.hpp"
|
||||
|
||||
namespace game::engine {
|
||||
namespace {
|
||||
constexpr auto PAGE_SIZE = 4096;
|
||||
|
||||
int can_use_server_large_local() { return Sys_IsServerThread(); }
|
||||
|
||||
void large_local_end(int start_pos) {
|
||||
assert(Sys_IsMainThread());
|
||||
assert(g_largeLocalBuf);
|
||||
|
||||
*g_largeLocalPos = start_pos;
|
||||
|
||||
assert(((*g_maxLargeLocalPos + (PAGE_SIZE - 1)) & ~(PAGE_SIZE - 1)) <=
|
||||
(*g_minLargeLocalRightPos & ~(PAGE_SIZE - 1)));
|
||||
}
|
||||
|
||||
void large_local_end_right(int start_pos) {
|
||||
assert(can_use_server_large_local());
|
||||
assert(g_largeLocalBuf);
|
||||
|
||||
*g_largeLocalRightPos = start_pos;
|
||||
|
||||
assert(((*g_maxLargeLocalPos + (PAGE_SIZE - 1)) & ~(PAGE_SIZE - 1)) <=
|
||||
(*g_minLargeLocalRightPos & ~(PAGE_SIZE - 1)));
|
||||
}
|
||||
|
||||
void* large_local_get_buf(int start_pos, int size) {
|
||||
assert(Sys_IsMainThread() || can_use_server_large_local());
|
||||
assert(g_largeLocalBuf);
|
||||
assert(!(size & 127));
|
||||
|
||||
if (Sys_IsMainThread()) {
|
||||
return &g_largeLocalBuf[start_pos];
|
||||
}
|
||||
|
||||
const auto start_index = start_pos - size;
|
||||
assert(start_index >= 0);
|
||||
|
||||
return &g_largeLocalBuf[start_index];
|
||||
}
|
||||
} // namespace
|
||||
|
||||
large_local::large_local(int size_param) {
|
||||
assert(size_param);
|
||||
assert(Sys_IsMainThread() || can_use_server_large_local());
|
||||
|
||||
size_param = ((size_param + (128 - 1)) & ~(128 - 1));
|
||||
|
||||
if (Sys_IsMainThread()) {
|
||||
this->start_pos_ = LargeLocalBegin(size_param);
|
||||
} else {
|
||||
this->start_pos_ = LargeLocalBeginRight(size_param);
|
||||
}
|
||||
|
||||
this->size_ = size_param;
|
||||
}
|
||||
|
||||
large_local::~large_local() {
|
||||
if (this->size_) {
|
||||
this->pop_buf();
|
||||
}
|
||||
}
|
||||
|
||||
void large_local::pop_buf() {
|
||||
assert(this->size_);
|
||||
assert(Sys_IsMainThread() || can_use_server_large_local());
|
||||
|
||||
if (Sys_IsMainThread()) {
|
||||
large_local_end(this->start_pos_);
|
||||
} else {
|
||||
large_local_end_right(this->start_pos_);
|
||||
}
|
||||
|
||||
this->size_ = 0;
|
||||
}
|
||||
|
||||
void* large_local::get_buf() const {
|
||||
assert(this->size_);
|
||||
assert(Sys_IsMainThread() || can_use_server_large_local());
|
||||
|
||||
return large_local_get_buf(this->start_pos_, this->size_);
|
||||
}
|
||||
} // namespace game::engine
|
@ -1,22 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
namespace game::engine {
|
||||
class large_local {
|
||||
public:
|
||||
explicit large_local(int size_param);
|
||||
~large_local();
|
||||
|
||||
large_local(large_local&&) = delete;
|
||||
large_local(const large_local&) = delete;
|
||||
large_local& operator=(large_local&&) = delete;
|
||||
large_local& operator=(const large_local&) = delete;
|
||||
|
||||
[[nodiscard]] void* get_buf() const;
|
||||
|
||||
private:
|
||||
void pop_buf();
|
||||
|
||||
int start_pos_;
|
||||
int size_;
|
||||
};
|
||||
} // namespace game::engine
|
@ -141,4 +141,6 @@ void Menu_FreeItemMemory(itemDef_s* item) {
|
||||
popad;
|
||||
}
|
||||
}
|
||||
|
||||
char* Com_GetCommandLine() { return reinterpret_cast<char*>(0x145D800); }
|
||||
} // namespace game
|
||||
|
@ -47,6 +47,8 @@ int PC_Float_Parse(int handle, float* f);
|
||||
|
||||
void Menu_FreeItemMemory(itemDef_s* item);
|
||||
|
||||
char* Com_GetCommandLine();
|
||||
|
||||
// Global definitions
|
||||
constexpr auto CMD_MAX_NESTING = 8;
|
||||
|
||||
|
@ -15,6 +15,13 @@ enum LocalClientNum_t {
|
||||
LOCAL_CLIENT_COUNT = 1,
|
||||
};
|
||||
|
||||
enum ControllerIndex_t {
|
||||
INVALID_CONTROLLER_PORT = -1,
|
||||
CONTROLLER_INDEX_0 = 0x0,
|
||||
CONTROLLER_INDEX_FIRST = 0x0,
|
||||
CONTROLLER_INDEX_COUNT = 0x1,
|
||||
};
|
||||
|
||||
struct scr_entref_t {
|
||||
unsigned __int16 entnum;
|
||||
unsigned __int16 classnum;
|
||||
|
@ -221,6 +221,7 @@ WEAK symbol<void(const char* base, const char* game, const char* qpath,
|
||||
char* ospath)>
|
||||
FS_BuildOSPath{0x4E48F0};
|
||||
WEAK symbol<void(const char* gameName)> FS_Startup{0x47AF20};
|
||||
WEAK symbol<int(const char* filename)> FS_FOpenTextFileWrite{0x4495F0};
|
||||
|
||||
// UI
|
||||
WEAK symbol<Font_s*(const ScreenPlacement* scrPlace, int fontEnum, float scale)>
|
||||
@ -257,6 +258,7 @@ WEAK symbol<void(pmove_t* pm, trace_t* results, const float* start,
|
||||
int contentMask)>
|
||||
PM_playerTrace{0x447B90};
|
||||
WEAK symbol<bool(const playerState_s* ps)> PM_IsSprinting{0x47CF70};
|
||||
WEAK symbol<void(playerState_s* ps)> Jump_ClearState{0x435A40};
|
||||
|
||||
// Live
|
||||
WEAK symbol<const char*(int controllerIndex)> Live_GetLocalClientName{0x492EF0};
|
||||
@ -278,12 +280,12 @@ WEAK symbol<int(const char* string)> StringTable_HashString{0x498080};
|
||||
// Vec3
|
||||
WEAK symbol<void(const float* v, float scale, const float* result)> Vec3Scale{
|
||||
0x429220};
|
||||
|
||||
// Renderer
|
||||
WEAK symbol<void(const char* text, int maxChars, Font_s* font, float x, float y,
|
||||
float xScale, float yScale, float rotation, const float* color,
|
||||
int style)>
|
||||
R_AddCmdDrawText{0x50E7A0};
|
||||
|
||||
// Renderer
|
||||
WEAK symbol<int(const char* text, int maxChars, Font_s* font)> R_TextWidth{
|
||||
0x508960};
|
||||
|
||||
@ -312,11 +314,12 @@ WEAK symbol<int> g_minLargeLocalRightPos{0x195AB00};
|
||||
|
||||
WEAK symbol<unsigned long> g_dwTlsIndex{0x1BFC750};
|
||||
|
||||
WEAK symbol<int> com_frameTime{0x145EC7C};
|
||||
|
||||
WEAK symbol<bool> cin_skippable{0x73264C};
|
||||
|
||||
WEAK symbol<int> com_frameTime{0x145EC7C};
|
||||
WEAK symbol<int> com_fixedConsolePosition{0x145EC10};
|
||||
WEAK symbol<int> opening_qconsole{0x145ECD4};
|
||||
WEAK symbol<int> com_consoleLogOpenFailed{0x145ECB0};
|
||||
|
||||
WEAK symbol<field_t> g_consoleField{0x88C700};
|
||||
WEAK symbol<ConDrawInputGlob> conDrawInputGlob{0x86E788};
|
||||
@ -342,5 +345,5 @@ WEAK symbol<void*> DB_GetXAssetSizeHandlers{0x733408};
|
||||
WEAK symbol<void*> DB_XAssetPool{0x7337F8};
|
||||
WEAK symbol<unsigned int> g_poolSize{0x733510};
|
||||
|
||||
WEAK symbol<localization_t> localization{0x19ff820};
|
||||
WEAK symbol<localization_t> localization{0x19FF820};
|
||||
} // namespace game
|
||||
|
@ -10,21 +10,33 @@
|
||||
#define SP_XLABS_HASH \
|
||||
"05D499D77028859D4BA30C852DA85CCA5F02678B22AEA9E27D7C56973B14A0BC"
|
||||
|
||||
#define SP_ALTER_HASH \
|
||||
"9480909B18CF5A4EC483C989AAFCE929D2172C5F9448F8C23B723683D1A43565"
|
||||
|
||||
namespace binary_loader {
|
||||
namespace {
|
||||
std::string load_base() {
|
||||
std::string path = "iw4sp.exe";
|
||||
|
||||
if (utils::io::file_exists("data/iw4sp.exe")) {
|
||||
path = "data/iw4sp.exe";
|
||||
}
|
||||
|
||||
std::string data;
|
||||
if (!utils::io::read_file("iw4sp.exe", &data)) {
|
||||
if (!utils::io::read_file(path, &data)) {
|
||||
throw std::runtime_error("Failed to read game binary (iw4sp.exe)!");
|
||||
}
|
||||
|
||||
const auto hash = utils::cryptography::sha256::compute(data, true);
|
||||
if ((hash != SP_XLABS_HASH) && (hash != SP_HASH)) {
|
||||
if ((hash != SP_ALTER_HASH) && (hash != SP_HASH)) {
|
||||
throw std::runtime_error(
|
||||
"Your iw4sp.exe is incompatible with this client.");
|
||||
"Your iw4sp.exe is incompatible with this client. Please use the "
|
||||
"AlterWare launcher to install IW4x-SP");
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
std::string load() { return load_base(); }
|
||||
} // namespace binary_loader
|
||||
|
20
src/common/utils/properties.cpp
Normal file
20
src/common/utils/properties.cpp
Normal file
@ -0,0 +1,20 @@
|
||||
#include "properties.hpp"
|
||||
|
||||
#include <gsl/gsl>
|
||||
|
||||
#include <ShlObj.h>
|
||||
|
||||
namespace utils::properties {
|
||||
std::filesystem::path get_appdata_path() {
|
||||
PWSTR path;
|
||||
if (!SUCCEEDED(
|
||||
SHGetKnownFolderPath(FOLDERID_LocalAppData, 0, nullptr, &path))) {
|
||||
throw std::runtime_error("Failed to read APPDATA path!");
|
||||
}
|
||||
|
||||
auto _ = gsl::finally([&path] { CoTaskMemFree(path); });
|
||||
|
||||
static auto appdata = std::filesystem::path(path) / "alterware";
|
||||
return appdata;
|
||||
}
|
||||
} // namespace utils::properties
|
6
src/common/utils/properties.hpp
Normal file
6
src/common/utils/properties.hpp
Normal file
@ -0,0 +1,6 @@
|
||||
#pragma once
|
||||
#include <filesystem>
|
||||
|
||||
namespace utils::properties {
|
||||
std::filesystem::path get_appdata_path();
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user