From 245cd533d1308af6c49cc3c5396aefbe934b6c37 Mon Sep 17 00:00:00 2001 From: momo5502 Date: Tue, 12 Jul 2016 18:33:25 +0200 Subject: [PATCH] Steam proxy --- deps/fmt | 2 +- deps/mongoose | 2 +- deps/protobuf | 2 +- src/Components/Modules/Colors.cpp | 508 ++++++------ src/Components/Modules/Console.cpp | 1098 ++++++++++++------------- src/Components/Modules/Exception.cpp | 6 +- src/Components/Modules/Logger.cpp | 310 +++---- src/Components/Modules/Maps.cpp | 2 +- src/Components/Modules/Menus.cpp | 4 +- src/Components/Modules/QuickPatch.cpp | 1 + src/Components/Modules/Script.cpp | 2 +- src/Components/Modules/Theatre.cpp | 7 +- src/STDInclude.hpp | 2 +- src/Steam/Interfaces/SteamUtils.cpp | 202 +++-- src/Steam/Proxy.cpp | 88 ++ src/Steam/Proxy.hpp | 30 + src/Steam/Steam.cpp | 20 +- src/Steam/Steam.hpp | 186 ++--- src/Utils/Hooking.cpp | 514 ++++++------ 19 files changed, 1544 insertions(+), 1442 deletions(-) create mode 100644 src/Steam/Proxy.cpp create mode 100644 src/Steam/Proxy.hpp diff --git a/deps/fmt b/deps/fmt index 4133e501..0d5ef5c2 160000 --- a/deps/fmt +++ b/deps/fmt @@ -1 +1 @@ -Subproject commit 4133e501f3277aeef530b75de2e7bfceca93e5d2 +Subproject commit 0d5ef5c2a66026409b0cfbafa1d2f46cdc5aa4d0 diff --git a/deps/mongoose b/deps/mongoose index 6f7f7740..36a19279 160000 --- a/deps/mongoose +++ b/deps/mongoose @@ -1 +1 @@ -Subproject commit 6f7f774080f0c2ec291bfa0a908bc31a923051a1 +Subproject commit 36a1927915f966f20486a80070f0428f2606a53a diff --git a/deps/protobuf b/deps/protobuf index 790e6afb..70c1ac75 160000 --- a/deps/protobuf +++ b/deps/protobuf @@ -1 +1 @@ -Subproject commit 790e6afb72ed4ad952d9c74e73ae53a01443fe97 +Subproject commit 70c1ac756d3cd8fa04725f82f0ad1a30404c3bb3 diff --git a/src/Components/Modules/Colors.cpp b/src/Components/Modules/Colors.cpp index 1499dff1..d7b61033 100644 --- a/src/Components/Modules/Colors.cpp +++ b/src/Components/Modules/Colors.cpp @@ -1,254 +1,254 @@ -#include "STDInclude.hpp" - -namespace Components -{ - Dvar::Var Colors::NewColors; - std::vector Colors::ColorTable; - - DWORD Colors::HsvToRgb(Colors::HsvColor hsv) - { - DWORD rgb; - unsigned char region, p, q, t; - unsigned int h, s, v, remainder; - - if (hsv.s == 0) - { - rgb = RGB(hsv.v, hsv.v, hsv.v); - return rgb; - } - - // converting to 16 bit to prevent overflow - h = hsv.h; - s = hsv.s; - v = hsv.v; - - region = static_cast(h / 43); - remainder = (h - (region * 43)) * 6; - - p = static_cast((v * (255 - s)) >> 8); - q = static_cast((v * (255 - ((s * remainder) >> 8))) >> 8); - t = static_cast((v * (255 - ((s * (255 - remainder)) >> 8))) >> 8); - - switch (region) - { - case 0: - rgb = RGB(v, t, p); - break; - case 1: - rgb = RGB(q, v, p); - break; - case 2: - rgb = RGB(p, v, t); - break; - case 3: - rgb = RGB(p, q, v); - break; - case 4: - rgb = RGB(t, p, v); - break; - default: - rgb = RGB(v, p, q); - break; - } - - return rgb; - } - - void Colors::Strip(const char* in, char* out, int max) - { - if (!in || !out) return; - - max--; - int current = 0; - while (*in != 0 && current < max) - { - char index = *(in + 1); - if (*in == '^' && (Colors::ColorIndex(index) != 7 || index == '7')) - { - ++in; - } - else - { - *out = *in; - ++out; - ++current; - } - - ++in; - } - *out = '\0'; - } - - std::string Colors::Strip(std::string in) - { - char buffer[1000] = { 0 }; // Should be more than enough - Colors::Strip(in.data(), buffer, sizeof(buffer)); - return std::string(buffer); - } - - void __declspec(naked) Colors::ClientUserinfoChanged() - { - __asm - { - mov eax, [esp + 4h] // length - sub eax, 1 - push eax - - push ecx // name - push edx // buffer - - call strncpy - - add esp, 0Ch - retn - } - } - - char* Colors::GetClientName(int localClientNum, int index, char *buf, size_t size) - { - Game::CL_GetClientName(localClientNum, index, buf, size); - - // Remove the colors - strncpy(buf, Colors::Strip(buf).data(), size); - - return buf; - } - - void Colors::PatchColorLimit(char limit) - { - Utils::Hook::Set(0x535629, limit); // DrawText2d - Utils::Hook::Set(0x4C1BE4, limit); // No idea :P - Utils::Hook::Set(0x4863DD, limit); // No idea :P - Utils::Hook::Set(0x486429, limit); // No idea :P - Utils::Hook::Set(0x49A5A8, limit); // No idea :P - Utils::Hook::Set(0x505721, limit); // R_TextWidth - Utils::Hook::Set(0x505801, limit); // No idea :P - Utils::Hook::Set(0x50597F, limit); // No idea :P - Utils::Hook::Set(0x5815DB, limit); // No idea :P - Utils::Hook::Set(0x592ED0, limit); // No idea :P - Utils::Hook::Set(0x5A2E2E, limit); // No idea :P - - Utils::Hook::Set(0x5A2733, limit - '0'); // No idea :P - } - - char Colors::Add(uint8_t r, uint8_t g, uint8_t b) - { - char index = '0' + static_cast(Colors::ColorTable.size()); - Colors::ColorTable.push_back(RGB(r, g, b)); - Colors::PatchColorLimit(index); - return index; - } - - unsigned int Colors::ColorIndex(unsigned char index) - { - unsigned int result = index - '0'; - if (result >= Colors::ColorTable.size() || result < 0) result = 7; - return result; - } - - void Colors::LookupColor(DWORD* color, char index) - { - *color = RGB(255, 255, 255); - - if (index == '8') // Color 8 - { - *color = *reinterpret_cast(0x66E5F70); - } - else if (index == '9') // Color 9 - { - *color = *reinterpret_cast(0x66E5F74); - } - else if (index == ':') - { - *color = Colors::HsvToRgb({ static_cast((Game::Sys_Milliseconds() / 200) % 256), 255,255 }); - } - else if (index == ';') - { - float fltColor[4]; - Game::Dvar_GetUnpackedColorByName("sv_customTextColor", fltColor); - *color = RGB(fltColor[0] * 255, fltColor[1] * 255, fltColor[2] * 255); - } - else - { - int clrIndex = Colors::ColorIndex(index); - - // Use native colors - if (clrIndex <= 7 && !Colors::NewColors.Get()) - { - *color = reinterpret_cast(0x78DC70)[index - 48]; - } - else - { - *color = Colors::ColorTable[clrIndex]; - } - } - } - - char* Colors::CleanStrStub(char* string) - { - Colors::Strip(string, string, strlen(string) + 1); - return string; - } - - void __declspec(naked) Colors::LookupColorStub() - { - __asm - { - push ebx - push [esp + 8h] // Index - push esi // Color ref - call Colors::LookupColor - add esp, 8h - pop ebx - retn - } - } - - Colors::Colors() - { - // Disable SV_UpdateUserinfo_f, to block changing the name ingame - Utils::Hook::Set(0x6258D0, 0xC3); - - // Allow colored names ingame - Utils::Hook(0x5D8B40, Colors::ClientUserinfoChanged, HOOK_JUMP).Install()->Quick(); - - // Though, don't apply that to overhead names. - Utils::Hook(0x581932, Colors::GetClientName, HOOK_CALL).Install()->Quick(); - - // Patch RB_LookupColor - Utils::Hook(0x534CD0, Colors::LookupColorStub, HOOK_JUMP).Install()->Quick(); - - // Patch ColorIndex - Utils::Hook(0x417770, Colors::ColorIndex, HOOK_JUMP).Install()->Quick(); - - // Patch I_CleanStr - Utils::Hook(0x4AD470, Colors::CleanStrStub, HOOK_JUMP).Install()->Quick(); - - // Register dvar - Colors::NewColors = Dvar::Register("cg_newColors", true, Game::dvar_flag::DVAR_FLAG_SAVED, "Use Warfare² color code style."); - Game::Dvar_RegisterColor("sv_customTextColor", 1, 0.7f, 0, 1, Game::dvar_flag::DVAR_FLAG_REPLICATED, "Color for the extended color code."); - - // Add our colors - Colors::Add(0, 0, 0); // 0 - Black - Colors::Add(255, 49, 49); // 1 - Red - Colors::Add(134, 192, 0); // 2 - Green - Colors::Add(255, 173, 34); // 3 - Yellow - Colors::Add(0, 135, 193); // 4 - Blue - Colors::Add(32, 197, 255); // 5 - Light Blue - Colors::Add(151, 80, 221); // 6 - Pink - - Colors::Add(255, 255, 255); // 7 - White - - Colors::Add(0, 0, 0); // 8 - Team color (axis?) - Colors::Add(0, 0, 0); // 9 - Team color (allies?) - - // Custom colors - Colors::Add(0, 0, 0); // 10 - Rainbow (:) - Colors::Add(0, 0, 0); // 11 - Server color (;) - using that color in infostrings (e.g. your name) fails, ';' is an illegal character! - } - - Colors::~Colors() - { - Colors::ColorTable.clear(); - } -} +#include "STDInclude.hpp" + +namespace Components +{ + Dvar::Var Colors::NewColors; + std::vector Colors::ColorTable; + + DWORD Colors::HsvToRgb(Colors::HsvColor hsv) + { + DWORD rgb; + unsigned char region, p, q, t; + unsigned int h, s, v, remainder; + + if (hsv.s == 0) + { + rgb = RGB(hsv.v, hsv.v, hsv.v); + return rgb; + } + + // converting to 16 bit to prevent overflow + h = hsv.h; + s = hsv.s; + v = hsv.v; + + region = static_cast(h / 43); + remainder = (h - (region * 43)) * 6; + + p = static_cast((v * (255 - s)) >> 8); + q = static_cast((v * (255 - ((s * remainder) >> 8))) >> 8); + t = static_cast((v * (255 - ((s * (255 - remainder)) >> 8))) >> 8); + + switch (region) + { + case 0: + rgb = RGB(v, t, p); + break; + case 1: + rgb = RGB(q, v, p); + break; + case 2: + rgb = RGB(p, v, t); + break; + case 3: + rgb = RGB(p, q, v); + break; + case 4: + rgb = RGB(t, p, v); + break; + default: + rgb = RGB(v, p, q); + break; + } + + return rgb; + } + + void Colors::Strip(const char* in, char* out, int max) + { + if (!in || !out) return; + + max--; + int current = 0; + while (*in != 0 && current < max) + { + char index = *(in + 1); + if (*in == '^' && (Colors::ColorIndex(index) != 7 || index == '7')) + { + ++in; + } + else + { + *out = *in; + ++out; + ++current; + } + + ++in; + } + *out = '\0'; + } + + std::string Colors::Strip(std::string in) + { + char buffer[1000] = { 0 }; // Should be more than enough + Colors::Strip(in.data(), buffer, sizeof(buffer)); + return std::string(buffer); + } + + void __declspec(naked) Colors::ClientUserinfoChanged() + { + __asm + { + mov eax, [esp + 4h] // length + sub eax, 1 + push eax + + push ecx // name + push edx // buffer + + call strncpy + + add esp, 0Ch + retn + } + } + + char* Colors::GetClientName(int localClientNum, int index, char *buf, size_t size) + { + Game::CL_GetClientName(localClientNum, index, buf, size); + + // Remove the colors + strncpy_s(buf, size, Colors::Strip(buf).data(), size); + + return buf; + } + + void Colors::PatchColorLimit(char limit) + { + Utils::Hook::Set(0x535629, limit); // DrawText2d + Utils::Hook::Set(0x4C1BE4, limit); // No idea :P + Utils::Hook::Set(0x4863DD, limit); // No idea :P + Utils::Hook::Set(0x486429, limit); // No idea :P + Utils::Hook::Set(0x49A5A8, limit); // No idea :P + Utils::Hook::Set(0x505721, limit); // R_TextWidth + Utils::Hook::Set(0x505801, limit); // No idea :P + Utils::Hook::Set(0x50597F, limit); // No idea :P + Utils::Hook::Set(0x5815DB, limit); // No idea :P + Utils::Hook::Set(0x592ED0, limit); // No idea :P + Utils::Hook::Set(0x5A2E2E, limit); // No idea :P + + Utils::Hook::Set(0x5A2733, limit - '0'); // No idea :P + } + + char Colors::Add(uint8_t r, uint8_t g, uint8_t b) + { + char index = '0' + static_cast(Colors::ColorTable.size()); + Colors::ColorTable.push_back(RGB(r, g, b)); + Colors::PatchColorLimit(index); + return index; + } + + unsigned int Colors::ColorIndex(unsigned char index) + { + unsigned int result = index - '0'; + if (result >= Colors::ColorTable.size() || result < 0) result = 7; + return result; + } + + void Colors::LookupColor(DWORD* color, char index) + { + *color = RGB(255, 255, 255); + + if (index == '8') // Color 8 + { + *color = *reinterpret_cast(0x66E5F70); + } + else if (index == '9') // Color 9 + { + *color = *reinterpret_cast(0x66E5F74); + } + else if (index == ':') + { + *color = Colors::HsvToRgb({ static_cast((Game::Sys_Milliseconds() / 200) % 256), 255,255 }); + } + else if (index == ';') + { + float fltColor[4]; + Game::Dvar_GetUnpackedColorByName("sv_customTextColor", fltColor); + *color = RGB(fltColor[0] * 255, fltColor[1] * 255, fltColor[2] * 255); + } + else + { + int clrIndex = Colors::ColorIndex(index); + + // Use native colors + if (clrIndex <= 7 && !Colors::NewColors.Get()) + { + *color = reinterpret_cast(0x78DC70)[index - 48]; + } + else + { + *color = Colors::ColorTable[clrIndex]; + } + } + } + + char* Colors::CleanStrStub(char* string) + { + Colors::Strip(string, string, strlen(string) + 1); + return string; + } + + void __declspec(naked) Colors::LookupColorStub() + { + __asm + { + push ebx + push [esp + 8h] // Index + push esi // Color ref + call Colors::LookupColor + add esp, 8h + pop ebx + retn + } + } + + Colors::Colors() + { + // Disable SV_UpdateUserinfo_f, to block changing the name ingame + Utils::Hook::Set(0x6258D0, 0xC3); + + // Allow colored names ingame + Utils::Hook(0x5D8B40, Colors::ClientUserinfoChanged, HOOK_JUMP).Install()->Quick(); + + // Though, don't apply that to overhead names. + Utils::Hook(0x581932, Colors::GetClientName, HOOK_CALL).Install()->Quick(); + + // Patch RB_LookupColor + Utils::Hook(0x534CD0, Colors::LookupColorStub, HOOK_JUMP).Install()->Quick(); + + // Patch ColorIndex + Utils::Hook(0x417770, Colors::ColorIndex, HOOK_JUMP).Install()->Quick(); + + // Patch I_CleanStr + Utils::Hook(0x4AD470, Colors::CleanStrStub, HOOK_JUMP).Install()->Quick(); + + // Register dvar + Colors::NewColors = Dvar::Register("cg_newColors", true, Game::dvar_flag::DVAR_FLAG_SAVED, "Use Warfare² color code style."); + Game::Dvar_RegisterColor("sv_customTextColor", 1, 0.7f, 0, 1, Game::dvar_flag::DVAR_FLAG_REPLICATED, "Color for the extended color code."); + + // Add our colors + Colors::Add(0, 0, 0); // 0 - Black + Colors::Add(255, 49, 49); // 1 - Red + Colors::Add(134, 192, 0); // 2 - Green + Colors::Add(255, 173, 34); // 3 - Yellow + Colors::Add(0, 135, 193); // 4 - Blue + Colors::Add(32, 197, 255); // 5 - Light Blue + Colors::Add(151, 80, 221); // 6 - Pink + + Colors::Add(255, 255, 255); // 7 - White + + Colors::Add(0, 0, 0); // 8 - Team color (axis?) + Colors::Add(0, 0, 0); // 9 - Team color (allies?) + + // Custom colors + Colors::Add(0, 0, 0); // 10 - Rainbow (:) + Colors::Add(0, 0, 0); // 11 - Server color (;) - using that color in infostrings (e.g. your name) fails, ';' is an illegal character! + } + + Colors::~Colors() + { + Colors::ColorTable.clear(); + } +} diff --git a/src/Components/Modules/Console.cpp b/src/Components/Modules/Console.cpp index 000c8130..9981b0df 100644 --- a/src/Components/Modules/Console.cpp +++ b/src/Components/Modules/Console.cpp @@ -1,549 +1,549 @@ -#include "STDInclude.hpp" - -namespace Components -{ - WINDOW* Console::OutputWindow; - WINDOW* Console::InputWindow; - WINDOW* Console::InfoWindow; - - int Console::OutputTop = 0; - int Console::OutBuffer = 0; - int Console::LastRefresh = 0; - - int Console::Height = 25; - int Console::Width = 80; - - char Console::LineBuffer[1024] = { 0 }; - char Console::LineBuffer2[1024] = { 0 }; - int Console::LineBufferIndex = 0; - - bool Console::HasConsole = false; - - std::thread Console::ConsoleThread; - - Game::SafeArea Console::OriginalSafeArea; - - char** Console::GetAutoCompleteFileList(const char *path, const char *extension, Game::FsListBehavior_e behavior, int *numfiles, int allocTrackType) - { - if (path == reinterpret_cast(0xBAADF00D) || path == reinterpret_cast(0xCDCDCDCD) || IsBadReadPtr(path, 1)) return nullptr; - return Game::FS_GetFileList(path, extension, behavior, numfiles, allocTrackType); - } - - void Console::ToggleConsole() - { - // possibly cls.keyCatchers? - Utils::Hook::Xor(0xB2C538, 1); - - // g_consoleField - Game::Field_Clear((void*)0xA1B6B0); - - // show console output? - Utils::Hook::Set(0xA15F38, 0); - } - - void Console::RefreshStatus() - { - std::string mapname = Dvar::Var("mapname").Get(); - std::string hostname = Colors::Strip(Dvar::Var("sv_hostname").Get()); - SetConsoleTitleA(hostname.data()); - - int clientCount = 0; - int maxclientCount = *Game::svs_numclients; - - if (maxclientCount) - { - for (int i = 0; i < maxclientCount; ++i) - { - if (Game::svs_clients[i].state >= 3) - { - ++clientCount; - } - } - } - else - { - //maxclientCount = Dvar::Var("sv_maxclients").Get(); - maxclientCount = Game::Party_GetMaxPlayers(*Game::partyIngame); - clientCount = Game::PartyHost_CountMembers(reinterpret_cast(0x1081C00)); - } - - wclear(Console::InfoWindow); - wprintw(Console::InfoWindow, "%s : %d/%d players : map %s", hostname.data(), clientCount, maxclientCount, (mapname.size() ? mapname.data() : "none")); - wnoutrefresh(Console::InfoWindow); - } - - void Console::ShowPrompt() - { - wattron(Console::InputWindow, COLOR_PAIR(10) | A_BOLD); - wprintw(Console::InputWindow, "%s> ", VERSION_STR); - } - - void Console::RefreshOutput() - { - prefresh(Console::OutputWindow, ((Console::OutputTop > 0) ? (Console::OutputTop - 1) : 0), 0, 1, 0, Console::Height - 2, Console::Width); - } - - void Console::ScrollOutput(int amount) - { - Console::OutputTop += amount; - - if (Console::OutputTop > OUTPUT_MAX_TOP) - { - Console::OutputTop = OUTPUT_MAX_TOP; - } - else if (Console::OutputTop < 0) - { - Console::OutputTop = 0; - } - - // make it only scroll the top if there's more than HEIGHT lines - if (Console::OutBuffer >= 0) - { - Console::OutBuffer += amount; - - if (Console::OutBuffer >= Console::Height) - { - Console::OutBuffer = -1; - } - - if (Console::OutputTop < Console::Height) - { - Console::OutputTop = 0; - } - } - } - - const char* Console::Input() - { - if (!Console::HasConsole) - { - Console::ShowPrompt(); - wrefresh(Console::InputWindow); - Console::HasConsole = true; - } - - int currentTime = static_cast(GetTickCount64()); // Make our compiler happy - if ((currentTime - Console::LastRefresh) > 250) - { - Console::RefreshOutput(); - Console::RefreshStatus(); - Console::LastRefresh = currentTime; - } - - int c = wgetch(Console::InputWindow); - - if (c == ERR) - { - return NULL; - } - - switch (c) - { - case '\r': - case 459: // keypad enter - { - wattron(Console::OutputWindow, COLOR_PAIR(10) | A_BOLD); - wprintw(Console::OutputWindow, "%s", "]"); - - if (Console::LineBufferIndex) - { - wprintw(Console::OutputWindow, "%s", Console::LineBuffer); - } - - wprintw(Console::OutputWindow, "%s", "\n"); - wattroff(Console::OutputWindow, A_BOLD); - wclear(Console::InputWindow); - - Console::ShowPrompt(); - - wrefresh(Console::InputWindow); - - Console::ScrollOutput(1); - Console::RefreshOutput(); - - if (Console::LineBufferIndex) - { - strcpy(Console::LineBuffer2, Console::LineBuffer); - strcat(Console::LineBuffer, "\n"); - Console::LineBufferIndex = 0; - return Console::LineBuffer; - } - - break; - } - case 'c' - 'a' + 1: // ctrl-c - case 27: - { - Console::LineBuffer[0] = '\0'; - Console::LineBufferIndex = 0; - - wclear(Console::InputWindow); - - Console::ShowPrompt(); - - wrefresh(Console::InputWindow); - break; - } - case 8: // backspace - { - if (Console::LineBufferIndex > 0) - { - Console::LineBufferIndex--; - Console::LineBuffer[Console::LineBufferIndex] = '\0'; - - wprintw(Console::InputWindow, "%c %c", static_cast(c), static_cast(c)); - wrefresh(Console::InputWindow); - } - break; - } - case KEY_PPAGE: - { - Console::ScrollOutput(-1); - Console::RefreshOutput(); - break; - } - case KEY_NPAGE: - { - Console::ScrollOutput(1); - Console::RefreshOutput(); - break; - } - case KEY_UP: - { - wclear(Console::InputWindow); - Console::ShowPrompt(); - wprintw(Console::InputWindow, "%s", Console::LineBuffer2); - wrefresh(Console::InputWindow); - - strcpy(Console::LineBuffer, Console::LineBuffer2); - Console::LineBufferIndex = strlen(Console::LineBuffer); - break; - } - default: - if (c <= 127 && Console::LineBufferIndex < 1022) - { - // temporary workaround , find out what overwrites our index later on - //consoleLineBufferIndex = strlen(consoleLineBuffer); - - Console::LineBuffer[Console::LineBufferIndex++] = static_cast(c); - Console::LineBuffer[Console::LineBufferIndex] = '\0'; - wprintw(Console::InputWindow, "%c", static_cast(c)); - wrefresh(Console::InputWindow); - } - break; - } - - return NULL; - } - - void Console::Destroy() - { - delwin(Console::OutputWindow); - delwin(Console::InputWindow); - delwin(Console::InfoWindow); - endwin(); - - Console::OutputWindow = nullptr; - Console::InputWindow = nullptr; - Console::InfoWindow = nullptr; - } - - void Console::Create() - { - Console::OutputTop = 0; - Console::OutBuffer = 0; - Console::LastRefresh = 0; - Console::LineBufferIndex = 0; - Console::HasConsole = false; - - CONSOLE_SCREEN_BUFFER_INFO info; - if (GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &info)) - { - Console::Width = info.dwSize.X; - Console::Height = info.srWindow.Bottom - info.srWindow.Top + 1; - } - else - { - Console::Height = 25; - Console::Width = 80; - } - - initscr(); - raw(); - noecho(); - - Console::OutputWindow = newpad(OUTPUT_HEIGHT, Console::Width); - Console::InputWindow = newwin(1, Console::Width, Console::Height - 1, 0); - Console::InfoWindow = newwin(1, Console::Width, 0, 0); - - scrollok(Console::OutputWindow, true); - scrollok(Console::InputWindow, true); - nodelay(Console::InputWindow, true); - keypad(Console::InputWindow, true); - - if (has_colors()) - { - start_color(); - init_pair(1, COLOR_BLACK, COLOR_WHITE); - init_pair(2, COLOR_WHITE, COLOR_BLACK); - init_pair(3, COLOR_RED, COLOR_BLACK); - init_pair(4, COLOR_GREEN, COLOR_BLACK); - init_pair(5, COLOR_YELLOW, COLOR_BLACK); - init_pair(6, COLOR_BLUE, COLOR_BLACK); - init_pair(7, COLOR_CYAN, COLOR_BLACK); - init_pair(8, COLOR_RED, COLOR_BLACK); - init_pair(9, COLOR_WHITE, COLOR_BLACK); - init_pair(10, COLOR_WHITE, COLOR_BLACK); - } - - wbkgd(Console::InfoWindow, COLOR_PAIR(1)); - - wrefresh(Console::InfoWindow); - wrefresh(Console::InputWindow); - - Console::RefreshOutput(); - } - - void Console::Error(const char* format, ...) - { - static char buffer[32768]; - - va_list va; - va_start(va, format); - _vsnprintf(buffer, sizeof(buffer), format, va); - va_end(va); - - Game::Com_Printf(0, "ERROR:\n"); - Game::Com_Printf(0, buffer); - - Console::RefreshOutput(); - - if (IsDebuggerPresent()) - { - while (true) - { - std::this_thread::sleep_for(5s); - } - } - - TerminateProcess(GetCurrentProcess(), 0xDEADDEAD); - } - - void Console::Print(const char* message) - { - if (!Console::OutputWindow) return; - - const char* p = message; - while (*p != '\0') - { - if (*p == '\n') - { - Console::ScrollOutput(1); - } - - if (*p == '^') - { - char color; - ++p; - - color = (*p - '0'); - - if (color < 9 && color > 0) - { - wattron(Console::OutputWindow, COLOR_PAIR(color + 2)); - ++p; - continue; - } - } - - waddch(Console::OutputWindow, *p); - - ++p; - } - - wattron(Console::OutputWindow, COLOR_PAIR(9)); - -// int currentTime = static_cast(GetTickCount64()); // Make our compiler happy -// -// if (!Console::HasConsole) -// { -// Console::RefreshOutput(); -// } -// else if ((currentTime - Console::LastRefresh) > 100) -// { -// Console::RefreshOutput(); -// Console::LastRefresh = currentTime; -// } - - Console::RefreshOutput(); - } - - void Console::ConsoleRunner() - { - Game::Sys_ShowConsole(); - - MSG message; - while (IsWindow(*reinterpret_cast(0x64A3288)) != FALSE && GetMessageA(&message, 0, 0, 0)) - { - TranslateMessage(&message); - DispatchMessageA(&message); - } - - if (Game::Sys_Milliseconds() - Console::LastRefresh > 100 && - MessageBoxA(0, "The application is not responding anymore, do you want to force its termination?", "Application is not responding", MB_ICONEXCLAMATION | MB_YESNO) == IDYES) - { - // Force process termination - // if the main thread is not responding - OutputDebugStringA("Process termination forced, as the main thread is not responding!"); - - // We can not force the termination in this thread - // The destructor would be called in this thread - // and would try to join this thread, which is impossible - std::async([] () - { - std::this_thread::sleep_for(200ms); - ExitProcess(static_cast(-1)); - }); - } - else - { - // Send quit command to safely terminate the application - Command::Execute("wait 200;quit\n", false); - } - } - - void Console::StdOutPrint(const char* message) - { - printf("%s", message); - fflush(stdout); - } - - void Console::StdOutError(const char* format, ...) - { - char buffer[0x1000] = { 0 }; - - va_list ap; - va_start(ap, format); - _vsnprintf(buffer, sizeof(buffer), format, ap); - va_end(ap); - - perror(buffer); - fflush(stderr); - - ExitProcess(1); - } - - void __declspec(naked) Console::DrawSolidConsoleStub() - { - __asm - { - pushad - call Console::StoreSafeArea - popad - - // We need esi preserved here, so we have to backup 'all' registers when storing the safearea - call Game::Con_DrawSolidConsole - - call Console::RestoreSafeArea - retn - } - } - - void Console::StoreSafeArea() - { - // Backup the original safe area - Console::OriginalSafeArea = *Game::safeArea; - - // Apply new safe area and border - float border = 6.0f; - Game::safeArea->top = border; - Game::safeArea->left = border; - Game::safeArea->bottom = static_cast(Renderer::Height()) - border; - Game::safeArea->right = static_cast(Renderer::Width()) - border; - - Game::safeArea->textHeight = static_cast((Game::safeArea->bottom - Game::safeArea->top - (2 * Game::safeArea->fontHeight) - 24.0) / Game::safeArea->fontHeight); - Game::safeArea->textWidth = static_cast(Game::safeArea->right - Game::safeArea->left - 10.0f - 18.0); - } - - void Console::RestoreSafeArea() - { - // Restore the initial safe area - *Game::safeArea = Console::OriginalSafeArea; - } - - Console::Console() - { - // Console '%s: %s> ' string - Utils::Hook::Set(0x5A44B4, "IW4x: r" REVISION_STR "> "); - - // Internal console - Utils::Hook(0x4F690C, Console::ToggleConsole, HOOK_CALL).Install()->Quick(); - Utils::Hook(0x4F65A5, Console::ToggleConsole, HOOK_JUMP).Install()->Quick(); - - // Patch safearea for ingame-console - Utils::Hook(0x5A50EF, Console::DrawSolidConsoleStub, HOOK_CALL).Install()->Quick(); - - // Check for bad food ;) - Utils::Hook(0x4CB9F4, Console::GetAutoCompleteFileList, HOOK_CALL).Install()->Quick(); - - // Modify console style - Utils::Hook::Set(0x428A8E, 0); // Adjust logo Y pos - Utils::Hook::Set(0x428A90, 0); // Adjust logo X pos - Utils::Hook::Set(0x428AF2, 67); // Adjust output Y pos - Utils::Hook::Set(0x428AC5, 397); // Adjust input Y pos - Utils::Hook::Set(0x428951, 609); // Reduce window width - Utils::Hook::Set(0x42895D, 423); // Reduce window height - Utils::Hook::Set(0x428AC0, 597); // Reduce input width - Utils::Hook::Set(0x428AED, 596); // Reduce output width - - // Don't resize the console - Utils::Hook(0x64DC6B, 0x64DCC2, HOOK_JUMP).Install()->Quick(); - - // Code below is not necessary, when performing unit tests! - if (Loader::PerformingUnitTests()) return; - - // External console - if (Flags::HasFlag("stdout")) - { - Utils::Hook(0x4B2080, Console::StdOutPrint, HOOK_JUMP).Install()->Quick(); - Utils::Hook(0x43D570, Console::StdOutError, HOOK_JUMP).Install()->Quick(); - } - else if (Flags::HasFlag("console") || ZoneBuilder::IsEnabled()) // ZoneBuilder uses the game's console, until the native one is adapted. - { - FreeConsole(); - Utils::Hook::Nop(0x60BB58, 11); - - Utils::Hook(0x60BB68, [] () - { - Console::ConsoleThread = std::thread(Console::ConsoleRunner); - }, HOOK_CALL).Install()->Quick(); - - QuickPatch::OnFrame([] () - { - Console::LastRefresh = Game::Sys_Milliseconds(); - }); - } - else if (Dedicated::IsDedicated()/* || ZoneBuilder::IsEnabled()*/) - { - Utils::Hook::Nop(0x60BB58, 11); - - Utils::Hook(0x4305E0, Console::Create, HOOK_JUMP).Install()->Quick(); - Utils::Hook(0x4528A0, Console::Destroy, HOOK_JUMP).Install()->Quick(); - Utils::Hook(0x4B2080, Console::Print, HOOK_JUMP).Install()->Quick(); - Utils::Hook(0x43D570, Console::Error, HOOK_JUMP).Install()->Quick(); - Utils::Hook(0x4859A5, Console::Input, HOOK_CALL).Install()->Quick(); - } - else - { - FreeConsole(); - } - } - - Console::~Console() - { - if (Console::ConsoleThread.joinable()) - { - Console::ConsoleThread.join(); - } - } -} +#include "STDInclude.hpp" + +namespace Components +{ + WINDOW* Console::OutputWindow; + WINDOW* Console::InputWindow; + WINDOW* Console::InfoWindow; + + int Console::OutputTop = 0; + int Console::OutBuffer = 0; + int Console::LastRefresh = 0; + + int Console::Height = 25; + int Console::Width = 80; + + char Console::LineBuffer[1024] = { 0 }; + char Console::LineBuffer2[1024] = { 0 }; + int Console::LineBufferIndex = 0; + + bool Console::HasConsole = false; + + std::thread Console::ConsoleThread; + + Game::SafeArea Console::OriginalSafeArea; + + char** Console::GetAutoCompleteFileList(const char *path, const char *extension, Game::FsListBehavior_e behavior, int *numfiles, int allocTrackType) + { + if (path == reinterpret_cast(0xBAADF00D) || path == reinterpret_cast(0xCDCDCDCD) || IsBadReadPtr(path, 1)) return nullptr; + return Game::FS_GetFileList(path, extension, behavior, numfiles, allocTrackType); + } + + void Console::ToggleConsole() + { + // possibly cls.keyCatchers? + Utils::Hook::Xor(0xB2C538, 1); + + // g_consoleField + Game::Field_Clear((void*)0xA1B6B0); + + // show console output? + Utils::Hook::Set(0xA15F38, 0); + } + + void Console::RefreshStatus() + { + std::string mapname = Dvar::Var("mapname").Get(); + std::string hostname = Colors::Strip(Dvar::Var("sv_hostname").Get()); + SetConsoleTitleA(hostname.data()); + + int clientCount = 0; + int maxclientCount = *Game::svs_numclients; + + if (maxclientCount) + { + for (int i = 0; i < maxclientCount; ++i) + { + if (Game::svs_clients[i].state >= 3) + { + ++clientCount; + } + } + } + else + { + //maxclientCount = Dvar::Var("sv_maxclients").Get(); + maxclientCount = Game::Party_GetMaxPlayers(*Game::partyIngame); + clientCount = Game::PartyHost_CountMembers(reinterpret_cast(0x1081C00)); + } + + wclear(Console::InfoWindow); + wprintw(Console::InfoWindow, "%s : %d/%d players : map %s", hostname.data(), clientCount, maxclientCount, (mapname.size() ? mapname.data() : "none")); + wnoutrefresh(Console::InfoWindow); + } + + void Console::ShowPrompt() + { + wattron(Console::InputWindow, COLOR_PAIR(10) | A_BOLD); + wprintw(Console::InputWindow, "%s> ", VERSION_STR); + } + + void Console::RefreshOutput() + { + prefresh(Console::OutputWindow, ((Console::OutputTop > 0) ? (Console::OutputTop - 1) : 0), 0, 1, 0, Console::Height - 2, Console::Width); + } + + void Console::ScrollOutput(int amount) + { + Console::OutputTop += amount; + + if (Console::OutputTop > OUTPUT_MAX_TOP) + { + Console::OutputTop = OUTPUT_MAX_TOP; + } + else if (Console::OutputTop < 0) + { + Console::OutputTop = 0; + } + + // make it only scroll the top if there's more than HEIGHT lines + if (Console::OutBuffer >= 0) + { + Console::OutBuffer += amount; + + if (Console::OutBuffer >= Console::Height) + { + Console::OutBuffer = -1; + } + + if (Console::OutputTop < Console::Height) + { + Console::OutputTop = 0; + } + } + } + + const char* Console::Input() + { + if (!Console::HasConsole) + { + Console::ShowPrompt(); + wrefresh(Console::InputWindow); + Console::HasConsole = true; + } + + int currentTime = static_cast(GetTickCount64()); // Make our compiler happy + if ((currentTime - Console::LastRefresh) > 250) + { + Console::RefreshOutput(); + Console::RefreshStatus(); + Console::LastRefresh = currentTime; + } + + int c = wgetch(Console::InputWindow); + + if (c == ERR) + { + return NULL; + } + + switch (c) + { + case '\r': + case 459: // keypad enter + { + wattron(Console::OutputWindow, COLOR_PAIR(10) | A_BOLD); + wprintw(Console::OutputWindow, "%s", "]"); + + if (Console::LineBufferIndex) + { + wprintw(Console::OutputWindow, "%s", Console::LineBuffer); + } + + wprintw(Console::OutputWindow, "%s", "\n"); + wattroff(Console::OutputWindow, A_BOLD); + wclear(Console::InputWindow); + + Console::ShowPrompt(); + + wrefresh(Console::InputWindow); + + Console::ScrollOutput(1); + Console::RefreshOutput(); + + if (Console::LineBufferIndex) + { + strcpy_s(Console::LineBuffer2, Console::LineBuffer); + strcat_s(Console::LineBuffer, "\n"); + Console::LineBufferIndex = 0; + return Console::LineBuffer; + } + + break; + } + case 'c' - 'a' + 1: // ctrl-c + case 27: + { + Console::LineBuffer[0] = '\0'; + Console::LineBufferIndex = 0; + + wclear(Console::InputWindow); + + Console::ShowPrompt(); + + wrefresh(Console::InputWindow); + break; + } + case 8: // backspace + { + if (Console::LineBufferIndex > 0) + { + Console::LineBufferIndex--; + Console::LineBuffer[Console::LineBufferIndex] = '\0'; + + wprintw(Console::InputWindow, "%c %c", static_cast(c), static_cast(c)); + wrefresh(Console::InputWindow); + } + break; + } + case KEY_PPAGE: + { + Console::ScrollOutput(-1); + Console::RefreshOutput(); + break; + } + case KEY_NPAGE: + { + Console::ScrollOutput(1); + Console::RefreshOutput(); + break; + } + case KEY_UP: + { + wclear(Console::InputWindow); + Console::ShowPrompt(); + wprintw(Console::InputWindow, "%s", Console::LineBuffer2); + wrefresh(Console::InputWindow); + + strcpy_s(Console::LineBuffer, Console::LineBuffer2); + Console::LineBufferIndex = strlen(Console::LineBuffer); + break; + } + default: + if (c <= 127 && Console::LineBufferIndex < 1022) + { + // temporary workaround , find out what overwrites our index later on + //consoleLineBufferIndex = strlen(consoleLineBuffer); + + Console::LineBuffer[Console::LineBufferIndex++] = static_cast(c); + Console::LineBuffer[Console::LineBufferIndex] = '\0'; + wprintw(Console::InputWindow, "%c", static_cast(c)); + wrefresh(Console::InputWindow); + } + break; + } + + return NULL; + } + + void Console::Destroy() + { + delwin(Console::OutputWindow); + delwin(Console::InputWindow); + delwin(Console::InfoWindow); + endwin(); + + Console::OutputWindow = nullptr; + Console::InputWindow = nullptr; + Console::InfoWindow = nullptr; + } + + void Console::Create() + { + Console::OutputTop = 0; + Console::OutBuffer = 0; + Console::LastRefresh = 0; + Console::LineBufferIndex = 0; + Console::HasConsole = false; + + CONSOLE_SCREEN_BUFFER_INFO info; + if (GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &info)) + { + Console::Width = info.dwSize.X; + Console::Height = info.srWindow.Bottom - info.srWindow.Top + 1; + } + else + { + Console::Height = 25; + Console::Width = 80; + } + + initscr(); + raw(); + noecho(); + + Console::OutputWindow = newpad(OUTPUT_HEIGHT, Console::Width); + Console::InputWindow = newwin(1, Console::Width, Console::Height - 1, 0); + Console::InfoWindow = newwin(1, Console::Width, 0, 0); + + scrollok(Console::OutputWindow, true); + scrollok(Console::InputWindow, true); + nodelay(Console::InputWindow, true); + keypad(Console::InputWindow, true); + + if (has_colors()) + { + start_color(); + init_pair(1, COLOR_BLACK, COLOR_WHITE); + init_pair(2, COLOR_WHITE, COLOR_BLACK); + init_pair(3, COLOR_RED, COLOR_BLACK); + init_pair(4, COLOR_GREEN, COLOR_BLACK); + init_pair(5, COLOR_YELLOW, COLOR_BLACK); + init_pair(6, COLOR_BLUE, COLOR_BLACK); + init_pair(7, COLOR_CYAN, COLOR_BLACK); + init_pair(8, COLOR_RED, COLOR_BLACK); + init_pair(9, COLOR_WHITE, COLOR_BLACK); + init_pair(10, COLOR_WHITE, COLOR_BLACK); + } + + wbkgd(Console::InfoWindow, COLOR_PAIR(1)); + + wrefresh(Console::InfoWindow); + wrefresh(Console::InputWindow); + + Console::RefreshOutput(); + } + + void Console::Error(const char* format, ...) + { + static char buffer[32768]; + + va_list va; + va_start(va, format); + _vsnprintf_s(buffer, sizeof(buffer), format, va); + va_end(va); + + Game::Com_Printf(0, "ERROR:\n"); + Game::Com_Printf(0, buffer); + + Console::RefreshOutput(); + + if (IsDebuggerPresent()) + { + while (true) + { + std::this_thread::sleep_for(5s); + } + } + + TerminateProcess(GetCurrentProcess(), 0xDEADDEAD); + } + + void Console::Print(const char* message) + { + if (!Console::OutputWindow) return; + + const char* p = message; + while (*p != '\0') + { + if (*p == '\n') + { + Console::ScrollOutput(1); + } + + if (*p == '^') + { + char color; + ++p; + + color = (*p - '0'); + + if (color < 9 && color > 0) + { + wattron(Console::OutputWindow, COLOR_PAIR(color + 2)); + ++p; + continue; + } + } + + waddch(Console::OutputWindow, *p); + + ++p; + } + + wattron(Console::OutputWindow, COLOR_PAIR(9)); + +// int currentTime = static_cast(GetTickCount64()); // Make our compiler happy +// +// if (!Console::HasConsole) +// { +// Console::RefreshOutput(); +// } +// else if ((currentTime - Console::LastRefresh) > 100) +// { +// Console::RefreshOutput(); +// Console::LastRefresh = currentTime; +// } + + Console::RefreshOutput(); + } + + void Console::ConsoleRunner() + { + Game::Sys_ShowConsole(); + + MSG message; + while (IsWindow(*reinterpret_cast(0x64A3288)) != FALSE && GetMessageA(&message, 0, 0, 0)) + { + TranslateMessage(&message); + DispatchMessageA(&message); + } + + if (Game::Sys_Milliseconds() - Console::LastRefresh > 100 && + MessageBoxA(0, "The application is not responding anymore, do you want to force its termination?", "Application is not responding", MB_ICONEXCLAMATION | MB_YESNO) == IDYES) + { + // Force process termination + // if the main thread is not responding + OutputDebugStringA("Process termination forced, as the main thread is not responding!"); + + // We can not force the termination in this thread + // The destructor would be called in this thread + // and would try to join this thread, which is impossible + std::async([] () + { + std::this_thread::sleep_for(200ms); + ExitProcess(static_cast(-1)); + }); + } + else + { + // Send quit command to safely terminate the application + Command::Execute("wait 200;quit\n", false); + } + } + + void Console::StdOutPrint(const char* message) + { + printf("%s", message); + fflush(stdout); + } + + void Console::StdOutError(const char* format, ...) + { + char buffer[0x1000] = { 0 }; + + va_list ap; + va_start(ap, format); + _vsnprintf_s(buffer, sizeof(buffer), format, ap); + va_end(ap); + + perror(buffer); + fflush(stderr); + + ExitProcess(1); + } + + void __declspec(naked) Console::DrawSolidConsoleStub() + { + __asm + { + pushad + call Console::StoreSafeArea + popad + + // We need esi preserved here, so we have to backup 'all' registers when storing the safearea + call Game::Con_DrawSolidConsole + + call Console::RestoreSafeArea + retn + } + } + + void Console::StoreSafeArea() + { + // Backup the original safe area + Console::OriginalSafeArea = *Game::safeArea; + + // Apply new safe area and border + float border = 6.0f; + Game::safeArea->top = border; + Game::safeArea->left = border; + Game::safeArea->bottom = static_cast(Renderer::Height()) - border; + Game::safeArea->right = static_cast(Renderer::Width()) - border; + + Game::safeArea->textHeight = static_cast((Game::safeArea->bottom - Game::safeArea->top - (2 * Game::safeArea->fontHeight) - 24.0) / Game::safeArea->fontHeight); + Game::safeArea->textWidth = static_cast(Game::safeArea->right - Game::safeArea->left - 10.0f - 18.0); + } + + void Console::RestoreSafeArea() + { + // Restore the initial safe area + *Game::safeArea = Console::OriginalSafeArea; + } + + Console::Console() + { + // Console '%s: %s> ' string + Utils::Hook::Set(0x5A44B4, "IW4x: r" REVISION_STR "> "); + + // Internal console + Utils::Hook(0x4F690C, Console::ToggleConsole, HOOK_CALL).Install()->Quick(); + Utils::Hook(0x4F65A5, Console::ToggleConsole, HOOK_JUMP).Install()->Quick(); + + // Patch safearea for ingame-console + Utils::Hook(0x5A50EF, Console::DrawSolidConsoleStub, HOOK_CALL).Install()->Quick(); + + // Check for bad food ;) + Utils::Hook(0x4CB9F4, Console::GetAutoCompleteFileList, HOOK_CALL).Install()->Quick(); + + // Modify console style + Utils::Hook::Set(0x428A8E, 0); // Adjust logo Y pos + Utils::Hook::Set(0x428A90, 0); // Adjust logo X pos + Utils::Hook::Set(0x428AF2, 67); // Adjust output Y pos + Utils::Hook::Set(0x428AC5, 397); // Adjust input Y pos + Utils::Hook::Set(0x428951, 609); // Reduce window width + Utils::Hook::Set(0x42895D, 423); // Reduce window height + Utils::Hook::Set(0x428AC0, 597); // Reduce input width + Utils::Hook::Set(0x428AED, 596); // Reduce output width + + // Don't resize the console + Utils::Hook(0x64DC6B, 0x64DCC2, HOOK_JUMP).Install()->Quick(); + + // Code below is not necessary, when performing unit tests! + if (Loader::PerformingUnitTests()) return; + + // External console + if (Flags::HasFlag("stdout")) + { + Utils::Hook(0x4B2080, Console::StdOutPrint, HOOK_JUMP).Install()->Quick(); + Utils::Hook(0x43D570, Console::StdOutError, HOOK_JUMP).Install()->Quick(); + } + else if (Flags::HasFlag("console") || ZoneBuilder::IsEnabled()) // ZoneBuilder uses the game's console, until the native one is adapted. + { + FreeConsole(); + Utils::Hook::Nop(0x60BB58, 11); + + Utils::Hook(0x60BB68, [] () + { + Console::ConsoleThread = std::thread(Console::ConsoleRunner); + }, HOOK_CALL).Install()->Quick(); + + QuickPatch::OnFrame([] () + { + Console::LastRefresh = Game::Sys_Milliseconds(); + }); + } + else if (Dedicated::IsDedicated()/* || ZoneBuilder::IsEnabled()*/) + { + Utils::Hook::Nop(0x60BB58, 11); + + Utils::Hook(0x4305E0, Console::Create, HOOK_JUMP).Install()->Quick(); + Utils::Hook(0x4528A0, Console::Destroy, HOOK_JUMP).Install()->Quick(); + Utils::Hook(0x4B2080, Console::Print, HOOK_JUMP).Install()->Quick(); + Utils::Hook(0x43D570, Console::Error, HOOK_JUMP).Install()->Quick(); + Utils::Hook(0x4859A5, Console::Input, HOOK_CALL).Install()->Quick(); + } + else + { + FreeConsole(); + } + } + + Console::~Console() + { + if (Console::ConsoleThread.joinable()) + { + Console::ConsoleThread.join(); + } + } +} diff --git a/src/Components/Modules/Exception.cpp b/src/Components/Modules/Exception.cpp index b317cef7..cf2ce4d9 100644 --- a/src/Components/Modules/Exception.cpp +++ b/src/Components/Modules/Exception.cpp @@ -13,11 +13,11 @@ namespace Components { char filename[MAX_PATH]; __time64_t time; - tm* ltime; + tm ltime; _time64(&time); - ltime = _localtime64(&time); - strftime(filename, sizeof(filename) - 1, "iw4x-" VERSION_STR "-%Y%m%d%H%M%S.dmp", ltime); + _localtime64_s(<ime, &time); + strftime(filename, sizeof(filename) - 1, "iw4x-" VERSION_STR "-%Y%m%d%H%M%S.dmp", <ime); HANDLE hFile = CreateFileA(filename, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); diff --git a/src/Components/Modules/Logger.cpp b/src/Components/Modules/Logger.cpp index d210865e..77729c3e 100644 --- a/src/Components/Modules/Logger.cpp +++ b/src/Components/Modules/Logger.cpp @@ -1,155 +1,155 @@ -#include "STDInclude.hpp" - -namespace Components -{ - std::mutex Logger::MessageMutex; - std::vector Logger::MessageQueue; - void(*Logger::PipeCallback)(std::string) = nullptr; - - bool Logger::IsConsoleReady() - { - return (IsWindow(*reinterpret_cast(0x64A3288)) != FALSE || (Dedicated::IsDedicated() && !Flags::HasFlag("console"))); - } - - void Logger::Print(const char* message, ...) - { - return Logger::MessagePrint(0, Logger::Format(&message)); - } - - void Logger::Print(int channel, const char* message, ...) - { - return Logger::MessagePrint(channel, Logger::Format(&message)); - } - - void Logger::MessagePrint(int channel, std::string message) - { - if (Flags::HasFlag("stdout") || Loader::PerformingUnitTests()) - { - printf("%s", message.data()); - fflush(stdout); - return; - } - - if (!Logger::IsConsoleReady()) - { - OutputDebugStringA(message.data()); - } - - if (!Game::Sys_IsMainThread()) - { - Logger::EnqueueMessage(message); - } - else - { - Game::Com_PrintMessage(0, message.data(), 0); - } - } - - void Logger::ErrorPrint(int error, std::string message) - { - return Game::Com_Error(error, "%s", message.data()); - } - - void Logger::Error(int error, const char* message, ...) - { - return Logger::ErrorPrint(error, Logger::Format(&message)); - } - - void Logger::Error(const char* message, ...) - { - return Logger::ErrorPrint(0, Logger::Format(&message)); - } - - void Logger::SoftError(const char* message, ...) - { - return Logger::ErrorPrint(2, Logger::Format(&message)); - } - - std::string Logger::Format(const char** message) - { - char buffer[0x1000] = { 0 }; - - va_list ap = reinterpret_cast(const_cast(&message[1])); - //va_start(ap, *message); - _vsnprintf(buffer, sizeof(buffer), *message, ap); - va_end(ap); - - return buffer; - } - - void Logger::Frame() - { - Logger::MessageMutex.lock(); - - for (unsigned int i = 0; i < Logger::MessageQueue.size(); ++i) - { - Game::Com_PrintMessage(0, Logger::MessageQueue[i].data(), 0); - - if (!Logger::IsConsoleReady()) - { - OutputDebugStringA(Logger::MessageQueue[i].data()); - } - } - - Logger::MessageQueue.clear(); - Logger::MessageMutex.unlock(); - } - - void Logger::PipeOutput(void(*callback)(std::string)) - { - Logger::PipeCallback = callback; - } - - void Logger::PrintMessagePipe(const char* data) - { - if (Logger::PipeCallback) - { - Logger::PipeCallback(data); - } - } - - void __declspec(naked) Logger::PrintMessageStub() - { - __asm - { - mov eax, Logger::PipeCallback - test eax, eax - jz returnPrint - - push [esp + 8h] - call Logger::PrintMessagePipe - add esp, 4h - retn - - returnPrint: - push esi - mov esi, [esp + 0Ch] - - mov eax, 4AA835h - jmp eax - } - } - - void Logger::EnqueueMessage(std::string message) - { - Logger::MessageMutex.lock(); - Logger::MessageQueue.push_back(message); - Logger::MessageMutex.unlock(); - } - - Logger::Logger() - { - Logger::PipeOutput(nullptr); - - QuickPatch::OnFrame(Logger::Frame); - - Utils::Hook(Game::Com_PrintMessage, Logger::PrintMessageStub, HOOK_JUMP).Install()->Quick(); - } - - Logger::~Logger() - { - Logger::MessageMutex.lock(); - Logger::MessageQueue.clear(); - Logger::MessageMutex.unlock(); - } -} +#include "STDInclude.hpp" + +namespace Components +{ + std::mutex Logger::MessageMutex; + std::vector Logger::MessageQueue; + void(*Logger::PipeCallback)(std::string) = nullptr; + + bool Logger::IsConsoleReady() + { + return (IsWindow(*reinterpret_cast(0x64A3288)) != FALSE || (Dedicated::IsDedicated() && !Flags::HasFlag("console"))); + } + + void Logger::Print(const char* message, ...) + { + return Logger::MessagePrint(0, Logger::Format(&message)); + } + + void Logger::Print(int channel, const char* message, ...) + { + return Logger::MessagePrint(channel, Logger::Format(&message)); + } + + void Logger::MessagePrint(int channel, std::string message) + { + if (Flags::HasFlag("stdout") || Loader::PerformingUnitTests()) + { + printf("%s", message.data()); + fflush(stdout); + return; + } + + if (!Logger::IsConsoleReady()) + { + OutputDebugStringA(message.data()); + } + + if (!Game::Sys_IsMainThread()) + { + Logger::EnqueueMessage(message); + } + else + { + Game::Com_PrintMessage(0, message.data(), 0); + } + } + + void Logger::ErrorPrint(int error, std::string message) + { + return Game::Com_Error(error, "%s", message.data()); + } + + void Logger::Error(int error, const char* message, ...) + { + return Logger::ErrorPrint(error, Logger::Format(&message)); + } + + void Logger::Error(const char* message, ...) + { + return Logger::ErrorPrint(0, Logger::Format(&message)); + } + + void Logger::SoftError(const char* message, ...) + { + return Logger::ErrorPrint(2, Logger::Format(&message)); + } + + std::string Logger::Format(const char** message) + { + char buffer[0x1000] = { 0 }; + + va_list ap = reinterpret_cast(const_cast(&message[1])); + //va_start(ap, *message); + _vsnprintf_s(buffer, sizeof(buffer), *message, ap); + va_end(ap); + + return buffer; + } + + void Logger::Frame() + { + Logger::MessageMutex.lock(); + + for (unsigned int i = 0; i < Logger::MessageQueue.size(); ++i) + { + Game::Com_PrintMessage(0, Logger::MessageQueue[i].data(), 0); + + if (!Logger::IsConsoleReady()) + { + OutputDebugStringA(Logger::MessageQueue[i].data()); + } + } + + Logger::MessageQueue.clear(); + Logger::MessageMutex.unlock(); + } + + void Logger::PipeOutput(void(*callback)(std::string)) + { + Logger::PipeCallback = callback; + } + + void Logger::PrintMessagePipe(const char* data) + { + if (Logger::PipeCallback) + { + Logger::PipeCallback(data); + } + } + + void __declspec(naked) Logger::PrintMessageStub() + { + __asm + { + mov eax, Logger::PipeCallback + test eax, eax + jz returnPrint + + push [esp + 8h] + call Logger::PrintMessagePipe + add esp, 4h + retn + + returnPrint: + push esi + mov esi, [esp + 0Ch] + + mov eax, 4AA835h + jmp eax + } + } + + void Logger::EnqueueMessage(std::string message) + { + Logger::MessageMutex.lock(); + Logger::MessageQueue.push_back(message); + Logger::MessageMutex.unlock(); + } + + Logger::Logger() + { + Logger::PipeOutput(nullptr); + + QuickPatch::OnFrame(Logger::Frame); + + Utils::Hook(Game::Com_PrintMessage, Logger::PrintMessageStub, HOOK_JUMP).Install()->Quick(); + } + + Logger::~Logger() + { + Logger::MessageMutex.lock(); + Logger::MessageQueue.clear(); + Logger::MessageMutex.unlock(); + } +} diff --git a/src/Components/Modules/Maps.cpp b/src/Components/Modules/Maps.cpp index a0f0b5c1..9a8e8d38 100644 --- a/src/Components/Modules/Maps.cpp +++ b/src/Components/Modules/Maps.cpp @@ -118,7 +118,7 @@ namespace Components AntiCheat::EmptyHash(); - _snprintf(buffer, size, format, mapname); + _snprintf_s(buffer, size, size, format, mapname); } void Maps::AddDependency(std::string expression, std::string zone) diff --git a/src/Components/Modules/Menus.cpp b/src/Components/Modules/Menus.cpp index d95e5b9c..9368dd62 100644 --- a/src/Components/Modules/Menus.cpp +++ b/src/Components/Modules/Menus.cpp @@ -45,7 +45,7 @@ namespace Components Game::Script_SetupTokens(script, reinterpret_cast(0x797F80)); script->punctuations = reinterpret_cast(0x797F80); - strcpy(script->buffer, buffer.data()); + memcpy(script->buffer, buffer.data(), script->length + 1); script->length = Game::Script_CleanString(script->buffer); @@ -75,7 +75,7 @@ namespace Components return 0; } - strncpy(source->filename, "string", 64); + strncpy_s(source->filename, 64, "string", 64); source->scriptstack = script; source->tokens = NULL; source->defines = NULL; diff --git a/src/Components/Modules/QuickPatch.cpp b/src/Components/Modules/QuickPatch.cpp index 05aeb6b2..46416daf 100644 --- a/src/Components/Modules/QuickPatch.cpp +++ b/src/Components/Modules/QuickPatch.cpp @@ -305,6 +305,7 @@ namespace Components Utils::Hook::Nop(0x6830B1, 20); Utils::Hook(0x682EBF, QuickPatch::GetStatsID, HOOK_CALL).Install()->Quick(); Utils::Hook(0x6830B1, QuickPatch::GetStatsID, HOOK_CALL).Install()->Quick(); + //Utils::Hook::Set(0x68323A, 0xEB); // Exploit fixes Utils::Hook(0x414D92, QuickPatch::MsgReadBitsCompressCheckSV, HOOK_CALL).Install()->Quick(); diff --git a/src/Components/Modules/Script.cpp b/src/Components/Modules/Script.cpp index 431d799d..8550c0de 100644 --- a/src/Components/Modules/Script.cpp +++ b/src/Components/Modules/Script.cpp @@ -144,7 +144,7 @@ namespace Components char msgbuf[1024] = { 0 }; va_list v; va_start(v, message); - _vsnprintf(msgbuf, sizeof(msgbuf), message, v); + _vsnprintf_s(msgbuf, sizeof(msgbuf), message, v); va_end(v); Game::Scr_ShutdownAllocNode(); diff --git a/src/Components/Modules/Theatre.cpp b/src/Components/Modules/Theatre.cpp index 96e5fc8f..cbe4c4aa 100644 --- a/src/Components/Modules/Theatre.cpp +++ b/src/Components/Modules/Theatre.cpp @@ -271,12 +271,17 @@ namespace Components Theatre::DemoContainer.CurrentSelection = index; Theatre::Container::DemoInfo info = Theatre::DemoContainer.Demos[index]; + tm time; + char buffer[1000] = { 0 }; + localtime_s(&time, &info.TimeStamp); + asctime_s(buffer, sizeof buffer, &time); + Dvar::Var("ui_demo_mapname").Set(info.Mapname); Dvar::Var("ui_demo_mapname_localized").Set(Game::UI_LocalizeMapName(info.Mapname.data())); Dvar::Var("ui_demo_gametype").Set(Game::UI_LocalizeGameType(info.Gametype.data())); Dvar::Var("ui_demo_length").Set(Utils::String::FormatTimeSpan(info.Length)); Dvar::Var("ui_demo_author").Set(info.Author); - Dvar::Var("ui_demo_date").Set(std::asctime(std::localtime(&info.TimeStamp))); + Dvar::Var("ui_demo_date").Set(buffer); } } diff --git a/src/STDInclude.hpp b/src/STDInclude.hpp index aa8f515f..13dc02a3 100644 --- a/src/STDInclude.hpp +++ b/src/STDInclude.hpp @@ -8,7 +8,7 @@ // Disable irrelevant warnings #pragma warning(disable: 4100) // Unreferenced parameter (steam has to have them and other stubs as well, due to their calling convention) -#define _CRT_SECURE_NO_WARNINGS +#define VC_EXTRALEAN #define WIN32_LEAN_AND_MEAN #include diff --git a/src/Steam/Interfaces/SteamUtils.cpp b/src/Steam/Interfaces/SteamUtils.cpp index 84831165..67216b7f 100644 --- a/src/Steam/Interfaces/SteamUtils.cpp +++ b/src/Steam/Interfaces/SteamUtils.cpp @@ -1,105 +1,97 @@ -#include "STDInclude.hpp" - -namespace Steam -{ - unsigned int Utils::GetSecondsSinceAppActive() - { - return 0; - } - - unsigned int Utils::GetSecondsSinceComputerActive() - { - return 0; - } - - int Utils::GetConnectedUniverse() - { - return 1; - } - - unsigned int Utils::GetServerRealTime() - { - return 0; - } - - const char* Utils::GetIPCountry() - { - return "US"; - } - - bool Utils::GetImageSize(int iImage, unsigned int *pnWidth, unsigned int *pnHeight) - { - return false; - } - - bool Utils::GetImageRGBA(int iImage, unsigned char *pubDest, int nDestBufferSize) - { - return false; - } - - bool Utils::GetCSERIPPort(unsigned int *unIP, unsigned short *usPort) - { - return false; - } - - unsigned char Utils::GetCurrentBatteryPower() - { - return 255; - } - - unsigned int Utils::GetAppID() - { - return 10190; - } - - void Utils::SetOverlayNotificationPosition(int eNotificationPosition) - { - if (Steam::Overlay) - { - FARPROC setPosition = GetProcAddress(Steam::Overlay, "SetNotificationPosition"); - - if (setPosition) - { - ::Utils::Hook::Call(setPosition)(eNotificationPosition); - } - } - } - - bool Utils::IsAPICallCompleted(unsigned __int64 hSteamAPICall, bool *pbFailed) - { - return false; - } - - int Utils::GetAPICallFailureReason(unsigned __int64 hSteamAPICall) - { - return -1; - } - - bool Utils::GetAPICallResult(unsigned __int64 hSteamAPICall, void *pCallback, int cubCallback, int iCallbackExpected, bool *pbFailed) - { - return false; - } - - void Utils::RunFrame() - { - } - - unsigned int Utils::GetIPCCallCount() - { - return 0; - } - - void Utils::SetWarningMessageHook(void(*pFunction)(int hpipe, const char *message)) - { - } - - bool Utils::IsOverlayEnabled() - { - return false; - } - - bool Utils::BOverlayNeedsPresent() - { - return false; - } -} +#include "STDInclude.hpp" + +namespace Steam +{ + unsigned int Utils::GetSecondsSinceAppActive() + { + return 0; + } + + unsigned int Utils::GetSecondsSinceComputerActive() + { + return 0; + } + + int Utils::GetConnectedUniverse() + { + return 1; + } + + unsigned int Utils::GetServerRealTime() + { + return 0; + } + + const char* Utils::GetIPCountry() + { + return "US"; + } + + bool Utils::GetImageSize(int iImage, unsigned int *pnWidth, unsigned int *pnHeight) + { + return false; + } + + bool Utils::GetImageRGBA(int iImage, unsigned char *pubDest, int nDestBufferSize) + { + return false; + } + + bool Utils::GetCSERIPPort(unsigned int *unIP, unsigned short *usPort) + { + return false; + } + + unsigned char Utils::GetCurrentBatteryPower() + { + return 255; + } + + unsigned int Utils::GetAppID() + { + return 10190; + } + + void Utils::SetOverlayNotificationPosition(int eNotificationPosition) + { + Proxy::SetOverlayNotificationPosition(eNotificationPosition); + } + + bool Utils::IsAPICallCompleted(unsigned __int64 hSteamAPICall, bool *pbFailed) + { + return false; + } + + int Utils::GetAPICallFailureReason(unsigned __int64 hSteamAPICall) + { + return -1; + } + + bool Utils::GetAPICallResult(unsigned __int64 hSteamAPICall, void *pCallback, int cubCallback, int iCallbackExpected, bool *pbFailed) + { + return false; + } + + void Utils::RunFrame() + { + } + + unsigned int Utils::GetIPCCallCount() + { + return 0; + } + + void Utils::SetWarningMessageHook(void(*pFunction)(int hpipe, const char *message)) + { + } + + bool Utils::IsOverlayEnabled() + { + return false; + } + + bool Utils::BOverlayNeedsPresent() + { + return false; + } +} diff --git a/src/Steam/Proxy.cpp b/src/Steam/Proxy.cpp new file mode 100644 index 00000000..910aa621 --- /dev/null +++ b/src/Steam/Proxy.cpp @@ -0,0 +1,88 @@ +#include "STDInclude.hpp" + +namespace Steam +{ + HMODULE Proxy::Client = nullptr; + HMODULE Proxy::Overlay = nullptr; + + bool Proxy::Inititalize() + { + std::string directoy = Proxy::GetSteamDirectory(); + if (directoy.empty()) return false; + + SetDllDirectoryA(Proxy::GetSteamDirectory().data()); + + Proxy::Client = LoadLibraryA(STEAMCLIENT_LIB); + Proxy::Overlay = LoadLibraryA(GAMEOVERLAY_LIB); + + return (Proxy::Client && Proxy::Overlay); + } + + void Proxy::Uninititalize() + { + if (Proxy::Client) FreeLibrary(Proxy::Client); + Proxy::Client = nullptr; + + if (Proxy::Overlay) FreeLibrary(Proxy::Overlay); + Proxy::Overlay = nullptr; + } + + std::string Proxy::GetSteamDirectory() + { + HKEY hRegKey; + char SteamPath[MAX_PATH]; + if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, STEAM_REGISTRY_PATH, 0, KEY_QUERY_VALUE, &hRegKey) == ERROR_SUCCESS) + { + DWORD dwLength = sizeof(SteamPath); + RegQueryValueExA(hRegKey, "InstallPath", NULL, NULL, reinterpret_cast(SteamPath), &dwLength); + RegCloseKey(hRegKey); + + return SteamPath; + } + + return ""; + } + + void Proxy::SetOverlayNotificationPosition(uint32_t eNotificationPosition) + { + if (Proxy::Overlay) + { + FARPROC SetNotificationPositionFn = GetProcAddress(Proxy::Overlay, "SetNotificationPosition"); + + if (SetNotificationPositionFn) + { + ::Utils::Hook::Call(SetNotificationPositionFn)(eNotificationPosition); + } + } + } + + bool Proxy::IsOverlayEnabled() + { + if (Proxy::Overlay) + { + FARPROC IsOverlayEnabledFn = GetProcAddress(Proxy::Overlay, "IsOverlayEnabled"); + + if (IsOverlayEnabledFn) + { + return ::Utils::Hook::Call(IsOverlayEnabledFn)(); + } + } + + return false; + } + + bool Proxy::BOverlayNeedsPresent() + { + if (Proxy::Overlay) + { + FARPROC BOverlayNeedsPresentFn = GetProcAddress(Proxy::Overlay, "BOverlayNeedsPresent"); + + if (BOverlayNeedsPresentFn) + { + return ::Utils::Hook::Call(BOverlayNeedsPresentFn)(); + } + } + + return false; + } +} diff --git a/src/Steam/Proxy.hpp b/src/Steam/Proxy.hpp new file mode 100644 index 00000000..ac3792a0 --- /dev/null +++ b/src/Steam/Proxy.hpp @@ -0,0 +1,30 @@ +#ifdef _WIN64 +#define GAMEOVERLAY_LIB "gameoverlayrenderer64.dll" +#define STEAMCLIENT_LIB "steamclient64.dll" +#define STEAM_REGISTRY_PATH "Software\\Wow6432Node\\Valve\\Steam" +#else +#define GAMEOVERLAY_LIB "gameoverlayrenderer.dll" +#define STEAMCLIENT_LIB "steamclient.dll" +#define STEAM_REGISTRY_PATH "Software\\Valve\\Steam" +#endif + +namespace Steam +{ + class Proxy + { + public: + static bool Inititalize(); + static void Uninititalize(); + + //Overlay related proxies + static void SetOverlayNotificationPosition(uint32_t eNotificationPosition); + static bool IsOverlayEnabled(); + static bool BOverlayNeedsPresent(); + + private: + static HMODULE Client; + static HMODULE Overlay; + + static std::string GetSteamDirectory(); + }; +} diff --git a/src/Steam/Steam.cpp b/src/Steam/Steam.cpp index 55aed87b..7c6c0222 100644 --- a/src/Steam/Steam.cpp +++ b/src/Steam/Steam.cpp @@ -2,8 +2,6 @@ namespace Steam { - HMODULE Overlay = 0; - uint64_t Callbacks::CallID = 0; std::map Callbacks::Calls; std::map Callbacks::ResultHandlers; @@ -71,22 +69,9 @@ namespace Steam { bool SteamAPI_Init() { - Overlay = GetModuleHandleA("gameoverlayrenderer.dll"); - - if (!Overlay) + if (!Proxy::Inititalize()) { - HKEY hRegKey; - if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, "Software\\Valve\\Steam", 0, KEY_QUERY_VALUE, &hRegKey) == ERROR_SUCCESS) - { - char steamPath[MAX_PATH] = { 0 }; - DWORD dwLength = sizeof(steamPath); - RegQueryValueExA(hRegKey, "InstallPath", NULL, NULL, reinterpret_cast(steamPath), &dwLength); - RegCloseKey(hRegKey); - - SetDllDirectoryA(steamPath); - - Overlay = LoadLibraryA(::Utils::String::VA("%s\\%s", steamPath, "gameoverlayrenderer.dll")); - } + OutputDebugStringA("Steamproxy not initialized properly"); } return true; @@ -109,6 +94,7 @@ namespace Steam void SteamAPI_Shutdown() { + Proxy::Uninititalize(); } void SteamAPI_UnregisterCallResult() diff --git a/src/Steam/Steam.hpp b/src/Steam/Steam.hpp index 0c51403c..59aa1603 100644 --- a/src/Steam/Steam.hpp +++ b/src/Steam/Steam.hpp @@ -1,93 +1,93 @@ -#pragma once - -#define STEAM_EXPORT extern "C" __declspec(dllexport) - -typedef union -{ - struct - { - unsigned int AccountID : 32; - unsigned int AccountInstance : 20; - unsigned int AccountType : 4; - int Universe : 8; - }; - - unsigned long long Bits; -} SteamID; - -#include "Interfaces\SteamUser.hpp" -#include "Interfaces\SteamUtils.hpp" -#include "Interfaces\SteamFriends.hpp" -#include "Interfaces\SteamGameServer.hpp" -#include "Interfaces\SteamNetworking.hpp" -#include "Interfaces\SteamMatchmaking.hpp" -#include "Interfaces\SteamRemoteStorage.hpp" -#include "Interfaces\SteamMasterServerUpdater.hpp" - -namespace Steam -{ - class Callbacks - { - public: - class Base - { - public: - Base() : Flags(0), Callback(0) {}; - - virtual void Run(void *pvParam) = 0; - virtual void Run(void *pvParam, bool bIOFailure, uint64_t hSteamAPICall) = 0; - virtual int GetCallbackSizeBytes() = 0; - - int GetICallback() { return Callback; } - void SetICallback(int iCallback) { Callback = iCallback; } - - protected: - unsigned char Flags; - int Callback; - }; - - struct Result - { - void* data; - int size; - int type; - uint64_t call; - }; - - static uint64_t RegisterCall(); - static void RegisterCallback(Base* handler, int callback); - static void RegisterCallResult(uint64_t call, Base* result); - static void ReturnCall(void* data, int size, int type, uint64_t call); - static void RunCallbacks(); - - private: - static uint64_t CallID; - static std::map Calls; - static std::map ResultHandlers; - static std::vector Results; - static std::vector CallbackList; - }; - - STEAM_EXPORT bool SteamAPI_Init(); - STEAM_EXPORT void SteamAPI_RegisterCallResult(Callbacks::Base* result, uint64_t call); - STEAM_EXPORT void SteamAPI_RegisterCallback(Callbacks::Base* handler, int callback); - STEAM_EXPORT void SteamAPI_RunCallbacks(); - STEAM_EXPORT void SteamAPI_Shutdown(); - STEAM_EXPORT void SteamAPI_UnregisterCallResult(); - STEAM_EXPORT void SteamAPI_UnregisterCallback(); - - STEAM_EXPORT bool SteamGameServer_Init(); - STEAM_EXPORT void SteamGameServer_RunCallbacks(); - STEAM_EXPORT void SteamGameServer_Shutdown(); - - STEAM_EXPORT Steam::Friends* SteamFriends(); - STEAM_EXPORT Steam::Matchmaking* SteamMatchmaking(); - STEAM_EXPORT Steam::GameServer* SteamGameServer(); - STEAM_EXPORT Steam::MasterServerUpdater* SteamMasterServerUpdater(); - STEAM_EXPORT Steam::Networking* SteamNetworking(); - STEAM_EXPORT Steam::RemoteStorage* SteamRemoteStorage(); - STEAM_EXPORT Steam::User* SteamUser(); - STEAM_EXPORT Steam::Utils* SteamUtils(); - - extern HMODULE Overlay; -} +#pragma once + +#define STEAM_EXPORT extern "C" __declspec(dllexport) + +typedef union +{ + struct + { + unsigned int AccountID : 32; + unsigned int AccountInstance : 20; + unsigned int AccountType : 4; + int Universe : 8; + }; + + unsigned long long Bits; +} SteamID; + +#include "Interfaces\SteamUser.hpp" +#include "Interfaces\SteamUtils.hpp" +#include "Interfaces\SteamFriends.hpp" +#include "Interfaces\SteamGameServer.hpp" +#include "Interfaces\SteamNetworking.hpp" +#include "Interfaces\SteamMatchmaking.hpp" +#include "Interfaces\SteamRemoteStorage.hpp" +#include "Interfaces\SteamMasterServerUpdater.hpp" + +#include "Proxy.hpp" + +namespace Steam +{ + class Callbacks + { + public: + class Base + { + public: + Base() : Flags(0), Callback(0) {}; + + virtual void Run(void *pvParam) = 0; + virtual void Run(void *pvParam, bool bIOFailure, uint64_t hSteamAPICall) = 0; + virtual int GetCallbackSizeBytes() = 0; + + int GetICallback() { return Callback; } + void SetICallback(int iCallback) { Callback = iCallback; } + + protected: + unsigned char Flags; + int Callback; + }; + + struct Result + { + void* data; + int size; + int type; + uint64_t call; + }; + + static uint64_t RegisterCall(); + static void RegisterCallback(Base* handler, int callback); + static void RegisterCallResult(uint64_t call, Base* result); + static void ReturnCall(void* data, int size, int type, uint64_t call); + static void RunCallbacks(); + + private: + static uint64_t CallID; + static std::map Calls; + static std::map ResultHandlers; + static std::vector Results; + static std::vector CallbackList; + }; + + STEAM_EXPORT bool SteamAPI_Init(); + STEAM_EXPORT void SteamAPI_RegisterCallResult(Callbacks::Base* result, uint64_t call); + STEAM_EXPORT void SteamAPI_RegisterCallback(Callbacks::Base* handler, int callback); + STEAM_EXPORT void SteamAPI_RunCallbacks(); + STEAM_EXPORT void SteamAPI_Shutdown(); + STEAM_EXPORT void SteamAPI_UnregisterCallResult(); + STEAM_EXPORT void SteamAPI_UnregisterCallback(); + + STEAM_EXPORT bool SteamGameServer_Init(); + STEAM_EXPORT void SteamGameServer_RunCallbacks(); + STEAM_EXPORT void SteamGameServer_Shutdown(); + + STEAM_EXPORT Steam::Friends* SteamFriends(); + STEAM_EXPORT Steam::Matchmaking* SteamMatchmaking(); + STEAM_EXPORT Steam::GameServer* SteamGameServer(); + STEAM_EXPORT Steam::MasterServerUpdater* SteamMasterServerUpdater(); + STEAM_EXPORT Steam::Networking* SteamNetworking(); + STEAM_EXPORT Steam::RemoteStorage* SteamRemoteStorage(); + STEAM_EXPORT Steam::User* SteamUser(); + STEAM_EXPORT Steam::Utils* SteamUtils(); +} diff --git a/src/Utils/Hooking.cpp b/src/Utils/Hooking.cpp index a4c5ef7b..206300bf 100644 --- a/src/Utils/Hooking.cpp +++ b/src/Utils/Hooking.cpp @@ -1,257 +1,257 @@ -#include "STDInclude.hpp" - -namespace Utils -{ - std::map Hook::Interceptor::IReturn; - std::map Hook::Interceptor::ICallbacks; - - void Hook::Signature::Process() - { - if (Hook::Signature::Signatures.empty()) return; - - char* start = reinterpret_cast(Hook::Signature::Start); - - unsigned int sigCount = Hook::Signature::Signatures.size(); - Hook::Signature::Container* containers = Hook::Signature::Signatures.data(); - - for (size_t i = 0; i < Hook::Signature::Length; ++i) - { - char* address = start + i; - - for (unsigned int k = 0; k < sigCount; ++k) - { - Hook::Signature::Container* container = &containers[k]; - - unsigned int j = 0; - for (j = 0; j < strlen(container->Mask); ++j) - { - if (container->Mask[j] != '?' &&container->Signature[j] != address[j]) - { - break; - } - } - - if (j == strlen(container->Mask)) - { - container->Callback(address); - } - } - } - } - - void Hook::Signature::Add(Hook::Signature::Container& container) - { - Hook::Signature::Signatures.push_back(container); - } - - void Hook::Interceptor::Install(void* place, void(*stub)()) - { - return Hook::Interceptor::Install(reinterpret_cast(place), stub); - } - - void Hook::Interceptor::Install(void** place, void(*stub)()) - { - Hook::Interceptor::IReturn[place] = *place; - Hook::Interceptor::ICallbacks[place] = stub; - *place = Hook::Interceptor::InterceptionStub; - } - - void __declspec(naked) Hook::Interceptor::InterceptionStub() - { - __asm - { - sub esp, 4h // Reserve space on the stack for the return address - pushad // Store registers - - lea eax, [esp + 20h] // Load initial stack pointer - push eax // Push it onto the stack - - call RunCallback // Run the callback based on the given stack pointer - call PopReturn // Get the initial return address according to the stack pointer - - add esp, 4h // Clear the stack - - mov [esp + 20h], eax // Store the return address at the reserved space - popad // Restore the registers - - retn // Return (jump to our return address) - } - } - - void Hook::Interceptor::RunCallback(void* place) - { - auto iCallback = Hook::Interceptor::ICallbacks.find(place); - if (iCallback != Hook::Interceptor::ICallbacks.end()) - { - iCallback->second(); - Hook::Interceptor::ICallbacks.erase(iCallback); - } - } - - void* Hook::Interceptor::PopReturn(void* place) - { - void* retVal = nullptr; - - auto iReturn = Hook::Interceptor::IReturn.find(place); - if (iReturn != Hook::Interceptor::IReturn.end()) - { - retVal = iReturn->second; - Hook::Interceptor::IReturn.erase(iReturn); - } - - return retVal; - } - - Hook::~Hook() - { - if (Hook::Initialized) - { - Hook::Uninstall(); - } - } - - Hook* Hook::Initialize(DWORD place, void(*stub)(), bool useJump) - { - return Hook::Initialize(place, reinterpret_cast(stub), useJump); - } - - Hook* Hook::Initialize(DWORD place, void* stub, bool useJump) - { - return Hook::Initialize(reinterpret_cast(place), stub, useJump); - } - - Hook* Hook::Initialize(void* place, void* stub, bool useJump) - { - if (Hook::Initialized) return this; - Hook::Initialized = true; - - Hook::UseJump = useJump; - Hook::Place = place; - Hook::Stub = stub; - - Hook::Original = static_cast(Hook::Place) + 5 + *reinterpret_cast((static_cast(Hook::Place) + 1)); - - return this; - } - - Hook* Hook::Install(bool unprotect, bool keepUnportected) - { - Hook::StateMutex.lock(); - - if (!Hook::Initialized || Hook::Installed) - { - Hook::StateMutex.unlock(); - return this; - } - - Hook::Installed = true; - - if (unprotect) VirtualProtect(Hook::Place, sizeof(Hook::Buffer), PAGE_EXECUTE_READWRITE, &this->Protection); - std::memcpy(Hook::Buffer, Hook::Place, sizeof(Hook::Buffer)); - - char* code = static_cast(Hook::Place); - - *code = static_cast(Hook::UseJump ? 0xE9 : 0xE8); - - *reinterpret_cast(code + 1) = reinterpret_cast(Hook::Stub) - (reinterpret_cast(Hook::Place) + 5); - - if (unprotect && !keepUnportected) VirtualProtect(Hook::Place, sizeof(Hook::Buffer), Hook::Protection, &this->Protection); - - FlushInstructionCache(GetCurrentProcess(), Hook::Place, sizeof(Hook::Buffer)); - - Hook::StateMutex.unlock(); - - return this; - } - - void Hook::Quick() - { - if (Hook::Installed) - { - Hook::Installed = false; - } - } - - Hook* Hook::Uninstall(bool unprotect) - { - Hook::StateMutex.lock(); - - if (!Hook::Initialized || !Hook::Installed) - { - Hook::StateMutex.unlock(); - return this; - } - - Hook::Installed = false; - - if(unprotect) VirtualProtect(Hook::Place, sizeof(Hook::Buffer), PAGE_EXECUTE_READWRITE, &this->Protection); - - std::memcpy(Hook::Place, Hook::Buffer, sizeof(Hook::Buffer)); - - if (unprotect) VirtualProtect(Hook::Place, sizeof(Hook::Buffer), Hook::Protection, &this->Protection); - - FlushInstructionCache(GetCurrentProcess(), Hook::Place, sizeof(Hook::Buffer)); - - Hook::StateMutex.unlock(); - - return this; - } - - void* Hook::GetAddress() - { - return Hook::Place; - } - - void Hook::Nop(void* place, size_t length) - { - DWORD oldProtect; - VirtualProtect(place, length, PAGE_EXECUTE_READWRITE, &oldProtect); - - memset(place, 0x90, length); - - VirtualProtect(place, length, oldProtect, &oldProtect); - FlushInstructionCache(GetCurrentProcess(), place, length); - } - - void Hook::Nop(DWORD place, size_t length) - { - Nop(reinterpret_cast(place), length); - } - - void Hook::SetString(void* place, const char* string, size_t length) - { - DWORD oldProtect; - VirtualProtect(place, length + 1, PAGE_EXECUTE_READWRITE, &oldProtect); - - strncpy(static_cast(place), string, length); - - VirtualProtect(place, length + 1, oldProtect, &oldProtect); - } - - void Hook::SetString(DWORD place, const char* string, size_t length) - { - Hook::SetString(reinterpret_cast(place), string, length); - } - - void Hook::SetString(void* place, const char* string) - { - Hook::SetString(place, string, strlen(static_cast(place))); - } - - void Hook::SetString(DWORD place, const char* string) - { - Hook::SetString(reinterpret_cast(place), string); - } - - void Hook::RedirectJump(void* place, void* stub) - { - char* operandPtr = static_cast(place) + 2; - int newOperand = reinterpret_cast(stub) - (reinterpret_cast(place) + 6); - Utils::Hook::Set(operandPtr, newOperand); - } - - void Hook::RedirectJump(DWORD place, void* stub) - { - Hook::RedirectJump(reinterpret_cast(place), stub); - } -} +#include "STDInclude.hpp" + +namespace Utils +{ + std::map Hook::Interceptor::IReturn; + std::map Hook::Interceptor::ICallbacks; + + void Hook::Signature::Process() + { + if (Hook::Signature::Signatures.empty()) return; + + char* start = reinterpret_cast(Hook::Signature::Start); + + unsigned int sigCount = Hook::Signature::Signatures.size(); + Hook::Signature::Container* containers = Hook::Signature::Signatures.data(); + + for (size_t i = 0; i < Hook::Signature::Length; ++i) + { + char* address = start + i; + + for (unsigned int k = 0; k < sigCount; ++k) + { + Hook::Signature::Container* container = &containers[k]; + + unsigned int j = 0; + for (j = 0; j < strlen(container->Mask); ++j) + { + if (container->Mask[j] != '?' &&container->Signature[j] != address[j]) + { + break; + } + } + + if (j == strlen(container->Mask)) + { + container->Callback(address); + } + } + } + } + + void Hook::Signature::Add(Hook::Signature::Container& container) + { + Hook::Signature::Signatures.push_back(container); + } + + void Hook::Interceptor::Install(void* place, void(*stub)()) + { + return Hook::Interceptor::Install(reinterpret_cast(place), stub); + } + + void Hook::Interceptor::Install(void** place, void(*stub)()) + { + Hook::Interceptor::IReturn[place] = *place; + Hook::Interceptor::ICallbacks[place] = stub; + *place = Hook::Interceptor::InterceptionStub; + } + + void __declspec(naked) Hook::Interceptor::InterceptionStub() + { + __asm + { + sub esp, 4h // Reserve space on the stack for the return address + pushad // Store registers + + lea eax, [esp + 20h] // Load initial stack pointer + push eax // Push it onto the stack + + call RunCallback // Run the callback based on the given stack pointer + call PopReturn // Get the initial return address according to the stack pointer + + add esp, 4h // Clear the stack + + mov [esp + 20h], eax // Store the return address at the reserved space + popad // Restore the registers + + retn // Return (jump to our return address) + } + } + + void Hook::Interceptor::RunCallback(void* place) + { + auto iCallback = Hook::Interceptor::ICallbacks.find(place); + if (iCallback != Hook::Interceptor::ICallbacks.end()) + { + iCallback->second(); + Hook::Interceptor::ICallbacks.erase(iCallback); + } + } + + void* Hook::Interceptor::PopReturn(void* place) + { + void* retVal = nullptr; + + auto iReturn = Hook::Interceptor::IReturn.find(place); + if (iReturn != Hook::Interceptor::IReturn.end()) + { + retVal = iReturn->second; + Hook::Interceptor::IReturn.erase(iReturn); + } + + return retVal; + } + + Hook::~Hook() + { + if (Hook::Initialized) + { + Hook::Uninstall(); + } + } + + Hook* Hook::Initialize(DWORD place, void(*stub)(), bool useJump) + { + return Hook::Initialize(place, reinterpret_cast(stub), useJump); + } + + Hook* Hook::Initialize(DWORD place, void* stub, bool useJump) + { + return Hook::Initialize(reinterpret_cast(place), stub, useJump); + } + + Hook* Hook::Initialize(void* place, void* stub, bool useJump) + { + if (Hook::Initialized) return this; + Hook::Initialized = true; + + Hook::UseJump = useJump; + Hook::Place = place; + Hook::Stub = stub; + + Hook::Original = static_cast(Hook::Place) + 5 + *reinterpret_cast((static_cast(Hook::Place) + 1)); + + return this; + } + + Hook* Hook::Install(bool unprotect, bool keepUnportected) + { + Hook::StateMutex.lock(); + + if (!Hook::Initialized || Hook::Installed) + { + Hook::StateMutex.unlock(); + return this; + } + + Hook::Installed = true; + + if (unprotect) VirtualProtect(Hook::Place, sizeof(Hook::Buffer), PAGE_EXECUTE_READWRITE, &this->Protection); + std::memcpy(Hook::Buffer, Hook::Place, sizeof(Hook::Buffer)); + + char* code = static_cast(Hook::Place); + + *code = static_cast(Hook::UseJump ? 0xE9 : 0xE8); + + *reinterpret_cast(code + 1) = reinterpret_cast(Hook::Stub) - (reinterpret_cast(Hook::Place) + 5); + + if (unprotect && !keepUnportected) VirtualProtect(Hook::Place, sizeof(Hook::Buffer), Hook::Protection, &this->Protection); + + FlushInstructionCache(GetCurrentProcess(), Hook::Place, sizeof(Hook::Buffer)); + + Hook::StateMutex.unlock(); + + return this; + } + + void Hook::Quick() + { + if (Hook::Installed) + { + Hook::Installed = false; + } + } + + Hook* Hook::Uninstall(bool unprotect) + { + Hook::StateMutex.lock(); + + if (!Hook::Initialized || !Hook::Installed) + { + Hook::StateMutex.unlock(); + return this; + } + + Hook::Installed = false; + + if(unprotect) VirtualProtect(Hook::Place, sizeof(Hook::Buffer), PAGE_EXECUTE_READWRITE, &this->Protection); + + std::memcpy(Hook::Place, Hook::Buffer, sizeof(Hook::Buffer)); + + if (unprotect) VirtualProtect(Hook::Place, sizeof(Hook::Buffer), Hook::Protection, &this->Protection); + + FlushInstructionCache(GetCurrentProcess(), Hook::Place, sizeof(Hook::Buffer)); + + Hook::StateMutex.unlock(); + + return this; + } + + void* Hook::GetAddress() + { + return Hook::Place; + } + + void Hook::Nop(void* place, size_t length) + { + DWORD oldProtect; + VirtualProtect(place, length, PAGE_EXECUTE_READWRITE, &oldProtect); + + memset(place, 0x90, length); + + VirtualProtect(place, length, oldProtect, &oldProtect); + FlushInstructionCache(GetCurrentProcess(), place, length); + } + + void Hook::Nop(DWORD place, size_t length) + { + Nop(reinterpret_cast(place), length); + } + + void Hook::SetString(void* place, const char* string, size_t length) + { + DWORD oldProtect; + VirtualProtect(place, length + 1, PAGE_EXECUTE_READWRITE, &oldProtect); + + strncpy_s(static_cast(place), length, string, length); + + VirtualProtect(place, length + 1, oldProtect, &oldProtect); + } + + void Hook::SetString(DWORD place, const char* string, size_t length) + { + Hook::SetString(reinterpret_cast(place), string, length); + } + + void Hook::SetString(void* place, const char* string) + { + Hook::SetString(place, string, strlen(static_cast(place))); + } + + void Hook::SetString(DWORD place, const char* string) + { + Hook::SetString(reinterpret_cast(place), string); + } + + void Hook::RedirectJump(void* place, void* stub) + { + char* operandPtr = static_cast(place) + 2; + int newOperand = reinterpret_cast(stub) - (reinterpret_cast(place) + 6); + Utils::Hook::Set(operandPtr, newOperand); + } + + void Hook::RedirectJump(DWORD place, void* stub) + { + Hook::RedirectJump(reinterpret_cast(place), stub); + } +}