maint: April update

This commit is contained in:
6arelyFuture 2024-04-26 10:59:05 +02:00
parent ce6b6f4112
commit 89a735326d
43 changed files with 375 additions and 87 deletions

View File

@ -1,14 +1,17 @@
# IW4: SP Client
# IW4x-SP: A Modded SP Client
This is a client modification for IW4 (Singleplayer) 159
**NOTE**: You must legally own Call of Duty®: Modern Warfare® 2 (2009) to run this mod. Cracked/Pirated versions of the game are **NOT** supported.
## How to compile
## Build
- Install [Visual Studio 2022][vs-link] and enable `Desktop development with C++`
- Install [Premake5][premake5-link] and add it to your system PATH
- Clone this repository using [Git][git-link]
- Update the submodules using ``git submodule update --init --recursive``
- Run Premake with the option ``premake5 vs2022`` (Visual Studio 2022). No other build systems are supported.
- Build project via solution file in `build\iw4x-sp.sln`.
This project requires [Git](https://git-scm.com), [Premake5](https://premake.github.io), and [MSVC](https://visualstudio.microsoft.com/vs/features/cplusplus) to build.
- Run `premake5 vs2022` or use the delivered `generate.bat`.
- Build via solution file found in `build\iw4-sp.sln`.
Only the Win32 platform is supported. Do not attempt to build for Windows ARM 64 or x64.
## Premake arguments
@ -20,9 +23,14 @@ This project requires [Git](https://git-scm.com), [Premake5](https://premake.git
Contributions are welcome! Please follow the guidelines below:
- Sign [AlterWare CLA](https://alterware.dev/cla) and send a pull request or email your patch at patches@alterware.dev
- Sign [AlterWare CLA][cla-link] and send a pull request or email your patch at patches@alterware.dev
- Make sure that PRs have only one commit, and deal with one issue only
## Disclaimer
This software has been created purely for the purposes of academic research. It is not intended to be used to attack other systems. Project maintainers are not responsible or liable for misuse of the software. Use responsibly.
[premake5-link]: https://premake.github.io
[git-link]: https://git-scm.com
[vs-link]: https://visualstudio.microsoft.com/vs
[cla-link]: https://alterware.dev/cla

2
deps/libtomcrypt vendored

@ -1 +1 @@
Subproject commit 7e863d21429f94ed6a720e24499a12a3f852bb31
Subproject commit f7e6519fae1e11ff5ff9d36c84101a673002133b

2
deps/libtommath vendored

@ -1 +1 @@
Subproject commit 8314bde5e5c8e5d9331460130a9d1066e324f091
Subproject commit 5809141a3a6ec1bf3443c927c02b955e19224016

2
deps/minhook vendored

@ -1 +1 @@
Subproject commit f5485b8454544c2f034c78f8f127c1d03dea3636
Subproject commit 1cc46107ee522d7a5c73656c519ca16addf2c23a

2
deps/rapidjson vendored

@ -1 +1 @@
Subproject commit 6089180ecb704cb2b136777798fa1be303618975
Subproject commit ab1842a2dae061284c0a62dca1cc6d5e7e37e346

2
deps/zlib vendored

@ -1 +1 @@
Subproject commit 643e17b7498d12ab8d15565662880579692f769d
Subproject commit 0f51fb4933fc9ce18199cb2554dacea8033e7fd3

View File

@ -214,7 +214,7 @@ newaction {
dependencies.load()
workspace "iw4-sp"
workspace "iw4x-sp"
startproject "client"
location "./build"
objdir "%{wks.location}/obj"
@ -288,7 +288,9 @@ project "client"
kind "WindowedApp"
language "C++"
targetname "iw4-sp"
targetname "iw4x-sp"
dependson {"tlsdll", "runner"}
pchheader "std_include.hpp"
pchsource "src/client/std_include.cpp"
@ -303,7 +305,7 @@ resincludedirs {"$(ProjectDir)src"}
links {"common"}
prebuildcommands {"pushd %{_MAIN_SCRIPT_DIR}", "tools\\premake5 generate-buildinfo", "popd"}
prebuildcommands {"pushd %{_MAIN_SCRIPT_DIR}", "premake5 generate-buildinfo", "popd"}
if _OPTIONS["copy-to"] then
postbuildcommands {

View File

@ -17,7 +17,7 @@ void load_map_entities(game::MapEnts* entry) {
// Load ent file from raw if it exists
if (ent_file.exists()) {
map_entities = ent_file.get_buffer();
entry->entityString = map_entities.data();
entry->entityString = const_cast<char*>(map_entities.c_str());
entry->numEntityChars = static_cast<int>(map_entities.size()) + 1;
}
}

View File

@ -20,7 +20,7 @@ std::string get_hw_profile_guid() {
}
std::string get_protected_data() {
std::string input = "Alter-Ware-IW4-SP-Auth";
std::string input = "Alter-Ware-IW4x-SP-Auth";
DATA_BLOB data_in{}, data_out{};
data_in.pbData = reinterpret_cast<std::uint8_t*>(input.data());

View File

@ -2,17 +2,19 @@
#include "loader/component_loader.hpp"
#include "game/dvars.hpp"
#include "scheduler.hpp"
#include <utils/hook.hpp>
#include <utils/string.hpp>
#include <version.h>
#include <version.hpp>
namespace branding {
namespace {
#ifdef _DEBUG
constexpr auto* BUILD_TYPE = "IW4_DEV SP";
constexpr auto* BUILD_TYPE = "IW4x_DEV SP";
#else
constexpr auto* BUILD_TYPE = "IW4 SP";
constexpr auto* BUILD_TYPE = "IW4x SP";
#endif
constexpr const char* get_build_number() {
@ -49,14 +51,13 @@ void cg_draw_version() {
font, font_scale);
const auto height = game::UI_TextHeight(font, font_scale);
// clang-format off
game::UI_DrawText(placement, (*dvars::version)->current.string, max_chars,
font,
1.0f - (dvars::cg_drawVersionX->current.value +
static_cast<float>(width)),
1.0f - (dvars::cg_drawVersionY->current.value +
static_cast<float>(height)),
3, 3, font_scale, shadow_color, 0);
game::UI_DrawText(
placement, (*dvars::version)->current.string, max_chars, font,
1.0f -
(dvars::cg_drawVersionX->current.value + static_cast<float>(width)),
1.0f -
(dvars::cg_drawVersionY->current.value + static_cast<float>(height)),
3, 3, font_scale, shadow_color, 0);
game::UI_DrawText(placement, (*dvars::version)->current.string, max_chars,
font,
(0.0f - static_cast<float>(width)) -
@ -64,7 +65,6 @@ void cg_draw_version() {
(0.0f - static_cast<float>(height)) -
dvars::cg_drawVersionY->current.value,
3, 3, font_scale, color, 0);
// clang-format on
}
void cg_draw_full_screen_debug_overlays_stub(int local_client_num) {
@ -76,6 +76,25 @@ void cg_draw_full_screen_debug_overlays_stub(int local_client_num) {
utils::hook::invoke<void>(0x44BD00, local_client_num);
}
game::Font_s** small_font;
void branding_loop() {
float color[4] = {1.0f, 1.0f, 1.0f, 0.25f};
const auto* text = "AlterWare IW4x-SP";
if (!*small_font) {
return;
}
auto* const scr_place =
game::ScrPlace_GetActivePlacement(game::LOCAL_CLIENT_0);
const auto x = scr_place->realViewportSize[0] -
static_cast<float>(game::R_TextWidth(text, 0, *small_font)) -
10.0f;
game::R_AddCmdDrawText(text, std::numeric_limits<int>::max(), *small_font, x,
30.0f, 1.0f, 1.0f, 0.0f, color, 3);
}
} // namespace
class component final : public component_interface {
@ -83,13 +102,13 @@ public:
void post_load() override {
utils::hook(0x46F570, get_build_number, HOOK_JUMP).install()->quick();
utils::hook(0x60429A, dvar_set_version_string, HOOK_CALL)
.install()
.install() // hook*
->quick();
utils::hook::set<const char*>(0x446A48, "iw4-sp: Console");
utils::hook::set<const char*>(0x50C110, "iw4-sp: Game");
utils::hook::set<const char*>(0x446A48, "iw4x-sp: Console");
utils::hook::set<const char*>(0x50C110, "iw4x-sp: Game");
utils::hook::set<const char*>(0x579364, "iw4-sp: " SHORTVERSION "> ");
utils::hook::set<const char*>(0x579364, "iw4x-sp: " SHORTVERSION "> ");
// Com_Init_Try_Block_Function
utils::hook::set<const char*>(0x604004, BUILD_TYPE);
@ -100,6 +119,9 @@ public:
utils::hook(0x57DAFF, cg_draw_full_screen_debug_overlays_stub, HOOK_CALL)
.install() // hook*
->quick();
small_font = reinterpret_cast<game::Font_s**>(0x192A0DC);
scheduler::loop(branding_loop, scheduler::pipeline::renderer);
}
static void register_branding_dvars() {

View File

@ -130,9 +130,9 @@ void execute(std::string command, const bool sync) {
command += "\n";
if (sync) {
game::Cmd_ExecuteSingleCommand(0, 0, command.data());
game::Cmd_ExecuteSingleCommand(0, 0, command.c_str());
} else {
game::Cbuf_AddText(0, command.data());
game::Cbuf_AddText(0, command.c_str());
}
}

View File

@ -41,9 +41,9 @@ void com_bug_f(const command::params& params) {
*game::logfile = 0;
}
game::FS_BuildOSPath(std::filesystem::current_path().string().data(), "",
game::FS_BuildOSPath(std::filesystem::current_path().string().c_str(), "",
"console.log", from_ospath);
game::FS_BuildOSPath(std::filesystem::current_path().string().data(), "",
game::FS_BuildOSPath(std::filesystem::current_path().string().c_str(), "",
new_file_name, to_ospath);
const auto result = CopyFileA(from_ospath, to_ospath, 0);
game::Com_OpenLogFile();

View File

@ -142,7 +142,7 @@ const game::dvar_t* dvar_register_string_stub(const char* name,
const char* description) {
auto* var = find_dvar(override::register_string_overrides, name);
if (var) {
value = var->value.data();
value = var->value.c_str();
flags = var->flags;
}

View File

@ -0,0 +1,110 @@
#include <std_include.hpp>
#include "loader/component_loader.hpp"
#include "game/dvars.hpp"
#include <utils/hook.hpp>
namespace fastfile {
namespace {
bool is_using_mods() {
return (*dvars::fs_gameDirVar) && *(*dvars::fs_gameDirVar)->current.string;
}
void db_build_os_path_from_source(const char* zone_name, game::FF_DIR source,
unsigned int size, char* filename) {
char user_map[game::MAX_QPATH]{};
switch (source) {
case game::FFD_DEFAULT:
(void)sprintf_s(filename, size, "%s\\%s%s.ff",
std::filesystem::current_path().string().c_str(),
game::Sys_GetMapZoneDir(zone_name), zone_name);
break;
case game::FFD_MOD_DIR:
assert(is_using_mods());
(void)sprintf_s(filename, size, "%s\\%s\\%s.ff",
std::filesystem::current_path().string().c_str(),
(*dvars::fs_gameDirVar)->current.string, zone_name);
break;
case game::FFD_USER_MAP:
game::I_strncpyz(user_map, zone_name, sizeof(user_map));
(void)sprintf_s(filename, size, "%s\\%s\\%s\\%s.ff",
std::filesystem::current_path().string().c_str(),
"usermaps", user_map, zone_name);
break;
default:
assert(false && "inconceivable");
break;
}
}
bool db_mod_file_exists() {
if (!*(*dvars::fs_gameDirVar)->current.string)
return false;
char filename[game::MAX_OSPATH]{};
db_build_os_path_from_source("mod", game::FFD_MOD_DIR, sizeof(filename),
filename);
if (auto zone_file = game::Sys_OpenFileReliable(filename);
zone_file != INVALID_HANDLE_VALUE) {
CloseHandle(zone_file);
return true;
}
return false;
}
void db_load_x_assets_stub(game::XZoneInfo* zone_info, unsigned int zone_count,
int sync_mode) {
std::vector<game::XZoneInfo> zones(zone_info, zone_info + zone_count);
if (db_mod_file_exists()) {
zones.emplace_back("mod", game::DB_ZONE_COMMON, 0);
}
game::DB_LoadXAssets(zones.data(), zones.size(), sync_mode);
}
game::Sys_File sys_create_file_stub(const char* dir, const char* filename) {
auto result = game::Sys_CreateFile(dir, filename);
if (result.handle != INVALID_HANDLE_VALUE) {
return result;
}
if (!is_using_mods()) {
return result;
}
// .ff extension was added previously
if (!game::I_stricmp(filename, "mod.ff") && db_mod_file_exists()) {
char file_path[game::MAX_OSPATH]{};
db_build_os_path_from_source("mod", game::FFD_MOD_DIR, sizeof(file_path),
file_path);
result.handle = game::Sys_OpenFileReliable(file_path);
}
return result;
}
} // namespace
class component final : public component_interface {
public:
static_assert(sizeof(game::Sys_File) == 4);
void post_load() override {
utils::hook(0x50B637, db_load_x_assets_stub, HOOK_CALL)
.install() // hook*
->quick();
utils::hook(0x582FA2, sys_create_file_stub, HOOK_CALL)
.install() // hook*
->quick();
}
};
} // namespace fastfile
REGISTER_COMPONENT(fastfile::component)

View File

@ -11,7 +11,7 @@ namespace filesystem {
namespace {
const char* sys_default_install_path_stub() {
static auto current_path = std::filesystem::current_path().string();
return current_path.data();
return current_path.c_str();
}
} // namespace
@ -20,7 +20,7 @@ std::vector<std::string> vectored_file_list(const std::string& path,
std::vector<std::string> file_list;
auto num_files = 0;
const auto** files = game::FS_ListFiles(path.data(), extension.data(),
const auto** files = game::FS_ListFiles(path.c_str(), extension.c_str(),
game::FS_LIST_ALL, &num_files, 10);
if (files) {
@ -46,7 +46,7 @@ file::file(std::string name, game::FsThread thread) : name_(std::move(name)) {
auto handle = 0;
const auto len =
game::FS_FOpenFileReadForThread(name_.data(), &handle, thread);
game::FS_FOpenFileReadForThread(name_.c_str(), &handle, thread);
if (!handle) {
this->valid_ = false;
@ -73,7 +73,7 @@ class component final : public component_interface {
public:
void post_load() override {
utils::hook(0x465B90, sys_default_install_path_stub, HOOK_CALL)
.install()
.install() // hook*
->quick(); // Sys_CreateFile
}
};

View File

@ -37,7 +37,7 @@ void g_scr_log_print() {
void g_init_game_stub() {
game::Com_Printf(game::CON_CHANNEL_SERVER,
"------- Game Initialization -------\n");
game::Com_Printf(game::CON_CHANNEL_SERVER, "gamename: iw4-sp\n");
game::Com_Printf(game::CON_CHANNEL_SERVER, "gamename: iw4x-sp\n");
game::Com_Printf(game::CON_CHANNEL_SERVER, "gamedate: %s\n", __DATE__);
if (*dvars::g_log->current.string == '\0') {

View File

@ -34,7 +34,7 @@ game::BuiltinFunction built_in_get_function_stub(const char** p_name,
} else {
for (const auto& [name, func] : custom_scr_funcs) {
game::Scr_RegisterFunction(reinterpret_cast<int>(func.actionFunc),
name.data());
name.c_str());
}
}
@ -52,7 +52,7 @@ game::BuiltinMethod built_in_get_method_stub(const char** p_name, int* type) {
} else {
for (const auto& [name, meth] : custom_scr_meths) {
game::Scr_RegisterFunction(reinterpret_cast<int>(meth.actionFunc),
name.data());
name.c_str());
}
}

View File

@ -1,5 +1,6 @@
#include <std_include.hpp>
#include "loader/component_loader.hpp"
#include "game/dvars.hpp"
#include <utils/hook.hpp>
#include <utils/string.hpp>
@ -10,23 +11,27 @@ std::vector<int> main_handles;
std::vector<int> init_handles;
// Do not use C++ objects because Scr_LoadScript may longjmp
void g_scr_load_scripts_stub() {
// Clear handles (from previous GSC loading session)
main_handles.clear();
init_handles.clear();
void load_scripts_from_folder(const char* dir) {
char path[MAX_PATH]{};
char search_path[MAX_PATH]{};
game::Com_Printf(game::CON_CHANNEL_SERVER,
"Scanning directory '%s' for custom GSC scripts...\n", dir);
strncpy_s(search_path, dir, _TRUNCATE);
strncat_s(search_path, "/", _TRUNCATE);
auto num_files = 0;
const auto** files =
game::FS_ListFiles("scripts/", "gsc", game::FS_LIST_ALL, &num_files, 10);
game::FS_ListFiles(search_path, "gsc", game::FS_LIST_ALL, &num_files, 10);
for (auto i = 0; i < num_files; ++i) {
const auto* script_file = files[i];
game::Com_Printf(game::CON_CHANNEL_SERVER, "Loading script %s...\n",
script_file);
const auto len = sprintf_s(path, "%s/%s", "scripts", script_file);
const auto len = sprintf_s(path, "%s/%s", dir, script_file);
if (len == -1) {
continue;
}
@ -36,12 +41,13 @@ void g_scr_load_scripts_stub() {
if (!game::Scr_LoadScript(path)) {
game::Com_Printf(game::CON_CHANNEL_SERVER,
"Script %s encountered an error while loading\n", path);
"Script '%s.gsc' encountered an error while loading\n",
path);
continue;
}
game::Com_Printf(game::CON_CHANNEL_SERVER,
"Script %s.gsc loaded successfully\n", path);
"Script '%s.gsc' loaded successfully\n", path);
const auto main_handle = game::Scr_GetFunctionHandle(path, "main");
if (main_handle) {
@ -58,6 +64,21 @@ void g_scr_load_scripts_stub() {
game::FS_FreeFileList(files, 10);
}
void g_scr_load_scripts_stub() {
// Clear handles (from previous GSC loading session)
main_handles.clear();
init_handles.clear();
load_scripts_from_folder("scripts");
load_scripts_from_folder("scripts/sp");
// Map specific
const auto* dir =
utils::string::va("scripts/sp/{0}", (*dvars::sv_mapname)->current.string);
load_scripts_from_folder(dir);
}
void scr_load_level_stub() {
for (const auto& handle : main_handles) {
const auto id = game::Scr_ExecThread(handle, 0);

View File

@ -29,6 +29,8 @@ void cl_start_multiplayer_f() {
const char* live_get_local_client_name_stub() {
return game::Dvar_FindVar("name")->current.string;
}
bool g_exit_after_tool_complete_stub() { return false; }
} // namespace
class component final : public component_interface {
@ -36,8 +38,24 @@ public:
void post_load() override {
utils::hook(0x6042A2, sys_init_stub, HOOK_CALL).install()->quick();
utils::hook(0x6216CC, g_exit_after_tool_complete_stub, HOOK_CALL)
.install() // hook*
->quick(); // UI_LoadMenuLists
utils::hook(0x4E638C, g_exit_after_tool_complete_stub, HOOK_CALL)
.install() // hook*
->quick(); // Vehicle_Create
utils::hook(0x65F54A, g_exit_after_tool_complete_stub, HOOK_CALL)
.install() // hook*
->quick(); // ??
utils::hook(0x425F6F, g_exit_after_tool_complete_stub, HOOK_CALL)
.install() // hook*
->quick(); // ??
utils::hook(0x663845, g_exit_after_tool_complete_stub, HOOK_CALL)
.install() // hook*
->quick(); // ??
utils::hook(0x492EF0, live_get_local_client_name_stub, HOOK_JUMP)
.install()
.install() // hook*
->quick();
patch_sp();

View File

@ -136,7 +136,8 @@ void __declspec(naked) jump_check_stub() {
}
}
void __declspec(naked) p_move_single_stub() {
// clang-format off
void __declspec(naked) pm_move_single_stub() {
__asm {
push eax;
mov eax, dvars::pm_snapVector;
@ -161,6 +162,7 @@ void __declspec(naked) p_move_single_stub() {
ret;
}
}
// clang-format on
void g_scr_is_sprinting(const game::scr_entref_t entref) {
const auto* client = game::GetEntity(entref)->client;
@ -212,7 +214,7 @@ public:
->quick(); // Vec3Scale
utils::hook(0x4D25E8, jump_check_stub, HOOK_JUMP).install()->quick();
utils::hook(0x6530C3, p_move_single_stub, HOOK_JUMP).install()->quick();
utils::hook(0x6530C3, pm_move_single_stub, HOOK_JUMP).install()->quick();
gsc::add_method("IsSprinting", g_scr_is_sprinting);
register_dvars();

View File

@ -87,9 +87,9 @@ void g_glass_update_stub() {
execute(pipeline::server);
}
void r_end_frame_stub() {
utils::hook::invoke<void>(0x50F540);
void ui_refresh_full_screen_stub(const int local_client_num) {
execute(pipeline::renderer);
utils::hook::invoke<void>(0x4EF430, local_client_num);
}
void main_frame_stub() {
@ -148,7 +148,9 @@ public:
void post_load() override {
utils::hook(0x4EDBDD, g_glass_update_stub, HOOK_CALL).install()->quick();
utils::hook(0x49C3AF, main_frame_stub, HOOK_CALL).install()->quick();
utils::hook(0x57DB13, r_end_frame_stub, HOOK_CALL).install()->quick();
utils::hook(0x57DAEC, ui_refresh_full_screen_stub, HOOK_CALL)
.install() // hook*
->quick();
}
void pre_destroy() override {

View File

@ -33,9 +33,10 @@ public:
static void patch_sp() {
// Prevent stat loading from steam
utils::hook::set<std::uint8_t>(0x43FB33, 0xC3);
utils::hook::nop(0x43FB33 + 1, 0x5);
// Steam must be running
utils::hook::nop(0x6040A3, 30);
utils::hook::set<std::uint8_t>(0x6040A1, 0xEB);
// No-Steam
utils::hook::nop(0x4E9458, 7);

View File

@ -23,7 +23,7 @@ public:
this->clean_up_on_error();
try {
this->start_mod("iw4-sp singleplayer", 10180);
this->start_mod("iw4x-sp singleplayer", 10180);
} catch (const std::exception& ex) {
printf("Steam: %s\n", ex.what());
}

View File

@ -36,8 +36,15 @@ private:
// Ignore missing default weapon
utils::hook::set<std::uint8_t>(0x659DBE, 0xEB);
// Skip double loading when fs_game is set
utils::hook::set<std::uint8_t>(0x43E1AD, 0xEB);
// Clear weapons even if fs_game is set
utils::hook::nop(0x4C3FBF, 2); // BG_ClearWeaponDefInterna
utils::hook::nop(0x4C3FC6, 5); // Disable BG_FreeWeaponDefStrings
utils::hook(0x659E00, bg_load_weapon_variant_def_fast_file_stub, HOOK_JUMP)
.install()
.install() // hook*
->quick();
// Disable warning if raw weapon file cannot be found
utils::hook::nop(0x659730, 5);

View File

@ -35,4 +35,7 @@ const game::dvar_t** com_developer =
reinterpret_cast<const game::dvar_t**>(0x145D648);
const game::dvar_t** com_developer_script =
reinterpret_cast<const game::dvar_t**>(0x145EC58);
const game::dvar_t** fs_gameDirVar =
reinterpret_cast<const game::dvar_t**>(0x1956138);
} // namespace dvars

View File

@ -30,4 +30,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_gameDirVar;
} // namespace dvars

View File

@ -87,6 +87,12 @@ void Sys_SnapVector(float* v) {
v[2] = std::floorf(v[2] + 0.5f);
}
HANDLE Sys_OpenFileReliable(const char* filename) {
return ::CreateFileA(filename, GENERIC_READ, FILE_SHARE_READ, nullptr,
OPEN_EXISTING,
FILE_FLAG_OVERLAPPED | FILE_FLAG_NO_BUFFERING, nullptr);
}
int PC_Int_Parse(int handle, int* i) {
const static DWORD PC_Int_Parse_t = 0x62DF10;
int result{};
@ -135,5 +141,4 @@ void Menu_FreeItemMemory(itemDef_s* item) {
popad;
}
}
} // namespace game

View File

@ -40,6 +40,7 @@ void Sys_LockRead(FastCriticalSection* critSect);
void Sys_UnlockRead(FastCriticalSection* critSect);
void Sys_UnlockWrite(FastCriticalSection* critSect);
void Sys_SnapVector(float* v);
HANDLE Sys_OpenFileReliable(const char* filename);
int PC_Int_Parse(int handle, int* i);
int PC_Float_Parse(int handle, float* f);
@ -54,6 +55,7 @@ constexpr auto MAX_POSSIBLE_LOCAL_CLIENTS = 1;
constexpr std::size_t MAX_LOCAL_CLIENTS = 1;
constexpr auto MAX_QPATH = 64;
constexpr auto MAX_OSPATH = 256;
constexpr auto MAX_OPCODE_LOOKUP_SIZE = 0x1000000;
constexpr auto MAX_SOURCEPOS_LOOKUP_SIZE = 0x800000;

View File

@ -9,6 +9,12 @@ typedef vec_t vec2_t[2];
typedef vec_t vec3_t[3];
typedef vec_t vec4_t[4];
enum LocalClientNum_t {
LOCAL_CLIENT_0 = 0,
LOCAL_CLIENT_LAST = 1,
LOCAL_CLIENT_COUNT = 1,
};
struct scr_entref_t {
unsigned __int16 entnum;
unsigned __int16 classnum;
@ -1293,6 +1299,44 @@ struct XAssetEntry {
static_assert(sizeof(XAssetEntry) == 0x10);
struct GfxConfiguration {
bool inited;
unsigned int maxClientViews;
unsigned int maxClientRenderViews;
unsigned int entCount;
unsigned int entnumNone;
unsigned int entnumOrdinaryEnd;
int threadContextCount;
int critSectCount;
const char* codeFastFileName;
const char* localizedCodeFastFileName;
const char* uiFastFileName;
const char* localizedUiFastFileName;
const char* commonFastFileName;
const char* localizedCommonFastFileName;
const char* patchFastFileName;
bool defaultFullscreen;
unsigned __int16 defaultFullscreenFlags;
int defaultMode;
unsigned int textureMinVRamTier1;
unsigned int textureMinVRamTier2;
};
enum FF_DIR {
FFD_DEFAULT = 0x0,
FFD_MOD_DIR = 0x1,
FFD_USER_MAP = 0x2,
};
enum {
DB_ZONE_COMMON = 0x1,
DB_ZONE_UI = 0x2,
DB_ZONE_GAME = 0x4,
DB_ZONE_LOAD = 0x8,
DB_ZONE_DEV = 0x10,
DB_ZONE_TRANSIENT = 0x20,
};
struct XZoneInfo {
const char* name;
int allocFlags;
@ -1685,6 +1729,15 @@ struct TraceThreadInfo {
};
static_assert(sizeof(TraceThreadInfo) == 0x8);
struct localization_t {
char* language;
char* strings;
};
struct Sys_File {
HANDLE handle;
};
} // namespace game
#pragma warning(pop)

View File

@ -24,6 +24,10 @@ WEAK symbol<const char*(const char* fmt, ...)> va{0x4869F0};
// Con
WEAK symbol<bool(const char* cmd)> Con_IsDvarCommand{0x4B6610};
// ScrPlace
WEAK symbol<ScreenPlacement*(int localClientNum)> ScrPlace_GetActivePlacement{
0x4D2A60};
// Sys
WEAK symbol<void(const char* exeName)> Sys_QuitAndStartProcess{0x4D69A0};
WEAK symbol<void(CriticalSection critSect)> Sys_EnterCriticalSection{0x4A4CD0};
@ -37,6 +41,9 @@ WEAK symbol<bool()> Sys_IsDatabaseThread{0x4C9380};
WEAK symbol<void(int valueIndex, void* data)> Sys_SetValue{0x483310};
WEAK symbol<void(int msec)> Sys_Sleep{0x4CFBE0};
WEAK symbol<void(const char* error, ...)> Sys_Error{0x40BFF0};
WEAK symbol<const char*(const char* zoneName)> Sys_GetMapZoneDir{0x4429F0};
WEAK symbol<Sys_File(const char* dir, const char* filename)> Sys_CreateFile{
0x465B80};
WEAK symbol<short(short l)> BigShort{0x40E7E0};
WEAK symbol<short(short l)> ShortNoSwap{0x4261A0};
@ -254,6 +261,8 @@ WEAK symbol<int(const char* s)> Info_Validate{0x425530};
// IW functions, could use Microsoft specific functions but who cares
WEAK symbol<int(const char* s0, const char* s1)> I_stricmp{0x409B80};
WEAK symbol<int(const char* s0, const char* s1, int n)> I_strnicmp{0x491E60};
WEAK symbol<void(char* dest, const char* src, int destsize)> I_strncpyz{
0x416920};
WEAK symbol<void(field_t* edit)> Field_Clear{0x45C350};
@ -263,6 +272,14 @@ WEAK symbol<int(const char* string)> StringTable_HashString{0x498080};
// Vec3
WEAK symbol<void(const float* v, float scale, const float* result)> Vec3Scale{
0x429220};
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};
// Variables
WEAK symbol<CmdArgs> cmd_args{0x144FED0};
@ -318,4 +335,6 @@ WEAK symbol<uiInfo_s> uiInfoArray{0x1920470};
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};
} // namespace game

View File

@ -121,7 +121,7 @@ void loader::load_imports(const utils::nt::library& target,
auto* import =
PIMAGE_IMPORT_BY_NAME(target.get_ptr() + *name_table_entry);
function_name = import->Name;
function_procname = function_name.data();
function_procname = function_name.c_str();
}
if (this->import_resolver_)

View File

@ -1,6 +1,5 @@
#include "std_include.hpp"
#include <utils/nt.hpp>
#include <utils/io.hpp>
#include <utils/string.hpp>
#include "loader/binary_loader.hpp"
@ -12,6 +11,19 @@
#include <version.hpp>
#include <DbgHelp.h>
std::string get_current_date() {
auto now = std::chrono::system_clock::now();
auto current_time = std::chrono::system_clock::to_time_t(now);
std::tm local_time{};
(void)localtime_s(&local_time, &current_time);
std::stringstream ss;
ss << std::put_time(&local_time, "%Y%m%d_%H%M%S");
return ss.str();
}
LONG WINAPI exception_handler(PEXCEPTION_POINTERS exception_info) {
if (exception_info->ExceptionRecord->ExceptionCode == 0x406D1388) {
return EXCEPTION_CONTINUE_EXECUTION;
@ -32,8 +44,8 @@ LONG WINAPI exception_handler(PEXCEPTION_POINTERS exception_info) {
| MiniDumpWithThreadInfo;
CreateDirectoryA("minidumps", nullptr);
const auto* file_name =
utils::string::va("minidumps\\iw4-sp_{0}.dmp", SHORTVERSION);
const auto* file_name = utils::string::va("minidumps\\iw4x-sp_{0}_{1}.dmp",
SHORTVERSION, get_current_date());
constexpr auto file_share = FILE_SHARE_READ | FILE_SHARE_WRITE;
const auto file_handle =
CreateFileA(file_name, GENERIC_WRITE | GENERIC_READ, file_share, nullptr,

View File

@ -65,12 +65,11 @@ BEGIN
VALUE "CompanyName", "AlterWare"
VALUE "FileDescription", "IW4 SP client modification"
VALUE "FileVersion", VERSION_FILE
VALUE "InternalName", "iw4-sp"
VALUE "InternalName", "iw4x-sp"
VALUE "LegalCopyright", "Copyright (C) 2023 AlterWare. All rights reserved."
VALUE "Licence", "GPLv3"
VALUE "Info", "https://alterware.dev"
VALUE "OriginalFilename", "iw4-sp.exe"
VALUE "ProductName", "iw4-sp"
VALUE "OriginalFilename", "iw4x-sp.exe"
VALUE "ProductName", "iw4x-sp"
VALUE "ProductVersion", VERSION_PRODUCT
END
END

View File

@ -7,7 +7,7 @@
#define WIN32_LEAN_AND_MEAN
#define BASEGAME "spdata"
#define CLIENT_CONFIG "iw4_sp_config.cfg"
#define CLIENT_CONFIG "iw4x_sp_config.cfg"
#include <WinSock2.h>
#include <Windows.h>

View File

@ -93,7 +93,7 @@ unsigned __int64 user::RequestEncryptedAppTicket(void* pUserData,
// Generate the authentication ticket
const auto id = this->GetSteamID();
auth_ticket = "iw4-sp";
auth_ticket = "iw4x-sp";
auth_ticket.resize(32);
auth_ticket.append(static_cast<char*>(pUserData), cbUserData);
auth_ticket.append(reinterpret_cast<const char*>(&id.bits), sizeof(id.bits));

View File

@ -96,7 +96,7 @@ namespace zip {
namespace {
bool add_file(zipFile& zip_file, const std::string& filename,
const std::string& data) {
if (zipOpenNewFileInZip(zip_file, filename.data(), nullptr, nullptr, 0,
if (zipOpenNewFileInZip(zip_file, filename.c_str(), nullptr, nullptr, 0,
nullptr, 0, nullptr, Z_DEFLATED,
Z_BEST_COMPRESSION) != ZIP_OK) {
return false;
@ -117,13 +117,13 @@ bool archive::write(const std::string& filename, const std::string& comment) {
io::write_file(filename, {});
io::remove_file(filename);
auto* zip_file = zipOpen(filename.data(), 0);
auto* zip_file = zipOpen(filename.c_str(), 0);
if (zip_file == nullptr) {
return false;
}
const auto _ = gsl::finally([&zip_file, &comment]() {
zipClose(zip_file, comment.empty() ? nullptr : comment.data());
zipClose(zip_file, comment.empty() ? nullptr : comment.c_str());
});
for (const auto& file : this->files_) {

View File

@ -4,11 +4,11 @@
namespace utils::io {
bool remove_file(const std::string& file) {
return DeleteFileA(file.data()) == TRUE;
return DeleteFileA(file.c_str()) == TRUE;
}
bool move_file(const std::string& src, const std::string& target) {
return MoveFileA(src.data(), target.data()) == TRUE;
return MoveFileA(src.c_str(), target.c_str()) == TRUE;
}
bool file_exists(const std::string& file) {

View File

@ -54,7 +54,7 @@ void* memory::allocate(const std::size_t length) {
char* memory::duplicate_string(const std::string& string) {
const auto new_string = allocate_array<char>(string.size() + 1);
std::memcpy(new_string, string.data(), string.size());
std::memcpy(new_string, string.c_str(), string.size());
return new_string;
}

View File

@ -2,7 +2,7 @@
namespace utils::nt {
library library::load(const std::string& name) {
return library(LoadLibraryA(name.data()));
return library(LoadLibraryA(name.c_str()));
}
library library::load(const std::filesystem::path& path) {
@ -19,7 +19,7 @@ library library::get_by_address(void* address) {
library::library() { this->module_ = GetModuleHandleA(nullptr); }
library::library(const std::string& name) {
this->module_ = GetModuleHandleA(name.data());
this->module_ = GetModuleHandleA(name.c_str());
}
library::library(const HMODULE handle) { this->module_ = handle; }
@ -161,7 +161,7 @@ void** library::get_iat_entry(const std::string& module_name,
while (import_descriptor->Name) {
if (!_stricmp(
reinterpret_cast<char*>(this->get_ptr() + import_descriptor->Name),
module_name.data())) {
module_name.c_str())) {
auto* original_thunk_data = reinterpret_cast<PIMAGE_THUNK_DATA>(
import_descriptor->OriginalFirstThunk + this->get_ptr());
auto* thunk_data = reinterpret_cast<PIMAGE_THUNK_DATA>(
@ -192,7 +192,7 @@ void** library::get_iat_entry(const std::string& module_name,
}
void library::set_dll_directory(const std::string& directory) {
SetDllDirectoryA(directory.data());
SetDllDirectoryA(directory.c_str());
}
std::string library::get_dll_directory() {
@ -245,7 +245,7 @@ void launch_process(const std::string& process,
char current_dir[MAX_PATH];
GetCurrentDirectoryA(sizeof(current_dir), current_dir);
CreateProcessA(process.data(), const_cast<char*>(command_line.data()),
CreateProcessA(process.c_str(), const_cast<char*>(command_line.c_str()),
nullptr, nullptr, false, NULL, nullptr, current_dir,
&startup_info, &process_info);

View File

@ -51,7 +51,7 @@ public:
template <typename T> T get_proc(const std::string& process) const {
if (!this->is_valid())
T{};
return reinterpret_cast<T>(GetProcAddress(this->module_, process.data()));
return reinterpret_cast<T>(GetProcAddress(this->module_, process.c_str()));
}
template <typename T> std::function<T> get(const std::string& process) const {

View File

@ -23,7 +23,7 @@ static const char* va(std::string_view fmt, Args&&... args) {
(sanitize_format_args(args), ...);
std::vformat(fmt, std::make_format_args(args...)).swap(va_buffer);
return va_buffer.data();
return va_buffer.c_str();
}
std::vector<std::string> split(const std::string& s, char delim);

View File

@ -22,7 +22,7 @@ bool set_name(const HANDLE t, const std::string& name) {
return false;
}
return SUCCEEDED(set_description(t, string::convert(name).data()));
return SUCCEEDED(set_description(t, string::convert(name).c_str()));
}
bool set_name(const DWORD id, const std::string& name) {

Binary file not shown.