maint: April update
This commit is contained in:
parent
ce6b6f4112
commit
89a735326d
22
README.md
22
README.md
@ -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
2
deps/libtomcrypt
vendored
@ -1 +1 @@
|
||||
Subproject commit 7e863d21429f94ed6a720e24499a12a3f852bb31
|
||||
Subproject commit f7e6519fae1e11ff5ff9d36c84101a673002133b
|
2
deps/libtommath
vendored
2
deps/libtommath
vendored
@ -1 +1 @@
|
||||
Subproject commit 8314bde5e5c8e5d9331460130a9d1066e324f091
|
||||
Subproject commit 5809141a3a6ec1bf3443c927c02b955e19224016
|
2
deps/minhook
vendored
2
deps/minhook
vendored
@ -1 +1 @@
|
||||
Subproject commit f5485b8454544c2f034c78f8f127c1d03dea3636
|
||||
Subproject commit 1cc46107ee522d7a5c73656c519ca16addf2c23a
|
2
deps/rapidjson
vendored
2
deps/rapidjson
vendored
@ -1 +1 @@
|
||||
Subproject commit 6089180ecb704cb2b136777798fa1be303618975
|
||||
Subproject commit ab1842a2dae061284c0a62dca1cc6d5e7e37e346
|
2
deps/zlib
vendored
2
deps/zlib
vendored
@ -1 +1 @@
|
||||
Subproject commit 643e17b7498d12ab8d15565662880579692f769d
|
||||
Subproject commit 0f51fb4933fc9ce18199cb2554dacea8033e7fd3
|
@ -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 {
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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());
|
||||
|
@ -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() {
|
||||
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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();
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
110
src/client/component/fastfile.cpp
Normal file
110
src/client/component/fastfile.cpp
Normal 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)
|
@ -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
|
||||
}
|
||||
};
|
||||
|
@ -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') {
|
||||
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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();
|
||||
|
@ -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();
|
||||
|
@ -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 {
|
||||
|
@ -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);
|
||||
|
@ -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());
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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_)
|
||||
|
@ -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, ¤t_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,
|
||||
|
@ -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
|
||||
|
@ -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>
|
||||
|
@ -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));
|
||||
|
@ -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_) {
|
||||
|
@ -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) {
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -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);
|
||||
|
@ -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.
Loading…
x
Reference in New Issue
Block a user