Merge pull request #22 from mjkzy/main
dark mode console, symbols, new logo, corrections
This commit is contained in:
commit
e2952e5905
@ -1,38 +1,29 @@
|
|||||||
#include <std_include.hpp>
|
#include <std_include.hpp>
|
||||||
#include "loader/component_loader.hpp"
|
#include "loader/component_loader.hpp"
|
||||||
|
#include "resource.hpp"
|
||||||
|
|
||||||
|
#include "game/game.hpp"
|
||||||
|
|
||||||
#include <utils/thread.hpp>
|
#include <utils/thread.hpp>
|
||||||
#include <utils/hook.hpp>
|
#include <utils/hook.hpp>
|
||||||
|
|
||||||
|
#define CONSOLE_BUFFER_SIZE 16384
|
||||||
|
|
||||||
namespace console
|
namespace console
|
||||||
{
|
{
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
volatile bool g_started = false;
|
volatile bool g_started = false;
|
||||||
|
HANDLE logo;
|
||||||
void create_game_console()
|
|
||||||
{
|
|
||||||
reinterpret_cast<void(*)()>(0x142333F80_g)();
|
|
||||||
}
|
|
||||||
|
|
||||||
void print_message(const char* message)
|
void print_message(const char* message)
|
||||||
{
|
{
|
||||||
if (g_started)
|
if (g_started)
|
||||||
{
|
{
|
||||||
reinterpret_cast<void(*)(int, int, const char*, ...)>(0x1421499C0_g)(0, 0, "%s", message);
|
game::Com_Printf(0, 0, "%s", message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void execute_command(const char* command)
|
|
||||||
{
|
|
||||||
reinterpret_cast<void(*)(int, const char*, ...)>(0x1420EC8B0_g)(0, command);
|
|
||||||
}
|
|
||||||
|
|
||||||
void terminate_game()
|
|
||||||
{
|
|
||||||
execute_command("quit\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
void print_stub(const char* fmt, ...)
|
void print_stub(const char* fmt, ...)
|
||||||
{
|
{
|
||||||
va_list ap;
|
va_list ap;
|
||||||
@ -45,6 +36,114 @@ namespace console
|
|||||||
|
|
||||||
va_end(ap);
|
va_end(ap);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LRESULT con_wnd_proc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
||||||
|
{
|
||||||
|
switch (uMsg)
|
||||||
|
{
|
||||||
|
case WM_CTLCOLORSTATIC:
|
||||||
|
SetBkColor((HDC)wParam, RGB(50, 50, 50));
|
||||||
|
SetTextColor((HDC)wParam, RGB(232, 230, 227));
|
||||||
|
return (INT_PTR)CreateSolidBrush(RGB(50, 50, 50));
|
||||||
|
case WM_CTLCOLOREDIT:
|
||||||
|
SetBkColor((HDC)wParam, RGB(50, 50, 50));
|
||||||
|
SetTextColor((HDC)wParam, RGB(232, 230, 227));
|
||||||
|
return (INT_PTR)CreateSolidBrush(RGB(50, 50, 50));
|
||||||
|
case WM_QUIT:
|
||||||
|
game::Cbuf_AddText(0, "quit\n");
|
||||||
|
return DefWindowProcA(hWnd, uMsg, wParam, lParam);
|
||||||
|
default:
|
||||||
|
return utils::hook::invoke<LRESULT>(0x142333520_g, hWnd, uMsg, wParam, lParam);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
LRESULT input_line_wnd_proc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
||||||
|
{
|
||||||
|
return utils::hook::invoke<LRESULT>(0x142333820_g, hWnd, uMsg, wParam, lParam);
|
||||||
|
}
|
||||||
|
|
||||||
|
void sys_create_console_stub(HINSTANCE hInstance)
|
||||||
|
{
|
||||||
|
// C6262
|
||||||
|
char text[CONSOLE_BUFFER_SIZE];
|
||||||
|
char cleanConsoleBuffer[CONSOLE_BUFFER_SIZE];
|
||||||
|
|
||||||
|
const auto* class_name = "BOIII WinConsole";
|
||||||
|
const auto* window_name = "BOIII Console";
|
||||||
|
|
||||||
|
WNDCLASSA WndClass;
|
||||||
|
WndClass.style = 0;
|
||||||
|
WndClass.lpfnWndProc = con_wnd_proc;
|
||||||
|
WndClass.cbClsExtra = 0;
|
||||||
|
WndClass.cbWndExtra = 0;
|
||||||
|
WndClass.hInstance = hInstance;
|
||||||
|
WndClass.hIcon = LoadIconA(hInstance, (LPCSTR)1);
|
||||||
|
WndClass.hCursor = LoadCursorA(0, (LPCSTR)0x7F00);
|
||||||
|
WndClass.hbrBackground = CreateSolidBrush(RGB(50, 50, 50));
|
||||||
|
WndClass.lpszMenuName = 0;
|
||||||
|
WndClass.lpszClassName = class_name;
|
||||||
|
|
||||||
|
if (!RegisterClassA(&WndClass))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
tagRECT Rect;
|
||||||
|
Rect.left = 0;
|
||||||
|
Rect.right = 620;
|
||||||
|
Rect.top = 0;
|
||||||
|
Rect.bottom = 450;
|
||||||
|
AdjustWindowRect(&Rect, 0x80CA0000, 0);
|
||||||
|
|
||||||
|
auto hDC = GetDC(GetDesktopWindow());
|
||||||
|
auto swidth = GetDeviceCaps(hDC, 8);
|
||||||
|
auto sheight = GetDeviceCaps(hDC, 10);
|
||||||
|
ReleaseDC(GetDesktopWindow(), hDC);
|
||||||
|
|
||||||
|
utils::hook::set<int>(game::s_wcd::windowWidth, Rect.right - Rect.left + 1);
|
||||||
|
utils::hook::set<int>(game::s_wcd::windowHeight, Rect.bottom - Rect.top + 1);
|
||||||
|
|
||||||
|
utils::hook::set<HWND>(game::s_wcd::hWnd, CreateWindowExA(
|
||||||
|
0, class_name, window_name, 0x80CA0000, (swidth - 600) / 2, (sheight - 450) / 2,
|
||||||
|
Rect.right - Rect.left + 1, Rect.bottom - Rect.top + 1, 0, 0, hInstance, 0));
|
||||||
|
|
||||||
|
if (!*game::s_wcd::hWnd)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// create fonts
|
||||||
|
hDC = GetDC(*game::s_wcd::hWnd);
|
||||||
|
auto nHeight = MulDiv(8, GetDeviceCaps(hDC, 90), 72);
|
||||||
|
|
||||||
|
utils::hook::set<HFONT>(game::s_wcd::hfBufferFont, CreateFontA(
|
||||||
|
-nHeight, 0, 0, 0, 300, 0, 0, 0, 1u, 0, 0, 0, 0x31u, "Courier New"));
|
||||||
|
|
||||||
|
ReleaseDC(*game::s_wcd::hWnd, hDC);
|
||||||
|
|
||||||
|
if (logo)
|
||||||
|
{
|
||||||
|
utils::hook::set<HWND>(game::s_wcd::codLogo, CreateWindowExA(
|
||||||
|
0, "Static", 0, 0x5000000Eu, 5, 5, 0, 0, *game::s_wcd::hWnd, (HMENU)1, hInstance, 0));
|
||||||
|
SendMessageA(*game::s_wcd::codLogo, 0x172u, 0, (LPARAM)logo);
|
||||||
|
}
|
||||||
|
|
||||||
|
// create the input line
|
||||||
|
utils::hook::set<HWND>(game::s_wcd::hwndInputLine, CreateWindowExA(
|
||||||
|
0, "edit", 0, 0x50800080u, 6, 400, 608, 20, *game::s_wcd::hWnd, (HMENU)0x65, hInstance, 0));
|
||||||
|
utils::hook::set<HWND>(game::s_wcd::hwndBuffer, CreateWindowExA(
|
||||||
|
0, "edit", 0, 0x50A00844u, 6, 70, 606, 324, *game::s_wcd::hWnd, (HMENU)0x64, hInstance, 0));
|
||||||
|
SendMessageA(*game::s_wcd::hwndBuffer, WM_SETFONT, (WPARAM)*game::s_wcd::hfBufferFont, 0);
|
||||||
|
|
||||||
|
utils::hook::set<WNDPROC>(game::s_wcd::SysInputLineWndProc, (WNDPROC)SetWindowLongPtrA(
|
||||||
|
*game::s_wcd::hwndInputLine, -4, (LONG_PTR)input_line_wnd_proc));
|
||||||
|
SendMessageA(*game::s_wcd::hwndInputLine, WM_SETFONT, (WPARAM)*game::s_wcd::hfBufferFont, 0);
|
||||||
|
|
||||||
|
SetFocus(*game::s_wcd::hwndInputLine);
|
||||||
|
game::Con_GetTextCopy(text, 0x4000);
|
||||||
|
game::Conbuf_CleanText(text, cleanConsoleBuffer);
|
||||||
|
SetWindowTextA(*game::s_wcd::hwndBuffer, cleanConsoleBuffer);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class component final : public component_interface
|
class component final : public component_interface
|
||||||
@ -52,6 +151,9 @@ namespace console
|
|||||||
public:
|
public:
|
||||||
void post_unpack() override
|
void post_unpack() override
|
||||||
{
|
{
|
||||||
|
const utils::nt::library self;
|
||||||
|
logo = LoadImageA(self.get_handle(), MAKEINTRESOURCEA(IMAGE_LOGO), 0, 0, 0, LR_COPYFROMRESOURCE);
|
||||||
|
|
||||||
utils::hook::jump(printf, print_stub);
|
utils::hook::jump(printf, print_stub);
|
||||||
|
|
||||||
this->terminate_runner_ = false;
|
this->terminate_runner_ = false;
|
||||||
@ -59,15 +161,10 @@ namespace console
|
|||||||
this->console_runner_ = utils::thread::create_named_thread("Console IO", [this]
|
this->console_runner_ = utils::thread::create_named_thread("Console IO", [this]
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
utils::hook::detour d;
|
utils::hook::detour sys_create_console_hook;
|
||||||
d.create(0x142333B40_g, utils::hook::assemble([](utils::hook::assembler& a)
|
sys_create_console_hook.create(0x1423339C0_g, sys_create_console_stub);
|
||||||
{
|
|
||||||
a.mov(r8, "BOIII Console");
|
game::Sys_ShowConsole();
|
||||||
a.mov(r9d, 0x80CA0000);
|
|
||||||
a.sub(eax, edx);
|
|
||||||
a.jmp(0x142333B4F_g);
|
|
||||||
}));
|
|
||||||
create_game_console();
|
|
||||||
g_started = true;
|
g_started = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -78,11 +175,6 @@ namespace console
|
|||||||
{
|
{
|
||||||
TranslateMessage(&msg);
|
TranslateMessage(&msg);
|
||||||
DispatchMessageW(&msg);
|
DispatchMessageW(&msg);
|
||||||
|
|
||||||
if(msg.message == WM_QUIT)
|
|
||||||
{
|
|
||||||
terminate_game();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
43
src/client/game/game.cpp
Normal file
43
src/client/game/game.cpp
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
#include <std_include.hpp>
|
||||||
|
|
||||||
|
#include "loader/component_loader.hpp"
|
||||||
|
#include "game.hpp"
|
||||||
|
|
||||||
|
namespace game
|
||||||
|
{
|
||||||
|
// inlined in cod, functionality stolen from https://github.com/id-Software/Quake-III-Arena/blob/master/code/win32/win_syscon.c#L520
|
||||||
|
int Conbuf_CleanText(const char* source, char* target)
|
||||||
|
{
|
||||||
|
char* b = target;
|
||||||
|
int i = 0;
|
||||||
|
while (source[i] && ((b - target) < sizeof(target) - 1))
|
||||||
|
{
|
||||||
|
if (source[i] == '\n' && source[i + 1] == '\r')
|
||||||
|
{
|
||||||
|
b[0] = '\r';
|
||||||
|
b[1] = '\n';
|
||||||
|
b += 2;
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
else if (source[i] == '\r' || source[i] == '\n')
|
||||||
|
{
|
||||||
|
b[0] = '\r';
|
||||||
|
b[1] = '\n';
|
||||||
|
b += 2;
|
||||||
|
}
|
||||||
|
else if (source && source[0] == '^' && source[1] && source[1] != '^' && source[1] >= 48 && source[1] <= 64) // Q_IsColorString
|
||||||
|
{
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
*b = source[i]; // C6011 here, should we be worried?
|
||||||
|
b++;
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
*b = 0;
|
||||||
|
return static_cast<int>(b - target);
|
||||||
|
}
|
||||||
|
}
|
39
src/client/game/game.hpp
Normal file
39
src/client/game/game.hpp
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
//#include "structs.hpp"
|
||||||
|
|
||||||
|
namespace game
|
||||||
|
{
|
||||||
|
int Conbuf_CleanText(const char* source, char* target);
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
class symbol
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
symbol(const size_t address)
|
||||||
|
: address_(reinterpret_cast<T*>(address))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
T* get() const
|
||||||
|
{
|
||||||
|
return reinterpret_cast<T*>((uint64_t)address_);
|
||||||
|
}
|
||||||
|
|
||||||
|
operator T* () const
|
||||||
|
{
|
||||||
|
return this->get();
|
||||||
|
}
|
||||||
|
|
||||||
|
T* operator->() const
|
||||||
|
{
|
||||||
|
return this->get();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
T* address_;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#include "symbols.hpp"
|
26
src/client/game/symbols.hpp
Normal file
26
src/client/game/symbols.hpp
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#define WEAK __declspec(selectany)
|
||||||
|
|
||||||
|
namespace game
|
||||||
|
{
|
||||||
|
WEAK symbol<void(int localClientNum, const char* text)> Cbuf_AddText{0x1420EC8B0_g};
|
||||||
|
|
||||||
|
WEAK symbol<void(int channel, unsigned int label, const char* fmt, ...)> Com_Printf{0x1421499C0_g};
|
||||||
|
|
||||||
|
WEAK symbol<void(char* text, int maxSize)> Con_GetTextCopy{0x14133A7D0_g};
|
||||||
|
|
||||||
|
WEAK symbol<void()> Sys_ShowConsole{0x142333F80_g};
|
||||||
|
|
||||||
|
namespace s_wcd
|
||||||
|
{
|
||||||
|
WEAK symbol<HWND> codLogo{0x157E77A50_g};
|
||||||
|
WEAK symbol<HFONT> hfBufferFont{0x157E77A58_g};
|
||||||
|
WEAK symbol<HWND> hWnd{0x157E77A40_g};
|
||||||
|
WEAK symbol<HWND> hwndBuffer{0x157E77A48_g};
|
||||||
|
WEAK symbol<HWND> hwndInputLine{0x157E77A60_g};
|
||||||
|
WEAK symbol<int> windowHeight{0x157E7806C_g};
|
||||||
|
WEAK symbol<int> windowWidth{0x157E78068_g};
|
||||||
|
WEAK symbol<WNDPROC> SysInputLineWndProc{0x157E78070_g};
|
||||||
|
}
|
||||||
|
}
|
@ -2,3 +2,5 @@
|
|||||||
|
|
||||||
#define ID_ICON 102
|
#define ID_ICON 102
|
||||||
#define IMAGE_SPLASH 300
|
#define IMAGE_SPLASH 300
|
||||||
|
|
||||||
|
#define IMAGE_LOGO 301
|
||||||
|
@ -93,6 +93,7 @@ END
|
|||||||
|
|
||||||
//ID_ICON ICON "resources/icon.ico"
|
//ID_ICON ICON "resources/icon.ico"
|
||||||
IMAGE_SPLASH BITMAP "resources/splash.bmp"
|
IMAGE_SPLASH BITMAP "resources/splash.bmp"
|
||||||
|
IMAGE_LOGO BITMAP "resources/logo.bmp"
|
||||||
|
|
||||||
#endif // English (United States) resources
|
#endif // English (United States) resources
|
||||||
/////////////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
|
BIN
src/client/resources/logo.bmp
Normal file
BIN
src/client/resources/logo.bmp
Normal file
Binary file not shown.
After Width: | Height: | Size: 107 KiB |
@ -115,7 +115,7 @@ namespace steam
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
MessageBoxA(nullptr, "Steam must be installed for the game to run. Please install steam!", "Error", MB_ICONERROR);
|
MessageBoxA(nullptr, "Steam must be installed for the game to run. Please install Steam!", "Error", MB_ICONERROR);
|
||||||
ShellExecuteA(nullptr, "open", "https://store.steampowered.com/about/", nullptr, nullptr, SW_SHOWNORMAL);
|
ShellExecuteA(nullptr, "open", "https://store.steampowered.com/about/", nullptr, nullptr, SW_SHOWNORMAL);
|
||||||
TerminateProcess(GetCurrentProcess(), 1);
|
TerminateProcess(GetCurrentProcess(), 1);
|
||||||
return true;
|
return true;
|
||||||
|
Loading…
Reference in New Issue
Block a user