[Dvar]: Don't lookup dvar every time we need it (#677)

* [Dvar]: Don't lookup dvar every time we need it

* [Console]: Cleanup the code

* [Party]: Improve source code quality

* [Party]: Update
This commit is contained in:
Edo 2022-12-31 15:03:33 +01:00 committed by GitHub
parent 676854167b
commit 86b402a5a0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 428 additions and 419 deletions

View File

@ -1,6 +1,8 @@
#include <STDInclude.hpp> #include <STDInclude.hpp>
#include "Console.hpp" #include "Console.hpp"
#include "Terminus_4.49.1.ttf.hpp"
#include <version.hpp> #include <version.hpp>
#ifdef MOUSE_MOVED #ifdef MOUSE_MOVED
@ -32,14 +34,14 @@ namespace Components
bool Console::SkipShutdown = false; bool Console::SkipShutdown = false;
COLORREF Console::TextColor = COLORREF Console::TextColor =
#if DEBUG #if _DEBUG
RGB(255, 200, 117); RGB(255, 200, 117);
#else #else
RGB(120, 237, 122); RGB(120, 237, 122);
#endif #endif
COLORREF Console::BackgroundColor = COLORREF Console::BackgroundColor =
#if DEBUG #if _DEBUG
RGB(35, 21, 0); RGB(35, 21, 0);
#else #else
RGB(25, 32, 25); RGB(25, 32, 25);
@ -64,16 +66,16 @@ namespace Components
const std::string mapname = (*Game::sv_mapname)->current.string; const std::string mapname = (*Game::sv_mapname)->current.string;
const auto hostname = TextRenderer::StripColors((*Game::sv_hostname)->current.string); const auto hostname = TextRenderer::StripColors((*Game::sv_hostname)->current.string);
if (Console::HasConsole) if (HasConsole)
{ {
SetConsoleTitleA(hostname.data()); SetConsoleTitleA(hostname.data());
auto clientCount = 0; auto clientCount = 0;
auto maxclientCount = *Game::svs_clientCount; auto maxClientCount = *Game::svs_clientCount;
if (maxclientCount) if (maxClientCount)
{ {
for (int i = 0; i < maxclientCount; ++i) for (auto i = 0; i < maxClientCount; ++i)
{ {
if (Game::svs_clients[i].header.state >= Game::CS_CONNECTED) if (Game::svs_clients[i].header.state >= Game::CS_CONNECTED)
{ {
@ -83,18 +85,17 @@ namespace Components
} }
else else
{ {
maxclientCount = Dvar::Var("party_maxplayers").get<int>(); maxClientCount = *Game::party_maxplayers ? (*Game::party_maxplayers)->current.integer : 18;
//maxclientCount = Game::Party_GetMaxPlayers(*Game::partyIngame); clientCount = Game::PartyHost_CountMembers(Game::g_lobbyData);
clientCount = Game::PartyHost_CountMembers(reinterpret_cast<Game::PartyData*>(0x1081C00));
} }
wclear(InfoWindow); wclear(InfoWindow);
wprintw(InfoWindow, "%s : %d/%d players : map %s", hostname.data(), clientCount, maxclientCount, (!mapname.empty()) ? mapname.data() : "none"); wprintw(InfoWindow, "%s : %d/%d players : map %s", hostname.data(), clientCount, maxClientCount, (!mapname.empty()) ? mapname.data() : "none");
wnoutrefresh(InfoWindow); wnoutrefresh(InfoWindow);
} }
else if (IsWindow(Console::GetWindow()) != FALSE) else if (IsWindow(GetWindow()) != FALSE)
{ {
SetWindowTextA(Console::GetWindow(), Utils::String::VA("IW4x(" VERSION ") : %s", hostname.data())); SetWindowTextA(GetWindow(), Utils::String::VA("IW4x(" VERSION ") : %s", hostname.data()));
} }
} }
@ -106,35 +107,35 @@ namespace Components
void Console::RefreshOutput() void Console::RefreshOutput()
{ {
prefresh(OutputWindow, ((Console::OutputTop > 0) ? (Console::OutputTop - 1) : 0), 0, 1, 0, Console::Height - 2, Console::Width - 1); prefresh(OutputWindow, ((OutputTop > 0) ? (OutputTop - 1) : 0), 0, 1, 0, Height - 2, Width - 1);
} }
void Console::ScrollOutput(int amount) void Console::ScrollOutput(int amount)
{ {
Console::OutputTop += amount; OutputTop += amount;
if (Console::OutputTop > OUTPUT_MAX_TOP) if (OutputTop > OUTPUT_MAX_TOP)
{ {
Console::OutputTop = OUTPUT_MAX_TOP; OutputTop = OUTPUT_MAX_TOP;
} }
else if (Console::OutputTop < 0) else if (OutputTop < 0)
{ {
Console::OutputTop = 0; OutputTop = 0;
} }
// make it only scroll the top if there's more than HEIGHT lines // make it only scroll the top if there's more than HEIGHT lines
if (Console::OutBuffer >= 0) if (OutBuffer >= 0)
{ {
Console::OutBuffer += amount; OutBuffer += amount;
if (Console::OutBuffer >= Console::Height) if (OutBuffer >= Height)
{ {
Console::OutBuffer = -1; OutBuffer = -1;
} }
if (Console::OutputTop < Console::Height) if (OutputTop < Height)
{ {
Console::OutputTop = 0; OutputTop = 0;
} }
} }
} }
@ -149,17 +150,13 @@ namespace Components
if (getDpiForWindow) if (getDpiForWindow)
{ {
dpi = getDpiForWindow(hWnd); dpi = static_cast<int>(getDpiForWindow(hWnd));
} }
else if (getDpiForMonitor) else if (getDpiForMonitor)
{ {
HMONITOR hMonitor = MonitorFromWindow(hWnd, MONITOR_DEFAULTTONEAREST); HMONITOR hMonitor = MonitorFromWindow(hWnd, MONITOR_DEFAULTTONEAREST);
UINT xdpi, ydpi; UINT xdpi, ydpi;
LRESULT success = getDpiForMonitor(hMonitor, 0, &xdpi, &ydpi); getDpiForMonitor(hMonitor, 0, &xdpi, &ydpi);
if (success == S_OK)
{
dpi = static_cast<int>(ydpi);
}
dpi = 96; dpi = 96;
} }
@ -167,33 +164,33 @@ namespace Components
{ {
HDC hDC = GetDC(hWnd); HDC hDC = GetDC(hWnd);
INT ydpi = GetDeviceCaps(hDC, LOGPIXELSY); INT ydpi = GetDeviceCaps(hDC, LOGPIXELSY);
ReleaseDC(NULL, hDC); ReleaseDC(nullptr, hDC);
dpi = ydpi; dpi = ydpi;
} }
constexpr auto unawareDpi = 96.0f; constexpr auto unawareDpi = 96.0f;
return dpi / unawareDpi; return static_cast<float>(dpi) / unawareDpi;
} }
const char* Console::Input() const char* Console::Input()
{ {
if (!Console::HasConsole) if (!HasConsole)
{ {
Console::ShowPrompt(); ShowPrompt();
wrefresh(InputWindow); wrefresh(InputWindow);
Console::HasConsole = true; HasConsole = true;
} }
int currentTime = static_cast<int>(GetTickCount64()); // Make our compiler happy auto currentTime = static_cast<int>(GetTickCount64()); // Make our compiler happy
if ((currentTime - Console::LastRefresh) > 250) if ((currentTime - LastRefresh) > 250)
{ {
Console::RefreshOutput(); RefreshOutput();
Console::LastRefresh = currentTime; LastRefresh = currentTime;
} }
int c = wgetch(InputWindow); auto c = wgetch(InputWindow);
if (c == ERR) if (c == ERR)
{ {
@ -208,28 +205,28 @@ namespace Components
wattron(OutputWindow, COLOR_PAIR(10) | A_BOLD); wattron(OutputWindow, COLOR_PAIR(10) | A_BOLD);
wprintw(OutputWindow, "%s", "]"); wprintw(OutputWindow, "%s", "]");
if (Console::LineBufferIndex) if (LineBufferIndex)
{ {
wprintw(OutputWindow, "%s", Console::LineBuffer); wprintw(OutputWindow, "%s", LineBuffer);
} }
wprintw(OutputWindow, "%s", "\n"); wprintw(OutputWindow, "%s", "\n");
wattroff(OutputWindow, A_BOLD); wattroff(OutputWindow, A_BOLD);
wclear(InputWindow); wclear(InputWindow);
Console::ShowPrompt(); ShowPrompt();
wrefresh(InputWindow); wrefresh(InputWindow);
Console::ScrollOutput(1); ScrollOutput(1);
Console::RefreshOutput(); RefreshOutput();
if (Console::LineBufferIndex) if (LineBufferIndex)
{ {
strcpy_s(Console::LineBuffer2, Console::LineBuffer); strcpy_s(LineBuffer2, LineBuffer);
strcat_s(Console::LineBuffer, "\n"); strcat_s(LineBuffer, "\n");
Console::LineBufferIndex = 0; LineBufferIndex = 0;
return Console::LineBuffer; return LineBuffer;
} }
break; break;
@ -237,22 +234,22 @@ namespace Components
case 'c' - 'a' + 1: // ctrl-c case 'c' - 'a' + 1: // ctrl-c
case 27: case 27:
{ {
Console::LineBuffer[0] = '\0'; LineBuffer[0] = '\0';
Console::LineBufferIndex = 0; LineBufferIndex = 0;
wclear(InputWindow); wclear(InputWindow);
Console::ShowPrompt(); ShowPrompt();
wrefresh(InputWindow); wrefresh(InputWindow);
break; break;
} }
case 8: // backspace case 8: // backspace
{ {
if (Console::LineBufferIndex > 0) if (LineBufferIndex > 0)
{ {
Console::LineBufferIndex--; LineBufferIndex--;
Console::LineBuffer[Console::LineBufferIndex] = '\0'; LineBuffer[LineBufferIndex] = '\0';
wprintw(InputWindow, "%c %c", static_cast<char>(c), static_cast<char>(c)); wprintw(InputWindow, "%c %c", static_cast<char>(c), static_cast<char>(c));
wrefresh(InputWindow); wrefresh(InputWindow);
@ -261,35 +258,35 @@ namespace Components
} }
case KEY_PPAGE: case KEY_PPAGE:
{ {
Console::ScrollOutput(-1); ScrollOutput(-1);
Console::RefreshOutput(); RefreshOutput();
break; break;
} }
case KEY_NPAGE: case KEY_NPAGE:
{ {
Console::ScrollOutput(1); ScrollOutput(1);
Console::RefreshOutput(); RefreshOutput();
break; break;
} }
case KEY_UP: case KEY_UP:
{ {
wclear(InputWindow); wclear(InputWindow);
Console::ShowPrompt(); ShowPrompt();
wprintw(InputWindow, "%s", Console::LineBuffer2); wprintw(InputWindow, "%s", LineBuffer2);
wrefresh(InputWindow); wrefresh(InputWindow);
strcpy_s(Console::LineBuffer, Console::LineBuffer2); strcpy_s(LineBuffer, LineBuffer2);
Console::LineBufferIndex = strlen(Console::LineBuffer); LineBufferIndex = static_cast<int>(std::strlen(LineBuffer));
break; break;
} }
default: default:
if (c <= 127 && Console::LineBufferIndex < 1022) if (c <= 127 && LineBufferIndex < 1022)
{ {
// temporary workaround , find out what overwrites our index later on // temporary workaround, find out what overwrites our index later on
//consoleLineBufferIndex = strlen(consoleLineBuffer); //consoleLineBufferIndex = strlen(consoleLineBuffer);
Console::LineBuffer[Console::LineBufferIndex++] = static_cast<char>(c); LineBuffer[LineBufferIndex++] = static_cast<char>(c);
Console::LineBuffer[Console::LineBufferIndex] = '\0'; LineBuffer[LineBufferIndex] = '\0';
wprintw(InputWindow, "%c", static_cast<char>(c)); wprintw(InputWindow, "%c", static_cast<char>(c));
wrefresh(InputWindow); wrefresh(InputWindow);
} }
@ -318,31 +315,31 @@ namespace Components
void Console::Create() void Console::Create()
{ {
Console::OutputTop = 0; OutputTop = 0;
Console::OutBuffer = 0; OutBuffer = 0;
Console::LastRefresh = 0; LastRefresh = 0;
Console::LineBufferIndex = 0; LineBufferIndex = 0;
Console::HasConsole = false; HasConsole = false;
CONSOLE_SCREEN_BUFFER_INFO info; CONSOLE_SCREEN_BUFFER_INFO info;
if (GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &info)) if (GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &info))
{ {
Console::Width = info.dwSize.X; Width = info.dwSize.X;
Console::Height = info.srWindow.Bottom - info.srWindow.Top + 1; Height = info.srWindow.Bottom - info.srWindow.Top + 1;
} }
else else
{ {
Console::Height = 25; Height = 25;
Console::Width = 80; Width = 80;
} }
initscr(); initscr();
raw(); raw();
noecho(); noecho();
OutputWindow = newpad(Console::Height - 1, Console::Width); OutputWindow = newpad(Height - 1, Width);
InputWindow = newwin(1, Console::Width, Console::Height - 1, 0); InputWindow = newwin(1, Width, Height - 1, 0);
InfoWindow = newwin(1, Console::Width, 0, 0); InfoWindow = newwin(1, Width, 0, 0);
scrollok(OutputWindow, true); scrollok(OutputWindow, true);
idlok(OutputWindow, true); idlok(OutputWindow, true);
@ -370,7 +367,7 @@ namespace Components
wrefresh(InfoWindow); wrefresh(InfoWindow);
wrefresh(InputWindow); wrefresh(InputWindow);
Console::RefreshOutput(); RefreshOutput();
} }
void Console::Error(const char* fmt, ...) void Console::Error(const char* fmt, ...)
@ -384,7 +381,7 @@ namespace Components
Logger::PrintError(Game::CON_CHANNEL_ERROR, "{}\n", buf); Logger::PrintError(Game::CON_CHANNEL_ERROR, "{}\n", buf);
Console::RefreshOutput(); RefreshOutput();
if (IsDebuggerPresent()) if (IsDebuggerPresent())
{ {
@ -394,7 +391,7 @@ namespace Components
} }
} }
TerminateProcess(GetCurrentProcess(), 0xDEADDEAD); TerminateProcess(GetCurrentProcess(), EXIT_FAILURE);
} }
void Console::Print(const char* message) void Console::Print(const char* message)
@ -406,11 +403,9 @@ namespace Components
{ {
if (*p == '^') if (*p == '^')
{ {
char color;
++p; ++p;
color = (*p - '0'); const char color = (*p - '0');
if (color < 9 && color > 0) if (color < 9 && color > 0)
{ {
wattron(OutputWindow, COLOR_PAIR(color + 2)); wattron(OutputWindow, COLOR_PAIR(color + 2));
@ -426,26 +421,26 @@ namespace Components
wattron(OutputWindow, COLOR_PAIR(9)); wattron(OutputWindow, COLOR_PAIR(9));
Console::RefreshOutput(); RefreshOutput();
} }
HFONT __stdcall Console::ReplaceFont( HFONT CALLBACK Console::ReplaceFont(
[[maybe_unused]] int cHeight, [[maybe_unused]] int cHeight,
int cWidth, int cWidth,
int cEscapement, int cEscapement,
int cOrientation, int cOrientation,
[[maybe_unused]] int cWeight, [[maybe_unused]] int cWeight,
DWORD bItalic, DWORD bItalic,
DWORD bUnderline, DWORD bUnderline,
DWORD bStrikeOut, DWORD bStrikeOut,
DWORD iCharSet, DWORD iCharSet,
[[maybe_unused]] DWORD iOutPrecision, [[maybe_unused]] DWORD iOutPrecision,
DWORD iClipPrecision, DWORD iClipPrecision,
[[maybe_unused]] DWORD iQuality, [[maybe_unused]] DWORD iQuality,
[[maybe_unused]] DWORD iPitchAndFamily, [[maybe_unused]] DWORD iPitchAndFamily,
[[maybe_unused]] LPCSTR pszFaceName) [[maybe_unused]] LPCSTR pszFaceName)
{ {
auto font = CreateFontA( HFONT font = CreateFontA(
12, 12,
cWidth, cWidth,
cEscapement, cEscapement,
@ -459,7 +454,8 @@ namespace Components
iClipPrecision, iClipPrecision,
NONANTIALIASED_QUALITY, NONANTIALIASED_QUALITY,
0x31, 0x31,
"Terminus (TTF)"); // Terminus (TTF) "Terminus (TTF)"
); // Terminus (TTF)
return font; return font;
} }
@ -467,7 +463,7 @@ namespace Components
void Console::GetWindowPos(HWND hWnd, int* x, int* y) void Console::GetWindowPos(HWND hWnd, int* x, int* y)
{ {
HWND hWndParent = GetParent(hWnd); HWND hWndParent = GetParent(hWnd);
POINT p = { 0 }; POINT p{};
MapWindowPoints(hWnd, hWndParent, &p, 1); MapWindowPoints(hWnd, hWndParent, &p, 1);
@ -478,8 +474,8 @@ namespace Components
BOOL CALLBACK Console::ResizeChildWindow(HWND hwndChild, LPARAM lParam) BOOL CALLBACK Console::ResizeChildWindow(HWND hwndChild, LPARAM lParam)
{ {
auto id = GetWindowLong(hwndChild, GWL_ID); auto id = GetWindowLong(hwndChild, GWL_ID);
bool isInputBox = id == INPUT_BOX; auto isInputBox = id == INPUT_BOX;
bool isOutputBox = id == OUTPUT_BOX; auto isOutputBox = id == OUTPUT_BOX;
if (isInputBox || isOutputBox) if (isInputBox || isOutputBox)
{ {
@ -496,31 +492,31 @@ namespace Components
HWND parent = Utils::Hook::Get<HWND>(0x64A3288); HWND parent = Utils::Hook::Get<HWND>(0x64A3288);
float scale = GetDpiScale(parent); auto scale = GetDpiScale(parent);
if (isInputBox) if (isInputBox)
{ {
int newX = childX; // No change! auto newX = childX; // No change!
int newY = static_cast<int>((newParentRect.bottom - newParentRect.top) - 65 * scale); auto newY = static_cast<int>((newParentRect.bottom - newParentRect.top) - 65 * scale);
int newWidth = static_cast<int>((newParentRect.right - newParentRect.left) - 29 * scale); auto newWidth = static_cast<int>((newParentRect.right - newParentRect.left) - 29 * scale);
int newHeight = static_cast<int>((childRect.bottom - childRect.top) * scale); // No change! auto newHeight = static_cast<int>((childRect.bottom - childRect.top) * scale); // No change!
MoveWindow(hwndChild, newX, newY, newWidth, newHeight, TRUE); MoveWindow(hwndChild, newX, newY, newWidth, newHeight, TRUE);
} }
if (isOutputBox) if (isOutputBox)
{ {
int newX = childX; // No change! auto newX = childX; // No change!
int newY = childY; // No change! auto newY = childY; // No change!
int newWidth = static_cast<int>((newParentRect.right - newParentRect.left) - 29); auto newWidth = static_cast<int>((newParentRect.right - newParentRect.left) - 29);
int margin = 70;
#ifdef REMOVE_HEADERBAR #ifdef REMOVE_HEADERBAR
margin = 10; constexpr auto margin = 10;
#else
constexpr auto margin = 70;
#endif #endif
int newHeight = static_cast<int>((newParentRect.bottom - newParentRect.top) - 74 * scale - margin); auto newHeight = static_cast<int>((newParentRect.bottom - newParentRect.top) - 74 * scale - margin);
MoveWindow(hwndChild, newX, newY, newWidth, newHeight, TRUE); MoveWindow(hwndChild, newX, newY, newWidth, newHeight, TRUE);
} }
@ -536,23 +532,21 @@ namespace Components
// around whenever clearing occurs. // around whenever clearing occurs.
void Console::MakeRoomForText([[maybe_unused]] int addedCharacters) void Console::MakeRoomForText([[maybe_unused]] int addedCharacters)
{ {
constexpr unsigned int maxChars = 0x4000; constexpr auto maxChars = 0x4000;
constexpr unsigned int maxAffectedChars = 0x100; constexpr auto maxAffectedChars = 0x100;
HWND outputBox = Utils::Hook::Get<HWND>(0x64A328C); HWND outputBox = Utils::Hook::Get<HWND>(0x64A328C);
unsigned int totalChars; auto totalClearLength = 0;
unsigned int totalClearLength = 0;
char str[maxAffectedChars]; char str[maxAffectedChars];
unsigned int fetchedCharacters = static_cast<unsigned int>(GetWindowText(outputBox, str, maxAffectedChars)); const auto fetchedCharacters = GetWindowTextA(outputBox, str, maxAffectedChars);
totalChars = GetWindowTextLengthA(outputBox);
auto totalChars = GetWindowTextLengthA(outputBox);
while (totalChars - totalClearLength > maxChars) while (totalChars - totalClearLength > maxChars)
{ {
unsigned int clearLength = maxAffectedChars; // Default to full clear auto clearLength = maxAffectedChars; // Default to full clear
for (size_t i = 0; i < fetchedCharacters; i++) for (auto i = 0; i < fetchedCharacters; i++)
{ {
if (str[i] == '\n') if (str[i] == '\n')
{ {
@ -567,10 +561,10 @@ namespace Components
if (totalClearLength > 0) if (totalClearLength > 0)
{ {
SendMessage(outputBox, WM_SETREDRAW, FALSE, 0); SendMessageA(outputBox, WM_SETREDRAW, FALSE, 0);
SendMessage(outputBox, EM_SETSEL, 0, totalClearLength); SendMessageA(outputBox, EM_SETSEL, 0, totalClearLength);
SendMessage(outputBox, EM_REPLACESEL, FALSE, 0); SendMessageA(outputBox, EM_REPLACESEL, FALSE, 0);
SendMessage(outputBox, WM_SETREDRAW, TRUE, 0); SendMessageA(outputBox, WM_SETREDRAW, TRUE, 0);
} }
Utils::Hook::Set(0x64A38B8, totalChars - totalClearLength); Utils::Hook::Set(0x64A38B8, totalChars - totalClearLength);
@ -596,18 +590,11 @@ namespace Components
{ {
switch (Msg) switch (Msg)
{ {
case WM_CREATE: case WM_CREATE:
{ {
BOOL darkMode = true; BOOL darkMode = TRUE;
constexpr auto DWMWA_USE_IMMERSIVE_DARK_MODE = 20;
#define DWMWA_USE_IMMERSIVE_DARK_MODE 20 DwmSetWindowAttribute(hWnd, DWMWA_USE_IMMERSIVE_DARK_MODE, &darkMode, sizeof(darkMode));
if (SUCCEEDED(DwmSetWindowAttribute(hWnd, DWMWA_USE_IMMERSIVE_DARK_MODE, reinterpret_cast<LPCVOID>(&darkMode), sizeof(darkMode))))
{
// cool !
}
break; break;
} }
@ -630,7 +617,6 @@ namespace Components
return 0; return 0;
} }
// Fall through to basegame
return Utils::Hook::Call<LRESULT CALLBACK(HWND, UINT, WPARAM, unsigned int)>(0x64DC50)(hWnd, Msg, wParam, lParam); return Utils::Hook::Call<LRESULT CALLBACK(HWND, UINT, WPARAM, unsigned int)>(0x64DC50)(hWnd, Msg, wParam, lParam);
} }
@ -645,14 +631,14 @@ namespace Components
void Console::ApplyConsoleStyle() void Console::ApplyConsoleStyle()
{ {
Utils::Hook::Set<BYTE>(0x428A8E, 0); // Adjust logo Y pos Utils::Hook::Set<std::uint8_t>(0x428A8E, 0); // Adjust logo Y pos
Utils::Hook::Set<BYTE>(0x428A90, 0); // Adjust logo X pos Utils::Hook::Set<std::uint8_t>(0x428A90, 0); // Adjust logo X pos
Utils::Hook::Set<BYTE>(0x428AF2, 67); // Adjust output Y pos Utils::Hook::Set<std::uint8_t>(0x428AF2, 67); // Adjust output Y pos
Utils::Hook::Set<DWORD>(0x428AC5, 397); // Adjust input Y pos Utils::Hook::Set<std::uint32_t>(0x428AC5, 397); // Adjust input Y pos
Utils::Hook::Set<DWORD>(0x428951, 609); // Reduce window width Utils::Hook::Set<std::uint32_t>(0x428951, 609); // Reduce window width
Utils::Hook::Set<DWORD>(0x42895D, 423); // Reduce window height Utils::Hook::Set<std::uint32_t>(0x42895D, 423); // Reduce window height
Utils::Hook::Set<DWORD>(0x428AC0, 597); // Reduce input width Utils::Hook::Set<std::uint32_t>(0x428AC0, 597); // Reduce input width
Utils::Hook::Set<DWORD>(0x428AED, 596); // Reduce output width Utils::Hook::Set<std::uint32_t>(0x428AED, 596); // Reduce output width
DWORD fontsInstalled; DWORD fontsInstalled;
CustomConsoleFont = AddFontMemResourceEx(const_cast<void*>(reinterpret_cast<const void*>(Font::Terminus::DATA)), Font::Terminus::LENGTH, 0, &fontsInstalled); CustomConsoleFont = AddFontMemResourceEx(const_cast<void*>(reinterpret_cast<const void*>(Font::Terminus::DATA)), Font::Terminus::LENGTH, 0, &fontsInstalled);
@ -680,35 +666,37 @@ namespace Components
// Never reset text // Never reset text
Utils::Hook::Nop(0x4F57DF, 0x4F57F6 - 0x4F57DF); Utils::Hook::Nop(0x4F57DF, 0x4F57F6 - 0x4F57DF);
Utils::Hook(0x4F57DF, Console::Sys_PrintStub, HOOK_JUMP).install()->quick(); Utils::Hook(0x4F57DF, Sys_PrintStub, HOOK_JUMP).install()->quick();
} }
void Console::ConsoleRunner() void Console::ConsoleRunner()
{ {
Console::SkipShutdown = false; SkipShutdown = false;
Game::Sys_ShowConsole(); Game::Sys_ShowConsole();
MSG message; MSG message;
while (IsWindow(Console::GetWindow()) != FALSE && GetMessageA(&message, nullptr, 0, 0)) while (IsWindow(GetWindow()) != FALSE && GetMessageA(&message, nullptr, 0, 0))
{ {
TranslateMessage(&message); TranslateMessage(&message);
DispatchMessageA(&message); DispatchMessageA(&message);
} }
if (Console::SkipShutdown) return; if (SkipShutdown) return;
if (Game::Sys_Milliseconds() - Console::LastRefresh > 100 && if (Game::Sys_Milliseconds() -LastRefresh > 100 &&
MessageBoxA(nullptr, "The application is not responding anymore, do you want to force its termination?", "Application is not responding", MB_ICONEXCLAMATION | MB_YESNO) == IDYES) MessageBoxA(nullptr, "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 // Force process termination
// if the main thread is not responding // if the main thread is not responding
OutputDebugStringA("Process termination forced, as the main thread is not responding!"); #ifdef _DEBUG
OutputDebugStringA("Process termination was forced as the main thread is not responding!");
#endif
// We can not force the termination in this thread // We can not force the termination in this thread
// The destructor would be called in this thread // The destructor would be called in this thread
// and would try to join this thread, which is impossible // and would try to join this thread, which is impossible
TerminateProcess(GetCurrentProcess(), 0xFFFFFFFF); TerminateProcess(GetCurrentProcess(), EXIT_FAILURE);
} }
else else
{ {
@ -729,7 +717,7 @@ namespace Components
va_list ap; va_list ap;
va_start(ap, fmt); va_start(ap, fmt);
_vsnprintf_s(buffer, _TRUNCATE, fmt, ap); vsnprintf_s(buffer, _TRUNCATE, fmt, ap);
va_end(ap); va_end(ap);
perror(buffer); perror(buffer);
@ -759,7 +747,7 @@ namespace Components
void Console::StoreSafeArea() void Console::StoreSafeArea()
{ {
// Backup the original safe area // Backup the original safe area
Console::OriginalSafeArea = *Game::safeArea; OriginalSafeArea = *Game::safeArea;
// Apply new safe area and border // Apply new safe area and border
float border = 6.0f; float border = 6.0f;
@ -775,12 +763,12 @@ namespace Components
void Console::RestoreSafeArea() void Console::RestoreSafeArea()
{ {
// Restore the initial safe area // Restore the initial safe area
*Game::safeArea = Console::OriginalSafeArea; *Game::safeArea = OriginalSafeArea;
} }
void Console::SetSkipShutdown() void Console::SetSkipShutdown()
{ {
Console::SkipShutdown = true; SkipShutdown = true;
} }
void Console::FreeNativeConsole() void Console::FreeNativeConsole()
@ -798,11 +786,10 @@ namespace Components
void Console::ShowAsyncConsole() void Console::ShowAsyncConsole()
{ {
Console::ConsoleThread = std::thread(Console::ConsoleRunner); ConsoleThread = std::thread(ConsoleRunner);
} }
Game::dvar_t* Console::RegisterConColor(const char* dvarName, float r, float g, float b, float a, float min, Game::dvar_t* Console::RegisterConColor(const char* dvarName, float r, float g, float b, float a, float min, float max, unsigned __int16 flags, const char* description)
float max, unsigned __int16 flags, const char* description)
{ {
static struct static struct
{ {
@ -857,7 +844,7 @@ namespace Components
{ {
Command::Add("con_echo", [] Command::Add("con_echo", []
{ {
Console::Con_ToggleConsole(); Con_ToggleConsole();
Game::I_strncpyz(Game::g_consoleField->buffer, "\\echo ", sizeof(Game::field_t::buffer)); Game::I_strncpyz(Game::g_consoleField->buffer, "\\echo ", sizeof(Game::field_t::buffer));
Game::g_consoleField->cursor = static_cast<int>(std::strlen(Game::g_consoleField->buffer)); Game::g_consoleField->cursor = static_cast<int>(std::strlen(Game::g_consoleField->buffer));
Game::Field_AdjustScroll(Game::ScrPlace_GetFullPlacement(), Game::g_consoleField); Game::Field_AdjustScroll(Game::ScrPlace_GetFullPlacement(), Game::g_consoleField);
@ -878,24 +865,24 @@ namespace Components
Utils::Hook::Set<float*>(0x5A4400, consoleColor); Utils::Hook::Set<float*>(0x5A4400, consoleColor);
// Remove the need to type '\' or '/' to send a console command // Remove the need to type '\' or '/' to send a console command
Utils::Hook::Set<BYTE>(0x431565, 0xEB); Utils::Hook::Set<std::uint8_t>(0x431565, 0xEB);
// Internal console // Internal console
Utils::Hook(0x4F690C, Console::Con_ToggleConsole, HOOK_CALL).install()->quick(); Utils::Hook(0x4F690C, Con_ToggleConsole, HOOK_CALL).install()->quick();
Utils::Hook(0x4F65A5, Console::Con_ToggleConsole, HOOK_JUMP).install()->quick(); Utils::Hook(0x4F65A5, Con_ToggleConsole, HOOK_JUMP).install()->quick();
// Patch safearea for ingame-console // Patch safearea for ingame-console
Utils::Hook(0x5A50EF, Console::DrawSolidConsoleStub, HOOK_CALL).install()->quick(); Utils::Hook(0x5A50EF, DrawSolidConsoleStub, HOOK_CALL).install()->quick();
// Check for bad food ;) // Check for bad food ;)
Utils::Hook(0x4CB9F4, Console::GetAutoCompleteFileList, HOOK_CALL).install()->quick(); Utils::Hook(0x4CB9F4, GetAutoCompleteFileList, HOOK_CALL).install()->quick();
// Patch console dvars // Patch console dvars
Utils::Hook(0x4829AB, Console::RegisterConColor, HOOK_CALL).install()->quick(); Utils::Hook(0x4829AB, RegisterConColor, HOOK_CALL).install()->quick();
Utils::Hook(0x4829EE, Console::RegisterConColor, HOOK_CALL).install()->quick(); Utils::Hook(0x4829EE, RegisterConColor, HOOK_CALL).install()->quick();
Utils::Hook(0x482A31, Console::RegisterConColor, HOOK_CALL).install()->quick(); Utils::Hook(0x482A31, RegisterConColor, HOOK_CALL).install()->quick();
Utils::Hook(0x482A7A, Console::RegisterConColor, HOOK_CALL).install()->quick(); Utils::Hook(0x482A7A, RegisterConColor, HOOK_CALL).install()->quick();
Utils::Hook(0x482AC3, Console::RegisterConColor, HOOK_CALL).install()->quick(); Utils::Hook(0x482AC3, RegisterConColor, HOOK_CALL).install()->quick();
// Modify console style // Modify console style
ApplyConsoleStyle(); ApplyConsoleStyle();
@ -909,7 +896,7 @@ namespace Components
if (Dedicated::IsEnabled() && !ZoneBuilder::IsEnabled()) if (Dedicated::IsEnabled() && !ZoneBuilder::IsEnabled())
{ {
Scheduler::Loop(Console::RefreshStatus, Scheduler::Pipeline::MAIN); Scheduler::Loop(RefreshStatus, Scheduler::Pipeline::MAIN);
} }
// Code below is not necessary when performing unit tests! // Code below is not necessary when performing unit tests!
@ -918,8 +905,8 @@ namespace Components
// External console // External console
if (Flags::HasFlag("stdout")) if (Flags::HasFlag("stdout"))
{ {
Utils::Hook(0x4B2080, Console::StdOutPrint, HOOK_JUMP).install()->quick(); Utils::Hook(0x4B2080, StdOutPrint, HOOK_JUMP).install()->quick();
Utils::Hook(0x43D570, Console::StdOutError, HOOK_JUMP).install()->quick(); Utils::Hook(0x43D570, StdOutError, HOOK_JUMP).install()->quick();
} }
else if (Flags::HasFlag("console") || ZoneBuilder::IsEnabled()) // ZoneBuilder uses the game's console, until the native one is adapted. else if (Flags::HasFlag("console") || ZoneBuilder::IsEnabled()) // ZoneBuilder uses the game's console, until the native one is adapted.
{ {
@ -930,28 +917,28 @@ namespace Components
Utils::Hook(0x60BB68, [] Utils::Hook(0x60BB68, []
{ {
Console::ShowAsyncConsole(); ShowAsyncConsole();
}, HOOK_CALL).install()->quick(); }, HOOK_CALL).install()->quick();
Utils::Hook(0x4D69A2, []() Utils::Hook(0x4D69A2, []
{ {
Console::SetSkipShutdown(); SetSkipShutdown();
// Sys_DestroyConsole // Sys_DestroyConsole
Utils::Hook::Call<void()>(0x4528A0)(); Utils::Hook::Call<void()>(0x4528A0)();
if (Console::ConsoleThread.joinable()) if (ConsoleThread.joinable())
{ {
Console::ConsoleThread.join(); ConsoleThread.join();
} }
}, HOOK_CALL).install()->quick(); }, HOOK_CALL).install()->quick();
Scheduler::Loop([] Scheduler::Loop([]
{ {
Console::LastRefresh = Game::Sys_Milliseconds(); LastRefresh = Game::Sys_Milliseconds();
}, Scheduler::Pipeline::MAIN); }, Scheduler::Pipeline::MAIN);
} }
else if (Dedicated::IsEnabled()/* || ZoneBuilder::IsEnabled()*/) else if (Dedicated::IsEnabled())
{ {
DWORD type = GetFileType(GetStdHandle(STD_INPUT_HANDLE)); DWORD type = GetFileType(GetStdHandle(STD_INPUT_HANDLE));
if (type != FILE_TYPE_CHAR) if (type != FILE_TYPE_CHAR)
@ -962,11 +949,11 @@ namespace Components
Utils::Hook::Nop(0x60BB58, 11); Utils::Hook::Nop(0x60BB58, 11);
Utils::Hook(0x4305E0, Console::Create, HOOK_JUMP).install()->quick(); Utils::Hook(0x4305E0, Create, HOOK_JUMP).install()->quick();
Utils::Hook(0x4528A0, Console::Destroy, HOOK_JUMP).install()->quick(); Utils::Hook(0x4528A0, Destroy, HOOK_JUMP).install()->quick();
Utils::Hook(0x4B2080, Console::Print, HOOK_JUMP).install()->quick(); Utils::Hook(0x4B2080, Print, HOOK_JUMP).install()->quick();
Utils::Hook(0x43D570, Console::Error, HOOK_JUMP).install()->quick(); Utils::Hook(0x43D570, Error, HOOK_JUMP).install()->quick();
Utils::Hook(0x4859A5, Console::Input, HOOK_CALL).install()->quick(); Utils::Hook(0x4859A5, Input, HOOK_CALL).install()->quick();
} }
else if(!Loader::IsPerformingUnitTests()) else if(!Loader::IsPerformingUnitTests())
{ {
@ -976,10 +963,10 @@ namespace Components
Console::~Console() Console::~Console()
{ {
Console::SetSkipShutdown(); SetSkipShutdown();
if (Console::ConsoleThread.joinable()) if (ConsoleThread.joinable())
{ {
Console::ConsoleThread.join(); ConsoleThread.join();
} }
} }
} }

View File

@ -1,7 +1,5 @@
#pragma once #pragma once
#include "Terminus_4.49.1.ttf.hpp"
#define OUTPUT_HEIGHT 250 #define OUTPUT_HEIGHT 250
#define OUTPUT_MAX_TOP (OUTPUT_HEIGHT - (Console::Height - 2)) #define OUTPUT_MAX_TOP (OUTPUT_HEIGHT - (Console::Height - 2))
@ -81,21 +79,7 @@ namespace Components
static LRESULT CALLBACK ConWndProc(HWND hWnd, UINT Msg, WPARAM wParam, unsigned int lParam); static LRESULT CALLBACK ConWndProc(HWND hWnd, UINT Msg, WPARAM wParam, unsigned int lParam);
static ATOM CALLBACK RegisterClassHook(WNDCLASSA* lpWndClass); static ATOM CALLBACK RegisterClassHook(WNDCLASSA* lpWndClass);
static BOOL CALLBACK ResizeChildWindow(HWND hwndChild, LPARAM lParam); static BOOL CALLBACK ResizeChildWindow(HWND hwndChild, LPARAM lParam);
static HFONT CALLBACK ReplaceFont( static HFONT CALLBACK ReplaceFont(int cHeight, int cWidth, int cEscapement, int cOrientation, int cWeight, DWORD bItalic, DWORD bUnderline, DWORD bStrikeOut, DWORD iCharSet, DWORD iOutPrecision, DWORD iClipPrecision, DWORD iQuality, DWORD iPitchAndFamily, LPCSTR pszFaceName);
int cHeight,
int cWidth,
int cEscapement,
int cOrientation,
int cWeight,
DWORD bItalic,
DWORD bUnderline,
DWORD bStrikeOut,
DWORD iCharSet,
DWORD iOutPrecision,
DWORD iClipPrecision,
DWORD iQuality,
DWORD iPitchAndFamily,
LPCSTR pszFaceName);
static void ApplyConsoleStyle(); static void ApplyConsoleStyle();
static void GetWindowPos(HWND hWnd, int* x, int* y); static void GetWindowPos(HWND hWnd, int* x, int* y);
static void Sys_PrintStub(); static void Sys_PrintStub();

View File

@ -8,6 +8,7 @@ namespace Components
SteamID Dedicated::PlayerGuids[18][2]; SteamID Dedicated::PlayerGuids[18][2];
Dvar::Var Dedicated::SVLanOnly; Dvar::Var Dedicated::SVLanOnly;
Dvar::Var Dedicated::SVMOTD;
Dvar::Var Dedicated::COMLogFilter; Dvar::Var Dedicated::COMLogFilter;
bool Dedicated::IsEnabled() bool Dedicated::IsEnabled()
@ -76,7 +77,7 @@ namespace Components
__asm __asm
{ {
pushad pushad
call Dedicated::PostInitialization call PostInitialization
popad popad
// Start Com_EvenLoop // Start Com_EvenLoop
@ -96,7 +97,7 @@ namespace Components
list.append(Utils::String::VA(" %llX", Game::svs_clients[i].steamID)); list.append(Utils::String::VA(" %llX", Game::svs_clients[i].steamID));
Utils::InfoString info(Game::svs_clients[i].userinfo); Utils::InfoString info(Game::svs_clients[i].userinfo);
list.append(Utils::String::VA(" %llX", strtoull(info.get("realsteamId").data(), nullptr, 16))); list.append(Utils::String::VA(" %llX", std::strtoull(info.get("realsteamId").data(), nullptr, 16)));
} }
else else
{ {
@ -127,7 +128,7 @@ namespace Components
void Dedicated::Heartbeat() void Dedicated::Heartbeat()
{ {
// Do not send a heartbeat if sv_lanOnly is set to true // Do not send a heartbeat if sv_lanOnly is set to true
if (Dedicated::SVLanOnly.get<bool>()) if (SVLanOnly.get<bool>())
{ {
return; return;
} }
@ -148,18 +149,17 @@ namespace Components
Dedicated::Dedicated() Dedicated::Dedicated()
{ {
Dedicated::COMLogFilter = Dvar::Register<bool>("com_logFilter", true, COMLogFilter = Dvar::Register<bool>("com_logFilter", true,
Game::DVAR_LATCH, "Removes ~95% of unneeded lines from the log"); Game::DVAR_LATCH, "Removes ~95% of unneeded lines from the log");
if (Dedicated::IsEnabled() || ZoneBuilder::IsEnabled()) if (IsEnabled() || ZoneBuilder::IsEnabled())
{ {
// Make sure all callbacks are handled // Make sure all callbacks are handled
Scheduler::Loop(Steam::SteamAPI_RunCallbacks, Scheduler::Pipeline::SERVER); Scheduler::Loop(Steam::SteamAPI_RunCallbacks, Scheduler::Pipeline::SERVER);
Dedicated::SVLanOnly = Dvar::Register<bool>("sv_lanOnly", false, SVLanOnly = Dvar::Register<bool>("sv_lanOnly", false, Game::DVAR_NONE, "Don't act as node");
Game::DVAR_NONE, "Don't act as node");
Utils::Hook(0x60BE98, Dedicated::InitDedicatedServer, HOOK_CALL).install()->quick(); Utils::Hook(0x60BE98, InitDedicatedServer, HOOK_CALL).install()->quick();
Utils::Hook::Set<BYTE>(0x683370, 0xC3); // steam sometimes doesn't like the server Utils::Hook::Set<BYTE>(0x683370, 0xC3); // steam sometimes doesn't like the server
@ -199,7 +199,7 @@ namespace Components
Utils::Hook::Set<DWORD>(0x5DEC04, 0); Utils::Hook::Set<DWORD>(0x5DEC04, 0);
// Manually register sv_network_fps // Manually register sv_network_fps
Utils::Hook(0x4D3C7B, Dedicated::Dvar_RegisterSVNetworkFps, HOOK_CALL).install()->quick(); Utils::Hook(0x4D3C7B, Dvar_RegisterSVNetworkFps, HOOK_CALL).install()->quick();
// r_loadForRenderer default to 0 // r_loadForRenderer default to 0
Utils::Hook::Set<BYTE>(0x519DDF, 0); Utils::Hook::Set<BYTE>(0x519DDF, 0);
@ -217,18 +217,18 @@ namespace Components
Utils::Hook::Set<BYTE>(0x4B4D19, 0xEB); Utils::Hook::Set<BYTE>(0x4B4D19, 0xEB);
// Intercept time wrapping // Intercept time wrapping
Utils::Hook(0x62737D, Dedicated::TimeWrapStub, HOOK_CALL).install()->quick(); Utils::Hook(0x62737D, TimeWrapStub, HOOK_CALL).install()->quick();
//Utils::Hook::Set<DWORD>(0x62735C, 50'000); // Time wrap after 50 seconds (for testing - i don't want to wait 3 weeks) //Utils::Hook::Set<DWORD>(0x62735C, 50'000); // Time wrap after 50 seconds (for testing - i don't want to wait 3 weeks)
if (!ZoneBuilder::IsEnabled()) if (!ZoneBuilder::IsEnabled())
{ {
Scheduler::Once([] Scheduler::Once([]
{ {
Dvar::Register<const char*>("sv_motd", "", Game::DVAR_NONE, "A custom message of the day for servers"); SVMOTD = Dvar::Register<const char*>("sv_motd", "", Game::DVAR_NONE, "A custom message of the day for servers");
}, Scheduler::Pipeline::MAIN); }, Scheduler::Pipeline::MAIN);
// Post initialization point // Post initialization point
Utils::Hook(0x60BFBF, Dedicated::PostInitializationStub, HOOK_JUMP).install()->quick(); Utils::Hook(0x60BFBF, PostInitializationStub, HOOK_JUMP).install()->quick();
// Transmit custom data // Transmit custom data
Scheduler::Loop([] Scheduler::Loop([]
@ -238,16 +238,16 @@ namespace Components
}, Scheduler::Pipeline::SERVER, 10s); }, Scheduler::Pipeline::SERVER, 10s);
// Heartbeats // Heartbeats
Scheduler::Once(Dedicated::Heartbeat, Scheduler::Pipeline::SERVER); Scheduler::Once(Heartbeat, Scheduler::Pipeline::SERVER);
Scheduler::Loop(Dedicated::Heartbeat, Scheduler::Pipeline::SERVER, 2min); Scheduler::Loop(Heartbeat, Scheduler::Pipeline::SERVER, 2min);
} }
} }
else else
{ {
for (int i = 0; i < ARRAYSIZE(Dedicated::PlayerGuids); ++i) for (int i = 0; i < ARRAYSIZE(PlayerGuids); ++i)
{ {
Dedicated::PlayerGuids[i][0].bits = 0; PlayerGuids[i][0].bits = 0;
Dedicated::PlayerGuids[i][1].bits = 0; PlayerGuids[i][1].bits = 0;
} }
// Intercept server commands // Intercept server commands
@ -255,12 +255,12 @@ namespace Components
{ {
for (int client = 0; client < 18; client++) for (int client = 0; client < 18; client++)
{ {
Dedicated::PlayerGuids[client][0].bits = strtoull(params->get(2 * client + 1), nullptr, 16); PlayerGuids[client][0].bits = std::strtoull(params->get(2 * client + 1), nullptr, 16);
Dedicated::PlayerGuids[client][1].bits = strtoull(params->get(2 * client + 2), nullptr, 16); PlayerGuids[client][1].bits = std::strtoull(params->get(2 * client + 2), nullptr, 16);
if (Steam::Proxy::SteamFriends && Dedicated::PlayerGuids[client][1].bits != 0) if (Steam::Proxy::SteamFriends && PlayerGuids[client][1].bits != 0)
{ {
Steam::Proxy::SteamFriends->SetPlayedWith(Dedicated::PlayerGuids[client][1]); Steam::Proxy::SteamFriends->SetPlayedWith(PlayerGuids[client][1]);
} }
} }
@ -270,9 +270,9 @@ namespace Components
Scheduler::Loop([] Scheduler::Loop([]
{ {
if (Dedicated::IsRunning()) if (IsRunning())
{ {
Dedicated::TransmitGuids(); TransmitGuids();
} }
}, Scheduler::Pipeline::SERVER, 15s); }, Scheduler::Pipeline::SERVER, 15s);
} }

View File

@ -9,6 +9,7 @@ namespace Components
static SteamID PlayerGuids[18][2]; static SteamID PlayerGuids[18][2];
static Dvar::Var SVLanOnly; static Dvar::Var SVLanOnly;
static Dvar::Var SVMOTD;
static Dvar::Var COMLogFilter; static Dvar::Var COMLogFilter;
static bool IsEnabled(); static bool IsEnabled();

View File

@ -8,6 +8,9 @@ namespace Components
{ {
static mg_mgr Mgr; static mg_mgr Mgr;
Dvar::Var Download::SV_wwwDownload;
Dvar::Var Download::SV_wwwBaseUrl;
Download::ClientDownload Download::CLDownload; Download::ClientDownload Download::CLDownload;
std::thread Download::ServerThread; std::thread Download::ServerThread;
@ -138,7 +141,7 @@ namespace Components
} }
auto host = "http://" + download->target.getString(); auto host = "http://" + download->target.getString();
auto fastHost = Dvar::Var("sv_wwwBaseUrl").get<std::string>(); auto fastHost = SV_wwwBaseUrl.get<std::string>();
if (Utils::String::StartsWith(fastHost, "https://")) if (Utils::String::StartsWith(fastHost, "https://"))
{ {
download->thread.detach(); download->thread.detach();
@ -173,7 +176,7 @@ namespace Components
// -mod.ff // -mod.ff
// /-mod2 // /-mod2
// ... // ...
if (Dvar::Var("sv_wwwDownload").get<bool>()) if (SV_wwwDownload.get<bool>())
{ {
if (!Utils::String::EndsWith(fastHost, "/")) fastHost.append("/"); if (!Utils::String::EndsWith(fastHost, "/")) fastHost.append("/");
url = fastHost + path; url = fastHost + path;
@ -720,8 +723,8 @@ namespace Components
Scheduler::Once([] Scheduler::Once([]
{ {
Dvar::Register<bool>("sv_wwwDownload", false, Game::DVAR_NONE, "Set to true to enable downloading maps/mods from an external server."); SV_wwwDownload = Dvar::Register<bool>("sv_wwwDownload", false, Game::DVAR_NONE, "Set to true to enable downloading maps/mods from an external server.");
Dvar::Register<const char*>("sv_wwwBaseUrl", "", Game::DVAR_NONE, "Set to the base url for the external map download."); SV_wwwBaseUrl = Dvar::Register<const char*>("sv_wwwBaseUrl", "", Game::DVAR_NONE, "Set to the base url for the external map download.");
}, Scheduler::Pipeline::MAIN); }, Scheduler::Pipeline::MAIN);
} }

View File

@ -13,6 +13,9 @@ namespace Components
static void InitiateClientDownload(const std::string& mod, bool needPassword, bool map = false); static void InitiateClientDownload(const std::string& mod, bool needPassword, bool map = false);
static void InitiateMapDownload(const std::string& map, bool needPassword); static void InitiateMapDownload(const std::string& map, bool needPassword);
static Dvar::Var SV_wwwDownload;
static Dvar::Var SV_wwwBaseUrl;
private: private:
class ClientDownload class ClientDownload
{ {

View File

@ -583,7 +583,7 @@ namespace Components
} }
// dlcIsTrue serves as a check if the map is a custom map and if it's missing // dlcIsTrue serves as a check if the map is a custom map and if it's missing
bool Maps::CheckMapInstalled(const char* mapname, bool error, bool dlcIsTrue) bool Maps::CheckMapInstalled(const std::string& mapname, bool error, bool dlcIsTrue)
{ {
if (FastFiles::Exists(mapname)) return true; if (FastFiles::Exists(mapname)) return true;
@ -591,12 +591,12 @@ namespace Components
{ {
for (auto map : pack.maps) for (auto map : pack.maps)
{ {
if (map == std::string(mapname)) if (map == mapname)
{ {
if (error) if (error)
{ {
Logger::Error(Game::ERR_DISCONNECT, "Missing DLC pack {} ({}) containing map {} ({}).\nPlease download it to play this map.", Logger::Error(Game::ERR_DISCONNECT, "Missing DLC pack {} ({}) containing map {} ({}).\nPlease download it to play this map.",
pack.name, pack.index, Game::UI_LocalizeMapName(mapname), mapname); pack.name, pack.index, Game::UI_LocalizeMapName(mapname.data()), mapname);
} }
return dlcIsTrue; return dlcIsTrue;

View File

@ -54,7 +54,7 @@ namespace Components
static std::string CurrentMainZone; static std::string CurrentMainZone;
static const char* UserMapFiles[4]; static const char* UserMapFiles[4];
static bool CheckMapInstalled(const char* mapname, bool error = false, bool dlcIsTrue = false); static bool CheckMapInstalled(const std::string& mapname, bool error = false, bool dlcIsTrue = false);
static UserMapContainer* GetUserMap(); static UserMapContainer* GetUserMap();
static unsigned int GetUsermapHash(const std::string& map); static unsigned int GetUsermapHash(const std::string& map);

View File

@ -28,35 +28,36 @@ namespace Components
Network::Address Party::Target() Network::Address Party::Target()
{ {
return Party::Container.target; return Container.target;
} }
void Party::Connect(Network::Address target) void Party::Connect(Network::Address target)
{ {
Node::Add(target); Node::Add(target);
Party::Container.valid = true; Container.valid = true;
Party::Container.awaitingPlaylist = false; Container.awaitingPlaylist = false;
Party::Container.joinTime = Game::Sys_Milliseconds(); Container.joinTime = Game::Sys_Milliseconds();
Party::Container.target = target; Container.target = target;
Party::Container.challenge = Utils::Cryptography::Rand::GenerateChallenge(); Container.challenge = Utils::Cryptography::Rand::GenerateChallenge();
Network::SendCommand(Party::Container.target, "getinfo", Party::Container.challenge); Network::SendCommand(Container.target, "getinfo", Container.challenge);
Command::Execute("openmenu popup_reconnectingtoparty"); Command::Execute("openmenu popup_reconnectingtoparty");
} }
const char* Party::GetLobbyInfo(SteamID lobby, const std::string& key) const char* Party::GetLobbyInfo(SteamID lobby, const std::string& key)
{ {
if (Party::LobbyMap.contains(lobby.bits)) if (LobbyMap.contains(lobby.bits))
{ {
Network::Address address = Party::LobbyMap[lobby.bits]; Network::Address address = LobbyMap[lobby.bits];
if (key == "addr") if (key == "addr"s)
{ {
return Utils::String::VA("%d", address.getIP().full); return Utils::String::VA("%d", address.getIP().full);
} }
else if (key == "port")
if (key == "port"s)
{ {
return Utils::String::VA("%d", address.getPort()); return Utils::String::VA("%d", address.getPort());
} }
@ -67,7 +68,7 @@ namespace Components
void Party::RemoveLobby(SteamID lobby) void Party::RemoveLobby(SteamID lobby)
{ {
Party::LobbyMap.erase(lobby.bits); LobbyMap.erase(lobby.bits);
} }
void Party::ConnectError(const std::string& message) void Party::ConnectError(const std::string& message)
@ -79,17 +80,12 @@ namespace Components
std::string Party::GetMotd() std::string Party::GetMotd()
{ {
return Party::Container.motd; return Container.motd;
}
Game::dvar_t* Party::RegisterMinPlayers(const char* name, int /*value*/, int /*min*/, int max, unsigned __int16 flag, const char* description)
{
return Dvar::Register<int>(name, 1, 1, max, Game::DVAR_INIT | flag, description).get<Game::dvar_t*>();
} }
bool Party::PlaylistAwaiting() bool Party::PlaylistAwaiting()
{ {
return Party::Container.awaitingPlaylist; return Container.awaitingPlaylist;
} }
void Party::PlaylistContinue() void Party::PlaylistContinue()
@ -99,20 +95,20 @@ namespace Components
// Ensure we can join // Ensure we can join
*Game::g_lobbyCreateInProgress = false; *Game::g_lobbyCreateInProgress = false;
Party::Container.awaitingPlaylist = false; Container.awaitingPlaylist = false;
SteamID id = Party::GenerateLobbyId(); SteamID id = GenerateLobbyId();
// Temporary workaround // Temporary workaround
// TODO: Patch the 127.0.0.1 -> loopback mapping in the party code // TODO: Patch the 127.0.0.1 -> loopback mapping in the party code
if (Party::Container.target.isLoopback()) if (Container.target.isLoopback())
{ {
if (*Game::numIP) if (*Game::numIP)
{ {
Party::Container.target.setIP(*Game::localIP); Container.target.setIP(*Game::localIP);
Party::Container.target.setType(Game::netadrtype_t::NA_IP); Container.target.setType(Game::netadrtype_t::NA_IP);
Logger::Print("Trying to connect to party with loopback address, using a local ip instead: {}\n", Party::Container.target.getString()); Logger::Print("Trying to connect to party with loopback address, using a local ip instead: {}\n", Container.target.getString());
} }
else else
{ {
@ -120,17 +116,17 @@ namespace Components
} }
} }
Party::LobbyMap[id.bits] = Party::Container.target; LobbyMap[id.bits] = Container.target;
Game::Steam_JoinLobby(id, 0); Game::Steam_JoinLobby(id, 0);
} }
void Party::PlaylistError(const std::string& error) void Party::PlaylistError(const std::string& error)
{ {
Party::Container.valid = false; Container.valid = false;
Party::Container.awaitingPlaylist = false; Container.awaitingPlaylist = false;
Party::ConnectError(error); ConnectError(error);
} }
DWORD Party::UIDvarIntStub(char* dvar) DWORD Party::UIDvarIntStub(char* dvar)
@ -150,7 +146,7 @@ namespace Components
bool Party::IsInUserMapLobby() bool Party::IsInUserMapLobby()
{ {
return (Party::IsInLobby() && Maps::IsUserMap(Dvar::Var("ui_mapname").get<const char*>())); return (IsInLobby() && Maps::IsUserMap(Dvar::Var("ui_mapname").get<const char*>()));
} }
bool Party::IsEnabled() bool Party::IsEnabled()
@ -160,7 +156,7 @@ namespace Components
Party::Party() Party::Party()
{ {
Party::PartyEnable = Dvar::Register<bool>("party_enable", Dedicated::IsEnabled(), Game::DVAR_NONE, "Enable party system"); PartyEnable = Dvar::Register<bool>("party_enable", Dedicated::IsEnabled(), Game::DVAR_NONE, "Enable party system");
Dvar::Register<bool>("xblive_privatematch", true, Game::DVAR_INIT, ""); Dvar::Register<bool>("xblive_privatematch", true, Game::DVAR_INIT, "");
// various changes to SV_DirectConnect-y stuff to allow non-party joinees // various changes to SV_DirectConnect-y stuff to allow non-party joinees
@ -227,7 +223,7 @@ namespace Components
Utils::Hook::Nop(0x5A8E33, 11); Utils::Hook::Nop(0x5A8E33, 11);
// Enable XP Bar // Enable XP Bar
Utils::Hook(0x62A2A7, Party::UIDvarIntStub, HOOK_CALL).install()->quick(); Utils::Hook(0x62A2A7, UIDvarIntStub, HOOK_CALL).install()->quick();
// Set NAT to open // Set NAT to open
Utils::Hook::Set<int>(0x79D898, 1); Utils::Hook::Set<int>(0x79D898, 1);
@ -238,7 +234,7 @@ namespace Components
Utils::Hook::Nop(0x4077A1, 5); // PartyMigrate_Frame Utils::Hook::Nop(0x4077A1, 5); // PartyMigrate_Frame
// Patch playlist stuff for non-party behavior // Patch playlist stuff for non-party behavior
static Game::dvar_t* partyEnable = Party::PartyEnable.get<Game::dvar_t*>(); static Game::dvar_t* partyEnable = PartyEnable.get<Game::dvar_t*>();
Utils::Hook::Set<Game::dvar_t**>(0x4A4093, &partyEnable); Utils::Hook::Set<Game::dvar_t**>(0x4A4093, &partyEnable);
Utils::Hook::Set<Game::dvar_t**>(0x4573F1, &partyEnable); Utils::Hook::Set<Game::dvar_t**>(0x4573F1, &partyEnable);
Utils::Hook::Set<Game::dvar_t**>(0x5B1A0C, &partyEnable); Utils::Hook::Set<Game::dvar_t**>(0x5B1A0C, &partyEnable);
@ -248,12 +244,6 @@ namespace Components
Utils::Hook::Xor<BYTE>(0x4573FA, 1); Utils::Hook::Xor<BYTE>(0x4573FA, 1);
Utils::Hook::Xor<BYTE>(0x5B1A17, 1); Utils::Hook::Xor<BYTE>(0x5B1A17, 1);
// Fix xstartlobby
//Utils::Hook::Set<BYTE>(0x5B71CD, 0xEB);
// Patch party_minplayers to 1 and protect it
//Utils::Hook(0x4D5D51, Party::RegisterMinPlayers, HOOK_CALL).install()->quick();
// Set ui_maxclients to sv_maxclients // Set ui_maxclients to sv_maxclients
Utils::Hook::Set<const char*>(0x42618F, "sv_maxclients"); Utils::Hook::Set<const char*>(0x42618F, "sv_maxclients");
Utils::Hook::Set<const char*>(0x4D3756, "sv_maxclients"); Utils::Hook::Set<const char*>(0x4D3756, "sv_maxclients");
@ -267,9 +257,6 @@ namespace Components
Utils::Hook::Xor<DWORD>(0x4D376D, Game::DVAR_LATCH); Utils::Hook::Xor<DWORD>(0x4D376D, Game::DVAR_LATCH);
Utils::Hook::Xor<DWORD>(0x5E3789, Game::DVAR_LATCH); Utils::Hook::Xor<DWORD>(0x5E3789, Game::DVAR_LATCH);
// Patch Live_PlayerHasLoopbackAddr
//Utils::Hook::Set<DWORD>(0x418F30, 0x90C3C033);
Command::Add("connect", [](Command::Params* params) Command::Add("connect", [](Command::Params* params)
{ {
if (params->size() < 2) if (params->size() < 2)
@ -284,33 +271,34 @@ namespace Components
} }
else else
{ {
Party::Connect(Network::Address(params->get(1))); Connect(Network::Address(params->get(1)));
} }
}); });
Command::Add("reconnect", [](Command::Params*) Command::Add("reconnect", [](Command::Params*)
{ {
Party::Connect(Party::Container.target); Connect(Container.target);
}); });
if (!Dedicated::IsEnabled() && !ZoneBuilder::IsEnabled()) if (!Dedicated::IsEnabled() && !ZoneBuilder::IsEnabled())
{ {
Scheduler::Loop([] Scheduler::Loop([]
{ {
if (Party::Container.valid) if (Container.valid)
{ {
if ((Game::Sys_Milliseconds() - Party::Container.joinTime) > 10'000) if ((Game::Sys_Milliseconds() - Container.joinTime) > 10'000)
{ {
Party::Container.valid = false; Container.valid = false;
Party::ConnectError("Server connection timed out."); ConnectError("Server connection timed out.");
} }
} }
if (Party::Container.awaitingPlaylist) if (Container.awaitingPlaylist)
{ {
if ((Game::Sys_Milliseconds() - Party::Container.requestTime) > 5'000) if ((Game::Sys_Milliseconds() - Container.requestTime) > 5'000)
{ {
Party::Container.awaitingPlaylist = false; Container.awaitingPlaylist = false;
Party::ConnectError("Playlist request timed out."); ConnectError("Playlist request timed out.");
} }
} }
@ -339,8 +327,8 @@ namespace Components
} }
else else
{ {
maxClientCount = Dvar::Var("party_maxplayers").get<int>(); maxClientCount = *Game::party_maxplayers ? (*Game::party_maxplayers)->current.integer : 18;
clientCount = Game::PartyHost_CountMembers(reinterpret_cast<Game::PartyData*>(0x1081C00)); clientCount = Game::PartyHost_CountMembers(Game::g_lobbyData);
} }
Utils::InfoString info; Utils::InfoString info;
@ -365,7 +353,7 @@ namespace Components
info.set("voiceChat", (Voice::SV_VoiceEnabled() ? "1" : "0")); info.set("voiceChat", (Voice::SV_VoiceEnabled() ? "1" : "0"));
// Ensure mapname is set // Ensure mapname is set
if (info.get("mapname").empty() || Party::IsInLobby()) if (info.get("mapname").empty() || IsInLobby())
{ {
info.set("mapname", Dvar::Var("ui_mapname").get<const char*>()); info.set("mapname", Dvar::Var("ui_mapname").get<const char*>());
} }
@ -374,14 +362,14 @@ namespace Components
{ {
info.set("usermaphash", Utils::String::VA("%i", Maps::GetUserMap()->getHash())); info.set("usermaphash", Utils::String::VA("%i", Maps::GetUserMap()->getHash()));
} }
else if (Party::IsInUserMapLobby()) else if (IsInUserMapLobby())
{ {
info.set("usermaphash", Utils::String::VA("%i", Maps::GetUsermapHash(info.get("mapname")))); info.set("usermaphash", Utils::String::VA("%i", Maps::GetUsermapHash(info.get("mapname"))));
} }
if (Dedicated::IsEnabled()) if (Dedicated::IsEnabled())
{ {
info.set("sv_motd", Dvar::Var("sv_motd").get<std::string>()); info.set("sv_motd", Dedicated::SVMOTD.get<std::string>());
} }
// Set matchtype // Set matchtype
@ -402,133 +390,172 @@ namespace Components
info.set("matchtype", "0"); info.set("matchtype", "0");
} }
info.set("wwwDownload", (Dvar::Var("sv_wwwDownload").get<bool>() ? "1" : "0")); info.set("wwwDownload", (Download::SV_wwwDownload.get<bool>() ? "1" : "0"));
info.set("wwwUrl", Dvar::Var("sv_wwwBaseUrl").get<std::string>()); info.set("wwwUrl", Download::SV_wwwBaseUrl.get<std::string>());
Network::SendCommand(address, "infoResponse", "\\" + info.build()); Network::SendCommand(address, "infoResponse", "\\" + info.build());
}); });
Network::OnClientPacket("infoResponse", [](const Network::Address& address, [[maybe_unused]] const std::string& data) Network::OnClientPacket("infoResponse", [](const Network::Address& address, [[maybe_unused]] const std::string& data)
{ {
Utils::InfoString info(data); const Utils::InfoString info(data);
const auto _0 = gsl::finally([&]
{
ServerList::Insert(address, info);
Friends::UpdateServer(address, info.get("hostname"), info.get("mapname"));
});
// Handle connection // Handle connection
if (Party::Container.valid) if (!Container.valid)
{ {
if (Party::Container.target == address) return;
{
// Invalidate handler for future packets
Party::Container.valid = false;
Party::Container.info = info;
Party::Container.matchType = atoi(info.get("matchtype").data());
uint32_t securityLevel = static_cast<uint32_t>(atoi(info.get("securityLevel").data()));
bool isUsermap = !info.get("usermaphash").empty();
unsigned int usermapHash = atoi(info.get("usermaphash").data());
std::string mod = (*Game::fs_gameDirVar)->current.string;
// set fast server stuff here so its updated when we go to download stuff
if (info.get("wwwDownload") == "1"s)
{
Dvar::Var("sv_wwwDownload").set(true);
Dvar::Var("sv_wwwBaseUrl").set(info.get("wwwUrl"));
}
else
{
Dvar::Var("sv_wwwDownload").set(false);
Dvar::Var("sv_wwwBaseUrl").set("");
}
if (info.get("challenge") != Party::Container.challenge)
{
Party::ConnectError("Invalid join response: Challenge mismatch.");
}
else if (securityLevel > Auth::GetSecurityLevel())
{
//Party::ConnectError(Utils::VA("Your security level (%d) is lower than the server's (%d)", Auth::GetSecurityLevel(), securityLevel));
Command::Execute("closemenu popup_reconnectingtoparty");
Auth::IncreaseSecurityLevel(securityLevel, "reconnect");
}
else if (!Party::Container.matchType)
{
Party::ConnectError("Server is not hosting a match.");
}
else if (Party::Container.matchType > 2 || Party::Container.matchType < 0)
{
Party::ConnectError("Invalid join response: Unknown matchtype");
}
else if (Party::Container.info.get("mapname").empty() || Party::Container.info.get("gametype").empty())
{
Party::ConnectError("Invalid map or gametype.");
}
else if (Party::Container.info.get("isPrivate") == "1"s && !Dvar::Var("password").get<std::string>().length())
{
Party::ConnectError("A password is required to join this server! Set it at the bottom of the serverlist.");
}
else if (isUsermap && usermapHash != Maps::GetUsermapHash(info.get("mapname")))
{
Command::Execute("closemenu popup_reconnectingtoparty");
Download::InitiateMapDownload(info.get("mapname"), info.get("isPrivate") == "1");
}
else if (!info.get("fs_game").empty() && Utils::String::ToLower(mod) != Utils::String::ToLower(info.get("fs_game")))
{
Command::Execute("closemenu popup_reconnectingtoparty");
Download::InitiateClientDownload(info.get("fs_game"), info.get("isPrivate") == "1"s);
}
else if (!Dvar::Var("fs_game").get<std::string>().empty() && info.get("fs_game").empty())
{
Game::Dvar_SetString(*Game::fs_gameDirVar, "");
if (Dvar::Var("cl_modVidRestart").get<bool>())
{
Command::Execute("vid_restart", false);
}
Command::Execute("reconnect", false);
}
else
{
if (!Maps::CheckMapInstalled(Party::Container.info.get("mapname").data(), true)) return;
Party::Container.motd = info.get("sv_motd");
if (Party::Container.matchType == 1) // Party
{
// Send playlist request
Party::Container.requestTime = Game::Sys_Milliseconds();
Party::Container.awaitingPlaylist = true;
Network::SendCommand(Party::Container.target, "getplaylist", Dvar::Var("password").get<std::string>());
// This is not a safe method
// TODO: Fix actual error!
if (Game::CL_IsCgameInitialized())
{
Command::Execute("disconnect", true);
}
}
else if (Party::Container.matchType == 2) // Match
{
if (atoi(Party::Container.info.get("clients").data()) >= atoi(Party::Container.info.get("sv_maxclients").data()))
{
Party::ConnectError("@EXE_SERVERISFULL");
}
else
{
Dvar::Var("xblive_privateserver").set(true);
Game::Menus_CloseAll(Game::uiContext);
Game::_XSESSION_INFO hostInfo;
Game::CL_ConnectFromParty(0, &hostInfo, *Party::Container.target.get(), 0, 0, Party::Container.info.get("mapname").data(), Party::Container.info.get("gametype").data());
}
}
}
}
} }
ServerList::Insert(address, info); if (Container.target == address)
Friends::UpdateServer(address, info.get("hostname"), info.get("mapname")); {
return;
}
// Invalidate handler for future packets
Container.valid = false;
Container.info = info;
Container.matchType = atoi(info.get("matchtype").data());
const auto securityLevel = static_cast<uint32_t>(std::strtol(info.get("securityLevel").data(), nullptr, 10));
bool isUsermap = !info.get("usermaphash").empty();
const auto usermapHash = static_cast<uint32_t>(std::strtol(info.get("usermaphash").data(), nullptr, 10));
std::string mod = (*Game::fs_gameDirVar)->current.string;
// set fast server stuff here so its updated when we go to download stuff
if (info.get("wwwDownload") == "1"s)
{
Download::SV_wwwDownload.set(true);
Download::SV_wwwBaseUrl.set(info.get("wwwUrl"));
}
else
{
Download::SV_wwwDownload.set(false);
Download::SV_wwwBaseUrl.set("");
}
if (info.get("challenge") != Container.challenge)
{
ConnectError("Invalid join response: Challenge mismatch.");
return;
}
if (securityLevel > Auth::GetSecurityLevel())
{
Command::Execute("closemenu popup_reconnectingtoparty");
Auth::IncreaseSecurityLevel(securityLevel, "reconnect");
return;
}
if (!Container.matchType)
{
ConnectError("Server is not hosting a match.");
return;
}
if (Container.matchType > 2 || Container.matchType < 0)
{
ConnectError("Invalid join response: Unknown matchtype");
return;
}
if (Container.info.get("mapname").empty() || Container.info.get("gametype").empty())
{
ConnectError("Invalid map or gametype.");
return;
}
if (Container.info.get("isPrivate") == "1"s && !Dvar::Var("password").get<std::string>().empty())
{
ConnectError("A password is required to join this server! Set it at the bottom of the serverlist.");
return;
}
if (isUsermap && usermapHash != Maps::GetUsermapHash(info.get("mapname")))
{
Command::Execute("closemenu popup_reconnectingtoparty");
Download::InitiateMapDownload(info.get("mapname"), info.get("isPrivate") == "1"s);
return;
}
if (!info.get("fs_game").empty() && Utils::String::ToLower(mod) != Utils::String::ToLower(info.get("fs_game")))
{
Command::Execute("closemenu popup_reconnectingtoparty");
Download::InitiateClientDownload(info.get("fs_game"), info.get("isPrivate") == "1"s);
return;
}
if (*(*Game::fs_gameDirVar)->current.string && info.get("fs_game").empty())
{
Game::Dvar_SetString(*Game::fs_gameDirVar, "");
if (Dvar::Var("cl_modVidRestart").get<bool>())
{
Command::Execute("vid_restart", false);
}
Command::Execute("reconnect", false);
return;
}
if (!Maps::CheckMapInstalled(Container.info.get("mapname"), true))
{
return;
}
Container.motd = info.get("sv_motd");
if (Container.matchType == 1) // Party
{
// Send playlist request
Container.requestTime = Game::Sys_Milliseconds();
Container.awaitingPlaylist = true;
Network::SendCommand(Party::Container.target, "getplaylist", Dvar::Var("password").get<std::string>());
// This is not a safe method
// TODO: Fix actual error!
if (Game::CL_IsCgameInitialized())
{
Command::Execute("disconnect", true);
}
}
else if (Container.matchType == 2) // Match
{
int clients;
int maxClients;
try
{
clients = std::stoi(Container.info.get("clients"));
maxClients = std::stoi(Container.info.get("sv_maxclients"));
}
catch ([[maybe_unused]] const std::exception& ex)
{
ConnectError("Invalid info string");
return;
}
if (clients >= maxClients)
{
ConnectError("@EXE_SERVERISFULL");
}
else
{
Dvar::Var("xblive_privateserver").set(true);
Game::Menus_CloseAll(Game::uiContext);
Game::_XSESSION_INFO hostInfo;
Game::CL_ConnectFromParty(0, &hostInfo, *Container.target.get(), 0, 0, Container.info.get("mapname").data(), Container.info.get("gametype").data());
}
}
}); });
} }
} }

View File

@ -50,8 +50,6 @@ namespace Components
static SteamID GenerateLobbyId(); static SteamID GenerateLobbyId();
static Game::dvar_t* RegisterMinPlayers(const char* name, int value, int min, int max, unsigned __int16 flag, const char* description);
static DWORD UIDvarIntStub(char* dvar); static DWORD UIDvarIntStub(char* dvar);
}; };
} }

View File

@ -140,7 +140,7 @@ namespace Components
if (!maxClientCount) if (!maxClientCount)
{ {
maxClientCount = Dvar::Var("party_maxplayers").get<int>(); maxClientCount = *Game::party_maxplayers ? (*Game::party_maxplayers)->current.integer : 18;
} }
Utils::InfoString info(Game::Dvar_InfoString_Big(Game::DVAR_SERVERINFO)); Utils::InfoString info(Game::Dvar_InfoString_Big(Game::DVAR_SERVERINFO));
@ -166,7 +166,7 @@ namespace Components
// 1 - Party, use Steam_JoinLobby to connect // 1 - Party, use Steam_JoinLobby to connect
// 2 - Match, use CL_ConnectFromParty to connect // 2 - Match, use CL_ConnectFromParty to connect
if (Dvar::Var("party_enable").get<bool>() && Dvar::Var("party_host").get<bool>()) // Party hosting if (Party::IsEnabled() && Dvar::Var("party_host").get<bool>()) // Party hosting
{ {
info.set("matchtype", "1"); info.set("matchtype", "1");
} }

View File

@ -113,7 +113,7 @@ namespace Components
{ {
if (server->svRunning) if (server->svRunning)
{ {
if (!sorting && !Maps::CheckMapInstalled(server->mapname.data())) if (!sorting && !Maps::CheckMapInstalled(server->mapname))
{ {
return Utils::String::VA("^1%s", Game::UI_LocalizeMapName(server->mapname.data())); return Utils::String::VA("^1%s", Game::UI_LocalizeMapName(server->mapname.data()));
} }

View File

@ -77,6 +77,9 @@ namespace Game
const dvar_t** loc_warnings = reinterpret_cast<const dvar_t**>(0x62C8700); const dvar_t** loc_warnings = reinterpret_cast<const dvar_t**>(0x62C8700);
const dvar_t** loc_warningsAsErrors = reinterpret_cast<const dvar_t**>(0x62C86FC); const dvar_t** loc_warningsAsErrors = reinterpret_cast<const dvar_t**>(0x62C86FC);
const dvar_t** party_minplayers = reinterpret_cast<const dvar_t**>(0x1081BFC);
const dvar_t** party_maxplayers = reinterpret_cast<const dvar_t**>(0x1080998);
__declspec(naked) void Dvar_SetVariant(dvar_t*, DvarValue, DvarSetSource) __declspec(naked) void Dvar_SetVariant(dvar_t*, DvarValue, DvarSetSource)
{ {
static DWORD Dvar_SetVariant_t = 0x647400; static DWORD Dvar_SetVariant_t = 0x647400;

View File

@ -127,6 +127,9 @@ namespace Game
extern const dvar_t** loc_warnings; extern const dvar_t** loc_warnings;
extern const dvar_t** loc_warningsAsErrors; extern const dvar_t** loc_warningsAsErrors;
extern const dvar_t** party_minplayers;
extern const dvar_t** party_maxplayers;
extern void Dvar_SetVariant(dvar_t* var, DvarValue value, DvarSetSource source); extern void Dvar_SetVariant(dvar_t* var, DvarValue value, DvarSetSource source);
extern void Dvar_SetFromStringFromSource(const dvar_t* dvar, const char* string, DvarSetSource source); extern void Dvar_SetFromStringFromSource(const dvar_t* dvar, const char* string, DvarSetSource source);
} }